use std::collections::BTreeMap;
use bincode::Options;
use zebra_chain::{
amount::NonNegative,
block::Height,
block_info::BlockInfo,
history_tree::{HistoryTreeError, NonEmptyHistoryTree},
parameters::{Network, NetworkKind},
primitives::zcash_history,
value_balance::ValueBalance,
};
use crate::service::finalized_state::disk_format::{FromDisk, IntoDisk};
impl IntoDisk for ValueBalance<NonNegative> {
type Bytes = [u8; 40];
fn as_bytes(&self) -> Self::Bytes {
self.to_bytes()
}
}
impl FromDisk for ValueBalance<NonNegative> {
fn from_bytes(bytes: impl AsRef<[u8]>) -> Self {
ValueBalance::from_bytes(bytes.as_ref()).expect("ValueBalance should be parsable")
}
}
#[derive(serde::Serialize, serde::Deserialize)]
pub struct HistoryTreeParts {
network_kind: NetworkKind,
size: u32,
peaks: BTreeMap<u32, zcash_history::Entry>,
current_height: Height,
}
impl HistoryTreeParts {
pub(crate) fn with_network(
self,
network: &Network,
) -> Result<NonEmptyHistoryTree, HistoryTreeError> {
assert_eq!(
self.network_kind,
network.kind(),
"history tree network kind should match current network"
);
NonEmptyHistoryTree::from_cache(network, self.size, self.peaks, self.current_height)
}
}
impl From<&NonEmptyHistoryTree> for HistoryTreeParts {
fn from(history_tree: &NonEmptyHistoryTree) -> Self {
HistoryTreeParts {
network_kind: history_tree.network().kind(),
size: history_tree.size(),
peaks: history_tree.peaks().clone(),
current_height: history_tree.current_height(),
}
}
}
impl IntoDisk for HistoryTreeParts {
type Bytes = Vec<u8>;
fn as_bytes(&self) -> Self::Bytes {
bincode::DefaultOptions::new()
.serialize(self)
.expect("serialization to vec doesn't fail")
}
}
impl FromDisk for HistoryTreeParts {
fn from_bytes(bytes: impl AsRef<[u8]>) -> Self {
bincode::DefaultOptions::new()
.deserialize(bytes.as_ref())
.expect("deserialization format should match the serialization format used by IntoDisk")
}
}
impl IntoDisk for BlockInfo {
type Bytes = Vec<u8>;
fn as_bytes(&self) -> Self::Bytes {
self.value_pools()
.as_bytes()
.iter()
.copied()
.chain(self.size().to_le_bytes().iter().copied())
.collect()
}
}
impl FromDisk for BlockInfo {
fn from_bytes(bytes: impl AsRef<[u8]>) -> Self {
match bytes.as_ref().len() {
44.. => {
let value_pools = ValueBalance::<NonNegative>::from_bytes(&bytes.as_ref()[0..40])
.expect("must work for 40 bytes");
let size =
u32::from_le_bytes(bytes.as_ref()[40..44].try_into().expect("must be 4 bytes"));
BlockInfo::new(value_pools, size)
}
_ => panic!("invalid format"),
}
}
}