ord/
chain.rs

1use {super::*, clap::ValueEnum};
2
3#[derive(Default, ValueEnum, Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
4#[serde(rename_all = "kebab-case")]
5pub enum Chain {
6  #[default]
7  #[value(alias("main"))]
8  Mainnet,
9  #[value(alias("test"))]
10  Testnet,
11  Signet,
12  Regtest,
13}
14
15impl Chain {
16  pub fn network(self) -> Network {
17    self.into()
18  }
19
20  pub(crate) fn default_rpc_port(self) -> u16 {
21    match self {
22      Self::Mainnet => 8332,
23      Self::Regtest => 18443,
24      Self::Signet => 38332,
25      Self::Testnet => 18332,
26    }
27  }
28
29  pub fn inscription_content_size_limit(self) -> Option<usize> {
30    match self {
31      Self::Mainnet | Self::Regtest => None,
32      Self::Testnet | Self::Signet => Some(1024),
33    }
34  }
35
36  pub fn first_inscription_height(self) -> u32 {
37    match self {
38      Self::Mainnet => 767430,
39      Self::Regtest => 0,
40      Self::Signet => 112402,
41      Self::Testnet => 2413343,
42    }
43  }
44
45  pub fn first_rune_height(self) -> u32 {
46    Rune::first_rune_height(self.into())
47  }
48
49  pub fn jubilee_height(self) -> u32 {
50    match self {
51      Self::Mainnet => 824544,
52      Self::Regtest => 110,
53      Self::Signet => 175392,
54      Self::Testnet => 2544192,
55    }
56  }
57
58  pub(crate) fn genesis_block(self) -> Block {
59    bitcoin::blockdata::constants::genesis_block(self.network())
60  }
61
62  pub(crate) fn genesis_coinbase_outpoint(self) -> OutPoint {
63    OutPoint {
64      txid: self.genesis_block().coinbase().unwrap().txid(),
65      vout: 0,
66    }
67  }
68
69  pub(crate) fn address_from_script(
70    self,
71    script: &Script,
72  ) -> Result<Address, bitcoin::address::Error> {
73    Address::from_script(script, self.network())
74  }
75
76  pub(crate) fn join_with_data_dir(self, data_dir: impl AsRef<Path>) -> PathBuf {
77    match self {
78      Self::Mainnet => data_dir.as_ref().to_owned(),
79      Self::Testnet => data_dir.as_ref().join("testnet3"),
80      Self::Signet => data_dir.as_ref().join("signet"),
81      Self::Regtest => data_dir.as_ref().join("regtest"),
82    }
83  }
84}
85
86impl From<Chain> for Network {
87  fn from(chain: Chain) -> Network {
88    match chain {
89      Chain::Mainnet => Network::Bitcoin,
90      Chain::Testnet => Network::Testnet,
91      Chain::Signet => Network::Signet,
92      Chain::Regtest => Network::Regtest,
93    }
94  }
95}
96
97impl Display for Chain {
98  fn fmt(&self, f: &mut Formatter) -> fmt::Result {
99    write!(
100      f,
101      "{}",
102      match self {
103        Self::Mainnet => "mainnet",
104        Self::Regtest => "regtest",
105        Self::Signet => "signet",
106        Self::Testnet => "testnet",
107      }
108    )
109  }
110}
111
112impl FromStr for Chain {
113  type Err = Error;
114
115  fn from_str(s: &str) -> Result<Self, Self::Err> {
116    match s {
117      "mainnet" => Ok(Self::Mainnet),
118      "regtest" => Ok(Self::Regtest),
119      "signet" => Ok(Self::Signet),
120      "testnet" => Ok(Self::Testnet),
121      _ => bail!("invalid chain `{s}`"),
122    }
123  }
124}
125
126#[cfg(test)]
127mod tests {
128  use super::*;
129
130  #[test]
131  fn from_str() {
132    assert_eq!("mainnet".parse::<Chain>().unwrap(), Chain::Mainnet);
133    assert_eq!("regtest".parse::<Chain>().unwrap(), Chain::Regtest);
134    assert_eq!("signet".parse::<Chain>().unwrap(), Chain::Signet);
135    assert_eq!("testnet".parse::<Chain>().unwrap(), Chain::Testnet);
136    assert_eq!(
137      "foo".parse::<Chain>().unwrap_err().to_string(),
138      "invalid chain `foo`"
139    );
140  }
141}