1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
//! Hard forks parameters.

use ckb_constant::hardfork::{mainnet, testnet};
use ckb_types::core::{
    hardfork::{HardForkSwitch, HardForkSwitchBuilder},
    EpochNumber,
};
use serde::{Deserialize, Serialize};

/// Hard forks parameters for spec.
#[derive(Default, Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct HardForkConfig {
    /// Use input cell committing block timestamp as the start time for the relative timestamp in `since`.
    ///
    /// Ref: [CKB RFC 0028](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0028-change-since-relative-timestamp/0028-change-since-relative-timestamp.md)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub rfc_0028: Option<EpochNumber>,
    /// Allow Multiple Cell Dep Matches When There Is No Ambiguity.
    ///
    /// Ref: [CKB RFC 0029](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0029-allow-script-multiple-matches-on-identical-code/0029-allow-script-multiple-matches-on-identical-code.md)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub rfc_0029: Option<EpochNumber>,
    /// Ensure That Index Is Less Than Length In the Input Since Field Using Epoch With Fraction.
    ///
    /// Ref: [CKB RFC 0030](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0030-ensure-index-less-than-length-in-since/0030-ensure-index-less-than-length-in-since.md)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub rfc_0030: Option<EpochNumber>,
    /// Add a variable length field in the block: reuse `uncles_hash` in the header as `extra_hash`.
    ///
    /// Ref: [CKB RFC 0031](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0031-variable-length-header-field/0031-variable-length-header-field.md)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub rfc_0031: Option<EpochNumber>,
    /// CKB VM Version Selection.
    ///
    /// This feature include 4 parts:
    /// - CKB VM Version Selection.
    /// - CKB VM version 1.
    /// - CKB VM Syscalls 2.
    /// - P2P protocol upgrade.
    ///
    /// Ref:
    /// - [CKB RFC 0032](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0032-ckb-vm-version-selection/0032-ckb-vm-version-selection.md)
    /// - [CKB RFC 0033](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0033-ckb-vm-version-1/0033-ckb-vm-version-1.md)
    /// - [CKB RFC 0034](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0034-vm-syscalls-2/0034-vm-syscalls-2.md)
    /// - [CKB RFC 0035](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0035-ckb2021-p2p-protocol-upgrade/0035-ckb2021-p2p-protocol-upgrade.md)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub rfc_0032: Option<EpochNumber>,
    /// Remove Header Deps Immature Rule.
    ///
    /// Ref: [CKB RFC 0036](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0036-remove-header-deps-immature-rule/0036-remove-header-deps-immature-rule.md)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub rfc_0036: Option<EpochNumber>,
    // TODO ckb2021 update the description and the rfc link
    /// Disallow over the max dep expansion limit.
    ///
    /// Ref: CKB RFC 0038
    #[serde(skip_serializing_if = "Option::is_none")]
    pub rfc_0038: Option<EpochNumber>,
}

macro_rules! check_default {
    ($config:ident, $feature:ident, $expected:expr) => {
        if $config.$feature.is_some() {
            let errmsg = format!(
                "Found the hard fork feature parameter \"{}\" is the chain specification file.
                Don't set any hard fork parameters for \"mainnet\" or \"testnet\".",
                stringify!($feature),
            );
            return Err(errmsg);
        } else {
            $expected
        }
    };
}

impl HardForkConfig {
    /// If all parameters which have been set are correct for mainnet, then
    /// sets all `None` to default values, otherwise, return an `Err`.
    pub fn complete_mainnet(&self) -> Result<HardForkSwitch, String> {
        let mut b = HardForkSwitch::new_builder();
        b = self.update_builder_via_edition(b, mainnet::CKB2021_START_EPOCH)?;
        b.build()
    }

    /// If all parameters which have been set are correct for testnet, then
    /// sets all `None` to default values, otherwise, return an `Err`.
    pub fn complete_testnet(&self) -> Result<HardForkSwitch, String> {
        let mut b = HardForkSwitch::new_builder();
        b = self.update_builder_via_edition(b, testnet::CKB2021_START_EPOCH)?;
        b.build()
    }

    fn update_builder_via_edition(
        &self,
        builder: HardForkSwitchBuilder,
        ckb2021: EpochNumber,
    ) -> Result<HardForkSwitchBuilder, String> {
        let builder = builder
            .rfc_0028(check_default!(self, rfc_0028, ckb2021))
            .rfc_0029(check_default!(self, rfc_0029, ckb2021))
            .rfc_0030(check_default!(self, rfc_0030, ckb2021))
            .rfc_0031(check_default!(self, rfc_0031, ckb2021))
            .rfc_0032(check_default!(self, rfc_0032, ckb2021))
            .rfc_0036(check_default!(self, rfc_0036, ckb2021))
            .rfc_0038(check_default!(self, rfc_0038, ckb2021));
        Ok(builder)
    }

    /// Converts to a hard fork switch.
    ///
    /// Enable features which are set to `None` at the user provided epoch.
    pub fn complete_with_default(&self, default: EpochNumber) -> Result<HardForkSwitch, String> {
        HardForkSwitch::new_builder()
            .rfc_0028(self.rfc_0028.unwrap_or(default))
            .rfc_0029(self.rfc_0029.unwrap_or(default))
            .rfc_0030(self.rfc_0030.unwrap_or(default))
            .rfc_0031(self.rfc_0031.unwrap_or(default))
            .rfc_0032(self.rfc_0032.unwrap_or(default))
            .rfc_0036(self.rfc_0036.unwrap_or(default))
            .rfc_0038(self.rfc_0038.unwrap_or(default))
            .build()
    }
}