penumbra_sdk_governance/action_handler/
delegator_vote.rs1use anyhow::{Context, Result};
2use ark_ff::Zero;
3use async_trait::async_trait;
4use cnidarium::StateWrite;
5use decaf377::Fr;
6use penumbra_sdk_proof_params::DELEGATOR_VOTE_PROOF_VERIFICATION_KEY;
7use penumbra_sdk_proto::StateWriteProto as _;
8use penumbra_sdk_txhash::TransactionContext;
9
10use crate::{
11 event, DelegatorVote, DelegatorVoteBody, DelegatorVoteProofPublic,
12 {component::StateWriteExt, StateReadExt},
13};
14use cnidarium_component::ActionHandler;
15
16#[async_trait]
17impl ActionHandler for DelegatorVote {
18 type CheckStatelessContext = TransactionContext;
19
20 async fn check_stateless(&self, context: TransactionContext) -> Result<()> {
21 let DelegatorVote {
22 auth_sig,
23 proof,
24 body:
25 DelegatorVoteBody {
26 start_position,
27 nullifier,
28 rk,
29 value,
30 unbonded_amount: _,
32 vote: _, proposal: _, },
35 } = self;
36
37 rk.verify(context.effect_hash.as_ref(), auth_sig)
39 .context("delegator vote auth signature failed to verify")?;
40
41 let public = DelegatorVoteProofPublic {
43 anchor: context.anchor,
44 balance_commitment: value.commit(Fr::zero()),
45 nullifier: *nullifier,
46 rk: *rk,
47 start_position: *start_position,
48 };
49 proof
50 .verify(&DELEGATOR_VOTE_PROOF_VERIFICATION_KEY, public)
51 .context("a delegator vote proof did not verify")?;
52
53 Ok(())
54 }
55
56 async fn check_and_execute<S: StateWrite>(&self, mut state: S) -> Result<()> {
57 let DelegatorVote {
58 body:
59 DelegatorVoteBody {
60 proposal,
61 vote,
62 start_position,
63 value,
64 unbonded_amount,
65 nullifier,
66 rk: _, },
68 auth_sig: _, proof: _, } = self;
71
72 state.check_proposal_votable(*proposal).await?;
73 state
74 .check_proposal_started_at_position(*proposal, *start_position)
75 .await?;
76 state
77 .check_nullifier_unspent_before_start_block_height(*proposal, nullifier)
78 .await?;
79 state
80 .check_nullifier_unvoted_for_proposal(*proposal, nullifier)
81 .await?;
82 state
83 .check_unbonded_amount_correct_exchange_for_proposal(*proposal, value, unbonded_amount)
84 .await?;
85
86 state
87 .mark_nullifier_voted_on_proposal(*proposal, nullifier)
88 .await;
89 let identity_key = state.validator_by_delegation_asset(value.asset_id).await?;
90 state
91 .cast_delegator_vote(*proposal, identity_key, *vote, nullifier, *unbonded_amount)
92 .await?;
93
94 state.record_proto(event::delegator_vote(self, &identity_key));
95
96 Ok(())
97 }
98}