use std::fmt;
use serde::{Deserialize, Serialize};
use crate::{
amount::{self, Amount, NegativeAllowed},
fmt::HexDebug,
primitives::{ed25519, ZkSnarkProof},
sprout::{self, JoinSplit, Nullifier},
};
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct JoinSplitData<P: ZkSnarkProof> {
#[serde(bound(
serialize = "JoinSplit<P>: Serialize",
deserialize = "JoinSplit<P>: Deserialize<'de>"
))]
pub first: JoinSplit<P>,
#[serde(bound(
serialize = "JoinSplit<P>: Serialize",
deserialize = "JoinSplit<P>: Deserialize<'de>"
))]
pub rest: Vec<JoinSplit<P>>,
pub pub_key: ed25519::VerificationKeyBytes,
pub sig: ed25519::Signature,
}
impl<P: ZkSnarkProof> fmt::Debug for JoinSplitData<P> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("JoinSplitData")
.field("first", &self.first)
.field("rest", &self.rest)
.field("pub_key", &self.pub_key)
.field("sig", &HexDebug(&self.sig.to_bytes()))
.finish()
}
}
impl<P: ZkSnarkProof> fmt::Display for JoinSplitData<P> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut fmter =
f.debug_struct(format!("JoinSplitData<{}>", std::any::type_name::<P>()).as_str());
fmter.field("joinsplits", &self.joinsplits().count());
fmter.field("value_balance", &self.value_balance());
fmter.finish()
}
}
impl<P: ZkSnarkProof> JoinSplitData<P> {
pub fn joinsplits(&self) -> impl Iterator<Item = &JoinSplit<P>> {
std::iter::once(&self.first).chain(self.rest.iter())
}
#[cfg(any(test, feature = "proptest-impl"))]
pub fn joinsplits_mut(&mut self) -> impl Iterator<Item = &mut JoinSplit<P>> {
std::iter::once(&mut self.first).chain(self.rest.iter_mut())
}
pub fn nullifiers(&self) -> impl Iterator<Item = &Nullifier> {
self.joinsplits()
.flat_map(|joinsplit| joinsplit.nullifiers.iter())
}
pub fn value_balance(&self) -> Result<Amount<NegativeAllowed>, amount::Error> {
self.joinsplit_value_balances().sum()
}
pub fn joinsplit_value_balances(
&self,
) -> Box<dyn Iterator<Item = Amount<NegativeAllowed>> + '_> {
Box::new(self.joinsplits().map(JoinSplit::value_balance))
}
pub fn note_commitments(&self) -> impl Iterator<Item = &sprout::commitment::NoteCommitment> {
self.joinsplits()
.flat_map(|joinsplit| &joinsplit.commitments)
}
}