dpp/block/block_info/
mod.rs1use crate::block::epoch::{Epoch, EPOCH_0};
2use crate::prelude::{BlockHeight, CoreBlockHeight, TimestampMillis};
3#[cfg(feature = "json-conversion")]
4use crate::serialization::json_safe_fields;
5#[cfg(feature = "json-conversion")]
6use crate::serialization::JsonConvertible;
7#[cfg(feature = "value-conversion")]
8use crate::serialization::ValueConvertible;
9use bincode::{Decode, Encode};
10use serde::{Deserialize, Serialize};
11use std::fmt;
12
13pub const DEFAULT_BLOCK_INFO: BlockInfo = BlockInfo {
14 time_ms: 0,
15 height: 0,
16 core_height: 0,
17 epoch: EPOCH_0,
18};
19
20#[cfg_attr(feature = "json-conversion", json_safe_fields)]
25#[cfg_attr(feature = "json-conversion", derive(JsonConvertible))]
26#[derive(Clone, Copy, Default, Debug, PartialEq, Eq, Encode, Decode, Serialize, Deserialize)]
27#[cfg_attr(feature = "value-conversion", derive(ValueConvertible))]
28#[serde(rename_all = "camelCase")]
29pub struct BlockInfo {
30 pub time_ms: TimestampMillis,
32
33 pub height: BlockHeight,
35
36 pub core_height: CoreBlockHeight,
38
39 pub epoch: Epoch,
41}
42
43impl fmt::Display for BlockInfo {
44 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
45 write!(
46 f,
47 "BlockInfo {{ time_ms: {}, height: {}, core_height: {}, epoch: {} }}",
48 self.time_ms, self.height, self.core_height, self.epoch.index
49 )
50 }
51}
52
53impl PartialOrd for BlockInfo {
55 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
56 Some(self.cmp(other))
57 }
58}
59
60impl Ord for BlockInfo {
62 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
63 self.height.cmp(&other.height)
64 }
65}
66
67impl BlockInfo {
68 pub fn genesis() -> BlockInfo {
71 BlockInfo::default()
72 }
73
74 pub fn default_with_time(time_ms: TimestampMillis) -> BlockInfo {
76 BlockInfo {
77 time_ms,
78 ..Default::default()
79 }
80 }
81
82 pub fn default_with_height(height: BlockHeight) -> BlockInfo {
84 BlockInfo {
85 height,
86 ..Default::default()
87 }
88 }
89
90 pub fn default_with_height_and_time(
92 height: BlockHeight,
93 time_ms: TimestampMillis,
94 ) -> BlockInfo {
95 BlockInfo {
96 height,
97 time_ms,
98 ..Default::default()
99 }
100 }
101
102 pub fn default_with_epoch(epoch: Epoch) -> BlockInfo {
104 BlockInfo {
105 epoch,
106 ..Default::default()
107 }
108 }
109}
110
111#[cfg(all(test, feature = "json-conversion"))]
112mod tests {
113 use super::*;
114 use crate::block::epoch::Epoch;
115 use crate::serialization::JsonConvertible;
116
117 #[test]
118 fn block_info_json_round_trip() {
119 let block_info = BlockInfo {
120 time_ms: 1_700_000_000_000u64,
121 height: 12345678u64,
122 core_height: 900_000u32,
123 epoch: Epoch::new(42).unwrap(),
124 };
125
126 let json = block_info.to_json().expect("to_json should succeed");
127 assert!(json["timeMs"].is_number());
128 assert_eq!(json["timeMs"].as_u64().unwrap(), 1700000000000);
129 assert!(json["height"].is_number());
130 assert_eq!(json["height"].as_u64().unwrap(), 12345678);
131 assert!(json["coreHeight"].is_number());
132 assert_eq!(json["coreHeight"].as_u64().unwrap(), 900_000);
133
134 let restored = BlockInfo::from_json(json).expect("from_json should succeed");
135 assert_eq!(block_info, restored);
136 }
137
138 #[test]
139 fn block_info_value_round_trip() {
140 let block_info = BlockInfo {
141 time_ms: u64::MAX,
142 height: 999u64,
143 core_height: 100u32,
144 epoch: Epoch::new(0).unwrap(),
145 };
146
147 let obj = block_info.to_object().expect("to_object should succeed");
148 let time_val = obj
149 .get("timeMs")
150 .expect("get should not fail on map")
151 .expect("timeMs key must exist");
152 assert!(
153 time_val.is_integer(),
154 "Value timeMs should be an integer type, got: {:?}",
155 time_val
156 );
157
158 let restored = BlockInfo::from_object(obj).expect("from_object should succeed");
159 assert_eq!(block_info, restored);
160 }
161
162 #[test]
163 fn block_info_max_u64_json_round_trip() {
164 let block_info = BlockInfo {
165 time_ms: u64::MAX,
166 height: u64::MAX,
167 core_height: u32::MAX,
168 epoch: Epoch::new(100).unwrap(),
169 };
170
171 let json = block_info.to_json().expect("to_json should succeed");
172 assert!(json["timeMs"].is_string());
174 assert_eq!(json["timeMs"].as_str().unwrap(), u64::MAX.to_string());
175 assert!(json["height"].is_string());
176 assert_eq!(json["height"].as_str().unwrap(), u64::MAX.to_string());
177
178 let restored = BlockInfo::from_json(json).expect("from_json should succeed");
179 assert_eq!(block_info, restored);
180 }
181}