Skip to main content

dpp/block/extended_block_info/
mod.rs

1use crate::block::block_info::BlockInfo;
2use crate::block::extended_block_info::v0::{
3    ExtendedBlockInfoV0, ExtendedBlockInfoV0Getters, ExtendedBlockInfoV0Setters,
4};
5use crate::protocol_error::ProtocolError;
6#[cfg(feature = "json-conversion")]
7use crate::serialization::JsonConvertible;
8#[cfg(feature = "value-conversion")]
9use crate::serialization::ValueConvertible;
10use crate::version::FeatureVersion;
11use bincode::{Decode, Encode};
12use derive_more::From;
13use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize};
14use serde::{Deserialize, Serialize};
15
16pub mod v0;
17
18/// Extended Block information
19#[cfg_attr(feature = "json-conversion", derive(JsonConvertible))]
20#[cfg_attr(feature = "value-conversion", derive(ValueConvertible))]
21#[derive(
22    Clone,
23    Debug,
24    PartialEq,
25    Eq,
26    Serialize,
27    Deserialize,
28    Encode,
29    Decode,
30    PlatformSerialize,
31    PlatformDeserialize,
32    From,
33)]
34#[platform_serialize(unversioned)] //versioned directly, no need to use platform_version
35#[serde(tag = "$formatVersion")]
36pub enum ExtendedBlockInfo {
37    #[serde(rename = "0")]
38    V0(ExtendedBlockInfoV0),
39}
40
41impl ExtendedBlockInfo {
42    /// Returns the version of this ExtendedBlockInfo.
43    /// Currently, the only available version is 0.
44    pub fn version(&self) -> FeatureVersion {
45        match self {
46            ExtendedBlockInfo::V0(_) => 0,
47        }
48    }
49}
50
51impl ExtendedBlockInfoV0Getters for ExtendedBlockInfo {
52    fn basic_info(&self) -> &BlockInfo {
53        match self {
54            ExtendedBlockInfo::V0(v0) => &v0.basic_info,
55        }
56    }
57
58    fn basic_info_mut(&mut self) -> &mut BlockInfo {
59        match self {
60            ExtendedBlockInfo::V0(v0) => &mut v0.basic_info,
61        }
62    }
63
64    fn basic_info_owned(self) -> BlockInfo {
65        match self {
66            ExtendedBlockInfo::V0(v0) => v0.basic_info,
67        }
68    }
69
70    fn app_hash(&self) -> &[u8; 32] {
71        match self {
72            ExtendedBlockInfo::V0(v0) => &v0.app_hash,
73        }
74    }
75
76    fn quorum_hash(&self) -> &[u8; 32] {
77        match self {
78            ExtendedBlockInfo::V0(v0) => &v0.quorum_hash,
79        }
80    }
81
82    fn proposer_pro_tx_hash(&self) -> &[u8; 32] {
83        match self {
84            ExtendedBlockInfo::V0(v0) => &v0.proposer_pro_tx_hash,
85        }
86    }
87
88    fn block_id_hash(&self) -> &[u8; 32] {
89        match self {
90            ExtendedBlockInfo::V0(v0) => &v0.block_id_hash,
91        }
92    }
93
94    fn signature(&self) -> &[u8; 96] {
95        match self {
96            ExtendedBlockInfo::V0(v0) => &v0.signature,
97        }
98    }
99
100    fn round(&self) -> u32 {
101        match self {
102            ExtendedBlockInfo::V0(v0) => v0.round,
103        }
104    }
105}
106
107impl ExtendedBlockInfoV0Setters for ExtendedBlockInfo {
108    fn set_basic_info(&mut self, info: BlockInfo) {
109        match self {
110            ExtendedBlockInfo::V0(v0) => {
111                v0.set_basic_info(info);
112            }
113        }
114    }
115
116    fn set_app_hash(&mut self, hash: [u8; 32]) {
117        match self {
118            ExtendedBlockInfo::V0(v0) => {
119                v0.set_app_hash(hash);
120            }
121        }
122    }
123
124    fn set_quorum_hash(&mut self, hash: [u8; 32]) {
125        match self {
126            ExtendedBlockInfo::V0(v0) => {
127                v0.set_quorum_hash(hash);
128            }
129        }
130    }
131
132    fn set_signature(&mut self, signature: [u8; 96]) {
133        match self {
134            ExtendedBlockInfo::V0(v0) => {
135                v0.set_signature(signature);
136            }
137        }
138    }
139
140    fn set_round(&mut self, round: u32) {
141        match self {
142            ExtendedBlockInfo::V0(v0) => {
143                v0.set_round(round);
144            }
145        }
146    }
147}
148
149#[cfg(test)]
150mod tests {
151    use super::*;
152    use crate::block::block_info::BlockInfo;
153    use crate::serialization::{PlatformDeserializable, PlatformSerializable};
154
155    #[test]
156    fn test_extended_block_info_bincode() {
157        let block_info: ExtendedBlockInfo = ExtendedBlockInfoV0 {
158            basic_info: BlockInfo::default(),
159            app_hash: [1; 32],
160            quorum_hash: [2; 32],
161            block_id_hash: [3; 32],
162            proposer_pro_tx_hash: [4; 32],
163            signature: [3; 96],
164            round: 1,
165        }
166        .into();
167
168        // Serialize into a vector
169        let encoded =
170            PlatformSerializable::serialize_to_bytes(&block_info).expect("expected to serialize");
171
172        // Deserialize from the vector
173        let decoded: ExtendedBlockInfo = PlatformDeserializable::deserialize_from_bytes(&encoded)
174            .expect("expected to deserialize");
175
176        assert_eq!(block_info, decoded);
177    }
178}
179
180// (TODO replaced) extendedblockinfo — needs explicit fixture (no Default).
181
182#[cfg(all(
183    test,
184    feature = "json-conversion",
185    feature = "value-conversion",
186    feature = "serde-conversion"
187))]
188mod json_convertible_tests_extendedblockinfo {
189    use super::*;
190    use crate::block::block_info::BlockInfo;
191    use crate::block::extended_block_info::v0::ExtendedBlockInfoV0;
192    use platform_value::platform_value;
193    use serde_json::json;
194
195    fn fixture() -> ExtendedBlockInfo {
196        ExtendedBlockInfo::V0(ExtendedBlockInfoV0 {
197            basic_info: BlockInfo::default(),
198            app_hash: [0x11; 32],
199            quorum_hash: [0x22; 32],
200            block_id_hash: [0x33; 32],
201            proposer_pro_tx_hash: [0x44; 32],
202            signature: [0x55; 96],
203            round: 3,
204        })
205    }
206
207    #[test]
208    fn json_round_trip_with_full_wire_shape() {
209        use crate::serialization::JsonConvertible;
210        let original = fixture();
211        let json = original.to_json().expect("to_json");
212        // `json_safe_fields` proc-macro converts u64 -> string only when above
213        // JS_MAX_SAFE_INTEGER. Default `BlockInfo` (zeros) stays numeric.
214        // 32-byte arrays are emitted as base64 strings (`appHash`, etc.); the
215        // 96-byte signature is also base64 (no Bytes32 path). JSON erases
216        // size for `round` (u32) — value-path locks `3u32` below.
217        assert_eq!(
218            json,
219            json!({
220                "$formatVersion": "0",
221                "basicInfo": {
222                    "timeMs": 0,
223                    "height": 0,
224                    "coreHeight": 0,
225                    "epoch": {"index": 0},
226                },
227                "appHash": "ERERERERERERERERERERERERERERERERERERERERERE=",
228                "quorumHash": "IiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiI=",
229                "blockIdHash": "MzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzM=",
230                "proposerProTxHash": "REREREREREREREREREREREREREREREREREREREREREQ=",
231                "signature": "VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV",
232                "round": 3,
233            })
234        );
235        let recovered = ExtendedBlockInfo::from_json(json).expect("from_json");
236        assert_eq!(original, recovered);
237    }
238
239    #[test]
240    fn value_round_trip_with_full_wire_shape() {
241        use crate::serialization::ValueConvertible;
242        use platform_value::Value;
243        let original = fixture();
244        let value = original.to_object().expect("to_object");
245        // `[u8; 32]` -> `Value::Bytes32`, `[u8; 96]` -> `Value::Bytes`,
246        // `round` is `u32` -> `Value::U32`. `BlockInfo` fields use their
247        // native typed variants (U64 / U32 / U16).
248        assert_eq!(
249            value,
250            platform_value!({
251                "$formatVersion": "0",
252                "basicInfo": {
253                    "timeMs": 0u64,
254                    "height": 0u64,
255                    "coreHeight": 0u32,
256                    "epoch": {"index": 0u16},
257                },
258                "appHash": Value::Bytes32([0x11; 32]),
259                "quorumHash": Value::Bytes32([0x22; 32]),
260                "blockIdHash": Value::Bytes32([0x33; 32]),
261                "proposerProTxHash": Value::Bytes32([0x44; 32]),
262                "signature": Value::Bytes(vec![0x55; 96]),
263                "round": 3u32,
264            })
265        );
266        let recovered = ExtendedBlockInfo::from_object(value).expect("from_object");
267        assert_eq!(original, recovered);
268    }
269}