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:

  1. Block Finalization Trigger – When a block reaches finality, the node's state watcher notifies the gas price service (StateWatcher::started()), initiating the update sequence.

  2. Metric Extraction – The service extracts the block's total execution gas used and total data bytes stored from the block header and receipts.

  3. 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.

  4. Dynamic Scaling

    • If avg_usage > high_watermarkexec_price = exec_price * (1 + change_percent)
    • If avg_usage < low_watermarkexec_price = exec_price * (1 - change_percent)
  5. DA Price Refresh – The DA source service supplies the current da_cost_per_byte, which the service multiplies by the configured da_gas_per_byte ratio to update the DA component.

  6. Persistence and Broadcast – The combined price is written atomically to GasPriceMetadata, and the service notifies awaiting RPC callers through its SharedData handle (await_synced), guaranteeing price continuity across node restarts and upgrades.

Key Source Files and Implementation

The algorithm implementation spans multiple crates within the repository:

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →