stratus/eth/miner/
miner_config.rs

1use std::str::FromStr;
2use std::sync::Arc;
3use std::time::Duration;
4
5use clap::Parser;
6use display_json::DebugAsJson;
7
8use crate::GlobalState;
9use crate::NodeMode;
10use crate::eth::miner::Miner;
11use crate::eth::storage::StratusStorage;
12use crate::ext::not;
13use crate::ext::parse_duration;
14
15// -----------------------------------------------------------------------------
16// Config
17// -----------------------------------------------------------------------------
18
19#[derive(Parser, DebugAsJson, Clone, serde::Serialize)]
20pub struct MinerConfig {
21    /// Target block time.
22    #[arg(long = "block-mode", env = "BLOCK_MODE", default_value = "automine")]
23    pub block_mode: MinerMode,
24}
25
26impl MinerConfig {
27    /// Inits [`Miner`] with the appropriate mining mode based on the node mode.
28    pub async fn init(&self, storage: Arc<StratusStorage>) -> anyhow::Result<Arc<Miner>> {
29        tracing::info!(config = ?self, "creating block miner");
30
31        let mode = match GlobalState::get_node_mode() {
32            NodeMode::Follower | NodeMode::FakeLeader => {
33                if not(self.block_mode.is_external()) {
34                    tracing::error!(block_mode = ?self.block_mode, "invalid block-mode, a follower's miner can only start as external!");
35                }
36                MinerMode::External
37            }
38            NodeMode::Leader => self.block_mode,
39        };
40
41        self.init_with_mode(mode, storage).await
42    }
43
44    /// Inits [`Miner`] with a specific mining mode, regardless of node mode.
45    pub async fn init_with_mode(&self, mode: MinerMode, storage: Arc<StratusStorage>) -> anyhow::Result<Arc<Miner>> {
46        tracing::info!(config = ?self, mode = ?mode, "creating block miner with specific mode");
47
48        // create miner
49        let miner = Miner::new(Arc::clone(&storage), mode);
50        let miner = Arc::new(miner);
51
52        if let MinerMode::Interval(block_time) = mode {
53            miner.start_interval_mining(block_time).await;
54        }
55
56        Ok(miner)
57    }
58}
59
60// -----------------------------------------------------------------------------
61// Mode
62// -----------------------------------------------------------------------------
63
64/// Indicates when the miner will mine new blocks.
65#[derive(Debug, Clone, Copy, PartialEq, strum::EnumIs, serde::Serialize, serde::Deserialize)]
66pub enum MinerMode {
67    /// Mines a new block for each transaction execution.
68    #[serde(rename = "automine")]
69    Automine,
70
71    /// Mines a new block at specified interval.
72    #[serde(rename = "interval")]
73    Interval(Duration),
74
75    /// Does not automatically mines a new block. A call to `mine_*` must be executed to mine a new block.
76    #[serde(rename = "external")]
77    External,
78}
79
80impl FromStr for MinerMode {
81    type Err = anyhow::Error;
82
83    fn from_str(s: &str) -> anyhow::Result<Self, Self::Err> {
84        match s {
85            "automine" => Ok(Self::Automine),
86            "external" => Ok(Self::External),
87            s => {
88                let block_time = parse_duration(s)?;
89                Ok(Self::Interval(block_time))
90            }
91        }
92    }
93}