battleware_client/
consensus.rs

1use crate::{Client, Error, Result};
2use battleware_types::{api::Query, Seed, NAMESPACE};
3use commonware_codec::{DecodeExt, Encode};
4use commonware_consensus::Viewable;
5use url::Url;
6
7fn query_seed_path(base: &Url, query: &Query) -> String {
8    let query = query.encode();
9    base.join(&format!("seed/{}", commonware_utils::hex(&query)))
10        .unwrap()
11        .to_string()
12}
13
14impl Client {
15    pub async fn query_seed(&self, query: Query) -> Result<Option<Seed>> {
16        // Make request
17        let result = self
18            .http_client
19            .get(query_seed_path(&self.base_url, &query))
20            .send()
21            .await?;
22
23        // Parse response
24        match result.status() {
25            reqwest::StatusCode::NOT_FOUND => Ok(None),
26            reqwest::StatusCode::OK => {
27                let bytes = result.bytes().await.map_err(Error::Reqwest)?;
28                let seed = Seed::decode(bytes.as_ref()).map_err(Error::InvalidData)?;
29                if !seed.verify(NAMESPACE, &self.identity) {
30                    return Err(Error::InvalidSignature);
31                }
32
33                // Verify the seed matches the query
34                match query {
35                    Query::Latest => {}
36                    Query::Index(index) => {
37                        if seed.view() != index {
38                            return Err(Error::UnexpectedResponse);
39                        }
40                    }
41                }
42                Ok(Some(seed))
43            }
44            _ => Err(Error::Failed(result.status())),
45        }
46    }
47}