Jelajahi Sumber

explorerd: folder-based modules for rpc, service, and store

This commit reorganizes the project structure by grouping RPC, service, and store functionalities into dedicated module folders:

- `rpc`: Handles JSON-RPC interactions, migrated from `rpc_*.rs` (e.g., `rpc_transactions.rs` → `rpc/transactions.rs`)
- `service`: structured to contain the core logic for block synchronization, chain data access, metadata storage/retrieval, and statistics computation
- `store`: manages persistent storage for blockchain, contracts, metrics, and metadata

This structural refactor introduces no functional changes.

Benefits:
- Simplifies the crate root
- Groups related functionality into cohesive module boundaries
- Removes need for file prefixes and suffixes (e.g., `rpc_`, `_store`) by relying on folder-based module names for context (e.g., `rpc::blocks`, `store::metrics`)
- Enhances separation of concerns with defined responsibilities across the `rpc`, `service`, and `store` modules
- Implements domain-based boundaries that reflect the system's architecture
- Aims to improve maintainability and readability, particularly for new contributors
kalm 1 tahun lalu
induk
melakukan
826b6dbc50

+ 16 - 212
bin/explorer/explorerd/src/main.rs

@@ -16,99 +16,50 @@
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-use lazy_static::lazy_static;
-use log::{debug, error, info};
-use sled_overlay::sled;
+use std::{collections::HashSet, path::Path, sync::Arc};
+
+use log::{error, info};
 use smol::{lock::Mutex, stream::StreamExt};
-use std::{
-    collections::{HashMap, HashSet},
-    path::Path,
-    str::FromStr,
-    sync::Arc,
-};
 use structopt_toml::{serde::Deserialize, structopt::StructOpt, StructOptToml};
 use url::Url;
 
 use darkfi::{
-    async_daemonize,
-    blockchain::{Blockchain, BlockchainOverlay},
-    cli_desc,
+    async_daemonize, cli_desc,
     rpc::{
         client::RpcClient,
         server::{listen_and_serve, RequestHandler},
     },
     system::{StoppableTask, StoppableTaskPtr},
-    util::path::{expand_path, get_config_path},
-    validator::utils::deploy_native_contracts,
+    util::path::get_config_path,
     Error, Result,
 };
-use darkfi_sdk::crypto::{ContractId, DAO_CONTRACT_ID, DEPLOYOOOR_CONTRACT_ID, MONEY_CONTRACT_ID};
 
 use crate::{
-    config::ExplorerNetworkConfig,
-    contract_meta_store::{ContractMetaData, ContractMetaStore},
-    contracts::untar_source,
-    metrics_store::MetricsStore,
-    rpc_blocks::subscribe_blocks,
+    config::ExplorerNetworkConfig, rpc::blocks::subscribe_blocks, service::ExplorerService,
 };
 
-/// Crate errors
-mod error;
+/// Configuration management across multiple networks (localnet, testnet, mainnet)
+mod config;
 
-/// JSON-RPC requests handler and methods
+/// Manages JSON-RPC interactions for the explorer
 mod rpc;
-mod rpc_blocks;
-mod rpc_contracts;
-mod rpc_statistics;
-mod rpc_transactions;
 
-/// Service functionality related to blocks
-mod blocks;
+/// Core logic for block synchronization, chain data access, metadata storage/retrieval,
+/// and statistics computation
+mod service;
 
-/// Service functionality related to transactions
-mod transactions;
+/// Manages persistent storage for blockchain, contracts, metrics, and metadata
+mod store;
 
-/// Service functionality related to statistics
-mod statistics;
-
-/// Service functionality related to contracts
-mod contracts;
+/// Crate errors
+mod error;
 
 /// Test utilities used for unit and integration testing
 mod test_utils;
 
-/// Database store functionality related to metrics
-mod metrics_store;
-
-/// Database store functionality related to contract metadata
-mod contract_meta_store;
-
-/// Configuration management across multiple networks (localnet, testnet, mainnet)
-mod config;
-
 const CONFIG_FILE: &str = "explorerd_config.toml";
 const CONFIG_FILE_CONTENTS: &str = include_str!("../explorerd_config.toml");
 
-// Load the contract source archives to bootstrap them on explorer startup
-lazy_static! {
-    static ref NATIVE_CONTRACT_SOURCE_ARCHIVES: HashMap<String, &'static [u8]> = {
-        let mut src_map = HashMap::new();
-        src_map.insert(
-            MONEY_CONTRACT_ID.to_string(),
-            &include_bytes!("../native_contracts_src/money_contract_src.tar")[..],
-        );
-        src_map.insert(
-            DAO_CONTRACT_ID.to_string(),
-            &include_bytes!("../native_contracts_src/dao_contract_src.tar")[..],
-        );
-        src_map.insert(
-            DEPLOYOOOR_CONTRACT_ID.to_string(),
-            &include_bytes!("../native_contracts_src/deployooor_contract_src.tar")[..],
-        );
-        src_map
-    };
-}
-
 #[derive(Clone, Debug, Deserialize, StructOpt, StructOptToml)]
 #[serde(default)]
 #[structopt(name = "explorerd", about = cli_desc!())]
@@ -134,153 +85,6 @@ struct Args {
     verbose: u8,
 }
 
-/// Represents the service layer for the Explorer application, bridging the RPC layer and the database.
-/// It encapsulates explorer business logic and provides a unified interface for core functionalities,
-/// providing a clear separation of concerns between RPC handling and data management layers.
-///
-/// Core functionalities include:
-///
-/// - Data Transformation: Converting database data into structured responses suitable for RPC callers.
-/// - Blocks: Synchronization, retrieval, counting, and management.
-/// - Contracts: Handling native and user contract data, source code, tar files, and metadata.
-/// - Metrics: Providing metric-related data over the life of the chain.
-/// - Transactions: Synchronization, calculating gas data, retrieval, counting, and related block information.
-pub struct ExplorerService {
-    /// Explorer database instance
-    db: ExplorerDb,
-}
-
-impl ExplorerService {
-    /// Creates a new `ExplorerService` instance.
-    pub fn new(db_path: String) -> Result<Self> {
-        // Initialize explorer database
-        let db = ExplorerDb::new(db_path)?;
-
-        Ok(Self { db })
-    }
-
-    /// Initializes the explorer service by deploying native contracts and loading native contract
-    /// source code and metadata required for its operation.
-    pub async fn init(&self) -> Result<()> {
-        self.deploy_native_contracts().await?;
-        self.load_native_contract_sources()?;
-        self.load_native_contract_metadata()?;
-        Ok(())
-    }
-
-    /// Deploys native contracts required for gas calculation and retrieval.
-    pub async fn deploy_native_contracts(&self) -> Result<()> {
-        let overlay = BlockchainOverlay::new(&self.db.blockchain)?;
-        deploy_native_contracts(&overlay, 10).await?;
-        overlay.lock().unwrap().overlay.lock().unwrap().apply()?;
-        Ok(())
-    }
-
-    /// Loads native contract source code into the explorer database by extracting it from tar archives
-    /// created during the explorer build process. The extracted source code is associated with
-    /// the corresponding [`ContractId`] for each loaded contract and stored.
-    pub fn load_native_contract_sources(&self) -> Result<()> {
-        // Iterate each native contract source archive
-        for (contract_id_str, archive_bytes) in NATIVE_CONTRACT_SOURCE_ARCHIVES.iter() {
-            // Untar the native contract source code
-            let source_code = untar_source(archive_bytes)?;
-
-            // Parse contract id into a contract id instance
-            let contract_id = &ContractId::from_str(contract_id_str)?;
-
-            // Add source code into the `ContractMetaStore`
-            self.db.contract_meta_store.insert_source(contract_id, &source_code)?;
-            info!(target: "explorerd: load_native_contract_sources", "Loaded native contract source {}", contract_id_str.to_string());
-        }
-        Ok(())
-    }
-
-    /// Loads [`ContractMetaData`] for deployed native contracts into the explorer database by adding descriptive
-    /// information (e.g., name and description) used to display contract details.
-    pub fn load_native_contract_metadata(&self) -> Result<()> {
-        let contract_ids = [*MONEY_CONTRACT_ID, *DAO_CONTRACT_ID, *DEPLOYOOOR_CONTRACT_ID];
-
-        // Create pre-defined native contract metadata
-        let metadatas = [
-            ContractMetaData::new(
-                "Money".to_string(),
-                "Facilitates money transfers, atomic swaps, minting, freezing, and staking of consensus tokens".to_string(),
-            ),
-            ContractMetaData::new(
-                "DAO".to_string(),
-                "Provides functionality for Anonymous DAOs".to_string(),
-            ),
-            ContractMetaData::new(
-                "Deployoor".to_string(),
-                "Handles non-native smart contract deployments".to_string(),
-            ),
-        ];
-
-        // Load contract metadata into the `ContractMetaStore`
-        self.db.contract_meta_store.insert_metadata(&contract_ids, &metadatas)?;
-        info!(target: "explorerd: load_native_contract_metadata", "Loaded metadata for native contracts");
-
-        Ok(())
-    }
-
-    /// Resets the explorer state to the specified height. If a genesis block height is provided,
-    /// all blocks and transactions are purged from the database. Otherwise, the state is reverted
-    /// to the given height. The explorer metrics are updated to reflect the updated blocks and
-    /// transactions up to the reset height, ensuring consistency. Returns a result indicating
-    /// success or an error if the operation fails.
-    pub fn reset_explorer_state(&self, height: u32) -> Result<()> {
-        debug!(target: "explorerd::reset_explorer_state", "Resetting explorer state to height: {height}");
-
-        // Check if a genesis block reset or to a specific height
-        match height {
-            // Reset for genesis height 0, purge blocks and transactions
-            0 => {
-                self.reset_blocks()?;
-                self.reset_transactions()?;
-                debug!(target: "explorerd::reset_explorer_state", "Reset explorer state to accept a new genesis block");
-            }
-            // Reset for all other heights
-            _ => {
-                self.reset_to_height(height)?;
-                debug!(target: "explorerd::reset_explorer_state", "Reset blocks to height: {height}");
-            }
-        }
-
-        // Reset gas metrics to the specified height to reflect the updated blockchain state
-        self.db.metrics_store.reset_gas_metrics(height)?;
-        debug!(target: "explorerd::reset_explorer_state", "Reset metrics store to height: {height}");
-
-        Ok(())
-    }
-}
-
-/// Represents the explorer database backed by a `sled` database connection, responsible for maintaining
-/// persistent state required for blockchain exploration. It serves as the core data layer for the Explorer application,
-/// storing and managing blockchain data, metrics, and contract-related information.
-pub struct ExplorerDb {
-    /// The main `sled` database connection used for data storage and retrieval
-    pub sled_db: sled::Db,
-    /// Local copy of the Darkfi blockchain used for block synchronization and exploration
-    pub blockchain: Blockchain,
-    /// Store for tracking chain-related metrics
-    pub metrics_store: MetricsStore,
-    /// Store for managing contract metadata, source code, and related data
-    pub contract_meta_store: ContractMetaStore,
-}
-
-impl ExplorerDb {
-    /// Creates a new `ExplorerDb` instance
-    pub fn new(db_path: String) -> Result<Self> {
-        let db_path = expand_path(db_path.as_str())?;
-        let sled_db = sled::open(&db_path)?;
-        let blockchain = Blockchain::new(&sled_db)?;
-        let metrics_store = MetricsStore::new(&sled_db)?;
-        let contract_meta_store = ContractMetaStore::new(&sled_db)?;
-        info!(target: "explorerd", "Initialized explorer database {}: block count: {}, tx count: {}", db_path.display(), blockchain.len(), blockchain.txs_len());
-        Ok(Self { sled_db, blockchain, metrics_store, contract_meta_store })
-    }
-}
-
 /// Defines a daemon structure responsible for handling incoming JSON-RPC requests and delegating them
 /// to the backend layer for processing. It provides a JSON-RPC interface for managing operations related to
 /// blocks, transactions, contracts, and metrics.

+ 0 - 0
bin/explorer/explorerd/src/rpc_blocks.rs → bin/explorer/explorerd/src/rpc/blocks.rs


+ 0 - 0
bin/explorer/explorerd/src/rpc_contracts.rs → bin/explorer/explorerd/src/rpc/contracts.rs


+ 12 - 0
bin/explorer/explorerd/src/rpc.rs → bin/explorer/explorerd/src/rpc/mod.rs

@@ -37,6 +37,18 @@ use crate::{
     Explorerd,
 };
 
+/// RPC block related requests
+pub mod blocks;
+
+/// RPC handlers for contract-related perations
+pub mod contracts;
+
+/// RPC handlers for blockchain statistics and metrics
+pub mod statistics;
+
+/// RPC handlers for transaction data, lookups, and processing
+pub mod transactions;
+
 #[async_trait]
 impl RequestHandler<()> for Explorerd {
     async fn handle_request(&self, req: JsonRequest) -> JsonResult {

+ 0 - 0
bin/explorer/explorerd/src/rpc_statistics.rs → bin/explorer/explorerd/src/rpc/statistics.rs


+ 0 - 0
bin/explorer/explorerd/src/rpc_transactions.rs → bin/explorer/explorerd/src/rpc/transactions.rs


+ 0 - 0
bin/explorer/explorerd/src/blocks.rs → bin/explorer/explorerd/src/service/blocks.rs


+ 73 - 8
bin/explorer/explorerd/src/contracts.rs → bin/explorer/explorerd/src/service/contracts.rs

@@ -16,17 +16,26 @@
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-use std::io::{Cursor, Read};
+use std::{
+    io::{Cursor, Read},
+    str::FromStr,
+};
 
+use log::info;
 use tar::Archive;
 use tinyjson::JsonValue;
 
-use darkfi::{Error, Result};
+use darkfi::{
+    blockchain::BlockchainOverlay, validator::utils::deploy_native_contracts, Error, Result,
+};
 use darkfi_sdk::crypto::{ContractId, DAO_CONTRACT_ID, DEPLOYOOOR_CONTRACT_ID, MONEY_CONTRACT_ID};
 use darkfi_serial::deserialize;
 
 use crate::{
-    contract_meta_store::{ContractMetaData, ContractSourceFile},
+    store::{
+        contract_metadata::{ContractMetaData, ContractSourceFile},
+        NATIVE_CONTRACT_SOURCE_ARCHIVES,
+    },
     ExplorerService,
 };
 
@@ -53,7 +62,13 @@ impl ContractRecord {
         ])
     }
 }
+
 impl ExplorerService {
+    /// Fetches the total contract count of all deployed contracts in the explorer database.
+    pub fn get_contract_count(&self) -> usize {
+        self.db.blockchain.contracts.wasm.len()
+    }
+
     /// Retrieves all contracts from the store excluding native contracts (DAO, Deployooor, and Money),
     /// transforming them into `Vec` of [`ContractRecord`]s, and returns the result.
     pub fn get_contracts(&self) -> Result<Vec<ContractRecord>> {
@@ -104,11 +119,6 @@ impl ExplorerService {
         })
     }
 
-    /// Fetches the total contract count of all deployed contracts in the explorer database.
-    pub fn get_contract_count(&self) -> usize {
-        self.db.blockchain.contracts.wasm.len()
-    }
-
     /// Adds source code for a specified [`ContractId`] from a provided tar file (in bytes).
     ///
     /// This function extracts the tar archive from `tar_bytes`, then loads each source file
@@ -140,6 +150,61 @@ impl ExplorerService {
         })
     }
 
+    /// Deploys native contracts required for gas calculation and retrieval.
+    pub async fn deploy_native_contracts(&self) -> Result<()> {
+        let overlay = BlockchainOverlay::new(&self.db.blockchain)?;
+        deploy_native_contracts(&overlay, 10).await?;
+        overlay.lock().unwrap().overlay.lock().unwrap().apply()?;
+        Ok(())
+    }
+
+    /// Loads native contract source code into the explorer database by extracting it from tar archives
+    /// created during the explorer build process. The extracted source code is associated with
+    /// the corresponding [`ContractId`] for each loaded contract and stored.
+    pub fn load_native_contract_sources(&self) -> Result<()> {
+        // Iterate each native contract source archive
+        for (contract_id_str, archive_bytes) in NATIVE_CONTRACT_SOURCE_ARCHIVES.iter() {
+            // Untar the native contract source code
+            let source_code = untar_source(archive_bytes)?;
+
+            // Parse contract id into a contract id instance
+            let contract_id = &ContractId::from_str(contract_id_str)?;
+
+            // Add source code into the `ContractMetaStore`
+            self.db.contract_meta_store.insert_source(contract_id, &source_code)?;
+            info!(target: "explorerd: load_native_contract_sources", "Loaded native contract source {}", contract_id_str.to_string());
+        }
+        Ok(())
+    }
+
+    /// Loads [`ContractMetaData`] for deployed native contracts into the explorer database by adding descriptive
+    /// information (e.g., name and description) used to display contract details.
+    pub fn load_native_contract_metadata(&self) -> Result<()> {
+        let contract_ids = [*MONEY_CONTRACT_ID, *DAO_CONTRACT_ID, *DEPLOYOOOR_CONTRACT_ID];
+
+        // Create pre-defined native contract metadata
+        let metadatas = [
+            ContractMetaData::new(
+                "Money".to_string(),
+                "Facilitates money transfers, atomic swaps, minting, freezing, and staking of consensus tokens".to_string(),
+            ),
+            ContractMetaData::new(
+                "DAO".to_string(),
+                "Provides functionality for Anonymous DAOs".to_string(),
+            ),
+            ContractMetaData::new(
+                "Deployoor".to_string(),
+                "Handles non-native smart contract deployments".to_string(),
+            ),
+        ];
+
+        // Load contract metadata into the `ContractMetaStore`
+        self.db.contract_meta_store.insert_metadata(&contract_ids, &metadatas)?;
+        info!(target: "explorerd: load_native_contract_metadata", "Loaded metadata for native contracts");
+
+        Ok(())
+    }
+
     /// Converts a [`ContractId`] into a [`ContractRecord`].
     ///
     /// This function retrieves the [`ContractMetaData`] associated with the provided Contract ID

+ 100 - 0
bin/explorer/explorerd/src/service/mod.rs

@@ -0,0 +1,100 @@
+/* This file is part of DarkFi (https://dark.fi)
+ *
+ * Copyright (C) 2020-2025 Dyne.org foundation
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+use log::debug;
+
+use darkfi::Result;
+
+use crate::store::ExplorerDb;
+
+/// Handles core block-related functionality
+pub mod blocks;
+
+/// Implements functionality for smart contracts
+pub mod contracts;
+
+/// Powers metrics gathering and analytical capabilities
+pub mod statistics;
+
+/// Manages transaction data processing
+pub mod transactions;
+
+/// Represents the service layer for the Explorer application, bridging the RPC layer and the database.
+/// It encapsulates explorer business logic and provides a unified interface for core functionalities,
+/// providing a clear separation of concerns between RPC handling and data management layers.
+///
+/// Core functionalities include:
+///
+/// - Data Transformation: Converting database data into structured responses suitable for RPC callers.
+/// - Blocks: Synchronization, retrieval, counting, and management.
+/// - Contracts: Handling native and user contract data, source code, tar files, and metadata.
+/// - Metrics: Providing metric-related data over the life of the chain.
+/// - Transactions: Synchronization, calculating gas data, retrieval, counting, and related block information.
+pub struct ExplorerService {
+    /// Explorer database instance
+    pub db: ExplorerDb,
+}
+
+impl ExplorerService {
+    /// Creates a new `ExplorerService` instance.
+    pub fn new(db_path: String) -> Result<Self> {
+        // Initialize explorer database
+        let db = ExplorerDb::new(db_path)?;
+
+        Ok(Self { db })
+    }
+
+    /// Initializes the explorer service by deploying native contracts and loading native contract
+    /// source code and metadata required for its operation.
+    pub async fn init(&self) -> Result<()> {
+        self.deploy_native_contracts().await?;
+        self.load_native_contract_sources()?;
+        self.load_native_contract_metadata()?;
+        Ok(())
+    }
+
+    /// Resets the explorer state to the specified height. If a genesis block height is provided,
+    /// all blocks and transactions are purged from the database. Otherwise, the state is reverted
+    /// to the given height. The explorer metrics are updated to reflect the updated blocks and
+    /// transactions up to the reset height, ensuring consistency. Returns a result indicating
+    /// success or an error if the operation fails.
+    pub fn reset_explorer_state(&self, height: u32) -> Result<()> {
+        debug!(target: "explorerd::reset_explorer_state", "Resetting explorer state to height: {height}");
+
+        // Check if a genesis block reset or to a specific height
+        match height {
+            // Reset for genesis height 0, purge blocks and transactions
+            0 => {
+                self.reset_blocks()?;
+                self.reset_transactions()?;
+                debug!(target: "explorerd::reset_explorer_state", "Reset explorer state to accept a new genesis block");
+            }
+            // Reset for all other heights
+            _ => {
+                self.reset_to_height(height)?;
+                debug!(target: "explorerd::reset_explorer_state", "Reset blocks to height: {height}");
+            }
+        }
+
+        // Reset gas metrics to the specified height to reflect the updated blockchain state
+        self.db.metrics_store.reset_gas_metrics(height)?;
+        debug!(target: "explorerd::reset_explorer_state", "Reset metrics store to height: {height}");
+
+        Ok(())
+    }
+}

+ 1 - 1
bin/explorer/explorerd/src/statistics.rs → bin/explorer/explorerd/src/service/statistics.rs

@@ -21,7 +21,7 @@ use tinyjson::JsonValue;
 use darkfi::{Error, Result};
 use darkfi_sdk::blockchain::block_epoch;
 
-use crate::{metrics_store::GasMetrics, ExplorerService};
+use crate::{service::ExplorerService, store::metrics::GasMetrics};
 
 #[derive(Debug, Clone)]
 /// Structure representing basic statistic extracted from the database.

+ 0 - 0
bin/explorer/explorerd/src/transactions.rs → bin/explorer/explorerd/src/service/transactions.rs


+ 0 - 0
bin/explorer/explorerd/src/contract_meta_store.rs → bin/explorer/explorerd/src/store/contract_metadata.rs


+ 0 - 0
bin/explorer/explorerd/src/metrics_store.rs → bin/explorer/explorerd/src/store/metrics.rs


+ 82 - 0
bin/explorer/explorerd/src/store/mod.rs

@@ -0,0 +1,82 @@
+/* This file is part of DarkFi (https://dark.fi)
+ *
+ * Copyright (C) 2020-2025 Dyne.org foundation
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+use std::collections::HashMap;
+
+use lazy_static::lazy_static;
+use log::info;
+use sled_overlay::sled;
+
+use darkfi::{blockchain::Blockchain, error::Result, util::path::expand_path};
+
+use darkfi_sdk::crypto::{DAO_CONTRACT_ID, DEPLOYOOOR_CONTRACT_ID, MONEY_CONTRACT_ID};
+
+use crate::store::{contract_metadata::ContractMetaStore, metrics::MetricsStore};
+
+/// Stores, manages, and provides access to explorer metrics
+pub mod metrics;
+
+/// Stores, manages, and provides access to contract metadata
+pub mod contract_metadata;
+
+/// Represents the explorer database backed by a `sled` database connection, responsible for maintaining
+/// persistent state required for blockchain exploration. It serves as the core data layer for the Explorer application,
+/// storing and managing blockchain data, metrics, and contract-related information.
+pub struct ExplorerDb {
+    /// The main `sled` database connection used for data storage and retrieval
+    pub sled_db: sled::Db,
+    /// Local copy of the Darkfi blockchain used for block synchronization and exploration
+    pub blockchain: Blockchain,
+    /// Store for tracking chain-related metrics
+    pub metrics_store: MetricsStore,
+    /// Store for managing contract metadata, source code, and related data
+    pub contract_meta_store: ContractMetaStore,
+}
+
+impl ExplorerDb {
+    /// Creates a new `ExplorerDb` instance
+    pub fn new(db_path: String) -> Result<Self> {
+        let db_path = expand_path(db_path.as_str())?;
+        let sled_db = sled::open(&db_path)?;
+        let blockchain = Blockchain::new(&sled_db)?;
+        let metrics_store = MetricsStore::new(&sled_db)?;
+        let contract_meta_store = ContractMetaStore::new(&sled_db)?;
+        info!(target: "explorerd", "Initialized explorer database {}: block count: {}, tx count: {}", db_path.display(), blockchain.len(), blockchain.txs_len());
+        Ok(Self { sled_db, blockchain, metrics_store, contract_meta_store })
+    }
+}
+
+// Contract source archives used to bootstrap native contracts during explorer startup
+lazy_static! {
+    pub static ref NATIVE_CONTRACT_SOURCE_ARCHIVES: HashMap<String, &'static [u8]> = {
+        let mut src_map = HashMap::new();
+        src_map.insert(
+            MONEY_CONTRACT_ID.to_string(),
+            &include_bytes!("../../native_contracts_src/money_contract_src.tar")[..],
+        );
+        src_map.insert(
+            DAO_CONTRACT_ID.to_string(),
+            &include_bytes!("../../native_contracts_src/dao_contract_src.tar")[..],
+        );
+        src_map.insert(
+            DEPLOYOOOR_CONTRACT_ID.to_string(),
+            &include_bytes!("../../native_contracts_src/deployooor_contract_src.tar")[..],
+        );
+        src_map
+    };
+}