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:
- WASM Executor Query: During contract execution, the WASM runtime calls
relayer_enabledorrelayer_get_eventsthrough theRelayerPortinterface. - Host Function Execution: The
ext.rswrappers invoke underlying host functions that query the Ethereum DA contract via RPC. - 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. - Database Persistence: Events store in the
relayercolumn family viaDatabase<Relayer>. - 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.rsprovides the execution interface via theRelayerPorttrait. - Host bindings in
ext.rshandle RPC communication with Ethereum's DA layer and deserialize events usingpostcard. - Database adapters persist events in the
EventsHistorytable, 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →