penumbra_sdk_governance/validator_vote/
action.rs1use 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#[derive(Debug, Clone, Serialize, Deserialize)]
11#[serde(try_from = "pb::ValidatorVote", into = "pb::ValidatorVote")]
12pub struct ValidatorVote {
13 pub body: ValidatorVoteBody,
15 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 }
24}
25
26impl 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#[derive(Debug, Clone, Serialize, Deserialize)]
66#[serde(try_from = "pb::ValidatorVoteBody", into = "pb::ValidatorVoteBody")]
67pub struct ValidatorVoteBody {
68 pub proposal: u64,
70 pub vote: Vote,
72 pub identity_key: IdentityKey,
74 pub governance_key: GovernanceKey,
76 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#[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 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}