stratus/eth/primitives/
external_block.rs

1use alloy_eips::eip4895::Withdrawals;
2use alloy_primitives::B64;
3use alloy_primitives::B256;
4use alloy_primitives::Bloom;
5use alloy_primitives::Bytes;
6use alloy_primitives::U256;
7use fake::Dummy;
8use fake::Fake;
9use fake::Faker;
10use serde::Deserialize;
11
12use super::Block;
13use crate::alias::AlloyBlockExternalTransaction;
14use crate::alias::JsonValue;
15use crate::eth::primitives::Address;
16use crate::eth::primitives::BlockNumber;
17use crate::eth::primitives::Hash;
18use crate::eth::primitives::UnixTime;
19use crate::eth::primitives::external_transaction::ExternalTransaction;
20use crate::log_and_err;
21
22#[derive(Debug, Clone, PartialEq, derive_more::Deref, derive_more::DerefMut, serde::Deserialize, serde::Serialize)]
23#[serde(transparent)]
24pub struct ExternalBlock(#[deref] pub AlloyBlockExternalTransaction);
25
26impl ExternalBlock {
27    /// Returns the block hash.
28    #[allow(clippy::expect_used)]
29    pub fn hash(&self) -> Hash {
30        Hash::from(self.0.header.hash)
31    }
32
33    /// Returns the block number.
34    #[allow(clippy::expect_used)]
35    pub fn number(&self) -> BlockNumber {
36        BlockNumber::from(self.0.header.inner.number)
37    }
38
39    /// Returns the block timestamp.
40    pub fn timestamp(&self) -> UnixTime {
41        self.0.header.inner.timestamp.into()
42    }
43
44    /// Returns the block author.
45    pub fn author(&self) -> Address {
46        self.0.header.inner.beneficiary.into()
47    }
48}
49
50impl PartialEq<Block> for ExternalBlock {
51    fn eq(&self, other: &Block) -> bool {
52        self.number() == other.number() && self.timestamp() == other.header.timestamp && self.hash() == other.header.hash
53    }
54}
55
56impl Dummy<Faker> for ExternalBlock {
57    fn dummy_with_rng<R: rand::Rng + ?Sized>(faker: &Faker, rng: &mut R) -> Self {
58        let mut addr_bytes = [0u8; 20];
59        let mut hash_bytes = [0u8; 32];
60        let mut nonce_bytes = [0u8; 8];
61        rng.fill_bytes(&mut addr_bytes);
62        rng.fill_bytes(&mut hash_bytes);
63        rng.fill_bytes(&mut nonce_bytes);
64
65        let transaction: ExternalTransaction = faker.fake_with_rng(rng);
66
67        let block = alloy_rpc_types_eth::Block {
68            header: alloy_rpc_types_eth::Header {
69                hash: B256::from_slice(&hash_bytes),
70                inner: alloy_consensus::Header {
71                    parent_hash: B256::from_slice(&hash_bytes),
72                    ommers_hash: B256::from_slice(&hash_bytes),
73                    beneficiary: alloy_primitives::Address::from_slice(&addr_bytes),
74                    state_root: B256::from_slice(&hash_bytes),
75                    transactions_root: B256::from_slice(&hash_bytes),
76                    receipts_root: B256::from_slice(&hash_bytes),
77                    withdrawals_root: Some(B256::from_slice(&hash_bytes)),
78                    number: rng.next_u64(),
79                    gas_used: rng.next_u64(),
80                    gas_limit: rng.next_u64(),
81                    extra_data: Bytes::default(),
82                    logs_bloom: Bloom::default(),
83                    timestamp: rng.next_u64(),
84                    difficulty: U256::from(rng.next_u64()),
85                    mix_hash: B256::from_slice(&hash_bytes),
86                    nonce: B64::from_slice(&nonce_bytes),
87                    base_fee_per_gas: Some(rng.next_u64()),
88                    blob_gas_used: None,
89                    excess_blob_gas: None,
90                    parent_beacon_block_root: None,
91                    requests_hash: None,
92                },
93                total_difficulty: Some(U256::from(rng.next_u64())),
94                size: Some(U256::from(rng.next_u64())),
95            },
96            uncles: vec![B256::from_slice(&hash_bytes)],
97            transactions: alloy_rpc_types_eth::BlockTransactions::Full(vec![transaction]),
98            withdrawals: Some(Withdrawals::default()),
99        };
100
101        ExternalBlock(block)
102    }
103}
104
105// -----------------------------------------------------------------------------
106// Conversions: Other -> Self
107// -----------------------------------------------------------------------------
108
109impl TryFrom<JsonValue> for ExternalBlock {
110    type Error = anyhow::Error;
111
112    fn try_from(value: JsonValue) -> Result<Self, Self::Error> {
113        match ExternalBlock::deserialize(&value) {
114            Ok(v) => Ok(v),
115            Err(e) => log_and_err!(reason = e, payload = value, "failed to convert payload value to ExternalBlock"),
116        }
117    }
118}