1use chrono::{DateTime, Utc};
2use serde::{Deserialize, Deserializer, Serialize, Serializer};
3use std::fmt;
4use std::str::FromStr;
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
7#[repr(i16)]
8pub enum ValidatorRsmEnvironment {
9 Development = 1,
10 Staging = 2,
11 Testnet = 3,
12 Mainnet = 4,
13}
14
15impl ValidatorRsmEnvironment {
16 pub fn as_i16(self) -> i16 {
17 self as i16
18 }
19}
20
21impl FromStr for ValidatorRsmEnvironment {
22 type Err = anyhow::Error;
23
24 fn from_str(value: &str) -> Result<Self, Self::Err> {
25 match value.trim().to_ascii_lowercase().as_str() {
26 "development" | "dev" | "local" => Ok(Self::Development),
27 "staging" | "aws-staging" | "linode-staging" => Ok(Self::Staging),
28 "testnet" => Ok(Self::Testnet),
29 "mainnet" | "production" | "prod" => Ok(Self::Mainnet),
30 other => Err(anyhow::anyhow!(
31 "unknown validator RSM environment name: {other}"
32 )),
33 }
34 }
35}
36
37impl TryFrom<i16> for ValidatorRsmEnvironment {
38 type Error = anyhow::Error;
39
40 fn try_from(value: i16) -> Result<Self, Self::Error> {
41 match value {
42 1 => Ok(Self::Development),
43 2 => Ok(Self::Staging),
44 3 => Ok(Self::Testnet),
45 4 => Ok(Self::Mainnet),
46 _ => Err(anyhow::anyhow!(
47 "unknown validator RSM environment id: {value}"
48 )),
49 }
50 }
51}
52
53impl fmt::Display for ValidatorRsmEnvironment {
54 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
55 let name = match self {
56 Self::Development => "development",
57 Self::Staging => "staging",
58 Self::Testnet => "testnet",
59 Self::Mainnet => "mainnet",
60 };
61 f.write_str(name)
62 }
63}
64
65impl Serialize for ValidatorRsmEnvironment {
66 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
67 where
68 S: Serializer,
69 {
70 serializer.serialize_str(&self.to_string())
71 }
72}
73
74impl<'de> Deserialize<'de> for ValidatorRsmEnvironment {
75 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
76 where
77 D: Deserializer<'de>,
78 {
79 let value = String::deserialize(deserializer)?;
80 value.parse().map_err(serde::de::Error::custom)
81 }
82}
83
84#[derive(Debug, Clone, PartialEq, Eq)]
85pub struct ValidatorRsmRootSummary {
86 pub environment: ValidatorRsmEnvironment,
87 pub version: u64,
88 pub batch_seq: u64,
89 pub state_root: [u8; 32],
90 pub risk_root: [u8; 32],
91 pub command_mmr_root: [u8; 32],
92 pub obligation_mmr_root: [u8; 32],
93 pub intent_mmr_root: [u8; 32],
94 pub batch_root: [u8; 32],
95 pub command_range_start: u64,
96 pub command_range_end: u64,
97 pub command_count: u64,
98 pub schema_version: i32,
99 pub accepted_block_hash: [u8; 32],
100 pub created_at: DateTime<Utc>,
101}
102
103#[derive(Debug, Clone, PartialEq, Eq)]
104pub struct RsmBlockHeader {
105 pub environment: ValidatorRsmEnvironment,
106 pub height: u64,
107 pub hash: [u8; 32],
108 pub parent_hash: [u8; 32],
109 pub commands_hash: [u8; 32],
110 pub batch_root: [u8; 32],
111 pub command_count: u64,
112 pub first_command_seq: u64,
113 pub last_command_seq: u64,
114 pub signer: Option<[u8; 20]>,
115 pub signature: Option<Vec<u8>>,
116 pub created_at: DateTime<Utc>,
117}
118
119#[derive(Debug, Clone, PartialEq, Eq)]
120pub struct NewRsmBlockHeader {
121 pub environment: ValidatorRsmEnvironment,
122 pub height: u64,
123 pub hash: [u8; 32],
124 pub parent_hash: [u8; 32],
125 pub commands_hash: [u8; 32],
126 pub batch_root: [u8; 32],
127 pub command_count: u64,
128 pub first_command_seq: u64,
129 pub last_command_seq: u64,
130 pub signer: Option<[u8; 20]>,
131 pub signature: Option<Vec<u8>>,
132}
133
134#[derive(Debug, Clone, PartialEq, Eq)]
135pub struct RsmBlockView {
136 pub block: RsmBlockHeader,
137 pub root_summary: ValidatorRsmRootSummary,
138}
139
140#[derive(Debug, Clone, PartialEq, Eq)]
141pub struct RsmBlockCommand {
142 pub environment: ValidatorRsmEnvironment,
143 pub height: u64,
144 pub rsm_command_seq: u64,
145 pub command_index: u64,
146 pub engine_command_id: i64,
147 pub request_uuid: uuid::Uuid,
148 pub command_type: String,
149 pub command_data: Vec<u8>,
150 pub command_identity_hash: [u8; 32],
151 pub created_at: DateTime<Utc>,
152}
153
154#[derive(Debug, Clone, PartialEq, Eq)]
155pub struct NewRsmBlockCommand {
156 pub environment: ValidatorRsmEnvironment,
157 pub height: u64,
158 pub rsm_command_seq: u64,
159 pub command_index: u64,
160 pub engine_command_id: i64,
161 pub request_uuid: uuid::Uuid,
162 pub command_type: String,
163 pub command_data: Vec<u8>,
164 pub command_identity_hash: [u8; 32],
165}
166
167#[derive(Debug, Clone, PartialEq, Eq)]
168pub struct RsmBlockData {
169 pub block: RsmBlockView,
170 pub commands: Vec<RsmBlockCommand>,
171}
172
173#[derive(Debug, Clone, PartialEq, Eq)]
174pub struct NewValidatorRsmRootSummary {
175 pub environment: ValidatorRsmEnvironment,
176 pub version: u64,
177 pub batch_seq: u64,
178 pub state_root: [u8; 32],
179 pub risk_root: [u8; 32],
180 pub command_mmr_root: [u8; 32],
181 pub obligation_mmr_root: [u8; 32],
182 pub intent_mmr_root: [u8; 32],
183 pub batch_root: [u8; 32],
184 pub command_range_start: u64,
185 pub command_range_end: u64,
186 pub command_count: u64,
187 pub schema_version: i32,
188 pub accepted_block_hash: [u8; 32],
189}
190
191#[derive(Debug, Clone, PartialEq, Eq)]
192pub struct ValidatorRsmCurrentState {
193 pub environment: ValidatorRsmEnvironment,
194 pub current_version: u64,
195 pub updated_at: DateTime<Utc>,
196}
197
198#[cfg(test)]
199mod tests {
200 use super::*;
201
202 #[test]
203 fn validator_rsm_environment_roundtrips_known_ids() {
204 for environment in [
205 ValidatorRsmEnvironment::Development,
206 ValidatorRsmEnvironment::Staging,
207 ValidatorRsmEnvironment::Testnet,
208 ValidatorRsmEnvironment::Mainnet,
209 ] {
210 assert_eq!(
211 ValidatorRsmEnvironment::try_from(environment.as_i16()).unwrap(),
212 environment
213 );
214 }
215 }
216
217 #[test]
218 fn validator_rsm_environment_rejects_unknown_ids() {
219 assert!(ValidatorRsmEnvironment::try_from(0).is_err());
220 assert!(ValidatorRsmEnvironment::try_from(5).is_err());
221 }
222
223 #[test]
224 fn validator_rsm_environment_parses_names() {
225 assert_eq!(
226 "development".parse::<ValidatorRsmEnvironment>().unwrap(),
227 ValidatorRsmEnvironment::Development
228 );
229 assert_eq!(
230 "staging".parse::<ValidatorRsmEnvironment>().unwrap(),
231 ValidatorRsmEnvironment::Staging
232 );
233 assert!("unknown".parse::<ValidatorRsmEnvironment>().is_err());
234 }
235}