Skip to main content

dusk_node_data/
hard_fork.rs

1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at http://mozilla.org/MPL/2.0/.
4//
5// Copyright (c) DUSK NETWORK. All rights reserved.
6
7use std::sync::OnceLock;
8
9use dusk_core::signatures::bls::BlsVersion;
10
11/// Activation height value that means "never activate".
12const NEVER: u64 = u64::MAX;
13
14/// Active protocol hardfork.
15#[derive(Debug, Clone, Copy, Eq, PartialEq)]
16pub enum HardFork {
17    /// Behavior before any explicit hardfork activation.
18    PreFork,
19    /// Behavior after Aegis activation.
20    Aegis,
21}
22
23impl HardFork {
24    /// Returns the BLS signature version for this hardfork.
25    pub fn bls_version(&self) -> BlsVersion {
26        match self {
27            HardFork::Aegis => BlsVersion::V2,
28            HardFork::PreFork => BlsVersion::V1,
29        }
30    }
31}
32
33/// Returns the BLS version for the given block height.
34pub fn bls_version_at(block_height: u64) -> BlsVersion {
35    hard_fork_at(block_height).bls_version()
36}
37
38static AEGIS_ACTIVATION_HEIGHT: OnceLock<u64> = OnceLock::new();
39
40/// Initializes the Aegis activation height once for this process.
41pub fn set_aegis_activation_height(block_height: u64) {
42    if let Some(existing) = AEGIS_ACTIVATION_HEIGHT.get() {
43        debug_assert_eq!(
44            *existing, block_height,
45            "Aegis activation height changed after initialization"
46        );
47        return;
48    }
49
50    let _ = AEGIS_ACTIVATION_HEIGHT.set(block_height);
51}
52
53/// Returns the configured Aegis activation height, or `NEVER` if unset.
54fn aegis_activation_height() -> u64 {
55    *AEGIS_ACTIVATION_HEIGHT.get().unwrap_or(&NEVER)
56}
57
58/// Returns the active hardfork for `block_height`.
59pub fn hard_fork_at(block_height: u64) -> HardFork {
60    if block_height >= aegis_activation_height() {
61        HardFork::Aegis
62    } else {
63        HardFork::PreFork
64    }
65}
66
67/// Returns the active hardfork for `block_height`, given an activation height.
68#[cfg(test)]
69pub(crate) const fn hard_fork_at_with_activation(
70    block_height: u64,
71    aegis_activation_height: u64,
72) -> HardFork {
73    if block_height >= aegis_activation_height {
74        HardFork::Aegis
75    } else {
76        HardFork::PreFork
77    }
78}
79
80#[cfg(test)]
81mod tests {
82    use super::*;
83
84    #[test]
85    fn aegis_activation_boundary() {
86        assert_eq!(hard_fork_at_with_activation(99, 100), HardFork::PreFork);
87        assert_eq!(hard_fork_at_with_activation(100, 100), HardFork::Aegis);
88        assert_eq!(hard_fork_at_with_activation(101, 100), HardFork::Aegis);
89        assert_eq!(hard_fork_at_with_activation(101, NEVER), HardFork::PreFork);
90    }
91}