starknet_rust_providers/sequencer/models/
state_update.rs

1use serde::Deserialize;
2use serde_with::serde_as;
3use starknet_rust_core::{serde::unsigned_field_element::UfeHex, types::Felt};
4use std::collections::HashMap;
5
6use super::Block;
7
8#[serde_as]
9#[derive(Debug, Deserialize)]
10#[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))]
11pub struct StateUpdateWithBlock {
12    pub state_update: StateUpdate,
13    pub block: Block,
14}
15
16#[serde_as]
17#[derive(Debug, Deserialize)]
18#[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))]
19pub struct StateUpdate {
20    #[serde_as(as = "Option<UfeHex>")]
21    pub block_hash: Option<Felt>,
22    #[serde_as(as = "Option<UfeHex>")]
23    pub new_root: Option<Felt>,
24    #[serde_as(as = "UfeHex")]
25    pub old_root: Felt,
26    pub state_diff: StateDiff,
27}
28
29#[serde_as]
30#[derive(Debug, Deserialize)]
31#[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))]
32pub struct StateDiff {
33    #[serde_as(as = "HashMap<UfeHex, _>")]
34    pub storage_diffs: HashMap<Felt, Vec<StorageDiff>>,
35    pub deployed_contracts: Vec<DeployedContract>,
36    #[serde_as(as = "Vec<UfeHex>")]
37    pub old_declared_contracts: Vec<Felt>,
38    pub declared_classes: Vec<DeclaredContract>,
39    #[serde(default)]
40    #[serde_as(as = "HashMap<UfeHex, UfeHex>")]
41    pub nonces: HashMap<Felt, Felt>,
42    pub replaced_classes: Vec<DeployedContract>,
43}
44
45#[serde_as]
46#[derive(Debug, Deserialize)]
47#[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))]
48pub struct StorageDiff {
49    #[serde_as(as = "UfeHex")]
50    pub key: Felt,
51    #[serde_as(as = "UfeHex")]
52    pub value: Felt,
53}
54
55#[serde_as]
56#[derive(Debug, Deserialize)]
57#[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))]
58pub struct DeployedContract {
59    #[serde_as(as = "UfeHex")]
60    pub address: Felt,
61    #[serde_as(as = "UfeHex")]
62    pub class_hash: Felt,
63}
64
65#[serde_as]
66#[derive(Debug, Deserialize)]
67#[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))]
68pub struct DeclaredContract {
69    #[serde_as(as = "UfeHex")]
70    pub class_hash: Felt,
71    #[serde_as(as = "UfeHex")]
72    pub compiled_class_hash: Felt,
73}
74
75#[cfg(test)]
76mod tests {
77    use super::*;
78
79    #[test]
80    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
81    fn test_state_update_deser() {
82        let raw =
83            include_str!("../../../test-data/raw_gateway_responses/get_state_update/1_success.txt");
84
85        let state_update: StateUpdate = serde_json::from_str(raw).unwrap();
86
87        let storage_diff = &state_update
88            .state_diff
89            .storage_diffs
90            .get(
91                &Felt::from_hex(
92                    "0x197b9913e67947b0605934ec72db497d341a0199282c1da6d4aae46b17e0e76",
93                )
94                .unwrap(),
95            )
96            .unwrap()[0];
97
98        assert_eq!(
99            storage_diff.key,
100            Felt::from_hex("0x34c0d833897dbc937dd35e9f49a5184aecd6ab47829de999f9587549f82d0e")
101                .unwrap()
102        );
103        assert_eq!(
104            storage_diff.value,
105            Felt::from_hex("0x74fd8ca6e84097ad9ae00febfb690ad032fc4477155ec2193382c1b30b5e12b")
106                .unwrap()
107        );
108    }
109
110    #[test]
111    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
112    fn test_pending_state_update_deser() {
113        let raw = include_str!(
114            "../../../test-data/raw_gateway_responses/get_state_update/2_pending_block.txt"
115        );
116
117        serde_json::from_str::<StateUpdate>(raw).unwrap();
118    }
119
120    #[test]
121    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
122    fn test_state_update_deser_with_nonce_changes() {
123        let raw = include_str!(
124            "../../../test-data/raw_gateway_responses/get_state_update/4_with_nonce_changes.txt"
125        );
126
127        let state_update: StateUpdate = serde_json::from_str(raw).unwrap();
128        assert_eq!(state_update.state_diff.nonces.len(), 2);
129    }
130
131    #[test]
132    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
133    fn test_state_update_deser_with_declare_v2() {
134        let raw = include_str!(
135            "../../../test-data/raw_gateway_responses/get_state_update/5_with_declare_v2.txt"
136        );
137        serde_json::from_str::<StateUpdate>(raw).unwrap();
138    }
139
140    #[test]
141    #[ignore = "block with the same criteria not found in alpha-sepolia yet"]
142    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
143    fn test_state_update_deser_with_replaced_classes() {
144        let raw = include_str!(
145            "../../../test-data/raw_gateway_responses/get_state_update/6_with_replaced_classes.txt"
146        );
147
148        let state_update: StateUpdate = serde_json::from_str(raw).unwrap();
149        assert_eq!(state_update.state_diff.replaced_classes.len(), 1);
150    }
151
152    #[test]
153    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
154    fn test_state_update_deser_with_deployed_contracts() {
155        let raw = include_str!(
156            "../../../test-data/raw_gateway_responses/get_state_update/7_with_deployed_contracts.txt"
157        );
158
159        let state_update: StateUpdate = serde_json::from_str(raw).unwrap();
160        assert_eq!(state_update.state_diff.deployed_contracts.len(), 5);
161    }
162}