feat(gas_oracle): implement median-based priority fee suggestion for Optimism (#16794)

This commit is contained in:
Mablr
2025-06-14 17:29:01 +02:00
committed by GitHub
parent 82e9988049
commit bb4bf298ec
2 changed files with 74 additions and 3 deletions

View File

@@ -244,9 +244,8 @@ where
}
async fn suggested_priority_fee(&self) -> Result<U256, Self::Error> {
let base_tip = self.inner.eth_api.gas_oracle().suggest_tip_cap().await?;
let min_tip = U256::from(self.inner.min_suggested_priority_fee);
Ok(base_tip.max(min_tip))
self.inner.eth_api.gas_oracle().op_suggest_tip_cap(min_tip).await.map_err(Into::into)
}
}

View File

@@ -2,7 +2,7 @@
//! previous blocks.
use super::{EthApiError, EthResult, EthStateCache, RpcInvalidTransactionError};
use alloy_consensus::{constants::GWEI_TO_WEI, BlockHeader, Transaction};
use alloy_consensus::{constants::GWEI_TO_WEI, BlockHeader, Transaction, TxReceipt};
use alloy_eips::BlockNumberOrTag;
use alloy_primitives::{B256, U256};
use alloy_rpc_types_eth::BlockId;
@@ -273,6 +273,78 @@ where
Ok(Some((parent_hash, prices)))
}
/// Suggests a max priority fee value using a simplified and more predictable algorithm
/// appropriate for chains like Optimism with a single known block builder.
///
/// It returns either:
/// - The minimum suggested priority fee when blocks have capacity
/// - 10% above the median effective priority fee from the last block when at capacity
///
/// A block is considered at capacity if its total gas used plus the maximum single transaction
/// gas would exceed the block's gas limit.
pub async fn op_suggest_tip_cap(&self, min_suggested_priority_fee: U256) -> EthResult<U256> {
let header = self
.provider
.sealed_header_by_number_or_tag(BlockNumberOrTag::Latest)?
.ok_or(EthApiError::HeaderNotFound(BlockId::latest()))?;
let mut inner = self.inner.lock().await;
// if we have stored a last price, then we check whether or not it was for the same head
if inner.last_price.block_hash == header.hash() {
return Ok(inner.last_price.price);
}
let mut suggestion = min_suggested_priority_fee;
// find the maximum gas used by any of the transactions in the block to use as the
// capacity margin for the block, if no receipts are found return the
// suggested_min_priority_fee
let Some(max_tx_gas_used) = self
.cache
.get_receipts(header.hash())
.await?
.ok_or(EthApiError::ReceiptsNotFound(BlockId::latest()))?
// get the gas used by each transaction in the block, by subtracting the
// cumulative gas used of the previous transaction from the cumulative gas used of the
// current transaction. This is because there is no gas_used() method on the Receipt
// trait.
.windows(2)
.map(|window| {
let prev = window[0].cumulative_gas_used();
let curr = window[1].cumulative_gas_used();
curr - prev
})
.max()
else {
return Ok(suggestion);
};
// if the block is at capacity, the suggestion must be increased
if header.gas_used() + max_tx_gas_used > header.gas_limit() {
let Some(median_tip) = self.get_block_median_tip(header.hash()).await? else {
return Ok(suggestion);
};
let new_suggestion = median_tip + median_tip / U256::from(10);
if new_suggestion > suggestion {
suggestion = new_suggestion;
}
}
// constrain to the max price
if let Some(max_price) = self.oracle_config.max_price {
if suggestion > max_price {
suggestion = max_price;
}
}
inner.last_price = GasPriceOracleResult { block_hash: header.hash(), price: suggestion };
Ok(suggestion)
}
/// Get the median tip value for the given block. This is useful for determining
/// tips when a block is at capacity.
///