snops_common/state/
height_request.rs

1use std::str::FromStr;
2
3use snops_checkpoint::RetentionSpan;
4
5use crate::format::{DataFormat, DataFormatReader, DataHeaderOf, DataReadError};
6
7/// for some reason bincode does not allow deserialize_any so if i want to allow
8/// end users to type "top", 42, or "persist" i need to do have to copies of
9/// this where one is not untagged.
10///
11/// bincode. please.
12#[derive(Debug, Copy, Default, Clone, serde::Serialize, serde::Deserialize, PartialEq, Eq)]
13#[serde(rename_all = "lowercase", untagged)]
14pub enum DocHeightRequest {
15    #[default]
16    /// Use the latest height for the ledger
17    #[serde(with = "super::strings::top")]
18    Top,
19    /// Set the height to the given block (there must be a checkpoint at this
20    /// height) Setting to 0 will reset the height to the genesis block
21    Absolute(u32),
22    /// Use the next checkpoint that matches this checkpoint span
23    Checkpoint(snops_checkpoint::RetentionSpan),
24    // the control plane doesn't know the heights the nodes are at
25    // TruncateHeight(u32),
26    // TruncateTime(i64),
27}
28
29impl FromStr for DocHeightRequest {
30    type Err = String;
31
32    fn from_str(s: &str) -> Result<Self, Self::Err> {
33        match s {
34            "top" => Ok(DocHeightRequest::Top),
35            s => {
36                if let Ok(height) = s.parse() {
37                    Ok(DocHeightRequest::Absolute(height))
38                } else if let Ok(span) = s.parse() {
39                    Ok(DocHeightRequest::Checkpoint(span))
40                } else {
41                    Err(format!("invalid DocHeightRequest: {}", s))
42                }
43            }
44        }
45    }
46}
47
48impl DataFormat for DocHeightRequest {
49    type Header = (u8, DataHeaderOf<RetentionSpan>);
50    const LATEST_HEADER: Self::Header = (1, RetentionSpan::LATEST_HEADER);
51
52    fn write_data<W: std::io::prelude::Write>(
53        &self,
54        writer: &mut W,
55    ) -> Result<usize, crate::format::DataWriteError> {
56        match self {
57            DocHeightRequest::Top => 0u8.write_data(writer),
58            DocHeightRequest::Absolute(height) => {
59                Ok(1u8.write_data(writer)? + height.write_data(writer)?)
60            }
61            DocHeightRequest::Checkpoint(retention) => {
62                Ok(2u8.write_data(writer)? + retention.write_data(writer)?)
63            }
64        }
65    }
66
67    fn read_data<R: std::io::prelude::Read>(
68        reader: &mut R,
69        header: &Self::Header,
70    ) -> Result<Self, DataReadError> {
71        if header.0 != Self::LATEST_HEADER.0 {
72            return Err(DataReadError::unsupported(
73                "DocHeightRequest",
74                Self::LATEST_HEADER.0,
75                header.0,
76            ));
77        }
78        match reader.read_data(&())? {
79            0u8 => Ok(DocHeightRequest::Top),
80            1u8 => Ok(DocHeightRequest::Absolute(reader.read_data(&())?)),
81            2u8 => Ok(DocHeightRequest::Checkpoint(reader.read_data(&header.1)?)),
82            n => Err(DataReadError::Custom(format!(
83                "invalid DocHeightRequest discrminant: {n}"
84            ))),
85        }
86    }
87}
88
89#[derive(Debug, Default, Copy, Clone, serde::Serialize, serde::Deserialize, PartialEq, Eq)]
90#[serde(rename_all = "lowercase")]
91pub enum HeightRequest {
92    #[default]
93    /// Use the latest height for the ledger
94    Top,
95    /// Set the height to the given block (there must be a checkpoint at this
96    /// height) Setting to 0 will reset the height to the genesis block
97    Absolute(u32),
98    /// Use the next checkpoint that matches this checkpoint span
99    Checkpoint(snops_checkpoint::RetentionSpan),
100    // the control plane doesn't know the heights the nodes are at
101    // TruncateHeight(u32),
102    // TruncateTime(i64),
103}
104
105// TODO: now that we don't use bincode for storage format, we should be able to
106// make remove HeightRequest and rename DocHeightRequest to HeightRequest
107impl DataFormat for HeightRequest {
108    type Header = (u8, DataHeaderOf<RetentionSpan>);
109    const LATEST_HEADER: Self::Header = (1, RetentionSpan::LATEST_HEADER);
110
111    fn write_data<W: std::io::prelude::Write>(
112        &self,
113        writer: &mut W,
114    ) -> Result<usize, crate::format::DataWriteError> {
115        match self {
116            HeightRequest::Top => 0u8.write_data(writer),
117            HeightRequest::Absolute(height) => {
118                Ok(1u8.write_data(writer)? + height.write_data(writer)?)
119            }
120            HeightRequest::Checkpoint(retention) => {
121                Ok(2u8.write_data(writer)? + retention.write_data(writer)?)
122            }
123        }
124    }
125
126    fn read_data<R: std::io::prelude::Read>(
127        reader: &mut R,
128        header: &Self::Header,
129    ) -> Result<Self, DataReadError> {
130        if header.0 != Self::LATEST_HEADER.0 {
131            return Err(DataReadError::unsupported(
132                "HeightRequest",
133                Self::LATEST_HEADER.0,
134                header.0,
135            ));
136        }
137        match reader.read_data(&())? {
138            0u8 => Ok(HeightRequest::Top),
139            1u8 => Ok(HeightRequest::Absolute(reader.read_data(&())?)),
140            2u8 => Ok(HeightRequest::Checkpoint(reader.read_data(&header.1)?)),
141            n => Err(DataReadError::Custom(format!(
142                "invalid HeightRequest discrminant: {n}"
143            ))),
144        }
145    }
146}
147
148impl HeightRequest {
149    pub fn is_top(&self) -> bool {
150        *self == Self::Top
151    }
152
153    pub fn reset(&self) -> bool {
154        *self == Self::Absolute(0)
155    }
156}
157
158impl From<DocHeightRequest> for HeightRequest {
159    fn from(req: DocHeightRequest) -> Self {
160        match req {
161            DocHeightRequest::Top => Self::Top,
162            DocHeightRequest::Absolute(h) => Self::Absolute(h),
163            DocHeightRequest::Checkpoint(c) => Self::Checkpoint(c),
164        }
165    }
166}