vote_commitment_tree_client/
http_sync_api.rs1use pasta_curves::Fp;
9
10use vote_commitment_tree::sync_api::{BlockCommitments, TreeState, TreeSyncApi};
11
12use crate::types::{
13 QueryCommitmentLeavesResponse, QueryCommitmentTreeResponse, QueryLatestTreeResponse,
14};
15
16#[derive(Debug, thiserror::Error)]
22pub enum HttpSyncError {
23 #[error("HTTP request failed: {0}")]
24 Http(#[from] reqwest::Error),
25
26 #[error("parse error: {0}")]
27 Parse(#[from] crate::types::ParseError),
28
29 #[error("server returned no tree state")]
30 NoTreeState,
31}
32
33pub struct HttpTreeSyncApi {
43 client: reqwest::blocking::Client,
44 base_url: String,
46 round_id: String,
48}
49
50impl HttpTreeSyncApi {
51 pub fn new(base_url: impl Into<String>, round_id: impl Into<String>) -> Self {
57 Self {
58 client: reqwest::blocking::Client::new(),
59 base_url: base_url.into(),
60 round_id: round_id.into(),
61 }
62 }
63
64 pub fn with_client(
66 client: reqwest::blocking::Client,
67 base_url: impl Into<String>,
68 round_id: impl Into<String>,
69 ) -> Self {
70 Self {
71 client,
72 base_url: base_url.into(),
73 round_id: round_id.into(),
74 }
75 }
76}
77
78impl TreeSyncApi for HttpTreeSyncApi {
79 type Error = HttpSyncError;
80
81 fn get_tree_state(&self) -> Result<TreeState, Self::Error> {
82 let url = format!(
83 "{}/shielded-vote/v1/commitment-tree/{}/latest",
84 self.base_url, self.round_id
85 );
86 let resp: QueryLatestTreeResponse = self.client.get(&url).send()?.json()?;
87 resp.tree
88 .ok_or(HttpSyncError::NoTreeState)?
89 .into_tree_state()
90 .map_err(HttpSyncError::Parse)
91 }
92
93 fn get_root_at_height(&self, height: u32) -> Result<Option<Fp>, Self::Error> {
94 let url = format!(
95 "{}/shielded-vote/v1/commitment-tree/{}/{}",
96 self.base_url, self.round_id, height
97 );
98 let resp: QueryCommitmentTreeResponse = self.client.get(&url).send()?.json()?;
99 match resp.tree {
100 Some(state) => {
101 let ts = state.into_tree_state().map_err(HttpSyncError::Parse)?;
102 Ok(Some(ts.root))
103 }
104 None => Ok(None),
105 }
106 }
107
108 fn get_block_commitments(
109 &self,
110 from_height: u32,
111 to_height: u32,
112 ) -> Result<Vec<BlockCommitments>, Self::Error> {
113 let url = format!(
114 "{}/shielded-vote/v1/commitment-tree/{}/leaves?from_height={}&to_height={}",
115 self.base_url, self.round_id, from_height, to_height
116 );
117 let resp: QueryCommitmentLeavesResponse = self.client.get(&url).send()?.json()?;
118 resp.blocks
119 .into_iter()
120 .map(|b| b.into_block_commitments().map_err(HttpSyncError::Parse))
121 .collect()
122 }
123}