minbft/
client_request.rs

1use std::ops::{Deref, DerefMut};
2
3use anyhow::Result;
4use serde::{Deserialize, Serialize};
5use shared_ids::ClientId;
6use tracing::trace;
7
8use crate::RequestPayload;
9
10/// Defines a ClientRequest.
11#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
12pub(crate) struct ClientRequest<P> {
13    pub(crate) client: ClientId,
14    pub(crate) payload: P,
15}
16
17impl<P> Deref for ClientRequest<P> {
18    type Target = P;
19
20    /// Returns a reference to the payload of the ClientRequest.
21    fn deref(&self) -> &Self::Target {
22        &self.payload
23    }
24}
25
26impl<P> DerefMut for ClientRequest<P> {
27    /// Returns a mutable reference to the payload of the ClientRequest.
28    fn deref_mut(&mut self) -> &mut <Self as Deref>::Target {
29        &mut self.payload
30    }
31}
32
33impl<P: RequestPayload> ClientRequest<P> {
34    /// Validates the RequestPayload.
35    pub(crate) fn validate(&self) -> Result<()> {
36        self.verify(self.client)
37    }
38}
39
40/// Defines a RequestBatch.
41#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
42#[repr(transparent)]
43#[serde(transparent)]
44pub(crate) struct RequestBatch<P> {
45    /// The batch of ClientRequests.
46    pub(crate) batch: Box<[ClientRequest<P>]>,
47}
48
49impl<P: RequestPayload> RequestBatch<P> {
50    /// Creates a new RequestBatch with the given batch of ClientRequests.
51    pub(crate) fn new(batch: Box<[ClientRequest<P>]>) -> Self {
52        Self { batch }
53    }
54
55    /// Validates the RequestBatch.
56    pub(crate) fn validate(&self) -> Result<()> {
57        trace!("Validating batch of requests ...");
58        for request in self.batch.iter() {
59            trace!(
60                "Validating client request (ID: {:?}, client ID: {:?}) contained in batch ...",
61                request.id(),
62                request.client
63            );
64            request.validate()?;
65            trace!("Successfully validated client request (ID: {:?}, client ID: {:?}) contained in batch.", request.id(), request.client);
66        }
67        trace!("Successfully validated batch of requests.");
68        Ok(())
69    }
70}
71
72impl<P> IntoIterator for RequestBatch<P> {
73    type Item = ClientRequest<P>;
74
75    type IntoIter = std::vec::IntoIter<Self::Item>;
76
77    /// Converts the RequestBatch into an Iterator.
78    fn into_iter(self) -> Self::IntoIter {
79        let batch = Vec::from(self.batch); // remove once https://github.com/rust-lang/rust/issues/59878 is fixed
80        batch.into_iter()
81    }
82}
83
84#[cfg(test)]
85
86pub(crate) mod test {
87    use rand::{rngs::ThreadRng, Rng};
88    use shared_ids::ClientId;
89
90    use crate::tests::DummyPayload;
91
92    use super::{ClientRequest, RequestBatch};
93
94    pub(crate) fn create_invalid_client_req(rng: &mut ThreadRng) -> ClientRequest<DummyPayload> {
95        let rand_client_id = rng.gen::<u64>();
96        let rand_req_id = rng.gen::<u64>();
97        ClientRequest {
98            client: ClientId::from_u64(rand_client_id),
99            payload: DummyPayload(rand_req_id, false),
100        }
101    }
102
103    pub(crate) fn create_batch() -> RequestBatch<DummyPayload> {
104        let mut batch = Vec::new();
105        for i in 0..10 {
106            let client_req = ClientRequest {
107                client: ClientId::from_u64(i),
108                payload: DummyPayload(i, true),
109            };
110            batch.push(client_req);
111        }
112        let batch: [ClientRequest<DummyPayload>; 10] = batch.try_into().unwrap();
113        let batch = Box::new(batch);
114        RequestBatch { batch }
115    }
116}