stratus/eth/primitives/
external_block.rs1use 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 #[allow(clippy::expect_used)]
29 pub fn hash(&self) -> Hash {
30 Hash::from(self.0.header.hash)
31 }
32
33 #[allow(clippy::expect_used)]
35 pub fn number(&self) -> BlockNumber {
36 BlockNumber::from(self.0.header.inner.number)
37 }
38
39 pub fn timestamp(&self) -> UnixTime {
41 self.0.header.inner.timestamp.into()
42 }
43
44 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
105impl 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}