How the Gas Price Service in Fuel Core Adjusts Prices Based on Network Activity
The gas price service in Fuel Core continuously monitors block-level execution gas consumption and data-availability costs, applying a sliding-window average and dynamic scaling to keep transaction fees responsive to network congestion.
The gas price service operates as an autonomous background task within the Fuel Core node, ensuring that transaction fees reflect real-time network conditions. According to the FuelLabs/fuel-core source code, the service maintains three distinct price components—execution, data-availability (DA), and combined total—updating them after every finalized block through an asynchronous adjustment loop.
Components of the Gas Price Calculation
The algorithm tracks separate cost drivers that combine to form the final gas price presented to users and RPC clients.
Execution Gas Price
The execution gas price measures average computational demand across recent blocks. After each finalized block, the service reads the total execution gas consumption from the GasPriceMetadata table and maintains a simple moving average over a configurable window (default 30 blocks). When average usage exceeds a high-watermark threshold, the service increases the price by a configurable percentage; when usage drops below a low-watermark, it decreases the price proportionally.
DA Gas Price
The DA gas price reflects the cost of storing transaction data on the underlying data-availability layer (e.g., Celestia). The service queries the injected DA source service (fuel_core_gas_price_service::v1::da_source_service) to obtain the latest per-byte cost, then multiplies that value by a protocol-defined "bytes per gas" ratio to derive the per-gas DA price component.
Total Gas Price Calculation
The total gas price equals the sum of execution and DA prices, clamped between user-defined minimum and maximum bounds (min_gas_price and max_gas_price). The final value is atomically persisted to the GasPriceMetadata table and broadcast to the rest of the node via the shared gas_price_service handle, ensuring all components read identical pricing data.
The Block-Driven Adjustment Loop
The gas price service implements a six-step update cycle that triggers immediately upon block finalization:
-
Block Finalization Trigger – When a block reaches finality, the node's state watcher notifies the gas price service (
StateWatcher::started()), initiating the update sequence. -
Metric Extraction – The service extracts the block's total execution gas used and total data bytes stored from the block header and receipts.
-
Window-Based Averaging – A sliding window stores recent usage statistics. New values push into the window while the oldest values drop out, and the service recomputes the average gas consumption across the entire window.
-
Dynamic Scaling –
- If
avg_usage > high_watermark→exec_price = exec_price * (1 + change_percent) - If
avg_usage < low_watermark→exec_price = exec_price * (1 - change_percent)
- If
-
DA Price Refresh – The DA source service supplies the current
da_cost_per_byte, which the service multiplies by the configuredda_gas_per_byteratio to update the DA component. -
Persistence and Broadcast – The combined price is written atomically to
GasPriceMetadata, and the service notifies awaiting RPC callers through itsSharedDatahandle (await_synced), guaranteeing price continuity across node restarts and upgrades.
Key Source Files and Implementation
The algorithm implementation spans multiple crates within the repository:
-
crates/services/gas_price_service/src/v1/algorithm.rs– Contains the moving-average calculation and percentage-based scaling logic for execution price adjustments. -
crates/services/gas_price_service/src/v1/service.rs– Orchestrates the periodic update loop, coordinates DA cost fetching, and manages metadata persistence. -
crates/services/gas_price_service/src/v1/da_source_service/– Houses the DA layer integration that provides real-time per-byte storage costs. -
crates/services/gas_price_service/src/common/fuel_core_storage_adapter/storage.rs– Implements read/write operations for theGasPriceMetadatatable. -
crates/fuel-core/src/service/sub_services.rs– Bootstraps the gas price service and injects it into the node's main Service struct during initialization.
Code Examples
Querying the Current Gas Price via Node API
use fuel_core::service::Service;
use fuel_core_gas_price_service::v1::service::SharedData;
// Assume you have a running `service: Service` instance.
let shared = &service.runner.shared.gas_price_service;
let current = shared.await_synced().await?.latest_price();
println!("Current total gas price: {}", current.total);
Source: crates/fuel-core/src/service.rs
Core Price Adjustment Algorithm
fn update_price(
window: &mut Vec<u64>,
exec_price: &mut u64,
usage: u64,
high: u64,
low: u64,
change_pct: f64,
) {
// Slide window
if window.len() == WINDOW_SIZE {
window.remove(0);
}
window.push(usage);
// Calculate average usage
let avg: u64 = window.iter().sum::<u64>() / window.len() as u64;
// Adjust execution price based on watermark thresholds
if avg > high {
*exec_price = ((*exec_price as f64) * (1.0 + change_pct)).ceil() as u64;
} else if avg < low {
*exec_price = ((*exec_price as f64) * (1.0 - change_pct)).floor() as u64;
}
}
Source: crates/services/gas_price_service/src/v1/algorithm.rs
DA Price Refresh Pattern
// Fetch current DA layer cost and compute DA gas price component
let da_cost_per_byte = da_source_service.current_cost_per_byte().await?;
let da_price = da_cost_per_byte * config.da_gas_per_byte;
Source: crates/services/gas_price_service/src/v1/da_source_service/service.rs
Summary
- The gas price service in Fuel Core runs as an asynchronous background task that updates after every block finalization.
- Execution prices adjust based on a sliding-window average of gas consumption, scaling up or down when usage crosses configurable high or low watermarks.
- DA prices synchronize with external data-availability networks, converting per-byte storage costs into per-gas fees using a fixed ratio.
- All price components are atomically persisted to
GasPriceMetadata, ensuring nodes resume with accurate pricing after restarts. - The implementation resides primarily in
crates/services/gas_price_service/src/v1/, with clear separation between algorithm logic, DA integration, and storage adapters.
Frequently Asked Questions
How does Fuel Core determine when to increase gas prices?
The service compares the moving-average execution gas usage against a configurable high-watermark threshold. When the average exceeds this threshold, indicating network congestion, the algorithm multiplies the current execution price by (1 + change_percent) as defined in gas_price_config, typically implemented in algorithm.rs.
What is the data availability (DA) gas price component?
The DA component represents the cost to post transaction data to an external DA layer like Celestia. The gas price service queries the DA source service for the current da_cost_per_byte, then calculates the per-gas DA price by multiplying this value by the protocol's da_gas_per_byte conversion factor.
How does the gas price service handle node restarts?
Because the service writes the latest calculated price to the GasPriceMetadata table atomically before broadcasting it, any node that restarts reads the most recent price from the database during initialization. This design guarantees price continuity and prevents fee market disruption across upgrades or crashes.
Where is the gas price configuration defined?
Configuration parameters including window_size, high_watermark, low_watermark, change_percent, min_gas_price, and max_gas_price are defined in the gas price service configuration and injected during node startup in crates/fuel-core/src/service/sub_services.rs, allowing operators to tune the fee market responsiveness for their specific network conditions.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →