penumbra_shielded_pool/component/action_handler/
spend.rsuse anyhow::{Context, Result};
use async_trait::async_trait;
use cnidarium::StateWrite;
use cnidarium_component::ActionHandler;
use penumbra_proof_params::SPEND_PROOF_VERIFICATION_KEY;
use penumbra_proto::{DomainType, StateWriteProto as _};
use penumbra_sct::component::{
source::SourceContext,
tree::{SctManager, VerificationExt},
};
use penumbra_txhash::TransactionContext;
use crate::{event, Spend, SpendProofPublic};
#[async_trait]
impl ActionHandler for Spend {
type CheckStatelessContext = TransactionContext;
async fn check_stateless(&self, context: TransactionContext) -> Result<()> {
let spend = self;
spend
.body
.rk
.verify(context.effect_hash.as_ref(), &spend.auth_sig)
.context("spend auth signature failed to verify")?;
let public = SpendProofPublic {
anchor: context.anchor,
balance_commitment: spend.body.balance_commitment,
nullifier: spend.body.nullifier,
rk: spend.body.rk,
};
spend
.proof
.verify(&SPEND_PROOF_VERIFICATION_KEY, public)
.context("a spend proof did not verify")?;
Ok(())
}
async fn check_and_execute<S: StateWrite>(&self, mut state: S) -> Result<()> {
let spent_nullifier = self.body.nullifier;
state.check_nullifier_unspent(spent_nullifier).await?;
let source = state.get_current_source().expect("source should be set");
state.nullify(self.body.nullifier, source).await;
state.record_proto(
event::EventSpend {
nullifier: self.body.nullifier,
}
.to_proto(),
);
Ok(())
}
}