apply diffs

This commit is contained in:
hinto.janai 2024-10-10 20:39:44 -04:00
parent 9923d8d69d
commit c590bbb8d7
No known key found for this signature in database
GPG key ID: D47CE05FA175A499
4 changed files with 134 additions and 31 deletions

23
Cargo.lock generated
View file

@ -933,6 +933,7 @@ dependencies = [
"proptest-derive", "proptest-derive",
"serde", "serde",
"serde_json", "serde_json",
"strum",
"thiserror", "thiserror",
] ]
@ -2673,6 +2674,28 @@ dependencies = [
"spin", "spin",
] ]
[[package]]
name = "strum"
version = "0.26.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06"
dependencies = [
"strum_macros",
]
[[package]]
name = "strum_macros"
version = "0.26.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be"
dependencies = [
"heck",
"proc-macro2",
"quote",
"rustversion",
"syn 2.0.77",
]
[[package]] [[package]]
name = "subtle" name = "subtle"
version = "2.6.1" version = "2.6.1"

View file

@ -78,6 +78,7 @@ rayon = { version = "1.10.0", default-features = false }
serde_bytes = { version = "0.11.15", default-features = false } serde_bytes = { version = "0.11.15", default-features = false }
serde_json = { version = "1.0.128", default-features = false } serde_json = { version = "1.0.128", default-features = false }
serde = { version = "1.0.210", default-features = false } serde = { version = "1.0.210", default-features = false }
strum = { version = "0.26.3", default-features = false }
thiserror = { version = "1.0.63", default-features = false } thiserror = { version = "1.0.63", default-features = false }
thread_local = { version = "1.1.8", default-features = false } thread_local = { version = "1.1.8", default-features = false }
tokio-util = { version = "0.7.12", default-features = false } tokio-util = { version = "0.7.12", default-features = false }

View file

@ -27,6 +27,7 @@ curve25519-dalek = { workspace = true }
monero-serai = { workspace = true } monero-serai = { workspace = true }
hex = { workspace = true, features = ["serde", "alloc"], optional = true } hex = { workspace = true, features = ["serde", "alloc"], optional = true }
serde = { workspace = true, features = ["derive"], optional = true } serde = { workspace = true, features = ["derive"], optional = true }
strum = { workspace = true, features = ["derive"] }
thiserror = { workspace = true } thiserror = { workspace = true }
proptest = { workspace = true, optional = true } proptest = { workspace = true, optional = true }

View file

@ -1,6 +1,10 @@
//! The [`HardFork`] type. //! The [`HardFork`] type.
use std::time::Duration; use std::time::Duration;
use strum::{
AsRefStr, Display, EnumCount, EnumIs, EnumString, FromRepr, IntoStaticStr, VariantArray,
};
use monero_serai::block::BlockHeader; use monero_serai::block::BlockHeader;
/// Target block time for hf 1. /// Target block time for hf 1.
@ -27,7 +31,25 @@ pub enum HardForkError {
} }
/// An identifier for every hard-fork Monero has had. /// An identifier for every hard-fork Monero has had.
#[derive(Default, Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Hash)] #[derive(
Default,
Debug,
PartialEq,
Eq,
PartialOrd,
Ord,
Copy,
Clone,
Hash,
EnumCount,
Display,
AsRefStr,
EnumIs,
EnumString,
FromRepr,
IntoStaticStr,
VariantArray,
)]
#[cfg_attr(any(feature = "proptest"), derive(proptest_derive::Arbitrary))] #[cfg_attr(any(feature = "proptest"), derive(proptest_derive::Arbitrary))]
#[repr(u8)] #[repr(u8)]
pub enum HardFork { pub enum HardFork {
@ -47,58 +69,87 @@ pub enum HardFork {
V13, V13,
V14, V14,
V15, V15,
// remember to update from_vote!
V16, V16,
} }
impl HardFork { impl HardFork {
/// The current [`HardFork`].
///
/// ```rust
/// # use cuprate_types::HardFork;
/// assert_eq!(HardFork::CURRENT, HardFork::V16);
/// ```
pub const CURRENT: Self = Self::VARIANTS[Self::COUNT - 1];
/// Returns the hard-fork for a blocks [`BlockHeader::hardfork_version`] field. /// Returns the hard-fork for a blocks [`BlockHeader::hardfork_version`] field.
/// ///
/// ref: <https://monero-book.cuprate.org/consensus_rules/hardforks.html#blocks-version-and-vote> /// ref: <https://monero-book.cuprate.org/consensus_rules/hardforks.html#blocks-version-and-vote>
/// ///
/// # Errors /// # Errors
///
/// Will return [`Err`] if the version is not a valid [`HardFork`]. /// Will return [`Err`] if the version is not a valid [`HardFork`].
///
/// ```rust
/// # use cuprate_types::{HardFork, HardForkError};
/// # use strum::VariantArray;
/// assert_eq!(HardFork::from_version(0), Err(HardForkError::HardForkUnknown));
/// assert_eq!(HardFork::from_version(17), Err(HardForkError::HardForkUnknown));
///
/// for (version, hf) in HardFork::VARIANTS.iter().enumerate() {
/// // +1 because enumerate starts at 0, hf starts at 1.
/// assert_eq!(*hf, HardFork::from_version(version as u8 + 1).unwrap());
/// }
/// ```
#[inline] #[inline]
pub const fn from_version(version: u8) -> Result<Self, HardForkError> { pub const fn from_version(version: u8) -> Result<Self, HardForkError> {
Ok(match version { #[expect(
1 => Self::V1, clippy::cast_possible_truncation,
2 => Self::V2, reason = "we check that `HardFork::COUNT` fits into a `u8`."
3 => Self::V3, )]
4 => Self::V4, const COUNT_AS_U8: u8 = {
5 => Self::V5, const COUNT: usize = HardFork::COUNT;
6 => Self::V6, assert!(COUNT <= u8::MAX as usize);
7 => Self::V7, COUNT as u8
8 => Self::V8, };
9 => Self::V9,
10 => Self::V10, if version == 0 || version > COUNT_AS_U8 {
11 => Self::V11, Err(HardForkError::HardForkUnknown)
12 => Self::V12, } else {
13 => Self::V13, // INVARIANT: we've proved above that `version` is in a valid range.
14 => Self::V14, Ok(Self::VARIANTS[(version - 1) as usize])
15 => Self::V15, }
16 => Self::V16,
_ => return Err(HardForkError::HardForkUnknown),
})
} }
/// Returns the hard-fork for a blocks [`BlockHeader::hardfork_signal`] (vote) field. /// Returns the hard-fork for a blocks [`BlockHeader::hardfork_signal`] (vote) field.
/// ///
/// <https://monero-book.cuprate.org/consensus_rules/hardforks.html#blocks-version-and-vote> /// <https://monero-book.cuprate.org/consensus_rules/hardforks.html#blocks-version-and-vote>
///
/// ```rust
/// # use cuprate_types::{HardFork, HardForkError};
/// # use strum::VariantArray;
/// // 0 is interpreted as 1.
/// assert_eq!(HardFork::from_vote(0), HardFork::V1);
/// // Unknown defaults to `CURRENT`.
/// assert_eq!(HardFork::from_vote(17), HardFork::V16);
///
/// for (vote, hf) in HardFork::VARIANTS.iter().enumerate() {
/// // +1 because enumerate starts at 0, hf starts at 1.
/// assert_eq!(*hf, HardFork::from_vote(vote as u8 + 1));
/// }
/// ```
#[inline] #[inline]
pub fn from_vote(vote: u8) -> Self { pub fn from_vote(vote: u8) -> Self {
if vote == 0 { if vote == 0 {
// A vote of 0 is interpreted as 1 as that's what Monero used to default to. // A vote of 0 is interpreted as 1 as that's what Monero used to default to.
return Self::V1; Self::V1
} else {
// This must default to the latest hard-fork!
Self::from_version(vote).unwrap_or(Self::CURRENT)
} }
// This must default to the latest hard-fork!
Self::from_version(vote).unwrap_or(Self::V16)
} }
/// Returns the [`HardFork`] version and vote from this block header. /// Returns the [`HardFork`] version and vote from this block header.
/// ///
/// # Errors /// # Errors
///
/// Will return [`Err`] if the [`BlockHeader::hardfork_version`] is not a valid [`HardFork`]. /// Will return [`Err`] if the [`BlockHeader::hardfork_version`] is not a valid [`HardFork`].
#[inline] #[inline]
pub fn from_block_header(header: &BlockHeader) -> Result<(Self, Self), HardForkError> { pub fn from_block_header(header: &BlockHeader) -> Result<(Self, Self), HardForkError> {
@ -109,22 +160,49 @@ impl HardFork {
} }
/// Returns the raw hard-fork value, as it would appear in [`BlockHeader::hardfork_version`]. /// Returns the raw hard-fork value, as it would appear in [`BlockHeader::hardfork_version`].
pub const fn as_u8(&self) -> u8 { ///
*self as u8 /// ```rust
/// # use cuprate_types::{HardFork, HardForkError};
/// # use strum::VariantArray;
/// for (i, hf) in HardFork::VARIANTS.iter().enumerate() {
/// // +1 because enumerate starts at 0, hf starts at 1.
/// assert_eq!(hf.as_u8(), i as u8 + 1);
/// }
/// ```
pub const fn as_u8(self) -> u8 {
self as u8
} }
/// Returns the next hard-fork. /// Returns the next hard-fork.
pub fn next_fork(&self) -> Option<Self> { pub fn next_fork(self) -> Option<Self> {
Self::from_version(*self as u8 + 1).ok() Self::from_version(self as u8 + 1).ok()
} }
/// Returns the target block time for this hardfork. /// Returns the target block time for this hardfork.
/// ///
/// ref: <https://monero-book.cuprate.org/consensus_rules/blocks/difficulty.html#target-seconds> /// ref: <https://monero-book.cuprate.org/consensus_rules/blocks/difficulty.html#target-seconds>
pub const fn block_time(&self) -> Duration { pub const fn block_time(self) -> Duration {
match self { match self {
Self::V1 => BLOCK_TIME_V1, Self::V1 => BLOCK_TIME_V1,
_ => BLOCK_TIME_V2, _ => BLOCK_TIME_V2,
} }
} }
/// Returns `true` if `self` is [`Self::CURRENT`].
///
/// ```rust
/// # use cuprate_types::HardFork;
/// # use strum::VariantArray;
///
/// for hf in HardFork::VARIANTS.iter() {
/// if *hf == HardFork::CURRENT {
/// assert!(hf.is_current());
/// } else {
/// assert!(!hf.is_current());
/// }
/// }
/// ```
pub const fn is_current(self) -> bool {
matches!(self, Self::CURRENT)
}
} }