use bincode::Options;
use zakura_chain::{
block::{merkle::AuthDataRoot, Height},
ironwood, orchard, sapling, sprout,
subtree::{NoteCommitmentSubtreeData, NoteCommitmentSubtreeIndex},
};
use crate::service::finalized_state::disk_format::{FromDisk, IntoDisk};
use super::block::HEIGHT_DISK_BYTES;
impl IntoDisk for sprout::Nullifier {
type Bytes = [u8; 32];
fn as_bytes(&self) -> Self::Bytes {
*self.0
}
}
impl IntoDisk for sapling::Nullifier {
type Bytes = [u8; 32];
fn as_bytes(&self) -> Self::Bytes {
*self.0
}
}
impl IntoDisk for orchard::Nullifier {
type Bytes = [u8; 32];
fn as_bytes(&self) -> Self::Bytes {
let nullifier: orchard::Nullifier = *self;
nullifier.into()
}
}
impl IntoDisk for sprout::tree::Root {
type Bytes = [u8; 32];
fn as_bytes(&self) -> Self::Bytes {
self.into()
}
}
impl FromDisk for sprout::tree::Root {
fn from_bytes(bytes: impl AsRef<[u8]>) -> Self {
let array: [u8; 32] = bytes.as_ref().try_into().unwrap();
array.into()
}
}
impl IntoDisk for sapling::tree::Root {
type Bytes = [u8; 32];
fn as_bytes(&self) -> Self::Bytes {
self.into()
}
}
impl FromDisk for sapling::tree::Root {
fn from_bytes(bytes: impl AsRef<[u8]>) -> Self {
let array: [u8; 32] = bytes.as_ref().try_into().unwrap();
array.try_into().expect("finalized data must be valid")
}
}
impl IntoDisk for orchard::tree::Root {
type Bytes = [u8; 32];
fn as_bytes(&self) -> Self::Bytes {
self.into()
}
}
impl FromDisk for orchard::tree::Root {
fn from_bytes(bytes: impl AsRef<[u8]>) -> Self {
let array: [u8; 32] = bytes.as_ref().try_into().unwrap();
array.try_into().expect("finalized data must be valid")
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct CommitmentRootsByHeight {
pub sapling: sapling::tree::Root,
pub orchard: orchard::tree::Root,
pub auth_data_root: AuthDataRoot,
pub ironwood: ironwood::tree::Root,
pub sapling_tx: u64,
pub orchard_tx: u64,
pub ironwood_tx: u64,
}
impl IntoDisk for CommitmentRootsByHeight {
type Bytes = [u8; 152];
fn as_bytes(&self) -> Self::Bytes {
let mut out = [0u8; 152];
out[..32].copy_from_slice(&IntoDisk::as_bytes(&self.sapling));
out[32..64].copy_from_slice(&IntoDisk::as_bytes(&self.orchard));
out[64..96].copy_from_slice(&<[u8; 32]>::from(self.auth_data_root));
out[96..128].copy_from_slice(&IntoDisk::as_bytes(&self.ironwood));
out[128..136].copy_from_slice(&self.sapling_tx.to_be_bytes());
out[136..144].copy_from_slice(&self.orchard_tx.to_be_bytes());
out[144..152].copy_from_slice(&self.ironwood_tx.to_be_bytes());
out
}
}
impl FromDisk for CommitmentRootsByHeight {
fn from_bytes(bytes: impl AsRef<[u8]>) -> Self {
let bytes = bytes.as_ref();
let auth_data_root = if bytes.len() >= 96 {
let mut auth_data_root = [0u8; 32];
auth_data_root.copy_from_slice(&bytes[64..96]);
AuthDataRoot::from(auth_data_root)
} else {
AuthDataRoot::from([0u8; 32])
};
let (ironwood, sapling_tx, orchard_tx, ironwood_tx) = if bytes.len() >= 152 {
(
ironwood::tree::Root::from_bytes(&bytes[96..128]),
u64::from_be_bytes(bytes[128..136].try_into().expect("8 bytes")),
u64::from_be_bytes(bytes[136..144].try_into().expect("8 bytes")),
u64::from_be_bytes(bytes[144..152].try_into().expect("8 bytes")),
)
} else {
(
ironwood::tree::NoteCommitmentTree::default().root(),
0,
0,
0,
)
};
CommitmentRootsByHeight {
sapling: sapling::tree::Root::from_bytes(&bytes[..32]),
orchard: orchard::tree::Root::from_bytes(&bytes[32..64]),
auth_data_root,
ironwood,
sapling_tx,
orchard_tx,
ironwood_tx,
}
}
}
impl IntoDisk for NoteCommitmentSubtreeIndex {
type Bytes = [u8; 2];
fn as_bytes(&self) -> Self::Bytes {
self.0.to_be_bytes()
}
}
impl FromDisk for NoteCommitmentSubtreeIndex {
fn from_bytes(bytes: impl AsRef<[u8]>) -> Self {
let array: [u8; 2] = bytes.as_ref().try_into().unwrap();
Self(u16::from_be_bytes(array))
}
}
impl IntoDisk for sprout::tree::NoteCommitmentTree {
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 sprout::tree::NoteCommitmentTree {
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 sapling::tree::NoteCommitmentTree {
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 sapling::tree::NoteCommitmentTree {
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 orchard::tree::NoteCommitmentTree {
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 orchard::tree::NoteCommitmentTree {
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 sapling_crypto::Node {
type Bytes = Vec<u8>;
fn as_bytes(&self) -> Self::Bytes {
self.to_bytes().to_vec()
}
}
impl IntoDisk for orchard::tree::Node {
type Bytes = Vec<u8>;
fn as_bytes(&self) -> Self::Bytes {
self.to_repr().to_vec()
}
}
impl<Root: IntoDisk<Bytes = Vec<u8>>> IntoDisk for NoteCommitmentSubtreeData<Root> {
type Bytes = Vec<u8>;
fn as_bytes(&self) -> Self::Bytes {
[self.end_height.as_bytes().to_vec(), self.root.as_bytes()].concat()
}
}
impl FromDisk for sapling_crypto::Node {
fn from_bytes(bytes: impl AsRef<[u8]>) -> Self {
Self::from_bytes(
bytes
.as_ref()
.try_into()
.expect("trusted data should be 32 bytes"),
)
.expect("trusted data should deserialize successfully")
}
}
impl FromDisk for orchard::tree::Node {
fn from_bytes(bytes: impl AsRef<[u8]>) -> Self {
Self::try_from(bytes.as_ref()).expect("trusted data should deserialize successfully")
}
}
impl<Node: FromDisk> FromDisk for NoteCommitmentSubtreeData<Node> {
fn from_bytes(disk_bytes: impl AsRef<[u8]>) -> Self {
let (height_bytes, node_bytes) = disk_bytes.as_ref().split_at(HEIGHT_DISK_BYTES);
Self::new(
Height::from_bytes(height_bytes),
Node::from_bytes(node_bytes),
)
}
}