ckb-chain-spec 0.107.0

The CKB block chain specification
Documentation
//! 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,
            mainnet::RFC0028_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,
            testnet::RFC0028_START_EPOCH,
        )?;
        b.build()
    }

    fn update_builder_via_edition(
        &self,
        builder: HardForkSwitchBuilder,
        ckb2021: EpochNumber,
        rfc_0028_start: EpochNumber,
    ) -> Result<HardForkSwitchBuilder, String> {
        let builder = builder
            .rfc_0028(check_default!(self, rfc_0028, rfc_0028_start))
            .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()
    }
}