1use crate::Error;
22use cfx_types::H256;
23use primitives::{BlockHashOrEpochNumber, EpochNumber};
24use serde::{
25 de::{Error as SerdeError, MapAccess, Visitor},
26 Deserialize, Deserializer, Serialize, Serializer,
27};
28use std::{convert::TryFrom, fmt};
29
30#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
32pub enum BlockId {
33 Hash {
35 hash: H256,
37 require_canonical: Option<bool>,
40 },
41 Num(u64),
43 Latest,
45 Earliest,
47 Pending,
49 Safe,
52 Finalized,
54}
55
56impl Default for BlockId {
57 fn default() -> Self { BlockId::Latest }
58}
59
60impl<'a> Deserialize<'a> for BlockId {
61 fn deserialize<D>(deserializer: D) -> Result<BlockId, D::Error>
62 where D: Deserializer<'a> {
63 deserializer.deserialize_any(BlockNumberVisitor)
64 }
65}
66
67impl BlockId {
68 pub fn to_min_block_num(&self) -> Option<u64> {
70 match *self {
71 BlockId::Num(ref x) => Some(*x),
72 _ => None,
73 }
74 }
75}
76
77impl Serialize for BlockId {
78 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
79 where S: Serializer {
80 use serde::ser::SerializeStruct;
81
82 match *self {
83 BlockId::Hash {
84 hash,
85 require_canonical,
86 } => {
87 let mut s = serializer.serialize_struct("BlockIdEip1898", 1)?;
88 s.serialize_field("blockHash", &hash)?;
89 if let Some(require_canonical) = require_canonical {
90 s.serialize_field("requireCanonical", &require_canonical)?;
91 }
92 s.end()
93 }
94 BlockId::Num(ref x) => {
95 serializer.serialize_str(&format!("0x{:x}", x))
96 }
97 BlockId::Latest => serializer.serialize_str("latest"),
98 BlockId::Earliest => serializer.serialize_str("earliest"),
99 BlockId::Pending => serializer.serialize_str("pending"),
100 BlockId::Safe => serializer.serialize_str("safe"),
101 BlockId::Finalized => serializer.serialize_str("finalized"),
102 }
103 }
104}
105
106struct BlockNumberVisitor;
107
108impl<'a> Visitor<'a> for BlockNumberVisitor {
109 type Value = BlockId;
110
111 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
112 write!(
113 formatter,
114 "a block number or 'latest', 'earliest' or 'pending'"
115 )
116 }
117
118 fn visit_map<V>(self, mut visitor: V) -> Result<Self::Value, V::Error>
119 where V: MapAccess<'a> {
120 let (mut require_canonical, mut block_number, mut block_hash) =
121 (None::<bool>, None::<u64>, None::<H256>);
122
123 loop {
124 let key_str: Option<String> = visitor.next_key()?;
125
126 match key_str {
127 Some(key) => match key.as_str() {
128 "blockNumber" => {
129 let value: String = visitor.next_value()?;
130 if value.starts_with("0x") {
131 let number = u64::from_str_radix(&value[2..], 16)
132 .map_err(|e| {
133 SerdeError::custom(format!(
134 "Invalid block number: {}",
135 e
136 ))
137 })?;
138
139 block_number = Some(number);
140 break;
141 } else {
142 return Err(SerdeError::custom(
143 "Invalid block number: missing 0x prefix"
144 .to_string(),
145 ));
146 }
147 }
148 "blockHash" => {
149 block_hash = Some(visitor.next_value()?);
150 }
151 "requireCanonical" => {
152 require_canonical = Some(visitor.next_value()?);
153 }
154 key => {
155 return Err(SerdeError::custom(format!(
156 "Unknown key: {}",
157 key
158 )))
159 }
160 },
161 None => break,
162 };
163 }
164
165 if let Some(number) = block_number {
166 return Ok(BlockId::Num(number));
167 }
168
169 if let Some(hash) = block_hash {
170 return Ok(BlockId::Hash {
171 hash,
172 require_canonical,
173 });
174 }
175
176 return Err(SerdeError::custom("Invalid input"));
177 }
178
179 fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
180 where E: SerdeError {
181 match value {
182 "latest" => Ok(BlockId::Latest),
183 "earliest" => Ok(BlockId::Earliest),
184 "pending" => Ok(BlockId::Pending),
185 "safe" => Ok(BlockId::Safe),
186 "finalized" => Ok(BlockId::Finalized),
187 _ if value.starts_with("0x") => {
188 if value.len() == 66 {
191 let hash =
192 value[2..].parse().map_err(SerdeError::custom)?;
193 Ok(BlockId::Hash {
194 hash,
195 require_canonical: None,
196 })
197 } else {
198 u64::from_str_radix(&value[2..], 16)
199 .map(BlockId::Num)
200 .map_err(|e| {
201 SerdeError::custom(format!(
202 "Invalid block number: {}",
203 e
204 ))
205 })
206 }
207 }
208 _ => Err(SerdeError::custom(
209 "Invalid block number: missing 0x prefix".to_string(),
210 )),
211 }
212 }
213
214 fn visit_string<E>(self, value: String) -> Result<Self::Value, E>
215 where E: SerdeError {
216 self.visit_str(value.as_ref())
217 }
218}
219
220impl TryFrom<BlockId> for EpochNumber {
221 type Error = Error;
222
223 fn try_from(x: BlockId) -> Result<EpochNumber, Error> {
224 match x {
225 BlockId::Num(num) => Ok(EpochNumber::Number(num)),
226 BlockId::Latest => Ok(EpochNumber::LatestState),
227 BlockId::Earliest => Ok(EpochNumber::Earliest),
228 BlockId::Pending => Ok(EpochNumber::LatestState), BlockId::Safe => Ok(EpochNumber::LatestConfirmed),
230 BlockId::Finalized => Ok(EpochNumber::LatestFinalized),
231 BlockId::Hash { .. } => Err(Error::InvalidParams(
232 "block_num".into(),
233 "Expected block number, found block hash".into(),
234 )),
235 }
236 }
237}
238
239impl From<BlockId> for BlockHashOrEpochNumber {
240 fn from(x: BlockId) -> BlockHashOrEpochNumber {
241 match x {
242 BlockId::Num(num) => {
243 BlockHashOrEpochNumber::EpochNumber(EpochNumber::Number(num))
244 }
245 BlockId::Latest => {
246 BlockHashOrEpochNumber::EpochNumber(EpochNumber::LatestState)
247 }
248 BlockId::Earliest => {
249 BlockHashOrEpochNumber::EpochNumber(EpochNumber::Earliest)
250 }
251 BlockId::Pending => {
252 BlockHashOrEpochNumber::EpochNumber(EpochNumber::LatestState)
253 }
254 BlockId::Safe => BlockHashOrEpochNumber::EpochNumber(
255 EpochNumber::LatestConfirmed,
256 ),
257 BlockId::Finalized => BlockHashOrEpochNumber::EpochNumber(
258 EpochNumber::LatestFinalized,
259 ),
260 BlockId::Hash {
261 hash,
262 require_canonical,
263 } => BlockHashOrEpochNumber::BlockHashWithOption {
264 hash,
265 require_pivot: require_canonical,
266 },
267 }
268 }
269}
270
271#[cfg(test)]
272mod tests {
273 use super::*;
274 use serde_json;
275 use std::str::FromStr;
276
277 #[test]
278 fn block_number_serialization() {
279 let hash = H256::from_str(
280 "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
281 )
282 .unwrap();
283
284 let block_number = BlockId::Hash {
285 hash,
286 require_canonical: None,
287 };
288 let serialized = serde_json::to_string(&block_number).unwrap();
289 assert_eq!(
290 serialized,
291 r#"{"blockHash":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"}"#
292 );
293
294 let block_number = BlockId::Hash {
295 hash,
296 require_canonical: Some(false),
297 };
298 let serialized = serde_json::to_string(&block_number).unwrap();
299 assert_eq!(
300 serialized,
301 r#"{"blockHash":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","requireCanonical":false}"#
302 );
303
304 let block_number = BlockId::Hash {
305 hash,
306 require_canonical: Some(true),
307 };
308 let serialized = serde_json::to_string(&block_number).unwrap();
309 assert_eq!(
310 serialized,
311 r#"{"blockHash":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","requireCanonical":true}"#
312 );
313 }
314
315 #[test]
316 fn block_number_deserialization() {
317 let s = r#"[
318 "0xa",
319 "latest",
320 "earliest",
321 "pending",
322 "safe",
323 "finalized",
324 {"blockNumber": "0xa"},
325 {"blockHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"},
326 {"blockHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", "requireCanonical": false},
327 {"blockHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", "requireCanonical": true}
328 ]"#;
329 let deserialized: Vec<BlockId> = serde_json::from_str(s).unwrap();
330
331 assert_eq!(
332 deserialized,
333 vec![
334 BlockId::Num(10),
335 BlockId::Latest,
336 BlockId::Earliest,
337 BlockId::Pending,
338 BlockId::Safe,
339 BlockId::Finalized,
340 BlockId::Num(10),
341 BlockId::Hash {
342 hash: H256::from_str(
343 "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
344 )
345 .unwrap(),
346 require_canonical: None,
347 },
348 BlockId::Hash {
349 hash: H256::from_str(
350 "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
351 )
352 .unwrap(),
353 require_canonical: Some(false),
354 },
355 BlockId::Hash {
356 hash: H256::from_str(
357 "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
358 )
359 .unwrap(),
360 require_canonical: Some(true),
361 }
362 ]
363 )
364 }
365
366 #[test]
367 fn should_not_deserialize() {
368 let s = r#"[{}, "10"]"#;
369 assert!(serde_json::from_str::<Vec<BlockId>>(s).is_err());
370 }
371}