penumbra_shielded_pool/
note_payload.rsuse anyhow::{Context, Error};
use penumbra_keys::keys::FullViewingKey;
use penumbra_num::Amount;
use penumbra_proto::{penumbra::core::component::shielded_pool::v1 as pb, DomainType};
use serde::{Deserialize, Serialize};
use crate::{note, Note, NoteCiphertext};
use decaf377_ka as ka;
#[derive(Clone, Serialize, Deserialize)]
#[serde(try_from = "pb::NotePayload", into = "pb::NotePayload")]
pub struct NotePayload {
pub note_commitment: note::StateCommitment,
pub ephemeral_key: ka::Public,
pub encrypted_note: NoteCiphertext,
}
impl NotePayload {
pub fn trial_decrypt(&self, fvk: &FullViewingKey) -> Option<Note> {
let note = Note::decrypt(&self.encrypted_note, fvk.incoming(), &self.ephemeral_key).ok()?;
tracing::debug!(note_commitment = ?note.commit(), ?note, "found note while scanning");
if note.amount() == Amount::zero() {
tracing::debug!("ignoring note recording zero assets");
return None;
}
if !note.controlled_by(fvk) {
tracing::warn!("decrypted note that is not spendable by provided full viewing key");
return None;
}
if note.commit() != self.note_commitment {
tracing::warn!("decrypted note does not match provided note commitment");
return None;
}
Some(note)
}
}
impl std::fmt::Debug for NotePayload {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("NotePayload")
.field("note_commitment", &self.note_commitment)
.field("ephemeral_key", &self.ephemeral_key)
.field("encrypted_note", &"...")
.finish()
}
}
impl DomainType for NotePayload {
type Proto = pb::NotePayload;
}
impl From<NotePayload> for pb::NotePayload {
fn from(msg: NotePayload) -> Self {
pb::NotePayload {
note_commitment: Some(msg.note_commitment.into()),
ephemeral_key: msg.ephemeral_key.0.to_vec(),
encrypted_note: Some(msg.encrypted_note.into()),
}
}
}
impl TryFrom<pb::NotePayload> for NotePayload {
type Error = Error;
fn try_from(proto: pb::NotePayload) -> anyhow::Result<Self, Self::Error> {
Ok(NotePayload {
note_commitment: proto
.note_commitment
.ok_or_else(|| anyhow::anyhow!("missing note commitment"))?
.try_into()?,
ephemeral_key: ka::Public::try_from(&proto.ephemeral_key[..])
.context("ephemeral key malformed")?,
encrypted_note: proto
.encrypted_note
.ok_or_else(|| anyhow::anyhow!("missing encrypted note"))?
.try_into()?,
})
}
}