1use bincode::{DecodeUntrusted, Encode};
2use platform_serialization::de::Decode;
3use serde::{Deserialize, Serialize};
4
5#[cfg(feature = "json-conversion")]
6use crate::serialization::json_safe_fields;
7use crate::{errors::ProtocolError, prelude::TimestampMillis, util::deserializer::ProtocolVersion};
8
9#[cfg_attr(feature = "json-conversion", json_safe_fields)]
10#[derive(
11 Serialize,
12 Deserialize,
13 Encode,
14 Decode,
15 Debug,
16 Default,
17 Clone,
18 Copy,
19 PartialEq,
20 PartialOrd,
21 Eq,
22 DecodeUntrusted,
23)]
24#[serde(rename_all = "camelCase")]
25pub struct Metadata {
26 #[serde(default)]
27 pub block_height: u64,
28 #[serde(default)]
29 pub core_chain_locked_height: u64,
30 #[serde(default)]
31 pub time_ms: TimestampMillis,
32 #[serde(default)]
33 pub protocol_version: ProtocolVersion,
34}
35
36impl std::convert::TryFrom<&str> for Metadata {
37 type Error = ProtocolError;
38
39 fn try_from(d: &str) -> Result<Metadata, Self::Error> {
40 serde_json::from_str(d).map_err(|e| ProtocolError::EncodingError(e.to_string()))
41 }
42}
43
44#[cfg(all(feature = "json-conversion", feature = "serde-conversion"))]
45impl crate::serialization::JsonConvertible for Metadata {}
46
47#[cfg(all(feature = "value-conversion", feature = "serde-conversion"))]
48impl crate::serialization::ValueConvertible for Metadata {}
49
50#[cfg(all(
51 test,
52 feature = "json-conversion",
53 feature = "value-conversion",
54 feature = "serde-conversion"
55))]
56mod json_convertible_tests {
57 use super::*;
58 use crate::serialization::{JsonConvertible, ValueConvertible};
59 use platform_value::platform_value;
60 use serde_json::json;
61
62 fn fixture() -> Metadata {
66 Metadata {
67 block_height: 1_234_567,
68 core_chain_locked_height: 2_222_333,
69 time_ms: 1_700_000_000_000,
70 protocol_version: 9,
71 }
72 }
73
74 #[test]
75 fn json_round_trip_with_full_wire_shape() {
76 let original = fixture();
77 let json = original.to_json().expect("to_json");
78 assert_eq!(
81 json,
82 json!({
83 "blockHeight": 1_234_567,
84 "coreChainLockedHeight": 2_222_333,
85 "timeMs": 1_700_000_000_000u64,
86 "protocolVersion": 9,
87 })
88 );
89 let recovered = Metadata::from_json(json).expect("from_json");
90 assert_eq!(original, recovered);
91 }
92
93 #[test]
94 fn value_round_trip_with_full_wire_shape() {
95 let original = fixture();
96 let value = original.to_object().expect("to_object");
97 assert_eq!(
98 value,
99 platform_value!({
100 "blockHeight": 1_234_567u64,
101 "coreChainLockedHeight": 2_222_333u64,
102 "timeMs": 1_700_000_000_000u64,
103 "protocolVersion": 9u32,
104 })
105 );
106 let recovered = Metadata::from_object(value).expect("from_object");
107 assert_eq!(original, recovered);
108 }
109
110 #[test]
113 fn json_stringifies_unsafe_u64() {
114 let original = Metadata {
115 block_height: u64::MAX,
116 ..fixture()
117 };
118 let json = original.to_json().expect("to_json");
119 assert_eq!(json["blockHeight"], json!(u64::MAX.to_string()));
120 let recovered = Metadata::from_json(json).expect("from_json");
121 assert_eq!(original, recovered);
122 }
123}