zebra/zebra-state/src/service/finalized_state/disk_format/shielded.rs

210 lines
5.6 KiB
Rust

//! Shielded transfer serialization formats for finalized data.
//!
//! # Correctness
//!
//! The [`crate::constants::DATABASE_FORMAT_VERSION`] constant must
//! be incremented each time the database format (column, serialization, etc) changes.
use bincode::Options;
use zebra_chain::{
block::Height,
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")
}
}
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))
}
}
// The following implementations for the note commitment trees use `serde` and
// `bincode`. `serde` serializations depend on the inner structure of the type.
// They should not be used in new code. (This is an issue for any derived serialization format.)
//
// We explicitly use `bincode::DefaultOptions` to disallow trailing bytes; see
// https://docs.rs/bincode/1.3.3/bincode/config/index.html#options-struct-vs-bincode-functions
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::tree::Node {
type Bytes = Vec<u8>;
fn as_bytes(&self) -> Self::Bytes {
self.as_ref().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::tree::Node {
fn from_bytes(bytes: impl AsRef<[u8]>) -> Self {
Self::try_from(bytes.as_ref()).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),
)
}
}