node/ledger/read/
ledger_read_state.rs

1use openmina_core::requests::{PendingRequests, RequestId, RequestIdType};
2use serde::{Deserialize, Serialize};
3
4use super::{LedgerReadRequest, LedgerReadResponse};
5
6const MAX_TOTAL_COST: usize = 256;
7
8pub struct LedgerReadIdType;
9impl RequestIdType for LedgerReadIdType {
10    fn request_id_type() -> &'static str {
11        "LedgerReadId"
12    }
13}
14
15pub type LedgerReadId = RequestId<LedgerReadIdType>;
16
17#[derive(Serialize, Deserialize, Debug, Default, Clone)]
18pub struct LedgerReadState {
19    pending: PendingRequests<LedgerReadIdType, LedgerReadRequestState>,
20    /// Total cost of currently pending requests.
21    total_cost: usize,
22}
23
24#[derive(Serialize, Deserialize, Debug, Clone)]
25pub enum LedgerReadRequestState {
26    Pending {
27        time: redux::Timestamp,
28        request: LedgerReadRequest,
29    },
30    Success {
31        time: redux::Timestamp,
32        request: LedgerReadRequest,
33        response: LedgerReadResponse,
34    },
35}
36
37impl LedgerReadState {
38    pub fn contains(&self, id: LedgerReadId) -> bool {
39        self.pending.contains(id)
40    }
41
42    pub fn get(&self, id: LedgerReadId) -> Option<&LedgerReadRequestState> {
43        self.pending.get(id)
44    }
45
46    pub fn get_mut(&mut self, id: LedgerReadId) -> Option<&mut LedgerReadRequestState> {
47        self.pending.get_mut(id)
48    }
49
50    pub fn is_total_cost_under_limit(&self) -> bool {
51        self.total_cost < MAX_TOTAL_COST
52    }
53
54    pub fn next_req_id(&self) -> LedgerReadId {
55        self.pending.next_req_id()
56    }
57
58    pub fn add(&mut self, time: redux::Timestamp, request: LedgerReadRequest) -> LedgerReadId {
59        self.total_cost = self.total_cost.saturating_add(request.cost());
60        self.pending
61            .add(LedgerReadRequestState::Pending { time, request })
62    }
63
64    pub fn remove(&mut self, id: LedgerReadId) -> Option<LedgerReadRequestState> {
65        let req = self.pending.remove(id)?;
66        self.total_cost = self.total_cost.saturating_sub(req.request().cost());
67        Some(req)
68    }
69
70    pub fn add_response(
71        &mut self,
72        id: LedgerReadId,
73        time: redux::Timestamp,
74        response: LedgerReadResponse,
75    ) {
76        self.pending.update(id, move |req| match req {
77            LedgerReadRequestState::Pending { request, .. } => LedgerReadRequestState::Success {
78                time,
79                request,
80                response,
81            },
82            LedgerReadRequestState::Success { .. } => {
83                unreachable!("must be prevented by enabling condition")
84            }
85        });
86    }
87
88    pub fn has_same_request(&self, req: &LedgerReadRequest) -> bool {
89        self.pending
90            .iter()
91            .any(|(_, pending)| pending.request() == req)
92    }
93
94    pub fn pending_requests(
95        &self,
96    ) -> impl Iterator<Item = (LedgerReadId, &LedgerReadRequest, redux::Timestamp)> {
97        self.pending.iter().filter_map(|(id, s)| match s {
98            LedgerReadRequestState::Pending { time, request } => Some((id, request, *time)),
99            _ => None,
100        })
101    }
102}
103
104impl LedgerReadRequestState {
105    pub fn request(&self) -> &LedgerReadRequest {
106        match self {
107            Self::Pending { request, .. } | Self::Success { request, .. } => request,
108        }
109    }
110}