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