Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 630
feat(gas-oracle): support moving average base fee#1735
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
base:develop
Are you sure you want to change the base?
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
197b0a3277e71eecb00c14d9fd55500490294da5203dd9ab6File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -105,23 +105,20 @@ func NewLayer1Relayer(ctx context.Context, db *gorm.DB, cfg *config.RelayerConfi | ||
| // ProcessGasPriceOracle imports gas price to layer2 | ||
| func (r *Layer1Relayer) ProcessGasPriceOracle() { | ||
| r.metrics.rollupL1RelayerGasPriceOraclerRunTotal.Inc() | ||
| latestBlockHeight, err := r.l1BlockOrm.GetLatestL1BlockHeight(r.ctx) | ||
| if err != nil { | ||
| log.Warn("Failed to fetch latest L1 block height from db", "err", err) | ||
| return | ||
| } | ||
| blocks, err := r.l1BlockOrm.GetL1Blocks(r.ctx, map[string]interface{}{ | ||
| "number": latestBlockHeight, | ||
| }) | ||
| limit := r.cfg.GasOracleConfig.CalculateAverageFeesWindowSize | ||
| blocks, err := r.l1BlockOrm.GetLatestL1Blocks(r.ctx, limit) | ||
| if err != nil { | ||
| log.Error("Failed to GetL1Blocks from db", "height", latestBlockHeight, "err", err) | ||
| log.Error("Failed to GetLatestL1Blocks from db", "limit", limit, "err", err) | ||
| return | ||
| } | ||
| if len(blocks) != 1 { | ||
| log.Error("Block not exist", "height", latestBlockHeight) | ||
| // nothing to do if we don't have any l1 blocks | ||
| if len(blocks) == 0 { | ||
| log.Warn("No l1 blocks to process", "limit", limit) | ||
| return | ||
| } | ||
| block := blocks[0] | ||
| if types.GasOracleStatus(block.GasOracleStatus) == types.GasOraclePending { | ||
| @@ -130,8 +127,8 @@ func (r *Layer1Relayer) ProcessGasPriceOracle() { | ||
| return | ||
| } | ||
| baseFee := block.BaseFee | ||
| blobBaseFee := block.BlobBaseFee | ||
| // calculate the average base fee and blob base fee of the last N blocks | ||
| baseFee, blobBaseFee := r.calculateAverageFees(blocks) | ||
Contributor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Many places below still use
| ||
| // include the token exchange rate in the fee data if alternative gas token enabled | ||
| if r.cfg.GasOracleConfig.AlternativeGasTokenConfig != nil && r.cfg.GasOracleConfig.AlternativeGasTokenConfig.Enabled { | ||
| @@ -154,16 +151,32 @@ func (r *Layer1Relayer) ProcessGasPriceOracle() { | ||
| log.Error("Invalid exchange rate", "exchangeRate", exchangeRate) | ||
| return | ||
| } | ||
| baseFee = uint64(math.Ceil(float64(baseFee) / exchangeRate)) | ||
| blobBaseFee = uint64(math.Ceil(float64(blobBaseFee) / exchangeRate)) | ||
| // Check for overflow in exchange rate calculation | ||
| adjustedBaseFee := math.Ceil(float64(baseFee) / exchangeRate) | ||
| adjustedBlobBaseFee := math.Ceil(float64(blobBaseFee) / exchangeRate) | ||
| if adjustedBaseFee > float64(^uint64(0)) { | ||
| log.Error("Base fee overflow after exchange rate adjustment", "originalBaseFee", baseFee, "exchangeRate", exchangeRate, "adjustedBaseFee", adjustedBaseFee) | ||
| baseFee = ^uint64(0) // Set to max uint64 | ||
| } else { | ||
| baseFee = uint64(adjustedBaseFee) | ||
| } | ||
| if adjustedBlobBaseFee > float64(^uint64(0)) { | ||
| log.Error("Blob base fee overflow after exchange rate adjustment", "originalBlobBaseFee", blobBaseFee, "exchangeRate", exchangeRate, "adjustedBlobBaseFee", adjustedBlobBaseFee) | ||
| blobBaseFee = ^uint64(0) // Set to max uint64 | ||
| } else { | ||
| blobBaseFee = uint64(adjustedBlobBaseFee) | ||
| } | ||
| } | ||
| if r.shouldUpdateGasOracle(baseFee, blobBaseFee) { | ||
| // It indicates the committing batch has been stuck for a long time, it's likely that the L1 gas fee spiked. | ||
| // If we are not committing batches due to high fees then we shouldn't update fees to prevent users from paying high l1_data_fee | ||
| // Also, set fees to some default value, because we have already updated fees to some high values, probably | ||
| var reachTimeout bool | ||
| if reachTimeout, err = r.commitBatchReachTimeout(); reachTimeout && block.BlobBaseFee > r.cfg.GasOracleConfig.L1BlobBaseFeeThreshold && err == nil { | ||
| if reachTimeout, err = r.commitBatchReachTimeout(); reachTimeout && blobBaseFee > r.cfg.GasOracleConfig.L1BlobBaseFeeThreshold && err == nil { | ||
| if r.lastBaseFee == r.cfg.GasOracleConfig.L1BaseFeeDefault && r.lastBlobBaseFee == r.cfg.GasOracleConfig.L1BlobBaseFeeDefault { | ||
| return | ||
| } | ||
| @@ -175,13 +188,13 @@ func (r *Layer1Relayer) ProcessGasPriceOracle() { | ||
| } | ||
| data, err := r.l1GasOracleABI.Pack("setL1BaseFeeAndBlobBaseFee", new(big.Int).SetUint64(baseFee), new(big.Int).SetUint64(blobBaseFee)) | ||
| if err != nil { | ||
| log.Error("Failed to pack setL1BaseFeeAndBlobBaseFee", "block.Hash", block.Hash, "block.Height", block.Number, "block.BaseFee", baseFee, "block.BlobBaseFee", blobBaseFee, "err", err) | ||
| log.Error("Failed to pack setL1BaseFeeAndBlobBaseFee", "block.Hash", block.Hash, "block.Height", block.Number, "baseFee", baseFee, "blobBaseFee", blobBaseFee, "err", err) | ||
| return | ||
| } | ||
| txHash, _, err := r.gasOracleSender.SendTransaction(block.Hash, &r.cfg.GasPriceOracleContractAddress, data, nil) | ||
| if err != nil { | ||
| log.Error("Failed to send gas oracle update tx to layer2", "block.Hash", block.Hash, "block.Height", block.Number, "block.BaseFee", baseFee, "block.BlobBaseFee", blobBaseFee, "err", err) | ||
| log.Error("Failed to send gas oracle update tx to layer2", "block.Hash", block.Hash, "block.Height", block.Number, "baseFee", baseFee, "blobBaseFee", blobBaseFee, "err", err) | ||
| return | ||
| } | ||
| @@ -287,3 +300,44 @@ func (r *Layer1Relayer) commitBatchReachTimeout() (bool, error) { | ||
| // Because batches[0].CommittedAt is nil in this case, this will only continue for a short time window. | ||
| return len(batches) == 0 || (batches[0].Index != 0 && batches[0].CommittedAt != nil && utils.NowUTC().Sub(*batches[0].CommittedAt) > time.Duration(r.cfg.GasOracleConfig.CheckCommittedBatchesWindowMinutes)*time.Minute), nil | ||
| } | ||
| // calculateAverageFees returns the average base fee and blob base fee. | ||
| // Uses big.Int for intermediate calculations to avoid overflow. | ||
| func (r *Layer1Relayer) calculateAverageFees(blocks []orm.L1Block) (avgBaseFee uint64, avgBlobBaseFee uint64) { | ||
| if len(blocks) == 0 { | ||
| return 0, 0 | ||
| } | ||
| // Use big.Int to handle large sums without overflow | ||
| totalBaseFee := big.NewInt(0) | ||
| totalBlobBaseFee := big.NewInt(0) | ||
| count := big.NewInt(int64(len(blocks))) | ||
| for _, b := range blocks { | ||
| totalBaseFee.Add(totalBaseFee, big.NewInt(0).SetUint64(b.BaseFee)) | ||
| totalBlobBaseFee.Add(totalBlobBaseFee, big.NewInt(0).SetUint64(b.BlobBaseFee)) | ||
| } | ||
| // Calculate averages | ||
| avgBaseFeeBig := big.NewInt(0).Div(totalBaseFee, count) | ||
| avgBlobBaseFeeBig := big.NewInt(0).Div(totalBlobBaseFee, count) | ||
| // Check if results fit in uint64 | ||
| maxUint64 := big.NewInt(0).SetUint64(^uint64(0)) | ||
| if avgBaseFeeBig.Cmp(maxUint64) > 0 { | ||
| log.Error("Average base fee exceeds uint64 max, capping at max value", "calculatedAvg", avgBaseFeeBig.String()) | ||
| avgBaseFee = ^uint64(0) | ||
| } else { | ||
| avgBaseFee = avgBaseFeeBig.Uint64() | ||
| } | ||
| if avgBlobBaseFeeBig.Cmp(maxUint64) > 0 { | ||
| log.Error("Average blob base fee exceeds uint64 max, capping at max value", "calculatedAvg", avgBlobBaseFeeBig.String()) | ||
| avgBlobBaseFee = ^uint64(0) | ||
| } else { | ||
| avgBlobBaseFee = avgBlobBaseFeeBig.Uint64() | ||
| } | ||
| return avgBaseFee, avgBlobBaseFee | ||
| } | ||
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 this the oldest or newest block?
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.
it's the newest block.