starknet_rust_providers/sequencer/models/
block.rs1use serde::Deserialize;
2use serde_with::serde_as;
3use starknet_rust_core::{
4 serde::unsigned_field_element::{UfeHex, UfeHexOption},
5 types::{Felt, L1DataAvailabilityMode, ResourcePrice},
6};
7
8use super::{ConfirmedTransactionReceipt, TransactionType};
9
10#[derive(Debug, Clone, Copy)]
11pub enum BlockId {
12 Hash(Felt),
13 Number(u64),
14 Pending,
15 Latest,
16}
17
18#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Eq)]
19#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
20#[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))]
21pub enum BlockStatus {
22 Pending,
24 Aborted,
26 Reverted,
28 AcceptedOnL2,
30 AcceptedOnL1,
32}
33
34#[serde_as]
36#[derive(Debug, Deserialize)]
37#[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))]
38pub struct Block {
39 #[serde(default)]
40 #[serde_as(as = "UfeHexOption")]
41 pub block_hash: Option<Felt>,
42 pub block_number: Option<u64>,
43 #[serde_as(as = "UfeHex")]
44 pub parent_block_hash: Felt,
45 pub timestamp: u64,
46 #[serde_as(as = "UfeHex")]
47 pub sequencer_address: Felt,
48 #[serde(default)]
49 #[serde_as(as = "UfeHexOption")]
50 pub state_root: Option<Felt>,
51 #[serde(default)]
52 #[serde_as(as = "UfeHexOption")]
53 pub transaction_commitment: Option<Felt>,
54 #[serde(default)]
55 #[serde_as(as = "UfeHexOption")]
56 pub event_commitment: Option<Felt>,
57 pub status: BlockStatus,
58 pub l1_da_mode: L1DataAvailabilityMode,
59 pub l1_gas_price: ResourcePrice,
60 pub l2_gas_price: ResourcePrice,
61 pub l1_data_gas_price: ResourcePrice,
62 pub transactions: Vec<TransactionType>,
63 pub transaction_receipts: Vec<ConfirmedTransactionReceipt>,
64 #[serde(default)]
65 pub starknet_version: String,
66 #[serde(default)]
67 #[serde_as(as = "UfeHexOption")]
68 pub receipt_commitment: Option<Felt>,
69 #[serde(default)]
70 #[serde_as(as = "UfeHexOption")]
71 pub state_diff_commitment: Option<Felt>,
72 #[serde(default)]
73 pub event_count: u64,
74 #[serde(default)]
75 pub transaction_count: u64,
76 #[serde(default)]
77 pub state_diff_length: Option<u64>,
78}
79
80#[cfg(test)]
81mod tests {
82 use super::{super::transaction_receipt::TransactionExecutionStatus, *};
83
84 #[test]
85 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
86 fn test_block_deser_with_transactions() {
87 let raw = include_str!(
88 "../../../test-data/raw_gateway_responses/get_block/1_with_transactions.txt"
89 );
90
91 let block: Block = serde_json::from_str(raw).unwrap();
92
93 assert_eq!(block.block_number.unwrap(), 100);
94 assert_eq!(block.status, BlockStatus::AcceptedOnL1);
95 assert_eq!(
96 block.state_root.unwrap(),
97 Felt::from_hex("051098918fd96edda4e251f695181c063e21fb0666352e3469db507c7fd62b89")
98 .unwrap()
99 );
100 assert_eq!(
101 block.transaction_commitment.unwrap(),
102 Felt::from_hex("0576db32d35cf011694a73c6ce400d5d77f768cbd77ee7cf87d12902e0f9b4ec")
103 .unwrap()
104 );
105 assert_eq!(
106 block.event_commitment.unwrap(),
107 Felt::from_hex("01c972780140fd16dde94639226ca25818e4f24ecd5b5c3065cc1f5f5fc410f9")
108 .unwrap()
109 );
110 assert_eq!(block.transactions.len(), 4);
111 assert_eq!(block.transaction_receipts.len(), 4);
112
113 if let TransactionType::InvokeFunction(tx) = &block.transactions[0] {
114 assert_eq!(tx.calldata.len(), 16);
115 } else {
116 panic!("Did not deserialize Transaction::InvokeFunction properly");
117 }
118 let receipt = &block.transaction_receipts[0];
119 assert_eq!(receipt.execution_resources.as_ref().unwrap().n_steps, 10552);
120 }
121
122 #[test]
123 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
124 fn test_block_deser_with_messages() {
125 let raw =
127 include_str!("../../../test-data/raw_gateway_responses/get_block/2_with_messages.txt");
128
129 let block: Block = serde_json::from_str(raw).unwrap();
130
131 assert_eq!(block.block_number.unwrap(), 25);
132 assert_eq!(block.transaction_receipts.len(), 11);
133 let receipt = &block.transaction_receipts[10];
134 assert_eq!(receipt.l2_to_l1_messages.len(), 1);
135 assert_eq!(receipt.l2_to_l1_messages[0].payload.len(), 2);
136 }
137
138 #[test]
139 #[ignore = "block with the same criteria not found in alpha-sepolia yet"]
140 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
141 fn test_block_deser_with_messages_without_nonce() {
142 let raw = include_str!(
144 "../../../test-data/raw_gateway_responses/get_block/9_with_messages_without_nonce.txt"
145 );
146
147 let block: Block = serde_json::from_str(raw).unwrap();
148
149 assert_eq!(block.block_number.unwrap(), 1564);
150 assert_eq!(block.transaction_receipts.len(), 4);
151 let receipt = &block.transaction_receipts[1];
152 assert_eq!(receipt.l2_to_l1_messages.len(), 1);
153 assert_eq!(receipt.l2_to_l1_messages[0].payload.len(), 2);
154
155 let receipt = &block.transaction_receipts[2];
156 assert!(receipt.l1_to_l2_consumed_message.is_some());
157 }
158
159 #[test]
160 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
161 fn test_block_deser_with_events() {
162 let raw =
164 include_str!("../../../test-data/raw_gateway_responses/get_block/3_with_events.txt");
165
166 let block: Block = serde_json::from_str(raw).unwrap();
167
168 assert_eq!(block.block_number.unwrap(), 4);
169 assert_eq!(block.transaction_receipts.len(), 4);
170 let receipt = &block.transaction_receipts[3];
171 assert_eq!(receipt.events.len(), 1);
172 assert_eq!(receipt.events[0].keys.len(), 1);
173 assert_eq!(receipt.events[0].data.len(), 4);
174 }
175
176 #[test]
177 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
178 fn test_block_deser_pending() {
179 let raw = include_str!("../../../test-data/raw_gateway_responses/get_block/4_pending.txt");
181
182 let block: Block = serde_json::from_str(raw).unwrap();
183
184 assert!(block.block_hash.is_none());
185 assert!(block.block_number.is_none());
186 assert!(block.state_root.is_none());
187 assert_eq!(block.status, BlockStatus::Pending);
188 }
189
190 #[test]
191 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
192 fn test_block_deser_new_attributes_0_8_2() {
193 let new_block: Block = serde_json::from_str(include_str!(
195 "../../../test-data/raw_gateway_responses/get_block/6_with_sequencer_address.txt"
196 ))
197 .unwrap();
198 assert_eq!(
199 new_block.sequencer_address,
200 Felt::from_hex("0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8")
201 .unwrap()
202 );
203 }
204
205 #[test]
206 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
207 fn test_block_deser_new_attributes_0_9_1() {
208 let new_block: Block = serde_json::from_str(include_str!(
210 "../../../test-data/raw_gateway_responses/get_block/8_with_starknet_version.txt"
211 ))
212 .unwrap();
213 assert_eq!(new_block.starknet_version, "0.12.3");
214 }
215
216 #[test]
217 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
218 fn test_block_deser_with_declare_tx() {
219 let raw = include_str!(
220 "../../../test-data/raw_gateway_responses/get_block/7_with_declare_tx.txt"
221 );
222
223 let block: Block = serde_json::from_str(raw).unwrap();
224
225 let tx = match &block.transactions[2] {
226 TransactionType::Declare(tx) => tx,
227 _ => panic!("Unexpected tx type"),
228 };
229
230 assert_eq!(
231 tx.sender_address,
232 Felt::from_hex("0x68922eb87daed71fc3099031e178b6534fc39a570022342e8c166024da893f5")
233 .unwrap()
234 );
235 }
236
237 #[test]
238 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
239 fn test_block_deser_with_l1_handler() {
240 let raw = include_str!(
241 "../../../test-data/raw_gateway_responses/get_block/10_with_l1_handler.txt"
242 );
243
244 let block: Block = serde_json::from_str(raw).unwrap();
245
246 let tx = match &block.transactions[0] {
247 TransactionType::L1Handler(tx) => tx,
248 _ => panic!("Unexpected tx type"),
249 };
250
251 assert_eq!(
252 tx.contract_address,
253 Felt::from_hex("0x4c5772d1914fe6ce891b64eb35bf3522aeae1315647314aac58b01137607f3f")
254 .unwrap()
255 );
256 }
257
258 #[test]
259 #[ignore = "block with the same criteria not found in alpha-sepolia yet"]
260 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
261 fn test_block_deser_without_execution_resources() {
262 let raw = include_str!(
263 "../../../test-data/raw_gateway_responses/get_block/11_without_execution_resources.txt"
264 );
265
266 let block: Block = serde_json::from_str(raw).unwrap();
267
268 let receipt = &block.transaction_receipts[17];
269
270 assert!(receipt.execution_resources.is_none());
271 }
272
273 #[test]
274 #[ignore = "block with the same criteria not found in alpha-sepolia yet"]
275 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
276 fn test_block_deser_l1_handler_without_nonce() {
277 let raw = include_str!(
278 "../../../test-data/raw_gateway_responses/get_block/12_l1_handler_without_nonce.txt"
279 );
280
281 let block: Block = serde_json::from_str(raw).unwrap();
282
283 let tx = match &block.transactions[22] {
284 TransactionType::L1Handler(tx) => tx,
285 _ => panic!("Unexpected tx type"),
286 };
287
288 assert!(tx.nonce.is_none());
289 }
290
291 #[test]
292 #[ignore = "block with the same criteria not found in alpha-sepolia yet"]
293 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
294 fn test_block_deser_without_entry_point() {
295 let raw = include_str!(
296 "../../../test-data/raw_gateway_responses/get_block/13_without_entry_point.txt"
297 );
298
299 let block: Block = serde_json::from_str(raw).unwrap();
300
301 let tx = match &block.transactions[16] {
302 TransactionType::InvokeFunction(tx) => tx,
303 _ => panic!("Unexpected tx type"),
304 };
305
306 assert!(tx.entry_point_selector.is_none());
307 }
308
309 #[test]
310 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
311 fn test_block_deser_with_deploy_account() {
312 let raw = include_str!(
313 "../../../test-data/raw_gateway_responses/get_block/14_deploy_account.txt"
314 );
315
316 let block: Block = serde_json::from_str(raw).unwrap();
317
318 let tx = match &block.transactions[1] {
319 TransactionType::DeployAccount(tx) => tx,
320 _ => panic!("Unexpected tx type"),
321 };
322
323 assert_eq!(tx.signature.len(), 2);
324 }
325
326 #[test]
327 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
328 fn test_block_deser_with_declare_v2() {
329 let raw =
330 include_str!("../../../test-data/raw_gateway_responses/get_block/15_declare_v2.txt");
331
332 let block: Block = serde_json::from_str(raw).unwrap();
333
334 assert!(block
335 .transactions
336 .into_iter()
337 .any(|tx| matches!(tx, TransactionType::Declare(_))));
338 }
339
340 #[test]
341 #[ignore = "block with the same criteria not found in alpha-sepolia yet"]
342 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
343 fn test_block_deser_with_reverted_tx() {
344 let raw = include_str!(
345 "../../../test-data/raw_gateway_responses/get_block/16_with_reverted_tx.txt"
346 );
347
348 let block: Block = serde_json::from_str(raw).unwrap();
349
350 assert!(block.transaction_receipts.into_iter().any(|tx| matches!(
351 tx.execution_status,
352 Some(TransactionExecutionStatus::Reverted)
353 )));
354 }
355
356 #[test]
357 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
358 fn test_block_new_v0_10_optional_fields_present() {
359 let raw = include_str!(
360 "../../../test-data/raw_gateway_responses/get_block/17_with_commitment_and_count_fields.txt"
361 );
362
363 let block: Block = serde_json::from_str(raw).unwrap();
364
365 assert_eq!(
366 block.receipt_commitment.unwrap(),
367 Felt::from_hex("0x2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b")
368 .unwrap()
369 );
370
371 assert_eq!(
372 block.state_diff_commitment.unwrap(),
373 Felt::from_hex("0x3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c")
374 .unwrap()
375 );
376
377 assert_eq!(block.event_count, 42);
378 assert_eq!(block.transaction_count, 15);
379 assert_eq!(block.state_diff_length, Some(128));
380 }
381}