zebra_state/service/finalized_state/disk_format/
chain.rs
1use std::collections::BTreeMap;
9
10use bincode::Options;
11
12use zebra_chain::{
13 amount::NonNegative,
14 block::Height,
15 block_info::BlockInfo,
16 history_tree::{HistoryTreeError, NonEmptyHistoryTree},
17 parameters::{Network, NetworkKind},
18 primitives::zcash_history,
19 value_balance::ValueBalance,
20};
21
22use crate::service::finalized_state::disk_format::{FromDisk, IntoDisk};
23
24impl IntoDisk for ValueBalance<NonNegative> {
25 type Bytes = [u8; 40];
26
27 fn as_bytes(&self) -> Self::Bytes {
28 self.to_bytes()
29 }
30}
31
32impl FromDisk for ValueBalance<NonNegative> {
33 fn from_bytes(bytes: impl AsRef<[u8]>) -> Self {
34 ValueBalance::from_bytes(bytes.as_ref()).expect("ValueBalance should be parsable")
35 }
36}
37
38#[derive(serde::Serialize, serde::Deserialize)]
46pub struct HistoryTreeParts {
47 network_kind: NetworkKind,
48 size: u32,
49 peaks: BTreeMap<u32, zcash_history::Entry>,
50 current_height: Height,
51}
52
53impl HistoryTreeParts {
54 pub(crate) fn with_network(
56 self,
57 network: &Network,
58 ) -> Result<NonEmptyHistoryTree, HistoryTreeError> {
59 assert_eq!(
60 self.network_kind,
61 network.kind(),
62 "history tree network kind should match current network"
63 );
64
65 NonEmptyHistoryTree::from_cache(network, self.size, self.peaks, self.current_height)
66 }
67}
68
69impl From<&NonEmptyHistoryTree> for HistoryTreeParts {
70 fn from(history_tree: &NonEmptyHistoryTree) -> Self {
71 HistoryTreeParts {
72 network_kind: history_tree.network().kind(),
73 size: history_tree.size(),
74 peaks: history_tree.peaks().clone(),
75 current_height: history_tree.current_height(),
76 }
77 }
78}
79
80impl IntoDisk for HistoryTreeParts {
81 type Bytes = Vec<u8>;
82
83 fn as_bytes(&self) -> Self::Bytes {
84 bincode::DefaultOptions::new()
85 .serialize(self)
86 .expect("serialization to vec doesn't fail")
87 }
88}
89
90impl FromDisk for HistoryTreeParts {
91 fn from_bytes(bytes: impl AsRef<[u8]>) -> Self {
92 bincode::DefaultOptions::new()
93 .deserialize(bytes.as_ref())
94 .expect("deserialization format should match the serialization format used by IntoDisk")
95 }
96}
97
98impl IntoDisk for BlockInfo {
99 type Bytes = Vec<u8>;
100
101 fn as_bytes(&self) -> Self::Bytes {
102 self.value_pools()
103 .as_bytes()
104 .iter()
105 .copied()
106 .chain(self.size().to_le_bytes().iter().copied())
107 .collect()
108 }
109}
110
111impl FromDisk for BlockInfo {
112 fn from_bytes(bytes: impl AsRef<[u8]>) -> Self {
113 match bytes.as_ref().len() {
116 44.. => {
117 let value_pools = ValueBalance::<NonNegative>::from_bytes(&bytes.as_ref()[0..40])
118 .expect("must work for 40 bytes");
119 let size =
120 u32::from_le_bytes(bytes.as_ref()[40..44].try_into().expect("must be 4 bytes"));
121 BlockInfo::new(value_pools, size)
122 }
123 _ => panic!("invalid format"),
124 }
125 }
126}