stratus/eth/primitives/
block.rs1use alloy_primitives::B256;
2use alloy_rpc_types_eth::BlockTransactions;
3use alloy_trie::root::ordered_trie_root;
4use display_json::DebugAsJson;
5use itertools::Itertools;
6
7use super::ExternalBlock;
8use super::Index;
9use super::PendingBlock;
10use super::Size;
11use super::TransactionExecution;
12use crate::alias::AlloyBlockAlloyTransaction;
13use crate::alias::AlloyBlockB256;
14use crate::alias::AlloyTransaction;
15use crate::alias::JsonValue;
16use crate::eth::primitives::BlockHeader;
17use crate::eth::primitives::BlockNumber;
18use crate::eth::primitives::Hash;
19use crate::eth::primitives::LogMessage;
20use crate::eth::primitives::TransactionMined;
21use crate::eth::primitives::UnixTime;
22use crate::ext::to_json_value;
23
24#[derive(DebugAsJson, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
25#[cfg_attr(test, derive(fake::Dummy))]
26pub struct Block {
27 pub header: BlockHeader,
28 pub transactions: Vec<TransactionMined>,
29}
30
31impl Block {
32 pub fn new(number: BlockNumber, timestamp: UnixTime) -> Self {
34 Self {
35 header: BlockHeader::new(number, timestamp),
36 transactions: Vec::new(),
37 }
38 }
39
40 pub fn genesis() -> Block {
42 Block::new(BlockNumber::ZERO, UnixTime::from(1702568764))
43 }
44
45 pub fn label_size_by_transactions(&self) -> &'static str {
47 match self.transactions.len() {
48 0 => "0",
49 1..=5 => "1-5",
50 6..=10 => "6-10",
51 11..=15 => "11-15",
52 16..=20 => "16-20",
53 _ => "20+",
54 }
55 }
56
57 pub fn label_size_by_gas(&self) -> &'static str {
59 match self.header.gas_used.as_u64() {
60 0 => "0",
61 1..=1_000_000 => "0-1M",
62 1_000_001..=2_000_000 => "1M-2M",
63 2_000_001..=3_000_000 => "2M-3M",
64 3_000_001..=4_000_000 => "3M-4M",
65 4_000_001..=5_000_000 => "4M-5M",
66 5_000_001..=6_000_000 => "5M-6M",
67 6_000_001..=7_000_000 => "6M-7M",
68 7_000_001..=8_000_000 => "7M-8M",
69 8_000_001..=9_000_000 => "8M-9M",
70 9_000_001..=10_000_000 => "9M-10M",
71 _ => "10M+",
72 }
73 }
74
75 pub fn to_json_rpc_with_full_transactions(self) -> JsonValue {
77 let alloy_block: AlloyBlockAlloyTransaction = self.into();
78 to_json_value(alloy_block)
79 }
80
81 pub fn to_json_rpc_with_transactions_hashes(self) -> JsonValue {
83 let alloy_block: AlloyBlockB256 = self.into();
84 to_json_value(alloy_block)
85 }
86
87 pub fn number(&self) -> BlockNumber {
89 self.header.number
90 }
91
92 pub fn hash(&self) -> Hash {
94 self.header.hash
95 }
96
97 pub fn create_log_messages(&self) -> Vec<LogMessage> {
98 let mut log_messages = vec![];
99 for (transaction_index, tx) in self.transactions.iter().enumerate() {
100 for (idx, log) in tx.logs().iter().enumerate() {
101 log_messages.push(LogMessage {
102 log: log.clone(),
103 transaction_hash: tx.info.hash,
104 transaction_index: (transaction_index as u64).into(),
105 block_hash: self.hash(),
106 block_number: self.number(),
107 index: tx.mined_data.first_log_index + Index(idx as u64),
108 });
109 }
110 }
111 log_messages
112 }
113
114 fn calculate_transaction_root(&mut self) {
115 if !self.transactions.is_empty() {
116 let transactions_hashes: Vec<B256> = self.transactions.iter().map(|x| x.info.hash).map(B256::from).collect();
117 self.header.transactions_root = ordered_trie_root(&transactions_hashes).into();
118 }
119 }
120
121 pub fn apply_external(&mut self, external_block: &ExternalBlock) {
122 self.header.hash = external_block.hash();
123 assert!(*self.header.timestamp == external_block.header.timestamp);
124 for transaction in self.transactions.iter_mut() {
125 assert!(transaction.evm_input.block_timestamp == self.header.timestamp);
126 transaction.mined_data.block_hash = external_block.hash();
127 }
128 }
129}
130
131impl From<PendingBlock> for Block {
132 fn from(value: PendingBlock) -> Self {
133 let mut block = Block::new(value.header.number, *value.header.timestamp);
134 let txs: Vec<TransactionExecution> = value.transactions.into_values().collect();
135 block.transactions.reserve(txs.len());
136 block.header.size = Size::from(txs.len() as u64);
137
138 let mut log_index = Index::ZERO;
139 for (tx_idx, execution) in txs.into_iter().enumerate() {
140 let log_count = execution.result.execution.logs.len() as u64;
141 let transaction_mined = TransactionMined::from_execution(execution, block.hash(), (tx_idx as u64).into(), log_index);
142 block.transactions.push(transaction_mined);
143 log_index += Index(log_count);
144 }
145
146 Self::calculate_transaction_root(&mut block);
147
148 block
149 }
150}
151
152impl From<Block> for AlloyBlockAlloyTransaction {
156 fn from(block: Block) -> Self {
157 let alloy_block: AlloyBlockAlloyTransaction = block.header.into();
158 let transactions: Vec<AlloyTransaction> = block.transactions.into_iter().map_into().collect();
159
160 Self {
161 transactions: BlockTransactions::Full(transactions),
162 ..alloy_block
163 }
164 }
165}
166
167impl From<Block> for AlloyBlockB256 {
168 fn from(block: Block) -> Self {
169 let alloy_block: AlloyBlockB256 = block.header.into();
170 let transaction_hashes: Vec<B256> = block.transactions.into_iter().map(|x| x.info.hash).map(B256::from).collect();
171
172 Self {
173 transactions: BlockTransactions::Hashes(transaction_hashes),
174 ..alloy_block
175 }
176 }
177}