diff --git a/committer/src/config.rs b/committer/src/config.rs index 59b4486e..ef3e9b9f 100644 --- a/committer/src/config.rs +++ b/committer/src/config.rs @@ -1,4 +1,4 @@ -use std::{net::Ipv4Addr, num::NonZeroU32, path::PathBuf, str::FromStr, time::Duration}; +use std::{net::Ipv4Addr, path::PathBuf, str::FromStr, time::Duration}; use clap::{command, Parser}; use eth::{Address, Chain}; @@ -34,8 +34,6 @@ pub struct EthConfig { pub chain_id: Chain, /// Ethereum address of the fuel chain state contract. pub state_contract_address: Address, - /// The number of fuel blocks between ethereum commits. If set to 1, then every block should be pushed to Ethereum. - pub commit_interval: NonZeroU32, } fn parse_chain_id<'de, D>(deserializer: D) -> Result diff --git a/committer/src/main.rs b/committer/src/main.rs index ca9bf0df..3a1a1acb 100644 --- a/committer/src/main.rs +++ b/committer/src/main.rs @@ -15,6 +15,7 @@ use setup::{ use tokio_util::sync::CancellationToken; use crate::setup::shut_down; +use ports::l1::Contract; pub type L1 = eth::WebsocketClient; pub type Database = storage::Postgres; @@ -34,7 +35,13 @@ async fn main() -> Result<()> { let metrics_registry = Registry::default(); + let (ethereum_rpc, eth_health_check) = + create_l1_adapter(&config, &internal_config, &metrics_registry).await?; + + let commit_interval = ethereum_rpc.commit_interval(); + let (rx_fuel_block, block_watcher_handle, fuel_health_check) = spawn_block_watcher( + commit_interval, &config, &internal_config, storage.clone(), @@ -42,9 +49,6 @@ async fn main() -> Result<()> { cancel_token.clone(), ); - let (ethereum_rpc, eth_health_check) = - create_l1_adapter(&config, &internal_config, &metrics_registry).await?; - let wallet_balance_tracker_handle = spawn_wallet_balance_tracker( &internal_config, &metrics_registry, diff --git a/committer/src/setup.rs b/committer/src/setup.rs index 31d90de5..2a0203a6 100644 --- a/committer/src/setup.rs +++ b/committer/src/setup.rs @@ -1,3 +1,4 @@ +use std::num::NonZeroU32; use std::time::Duration; use metrics::{prometheus::Registry, HealthChecker, RegistersMetrics}; @@ -15,6 +16,7 @@ use crate::{ }; pub fn spawn_block_watcher( + commit_interval: NonZeroU32, config: &Config, internal_config: &InternalConfig, storage: Database, @@ -28,7 +30,8 @@ pub fn spawn_block_watcher( let (fuel_adapter, fuel_connection_health) = create_fuel_adapter(config, internal_config, registry); - let (block_watcher, rx) = create_block_watcher(config, registry, fuel_adapter, storage); + let (block_watcher, rx) = + create_block_watcher(commit_interval, config, registry, fuel_adapter, storage); let handle = schedule_polling( internal_config.fuel_polling_interval, @@ -105,7 +108,6 @@ pub async fn create_l1_adapter( config.eth.chain_id, config.eth.state_contract_address, &config.eth.wallet_key, - config.eth.commit_interval, internal_config.eth_errors_before_unhealthy, ) .await?; @@ -157,6 +159,7 @@ fn create_fuel_adapter( } fn create_block_watcher( + commit_interval: NonZeroU32, config: &Config, registry: &Registry, fuel_adapter: FuelApi, @@ -167,7 +170,7 @@ fn create_block_watcher( ) { let (tx_fuel_block, rx_fuel_block) = tokio::sync::mpsc::channel(100); let block_watcher = BlockWatcher::new( - config.eth.commit_interval, + commit_interval, tx_fuel_block, fuel_adapter, storage, diff --git a/configurations/development/config.toml b/configurations/development/config.toml index 9f06222e..639a558c 100644 --- a/configurations/development/config.toml +++ b/configurations/development/config.toml @@ -2,7 +2,6 @@ wallet_key = "0x9e56ccf010fa4073274b8177ccaad46fbaf286645310d03ac9bb6afa922a7c36" chain_id = "hardhat" state_contract_address = "0xdAad669b06d79Cb48C8cfef789972436dBe6F24d" -commit_interval = 3 rpc = "ws://localhost:8089" [fuel] diff --git a/e2e/src/lib.rs b/e2e/src/lib.rs index 963f4274..161c364d 100644 --- a/e2e/src/lib.rs +++ b/e2e/src/lib.rs @@ -1,11 +1,11 @@ #[cfg(test)] mod tests { - use std::time::Duration; - use anyhow::{anyhow, Result}; use eth::{Chain, WebsocketClient}; use fuel::HttpClient; use ports::fuel::{Api, FuelPublicKey}; + use ports::l1::Contract; + use std::time::Duration; use validator::{BlockValidator, Validator}; const FUEL_NODE_PORT: u16 = 4000; @@ -20,12 +20,13 @@ mod tests { Chain::AnvilHardhat, "0xdAad669b06d79Cb48C8cfef789972436dBe6F24d".parse()?, "0x9e56ccf010fa4073274b8177ccaad46fbaf286645310d03ac9bb6afa922a7c36", - 3.try_into()?, 10, ) .await?; - provider.produce_blocks(3).await?; + provider + .produce_blocks(fuel_contract.commit_interval().into()) + .await?; // time enough to fwd the block to ethereum and for the TIME_TO_FINALIZE (1s) to elapse tokio::time::sleep(Duration::from_secs(5)).await; diff --git a/eth_node/Dockerfile b/eth_node/Dockerfile index 20ceee11..ea26a62b 100644 --- a/eth_node/Dockerfile +++ b/eth_node/Dockerfile @@ -6,7 +6,6 @@ RUN git clone --no-checkout https://github.com/FuelLabs/fuel-bridge \ && cd packages/solidity-contracts \ && rm -rf deploy deployments exports test \ && cd contracts \ - && sed 's/\(BLOCKS_PER_COMMIT_INTERVAL\) = 10800/\1 = 3/g' -i ./fuelchain/FuelChainState.sol \ && sed 's/\(TIME_TO_FINALIZE\) = 10800/\1 = 1/g' -i ./fuelchain/FuelChainState.sol FROM alpine:3.19.1 diff --git a/packages/eth/src/lib.rs b/packages/eth/src/lib.rs index 24ff5230..cd250736 100644 --- a/packages/eth/src/lib.rs +++ b/packages/eth/src/lib.rs @@ -1,4 +1,6 @@ #![deny(unused_crate_dependencies)] + +use std::num::NonZeroU32; use std::pin::Pin; use async_trait::async_trait; @@ -26,6 +28,10 @@ impl Contract for WebsocketClient { fn event_streamer(&self, height: L1Height) -> Box { Box::new(self.event_streamer(height.into())) } + + fn commit_interval(&self) -> NonZeroU32 { + self.commit_interval() + } } #[async_trait] diff --git a/packages/eth/src/websocket.rs b/packages/eth/src/websocket.rs index 6826c159..e484cfdd 100644 --- a/packages/eth/src/websocket.rs +++ b/packages/eth/src/websocket.rs @@ -1,11 +1,10 @@ -use std::num::NonZeroU32; - use ::metrics::{prometheus::core::Collector, HealthChecker, RegistersMetrics}; use ethers::types::{Address, Chain}; use ports::{ l1::Result, types::{ValidatedFuelBlock, U256}, }; +use std::num::NonZeroU32; use url::Url; pub use self::event_streamer::EthEventStreamer; @@ -29,12 +28,9 @@ impl WebsocketClient { chain_id: Chain, contract_address: Address, wallet_key: &str, - commit_interval: NonZeroU32, unhealthy_after_n_errors: usize, ) -> ports::l1::Result { - let provider = - WsConnection::connect(url, chain_id, contract_address, wallet_key, commit_interval) - .await?; + let provider = WsConnection::connect(url, chain_id, contract_address, wallet_key).await?; Ok(Self { inner: HealthTrackingMiddleware::new(provider, unhealthy_after_n_errors), @@ -54,6 +50,10 @@ impl WebsocketClient { Ok(self.inner.submit(block).await?) } + pub(crate) fn commit_interval(&self) -> NonZeroU32 { + self.inner.commit_interval() + } + pub(crate) async fn get_block_number(&self) -> Result { Ok(self.inner.get_block_number().await?) } diff --git a/packages/eth/src/websocket/connection.rs b/packages/eth/src/websocket/connection.rs index 95613265..157051fb 100644 --- a/packages/eth/src/websocket/connection.rs +++ b/packages/eth/src/websocket/connection.rs @@ -11,7 +11,7 @@ use serde_json::Value; use url::Url; use super::{event_streamer::EthEventStreamer, health_tracking_middleware::EthApi}; -use crate::error::Result; +use crate::error::{Error, Result}; abigen!( FUEL_STATE_CONTRACT, @@ -20,6 +20,7 @@ abigen!( event CommitSubmitted(uint256 indexed commitHeight, bytes32 blockHash) function finalized(bytes32 blockHash, uint256 blockHeight) external view whenNotPaused returns (bool) function blockHashAtCommit(uint256 commitHeight) external view returns (bytes32) + function BLOCKS_PER_COMMIT_INTERVAL() external view returns (uint256) ]"#, ); @@ -60,6 +61,10 @@ impl EthApi for WsConnection { Ok(self.provider.get_balance(address, None).await?) } + fn commit_interval(&self) -> NonZeroU32 { + self.commit_interval + } + fn event_streamer(&self, eth_block_height: u64) -> EthEventStreamer { let events = self .contract @@ -94,7 +99,6 @@ impl WsConnection { chain_id: Chain, contract_address: Address, wallet_key: &str, - commit_interval: NonZeroU32, ) -> Result { let provider = Provider::::connect(url.to_string()).await?; @@ -106,6 +110,16 @@ impl WsConnection { let contract_address = Address::from_slice(contract_address.as_ref()); let contract = FUEL_STATE_CONTRACT::new(contract_address, Arc::new(signer)); + let interval_u256 = contract.blocks_per_commit_interval().call().await?; + + let commit_interval = u32::try_from(interval_u256) + .map_err(|e| Error::Other(e.to_string())) + .and_then(|value| { + NonZeroU32::new(value).ok_or_else(|| { + Error::Other("l1 contract reported a commit interval of 0".to_string()) + }) + })?; + Ok(Self { provider, contract, diff --git a/packages/eth/src/websocket/health_tracking_middleware.rs b/packages/eth/src/websocket/health_tracking_middleware.rs index c4bdcc4e..280d13b9 100644 --- a/packages/eth/src/websocket/health_tracking_middleware.rs +++ b/packages/eth/src/websocket/health_tracking_middleware.rs @@ -1,6 +1,9 @@ use ::metrics::{ prometheus::core::Collector, ConnectionHealthTracker, HealthChecker, RegistersMetrics, }; + +use std::num::NonZeroU32; + use ports::types::{ValidatedFuelBlock, U256}; use crate::{ @@ -15,6 +18,7 @@ pub trait EthApi { async fn submit(&self, block: ValidatedFuelBlock) -> Result<()>; async fn get_block_number(&self) -> Result; async fn balance(&self) -> Result; + fn commit_interval(&self) -> NonZeroU32; fn event_streamer(&self, eth_block_height: u64) -> EthEventStreamer; #[cfg(feature = "test-helpers")] async fn finalized(&self, block: ValidatedFuelBlock) -> Result; @@ -90,6 +94,10 @@ where response } + fn commit_interval(&self) -> NonZeroU32 { + self.adapter.commit_interval() + } + #[cfg(feature = "test-helpers")] async fn finalized(&self, block: ValidatedFuelBlock) -> Result { self.adapter.finalized(block).await diff --git a/packages/ports/src/ports/l1.rs b/packages/ports/src/ports/l1.rs index ba447bde..bf823fbd 100644 --- a/packages/ports/src/ports/l1.rs +++ b/packages/ports/src/ports/l1.rs @@ -25,6 +25,7 @@ impl From for Error { pub trait Contract: Send + Sync { async fn submit(&self, block: ValidatedFuelBlock) -> Result<()>; fn event_streamer(&self, height: L1Height) -> Box; + fn commit_interval(&self) -> std::num::NonZeroU32; } #[cfg_attr(feature = "test-helpers", mockall::automock)] diff --git a/packages/services/src/block_committer.rs b/packages/services/src/block_committer.rs index a07831fb..0f691e45 100644 --- a/packages/services/src/block_committer.rs +++ b/packages/services/src/block_committer.rs @@ -76,6 +76,7 @@ where #[cfg(test)] mod tests { + use std::num::NonZeroU32; use std::time::Duration; use mockall::predicate; @@ -101,6 +102,10 @@ mod tests { fn event_streamer(&self, height: L1Height) -> Box { self.contract.event_streamer(height) } + + fn commit_interval(&self) -> NonZeroU32 { + self.contract.commit_interval() + } } #[cfg_attr(feature = "test-helpers", mockall::automock)]