How the Relayer Service Enables Communication Between Fuel and Ethereum

The relayer service bridges Fuel and Ethereum by fetching Ethereum events through host functions, storing them in the node's database, and exposing them to the WASM executor via the RelayerPort trait.

The fuel-core node from FuelLabs uses a specialized relayer service to enable seamless cross-chain communication between the Fuel blockchain and Ethereum's data-availability layer. This service acts as a critical bridge that allows Fuel to ingest and process Ethereum events, making them available for execution within the Fuel environment.

Architecture of the Relayer Service

The relayer architecture consists of three distinct layers that work together to move data from Ethereum into Fuel's execution environment.

The WASM Executor Interface

At the execution layer, the WasmRelayer struct in crates/services/upgradable-executor/wasm-executor/src/relayer.rs implements the RelayerPort trait. This provides a clean interface for WASM contracts to query relayer functionality without direct access to host resources.

// crates/services/upgradable-executor/wasm-executor/src/relayer.rs
impl RelayerPort for WasmRelayer {
    fn enabled(&self) -> bool {
        ext::relayer_enabled()
    }
    fn get_events(&self, da_block_height: &DaBlockHeight) -> anyhow::Result<Vec<Event>> {
        ext::relayer_get_events(*da_block_height)
    }
}

Host Function Bindings

The ext.rs module in crates/services/upgradable-executor/wasm-executor/src/ext.rs wraps low-level host functions with safe Rust interfaces. These functions communicate directly with the Ethereum DA layer via RPC, decode returned events using postcard serialization, and return them as fuel_core_types::services::relayer::Event instances.

// crates/services/upgradable-executor/wasm-executor/src/ext.rs
pub fn relayer_enabled() -> bool {
    unsafe { host::relayer_enabled() }
}
pub fn relayer_get_events(da_block_height: DaBlockHeight) -> anyhow::Result<Vec<Event>> {
    // …call host::relayer_size_of_events & host::relayer_get_events, decode with postcard…
}

Database Storage and Retrieval

Once fetched, events persist in the node's key-value store through the Database<Relayer> adapter located in crates/fuel-core/src/service/adapters/relayer.rs. The get_events method retrieves stored EventsHistory for a specific DA block height, decoupling the relayer runtime from other node components.

// crates/fuel-core/src/service/adapters/relayer.rs
impl Database<Relayer> {
    pub fn get_events(&self, da_height: &DaBlockHeight) -> StorageResult<Vec<Event>> {
        self.latest_view()?
            .storage_as_ref::<fuel_core_relayer::storage::EventsHistory>()
            .get(da_height)?
            .unwrap_or_default()
            .into_owned()
    }
}

Execution Flow: From Ethereum to Fuel Blocks

The relayer service operates through a five-step pipeline that moves Ethereum data into Fuel's execution environment:

  1. WASM Executor Query: During contract execution, the WASM runtime calls relayer_enabled or relayer_get_events through the RelayerPort interface.
  2. Host Function Execution: The ext.rs wrappers invoke underlying host functions that query the Ethereum DA contract via RPC.
  3. Background Sync: The relayer service task (in crates/services/relayer) polls for new DA heights, downloads missing Ethereum logs, and writes them to the database.
  4. Database Persistence: Events store in the relayer column family via Database<Relayer>.
  5. Block Inclusion: The executor reads these events to include bridge messages and transactions in Fuel blocks, completing the cross-chain communication cycle.

Key Code Examples

Checking Relayer Status from WASM:

let enabled = ext::relayer_enabled(); // returns `true` if the relayer feature is compiled

Fetching Ethereum Events for a Specific Block:

let da_height = DaBlockHeight::new(12345);
let events = ext::relayer_get_events(da_height)?; // Vec<Event>
for ev in events {
    // process Message or Transaction events
}

Querying Persisted Events from the Node:

let db: Database<Relayer> = ...; // obtained from node context
let events = db.get_events(&da_height)?;
println!("Fetched {} relayer events", events.len());

Critical Source Files

File Role
crates/services/upgradable-executor/wasm-executor/src/relayer.rs WasmRelayer implementing the RelayerPort trait.
crates/services/upgradable-executor/wasm-executor/src/ext.rs Host‑side wrappers for relayer_enabled and relayer_get_events.
crates/fuel-core/src/service/adapters/relayer.rs Database adapter exposing get_events.
crates/types/src/services/relayer.rs Public Event enum (Message / Transaction) used throughout the stack.
crates/services/upgradable-executor/src/instance.rs (section add_relayer) Registers the relayer host functions (relayer_enabled, relayer_size_of_events, relayer_get_events) for WASM modules.
crates/services/relayer/README.md High‑level design description of the relayer background task.

Summary

  • The relayer service enables Fuel-Ethereum communication through a layered architecture separating WASM execution, host functions, and database storage.
  • WasmRelayer in relayer.rs provides the execution interface via the RelayerPort trait.
  • Host bindings in ext.rs handle RPC communication with Ethereum's DA layer and deserialize events using postcard.
  • Database adapters persist events in the EventsHistory table, allowing the executor to include bridge messages in Fuel blocks.
  • The background relayer task continuously syncs Ethereum logs, ensuring the Fuel node maintains an up-to-date view of the DA layer.

Frequently Asked Questions

What is the primary function of the relayer service in fuel-core?

The relayer service acts as a bridge between Fuel and Ethereum by monitoring Ethereum's data-availability layer for specific events, downloading them via RPC, and storing them in the Fuel node's database. This allows Fuel contracts to access Ethereum state through the RelayerPort interface during execution.

How does the WASM executor access Ethereum events?

The WASM executor accesses Ethereum events through the WasmRelayer struct, which implements the RelayerPort trait. When a contract calls get_events, the executor delegates to host functions defined in ext.rs, which communicate with the Ethereum DA layer and return deserialized Event structs.

Where are Ethereum events stored in the Fuel node?

Ethereum events are stored in the EventsHistory table within the node's key-value database, accessible through the Database<Relayer> adapter in crates/fuel-core/src/service/adapters/relayer.rs. This persistence layer decouples event retrieval from execution, allowing the background relayer task to sync data independently.

What serialization format does the relayer use for Ethereum events?

The relayer uses the postcard serialization format to encode and decode Ethereum events when passing them between the host functions and the WASM executor. This lightweight binary format ensures efficient data transfer across the host-guest boundary while maintaining type safety through the Event enum defined in fuel_core_types.

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 →