mwc_web3/types/
sync_state.rs1use crate::types::U256;
2use serde::{
3 de::{Deserializer, Error},
4 ser::Serializer,
5 Deserialize, Serialize,
6};
7
8#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
10#[serde(rename_all = "camelCase")]
11pub struct SyncInfo {
12 pub starting_block: U256,
14
15 pub current_block: U256,
17
18 pub highest_block: U256,
20}
21
22#[derive(Debug, Clone, PartialEq)]
24pub enum SyncState {
25 Syncing(SyncInfo),
27
28 NotSyncing,
30}
31
32#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
34#[serde(rename_all = "PascalCase")]
35struct SubscriptionSyncInfo {
36 pub starting_block: U256,
38
39 pub current_block: U256,
41
42 pub highest_block: U256,
44}
45
46impl From<SubscriptionSyncInfo> for SyncInfo {
47 fn from(s: SubscriptionSyncInfo) -> Self {
48 Self {
49 starting_block: s.starting_block,
50 current_block: s.current_block,
51 highest_block: s.highest_block,
52 }
53 }
54}
55
56#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
57struct SubscriptionSyncState {
58 pub syncing: bool,
59 pub status: Option<SubscriptionSyncInfo>,
60}
61
62#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
63#[serde(untagged)]
64enum SyncStateVariants {
65 Rpc(SyncInfo),
66 Subscription(SubscriptionSyncState),
67 Boolean(bool),
68}
69
70impl<'de> Deserialize<'de> for SyncState {
74 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
75 where
76 D: Deserializer<'de>,
77 {
78 let v: SyncStateVariants = Deserialize::deserialize(deserializer)?;
79 match v {
80 SyncStateVariants::Rpc(info) => Ok(SyncState::Syncing(info)),
81 SyncStateVariants::Subscription(state) => match state.status {
82 None if !state.syncing => Ok(SyncState::NotSyncing),
83 Some(ref info) if state.syncing => Ok(SyncState::Syncing(info.clone().into())),
84 _ => Err(D::Error::custom(
85 "expected object or `syncing = false`, got `syncing = true`",
86 )),
87 },
88 SyncStateVariants::Boolean(boolean) => {
89 if !boolean {
90 Ok(SyncState::NotSyncing)
91 } else {
92 Err(D::Error::custom("expected object or `false`, got `true`"))
93 }
94 }
95 }
96 }
97}
98
99impl Serialize for SyncState {
100 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
101 where
102 S: Serializer,
103 {
104 match *self {
105 SyncState::Syncing(ref info) => info.serialize(serializer),
106 SyncState::NotSyncing => false.serialize(serializer),
107 }
108 }
109}
110
111#[cfg(test)]
112mod tests {
113 use super::{SyncInfo, SyncState};
114
115 #[test]
116 fn should_deserialize_rpc_sync_info() {
117 let sync_state = r#"{
118 "currentBlock": "0x42",
119 "highestBlock": "0x9001",
120 "knownStates": "0x1337",
121 "pulledStates": "0x13",
122 "startingBlock": "0x0"
123 }"#;
124
125 let value: SyncState = serde_json::from_str(sync_state).unwrap();
126
127 assert_eq!(
128 value,
129 SyncState::Syncing(SyncInfo {
130 starting_block: 0x0.into(),
131 current_block: 0x42.into(),
132 highest_block: 0x9001.into()
133 })
134 );
135 }
136
137 #[test]
138 fn should_deserialize_subscription_sync_info() {
139 let sync_state = r#"{
140 "syncing": true,
141 "status": {
142 "CurrentBlock": "0x42",
143 "HighestBlock": "0x9001",
144 "KnownStates": "0x1337",
145 "PulledStates": "0x13",
146 "StartingBlock": "0x0"
147 }
148 }"#;
149
150 let value: SyncState = serde_json::from_str(sync_state).unwrap();
151
152 assert_eq!(
153 value,
154 SyncState::Syncing(SyncInfo {
155 starting_block: 0x0.into(),
156 current_block: 0x42.into(),
157 highest_block: 0x9001.into()
158 })
159 );
160 }
161
162 #[test]
163 fn should_deserialize_boolean_not_syncing() {
164 let sync_state = r#"false"#;
165 let value: SyncState = serde_json::from_str(sync_state).unwrap();
166
167 assert_eq!(value, SyncState::NotSyncing);
168 }
169
170 #[test]
171 fn should_deserialize_subscription_not_syncing() {
172 let sync_state = r#"{
173 "syncing": false
174 }"#;
175
176 let value: SyncState = serde_json::from_str(sync_state).unwrap();
177
178 assert_eq!(value, SyncState::NotSyncing);
179 }
180
181 #[test]
182 fn should_not_deserialize_invalid_boolean_syncing() {
183 let sync_state = r#"true"#;
184 let res: Result<SyncState, _> = serde_json::from_str(sync_state);
185 assert!(res.is_err());
186 }
187
188 #[test]
189 fn should_not_deserialize_invalid_subscription_syncing() {
190 let sync_state = r#"{
191 "syncing": true
192 }"#;
193
194 let res: Result<SyncState, _> = serde_json::from_str(sync_state);
195 assert!(res.is_err());
196 }
197
198 #[test]
199 fn should_not_deserialize_invalid_subscription_not_syncing() {
200 let sync_state = r#"{
201 "syncing": false,
202 "status": {
203 "CurrentBlock": "0x42",
204 "HighestBlock": "0x9001",
205 "KnownStates": "0x1337",
206 "PulledStates": "0x13",
207 "StartingBlock": "0x0"
208 }
209 }"#;
210
211 let res: Result<SyncState, _> = serde_json::from_str(sync_state);
212 assert!(res.is_err());
213 }
214}