From d0a495af83cf0f3564575136d8d09295e6a8f3d3 Mon Sep 17 00:00:00 2001 From: green Date: Mon, 5 Dec 2022 00:59:55 +0000 Subject: [PATCH 1/2] Move block-producer requirements into corresponding crates. Reused patter of adapter in the `fuel-core`. --- Cargo.lock | 1 + fuel-block-producer/Cargo.toml | 1 + fuel-block-producer/src/block_producer.rs | 50 ++++++++----- .../src/block_producer/tests.rs | 5 +- fuel-block-producer/src/mocks.rs | 6 +- fuel-block-producer/tests/integration.rs | 1 - fuel-core-bft/src/service.rs | 3 - fuel-core-interfaces/src/block_producer.rs | 71 ------------------- fuel-core-interfaces/src/lib.rs | 1 - fuel-core/src/schema/tx.rs | 3 +- fuel-core/src/service/modules.rs | 48 ++++++++++--- fuel-poa-coordinator/Cargo.toml | 2 +- fuel-poa-coordinator/src/service.rs | 45 +++++++++--- fuel-poa-coordinator/tests/test_trigger.rs | 23 +++--- 14 files changed, 123 insertions(+), 137 deletions(-) delete mode 100644 fuel-core-interfaces/src/block_producer.rs diff --git a/Cargo.lock b/Cargo.lock index b54519883f1..fabedd72cf3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2307,6 +2307,7 @@ dependencies = [ "parking_lot 0.12.1", "rand 0.8.5", "rstest", + "thiserror", "tokio", "tracing", ] diff --git a/fuel-block-producer/Cargo.toml b/fuel-block-producer/Cargo.toml index 2af16448d9f..b25ddd4fd26 100644 --- a/fuel-block-producer/Cargo.toml +++ b/fuel-block-producer/Cargo.toml @@ -14,6 +14,7 @@ anyhow = "1.0" async-trait = "0.1" fuel-core-interfaces = { path = "../fuel-core-interfaces", version = "0.14.1" } parking_lot = "0.12" +thiserror = "1.0" tokio = { version = "1.21", features = ["full"] } tracing = { version = "0.1" } diff --git a/fuel-block-producer/src/block_producer.rs b/fuel-block-producer/src/block_producer.rs index e23240442d3..08987e0013e 100644 --- a/fuel-block-producer/src/block_producer.rs +++ b/fuel-block-producer/src/block_producer.rs @@ -9,15 +9,6 @@ use anyhow::{ Result, }; use fuel_core_interfaces::{ - block_producer::{ - BlockProducer as Trait, - Error::{ - GenesisBlock, - InvalidDaFinalizationState, - MissingBlock, - }, - Relayer, - }, common::{ crypto::ephemeral_merkle_root, fuel_tx::{ @@ -43,6 +34,7 @@ use fuel_core_interfaces::{ }, }; use std::sync::Arc; +use thiserror::Error; use tokio::{ sync::{ Mutex, @@ -55,6 +47,27 @@ use tracing::debug; #[cfg(test)] mod tests; +#[derive(Error, Debug)] +pub enum Error { + #[error( + "0 is an invalid block height for production. It is reserved for genesis data." + )] + GenesisBlock, + #[error("Previous block height {0} doesn't exist")] + MissingBlock(BlockHeight), + #[error("Best finalized da_height {best} is behind previous block da_height {previous_block}")] + InvalidDaFinalizationState { + best: DaBlockHeight, + previous_block: DaBlockHeight, + }, +} + +#[async_trait::async_trait] +pub trait Relayer: Sync + Send { + /// Get the best finalized height from the DA layer + async fn get_best_finalized_da_height(&self) -> Result; +} + pub struct Producer { pub config: Config, pub db: Box, @@ -67,10 +80,9 @@ pub struct Producer { pub dry_run_semaphore: Semaphore, } -#[async_trait::async_trait] -impl Trait for Producer { +impl Producer { /// Produces and execute block for the specified height - async fn produce_and_execute_block( + pub async fn produce_and_execute_block( &self, height: BlockHeight, max_gas: Word, @@ -111,10 +123,10 @@ impl Trait for Producer { Ok(result) } - // simulate a transaction without altering any state. Does not aquire the production lock - // since it is basically a "read only" operation and shouldn't get in the way of normal - // production. - async fn dry_run( + /// Simulate a transaction without altering any state. Does not aquire the production lock + /// since it is basically a "read only" operation and shouldn't get in the way of normal + /// production. + pub async fn dry_run( &self, transaction: Transaction, height: Option, @@ -184,7 +196,7 @@ impl Producer { if best_height < previous_da_height { // If this happens, it could mean a block was erroneously imported // without waiting for our relayer's da_height to catch up to imported da_height. - return Err(InvalidDaFinalizationState { + return Err(Error::InvalidDaFinalizationState { best: best_height, previous_block: previous_da_height, } @@ -196,7 +208,7 @@ impl Producer { fn previous_block_info(&self, height: BlockHeight) -> Result { // block 0 is reserved for genesis if height == 0u32.into() { - Err(GenesisBlock.into()) + Err(Error::GenesisBlock.into()) } // if this is the first block, fill in base metadata from genesis else if height == 1u32.into() { @@ -211,7 +223,7 @@ impl Producer { let previous_block = self .db .get_block(prev_height)? - .ok_or(MissingBlock(prev_height))?; + .ok_or(Error::MissingBlock(prev_height))?; // TODO: this should use a proper BMT MMR let hash = previous_block.id(); let prev_root = ephemeral_merkle_root( diff --git a/fuel-block-producer/src/block_producer/tests.rs b/fuel-block-producer/src/block_producer/tests.rs index bc12956d9ed..5062e2e5446 100644 --- a/fuel-block-producer/src/block_producer/tests.rs +++ b/fuel-block-producer/src/block_producer/tests.rs @@ -1,4 +1,5 @@ use crate::{ + block_producer::Error, mocks::{ FailingMockExecutor, MockDb, @@ -10,10 +11,6 @@ use crate::{ Producer, }; use fuel_core_interfaces::{ - block_producer::{ - BlockProducer, - Error, - }, executor::Executor, model::{ FuelApplicationHeader, diff --git a/fuel-block-producer/src/mocks.rs b/fuel-block-producer/src/mocks.rs index 7f083a15553..66a2cd672b5 100644 --- a/fuel-block-producer/src/mocks.rs +++ b/fuel-block-producer/src/mocks.rs @@ -1,8 +1,10 @@ use super::db::BlockProducerDatabase; -use crate::ports::TxPool; +use crate::{ + block_producer::Relayer, + ports::TxPool, +}; use anyhow::Result; use fuel_core_interfaces::{ - block_producer::Relayer, common::{ fuel_storage::StorageInspect, fuel_tx::{ diff --git a/fuel-block-producer/tests/integration.rs b/fuel-block-producer/tests/integration.rs index 9dff491699e..b1ab7e133be 100644 --- a/fuel-block-producer/tests/integration.rs +++ b/fuel-block-producer/tests/integration.rs @@ -10,7 +10,6 @@ use fuel_block_producer::{ }; use fuel_core_interfaces::{ block_importer::ImportBlockBroadcast, - block_producer::BlockProducer as Trait, common::{ fuel_asm::Opcode, fuel_crypto::{ diff --git a/fuel-core-bft/src/service.rs b/fuel-core-bft/src/service.rs index c395da0d625..30887a2d7e0 100644 --- a/fuel-core-bft/src/service.rs +++ b/fuel-core-bft/src/service.rs @@ -5,11 +5,9 @@ use fuel_core_interfaces::{ ImportBlockBroadcast, ImportBlockMpsc, }, - block_producer::BlockProducer, p2p::P2pRequestEvent, }; use parking_lot::Mutex; -use std::sync::Arc; use tokio::{ sync::{ broadcast, @@ -35,7 +33,6 @@ impl Service { pub async fn start( &self, _p2p_consensus: mpsc::Sender, - _block_producer: Arc, _block_importer_sender: mpsc::Sender, _block_importer_broadcast: broadcast::Receiver, ) { diff --git a/fuel-core-interfaces/src/block_producer.rs b/fuel-core-interfaces/src/block_producer.rs deleted file mode 100644 index 311858b43ce..00000000000 --- a/fuel-core-interfaces/src/block_producer.rs +++ /dev/null @@ -1,71 +0,0 @@ -use crate::{ - common::fuel_tx::{ - Receipt, - Transaction, - }, - executor::ExecutionResult, - model::{ - BlockHeight, - DaBlockHeight, - FuelBlock, - }, -}; -use anyhow::Result; -use fuel_vm::prelude::Word; -use std::sync::Arc; -use thiserror::Error; -use tokio::sync::oneshot; - -#[derive(Debug)] -pub enum BlockProducerMpsc { - Produce { - // add needed information for block to be produced - height: BlockHeight, - response: oneshot::Sender>>, - }, - Stop, -} - -#[derive(Clone, Debug)] -pub enum BlockProducerBroadcast { - NewBlockProduced(Arc), -} - -#[async_trait::async_trait] -pub trait BlockProducer: Send + Sync { - // TODO: Right now production and execution of the block is one step, but in the future, - // `produce_block` should only produce a block without affecting the blockchain state. - async fn produce_and_execute_block( - &self, - height: BlockHeight, - max_gas: Word, - ) -> Result; - - async fn dry_run( - &self, - transaction: Transaction, - height: Option, - utxo_validation: Option, - ) -> Result>; -} - -#[derive(Error, Debug)] -pub enum Error { - #[error( - "0 is an invalid block height for production. It is reserved for genesis data." - )] - GenesisBlock, - #[error("Previous block height {0} doesn't exist")] - MissingBlock(BlockHeight), - #[error("Best finalized da_height {best} is behind previous block da_height {previous_block}")] - InvalidDaFinalizationState { - best: DaBlockHeight, - previous_block: DaBlockHeight, - }, -} - -#[async_trait::async_trait] -pub trait Relayer: Sync + Send { - /// Get the best finalized height from the DA layer - async fn get_best_finalized_da_height(&self) -> Result; -} diff --git a/fuel-core-interfaces/src/lib.rs b/fuel-core-interfaces/src/lib.rs index e2f0079c260..61b1f8784e6 100644 --- a/fuel-core-interfaces/src/lib.rs +++ b/fuel-core-interfaces/src/lib.rs @@ -1,6 +1,5 @@ pub mod bft; pub mod block_importer; -pub mod block_producer; pub mod db; pub mod executor; pub mod model; diff --git a/fuel-core/src/schema/tx.rs b/fuel-core/src/schema/tx.rs index 656d3276a5d..4212fb93645 100644 --- a/fuel-core/src/schema/tx.rs +++ b/fuel-core/src/schema/tx.rs @@ -31,7 +31,6 @@ use async_graphql::{ Subscription, }; use fuel_core_interfaces::{ - block_producer::BlockProducer, common::{ fuel_storage::StorageAsRef, fuel_tx::{ @@ -335,7 +334,7 @@ impl TxMutation { // for read-only calls. utxo_validation: Option, ) -> async_graphql::Result> { - let block_producer = ctx.data_unchecked::>(); + let block_producer = ctx.data_unchecked::>(); let mut tx = FuelTx::from_bytes(&tx.0)?; tx.precompute(); diff --git a/fuel-core/src/service/modules.rs b/fuel-core/src/service/modules.rs index 3ed8254642e..7a18fd014ec 100644 --- a/fuel-core/src/service/modules.rs +++ b/fuel-core/src/service/modules.rs @@ -10,17 +10,20 @@ use anyhow::Result; use fuel_core_interfaces::p2p::P2pDb; use fuel_core_interfaces::{ self, - block_producer::{ - BlockProducer, - Relayer as BlockProducerRelayer, + common::{ + fuel_tx::Receipt, + prelude::{ + Transaction, + Word, + }, }, - common::fuel_tx::Receipt, executor::{ Error, ExecutionBlock, ExecutionResult, Executor as ExecutorTrait, }, + model::BlockHeight, relayer::RelayerDb, txpool::{ Sender, @@ -45,7 +48,7 @@ use tokio::{ pub struct Modules { pub txpool: Arc, pub block_importer: Arc, - pub block_producer: Arc, + pub block_producer: Arc, pub coordinator: Arc, pub sync: Arc, #[cfg(feature = "relayer")] @@ -202,7 +205,9 @@ pub async fn start_modules(config: &Config, database: &Database) -> Result Result { bft.start( p2p_request_event_sender.clone(), - block_producer.clone(), block_importer.sender().clone(), block_importer.subscribe(), ) @@ -283,7 +287,7 @@ struct MaybeRelayerAdapter { } #[async_trait::async_trait] -impl BlockProducerRelayer for MaybeRelayerAdapter { +impl fuel_block_producer::block_producer::Relayer for MaybeRelayerAdapter { async fn get_best_finalized_da_height( &self, ) -> Result { @@ -301,3 +305,31 @@ impl BlockProducerRelayer for MaybeRelayerAdapter { .unwrap_or_default()) } } + +struct PoACoordinatorAdapter { + block_producer: Arc, +} + +#[async_trait::async_trait] +impl fuel_poa_coordinator::service::BlockProducer for PoACoordinatorAdapter { + async fn produce_and_execute_block( + &self, + height: BlockHeight, + max_gas: Word, + ) -> anyhow::Result { + self.block_producer + .produce_and_execute_block(height, max_gas) + .await + } + + async fn dry_run( + &self, + transaction: Transaction, + height: Option, + utxo_validation: Option, + ) -> anyhow::Result> { + self.block_producer + .dry_run(transaction, height, utxo_validation) + .await + } +} diff --git a/fuel-poa-coordinator/Cargo.toml b/fuel-poa-coordinator/Cargo.toml index c3964e78985..8f355078d88 100644 --- a/fuel-poa-coordinator/Cargo.toml +++ b/fuel-poa-coordinator/Cargo.toml @@ -11,6 +11,7 @@ description = "Fuel Core PoA Coordinator" [dependencies] anyhow = "1.0" +async-trait = "0.1" fuel-core-interfaces = { path = "../fuel-core-interfaces", version = "0.14.1" } humantime-serde = "1.1.1" parking_lot = "0.12" @@ -19,7 +20,6 @@ tokio = { version = "1.21", features = ["full"] } tracing = "0.1" [dev-dependencies] -async-trait = "0.1" fuel-core-interfaces = { path = "../fuel-core-interfaces", features = ["test-helpers"] } mockall = "0.11" rand = "0.8" diff --git a/fuel-poa-coordinator/src/service.rs b/fuel-poa-coordinator/src/service.rs index cf5e1fac6c4..a320bd90792 100644 --- a/fuel-poa-coordinator/src/service.rs +++ b/fuel-poa-coordinator/src/service.rs @@ -12,9 +12,12 @@ use anyhow::{ }; use fuel_core_interfaces::{ block_importer::ImportBlockBroadcast, - block_producer::BlockProducer, common::{ - fuel_tx::UniqueIdentifier, + fuel_tx::{ + Receipt, + Transaction, + UniqueIdentifier, + }, prelude::{ Signature, Word, @@ -56,6 +59,24 @@ use tracing::{ warn, }; +#[async_trait::async_trait] +pub trait BlockProducer: Send + Sync { + // TODO: Right now production and execution of the block is one step, but in the future, + // `produce_block` should only produce a block without affecting the blockchain state. + async fn produce_and_execute_block( + &self, + height: BlockHeight, + max_gas: Word, + ) -> anyhow::Result; + + async fn dry_run( + &self, + transaction: Transaction, + height: Option, + utxo_validation: Option, + ) -> anyhow::Result>; +} + pub struct RunningService { join: JoinHandle<()>, stop: mpsc::Sender<()>, @@ -74,16 +95,17 @@ impl Service { } } - pub async fn start( + pub async fn start( &self, txpool_broadcast: broadcast::Receiver, txpool: T, import_block_events_tx: broadcast::Sender, - block_producer: Arc, + block_producer: B, db: S, ) where S: BlockDb + Send + Clone + 'static, T: TransactionPool + Send + Sync + 'static, + B: BlockProducer + 'static, { let mut running = self.running.lock(); @@ -127,16 +149,17 @@ impl Service { } } -pub struct Task +pub struct Task where S: BlockDb + Send + Sync, T: TransactionPool, + B: BlockProducer, { stop: mpsc::Receiver<()>, block_gas_limit: Word, signing_key: Option>, db: S, - block_producer: Arc, + block_producer: B, txpool: T, txpool_broadcast: broadcast::Receiver, import_block_events_tx: broadcast::Sender, @@ -148,10 +171,11 @@ where /// Deadline clock, used by the triggers timer: DeadlineClock, } -impl Task +impl Task where S: BlockDb + Send, T: TransactionPool, + B: BlockProducer, { // Request the block producer to make a new block, and return it when ready async fn signal_produce_block(&mut self) -> anyhow::Result { @@ -176,6 +200,7 @@ where let ExecutionResult { block, skipped_transactions, + .. } = self.signal_produce_block().await?; // sign the block and seal it @@ -536,7 +561,7 @@ mod test { block_gas_limit: 1000000, signing_key: Some(Secret::new(secret_key.into())), db, - block_producer: Arc::new(block_producer), + block_producer, txpool, txpool_broadcast, import_block_events_tx, @@ -582,7 +607,7 @@ mod test { block_gas_limit: 1000000, signing_key: Some(Secret::new(secret_key.into())), db, - block_producer: Arc::new(block_producer), + block_producer, txpool, txpool_broadcast, import_block_events_tx, @@ -635,7 +660,7 @@ mod test { block_gas_limit: 1000000, signing_key: Some(Secret::new(secret_key.into())), db, - block_producer: Arc::new(block_producer), + block_producer, txpool, txpool_broadcast, import_block_events_tx, diff --git a/fuel-poa-coordinator/tests/test_trigger.rs b/fuel-poa-coordinator/tests/test_trigger.rs index 82bcb913c73..35dbf0ee0fc 100644 --- a/fuel-poa-coordinator/tests/test_trigger.rs +++ b/fuel-poa-coordinator/tests/test_trigger.rs @@ -3,7 +3,6 @@ use anyhow::anyhow; use fuel_core_interfaces::{ block_importer::ImportBlockBroadcast, - block_producer::BlockProducer, common::{ consts::REG_ZERO, fuel_tx::TransactionBuilder, @@ -34,6 +33,7 @@ use fuel_core_interfaces::{ }, }; use fuel_poa_coordinator::{ + service::BlockProducer, Config, Service, Trigger, @@ -397,7 +397,7 @@ async fn clean_startup_shutdown_each_trigger() -> anyhow::Result<()> { broadcast_rx, txpool.sender(), txpool.import_block_tx.clone(), - Arc::new(MockBlockProducer::new(txpool.sender(), db.clone())), + MockBlockProducer::new(txpool.sender(), db.clone()), db, ) .await; @@ -468,13 +468,12 @@ async fn never_trigger_never_produces_blocks() -> anyhow::Result<()> { let (mut txpool, broadcast_rx) = MockTxPool::spawn(); let producer = MockBlockProducer::new(txpool.sender(), db.clone()); - let producer = Arc::new(producer); service .start( broadcast_rx, txpool.sender(), txpool.import_block_tx.clone(), - producer.clone(), + producer, db, ) .await; @@ -515,14 +514,12 @@ async fn instant_trigger_produces_block_instantly() -> anyhow::Result<()> { let (mut txpool, broadcast_rx) = MockTxPool::spawn(); let producer = MockBlockProducer::new(txpool.sender(), db.clone()); - - let producer = Arc::new(producer); service .start( broadcast_rx, txpool.sender(), txpool.import_block_tx.clone(), - producer.clone(), + producer, db.clone(), ) .await; @@ -579,13 +576,12 @@ async fn interval_trigger_produces_blocks_periodically() -> anyhow::Result<()> { let (mut txpool, broadcast_rx) = MockTxPool::spawn(); let producer = MockBlockProducer::new(txpool.sender(), db.clone()); - let producer = Arc::new(producer); service .start( broadcast_rx, txpool.sender(), txpool.import_block_tx.clone(), - producer.clone(), + producer, db, ) .await; @@ -675,13 +671,12 @@ async fn interval_trigger_doesnt_react_to_full_txpool() -> anyhow::Result<()> { let (mut txpool, broadcast_rx) = MockTxPool::spawn(); let producer = MockBlockProducer::new(txpool.sender(), db.clone()); - let producer = Arc::new(producer); service .start( broadcast_rx, txpool.sender(), txpool.import_block_tx.clone(), - producer.clone(), + producer, db, ) .await; @@ -735,13 +730,12 @@ async fn hybrid_trigger_produces_blocks_correctly() -> anyhow::Result<()> { let (mut txpool, broadcast_rx) = MockTxPool::spawn(); let producer = MockBlockProducer::new(txpool.sender(), db.clone()); - let producer = Arc::new(producer); service .start( broadcast_rx, txpool.sender(), txpool.import_block_tx.clone(), - producer.clone(), + producer, db, ) .await; @@ -818,13 +812,12 @@ async fn hybrid_trigger_reacts_correctly_to_full_txpool() -> anyhow::Result<()> let (mut txpool, broadcast_rx) = MockTxPool::spawn(); let producer = MockBlockProducer::new(txpool.sender(), db.clone()); - let producer = Arc::new(producer); service .start( broadcast_rx, txpool.sender(), txpool.import_block_tx.clone(), - producer.clone(), + producer, db, ) .await; From edc44f7200d1c46fe69bae4c2907520019422bd9 Mon Sep 17 00:00:00 2001 From: green Date: Mon, 5 Dec 2022 21:53:32 +0000 Subject: [PATCH 2/2] Apply nits from the review --- fuel-block-producer/src/block_producer.rs | 11 +-- fuel-block-producer/src/mocks.rs | 6 +- fuel-block-producer/src/ports.rs | 10 +- fuel-core/src/service.rs | 1 + fuel-core/src/service/adapters.rs | 107 ++++++++++++++++++++ fuel-core/src/service/modules.rs | 109 ++------------------- fuel-poa-coordinator/src/lib.rs | 1 + fuel-poa-coordinator/src/ports.rs | 29 ++++++ fuel-poa-coordinator/src/service.rs | 25 +---- fuel-poa-coordinator/tests/test_trigger.rs | 2 +- version-compatibility/Cargo.lock | 2 + 11 files changed, 166 insertions(+), 137 deletions(-) create mode 100644 fuel-core/src/service/adapters.rs create mode 100644 fuel-poa-coordinator/src/ports.rs diff --git a/fuel-block-producer/src/block_producer.rs b/fuel-block-producer/src/block_producer.rs index 08987e0013e..a146d8ac90c 100644 --- a/fuel-block-producer/src/block_producer.rs +++ b/fuel-block-producer/src/block_producer.rs @@ -1,6 +1,9 @@ use crate::{ db::BlockProducerDatabase, - ports::TxPool, + ports::{ + Relayer, + TxPool, + }, Config, }; use anyhow::{ @@ -62,12 +65,6 @@ pub enum Error { }, } -#[async_trait::async_trait] -pub trait Relayer: Sync + Send { - /// Get the best finalized height from the DA layer - async fn get_best_finalized_da_height(&self) -> Result; -} - pub struct Producer { pub config: Config, pub db: Box, diff --git a/fuel-block-producer/src/mocks.rs b/fuel-block-producer/src/mocks.rs index 66a2cd672b5..b0d6e045f1b 100644 --- a/fuel-block-producer/src/mocks.rs +++ b/fuel-block-producer/src/mocks.rs @@ -1,7 +1,7 @@ use super::db::BlockProducerDatabase; -use crate::{ - block_producer::Relayer, - ports::TxPool, +use crate::ports::{ + Relayer, + TxPool, }; use anyhow::Result; use fuel_core_interfaces::{ diff --git a/fuel-block-producer/src/ports.rs b/fuel-block-producer/src/ports.rs index deeb9f34ed2..86f378e0046 100644 --- a/fuel-block-producer/src/ports.rs +++ b/fuel-block-producer/src/ports.rs @@ -1,8 +1,8 @@ -use anyhow::Result; use async_trait::async_trait; use fuel_core_interfaces::model::{ ArcPoolTx, BlockHeight, + DaBlockHeight, }; #[async_trait] @@ -13,5 +13,11 @@ pub trait TxPool: Sync + Send { block_height: BlockHeight, // The upper limit for the total amount of gas of these txs max_gas: u64, - ) -> Result>; + ) -> anyhow::Result>; +} + +#[async_trait::async_trait] +pub trait Relayer: Sync + Send { + /// Get the best finalized height from the DA layer + async fn get_best_finalized_da_height(&self) -> anyhow::Result; } diff --git a/fuel-core/src/service.rs b/fuel-core/src/service.rs index 4f1e15a0c93..b7bf97ff99f 100644 --- a/fuel-core/src/service.rs +++ b/fuel-core/src/service.rs @@ -18,6 +18,7 @@ pub use config::{ VMConfig, }; +pub mod adapters; pub mod config; pub(crate) mod genesis; pub mod graph_api; diff --git a/fuel-core/src/service/adapters.rs b/fuel-core/src/service/adapters.rs new file mode 100644 index 00000000000..dffc26f8cc2 --- /dev/null +++ b/fuel-core/src/service/adapters.rs @@ -0,0 +1,107 @@ +use crate::{ + database::Database, + executor::Executor, + service::Config, +}; +use fuel_core_interfaces::{ + common::{ + fuel_tx::{ + Receipt, + Transaction, + }, + fuel_types::Word, + }, + executor::{ + Error, + ExecutionBlock, + ExecutionResult, + Executor as ExecutorTrait, + }, + model::BlockHeight, + relayer::RelayerDb, +}; +#[cfg(feature = "relayer")] +use fuel_relayer::RelayerSynced; +use std::sync::Arc; + +pub struct ExecutorAdapter { + pub database: Database, + pub config: Config, +} + +#[async_trait::async_trait] +impl ExecutorTrait for ExecutorAdapter { + fn execute(&self, block: ExecutionBlock) -> Result { + let executor = Executor { + database: self.database.clone(), + config: self.config.clone(), + }; + executor.execute(block) + } + + fn dry_run( + &self, + block: ExecutionBlock, + utxo_validation: Option, + ) -> Result>, Error> { + let executor = Executor { + database: self.database.clone(), + config: self.config.clone(), + }; + executor.dry_run(block, utxo_validation) + } +} + +pub struct MaybeRelayerAdapter { + pub database: Database, + #[cfg(feature = "relayer")] + pub relayer_synced: Option, +} + +#[async_trait::async_trait] +impl fuel_block_producer::ports::Relayer for MaybeRelayerAdapter { + async fn get_best_finalized_da_height( + &self, + ) -> anyhow::Result { + #[cfg(feature = "relayer")] + { + if let Some(sync) = self.relayer_synced.as_ref() { + sync.await_synced().await?; + } + } + + Ok(self + .database + .get_finalized_da_height() + .await + .unwrap_or_default()) + } +} + +pub struct PoACoordinatorAdapter { + pub block_producer: Arc, +} + +#[async_trait::async_trait] +impl fuel_poa_coordinator::ports::BlockProducer for PoACoordinatorAdapter { + async fn produce_and_execute_block( + &self, + height: BlockHeight, + max_gas: Word, + ) -> anyhow::Result { + self.block_producer + .produce_and_execute_block(height, max_gas) + .await + } + + async fn dry_run( + &self, + transaction: Transaction, + height: Option, + utxo_validation: Option, + ) -> anyhow::Result> { + self.block_producer + .dry_run(transaction, height, utxo_validation) + .await + } +} diff --git a/fuel-core/src/service/modules.rs b/fuel-core/src/service/modules.rs index 7a18fd014ec..8a582bed8d8 100644 --- a/fuel-core/src/service/modules.rs +++ b/fuel-core/src/service/modules.rs @@ -2,36 +2,25 @@ use crate::{ chain_config::BlockProduction, database::Database, - executor::Executor, - service::Config, + service::{ + adapters::{ + ExecutorAdapter, + MaybeRelayerAdapter, + PoACoordinatorAdapter, + }, + Config, + }, }; use anyhow::Result; #[cfg(feature = "p2p")] use fuel_core_interfaces::p2p::P2pDb; use fuel_core_interfaces::{ self, - common::{ - fuel_tx::Receipt, - prelude::{ - Transaction, - Word, - }, - }, - executor::{ - Error, - ExecutionBlock, - ExecutionResult, - Executor as ExecutorTrait, - }, - model::BlockHeight, - relayer::RelayerDb, txpool::{ Sender, TxPoolDb, }, }; -#[cfg(feature = "relayer")] -use fuel_relayer::RelayerSynced; use fuel_txpool::service::TxStatusChange; use futures::future::join_all; use std::sync::Arc; @@ -251,85 +240,3 @@ pub async fn start_modules(config: &Config, database: &Database) -> Result Result { - let executor = Executor { - database: self.database.clone(), - config: self.config.clone(), - }; - executor.execute(block) - } - - fn dry_run( - &self, - block: ExecutionBlock, - utxo_validation: Option, - ) -> std::result::Result>, Error> { - let executor = Executor { - database: self.database.clone(), - config: self.config.clone(), - }; - executor.dry_run(block, utxo_validation) - } -} - -struct MaybeRelayerAdapter { - database: Database, - #[cfg(feature = "relayer")] - relayer_synced: Option, -} - -#[async_trait::async_trait] -impl fuel_block_producer::block_producer::Relayer for MaybeRelayerAdapter { - async fn get_best_finalized_da_height( - &self, - ) -> Result { - #[cfg(feature = "relayer")] - { - if let Some(sync) = self.relayer_synced.as_ref() { - sync.await_synced().await?; - } - } - - Ok(self - .database - .get_finalized_da_height() - .await - .unwrap_or_default()) - } -} - -struct PoACoordinatorAdapter { - block_producer: Arc, -} - -#[async_trait::async_trait] -impl fuel_poa_coordinator::service::BlockProducer for PoACoordinatorAdapter { - async fn produce_and_execute_block( - &self, - height: BlockHeight, - max_gas: Word, - ) -> anyhow::Result { - self.block_producer - .produce_and_execute_block(height, max_gas) - .await - } - - async fn dry_run( - &self, - transaction: Transaction, - height: Option, - utxo_validation: Option, - ) -> anyhow::Result> { - self.block_producer - .dry_run(transaction, height, utxo_validation) - .await - } -} diff --git a/fuel-poa-coordinator/src/lib.rs b/fuel-poa-coordinator/src/lib.rs index b3754ebf6f1..84edc82307e 100644 --- a/fuel-poa-coordinator/src/lib.rs +++ b/fuel-poa-coordinator/src/lib.rs @@ -3,6 +3,7 @@ mod deadline_clock; pub mod config; +pub mod ports; pub mod service; pub use config::{ diff --git a/fuel-poa-coordinator/src/ports.rs b/fuel-poa-coordinator/src/ports.rs new file mode 100644 index 00000000000..beee61ef2e0 --- /dev/null +++ b/fuel-poa-coordinator/src/ports.rs @@ -0,0 +1,29 @@ +use fuel_core_interfaces::{ + common::{ + fuel_asm::Word, + fuel_tx::{ + Receipt, + Transaction, + }, + }, + executor::ExecutionResult, + model::BlockHeight, +}; + +#[async_trait::async_trait] +pub trait BlockProducer: Send + Sync { + // TODO: Right now production and execution of the block is one step, but in the future, + // `produce_block` should only produce a block without affecting the blockchain state. + async fn produce_and_execute_block( + &self, + height: BlockHeight, + max_gas: Word, + ) -> anyhow::Result; + + async fn dry_run( + &self, + transaction: Transaction, + height: Option, + utxo_validation: Option, + ) -> anyhow::Result>; +} diff --git a/fuel-poa-coordinator/src/service.rs b/fuel-poa-coordinator/src/service.rs index a320bd90792..7a00ca0cf81 100644 --- a/fuel-poa-coordinator/src/service.rs +++ b/fuel-poa-coordinator/src/service.rs @@ -3,6 +3,7 @@ use crate::{ DeadlineClock, OnConflict, }, + ports::BlockProducer, Config, Trigger, }; @@ -13,11 +14,7 @@ use anyhow::{ use fuel_core_interfaces::{ block_importer::ImportBlockBroadcast, common::{ - fuel_tx::{ - Receipt, - Transaction, - UniqueIdentifier, - }, + fuel_tx::UniqueIdentifier, prelude::{ Signature, Word, @@ -59,24 +56,6 @@ use tracing::{ warn, }; -#[async_trait::async_trait] -pub trait BlockProducer: Send + Sync { - // TODO: Right now production and execution of the block is one step, but in the future, - // `produce_block` should only produce a block without affecting the blockchain state. - async fn produce_and_execute_block( - &self, - height: BlockHeight, - max_gas: Word, - ) -> anyhow::Result; - - async fn dry_run( - &self, - transaction: Transaction, - height: Option, - utxo_validation: Option, - ) -> anyhow::Result>; -} - pub struct RunningService { join: JoinHandle<()>, stop: mpsc::Sender<()>, diff --git a/fuel-poa-coordinator/tests/test_trigger.rs b/fuel-poa-coordinator/tests/test_trigger.rs index 35dbf0ee0fc..873cb0d7645 100644 --- a/fuel-poa-coordinator/tests/test_trigger.rs +++ b/fuel-poa-coordinator/tests/test_trigger.rs @@ -33,7 +33,7 @@ use fuel_core_interfaces::{ }, }; use fuel_poa_coordinator::{ - service::BlockProducer, + ports::BlockProducer, Config, Service, Trigger, diff --git a/version-compatibility/Cargo.lock b/version-compatibility/Cargo.lock index 1351149a27d..6fdac4a6068 100644 --- a/version-compatibility/Cargo.lock +++ b/version-compatibility/Cargo.lock @@ -1527,6 +1527,7 @@ dependencies = [ "async-trait", "fuel-core-interfaces 0.14.1", "parking_lot 0.12.1", + "thiserror", "tokio", "tracing", ] @@ -1863,6 +1864,7 @@ name = "fuel-poa-coordinator" version = "0.14.1" dependencies = [ "anyhow", + "async-trait", "fuel-core-interfaces 0.14.1", "humantime-serde", "parking_lot 0.12.1",