zebra_state/service/finalized_state/
disk_format.rs1use std::{io::Write, sync::Arc};
9
10pub mod block;
11pub mod chain;
12pub mod shielded;
13pub mod transparent;
14pub mod upgrade;
15
16#[cfg(any(test, feature = "proptest-impl"))]
17mod tests;
18
19pub use block::{TransactionIndex, TransactionLocation, MAX_ON_DISK_HEIGHT};
20pub use transparent::OutputLocation;
21
22#[cfg(any(test, feature = "proptest-impl"))]
23pub use tests::KV;
24
25pub trait IntoDisk {
28 type Bytes: AsRef<[u8]>;
31
32 fn as_bytes(&self) -> Self::Bytes;
44}
45
46pub trait FromDisk: Sized {
48 fn from_bytes(bytes: impl AsRef<[u8]>) -> Self;
58}
59
60impl<T> IntoDisk for &T
63where
64 T: IntoDisk,
65{
66 type Bytes = T::Bytes;
67
68 fn as_bytes(&self) -> Self::Bytes {
69 T::as_bytes(*self)
70 }
71}
72
73impl<T> IntoDisk for Arc<T>
74where
75 T: IntoDisk,
76{
77 type Bytes = T::Bytes;
78
79 fn as_bytes(&self) -> Self::Bytes {
80 T::as_bytes(self)
81 }
82}
83
84impl<T> FromDisk for Arc<T>
85where
86 T: FromDisk,
87{
88 fn from_bytes(bytes: impl AsRef<[u8]>) -> Self {
89 Arc::new(T::from_bytes(bytes))
90 }
91}
92
93impl IntoDisk for () {
96 type Bytes = [u8; 0];
97
98 fn as_bytes(&self) -> Self::Bytes {
99 []
100 }
101}
102
103impl FromDisk for () {
104 #[allow(clippy::unused_unit)]
105 fn from_bytes(bytes: impl AsRef<[u8]>) -> Self {
106 assert_eq!(
107 bytes.as_ref().len(),
108 0,
109 "unexpected data in zero-sized column family type",
110 );
111
112 ()
113 }
114}
115
116#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
119pub struct RawBytes(Vec<u8>);
120
121impl RawBytes {
125 pub fn new_raw_bytes(bytes: Vec<u8>) -> Self {
130 Self(bytes)
131 }
132
133 pub fn raw_bytes(&self) -> &Vec<u8> {
136 &self.0
137 }
138}
139
140impl IntoDisk for RawBytes {
141 type Bytes = Vec<u8>;
142
143 fn as_bytes(&self) -> Self::Bytes {
144 self.raw_bytes().clone()
145 }
146}
147
148impl FromDisk for RawBytes {
149 fn from_bytes(bytes: impl AsRef<[u8]>) -> Self {
150 Self::new_raw_bytes(bytes.as_ref().to_vec())
151 }
152}
153
154pub fn truncate_zero_be_bytes(mem_bytes: &[u8], disk_len: usize) -> Option<&[u8]> {
165 #![allow(clippy::unwrap_in_result)]
166 let discarded_bytes = mem_bytes
167 .len()
168 .checked_sub(disk_len)
169 .expect("unexpected `mem_bytes` length: must be at least `disk_len`");
170
171 if discarded_bytes == 0 {
172 return Some(mem_bytes);
173 }
174
175 let (discarded, truncated) = mem_bytes.split_at(discarded_bytes);
176
177 if !discarded.iter().all(|&byte| byte == 0) {
178 return None;
179 }
180
181 assert_eq!(truncated.len(), disk_len);
182
183 Some(truncated)
184}
185
186#[inline]
193pub fn expand_zero_be_bytes<const MEM_SIZE: usize>(disk_bytes: &[u8]) -> [u8; MEM_SIZE] {
194 if let Ok(disk_bytes_array) = disk_bytes.try_into() {
196 return disk_bytes_array;
197 }
198
199 let extra_bytes = MEM_SIZE
200 .checked_sub(disk_bytes.len())
201 .expect("unexpected `disk_bytes` length: must not exceed `MEM_SIZE`");
202
203 let mut expanded = [0; MEM_SIZE];
204 let _ = (&mut expanded[extra_bytes..])
205 .write(disk_bytes)
206 .expect("should fit");
207
208 expanded
209}