{"owner":"FuelLabs","repo":"fuel-core","hasSkills":true,"totalSkillsCount":1,"totalTokensCount":4064,"categories":["project-spec"],"hasMcp":false,"mcpConfig":null,"found":["docs/architecture.md"],"skills":{"docs/architecture.md":"# Fuel Client Software Architecture\n\nInspired by [Hexagonal Architecture](https://en.wikipedia.org/wiki/Hexagonal_architecture_(software)), the Fuel \nblockchain client is composed of various domain modules. Each module defines its own view of the system \nvia a class of traits we'll call \"Ports\". This is in contrast to creating globally shared interfaces\nwith the difficulty of trying to cover every possible use-case in a future-proof way, while on the other hand\nleaking many irrelevant concerns across different domains. This approach may lead to a small amount of\nmonotonous and boring bloat in a few areas, but this is offset by the advantages of loose coupling.\nThis is intended to minimize the overall complexity and cognitive load of the codebase.\nBusiness logic will have clear intentions and be easy to follow, unit tests don't need to mock low level details\nabout unrelated components, and refactors can easily control their blast radius.\n\nIn a system of shared global traits between modules, any updates to an interface will cause breaking changes\nto the mocks and test harnesses for all consuming modules. This is less than ideal when these domain modules\ndon't need to use the new changes. However, in a system where each domain controls its ports, adjusting an\ninterface will only affect the port owner and the implementer.\n\nThe implementation of \"Ports\" (aka adapters) referring to other domain modules, should reside in the main fuel-core\ncrate. This way, domain modules should never need to take a dependency on each other. This helps to avoid circular\ndependencies, and also allows for lightweight rapid developer iteration within a domain module. It also ensures\nthe purity of the domain modules, preventing implementation details of modules from contaminating each other. Adapters\nare intended to restrict the viral spread of any ugly complexity that arises when integrating modules. Decisions\nsuch as whether to use channels, networking, IPC, or direct calls between domain modules can be decided in the adapter\nwithout any effect on the domain logic. They should avoid implementing any business rules, and only contain integration\nglue logic between systems.\n\nSpecial care was also taken in this design approach to keep implementation details regarding synchronization primitives\nor proprietary async runtime requirements out of any public interfaces (No channels!).\n\nSummary:\n\n - Business logic with many external dependencies should be segmented where possible into separate domain crates\n - Domain crates define \"Ports\" (traits) for external dependencies that aren't strictly of concern to the business logic.\n - Domain crates should aim to be as pure as possible and have minimal dependencies, and not depend on each other.\n - Adapters implement Ports. They are for integrating with the \"real-world\" dependencies like using other domain modules,\n   implementing serialization logic, or calling a database.\n - Adapters should either reside in the top-level crate (\"fuel-core\") or in their own crates. This prevents the domains\n   from being polluted by dependencies with large compile times or unstable interfaces. This allows for libraries like \n   networking, third-party SDKs, or database drivers to be swapped out without breaking our core domain specific logic.\n\nThe following is intended to be a living document to convey how P&A can and should be applied to the client. However, given\nmany of these components remain in flux as our needs change, these ports and flows should be considered as a foundation \nand structure for future design RFC refinements to build upon, rather than reflect a finalized view dictating how the \nsystem should forever be. When applying this design, it's encouraged to take practical and experimental steps to evolve our \ncodebase using the Ports and Adapters (P&A) principles previously summarized to help guide our decision-making based on \nevidence discovered in the process of implementation and testing.\n\n## Domains:\n\n```mermaid\nflowchart TB\n    subgraph Fuel Core\n        direction TB\n        subgraph POAS[PoA Service]\n            POAD{{Domain}}\n            SYNCPOA[Synchronizer Adapter]\n        end\n        subgraph BPS[Block Producer Service]\n            BPD{{Domain}}\n            POABP[PoA Adapter]\n            APIBP[API Adapter]\n        end\n        subgraph BIS[Block Importer Service]\n            BID{{Domain}}\n            SYNCBI[\"Sync Adapter\"]\n            POABI[\"PoA Adapter\"]\n        end\n        subgraph SS[Synchronizer Service]\n            SSD{{Domain}}\n        end\n        subgraph P2PS[P2P Service]\n            P2PD{{Domain}}\n            POAP2P[PoA Adapter]\n            SYNCP2P[Sync Adapter]\n            TXP2P[Transaction Pool Adapter]\n        end\n        subgraph TXS[Transaction Pool Service]\n            TXD{{Domain}}\n            BPTXS[Block Producer Adapter]\n            BITXS[Block Importer Adapter]\n        end\n        subgraph RS[Relayer Service]\n            RSD{{Domain}}\n            POAR[POA Adapter]\n            BPR[Block Producer Adapter]\n            BIR[Block Importer Adapter]\n        end\n        subgraph ES[Executor Service]\n            ESD{{Domain}}\n            BPEXE[Block Producer Adapter]\n            BIEXE[Block Importer Adapter]\n        end\n        subgraph APIS[API Service]\n            APID{{Domain}}\n        end\n        BID & BPD --> ES & RS & TXS\n        SSD --> P2PS & BIS\n        TXD --> P2PS\n        POAD --> P2PS & RS & BPS & BIS\n        APID --> BPS\n        \n        %% Red color - Block Importer\n        linkStyle 0,1,2 fill:none,stroke-width:4px,stroke:red\n        %% Pink color - Block Producer\n        linkStyle 3,4,5 fill:none,stroke-width:4px,stroke:pink\n        %% Green color - Synchronizer\n        linkStyle 6,7 fill:none,stroke-width:4px,stroke:green\n        %% Blue color - Transaction pool\n        linkStyle 8 fill:none,stroke-width:4px,stroke:blue\n        %% Orange color - PoA\n        linkStyle 10,11,12,9 fill:none,stroke-width:4px,stroke:orange\n        %% Purple color - API\n        linkStyle 13 fill:none,stroke-width:4px,stroke:purple\n    end\n```\n\n### (PoA) Consensus Module\n\n#### Ports: fuel_poa_consensus::ports\n```rust\ntrait BlockProducer {\n    // used by the PoA node to produce a new block and obtain fully computed block headers\n    async fn produce_block(height: BlockHeight) -> Result<FuelBlock>;\n}\n\ntrait BlockImporter {\n    // After the PoA node has signed over the block, send it to the block importer for inclusion\n    // into the finalized state of the node.\n    async fn commit(sealed_block: SealedBlock) -> Result<()>;\n}\n\ntrait Relayer {\n    // wait until the relayer eth node is synced\n    async fn await_synced() -> Result<()>;\n    // wait until the relayer reaches a desired da_height\n    async fn await_da_height(da_height: DaHeight) -> Result<()>;\n    // get the consensus key associated with a da_height\n    async fn get_poa_key(da_height: DaHeight) -> Result<ConsensusKey>;\n}\n\ntrait Database {\n    // get the current fuel chain height\n    fn get_current_height() -> Result<BlockHeight>;\n    // insert consensus information associated with a sealed block that was locally produced\n    fn insert_consensus_data(sealed_block: &SealedBlock) -> Result<()>;\n}\n```\n#### Adapters: fuel_core::service::adapters::poa_consensus\n```rust\nimpl fuel_core_sync::ports::Consensus for Service<PoA> {\n    // insert impl here\n}\n```\n\n### Block Producer\n\n#### Ports: fuel_core_producer::ports\n\n```rust\ntrait TransactionPool {\n    fn select_block_txs(max_gas: u64, block_height: BlockHeight) -> Result<Vec<Arc<CheckedTransaction>>>;\n    fn drop_txs(txs: Vec<TxId>) -> Result<()>;\n}\n\ntrait Executor {\n    async fn produce_block(block: &mut FuelBlock) -> Result<()>;\n}\n\ntrait Relayer {\n    fn get_finalized_da_height() -> Result<DaHeight>;\n}\n```\n#### Adapters: fuel_core::service::adapters::block_producer\n```rust\nimpl fuel_poa_consensus::ports::BlockProducer for Service<BlockProducer> {\n    // insert impl here\n}\n```\n\n### Block Importer\n\n#### Ports: fuel_core_importer::ports\n\n```rust\ntrait Relayer {\n    // wait until the relayer is synced with ethereum\n    async fn await_synced() -> Result<()>;\n    // wait until a specific da_height is reached\n    async fn await_da_height(da_height: DaHeight) -> Result<()>;\n}\n\ntrait Executor {\n    async fn validate_and_store_block(block: &FuelBlock) -> Result<()>;\n}\n\ntrait TransactionPool {\n    // remove a set of txs from the pool after a block is committed\n    fn drop_txs(txs: Vec<TxId>) -> Result<()>;\n}\n\ntrait Database {\n    // insert consensus information associated with a sealed block\n    fn insert_consensus_data(sealed_block: &SealedBlock) -> Result<()>;\n}\n\ntrait PeerToPeer {\n   // broadcast the finalized header to peers who may need to sync\n   async fn broadcast_sealed_header(sealed_block_header: SealedBlockHeader) -> Result<()>;\n}\n\n```\n#### Adapters: fuel_core::service::adapters::block_importer\n```rust\nimpl fuel_poa_consensus::ports::BlockImporter for Service<BlockImporter> {\n    // insert impl here\n}\n\nimpl fuel_core_sync::ports::BlockImporter for Service<BlockImporter> {\n    // insert impl here\n}\n```\n\n### Synchronizer\n\n#### Ports: fuel_core_sync::ports\n\n```rust\ntrait PeerToPeer {\n    type SealedHeaderResponse: NetworkData<SealedBlockHeader>;\n    type BlockResponse: NetworkData<Vec<SealedBlock>>;\n    type GossipedBlockHeader: NetworkData<SealedBlockHeader>;\n    \n    async fn fetch_best_network_block_header(&self) -> Result<Option<Self::SealedHeaderResponse>>;\n    async fn fetch_blocks(&self, query: Range<BlockHeight>) -> Result<Self::BlockResponse>;\n    // punish the sender for providing an invalid block header\n    fn report_invalid_block_header(&self, invalid_header: &Self::SealedHeaderResponse) -> Result<()>;\n    // punish the sender for providing a set of blocks that aren't valid\n    fn report_invalid_blocks(&self, invalid_blocks: &Self::BlockResponse) -> Result<()>;\n    // provides a stream of gossiped block header events\n    fn gossiped_block_header_events(&self) -> BoxStream<Self::SealedBlockHeader>;\n    // notify the p2p network whether to continue gossiping this message to others or\n    // punish the peer that sent it\n    fn notify_gossip_block_validity(&self, message: &Self::GossipedBlockHeader, validity: GossipValidity);\n}\n\n// Generic wrapper for data received from peers while abstracting\n// networking metadata (e.g. IP's or other IDs) needed for gossip validation\npub trait NetworkData<D> {\n    // Transfer ownership of the provided data without consuming other message metadata\n    fn take_data(&mut self) -> Option<D>;\n}\n\npub enum GossipValidity {\n    // Report whether the gossiped message is valid and safe to rebroadcast\n    Accept,\n    // Ignore the received message and prevent further gossiping\n    Ignore,\n    // Punish the gossip sender for providing invalid \n    // (or malicious) data and prevent further gossiping\n    Invalid,\n}\n\ntrait BlockImporter {\n    // commit a sealed block to the chain\n    async fn commit(block: SealedBlock) -> Result<()>;\n   \n   // check with the block importer whether a block header passes consensus rules\n   async fn validate_sealed_block_header(block: SealedBlockHeader) -> Result<()>;\n}\n\ntrait Database {\n    // get current fuel blockchain height\n    fn get_current_height() -> Result<BlockHeight>;\n}\n```\n#### Adapters: fuel_core::service::adapters::fuel_core_sync\n_N/A_\n\n### P2P\n\n#### Ports: fuel_core_p2p::ports\n```rust\ntrait Database {\n    // used when other peers are syncing\n    fn get_sealed_block(height: BlockHeight) -> Result<SealedBlock>; \n}\n```\n\n#### Adapters: fuel_core::service::adapters::peer_to_peer\n```rust\nimpl fuel_poa_consensus::ports::PeerToPeer for Service<P2pService> {\n    // insert impl here\n}\n\nimpl fuel_core_sync::ports::PeerToPeer for Service<P2pService> {\n    // insert impl here\n}\n\nimpl fuel_core_txpool::ports::PeerToPeer for Service<P2pService> {\n    // insert impl here\n}\n```\n\n### Transaction Pool\n\n#### Ports: fuel_core_txpool::ports\n```rust\ntrait PeerToPeer {\n    type GossipedTransaction: NetworkData<Transaction>;\n   \n    // Gossip broadcast a transaction inserted via API.\n    async fn broadcast_transaction(transaction: Transaction) -> Result<()>;\n\n    // Provides a stream of gossiped transactions.\n    fn gossiped_transaction_events(&self) -> BoxStream<Self::GossipedTransaction>;\n   \n    // Report the validity of a transaction received from the network.\n    fn notify_gossip_transaction_validity(message: &Self::GossipedTransaction, validity: GossipValidity) -> anyhow::Result<()>;\n}\n\ntrait BlockImporter {\n   // used to update the transaction pool from imported blocks\n   fn committed_block_events(&self) -> BoxStream<SealedBlock>;\n}\n\n// Generic wrapper for data received from peers while abstracting\n// networking metadata (e.g. IP's or other IDs) needed for gossip validation\npub trait NetworkData<D> {\n   // Transfer ownership of the provided data without consuming other message metadata\n   fn take_data(&mut self) -> Option<D>;\n}\n\npub enum GossipValidity {\n    // Report whether the gossiped message is valid and safe to rebroadcast\n    Accept,\n    // Ignore the received message and prevent further gossiping\n    Ignore,\n    // Punish the gossip sender for providing invalid \n    // (or malicious) data and prevent further gossiping\n    Invalid,\n}\n\npub trait Database:\n    StorageInspect<Coins, Error = StorageError>\n    + StorageInspect<ContractsRawCode, Error = StorageError>\n    + StorageInspect<Messages, Error = StorageError>\n    + Send\n    + Sync\n{}\n```\n\n#### Adapters: fuel_core::service::adapters::transaction_pool\n```rust\nimpl block_importer::ports::TransactionPool for Service<TransactionPool> {\n    // insert impl here\n}\n\nimpl block_producer::ports::TransactionPool for Service<TransactionPool> {\n    // insert impl here\n}\n```\n\n#### Adapters: fuel_core::service::adapters::block_importer\n```rust\nimpl transaction_pool::ports::BlockImporter for Service<BlockImporter> {\n   // insert impl here\n}\n\n```\n\n### Executor\n\n#### Ports: fuel_core_executor::ports\n```rust\ntrait Database: InterpreterStorage\n  + StorageMut<Coins, Error = StorageError>\n  + StorageMut<Messages, Error = StorageError>\n  + StorageMut<Contracts, Error = StorageError>\n  + StorageMut<Blocks, Error = StorageError>\n  + StorageMut<ContractUtxos, Error = StorageError>\n  + StorageMut<Transactions, Error = StorageError>\n  + Send\n  + Sync {\n    // start a nested transaction to allow changes to be rolled-back\n    fn db_transaction(&self) -> Box<dyn DatabaseTransaction>;\n}\n\n// Database overlay that accumulates changes until committed at the end.\ntrait DatabaseTransaction: AsRef<Box<dyn Database>> {\n    // consume the transaction and commit the changes\n    fn commit(self) -> Result<()>;\n}\n```\n#### Adapters: fuel_core::service::adapters::executor\n```rust\nimpl fuel_core_producer::ports::Executor for Service<Executor> {\n    // insert impl here\n}\n\nimpl fuel_core_importer::ports::Executor for Service<Executor> {\n    // insert impl here\n}\n```\n\n### Relayer\n\n#### Ports: fuel_core_relayer::ports\n```rust\ntrait Database: StorageMutate<Messages, Error = StorageError> {\n    fn get_da_synced_height(&self) -> Result<DaBlockHeight>;\n    fn set_da_synced_height(&self, height: DaBlockHeight) -> Result<()>;\n}\n\ntrait DataAvailabilityLayer {\n    async fn is_syncing(&self) -> SyncState;\n    async fn best_finalized_block(&self) -> Result<DaBlockHeight>;\n    async fn download_messages(&self, blocks: Range<DaBlockHeight>) -> Result<Vec<Message>>;\n}\n\npub struct DaBlockHeight(u64);\n```\n\n#### Adapters: fuel_core::service::adapters::relayer\n```rust\nimpl fuel_core_importer::ports::Relayer for Service<Relayer> {\n    // insert impl here\n}\n\nimpl fuel_core_producer::ports::Relayer for Service<Relayer> {\n    // insert impl here\n}\n\nimpl fuel_poa_consensus::ports::Relayer for Service<Relayer> {\n    // insert impl here\n}\n```\n\n### API (GraphQL)\nToo extensive to fully detail...\n\n#### Ports: fuel_core_api::ports\n\n```rust\ntrait BlockProducer {\n    // produce a single-tx block at a given height and return the receipts\n    async fn dry_run_transaction(transaction: Transaction, height: Option<BlockHeight>) -> Result<Vec<Receipt>>;\n    // start a debug session at a given height.\n    async fn start_debug_session<S>(transaction: Transaction, height: Option<BlockHeight>) -> Result<Box<dyn DebugSession<S>>>;\n}\n\ntrait DebugSession<S>: AsRef<Interpreter<S>> {\n    fn memory(&self, start: usize, len: usize) -> Option<&[u8]>;\n    fn register(&self, register: RegisterId) -> Option<Word>;\n    fn reset(&mut self) -> Result<()>;\n    fn execute(&mut self) -> Result<()>;\n}\n```\n\n#### Adapters: fuel_core::service::adapters::api\n\n```rust\nimpl fuel_core_api::ports::BlockProducer for Service<BlockProducer> {\n    // insert impl here\n}\n\nimpl<S> fuel_core_api::ports::DebugSession<S> for DebugSessionAdapter<S> {\n    // insert impl here\n}\n\n// example of adapter fulfilled implementation\npub struct DebugSessionAdapter<S> {\n    vm: Interpreter<S>,\n    db: Database,\n    tx: Transaction,\n}\n```\n\n## Fuel Core Services\n\n`fuel-core` is the connection point between all modules. Since adapters implement foreign traits for foreign domains,\neach domain should be wrapped in a local new-type such as `Service<D>`. Services should be sharable via \n`Arc<Service<D: Stoppable + Send + Sync>>`.\n\nThe `Stoppable` trait ensures each service has a graceful shutdown method and join handle for any background tasks.\nIf a service does not spawn any background tasks, this trait can be implemented as a no-op.\n\n## [Flows](./poa/flows.md)\n"},"files":{"docs/architecture.md":"# Fuel Client Software Architecture\n\nInspired by [Hexagonal Architecture](https://en.wikipedia.org/wiki/Hexagonal_architecture_(software)), the Fuel \nblockchain client is composed of various domain modules. Each module defines its own view of the system \nvia a class of traits we'll call \"Ports\". This is in contrast to creating globally shared interfaces\nwith the difficulty of trying to cover every possible use-case in a future-proof way, while on the other hand\nleaking many irrelevant concerns across different domains. This approach may lead to a small amount of\nmonotonous and boring bloat in a few areas, but this is offset by the advantages of loose coupling.\nThis is intended to minimize the overall complexity and cognitive load of the codebase.\nBusiness logic will have clear intentions and be easy to follow, unit tests don't need to mock low level details\nabout unrelated components, and refactors can easily control their blast radius.\n\nIn a system of shared global traits between modules, any updates to an interface will cause breaking changes\nto the mocks and test harnesses for all consuming modules. This is less than ideal when these domain modules\ndon't need to use the new changes. However, in a system where each domain controls its ports, adjusting an\ninterface will only affect the port owner and the implementer.\n\nThe implementation of \"Ports\" (aka adapters) referring to other domain modules, should reside in the main fuel-core\ncrate. This way, domain modules should never need to take a dependency on each other. This helps to avoid circular\ndependencies, and also allows for lightweight rapid developer iteration within a domain module. It also ensures\nthe purity of the domain modules, preventing implementation details of modules from contaminating each other. Adapters\nare intended to restrict the viral spread of any ugly complexity that arises when integrating modules. Decisions\nsuch as whether to use channels, networking, IPC, or direct calls between domain modules can be decided in the adapter\nwithout any effect on the domain logic. They should avoid implementing any business rules, and only contain integration\nglue logic between systems.\n\nSpecial care was also taken in this design approach to keep implementation details regarding synchronization primitives\nor proprietary async runtime requirements out of any public interfaces (No channels!).\n\nSummary:\n\n - Business logic with many external dependencies should be segmented where possible into separate domain crates\n - Domain crates define \"Ports\" (traits) for external dependencies that aren't strictly of concern to the business logic.\n - Domain crates should aim to be as pure as possible and have minimal dependencies, and not depend on each other.\n - Adapters implement Ports. They are for integrating with the \"real-world\" dependencies like using other domain modules,\n   implementing serialization logic, or calling a database.\n - Adapters should either reside in the top-level crate (\"fuel-core\") or in their own crates. This prevents the domains\n   from being polluted by dependencies with large compile times or unstable interfaces. This allows for libraries like \n   networking, third-party SDKs, or database drivers to be swapped out without breaking our core domain specific logic.\n\nThe following is intended to be a living document to convey how P&A can and should be applied to the client. However, given\nmany of these components remain in flux as our needs change, these ports and flows should be considered as a foundation \nand structure for future design RFC refinements to build upon, rather than reflect a finalized view dictating how the \nsystem should forever be. When applying this design, it's encouraged to take practical and experimental steps to evolve our \ncodebase using the Ports and Adapters (P&A) principles previously summarized to help guide our decision-making based on \nevidence discovered in the process of implementation and testing.\n\n## Domains:\n\n```mermaid\nflowchart TB\n    subgraph Fuel Core\n        direction TB\n        subgraph POAS[PoA Service]\n            POAD{{Domain}}\n            SYNCPOA[Synchronizer Adapter]\n        end\n        subgraph BPS[Block Producer Service]\n            BPD{{Domain}}\n            POABP[PoA Adapter]\n            APIBP[API Adapter]\n        end\n        subgraph BIS[Block Importer Service]\n            BID{{Domain}}\n            SYNCBI[\"Sync Adapter\"]\n            POABI[\"PoA Adapter\"]\n        end\n        subgraph SS[Synchronizer Service]\n            SSD{{Domain}}\n        end\n        subgraph P2PS[P2P Service]\n            P2PD{{Domain}}\n            POAP2P[PoA Adapter]\n            SYNCP2P[Sync Adapter]\n            TXP2P[Transaction Pool Adapter]\n        end\n        subgraph TXS[Transaction Pool Service]\n            TXD{{Domain}}\n            BPTXS[Block Producer Adapter]\n            BITXS[Block Importer Adapter]\n        end\n        subgraph RS[Relayer Service]\n            RSD{{Domain}}\n            POAR[POA Adapter]\n            BPR[Block Producer Adapter]\n            BIR[Block Importer Adapter]\n        end\n        subgraph ES[Executor Service]\n            ESD{{Domain}}\n            BPEXE[Block Producer Adapter]\n            BIEXE[Block Importer Adapter]\n        end\n        subgraph APIS[API Service]\n            APID{{Domain}}\n        end\n        BID & BPD --> ES & RS & TXS\n        SSD --> P2PS & BIS\n        TXD --> P2PS\n        POAD --> P2PS & RS & BPS & BIS\n        APID --> BPS\n        \n        %% Red color - Block Importer\n        linkStyle 0,1,2 fill:none,stroke-width:4px,stroke:red\n        %% Pink color - Block Producer\n        linkStyle 3,4,5 fill:none,stroke-width:4px,stroke:pink\n        %% Green color - Synchronizer\n        linkStyle 6,7 fill:none,stroke-width:4px,stroke:green\n        %% Blue color - Transaction pool\n        linkStyle 8 fill:none,stroke-width:4px,stroke:blue\n        %% Orange color - PoA\n        linkStyle 10,11,12,9 fill:none,stroke-width:4px,stroke:orange\n        %% Purple color - API\n        linkStyle 13 fill:none,stroke-width:4px,stroke:purple\n    end\n```\n\n### (PoA) Consensus Module\n\n#### Ports: fuel_poa_consensus::ports\n```rust\ntrait BlockProducer {\n    // used by the PoA node to produce a new block and obtain fully computed block headers\n    async fn produce_block(height: BlockHeight) -> Result<FuelBlock>;\n}\n\ntrait BlockImporter {\n    // After the PoA node has signed over the block, send it to the block importer for inclusion\n    // into the finalized state of the node.\n    async fn commit(sealed_block: SealedBlock) -> Result<()>;\n}\n\ntrait Relayer {\n    // wait until the relayer eth node is synced\n    async fn await_synced() -> Result<()>;\n    // wait until the relayer reaches a desired da_height\n    async fn await_da_height(da_height: DaHeight) -> Result<()>;\n    // get the consensus key associated with a da_height\n    async fn get_poa_key(da_height: DaHeight) -> Result<ConsensusKey>;\n}\n\ntrait Database {\n    // get the current fuel chain height\n    fn get_current_height() -> Result<BlockHeight>;\n    // insert consensus information associated with a sealed block that was locally produced\n    fn insert_consensus_data(sealed_block: &SealedBlock) -> Result<()>;\n}\n```\n#### Adapters: fuel_core::service::adapters::poa_consensus\n```rust\nimpl fuel_core_sync::ports::Consensus for Service<PoA> {\n    // insert impl here\n}\n```\n\n### Block Producer\n\n#### Ports: fuel_core_producer::ports\n\n```rust\ntrait TransactionPool {\n    fn select_block_txs(max_gas: u64, block_height: BlockHeight) -> Result<Vec<Arc<CheckedTransaction>>>;\n    fn drop_txs(txs: Vec<TxId>) -> Result<()>;\n}\n\ntrait Executor {\n    async fn produce_block(block: &mut FuelBlock) -> Result<()>;\n}\n\ntrait Relayer {\n    fn get_finalized_da_height() -> Result<DaHeight>;\n}\n```\n#### Adapters: fuel_core::service::adapters::block_producer\n```rust\nimpl fuel_poa_consensus::ports::BlockProducer for Service<BlockProducer> {\n    // insert impl here\n}\n```\n\n### Block Importer\n\n#### Ports: fuel_core_importer::ports\n\n```rust\ntrait Relayer {\n    // wait until the relayer is synced with ethereum\n    async fn await_synced() -> Result<()>;\n    // wait until a specific da_height is reached\n    async fn await_da_height(da_height: DaHeight) -> Result<()>;\n}\n\ntrait Executor {\n    async fn validate_and_store_block(block: &FuelBlock) -> Result<()>;\n}\n\ntrait TransactionPool {\n    // remove a set of txs from the pool after a block is committed\n    fn drop_txs(txs: Vec<TxId>) -> Result<()>;\n}\n\ntrait Database {\n    // insert consensus information associated with a sealed block\n    fn insert_consensus_data(sealed_block: &SealedBlock) -> Result<()>;\n}\n\ntrait PeerToPeer {\n   // broadcast the finalized header to peers who may need to sync\n   async fn broadcast_sealed_header(sealed_block_header: SealedBlockHeader) -> Result<()>;\n}\n\n```\n#### Adapters: fuel_core::service::adapters::block_importer\n```rust\nimpl fuel_poa_consensus::ports::BlockImporter for Service<BlockImporter> {\n    // insert impl here\n}\n\nimpl fuel_core_sync::ports::BlockImporter for Service<BlockImporter> {\n    // insert impl here\n}\n```\n\n### Synchronizer\n\n#### Ports: fuel_core_sync::ports\n\n```rust\ntrait PeerToPeer {\n    type SealedHeaderResponse: NetworkData<SealedBlockHeader>;\n    type BlockResponse: NetworkData<Vec<SealedBlock>>;\n    type GossipedBlockHeader: NetworkData<SealedBlockHeader>;\n    \n    async fn fetch_best_network_block_header(&self) -> Result<Option<Self::SealedHeaderResponse>>;\n    async fn fetch_blocks(&self, query: Range<BlockHeight>) -> Result<Self::BlockResponse>;\n    // punish the sender for providing an invalid block header\n    fn report_invalid_block_header(&self, invalid_header: &Self::SealedHeaderResponse) -> Result<()>;\n    // punish the sender for providing a set of blocks that aren't valid\n    fn report_invalid_blocks(&self, invalid_blocks: &Self::BlockResponse) -> Result<()>;\n    // provides a stream of gossiped block header events\n    fn gossiped_block_header_events(&self) -> BoxStream<Self::SealedBlockHeader>;\n    // notify the p2p network whether to continue gossiping this message to others or\n    // punish the peer that sent it\n    fn notify_gossip_block_validity(&self, message: &Self::GossipedBlockHeader, validity: GossipValidity);\n}\n\n// Generic wrapper for data received from peers while abstracting\n// networking metadata (e.g. IP's or other IDs) needed for gossip validation\npub trait NetworkData<D> {\n    // Transfer ownership of the provided data without consuming other message metadata\n    fn take_data(&mut self) -> Option<D>;\n}\n\npub enum GossipValidity {\n    // Report whether the gossiped message is valid and safe to rebroadcast\n    Accept,\n    // Ignore the received message and prevent further gossiping\n    Ignore,\n    // Punish the gossip sender for providing invalid \n    // (or malicious) data and prevent further gossiping\n    Invalid,\n}\n\ntrait BlockImporter {\n    // commit a sealed block to the chain\n    async fn commit(block: SealedBlock) -> Result<()>;\n   \n   // check with the block importer whether a block header passes consensus rules\n   async fn validate_sealed_block_header(block: SealedBlockHeader) -> Result<()>;\n}\n\ntrait Database {\n    // get current fuel blockchain height\n    fn get_current_height() -> Result<BlockHeight>;\n}\n```\n#### Adapters: fuel_core::service::adapters::fuel_core_sync\n_N/A_\n\n### P2P\n\n#### Ports: fuel_core_p2p::ports\n```rust\ntrait Database {\n    // used when other peers are syncing\n    fn get_sealed_block(height: BlockHeight) -> Result<SealedBlock>; \n}\n```\n\n#### Adapters: fuel_core::service::adapters::peer_to_peer\n```rust\nimpl fuel_poa_consensus::ports::PeerToPeer for Service<P2pService> {\n    // insert impl here\n}\n\nimpl fuel_core_sync::ports::PeerToPeer for Service<P2pService> {\n    // insert impl here\n}\n\nimpl fuel_core_txpool::ports::PeerToPeer for Service<P2pService> {\n    // insert impl here\n}\n```\n\n### Transaction Pool\n\n#### Ports: fuel_core_txpool::ports\n```rust\ntrait PeerToPeer {\n    type GossipedTransaction: NetworkData<Transaction>;\n   \n    // Gossip broadcast a transaction inserted via API.\n    async fn broadcast_transaction(transaction: Transaction) -> Result<()>;\n\n    // Provides a stream of gossiped transactions.\n    fn gossiped_transaction_events(&self) -> BoxStream<Self::GossipedTransaction>;\n   \n    // Report the validity of a transaction received from the network.\n    fn notify_gossip_transaction_validity(message: &Self::GossipedTransaction, validity: GossipValidity) -> anyhow::Result<()>;\n}\n\ntrait BlockImporter {\n   // used to update the transaction pool from imported blocks\n   fn committed_block_events(&self) -> BoxStream<SealedBlock>;\n}\n\n// Generic wrapper for data received from peers while abstracting\n// networking metadata (e.g. IP's or other IDs) needed for gossip validation\npub trait NetworkData<D> {\n   // Transfer ownership of the provided data without consuming other message metadata\n   fn take_data(&mut self) -> Option<D>;\n}\n\npub enum GossipValidity {\n    // Report whether the gossiped message is valid and safe to rebroadcast\n    Accept,\n    // Ignore the received message and prevent further gossiping\n    Ignore,\n    // Punish the gossip sender for providing invalid \n    // (or malicious) data and prevent further gossiping\n    Invalid,\n}\n\npub trait Database:\n    StorageInspect<Coins, Error = StorageError>\n    + StorageInspect<ContractsRawCode, Error = StorageError>\n    + StorageInspect<Messages, Error = StorageError>\n    + Send\n    + Sync\n{}\n```\n\n#### Adapters: fuel_core::service::adapters::transaction_pool\n```rust\nimpl block_importer::ports::TransactionPool for Service<TransactionPool> {\n    // insert impl here\n}\n\nimpl block_producer::ports::TransactionPool for Service<TransactionPool> {\n    // insert impl here\n}\n```\n\n#### Adapters: fuel_core::service::adapters::block_importer\n```rust\nimpl transaction_pool::ports::BlockImporter for Service<BlockImporter> {\n   // insert impl here\n}\n\n```\n\n### Executor\n\n#### Ports: fuel_core_executor::ports\n```rust\ntrait Database: InterpreterStorage\n  + StorageMut<Coins, Error = StorageError>\n  + StorageMut<Messages, Error = StorageError>\n  + StorageMut<Contracts, Error = StorageError>\n  + StorageMut<Blocks, Error = StorageError>\n  + StorageMut<ContractUtxos, Error = StorageError>\n  + StorageMut<Transactions, Error = StorageError>\n  + Send\n  + Sync {\n    // start a nested transaction to allow changes to be rolled-back\n    fn db_transaction(&self) -> Box<dyn DatabaseTransaction>;\n}\n\n// Database overlay that accumulates changes until committed at the end.\ntrait DatabaseTransaction: AsRef<Box<dyn Database>> {\n    // consume the transaction and commit the changes\n    fn commit(self) -> Result<()>;\n}\n```\n#### Adapters: fuel_core::service::adapters::executor\n```rust\nimpl fuel_core_producer::ports::Executor for Service<Executor> {\n    // insert impl here\n}\n\nimpl fuel_core_importer::ports::Executor for Service<Executor> {\n    // insert impl here\n}\n```\n\n### Relayer\n\n#### Ports: fuel_core_relayer::ports\n```rust\ntrait Database: StorageMutate<Messages, Error = StorageError> {\n    fn get_da_synced_height(&self) -> Result<DaBlockHeight>;\n    fn set_da_synced_height(&self, height: DaBlockHeight) -> Result<()>;\n}\n\ntrait DataAvailabilityLayer {\n    async fn is_syncing(&self) -> SyncState;\n    async fn best_finalized_block(&self) -> Result<DaBlockHeight>;\n    async fn download_messages(&self, blocks: Range<DaBlockHeight>) -> Result<Vec<Message>>;\n}\n\npub struct DaBlockHeight(u64);\n```\n\n#### Adapters: fuel_core::service::adapters::relayer\n```rust\nimpl fuel_core_importer::ports::Relayer for Service<Relayer> {\n    // insert impl here\n}\n\nimpl fuel_core_producer::ports::Relayer for Service<Relayer> {\n    // insert impl here\n}\n\nimpl fuel_poa_consensus::ports::Relayer for Service<Relayer> {\n    // insert impl here\n}\n```\n\n### API (GraphQL)\nToo extensive to fully detail...\n\n#### Ports: fuel_core_api::ports\n\n```rust\ntrait BlockProducer {\n    // produce a single-tx block at a given height and return the receipts\n    async fn dry_run_transaction(transaction: Transaction, height: Option<BlockHeight>) -> Result<Vec<Receipt>>;\n    // start a debug session at a given height.\n    async fn start_debug_session<S>(transaction: Transaction, height: Option<BlockHeight>) -> Result<Box<dyn DebugSession<S>>>;\n}\n\ntrait DebugSession<S>: AsRef<Interpreter<S>> {\n    fn memory(&self, start: usize, len: usize) -> Option<&[u8]>;\n    fn register(&self, register: RegisterId) -> Option<Word>;\n    fn reset(&mut self) -> Result<()>;\n    fn execute(&mut self) -> Result<()>;\n}\n```\n\n#### Adapters: fuel_core::service::adapters::api\n\n```rust\nimpl fuel_core_api::ports::BlockProducer for Service<BlockProducer> {\n    // insert impl here\n}\n\nimpl<S> fuel_core_api::ports::DebugSession<S> for DebugSessionAdapter<S> {\n    // insert impl here\n}\n\n// example of adapter fulfilled implementation\npub struct DebugSessionAdapter<S> {\n    vm: Interpreter<S>,\n    db: Database,\n    tx: Transaction,\n}\n```\n\n## Fuel Core Services\n\n`fuel-core` is the connection point between all modules. Since adapters implement foreign traits for foreign domains,\neach domain should be wrapped in a local new-type such as `Service<D>`. Services should be sharable via \n`Arc<Service<D: Stoppable + Send + Sync>>`.\n\nThe `Stoppable` trait ensures each service has a graceful shutdown method and join handle for any background tasks.\nIf a service does not spawn any background tasks, this trait can be implemented as a no-op.\n\n## [Flows](./poa/flows.md)\n"},"items":[{"name":"architecture.md","path":"docs/architecture.md","rawUrl":"https://raw.githubusercontent.com/FuelLabs/fuel-core/HEAD/docs/architecture.md","title":"docs - System Architecture & Module Boundaries","category":"project-spec","format":"markdown","content":"# Fuel Client Software Architecture\n\nInspired by [Hexagonal Architecture](https://en.wikipedia.org/wiki/Hexagonal_architecture_(software)), the Fuel \nblockchain client is composed of various domain modules. Each module defines its own view of the system \nvia a class of traits we'll call \"Ports\". This is in contrast to creating globally shared interfaces\nwith the difficulty of trying to cover every possible use-case in a future-proof way, while on the other hand\nleaking many irrelevant concerns across different domains. This approach may lead to a small amount of\nmonotonous and boring bloat in a few areas, but this is offset by the advantages of loose coupling.\nThis is intended to minimize the overall complexity and cognitive load of the codebase.\nBusiness logic will have clear intentions and be easy to follow, unit tests don't need to mock low level details\nabout unrelated components, and refactors can easily control their blast radius.\n\nIn a system of shared global traits between modules, any updates to an interface will cause breaking changes\nto the mocks and test harnesses for all consuming modules. This is less than ideal when these domain modules\ndon't need to use the new changes. However, in a system where each domain controls its ports, adjusting an\ninterface will only affect the port owner and the implementer.\n\nThe implementation of \"Ports\" (aka adapters) referring to other domain modules, should reside in the main fuel-core\ncrate. This way, domain modules should never need to take a dependency on each other. This helps to avoid circular\ndependencies, and also allows for lightweight rapid developer iteration within a domain module. It also ensures\nthe purity of the domain modules, preventing implementation details of modules from contaminating each other. Adapters\nare intended to restrict the viral spread of any ugly complexity that arises when integrating modules. Decisions\nsuch as whether to use channels, networking, IPC, or direct calls between domain modules can be decided in the adapter\nwithout any effect on the domain logic. They should avoid implementing any business rules, and only contain integration\nglue logic between systems.\n\nSpecial care was also taken in this design approach to keep implementation details regarding synchronization primitives\nor proprietary async runtime requirements out of any public interfaces (No channels!).\n\nSummary:\n\n - Business logic with many external dependencies should be segmented where possible into separate domain crates\n - Domain crates define \"Ports\" (traits) for external dependencies that aren't strictly of concern to the business logic.\n - Domain crates should aim to be as pure as possible and have minimal dependencies, and not depend on each other.\n - Adapters implement Ports. They are for integrating with the \"real-world\" dependencies like using other domain modules,\n   implementing serialization logic, or calling a database.\n - Adapters should either reside in the top-level crate (\"fuel-core\") or in their own crates. This prevents the domains\n   from being polluted by dependencies with large compile times or unstable interfaces. This allows for libraries like \n   networking, third-party SDKs, or database drivers to be swapped out without breaking our core domain specific logic.\n\nThe following is intended to be a living document to convey how P&A can and should be applied to the client. However, given\nmany of these components remain in flux as our needs change, these ports and flows should be considered as a foundation \nand structure for future design RFC refinements to build upon, rather than reflect a finalized view dictating how the \nsystem should forever be. When applying this design, it's encouraged to take practical and experimental steps to evolve our \ncodebase using the Ports and Adapters (P&A) principles previously summarized to help guide our decision-making based on \nevidence discovered in the process of implementation and testing.\n\n## Domains:\n\n```mermaid\nflowchart TB\n    subgraph Fuel Core\n        direction TB\n        subgraph POAS[PoA Service]\n            POAD{{Domain}}\n            SYNCPOA[Synchronizer Adapter]\n        end\n        subgraph BPS[Block Producer Service]\n            BPD{{Domain}}\n            POABP[PoA Adapter]\n            APIBP[API Adapter]\n        end\n        subgraph BIS[Block Importer Service]\n            BID{{Domain}}\n            SYNCBI[\"Sync Adapter\"]\n            POABI[\"PoA Adapter\"]\n        end\n        subgraph SS[Synchronizer Service]\n            SSD{{Domain}}\n        end\n        subgraph P2PS[P2P Service]\n            P2PD{{Domain}}\n            POAP2P[PoA Adapter]\n            SYNCP2P[Sync Adapter]\n            TXP2P[Transaction Pool Adapter]\n        end\n        subgraph TXS[Transaction Pool Service]\n            TXD{{Domain}}\n            BPTXS[Block Producer Adapter]\n            BITXS[Block Importer Adapter]\n        end\n        subgraph RS[Relayer Service]\n            RSD{{Domain}}\n            POAR[POA Adapter]\n            BPR[Block Producer Adapter]\n            BIR[Block Importer Adapter]\n        end\n        subgraph ES[Executor Service]\n            ESD{{Domain}}\n            BPEXE[Block Producer Adapter]\n            BIEXE[Block Importer Adapter]\n        end\n        subgraph APIS[API Service]\n            APID{{Domain}}\n        end\n        BID & BPD --> ES & RS & TXS\n        SSD --> P2PS & BIS\n        TXD --> P2PS\n        POAD --> P2PS & RS & BPS & BIS\n        APID --> BPS\n        \n        %% Red color - Block Importer\n        linkStyle 0,1,2 fill:none,stroke-width:4px,stroke:red\n        %% Pink color - Block Producer\n        linkStyle 3,4,5 fill:none,stroke-width:4px,stroke:pink\n        %% Green color - Synchronizer\n        linkStyle 6,7 fill:none,stroke-width:4px,stroke:green\n        %% Blue color - Transaction pool\n        linkStyle 8 fill:none,stroke-width:4px,stroke:blue\n        %% Orange color - PoA\n        linkStyle 10,11,12,9 fill:none,stroke-width:4px,stroke:orange\n        %% Purple color - API\n        linkStyle 13 fill:none,stroke-width:4px,stroke:purple\n    end\n```\n\n### (PoA) Consensus Module\n\n#### Ports: fuel_poa_consensus::ports\n```rust\ntrait BlockProducer {\n    // used by the PoA node to produce a new block and obtain fully computed block headers\n    async fn produce_block(height: BlockHeight) -> Result<FuelBlock>;\n}\n\ntrait BlockImporter {\n    // After the PoA node has signed over the block, send it to the block importer for inclusion\n    // into the finalized state of the node.\n    async fn commit(sealed_block: SealedBlock) -> Result<()>;\n}\n\ntrait Relayer {\n    // wait until the relayer eth node is synced\n    async fn await_synced() -> Result<()>;\n    // wait until the relayer reaches a desired da_height\n    async fn await_da_height(da_height: DaHeight) -> Result<()>;\n    // get the consensus key associated with a da_height\n    async fn get_poa_key(da_height: DaHeight) -> Result<ConsensusKey>;\n}\n\ntrait Database {\n    // get the current fuel chain height\n    fn get_current_height() -> Result<BlockHeight>;\n    // insert consensus information associated with a sealed block that was locally produced\n    fn insert_consensus_data(sealed_block: &SealedBlock) -> Result<()>;\n}\n```\n#### Adapters: fuel_core::service::adapters::poa_consensus\n```rust\nimpl fuel_core_sync::ports::Consensus for Service<PoA> {\n    // insert impl here\n}\n```\n\n### Block Producer\n\n#### Ports: fuel_core_producer::ports\n\n```rust\ntrait TransactionPool {\n    fn select_block_txs(max_gas: u64, block_height: BlockHeight) -> Result<Vec<Arc<CheckedTransaction>>>;\n    fn drop_txs(txs: Vec<TxId>) -> Result<()>;\n}\n\ntrait Executor {\n    async fn produce_block(block: &mut FuelBlock) -> Result<()>;\n}\n\ntrait Relayer {\n    fn get_finalized_da_height() -> Result<DaHeight>;\n}\n```\n#### Adapters: fuel_core::service::adapters::block_producer\n```rust\nimpl fuel_poa_consensus::ports::BlockProducer for Service<BlockProducer> {\n    // insert impl here\n}\n```\n\n### Block Importer\n\n#### Ports: fuel_core_importer::ports\n\n```rust\ntrait Relayer {\n    // wait until the relayer is synced with ethereum\n    async fn await_synced() -> Result<()>;\n    // wait until a specific da_height is reached\n    async fn await_da_height(da_height: DaHeight) -> Result<()>;\n}\n\ntrait Executor {\n    async fn validate_and_store_block(block: &FuelBlock) -> Result<()>;\n}\n\ntrait TransactionPool {\n    // remove a set of txs from the pool after a block is committed\n    fn drop_txs(txs: Vec<TxId>) -> Result<()>;\n}\n\ntrait Database {\n    // insert consensus information associated with a sealed block\n    fn insert_consensus_data(sealed_block: &SealedBlock) -> Result<()>;\n}\n\ntrait PeerToPeer {\n   // broadcast the finalized header to peers who may need to sync\n   async fn broadcast_sealed_header(sealed_block_header: SealedBlockHeader) -> Result<()>;\n}\n\n```\n#### Adapters: fuel_core::service::adapters::block_importer\n```rust\nimpl fuel_poa_consensus::ports::BlockImporter for Service<BlockImporter> {\n    // insert impl here\n}\n\nimpl fuel_core_sync::ports::BlockImporter for Service<BlockImporter> {\n    // insert impl here\n}\n```\n\n### Synchronizer\n\n#### Ports: fuel_core_sync::ports\n\n```rust\ntrait PeerToPeer {\n    type SealedHeaderResponse: NetworkData<SealedBlockHeader>;\n    type BlockResponse: NetworkData<Vec<SealedBlock>>;\n    type GossipedBlockHeader: NetworkData<SealedBlockHeader>;\n    \n    async fn fetch_best_network_block_header(&self) -> Result<Option<Self::SealedHeaderResponse>>;\n    async fn fetch_blocks(&self, query: Range<BlockHeight>) -> Result<Self::BlockResponse>;\n    // punish the sender for providing an invalid block header\n    fn report_invalid_block_header(&self, invalid_header: &Self::SealedHeaderResponse) -> Result<()>;\n    // punish the sender for providing a set of blocks that aren't valid\n    fn report_invalid_blocks(&self, invalid_blocks: &Self::BlockResponse) -> Result<()>;\n    // provides a stream of gossiped block header events\n    fn gossiped_block_header_events(&self) -> BoxStream<Self::SealedBlockHeader>;\n    // notify the p2p network whether to continue gossiping this message to others or\n    // punish the peer that sent it\n    fn notify_gossip_block_validity(&self, message: &Self::GossipedBlockHeader, validity: GossipValidity);\n}\n\n// Generic wrapper for data received from peers while abstracting\n// networking metadata (e.g. IP's or other IDs) needed for gossip validation\npub trait NetworkData<D> {\n    // Transfer ownership of the provided data without consuming other message metadata\n    fn take_data(&mut self) -> Option<D>;\n}\n\npub enum GossipValidity {\n    // Report whether the gossiped message is valid and safe to rebroadcast\n    Accept,\n    // Ignore the received message and prevent further gossiping\n    Ignore,\n    // Punish the gossip sender for providing invalid \n    // (or malicious) data and prevent further gossiping\n    Invalid,\n}\n\ntrait BlockImporter {\n    // commit a sealed block to the chain\n    async fn commit(block: SealedBlock) -> Result<()>;\n   \n   // check with the block importer whether a block header passes consensus rules\n   async fn validate_sealed_block_header(block: SealedBlockHeader) -> Result<()>;\n}\n\ntrait Database {\n    // get current fuel blockchain height\n    fn get_current_height() -> Result<BlockHeight>;\n}\n```\n#### Adapters: fuel_core::service::adapters::fuel_core_sync\n_N/A_\n\n### P2P\n\n#### Ports: fuel_core_p2p::ports\n```rust\ntrait Database {\n    // used when other peers are syncing\n    fn get_sealed_block(height: BlockHeight) -> Result<SealedBlock>; \n}\n```\n\n#### Adapters: fuel_core::service::adapters::peer_to_peer\n```rust\nimpl fuel_poa_consensus::ports::PeerToPeer for Service<P2pService> {\n    // insert impl here\n}\n\nimpl fuel_core_sync::ports::PeerToPeer for Service<P2pService> {\n    // insert impl here\n}\n\nimpl fuel_core_txpool::ports::PeerToPeer for Service<P2pService> {\n    // insert impl here\n}\n```\n\n### Transaction Pool\n\n#### Ports: fuel_core_txpool::ports\n```rust\ntrait PeerToPeer {\n    type GossipedTransaction: NetworkData<Transaction>;\n   \n    // Gossip broadcast a transaction inserted via API.\n    async fn broadcast_transaction(transaction: Transaction) -> Result<()>;\n\n    // Provides a stream of gossiped transactions.\n    fn gossiped_transaction_events(&self) -> BoxStream<Self::GossipedTransaction>;\n   \n    // Report the validity of a transaction received from the network.\n    fn notify_gossip_transaction_validity(message: &Self::GossipedTransaction, validity: GossipValidity) -> anyhow::Result<()>;\n}\n\ntrait BlockImporter {\n   // used to update the transaction pool from imported blocks\n   fn committed_block_events(&self) -> BoxStream<SealedBlock>;\n}\n\n// Generic wrapper for data received from peers while abstracting\n// networking metadata (e.g. IP's or other IDs) needed for gossip validation\npub trait NetworkData<D> {\n   // Transfer ownership of the provided data without consuming other message metadata\n   fn take_data(&mut self) -> Option<D>;\n}\n\npub enum GossipValidity {\n    // Report whether the gossiped message is valid and safe to rebroadcast\n    Accept,\n    // Ignore the received message and prevent further gossiping\n    Ignore,\n    // Punish the gossip sender for providing invalid \n    // (or malicious) data and prevent further gossiping\n    Invalid,\n}\n\npub trait Database:\n    StorageInspect<Coins, Error = StorageError>\n    + StorageInspect<ContractsRawCode, Error = StorageError>\n    + StorageInspect<Messages, Error = StorageError>\n    + Send\n    + Sync\n{}\n```\n\n#### Adapters: fuel_core::service::adapters::transaction_pool\n```rust\nimpl block_importer::ports::TransactionPool for Service<TransactionPool> {\n    // insert impl here\n}\n\nimpl block_producer::ports::TransactionPool for Service<TransactionPool> {\n    // insert impl here\n}\n```\n\n#### Adapters: fuel_core::service::adapters::block_importer\n```rust\nimpl transaction_pool::ports::BlockImporter for Service<BlockImporter> {\n   // insert impl here\n}\n\n```\n\n### Executor\n\n#### Ports: fuel_core_executor::ports\n```rust\ntrait Database: InterpreterStorage\n  + StorageMut<Coins, Error = StorageError>\n  + StorageMut<Messages, Error = StorageError>\n  + StorageMut<Contracts, Error = StorageError>\n  + StorageMut<Blocks, Error = StorageError>\n  + StorageMut<ContractUtxos, Error = StorageError>\n  + StorageMut<Transactions, Error = StorageError>\n  + Send\n  + Sync {\n    // start a nested transaction to allow changes to be rolled-back\n    fn db_transaction(&self) -> Box<dyn DatabaseTransaction>;\n}\n\n// Database overlay that accumulates changes until committed at the end.\ntrait DatabaseTransaction: AsRef<Box<dyn Database>> {\n    // consume the transaction and commit the changes\n    fn commit(self) -> Result<()>;\n}\n```\n#### Adapters: fuel_core::service::adapters::executor\n```rust\nimpl fuel_core_producer::ports::Executor for Service<Executor> {\n    // insert impl here\n}\n\nimpl fuel_core_importer::ports::Executor for Service<Executor> {\n    // insert impl here\n}\n```\n\n### Relayer\n\n#### Ports: fuel_core_relayer::ports\n```rust\ntrait Database: StorageMutate<Messages, Error = StorageError> {\n    fn get_da_synced_height(&self) -> Result<DaBlockHeight>;\n    fn set_da_synced_height(&self, height: DaBlockHeight) -> Result<()>;\n}\n\ntrait DataAvailabilityLayer {\n    async fn is_syncing(&self) -> SyncState;\n    async fn best_finalized_block(&self) -> Result<DaBlockHeight>;\n    async fn download_messages(&self, blocks: Range<DaBlockHeight>) -> Result<Vec<Message>>;\n}\n\npub struct DaBlockHeight(u64);\n```\n\n#### Adapters: fuel_core::service::adapters::relayer\n```rust\nimpl fuel_core_importer::ports::Relayer for Service<Relayer> {\n    // insert impl here\n}\n\nimpl fuel_core_producer::ports::Relayer for Service<Relayer> {\n    // insert impl here\n}\n\nimpl fuel_poa_consensus::ports::Relayer for Service<Relayer> {\n    // insert impl here\n}\n```\n\n### API (GraphQL)\nToo extensive to fully detail...\n\n#### Ports: fuel_core_api::ports\n\n```rust\ntrait BlockProducer {\n    // produce a single-tx block at a given height and return the receipts\n    async fn dry_run_transaction(transaction: Transaction, height: Option<BlockHeight>) -> Result<Vec<Receipt>>;\n    // start a debug session at a given height.\n    async fn start_debug_session<S>(transaction: Transaction, height: Option<BlockHeight>) -> Result<Box<dyn DebugSession<S>>>;\n}\n\ntrait DebugSession<S>: AsRef<Interpreter<S>> {\n    fn memory(&self, start: usize, len: usize) -> Option<&[u8]>;\n    fn register(&self, register: RegisterId) -> Option<Word>;\n    fn reset(&mut self) -> Result<()>;\n    fn execute(&mut self) -> Result<()>;\n}\n```\n\n#### Adapters: fuel_core::service::adapters::api\n\n```rust\nimpl fuel_core_api::ports::BlockProducer for Service<BlockProducer> {\n    // insert impl here\n}\n\nimpl<S> fuel_core_api::ports::DebugSession<S> for DebugSessionAdapter<S> {\n    // insert impl here\n}\n\n// example of adapter fulfilled implementation\npub struct DebugSessionAdapter<S> {\n    vm: Interpreter<S>,\n    db: Database,\n    tx: Transaction,\n}\n```\n\n## Fuel Core Services\n\n`fuel-core` is the connection point between all modules. Since adapters implement foreign traits for foreign domains,\neach domain should be wrapped in a local new-type such as `Service<D>`. Services should be sharable via \n`Arc<Service<D: Stoppable + Send + Sync>>`.\n\nThe `Stoppable` trait ensures each service has a graceful shutdown method and join handle for any background tasks.\nIf a service does not spawn any background tasks, this trait can be implemented as a no-op.\n\n## [Flows](./poa/flows.md)\n","isInternal":false,"tokens":4064,"sizeBytes":17488}],"systemPromptSnippet":"<yakaai_skills repo=\"FuelLabs/fuel-core\">\n<!-- File: docs/architecture.md (Tokens: ~4064 | Category: project-spec) -->\n# Fuel Client Software Architecture\n\nInspired by [Hexagonal Architecture](https://en.wikipedia.org/wiki/Hexagonal_architecture_(software)), the Fuel \nblockchain client is composed of various domain modules. Each module defines its own view of the system \nvia a class of traits we'll call \"Ports\". This is in contrast to creating globally shared interfaces\nwith the difficulty of trying to cover every possible use-case in a future-proof way, while on the other hand\nleaking many irrelevant concerns across different domains. This approach may lead to a small amount of\nmonotonous and boring bloat in a few areas, but this is offset by the advantages of loose coupling.\nThis is intended to minimize the overall complexity and cognitive load of the codebase.\nBusiness logic will have clear intentions and be easy to follow, unit tests don't need to mock low level details\nabout unrelated components, and refactors can easily control their blast radius.\n\nIn a system of shared global traits between modules, any updates to an interface will cause breaking changes\nto the mocks and test harnesses for all consuming modules. This is less than ideal when these domain modules\ndon't need to use the new changes. However, in a system where each domain controls its ports, adjusting an\ninterface will only affect the port owner and the implementer.\n\nThe implementation of \"Ports\" (aka adapters) referring to other domain modules, should reside in the main fuel-core\ncrate. This way, domain modules should never need to take a dependency on each other. This helps to avoid circular\ndependencies, and also allows for lightweight rapid developer iteration within a domain module. It also ensures\nthe purity of the domain modules, preventing implementation details of modules from contaminating each other. Adapters\nare intended to restrict the viral spread of any ugly complexity that arises when integrating modules. Decisions\nsuch as whether to use channels, networking, IPC, or direct calls between domain modules can be decided in the adapter\nwithout any effect on the domain logic. They should avoid implementing any business rules, and only contain integration\nglue logic between systems.\n\nSpecial care was also taken in this design approach to keep implementation details regarding synchronization primitives\nor proprietary async runtime requirements out of any public interfaces (No channels!).\n\nSummary:\n\n - Business logic with many external dependencies should be segmented where possible into separate domain crates\n - Domain crates define \"Ports\" (traits) for external dependencies that aren't strictly of concern to the business logic.\n - Domain crates should aim to be as pure as possible and have minimal dependencies, and not depend on each other.\n - Adapters implement Ports. They are for integrating with the \"real-world\" dependencies like using other domain modules,\n   implementing serialization logic, or calling a database.\n - Adapters should either reside in the top-level crate (\"fuel-core\") or in their own crates. This prevents the domains\n   from being polluted by dependencies with large compile times or unstable interfaces. This allows for libraries like \n   networking, third-party SDKs, or database drivers to be swapped out without breaking our core domain specific logic.\n\nThe following is intended to be a living document to convey how P&A can and should be applied to the client. However, given\nmany of these components remain in flux as our needs change, these ports and flows should be considered as a foundation \nand structure for future design RFC refinements to build upon, rather than reflect a finalized view dictating how the \nsystem should forever be. When applying this design, it's encouraged to take practical and experimental steps to evolve our \ncodebase using the Ports and Adapters (P&A) principles previously summarized to help guide our decision-making based on \nevidence discovered in the process of implementation and testing.\n\n## Domains:\n\n```mermaid\nflowchart TB\n    subgraph Fuel Core\n        direction TB\n        subgraph POAS[PoA Service]\n            POAD{{Domain}}\n            SYNCPOA[Synchronizer Adapter]\n        end\n        subgraph BPS[Block Producer Service]\n            BPD{{Domain}}\n            POABP[PoA Adapter]\n            APIBP[API Adapter]\n        end\n        subgraph BIS[Block Importer Service]\n            BID{{Domain}}\n            SYNCBI[\"Sync Adapter\"]\n            POABI[\"PoA Adapter\"]\n        end\n        subgraph SS[Synchronizer Service]\n            SSD{{Domain}}\n        end\n        subgraph P2PS[P2P Service]\n            P2PD{{Domain}}\n            POAP2P[PoA Adapter]\n            SYNCP2P[Sync Adapter]\n            TXP2P[Transaction Pool Adapter]\n        end\n        subgraph TXS[Transaction Pool Service]\n            TXD{{Domain}}\n            BPTXS[Block Producer Adapter]\n            BITXS[Block Importer Adapter]\n        end\n        subgraph RS[Relayer Service]\n            RSD{{Domain}}\n            POAR[POA Adapter]\n            BPR[Block Producer Adapter]\n            BIR[Block Importer Adapter]\n        end\n        subgraph ES[Executor Service]\n            ESD{{Domain}}\n            BPEXE[Block Producer Adapter]\n            BIEXE[Block Importer Adapter]\n        end\n        subgraph APIS[API Service]\n            APID{{Domain}}\n        end\n        BID & BPD --> ES & RS & TXS\n        SSD --> P2PS & BIS\n        TXD --> P2PS\n        POAD --> P2PS & RS & BPS & BIS\n        APID --> BPS\n        \n        %% Red color - Block Importer\n        linkStyle 0,1,2 fill:none,stroke-width:4px,stroke:red\n        %% Pink color - Block Producer\n        linkStyle 3,4,5 fill:none,stroke-width:4px,stroke:pink\n        %% Green color - Synchronizer\n        linkStyle 6,7 fill:none,stroke-width:4px,stroke:green\n        %% Blue color - Transaction pool\n        linkStyle 8 fill:none,stroke-width:4px,stroke:blue\n        %% Orange color - PoA\n        linkStyle 10,11,12,9 fill:none,stroke-width:4px,stroke:orange\n        %% Purple color - API\n        linkStyle 13 fill:none,stroke-width:4px,stroke:purple\n    end\n```\n\n### (PoA) Consensus Module\n\n#### Ports: fuel_poa_consensus::ports\n```rust\ntrait BlockProducer {\n    // used by the PoA node to produce a new block and obtain fully computed block headers\n    async fn produce_block(height: BlockHeight) -> Result<FuelBlock>;\n}\n\ntrait BlockImporter {\n    // After the PoA node has signed over the block, send it to the block importer for inclusion\n    // into the finalized state of the node.\n    async fn commit(sealed_block: SealedBlock) -> Result<()>;\n}\n\ntrait Relayer {\n    // wait until the relayer eth node is synced\n    async fn await_synced() -> Result<()>;\n    // wait until the relayer reaches a desired da_height\n    async fn await_da_height(da_height: DaHeight) -> Result<()>;\n    // get the consensus key associated with a da_height\n    async fn get_poa_key(da_height: DaHeight) -> Result<ConsensusKey>;\n}\n\ntrait Database {\n    // get the current fuel chain height\n    fn get_current_height() -> Result<BlockHeight>;\n    // insert consensus information associated with a sealed block that was locally produced\n    fn insert_consensus_data(sealed_block: &SealedBlock) -> Result<()>;\n}\n```\n#### Adapters: fuel_core::service::adapters::poa_consensus\n```rust\nimpl fuel_core_sync::ports::Consensus for Service<PoA> {\n    // insert impl here\n}\n```\n\n### Block Producer\n\n#### Ports: fuel_core_producer::ports\n\n```rust\ntrait TransactionPool {\n    fn select_block_txs(max_gas: u64, block_height: BlockHeight) -> Result<Vec<Arc<CheckedTransaction>>>;\n    fn drop_txs(txs: Vec<TxId>) -> Result<()>;\n}\n\ntrait Executor {\n    async fn produce_block(block: &mut FuelBlock) -> Result<()>;\n}\n\ntrait Relayer {\n    fn get_finalized_da_height() -> Result<DaHeight>;\n}\n```\n#### Adapters: fuel_core::service::adapters::block_producer\n```rust\nimpl fuel_poa_consensus::ports::BlockProducer for Service<BlockProducer> {\n    // insert impl here\n}\n```\n\n### Block Importer\n\n#### Ports: fuel_core_importer::ports\n\n```rust\ntrait Relayer {\n    // wait until the relayer is synced with ethereum\n    async fn await_synced() -> Result<()>;\n    // wait until a specific da_height is reached\n    async fn await_da_height(da_height: DaHeight) -> Result<()>;\n}\n\ntrait Executor {\n    async fn validate_and_store_block(block: &FuelBlock) -> Result<()>;\n}\n\ntrait TransactionPool {\n    // remove a set of txs from the pool after a block is committed\n    fn drop_txs(txs: Vec<TxId>) -> Result<()>;\n}\n\ntrait Database {\n    // insert consensus information associated with a sealed block\n    fn insert_consensus_data(sealed_block: &SealedBlock) -> Result<()>;\n}\n\ntrait PeerToPeer {\n   // broadcast the finalized header to peers who may need to sync\n   async fn broadcast_sealed_header(sealed_block_header: SealedBlockHeader) -> Result<()>;\n}\n\n```\n#### Adapters: fuel_core::service::adapters::block_importer\n```rust\nimpl fuel_poa_consensus::ports::BlockImporter for Service<BlockImporter> {\n    // insert impl here\n}\n\nimpl fuel_core_sync::ports::BlockImporter for Service<BlockImporter> {\n    // insert impl here\n}\n```\n\n### Synchronizer\n\n#### Ports: fuel_core_sync::ports\n\n```rust\ntrait PeerToPeer {\n    type SealedHeaderResponse: NetworkData<SealedBlockHeader>;\n    type BlockResponse: NetworkData<Vec<SealedBlock>>;\n    type GossipedBlockHeader: NetworkData<SealedBlockHeader>;\n    \n    async fn fetch_best_network_block_header(&self) -> Result<Option<Self::SealedHeaderResponse>>;\n    async fn fetch_blocks(&self, query: Range<BlockHeight>) -> Result<Self::BlockResponse>;\n    // punish the sender for providing an invalid block header\n    fn report_invalid_block_header(&self, invalid_header: &Self::SealedHeaderResponse) -> Result<()>;\n    // punish the sender for providing a set of blocks that aren't valid\n    fn report_invalid_blocks(&self, invalid_blocks: &Self::BlockResponse) -> Result<()>;\n    // provides a stream of gossiped block header events\n    fn gossiped_block_header_events(&self) -> BoxStream<Self::SealedBlockHeader>;\n    // notify the p2p network whether to continue gossiping this message to others or\n    // punish the peer that sent it\n    fn notify_gossip_block_validity(&self, message: &Self::GossipedBlockHeader, validity: GossipValidity);\n}\n\n// Generic wrapper for data received from peers while abstracting\n// networking metadata (e.g. IP's or other IDs) needed for gossip validation\npub trait NetworkData<D> {\n    // Transfer ownership of the provided data without consuming other message metadata\n    fn take_data(&mut self) -> Option<D>;\n}\n\npub enum GossipValidity {\n    // Report whether the gossiped message is valid and safe to rebroadcast\n    Accept,\n    // Ignore the received message and prevent further gossiping\n    Ignore,\n    // Punish the gossip sender for providing invalid \n    // (or malicious) data and prevent further gossiping\n    Invalid,\n}\n\ntrait BlockImporter {\n    // commit a sealed block to the chain\n    async fn commit(block: SealedBlock) -> Result<()>;\n   \n   // check with the block importer whether a block header passes consensus rules\n   async fn validate_sealed_block_header(block: SealedBlockHeader) -> Result<()>;\n}\n\ntrait Database {\n    // get current fuel blockchain height\n    fn get_current_height() -> Result<BlockHeight>;\n}\n```\n#### Adapters: fuel_core::service::adapters::fuel_core_sync\n_N/A_\n\n### P2P\n\n#### Ports: fuel_core_p2p::ports\n```rust\ntrait Database {\n    // used when other peers are syncing\n    fn get_sealed_block(height: BlockHeight) -> Result<SealedBlock>; \n}\n```\n\n#### Adapters: fuel_core::service::adapters::peer_to_peer\n```rust\nimpl fuel_poa_consensus::ports::PeerToPeer for Service<P2pService> {\n    // insert impl here\n}\n\nimpl fuel_core_sync::ports::PeerToPeer for Service<P2pService> {\n    // insert impl here\n}\n\nimpl fuel_core_txpool::ports::PeerToPeer for Service<P2pService> {\n    // insert impl here\n}\n```\n\n### Transaction Pool\n\n#### Ports: fuel_core_txpool::ports\n```rust\ntrait PeerToPeer {\n    type GossipedTransaction: NetworkData<Transaction>;\n   \n    // Gossip broadcast a transaction inserted via API.\n    async fn broadcast_transaction(transaction: Transaction) -> Result<()>;\n\n    // Provides a stream of gossiped transactions.\n    fn gossiped_transaction_events(&self) -> BoxStream<Self::GossipedTransaction>;\n   \n    // Report the validity of a transaction received from the network.\n    fn notify_gossip_transaction_validity(message: &Self::GossipedTransaction, validity: GossipValidity) -> anyhow::Result<()>;\n}\n\ntrait BlockImporter {\n   // used to update the transaction pool from imported blocks\n   fn committed_block_events(&self) -> BoxStream<SealedBlock>;\n}\n\n// Generic wrapper for data received from peers while abstracting\n// networking metadata (e.g. IP's or other IDs) needed for gossip validation\npub trait NetworkData<D> {\n   // Transfer ownership of the provided data without consuming other message metadata\n   fn take_data(&mut self) -> Option<D>;\n}\n\npub enum GossipValidity {\n    // Report whether the gossiped message is valid and safe to rebroadcast\n    Accept,\n    // Ignore the received message and prevent further gossiping\n    Ignore,\n    // Punish the gossip sender for providing invalid \n    // (or malicious) data and prevent further gossiping\n    Invalid,\n}\n\npub trait Database:\n    StorageInspect<Coins, Error = StorageError>\n    + StorageInspect<ContractsRawCode, Error = StorageError>\n    + StorageInspect<Messages, Error = StorageError>\n    + Send\n    + Sync\n{}\n```\n\n#### Adapters: fuel_core::service::adapters::transaction_pool\n```rust\nimpl block_importer::ports::TransactionPool for Service<TransactionPool> {\n    // insert impl here\n}\n\nimpl block_producer::ports::TransactionPool for Service<TransactionPool> {\n    // insert impl here\n}\n```\n\n#### Adapters: fuel_core::service::adapters::block_importer\n```rust\nimpl transaction_pool::ports::BlockImporter for Service<BlockImporter> {\n   // insert impl here\n}\n\n```\n\n### Executor\n\n#### Ports: fuel_core_executor::ports\n```rust\ntrait Database: InterpreterStorage\n  + StorageMut<Coins, Error = StorageError>\n  + StorageMut<Messages, Error = StorageError>\n  + StorageMut<Contracts, Error = StorageError>\n  + StorageMut<Blocks, Error = StorageError>\n  + StorageMut<ContractUtxos, Error = StorageError>\n  + StorageMut<Transactions, Error = StorageError>\n  + Send\n  + Sync {\n    // start a nested transaction to allow changes to be rolled-back\n    fn db_transaction(&self) -> Box<dyn DatabaseTransaction>;\n}\n\n// Database overlay that accumulates changes until committed at the end.\ntrait DatabaseTransaction: AsRef<Box<dyn Database>> {\n    // consume the transaction and commit the changes\n    fn commit(self) -> Result<()>;\n}\n```\n#### Adapters: fuel_core::service::adapters::executor\n```rust\nimpl fuel_core_producer::ports::Executor for Service<Executor> {\n    // insert impl here\n}\n\nimpl fuel_core_importer::ports::Executor for Service<Executor> {\n    // insert impl here\n}\n```\n\n### Relayer\n\n#### Ports: fuel_core_relayer::ports\n```rust\ntrait Database: StorageMutate<Messages, Error = StorageError> {\n    fn get_da_synced_height(&self) -> Result<DaBlockHeight>;\n    fn set_da_synced_height(&self, height: DaBlockHeight) -> Result<()>;\n}\n\ntrait DataAvailabilityLayer {\n    async fn is_syncing(&self) -> SyncState;\n    async fn best_finalized_block(&self) -> Result<DaBlockHeight>;\n    async fn download_messages(&self, blocks: Range<DaBlockHeight>) -> Result<Vec<Message>>;\n}\n\npub struct DaBlockHeight(u64);\n```\n\n#### Adapters: fuel_core::service::adapters::relayer\n```rust\nimpl fuel_core_importer::ports::Relayer for Service<Relayer> {\n    // insert impl here\n}\n\nimpl fuel_core_producer::ports::Relayer for Service<Relayer> {\n    // insert impl here\n}\n\nimpl fuel_poa_consensus::ports::Relayer for Service<Relayer> {\n    // insert impl here\n}\n```\n\n### API (GraphQL)\nToo extensive to fully detail...\n\n#### Ports: fuel_core_api::ports\n\n```rust\ntrait BlockProducer {\n    // produce a single-tx block at a given height and return the receipts\n    async fn dry_run_transaction(transaction: Transaction, height: Option<BlockHeight>) -> Result<Vec<Receipt>>;\n    // start a debug session at a given height.\n    async fn start_debug_session<S>(transaction: Transaction, height: Option<BlockHeight>) -> Result<Box<dyn DebugSession<S>>>;\n}\n\ntrait DebugSession<S>: AsRef<Interpreter<S>> {\n    fn memory(&self, start: usize, len: usize) -> Option<&[u8]>;\n    fn register(&self, register: RegisterId) -> Option<Word>;\n    fn reset(&mut self) -> Result<()>;\n    fn execute(&mut self) -> Result<()>;\n}\n```\n\n#### Adapters: fuel_core::service::adapters::api\n\n```rust\nimpl fuel_core_api::ports::BlockProducer for Service<BlockProducer> {\n    // insert impl here\n}\n\nimpl<S> fuel_core_api::ports::DebugSession<S> for DebugSessionAdapter<S> {\n    // insert impl here\n}\n\n// example of adapter fulfilled implementation\npub struct DebugSessionAdapter<S> {\n    vm: Interpreter<S>,\n    db: Database,\n    tx: Transaction,\n}\n```\n\n## Fuel Core Services\n\n`fuel-core` is the connection point between all modules. Since adapters implement foreign traits for foreign domains,\neach domain should be wrapped in a local new-type such as `Service<D>`. Services should be sharable via \n`Arc<Service<D: Stoppable + Send + Sync>>`.\n\nThe `Stoppable` trait ensures each service has a graceful shutdown method and join handle for any background tasks.\nIf a service does not spawn any background tasks, this trait can be implemented as a no-op.\n\n## [Flows](./poa/flows.md)\n</yakaai_skills>"}