stratus/eth/primitives/
block_number.rs1use std::ops::Add;
2use std::ops::AddAssign;
3use std::str::FromStr;
4
5use alloy_primitives::U64;
6use alloy_primitives::U256;
7use alloy_primitives::keccak256;
8use anyhow::anyhow;
9use display_json::DebugAsJson;
10#[cfg(test)]
11use fake::Dummy;
12#[cfg(test)]
13use fake::Faker;
14
15use crate::eth::primitives::Hash;
16
17#[derive(DebugAsJson, derive_more::Display, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Serialize, serde::Deserialize)]
18#[serde(transparent)]
19pub struct BlockNumber(pub U64);
20
21impl BlockNumber {
22 pub const ZERO: BlockNumber = BlockNumber(U64::ZERO);
23 pub const ONE: BlockNumber = BlockNumber(U64::ONE);
24 pub const MAX: BlockNumber = BlockNumber(U64::from_limbs([i64::MAX as u64]));
25
26 pub fn hash(&self) -> Hash {
28 Hash::new(*keccak256(<[u8; 8]>::from(*self)))
29 }
30
31 pub fn prev(&self) -> Option<Self> {
33 if self.is_zero() { None } else { Some(Self(self.0 - U64::ONE)) }
34 }
35
36 pub fn next_block_number(&self) -> Self {
38 Self(self.0 + U64::ONE)
39 }
40
41 pub fn is_zero(&self) -> bool {
43 self.0.is_zero()
44 }
45
46 pub fn count_to(self, higher_end: impl Into<u64>) -> u64 {
50 higher_end.into().saturating_sub(self.as_u64()) + 1
51 }
52
53 pub fn as_i64(&self) -> i64 {
54 self.0.try_into().unwrap()
55 }
56
57 pub fn as_u64(&self) -> u64 {
58 self.0.try_into().unwrap()
59 }
60
61 pub fn as_u32(&self) -> u32 {
62 self.0.try_into().unwrap()
63 }
64}
65
66#[cfg(test)]
67impl Dummy<Faker> for BlockNumber {
68 fn dummy_with_rng<R: rand::Rng + ?Sized>(_: &Faker, rng: &mut R) -> Self {
69 rng.next_u64().into()
70 }
71}
72
73impl Add<usize> for BlockNumber {
78 type Output = BlockNumber;
79
80 fn add(self, rhs: usize) -> Self::Output {
81 Self(self.0 + U64::from(rhs))
82 }
83}
84
85impl AddAssign<usize> for BlockNumber {
86 fn add_assign(&mut self, rhs: usize) {
87 self.0 = self.0 + U64::from(rhs);
88 }
89}
90
91impl From<u8> for BlockNumber {
96 fn from(value: u8) -> Self {
97 Self(U64::from(value))
98 }
99}
100
101impl From<u16> for BlockNumber {
102 fn from(value: u16) -> Self {
103 Self(U64::from(value))
104 }
105}
106
107impl From<u32> for BlockNumber {
108 fn from(value: u32) -> Self {
109 Self(U64::from(value))
110 }
111}
112
113impl From<u64> for BlockNumber {
114 fn from(value: u64) -> Self {
115 Self(U64::from(value))
116 }
117}
118
119impl From<U64> for BlockNumber {
120 fn from(value: U64) -> Self {
121 Self(value)
122 }
123}
124
125impl From<usize> for BlockNumber {
126 fn from(value: usize) -> Self {
127 Self(U64::from(value))
128 }
129}
130
131impl From<i32> for BlockNumber {
132 fn from(value: i32) -> Self {
133 Self(U64::from(value as u32))
134 }
135}
136
137impl From<i64> for BlockNumber {
138 fn from(value: i64) -> Self {
139 Self(U64::from(value as u64))
140 }
141}
142
143impl FromStr for BlockNumber {
144 type Err = anyhow::Error;
145
146 fn from_str(s: &str) -> anyhow::Result<Self> {
147 match U64::from_str(s) {
149 Ok(parsed) => Ok(Self(parsed)),
150 Err(e) => {
151 tracing::warn!(reason = ?e, value = %s, "failed to parse block number");
152 Err(anyhow!("Failed to parse field '{}' with value '{}'", "blockNumber", s))
153 }
154 }
155 }
156}
157
158impl From<BlockNumber> for u64 {
162 fn from(block_number: BlockNumber) -> Self {
163 block_number.as_u64()
164 }
165}
166
167impl From<BlockNumber> for U64 {
168 fn from(block_number: BlockNumber) -> Self {
169 block_number.0
170 }
171}
172
173impl From<BlockNumber> for U256 {
174 fn from(block_number: BlockNumber) -> Self {
175 Self::from(block_number.as_u64())
176 }
177}
178
179impl From<BlockNumber> for [u8; 8] {
180 fn from(block_number: BlockNumber) -> Self {
181 block_number.as_u64().to_be_bytes()
182 }
183}