dusk_node_data/
hard_fork.rs1use std::sync::OnceLock;
8
9use dusk_core::signatures::bls::BlsVersion;
10use dusk_core::transfer::TransactionFormat;
11
12const NEVER: u64 = u64::MAX;
14
15#[derive(Debug, Clone, Copy, Eq, PartialEq)]
17pub enum HardFork {
18 PreFork,
20 Aegis,
22 Boreas,
24}
25
26impl HardFork {
27 pub const fn bls_version(self) -> BlsVersion {
29 match self {
30 HardFork::Aegis | HardFork::Boreas => BlsVersion::V2,
31 HardFork::PreFork => BlsVersion::V1,
32 }
33 }
34
35 pub const fn ledger_tx_format(self) -> TransactionFormat {
37 match self {
38 HardFork::PreFork => TransactionFormat::PreAegis,
39 HardFork::Aegis => TransactionFormat::Aegis,
40 HardFork::Boreas => TransactionFormat::Boreas,
41 }
42 }
43
44 pub const fn ingress_tx_format(self) -> TransactionFormat {
46 match self {
47 HardFork::PreFork | HardFork::Aegis => TransactionFormat::Aegis,
48 HardFork::Boreas => TransactionFormat::Boreas,
49 }
50 }
51}
52
53pub fn bls_version_at(block_height: u64) -> BlsVersion {
55 hard_fork_at(block_height).bls_version()
56}
57
58static AEGIS_ACTIVATION_HEIGHT: OnceLock<u64> = OnceLock::new();
59static BOREAS_ACTIVATION_HEIGHT: OnceLock<u64> = OnceLock::new();
60
61pub fn set_aegis_activation_height(block_height: u64) {
63 if let Some(existing) = AEGIS_ACTIVATION_HEIGHT.get() {
64 debug_assert_eq!(
65 *existing, block_height,
66 "Aegis activation height changed after initialization"
67 );
68 return;
69 }
70
71 let _ = AEGIS_ACTIVATION_HEIGHT.set(block_height);
72}
73
74pub fn set_boreas_activation_height(block_height: u64) {
76 if let Some(existing) = BOREAS_ACTIVATION_HEIGHT.get() {
77 debug_assert_eq!(
78 *existing, block_height,
79 "Boreas activation height changed after initialization"
80 );
81 return;
82 }
83
84 let _ = BOREAS_ACTIVATION_HEIGHT.set(block_height);
85}
86
87fn aegis_activation_height() -> u64 {
89 *AEGIS_ACTIVATION_HEIGHT.get().unwrap_or(&NEVER)
90}
91
92fn boreas_activation_height() -> u64 {
94 *BOREAS_ACTIVATION_HEIGHT.get().unwrap_or(&NEVER)
95}
96
97pub fn hard_fork_at(block_height: u64) -> HardFork {
99 if block_height >= boreas_activation_height() {
100 HardFork::Boreas
101 } else if block_height >= aegis_activation_height() {
102 HardFork::Aegis
103 } else {
104 HardFork::PreFork
105 }
106}
107
108pub fn ledger_tx_format_at(block_height: u64) -> TransactionFormat {
110 hard_fork_at(block_height).ledger_tx_format()
111}
112
113pub fn ingress_tx_format_at(block_height: u64) -> TransactionFormat {
115 hard_fork_at(block_height).ingress_tx_format()
116}
117
118#[cfg(test)]
120pub(crate) const fn hard_fork_at_with_activation(
121 block_height: u64,
122 aegis_activation_height: u64,
123 boreas_activation_height: u64,
124) -> HardFork {
125 if block_height >= boreas_activation_height {
126 HardFork::Boreas
127 } else if block_height >= aegis_activation_height {
128 HardFork::Aegis
129 } else {
130 HardFork::PreFork
131 }
132}
133
134#[cfg(test)]
135mod tests {
136 use super::*;
137
138 #[test]
139 fn hard_fork_and_format_policy_matrix() {
140 let cases = [
141 (
142 99,
143 100,
144 NEVER,
145 HardFork::PreFork,
146 TransactionFormat::PreAegis,
147 TransactionFormat::Aegis,
148 ),
149 (
150 100,
151 100,
152 NEVER,
153 HardFork::Aegis,
154 TransactionFormat::Aegis,
155 TransactionFormat::Aegis,
156 ),
157 (
158 101,
159 NEVER,
160 NEVER,
161 HardFork::PreFork,
162 TransactionFormat::PreAegis,
163 TransactionFormat::Aegis,
164 ),
165 (
166 199,
167 100,
168 200,
169 HardFork::Aegis,
170 TransactionFormat::Aegis,
171 TransactionFormat::Aegis,
172 ),
173 (
174 200,
175 100,
176 200,
177 HardFork::Boreas,
178 TransactionFormat::Boreas,
179 TransactionFormat::Boreas,
180 ),
181 ];
182
183 for (
184 height,
185 aegis_activation_height,
186 boreas_activation_height,
187 expected_hard_fork,
188 expected_ledger_format,
189 expected_ingress_format,
190 ) in cases
191 {
192 let hard_fork = hard_fork_at_with_activation(
193 height,
194 aegis_activation_height,
195 boreas_activation_height,
196 );
197
198 assert_eq!(hard_fork, expected_hard_fork);
199 assert_eq!(hard_fork.ledger_tx_format(), expected_ledger_format);
200 assert_eq!(hard_fork.ingress_tx_format(), expected_ingress_format);
201 }
202 }
203}