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

Report L1 base fee set by L2s #111

Merged
merged 34 commits into from
Oct 2, 2023
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
c35425e
CCIP plugin code sketch
matYang Sep 2, 2023
0978d8f
Merge branch 'ccip-develop' into feature/offchain-report-l1-base-fee-…
matYang Sep 19, 2023
27d328d
revert models changes
matYang Sep 19, 2023
6fd2486
update gas price encoding and deviation
matYang Sep 20, 2023
4288094
udpate exec cost estimation
matYang Sep 20, 2023
65ec92f
Update exec cost estimation
matYang Sep 20, 2023
d68a786
update offchain config
matYang Sep 21, 2023
fb7b0af
use gas price struct instead of encoding where applicable
matYang Sep 21, 2023
b2c5866
do not use v2 suffix for latest version of offchain config
matYang Sep 21, 2023
3985918
add nil check for gas update
matYang Sep 21, 2023
159cc13
Merge branch 'ccip-develop' into feature/offchain-report-l1-base-fee-…
matYang Sep 22, 2023
bc94b46
Adding price estimator interfaces
matYang Sep 22, 2023
78ab531
update commit plugin
matYang Sep 23, 2023
a6cd7c4
update name to prices
matYang Sep 24, 2023
71992a3
update exec plugin
matYang Sep 24, 2023
436eef3
comments and nits
matYang Sep 25, 2023
5e4ec20
change the loaders to also return version
matYang Sep 25, 2023
9b52b04
address comments
matYang Sep 26, 2023
3367405
making tests build
matYang Sep 26, 2023
5fb58a2
validate observed token prices match token with decimals
matYang Sep 26, 2023
4bfb882
fixed commit reporting tests
matYang Sep 27, 2023
d3e7142
add test for validateObservations
matYang Sep 27, 2023
37badf1
pass tests
matYang Sep 27, 2023
76aa3ef
Merge branch 'ccip-develop' into feature/offchain-report-l1-base-fee-…
matYang Sep 27, 2023
3d9d6ba
add test for exec getPrice
matYang Sep 27, 2023
3237406
couple more tests in exec price estimator
matYang Sep 27, 2023
337a715
complete exec price estimator test
matYang Sep 27, 2023
9717f92
add da price estimator test
matYang Sep 28, 2023
d795be9
Merge branch 'ccip-develop' into feature/offchain-report-l1-base-fee-…
matYang Sep 28, 2023
c4f9718
resolve exec logpoller fiter test
matYang Sep 28, 2023
f619ede
address comments
matYang Sep 29, 2023
42fa3bd
remove price estimator deviation and computeCost opts
matYang Sep 30, 2023
9d7673f
Merge branch 'ccip-develop' into feature/offchain-report-l1-base-fee-…
matYang Oct 2, 2023
db7be89
fix 1.21 import
matYang Oct 2, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions core/services/ocr2/plugins/ccip/commit_inflight.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,10 @@ func (c *inflightCommitReportsContainer) maxInflightSeqNr() uint64 {
}

// latestGasPriceUpdate return the latest inflight gas price update or nil if there is no inflight gas price update.
func (c *inflightCommitReportsContainer) getLatestInflightGasPriceUpdate() *update {
func (c *inflightCommitReportsContainer) getLatestInflightGasPriceUpdate() *gasPriceUpdate {
c.locker.RLock()
defer c.locker.RUnlock()
var latestGasPriceUpdate *update
var latestGasPriceUpdate *gasPriceUpdate
var latestEpochAndRound uint64
for _, inflight := range c.inFlightPriceUpdates {
if inflight.priceUpdates.DestChainSelector == 0 {
Expand All @@ -80,9 +80,9 @@ func (c *inflightCommitReportsContainer) getLatestInflightGasPriceUpdate() *upda
}
if latestGasPriceUpdate == nil || inflight.epochAndRound > latestEpochAndRound {
// First price found or found later update, set it
latestGasPriceUpdate = &update{
latestGasPriceUpdate = &gasPriceUpdate{
timestamp: inflight.createdAt,
value: inflight.priceUpdates.UsdPerUnitGas,
value: parseEncodedGasPrice(inflight.priceUpdates.UsdPerUnitGas),
}
latestEpochAndRound = inflight.epochAndRound
continue
Expand All @@ -92,22 +92,22 @@ func (c *inflightCommitReportsContainer) getLatestInflightGasPriceUpdate() *upda
}

// latestInflightTokenPriceUpdates returns a map of the latest token price updates
func (c *inflightCommitReportsContainer) latestInflightTokenPriceUpdates() map[common.Address]update {
func (c *inflightCommitReportsContainer) latestInflightTokenPriceUpdates() map[common.Address]tokenPriceUpdate {
c.locker.RLock()
defer c.locker.RUnlock()
latestTokenPriceUpdates := make(map[common.Address]update)
latestTokenPriceUpdates := make(map[common.Address]tokenPriceUpdate)
latestEpochAndRounds := make(map[common.Address]uint64)
for _, inflight := range c.inFlightPriceUpdates {
for _, inflightTokenUpdate := range inflight.priceUpdates.TokenPriceUpdates {
if _, ok := latestTokenPriceUpdates[inflightTokenUpdate.SourceToken]; !ok {
latestTokenPriceUpdates[inflightTokenUpdate.SourceToken] = update{
latestTokenPriceUpdates[inflightTokenUpdate.SourceToken] = tokenPriceUpdate{
value: inflightTokenUpdate.UsdPerToken,
timestamp: inflight.createdAt,
}
latestEpochAndRounds[inflightTokenUpdate.SourceToken] = inflight.epochAndRound
}
if inflight.epochAndRound > latestEpochAndRounds[inflightTokenUpdate.SourceToken] {
latestTokenPriceUpdates[inflightTokenUpdate.SourceToken] = update{
latestTokenPriceUpdates[inflightTokenUpdate.SourceToken] = tokenPriceUpdate{
value: inflightTokenUpdate.UsdPerToken,
timestamp: inflight.createdAt,
}
Expand Down
10 changes: 10 additions & 0 deletions core/services/ocr2/plugins/ccip/commit_plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
libocr2 "github.com/smartcontractkit/libocr/offchainreporting2plus"

relaylogger "github.com/smartcontractkit/chainlink-relay/pkg/logger"

"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata"
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/hashlib"
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/oraclelib"
Expand Down Expand Up @@ -63,6 +64,14 @@ func NewCommitServices(lggr logger.Logger, jb job.Job, chainSet evm.LegacyChainC
if err != nil {
return nil, errors.Wrap(err, "failed getting the static config from the commitStore")
}
typeAndVersion, err := commitStore.TypeAndVersion(&bind.CallOpts{})
Copy link
Collaborator

Choose a reason for hiding this comment

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

Maybe we should change the loaders to also return the version, as we already parse it in LoadCommitStore

if err != nil {
return nil, errors.Wrap(err, "failed to get type and version")
}
_, commitStoreVersion, err := ccipconfig.ParseTypeAndVersion(typeAndVersion)
if err != nil {
return nil, errors.Wrap(err, "failed to parse commitStore type and version")
}
chainId, err := chainselectors.ChainIdFromSelector(staticConfig.SourceChainSelector)
if err != nil {
return nil, err
Expand Down Expand Up @@ -119,6 +128,7 @@ func NewCommitServices(lggr logger.Logger, jb job.Job, chainSet evm.LegacyChainC
commitStore: commitStore,
leafHasher: leafHasher,
checkFinalityTags: sourceChain.Config().EVM().FinalityTagEnabled(),
commitStoreVersion: commitStoreVersion,
})

err = wrappedPluginFactory.UpdateLogPollerFilters(zeroAddress, qopts...)
Expand Down
141 changes: 92 additions & 49 deletions core/services/ocr2/plugins/ccip/commit_reporting_plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,16 @@ var (
_ types.ReportingPlugin = &CommitReportingPlugin{}
)

type update struct {
type tokenPriceUpdate struct {
timestamp time.Time
value *big.Int
}

type gasPriceUpdate struct {
timestamp time.Time
value GasPrice
}

type CommitPluginConfig struct {
lggr logger.Logger
sourceLP, destLP logpoller.LogPoller
Expand All @@ -68,6 +73,7 @@ type CommitPluginConfig struct {
sourceClient, destClient evmclient.Client
leafHasher hashlib.LeafHasherInterface[[32]byte]
checkFinalityTags bool
commitStoreVersion string
}

type CommitReportingPlugin struct {
Expand Down Expand Up @@ -104,7 +110,7 @@ func (rf *CommitReportingPluginFactory) NewReportingPlugin(config types.Reportin
if err != nil {
return nil, types.ReportingPluginInfo{}, err
}
offchainConfig, err := ccipconfig.DecodeOffchainConfig[ccipconfig.CommitOffchainConfig](config.OffchainConfig)
offchainConfig, err := DecodeCommitStoreOffchainConfig(rf.config.commitStoreVersion, config.OffchainConfig)
if err != nil {
return nil, types.ReportingPluginInfo{}, err
}
Expand Down Expand Up @@ -296,7 +302,7 @@ func (r *CommitReportingPlugin) generatePriceUpdates(
ctx context.Context,
lggr logger.Logger,
tokenDecimals map[common.Address]uint8,
) (sourceGasPriceUSD *big.Int, tokenPricesUSD map[common.Address]*big.Int, err error) {
) (sourceGasPriceUSD GasPrice, tokenPricesUSD map[common.Address]*big.Int, err error) {
tokensWithDecimal := make([]common.Address, 0, len(tokenDecimals))
for token := range tokenDecimals {
tokensWithDecimal = append(tokensWithDecimal, token)
Expand All @@ -309,20 +315,20 @@ func (r *CommitReportingPlugin) generatePriceUpdates(

rawTokenPricesUSD, err := r.config.priceGetter.TokenPricesUSD(ctx, queryTokens)
if err != nil {
return nil, nil, err
return GasPrice{}, nil, err
}
lggr.Infow("Raw token prices", "rawTokenPrices", rawTokenPricesUSD)

// make sure that we got prices for all the tokens of our query
for _, token := range queryTokens {
if rawTokenPricesUSD[token] == nil {
return nil, nil, errors.Errorf("missing token price: %+v", token)
return GasPrice{}, nil, errors.Errorf("missing token price: %+v", token)
}
}

sourceNativePriceUSD, exists := rawTokenPricesUSD[r.config.sourceNative]
if !exists {
return nil, nil, fmt.Errorf("missing source native (%s) price", r.config.sourceNative)
return GasPrice{}, nil, fmt.Errorf("missing source native (%s) price", r.config.sourceNative)
}

tokenPricesUSD = make(map[common.Address]*big.Int, len(rawTokenPricesUSD))
Expand All @@ -339,17 +345,35 @@ func (r *CommitReportingPlugin) generatePriceUpdates(
// Observe a source chain price for pricing.
sourceGasPriceWei, _, err := r.config.sourceFeeEstimator.GetFee(ctx, nil, 0, assets.NewWei(big.NewInt(int64(r.offchainConfig.MaxGasPrice))))
if err != nil {
return nil, nil, err
return GasPrice{}, nil, err
}
// Use legacy if no dynamic is available.
gasPrice := sourceGasPriceWei.Legacy.ToInt()
if sourceGasPriceWei.DynamicFeeCap != nil {
gasPrice = sourceGasPriceWei.DynamicFeeCap.ToInt()
}
if gasPrice == nil {
return nil, nil, fmt.Errorf("missing gas price %+v", sourceGasPriceWei)
return GasPrice{}, nil, fmt.Errorf("missing gas price %+v", sourceGasPriceWei)
}

sourceNativeGasPriceUSD := calculateUsdPerUnitGas(gasPrice, sourceNativePriceUSD)
sourceGasPriceUSD = GasPrice{
DAGasPrice: big.NewInt(0),
NativeGasPrice: sourceNativeGasPriceUSD,
}

// If l1 oracle exists, l1 gas price is a price component of overall tx, need to fetch and encode l1 gas price.
Copy link
Collaborator

@connorwstein connorwstein Sep 21, 2023

Choose a reason for hiding this comment

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

seems very hard to follow what will happen with different versions here and the plugin doesn't need to know any of these details. I think we can abstract all of this into 2 helper components (which wrap gas.EvmGasEstimator) one for 1.0/1.1 and one for 1.2 which implement a common interface that the plugin uses. Something like:

type GasPriceEstimator interface {
	EstimateGasPrice() (GasPrice, error) // plugin calls this then EncodeGasPrice in Observe
	EncodeGasPrice(GasPrice) ([]byte, error) // encodes according to version
	DecodeGasPrice([]byte)(GasPrice, error) //  decodes according to version
}

type GasPrice interface {
	String() string // for logging
	Cmp(GasPrice) int // Used for deviation and median
}

When we instantiate the plugin:

var gasPriceEstimator GasPriceEstimator
switch commitVersion 
case 1_0, 1_1 {
    gasPriceEstimator = NewV1GasPriceEstimator() // native fees only
} case 1_2 {
    gasPriceEstimator = NewV2GasPriceEstimator() // native fees and da
} default {
	error
}
commitPlugin{gasPriceEstimator: gasPriceEstimator...}

Has an added benefit of improving testability, smaller interface injected vs the whole gas.EvmFeeEstimator and it will help reduce duplicate code in the exec plugin I think

if l1Oracle := r.config.sourceFeeEstimator.L1Oracle(); l1Oracle != nil {
l1GasPriceWei, err := l1Oracle.GasPrice(ctx)
if err != nil {
return GasPrice{}, nil, err
}

if l1GasPrice := l1GasPriceWei.ToInt(); l1GasPrice.Cmp(big.NewInt(0)) > 0 {
// This assumes l1GasPrice is priced using the same native token as l2 native
sourceGasPriceUSD.DAGasPrice = calculateUsdPerUnitGas(l1GasPrice, sourceNativePriceUSD)
}
}
sourceGasPriceUSD = calculateUsdPerUnitGas(gasPrice, sourceNativePriceUSD)

lggr.Infow("Observing gas price", "observedGasPriceWei", gasPrice, "observedGasPriceUSD", sourceGasPriceUSD)
lggr.Infow("Observing token prices", "tokenPrices", tokenPricesUSD, "sourceNativePriceUSD", sourceNativePriceUSD)
Expand All @@ -366,24 +390,24 @@ func calculateUsdPer1e18TokenAmount(price *big.Int, decimals uint8) *big.Int {

// Gets the latest token price updates based on logs within the heartbeat
// The updates returned by this function are guaranteed to not contain nil values.
func (r *CommitReportingPlugin) getLatestTokenPriceUpdates(ctx context.Context, now time.Time, checkInflight bool) (map[common.Address]update, error) {
func (r *CommitReportingPlugin) getLatestTokenPriceUpdates(ctx context.Context, now time.Time, checkInflight bool) (map[common.Address]tokenPriceUpdate, error) {
tokenPriceUpdates, err := r.config.destReader.GetTokenPriceUpdatesCreatedAfter(
ctx,
r.destPriceRegistry.Address(),
now.Add(-r.offchainConfig.FeeUpdateHeartBeat.Duration()),
now.Add(-r.offchainConfig.TokenPriceHeartBeat.Duration()),
0,
)
if err != nil {
return nil, err
}

latestUpdates := make(map[common.Address]update)
for _, tokenPriceUpdate := range tokenPriceUpdates {
priceUpdate := tokenPriceUpdate.Data
latestUpdates := make(map[common.Address]tokenPriceUpdate)
for _, tokenUpdate := range tokenPriceUpdates {
priceUpdate := tokenUpdate.Data
// Ordered by ascending timestamps
timestamp := time.Unix(priceUpdate.Timestamp.Int64(), 0)
if priceUpdate.Value != nil && !timestamp.Before(latestUpdates[priceUpdate.Token].timestamp) {
latestUpdates[priceUpdate.Token] = update{
latestUpdates[priceUpdate.Token] = tokenPriceUpdate{
timestamp: timestamp,
value: priceUpdate.Value,
}
Expand All @@ -407,18 +431,18 @@ func (r *CommitReportingPlugin) getLatestTokenPriceUpdates(ctx context.Context,
}

// Gets the latest gas price updates based on logs within the heartbeat
func (r *CommitReportingPlugin) getLatestGasPriceUpdate(ctx context.Context, now time.Time, checkInflight bool) (gasPriceUpdate update, error error) {
func (r *CommitReportingPlugin) getLatestGasPriceUpdate(ctx context.Context, now time.Time, checkInflight bool) (gasUpdate gasPriceUpdate, error error) {
if checkInflight {
latestInflightGasPriceUpdate := r.inflightReports.getLatestInflightGasPriceUpdate()
if latestInflightGasPriceUpdate != nil && latestInflightGasPriceUpdate.timestamp.After(gasPriceUpdate.timestamp) {
gasPriceUpdate = *latestInflightGasPriceUpdate
if latestInflightGasPriceUpdate != nil && latestInflightGasPriceUpdate.timestamp.After(gasUpdate.timestamp) {
gasUpdate = *latestInflightGasPriceUpdate
}

if gasPriceUpdate.value != nil {
r.lggr.Infow("Latest gas price from inflight", "gasPriceUpdateVal", gasPriceUpdate.value, "gasPriceUpdateTs", gasPriceUpdate.timestamp)
if gasUpdate.value.notNil() {
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think clarity would be improved if we just explicitly return a boolean indicating whether there is a prior gas price update and remove this "notNil means no update"

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Can change getLatestInflightGasPriceUpdate to return (update, bool) as opposed to *update.
Per my understanding a priori gas price update where chain selector is not 0 should never contain a gas value that's nil, was this nil check more intended as defensive code?

Copy link
Collaborator Author

@matYang matYang Sep 26, 2023

Choose a reason for hiding this comment

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

Checks removed

r.lggr.Infow("Latest gas price from inflight", "gasPriceUpdateVal", gasUpdate.value, "gasPriceUpdateTs", gasUpdate.timestamp)
// Gas price can fluctuate frequently, many updates may be in flight.
// If there is gas price update inflight, use it as source of truth, no need to check onchain.
return gasPriceUpdate, nil
return gasUpdate, nil
}
}

Expand All @@ -427,29 +451,29 @@ func (r *CommitReportingPlugin) getLatestGasPriceUpdate(ctx context.Context, now
ctx,
r.destPriceRegistry.Address(),
r.config.sourceChainSelector,
now.Add(-r.offchainConfig.FeeUpdateHeartBeat.Duration()),
now.Add(-r.offchainConfig.GasPriceHeartBeat.Duration()),
0,
)
if err != nil {
return update{}, err
return gasPriceUpdate{}, err
}

for _, priceUpdate := range gasPriceUpdates {
// Ordered by ascending timestamps
timestamp := time.Unix(priceUpdate.Data.Timestamp.Int64(), 0)
if !timestamp.Before(gasPriceUpdate.timestamp) {
gasPriceUpdate = update{
if !timestamp.Before(gasUpdate.timestamp) {
gasUpdate = gasPriceUpdate{
timestamp: timestamp,
value: priceUpdate.Data.Value,
value: parseEncodedGasPrice(priceUpdate.Data.Value),
}
}
}

if gasPriceUpdate.value != nil {
r.lggr.Infow("Latest gas price from log poller", "gasPriceUpdateVal", gasPriceUpdate.value, "gasPriceUpdateTs", gasPriceUpdate.timestamp)
if gasUpdate.value.notNil() {
r.lggr.Infow("Latest gas price from log poller", "gasPriceUpdateVal", gasUpdate.value, "gasPriceUpdateTs", gasUpdate.timestamp)
}

return gasPriceUpdate, nil
return gasUpdate, nil
}

func (r *CommitReportingPlugin) Report(ctx context.Context, epochAndRound types.ReportTimestamp, _ types.Query, observations []types.AttributedObservation) (bool, types.Report, error) {
Expand Down Expand Up @@ -572,12 +596,12 @@ func calculateIntervalConsensus(intervals []commit_store.CommitStoreInterval, f

// Note priceUpdates must be deterministic.
// The provided latestTokenPrices should not contain nil values.
func (r *CommitReportingPlugin) calculatePriceUpdates(observations []CommitObservation, latestGasPrice update, latestTokenPrices map[common.Address]update) commit_store.InternalPriceUpdates {
func (r *CommitReportingPlugin) calculatePriceUpdates(observations []CommitObservation, latestGasPrice gasPriceUpdate, latestTokenPrices map[common.Address]tokenPriceUpdate) commit_store.InternalPriceUpdates {
priceObservations := make(map[common.Address][]*big.Int)
var sourceGasObservations []*big.Int
var sourceGasObservations []GasPrice

for _, obs := range observations {
if obs.SourceGasPriceUSD != nil {
if obs.SourceGasPriceUSD.notNil() {
Copy link
Collaborator

Choose a reason for hiding this comment

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

aside: we should move this validation into getParseableObservations and we should similarly move the > r.F check into the top level report instead of spread out in 3 places. Just consider observations all or nothing

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

seems tricky, since interval | token price | gas price are validated individually, e.g. an Observation where gas price is nil can contain valid values for token price and/or interval, I think it'd still make sense to check them separately

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Communicated on Slack, decision is to reject Observations if any price field is nil, since with current impl, non-faulty nodes should not produce observations with nil fields.

// Add only non-nil source gas price
sourceGasObservations = append(sourceGasObservations, obs.SourceGasPriceUSD)
}
Expand All @@ -600,8 +624,8 @@ func (r *CommitReportingPlugin) calculatePriceUpdates(observations []CommitObser

latestTokenPrice, exists := latestTokenPrices[token]
if exists {
tokenPriceUpdatedRecently := time.Since(latestTokenPrice.timestamp) < r.offchainConfig.FeeUpdateHeartBeat.Duration()
tokenPriceNotChanged := !deviates(medianPrice, latestTokenPrice.value, int64(r.offchainConfig.FeeUpdateDeviationPPB))
tokenPriceUpdatedRecently := time.Since(latestTokenPrice.timestamp) < r.offchainConfig.TokenPriceHeartBeat.Duration()
tokenPriceNotChanged := !deviates(medianPrice, latestTokenPrice.value, int64(r.offchainConfig.TokenPriceDeviationPPB))
if tokenPriceUpdatedRecently && tokenPriceNotChanged {
r.lggr.Debugw("price was updated recently, skipping the update",
"token", token, "newPrice", medianPrice, "existingPrice", latestTokenPrice.value)
Expand All @@ -620,18 +644,32 @@ func (r *CommitReportingPlugin) calculatePriceUpdates(observations []CommitObser
return bytes.Compare(tokenPriceUpdates[i].SourceToken[:], tokenPriceUpdates[j].SourceToken[:]) == -1
})

usdPerUnitGas := big.NewInt(0)
newGasPrice := GasPrice{}
destChainSelector := uint64(0)

if len(sourceGasObservations) > r.F {
usdPerUnitGas = median(sourceGasObservations) // Compute the median price
var daGasPrices []*big.Int
var nativeGasPrices []*big.Int
for _, o := range sourceGasObservations {
daGasPrices = append(daGasPrices, o.DAGasPrice)
nativeGasPrices = append(nativeGasPrices, o.NativeGasPrice)
}
newGasPrice = GasPrice{
DAGasPrice: median(daGasPrices), // Compute the median data availability gas price
NativeGasPrice: median(nativeGasPrices), // Compute the median nativ gas price
}

destChainSelector = r.config.sourceChainSelector // Assuming plugin lane is A->B, we write to B the gas price of A

if latestGasPrice.value != nil {
gasPriceUpdatedRecently := time.Since(latestGasPrice.timestamp) < r.offchainConfig.FeeUpdateHeartBeat.Duration()
gasPriceNotChanged := !deviates(usdPerUnitGas, latestGasPrice.value, int64(r.offchainConfig.FeeUpdateDeviationPPB))
if latestGasPrice.value.notNil() {
gasPriceUpdatedRecently := time.Since(latestGasPrice.timestamp) < r.offchainConfig.GasPriceHeartBeat.Duration()
gasPriceNotChanged := !deviates(newGasPrice.DAGasPrice, latestGasPrice.value.DAGasPrice, int64(r.offchainConfig.DAGasPriceDeviationPPB)) && !deviates(newGasPrice.NativeGasPrice, latestGasPrice.value.NativeGasPrice, int64(r.offchainConfig.NativeGasPriceDeviationPPB))

if gasPriceUpdatedRecently && gasPriceNotChanged {
usdPerUnitGas = big.NewInt(0)
newGasPrice = GasPrice{
DAGasPrice: big.NewInt(0),
NativeGasPrice: big.NewInt(0),
}
destChainSelector = uint64(0)
}
}
Expand All @@ -640,7 +678,7 @@ func (r *CommitReportingPlugin) calculatePriceUpdates(observations []CommitObser
return commit_store.InternalPriceUpdates{
TokenPriceUpdates: tokenPriceUpdates,
DestChainSelector: destChainSelector,
UsdPerUnitGas: usdPerUnitGas, // we MUST pass zero to skip the update (never nil)
UsdPerUnitGas: newGasPrice.encode(), // we MUST pass zero to skip the update (never nil)
}
}

Expand Down Expand Up @@ -818,17 +856,22 @@ func (r *CommitReportingPlugin) isStaleMerkleRoot(ctx context.Context, lggr logg
}

func (r *CommitReportingPlugin) isStaleGasPrice(ctx context.Context, lggr logger.Logger, priceUpdates commit_store.InternalPriceUpdates, checkInflight bool) bool {
gasPriceUpdate, err := r.getLatestGasPriceUpdate(ctx, time.Now(), checkInflight)
latestGasPrice, err := r.getLatestGasPriceUpdate(ctx, time.Now(), checkInflight)
if err != nil {
return true
}

if gasPriceUpdate.value != nil && !deviates(priceUpdates.UsdPerUnitGas, gasPriceUpdate.value, int64(r.offchainConfig.FeeUpdateDeviationPPB)) {
lggr.Infow("Report is stale because of gas price",
"latestGasPriceUpdate", gasPriceUpdate.value,
"usdPerUnitGas", priceUpdates.UsdPerUnitGas,
"destChainSelector", priceUpdates.DestChainSelector)
return true
if latestGasPrice.value.notNil() {
newGasPrice := parseEncodedGasPrice(priceUpdates.UsdPerUnitGas)
gasPriceNotChanged := !deviates(newGasPrice.DAGasPrice, latestGasPrice.value.NativeGasPrice, int64(r.offchainConfig.DAGasPriceDeviationPPB)) && !deviates(newGasPrice.NativeGasPrice, latestGasPrice.value.NativeGasPrice, int64(r.offchainConfig.NativeGasPriceDeviationPPB))

if gasPriceNotChanged {
lggr.Infow("Report is stale because of gas price",
"latestGasPriceUpdate", latestGasPrice.value,
"usdPerUnitGas", priceUpdates.UsdPerUnitGas,
"destChainSelector", priceUpdates.DestChainSelector)
return true
}
}

return false
Expand All @@ -844,7 +887,7 @@ func (r *CommitReportingPlugin) isStaleTokenPrices(ctx context.Context, lggr log

for _, tokenUpdate := range priceUpdates {
latestUpdate, ok := latestTokenPriceUpdates[tokenUpdate.SourceToken]
priceEqual := ok && !deviates(tokenUpdate.UsdPerToken, latestUpdate.value, int64(r.offchainConfig.FeeUpdateDeviationPPB))
priceEqual := ok && !deviates(tokenUpdate.UsdPerToken, latestUpdate.value, int64(r.offchainConfig.TokenPriceDeviationPPB))

if !priceEqual {
lggr.Infow("Found non-stale token price", "token", tokenUpdate.SourceToken, "usdPerToken", tokenUpdate.UsdPerToken, "latestUpdate", latestUpdate.value)
Expand Down
Loading