1use crate::constants::*;
8use crate::types::{ForkId, Network};
9
10pub trait IsForkActive {
15 fn is_fork_active(&self, fork: ForkId, height: u64) -> bool;
17}
18
19#[derive(Debug, Clone)]
24pub struct ForkActivationTable {
25 pub bip30_deactivation: u64,
27 pub bip16: u64,
29 pub bip34: u64,
30 pub bip66: u64,
31 pub bip65: u64,
32 pub bip112: u64,
33 pub bip147: u64,
34 pub segwit: u64,
35 pub taproot: u64,
36 pub ctv: u64,
37 pub csfs: u64,
38 pub bip54: u64,
39}
40
41impl IsForkActive for ForkActivationTable {
42 #[inline]
43 fn is_fork_active(&self, fork: ForkId, height: u64) -> bool {
44 match fork {
45 ForkId::Bip30 => height <= self.bip30_deactivation,
46 ForkId::Bip16 => height >= self.bip16,
47 ForkId::Bip34 => height >= self.bip34,
48 ForkId::Bip66 => height >= self.bip66,
49 ForkId::Bip65 => height >= self.bip65,
50 ForkId::Bip112 => height >= self.bip112,
51 ForkId::Bip147 => height >= self.bip147,
52 ForkId::SegWit => height >= self.segwit,
53 ForkId::Taproot => height >= self.taproot,
54 ForkId::Ctv => self.ctv != u64::MAX && height >= self.ctv,
55 ForkId::Csfs => self.csfs != u64::MAX && height >= self.csfs,
56 ForkId::Bip54 => height >= self.bip54,
57 }
58 }
59}
60
61impl ForkActivationTable {
62 pub fn from_network(network: Network) -> Self {
64 Self::from_network_and_bip54_override(network, None)
65 }
66
67 pub fn from_network_and_bip54_override(
69 network: Network,
70 bip54_activation_override: Option<u64>,
71 ) -> Self {
72 let (
73 bip30_deactivation,
74 bip16,
75 bip34,
76 bip66,
77 bip65,
78 bip112,
79 bip147,
80 segwit,
81 taproot,
82 ctv,
83 csfs,
84 ) = match network {
85 Network::Mainnet => (
86 BIP30_DEACTIVATION_MAINNET,
87 BIP16_P2SH_ACTIVATION_MAINNET,
88 BIP34_ACTIVATION_MAINNET,
89 BIP66_ACTIVATION_MAINNET,
90 BIP65_ACTIVATION_MAINNET,
91 BIP112_CSV_ACTIVATION_MAINNET,
92 BIP147_ACTIVATION_MAINNET,
93 SEGWIT_ACTIVATION_MAINNET,
94 TAPROOT_ACTIVATION_MAINNET,
95 if CTV_ACTIVATION_MAINNET == 0 {
96 u64::MAX
97 } else {
98 CTV_ACTIVATION_MAINNET
99 },
100 if CSFS_ACTIVATION_MAINNET == 0 {
101 u64::MAX
102 } else {
103 CSFS_ACTIVATION_MAINNET
104 },
105 ),
106 Network::Testnet => (
107 BIP30_DEACTIVATION_TESTNET,
108 BIP16_P2SH_ACTIVATION_TESTNET,
109 BIP34_ACTIVATION_TESTNET,
110 BIP66_ACTIVATION_TESTNET,
111 BIP65_ACTIVATION_TESTNET,
112 BIP112_CSV_ACTIVATION_TESTNET,
113 BIP147_ACTIVATION_TESTNET,
114 SEGWIT_ACTIVATION_TESTNET,
115 TAPROOT_ACTIVATION_TESTNET,
116 if CTV_ACTIVATION_TESTNET == 0 {
117 u64::MAX
118 } else {
119 CTV_ACTIVATION_TESTNET
120 },
121 if CSFS_ACTIVATION_TESTNET == 0 {
122 u64::MAX
123 } else {
124 CSFS_ACTIVATION_TESTNET
125 },
126 ),
127 Network::Regtest => (
128 BIP30_DEACTIVATION_REGTEST,
129 BIP16_P2SH_ACTIVATION_REGTEST,
130 BIP34_ACTIVATION_REGTEST,
131 BIP66_ACTIVATION_REGTEST,
132 0,
133 BIP112_CSV_ACTIVATION_REGTEST,
134 0,
135 0,
136 0,
137 CTV_ACTIVATION_REGTEST,
138 CSFS_ACTIVATION_REGTEST,
139 ),
140 };
141
142 let bip54 = bip54_activation_override.unwrap_or(match network {
143 Network::Mainnet => BIP54_ACTIVATION_MAINNET,
144 Network::Testnet => BIP54_ACTIVATION_TESTNET,
145 Network::Regtest => BIP54_ACTIVATION_REGTEST,
146 });
147
148 Self {
149 bip30_deactivation,
150 bip16,
151 bip34,
152 bip66,
153 bip65,
154 bip112,
155 bip147,
156 segwit,
157 taproot,
158 ctv,
159 csfs,
160 bip54,
161 }
162 }
163}
164
165#[inline]
167pub fn taproot_activation_height(network: Network) -> u64 {
168 match network {
169 Network::Mainnet => TAPROOT_ACTIVATION_MAINNET,
170 Network::Testnet => TAPROOT_ACTIVATION_TESTNET,
171 Network::Regtest => 0,
172 }
173}
174
175#[cfg(test)]
176mod tests {
177 use super::*;
178 use crate::types::Network;
179
180 #[test]
181 fn fork_table_testnet_matches_primitives() {
182 let t = ForkActivationTable::from_network(Network::Testnet);
183 assert_eq!(t.bip65, BIP65_ACTIVATION_TESTNET);
184 assert_eq!(t.bip112, BIP112_CSV_ACTIVATION_TESTNET);
185 assert_eq!(t.bip147, BIP147_ACTIVATION_TESTNET);
186 assert_eq!(t.segwit, SEGWIT_ACTIVATION_TESTNET);
187 assert_eq!(t.taproot, TAPROOT_ACTIVATION_TESTNET);
188 }
189
190 #[test]
191 fn taproot_activation_height_matches_table() {
192 for net in [Network::Mainnet, Network::Testnet, Network::Regtest] {
193 let h = taproot_activation_height(net);
194 let t = ForkActivationTable::from_network(net).taproot;
195 assert_eq!(h, t, "{net:?}");
196 }
197 }
198}