starknet_rust_providers/sequencer/models/
state_update.rs1use serde::Deserialize;
2use serde_with::serde_as;
3use starknet_rust_core::{
4 serde::unsigned_field_element::UfeHex,
5 types::{Felt, MigratedCompiledClassItem},
6};
7use std::collections::HashMap;
8
9use super::Block;
10
11#[serde_as]
12#[derive(Debug, Deserialize)]
13#[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))]
14pub struct StateUpdateWithBlock {
15 pub state_update: StateUpdate,
16 pub block: Block,
17}
18
19#[serde_as]
20#[derive(Debug, Deserialize)]
21#[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))]
22pub struct StateUpdate {
23 #[serde_as(as = "Option<UfeHex>")]
24 pub block_hash: Option<Felt>,
25 #[serde_as(as = "Option<UfeHex>")]
26 pub new_root: Option<Felt>,
27 #[serde_as(as = "Option<UfeHex>")]
28 pub old_root: Option<Felt>,
29 pub state_diff: StateDiff,
30}
31
32#[serde_as]
33#[derive(Debug, Deserialize)]
34#[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))]
35pub struct StateDiff {
36 #[serde_as(as = "HashMap<UfeHex, _>")]
37 pub storage_diffs: HashMap<Felt, Vec<StorageDiff>>,
38 pub deployed_contracts: Vec<DeployedContract>,
39 #[serde_as(as = "Vec<UfeHex>")]
40 pub old_declared_contracts: Vec<Felt>,
41 pub declared_classes: Vec<DeclaredContract>,
42 pub migrated_compiled_classes: Option<Vec<DeclaredContract>>,
43 #[serde(default)]
44 #[serde_as(as = "HashMap<UfeHex, UfeHex>")]
45 pub nonces: HashMap<Felt, Felt>,
46 pub replaced_classes: Vec<DeployedContract>,
47}
48
49#[serde_as]
50#[derive(Debug, Deserialize)]
51#[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))]
52pub struct StorageDiff {
53 #[serde_as(as = "UfeHex")]
54 pub key: Felt,
55 #[serde_as(as = "UfeHex")]
56 pub value: Felt,
57}
58
59#[serde_as]
60#[derive(Debug, Deserialize)]
61#[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))]
62pub struct DeployedContract {
63 #[serde_as(as = "UfeHex")]
64 pub address: Felt,
65 #[serde_as(as = "UfeHex")]
66 pub class_hash: Felt,
67}
68
69#[serde_as]
70#[derive(Debug, Deserialize)]
71#[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))]
72pub struct DeclaredContract {
73 #[serde_as(as = "UfeHex")]
74 pub class_hash: Felt,
75 #[serde_as(as = "UfeHex")]
76 pub compiled_class_hash: Felt,
77}
78
79#[cfg(test)]
80mod tests {
81 use super::*;
82
83 #[test]
84 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
85 fn test_state_update_deser() {
86 let raw =
87 include_str!("../../../test-data/raw_gateway_responses/get_state_update/1_success.txt");
88
89 let state_update: StateUpdate = serde_json::from_str(raw).unwrap();
90
91 let storage_diff = &state_update
92 .state_diff
93 .storage_diffs
94 .get(
95 &Felt::from_hex(
96 "0x197b9913e67947b0605934ec72db497d341a0199282c1da6d4aae46b17e0e76",
97 )
98 .unwrap(),
99 )
100 .unwrap()[0];
101
102 assert_eq!(
103 storage_diff.key,
104 Felt::from_hex("0x34c0d833897dbc937dd35e9f49a5184aecd6ab47829de999f9587549f82d0e")
105 .unwrap()
106 );
107 assert_eq!(
108 storage_diff.value,
109 Felt::from_hex("0x74fd8ca6e84097ad9ae00febfb690ad032fc4477155ec2193382c1b30b5e12b")
110 .unwrap()
111 );
112 }
113
114 #[test]
115 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
116 fn test_pending_state_update_deser() {
117 let raw = include_str!(
118 "../../../test-data/raw_gateway_responses/get_state_update/2_pending_block.txt"
119 );
120
121 serde_json::from_str::<StateUpdate>(raw).unwrap();
122 }
123
124 #[test]
125 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
126 fn test_state_update_deser_with_nonce_changes() {
127 let raw = include_str!(
128 "../../../test-data/raw_gateway_responses/get_state_update/4_with_nonce_changes.txt"
129 );
130
131 let state_update: StateUpdate = serde_json::from_str(raw).unwrap();
132 assert_eq!(state_update.state_diff.nonces.len(), 2);
133 }
134
135 #[test]
136 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
137 fn test_state_update_deser_with_declare_v2() {
138 let raw = include_str!(
139 "../../../test-data/raw_gateway_responses/get_state_update/5_with_declare_v2.txt"
140 );
141 serde_json::from_str::<StateUpdate>(raw).unwrap();
142 }
143
144 #[test]
145 #[ignore = "block with the same criteria not found in alpha-sepolia yet"]
146 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
147 fn test_state_update_deser_with_replaced_classes() {
148 let raw = include_str!(
149 "../../../test-data/raw_gateway_responses/get_state_update/6_with_replaced_classes.txt"
150 );
151
152 let state_update: StateUpdate = serde_json::from_str(raw).unwrap();
153 assert_eq!(state_update.state_diff.replaced_classes.len(), 1);
154 }
155
156 #[test]
157 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
158 fn test_state_update_deser_with_deployed_contracts() {
159 let raw = include_str!(
160 "../../../test-data/raw_gateway_responses/get_state_update/7_with_deployed_contracts.txt"
161 );
162
163 let state_update: StateUpdate = serde_json::from_str(raw).unwrap();
164 assert_eq!(state_update.state_diff.deployed_contracts.len(), 5);
165 }
166
167 #[test]
168 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
169 fn test_state_diff_migrated_compiled_classes_none() {
170 let raw = include_str!(
171 "../../../test-data/raw_gateway_responses/get_state_update/7_with_deployed_contracts.txt"
172 );
173
174 let state_update: StateUpdate = serde_json::from_str(raw).unwrap();
175 assert!(state_update.state_diff.migrated_compiled_classes.is_none());
176 }
177
178 #[test]
179 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
180 fn test_state_update_deser_with_migrated_compiled_classes() {
181 let raw = include_str!(
182 "../../../test-data/raw_gateway_responses/get_state_update/8_with_migrated_compiled_classes.txt"
183 );
184
185 let state_update: StateUpdate = serde_json::from_str(raw).unwrap();
186 assert!(state_update.state_diff.migrated_compiled_classes.is_some());
187 assert_eq!(
188 state_update
189 .state_diff
190 .migrated_compiled_classes
191 .as_ref()
192 .unwrap()
193 .len(),
194 2
195 );
196 }
197
198 #[test]
199 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
200 fn test_state_update_conversion_pending_without_old_root() {
201 let raw = include_str!(
202 "../../../test-data/raw_gateway_responses/get_state_update/9_pending_without_old_root.txt"
203 );
204
205 let state_update: StateUpdate = serde_json::from_str(raw).unwrap();
206 let converted: starknet_rust_core::types::MaybePreConfirmedStateUpdate =
207 state_update.try_into().unwrap();
208
209 match converted {
210 starknet_rust_core::types::MaybePreConfirmedStateUpdate::PreConfirmedUpdate(update) => {
211 assert!(update.old_root.is_none());
212 }
213 _ => panic!("Expected PreConfirmedUpdate variant"),
214 }
215 }
216}