penumbra_sdk_funding/component/
rpc.rs1use cnidarium::Storage;
2use penumbra_sdk_proto::core::component::funding::v1::{
3 self as pb, funding_service_server::FundingService,
4};
5use penumbra_sdk_sct::{component::clock::EpochRead, Nullifier};
6
7use super::liquidity_tournament::nullifier::NullifierRead;
8
9pub struct Server {
10 storage: Storage,
11}
12
13impl Server {
14 pub fn new(storage: Storage) -> Self {
15 Self { storage }
16 }
17}
18
19#[tonic::async_trait]
20impl FundingService for Server {
21 async fn lqt_check_nullifier(
22 &self,
23 request: tonic::Request<pb::LqtCheckNullifierRequest>,
24 ) -> Result<tonic::Response<pb::LqtCheckNullifierResponse>, tonic::Status> {
25 let state = self.storage.latest_snapshot();
27
28 let req_inner = request.into_inner();
29 let nullifier_proto = req_inner
30 .nullifier
31 .ok_or_else(|| tonic::Status::invalid_argument("missing nullifier"))?;
32
33 let nullifier: Nullifier = nullifier_proto
35 .try_into()
36 .map_err(|e| tonic::Status::invalid_argument(format!("invalid nullifier: {e}")))?;
37
38 let epoch_index = if req_inner.epoch_index == 0 {
41 let current_epoch = state.get_current_epoch().await.map_err(|e| {
42 tonic::Status::internal(format!("failed to retrieve current epoch: {e}"))
43 })?;
44 current_epoch.index
45 } else {
46 req_inner.epoch_index
47 };
48
49 let maybe_tx_id = state
51 .get_lqt_spent_nullifier_by_epoch(nullifier, epoch_index)
52 .await;
53
54 if let Some(tx_id) = maybe_tx_id {
55 Ok(tonic::Response::new(pb::LqtCheckNullifierResponse {
57 transaction: Some(tx_id.into()),
58 already_voted: true,
59 epoch_index,
60 }))
61 } else {
62 Ok(tonic::Response::new(pb::LqtCheckNullifierResponse {
64 transaction: None,
65 already_voted: false,
66 epoch_index,
67 }))
68 }
69 }
70}