stratus/eth/primitives/
block_number.rs

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
125
126
127
128
129
130
131
132
133
134
135
136
use std::ops::Add;
use std::ops::AddAssign;
use std::str::FromStr;

use alloy_primitives::keccak256;
use anyhow::anyhow;
use display_json::DebugAsJson;
use ethereum_types::U64;
use fake::Dummy;
use fake::Faker;

use crate::alias::RevmU256;
use crate::eth::primitives::Hash;
use crate::gen_newtype_from;

#[derive(DebugAsJson, derive_more::Display, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Serialize, serde::Deserialize)]
#[serde(transparent)]
pub struct BlockNumber(pub U64);

impl BlockNumber {
    pub const ZERO: BlockNumber = BlockNumber(U64::zero());
    pub const ONE: BlockNumber = BlockNumber(U64::one());
    pub const MAX: BlockNumber = BlockNumber(U64([i64::MAX as u64])); // use i64 to avoid overflow PostgreSQL because its max limit is i64, not u64.

    /// Calculates the keccak256 hash of the block number.
    pub fn hash(&self) -> Hash {
        Hash::new(*keccak256(<[u8; 8]>::from(*self)))
    }

    /// Returns the previous block number.
    pub fn prev(&self) -> Option<Self> {
        if self.is_zero() {
            None
        } else {
            Some(Self(self.0 - 1))
        }
    }

    /// Returns the next block number.
    pub fn next_block_number(&self) -> Self {
        Self(self.0 + 1)
    }

    /// Checks if it is the zero block number.
    pub fn is_zero(&self) -> bool {
        self.0.is_zero()
    }

    /// Count how many blocks there is between itself and the othe block.
    ///
    /// Assumes that self is the lower-end of the range.
    pub fn count_to(self, higher_end: BlockNumber) -> u64 {
        if higher_end >= self {
            higher_end.as_u64() - self.as_u64() + 1
        } else {
            0
        }
    }

    pub fn as_i64(&self) -> i64 {
        self.0.as_u64() as i64
    }

    pub fn as_u64(&self) -> u64 {
        self.0.as_u64()
    }

    pub fn as_u32(&self) -> u32 {
        self.0.as_u64() as u32
    }
}

impl Dummy<Faker> for BlockNumber {
    fn dummy_with_rng<R: rand_core::RngCore + ?Sized>(_: &Faker, rng: &mut R) -> Self {
        rng.next_u64().into()
    }
}

// -----------------------------------------------------------------------------
// Math
// -----------------------------------------------------------------------------

impl Add<usize> for BlockNumber {
    type Output = BlockNumber;

    fn add(self, rhs: usize) -> Self::Output {
        Self(self.0 + rhs)
    }
}

impl AddAssign<usize> for BlockNumber {
    fn add_assign(&mut self, rhs: usize) {
        self.0 = self.0 + rhs;
    }
}

// -----------------------------------------------------------------------------
// Conversions: Other -> Self
// -----------------------------------------------------------------------------
gen_newtype_from!(self = BlockNumber, other = u8, u16, u32, u64, U64, usize, i32, i64);

impl FromStr for BlockNumber {
    type Err = anyhow::Error;

    fn from_str(s: &str) -> anyhow::Result<Self> {
        // This parses a hexadecimal string
        match U64::from_str(s) {
            Ok(parsed) => Ok(Self(parsed)),
            Err(e) => {
                tracing::warn!(reason = ?e, value = %s, "failed to parse block number");
                Err(anyhow!("Failed to parse field '{}' with value '{}'", "blockNumber", s))
            }
        }
    }
}

// -----------------------------------------------------------------------------
// Conversions: Self -> Other
// -----------------------------------------------------------------------------
impl From<BlockNumber> for U64 {
    fn from(block_number: BlockNumber) -> Self {
        block_number.0
    }
}

impl From<BlockNumber> for RevmU256 {
    fn from(block_number: BlockNumber) -> Self {
        Self::from_limbs([block_number.0.as_u64(), 0, 0, 0])
    }
}

impl From<BlockNumber> for [u8; 8] {
    fn from(block_number: BlockNumber) -> Self {
        block_number.0.as_u64().to_be_bytes()
    }
}