penumbra_sdk_governance/delegator_vote/
action.rs

1use anyhow::Context;
2
3use crate::{vote::Vote, DelegatorVoteProof};
4use decaf377_rdsa::{Signature, SpendAuth, VerificationKey};
5use penumbra_sdk_asset::Value;
6use penumbra_sdk_num::Amount;
7use penumbra_sdk_proto::{core::component::governance::v1 as pb, DomainType};
8use penumbra_sdk_sct::Nullifier;
9use penumbra_sdk_tct as tct;
10use penumbra_sdk_txhash::{EffectHash, EffectingData};
11
12#[derive(Debug, Clone, Copy)]
13pub struct DelegatorVote {
14    pub body: DelegatorVoteBody,
15    pub auth_sig: Signature<SpendAuth>,
16    pub proof: DelegatorVoteProof,
17}
18
19impl EffectingData for DelegatorVote {
20    fn effect_hash(&self) -> EffectHash {
21        self.body.effect_hash()
22    }
23}
24
25/// The body of a delegator vote.
26#[derive(Debug, Clone, Copy)]
27pub struct DelegatorVoteBody {
28    /// The proposal ID the vote is for.
29    pub proposal: u64,
30    /// The start position of the proposal in the TCT.
31    pub start_position: tct::Position,
32    /// The vote on the proposal.
33    pub vote: Vote, // With flow encryption, this will be a triple of flow ciphertexts
34    /// The value of the staked note being used to vote.
35    pub value: Value, // With flow encryption, this will be a triple of balance commitments, and a public denomination
36    /// The unbonded amount equivalent to the value above
37    pub unbonded_amount: Amount,
38    /// The nullifier of the staked note being used to vote.
39    pub nullifier: Nullifier,
40    /// The randomized validating key for the spend authorization signature.
41    pub rk: VerificationKey<SpendAuth>,
42}
43
44impl EffectingData for DelegatorVoteBody {
45    fn effect_hash(&self) -> EffectHash {
46        EffectHash::from_proto_effecting_data(&self.to_proto())
47    }
48}
49
50impl From<DelegatorVoteBody> for pb::DelegatorVoteBody {
51    fn from(value: DelegatorVoteBody) -> Self {
52        pb::DelegatorVoteBody {
53            proposal: value.proposal,
54            start_position: value.start_position.into(),
55            vote: Some(value.vote.into()),
56            value: Some(value.value.into()),
57            unbonded_amount: Some(value.unbonded_amount.into()),
58            nullifier: Some(value.nullifier.into()),
59            rk: Some(value.rk.into()),
60        }
61    }
62}
63
64impl TryFrom<pb::DelegatorVoteBody> for DelegatorVoteBody {
65    type Error = anyhow::Error;
66
67    fn try_from(msg: pb::DelegatorVoteBody) -> Result<Self, Self::Error> {
68        Ok(DelegatorVoteBody {
69            proposal: msg.proposal,
70            start_position: msg
71                .start_position
72                .try_into()
73                .context("invalid start position in `DelegatorVote`")?,
74            vote: msg
75                .vote
76                .ok_or_else(|| anyhow::anyhow!("missing vote in `DelegatorVote`"))?
77                .try_into()?,
78            value: msg
79                .value
80                .ok_or_else(|| anyhow::anyhow!("missing value in `DelegatorVote`"))?
81                .try_into()?,
82            unbonded_amount: msg
83                .unbonded_amount
84                .ok_or_else(|| anyhow::anyhow!("missing unbonded amount in `DelegatorVote`"))?
85                .try_into()?,
86            nullifier: msg
87                .nullifier
88                .ok_or_else(|| anyhow::anyhow!("missing nullifier in `DelegatorVote`"))?
89                .try_into()
90                .context("invalid nullifier in `DelegatorVote`")?,
91            rk: msg
92                .rk
93                .ok_or_else(|| anyhow::anyhow!("missing rk in `DelegatorVote`"))?
94                .try_into()
95                .context("invalid rk in `DelegatorVote`")?,
96        })
97    }
98}
99
100impl DomainType for DelegatorVoteBody {
101    type Proto = pb::DelegatorVoteBody;
102}
103
104impl From<DelegatorVote> for pb::DelegatorVote {
105    fn from(value: DelegatorVote) -> Self {
106        pb::DelegatorVote {
107            body: Some(value.body.into()),
108            auth_sig: Some(value.auth_sig.into()),
109            proof: Some(value.proof.into()),
110        }
111    }
112}
113
114impl TryFrom<pb::DelegatorVote> for DelegatorVote {
115    type Error = anyhow::Error;
116
117    fn try_from(msg: pb::DelegatorVote) -> Result<Self, Self::Error> {
118        Ok(DelegatorVote {
119            body: msg
120                .body
121                .ok_or_else(|| anyhow::anyhow!("missing body in `DelegatorVote`"))?
122                .try_into()?,
123            auth_sig: msg
124                .auth_sig
125                .ok_or_else(|| anyhow::anyhow!("missing auth sig in `DelegatorVote`"))?
126                .try_into()?,
127            proof: msg
128                .proof
129                .ok_or_else(|| anyhow::anyhow!("missing delegator vote proof"))?
130                .try_into()
131                .context("delegator vote proof malformed")?,
132        })
133    }
134}