use super::{MptProof, SmtProof};
use crate::{Result, VsdbError};
use serde::{
Deserialize, Deserializer, Serialize, Serializer, de, ser::SerializeStruct,
};
use std::result::Result as StdResult;
const MPT_FORMAT: [u8; 8] = *b"VSMPTP01";
const SMT_FORMAT: [u8; 8] = *b"VSSMTP01";
#[derive(Deserialize)]
#[serde(deny_unknown_fields)]
struct MptWire {
format: [u8; 8],
key: Vec<u8>,
value: Option<Vec<u8>>,
nodes: Vec<Vec<u8>>,
}
impl Serialize for MptProof {
fn serialize<S: Serializer>(&self, serializer: S) -> StdResult<S::Ok, S::Error> {
let mut wire = serializer.serialize_struct("MptProof", 4)?;
wire.serialize_field("format", &MPT_FORMAT)?;
wire.serialize_field("key", &self.key)?;
wire.serialize_field("value", &self.value)?;
wire.serialize_field("nodes", &self.nodes)?;
wire.end()
}
}
impl<'de> Deserialize<'de> for MptProof {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> StdResult<Self, D::Error> {
let wire = MptWire::deserialize(deserializer)?;
if wire.format != MPT_FORMAT {
return Err(de::Error::custom("unsupported MPT proof format"));
}
Ok(Self {
key: wire.key,
value: wire.value,
nodes: wire.nodes,
})
}
}
#[derive(Deserialize)]
#[serde(deny_unknown_fields)]
struct SmtWire {
format: [u8; 8],
key_hash: [u8; 32],
leaf: Option<([u8; 32], Vec<u8>)>,
siblings: Vec<[u8; 32]>,
}
impl Serialize for SmtProof {
fn serialize<S: Serializer>(&self, serializer: S) -> StdResult<S::Ok, S::Error> {
let mut wire = serializer.serialize_struct("SmtProof", 4)?;
wire.serialize_field("format", &SMT_FORMAT)?;
wire.serialize_field("key_hash", &self.key_hash)?;
wire.serialize_field("leaf", &self.leaf)?;
wire.serialize_field("siblings", &self.siblings)?;
wire.end()
}
}
impl<'de> Deserialize<'de> for SmtProof {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> StdResult<Self, D::Error> {
let wire = SmtWire::deserialize(deserializer)?;
if wire.format != SMT_FORMAT {
return Err(de::Error::custom("unsupported SMT proof format"));
}
Ok(Self {
key_hash: wire.key_hash,
leaf: wire.leaf,
siblings: wire.siblings,
})
}
}
fn decode<T: de::DeserializeOwned>(bytes: &[u8], expected: &[u8; 8]) -> Result<T> {
let tag = bytes
.get(..expected.len())
.ok_or_else(|| VsdbError::Decode {
detail: "incomplete proof format header".into(),
})?;
if tag != expected {
return Err(VsdbError::Decode {
detail: format!(
"unsupported proof format {tag:?}; expected {}",
String::from_utf8_lossy(expected),
),
});
}
let (proof, remaining) = postcard::take_from_bytes(bytes)?;
if !remaining.is_empty() {
return Err(VsdbError::Decode {
detail: "trailing bytes after proof".into(),
});
}
Ok(proof)
}
impl MptProof {
pub fn to_bytes(&self) -> Result<Vec<u8>> {
Ok(postcard::to_allocvec(self)?)
}
pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
decode(bytes, &MPT_FORMAT)
}
}
impl SmtProof {
pub fn to_bytes(&self) -> Result<Vec<u8>> {
Ok(postcard::to_allocvec(self)?)
}
pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
decode(bytes, &SMT_FORMAT)
}
}