penumbra_sdk_governance/validator_vote/
action.rs

1use decaf377_rdsa::{Signature, SpendAuth};
2use penumbra_sdk_proto::{penumbra::core::component::governance::v1 as pb, DomainType};
3use penumbra_sdk_stake::{GovernanceKey, IdentityKey};
4use penumbra_sdk_txhash::{EffectHash, EffectingData};
5use serde::{Deserialize, Serialize};
6
7use crate::{vote::Vote, MAX_VALIDATOR_VOTE_REASON_LENGTH};
8
9/// A vote by a validator.
10#[derive(Debug, Clone, Serialize, Deserialize)]
11#[serde(try_from = "pb::ValidatorVote", into = "pb::ValidatorVote")]
12pub struct ValidatorVote {
13    /// The body of the validator vote.
14    pub body: ValidatorVoteBody,
15    /// The signature authorizing the vote (signed with governance key over the body).
16    pub auth_sig: Signature<SpendAuth>,
17}
18
19impl EffectingData for ValidatorVote {
20    fn effect_hash(&self) -> EffectHash {
21        EffectHash::from_proto_effecting_data(&self.to_proto())
22        //self.body.effect_hash()
23    }
24}
25
26/*
27impl EffectingData for ValidatorVoteBody {
28    fn effect_hash(&self) -> EffectHash {
29        EffectHash::from_proto_effecting_data(&self.to_proto())
30    }
31}
32*/
33
34impl DomainType for ValidatorVote {
35    type Proto = pb::ValidatorVote;
36}
37
38impl From<ValidatorVote> for pb::ValidatorVote {
39    fn from(msg: ValidatorVote) -> Self {
40        Self {
41            body: Some(msg.body.into()),
42            auth_sig: Some(msg.auth_sig.into()),
43        }
44    }
45}
46
47impl TryFrom<pb::ValidatorVote> for ValidatorVote {
48    type Error = anyhow::Error;
49
50    fn try_from(msg: pb::ValidatorVote) -> Result<Self, Self::Error> {
51        Ok(Self {
52            body: msg
53                .body
54                .ok_or_else(|| anyhow::anyhow!("missing validator vote body"))?
55                .try_into()?,
56            auth_sig: msg
57                .auth_sig
58                .ok_or_else(|| anyhow::anyhow!("missing validator auth sig"))?
59                .try_into()?,
60        })
61    }
62}
63
64/// A public vote as a validator.
65#[derive(Debug, Clone, Serialize, Deserialize)]
66#[serde(try_from = "pb::ValidatorVoteBody", into = "pb::ValidatorVoteBody")]
67pub struct ValidatorVoteBody {
68    /// The proposal ID to vote on.
69    pub proposal: u64,
70    /// The vote to cast.
71    pub vote: Vote,
72    /// The identity of the validator who is voting.
73    pub identity_key: IdentityKey,
74    /// The governance key for the validator who is voting.
75    pub governance_key: GovernanceKey,
76    /// A comment or justification of the vote. Limited to 1 KB.
77    pub reason: ValidatorVoteReason,
78}
79
80impl From<ValidatorVoteBody> for pb::ValidatorVoteBody {
81    fn from(value: ValidatorVoteBody) -> Self {
82        pb::ValidatorVoteBody {
83            proposal: value.proposal,
84            vote: Some(value.vote.into()),
85            identity_key: Some(value.identity_key.into()),
86            governance_key: Some(value.governance_key.into()),
87            reason: Some(value.reason.into()),
88        }
89    }
90}
91
92impl TryFrom<pb::ValidatorVoteBody> for ValidatorVoteBody {
93    type Error = anyhow::Error;
94
95    fn try_from(msg: pb::ValidatorVoteBody) -> Result<Self, Self::Error> {
96        Ok(ValidatorVoteBody {
97            proposal: msg.proposal,
98            vote: msg
99                .vote
100                .ok_or_else(|| anyhow::anyhow!("missing vote in `ValidatorVote`"))?
101                .try_into()?,
102            identity_key: msg
103                .identity_key
104                .ok_or_else(|| anyhow::anyhow!("missing validator identity in `ValidatorVote`"))?
105                .try_into()?,
106            governance_key: msg
107                .governance_key
108                .ok_or_else(|| {
109                    anyhow::anyhow!("missing validator governance key in `ValidatorVote`")
110                })?
111                .try_into()?,
112            reason: msg
113                .reason
114                .ok_or_else(|| {
115                    anyhow::anyhow!("missing validator governance key in `ValidatorVote`")
116                })?
117                .try_into()?,
118        })
119    }
120}
121
122impl DomainType for ValidatorVoteBody {
123    type Proto = pb::ValidatorVoteBody;
124}
125
126/// A comment or justification of the vote. Limited to 1 KB.
127#[derive(Debug, Clone, Serialize, Deserialize)]
128#[serde(try_from = "pb::ValidatorVoteReason", into = "pb::ValidatorVoteReason")]
129pub struct ValidatorVoteReason(pub String);
130
131impl From<ValidatorVoteReason> for pb::ValidatorVoteReason {
132    fn from(value: ValidatorVoteReason) -> Self {
133        pb::ValidatorVoteReason { reason: value.0 }
134    }
135}
136
137impl TryFrom<pb::ValidatorVoteReason> for ValidatorVoteReason {
138    type Error = anyhow::Error;
139
140    fn try_from(msg: pb::ValidatorVoteReason) -> Result<Self, Self::Error> {
141        // Check the length of the validator reason field.
142        if msg.reason.len() > MAX_VALIDATOR_VOTE_REASON_LENGTH {
143            anyhow::bail!("validator vote reason is too long");
144        }
145
146        Ok(ValidatorVoteReason(msg.reason))
147    }
148}
149
150impl DomainType for ValidatorVoteReason {
151    type Proto = pb::ValidatorVoteReason;
152}