stratus/eth/primitives/
external_block.rs

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