penumbra_sdk_shielded_pool/output/
action.rs1use std::convert::{TryFrom, TryInto};
2
3use anyhow::{Context, Error};
4use penumbra_sdk_asset::balance;
5use penumbra_sdk_keys::symmetric::{OvkWrappedKey, WrappedMemoKey};
6use penumbra_sdk_proto::{
7 core::component::shielded_pool::v1 as pb, penumbra::core::component::shielded_pool::v1 as pbc,
8 DomainType,
9};
10use penumbra_sdk_txhash::{EffectHash, EffectingData};
11use serde::{Deserialize, Serialize};
12
13use crate::{NotePayload, OutputProof};
14
15#[derive(Clone, Debug)]
16pub struct Output {
17 pub body: Body,
18 pub proof: OutputProof,
19}
20
21#[derive(Clone, Debug, Deserialize, Serialize)]
22#[serde(try_from = "pb::OutputBody", into = "pb::OutputBody")]
23pub struct Body {
24 pub note_payload: NotePayload,
25 pub balance_commitment: balance::Commitment,
26 pub ovk_wrapped_key: OvkWrappedKey,
27 pub wrapped_memo_key: WrappedMemoKey,
28}
29
30impl EffectingData for Body {
31 fn effect_hash(&self) -> EffectHash {
32 EffectHash::from_proto_effecting_data(&self.to_proto())
33 }
34}
35
36impl EffectingData for Output {
37 fn effect_hash(&self) -> EffectHash {
38 self.body.effect_hash()
41 }
42}
43
44impl DomainType for Output {
45 type Proto = pb::Output;
46}
47
48impl From<Output> for pb::Output {
49 fn from(output: Output) -> Self {
50 let proof: pbc::ZkOutputProof = output.proof.into();
51 pb::Output {
52 body: Some(output.body.into()),
53 proof: Some(proof),
54 }
55 }
56}
57
58impl TryFrom<pb::Output> for Output {
59 type Error = Error;
60
61 fn try_from(proto: pb::Output) -> anyhow::Result<Self, Self::Error> {
62 Ok(Output {
63 body: proto
64 .body
65 .ok_or_else(|| anyhow::anyhow!("missing output body"))?
66 .try_into()?,
67 proof: proto
68 .proof
69 .ok_or_else(|| anyhow::anyhow!("missing output proof"))?
70 .try_into()
71 .context("output proof malformed")?,
72 })
73 }
74}
75
76impl DomainType for Body {
77 type Proto = pb::OutputBody;
78}
79
80impl From<Body> for pb::OutputBody {
81 fn from(output: Body) -> Self {
82 pb::OutputBody {
83 note_payload: Some(output.note_payload.into()),
84 balance_commitment: Some(output.balance_commitment.into()),
85 wrapped_memo_key: output.wrapped_memo_key.0.to_vec(),
86 ovk_wrapped_key: output.ovk_wrapped_key.0.to_vec(),
87 }
88 }
89}
90
91impl TryFrom<pb::OutputBody> for Body {
92 type Error = Error;
93
94 fn try_from(proto: pb::OutputBody) -> anyhow::Result<Self, Self::Error> {
95 let note_payload = proto
96 .note_payload
97 .ok_or_else(|| anyhow::anyhow!("missing note payload"))?
98 .try_into()
99 .context("malformed note payload")?;
100
101 let wrapped_memo_key = proto.wrapped_memo_key[..]
102 .try_into()
103 .context("malformed wrapped memo key")?;
104
105 let ovk_wrapped_key: OvkWrappedKey = proto.ovk_wrapped_key[..]
106 .try_into()
107 .context("malformed ovk wrapped key")?;
108
109 let balance_commitment = proto
110 .balance_commitment
111 .ok_or_else(|| anyhow::anyhow!("missing balance commitment"))?
112 .try_into()
113 .context("malformed balance commitment")?;
114
115 Ok(Body {
116 note_payload,
117 wrapped_memo_key,
118 ovk_wrapped_key,
119 balance_commitment,
120 })
121 }
122}