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}