1use serde::{Deserialize, Serialize};
10
11#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
13#[serde(rename_all = "camelCase")]
14pub struct TransactionBlock<Hash> {
15 pub hash: Hash,
17 pub index: usize,
19}
20
21#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
23#[serde(rename_all = "camelCase")]
24pub struct TransactionError {
25 pub error: String,
27}
28
29#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
31#[serde(rename_all = "camelCase")]
32pub struct TransactionDropped {
33 pub error: String,
35}
36
37#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
59#[serde(bound(
62 serialize = "Hash: Serialize + Clone",
63 deserialize = "Hash: Deserialize<'de> + Clone"
64))]
65#[serde(into = "TransactionEventIR<Hash>", from = "TransactionEventIR<Hash>")]
66pub enum TransactionEvent<Hash> {
67 Validated,
69 BestChainBlockIncluded(Option<TransactionBlock<Hash>>),
76 Finalized(TransactionBlock<Hash>),
78 Error(TransactionError),
80 Invalid(TransactionError),
82 Dropped(TransactionDropped),
84}
85
86impl<Hash> TransactionEvent<Hash> {
87 pub fn is_final(&self) -> bool {
89 matches!(
90 &self,
91 TransactionEvent::Finalized(_)
92 | TransactionEvent::Error(_)
93 | TransactionEvent::Invalid(_)
94 | TransactionEvent::Dropped(_)
95 )
96 }
97}
98
99#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
112#[serde(rename_all = "camelCase")]
113#[serde(tag = "event", content = "block")]
114enum TransactionEventBlockIR<Hash> {
115 BestChainBlockIncluded(Option<TransactionBlock<Hash>>),
117 Finalized(TransactionBlock<Hash>),
119}
120
121#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
134#[serde(rename_all = "camelCase")]
135#[serde(tag = "event")]
136enum TransactionEventNonBlockIR {
137 Validated,
138 Error(TransactionError),
139 Invalid(TransactionError),
140 Dropped(TransactionDropped),
141}
142
143#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
151#[serde(bound(serialize = "Hash: Serialize", deserialize = "Hash: Deserialize<'de>"))]
152#[serde(rename_all = "camelCase")]
153#[serde(untagged)]
154enum TransactionEventIR<Hash> {
155 Block(TransactionEventBlockIR<Hash>),
156 NonBlock(TransactionEventNonBlockIR),
157}
158
159impl<Hash> From<TransactionEvent<Hash>> for TransactionEventIR<Hash> {
160 fn from(value: TransactionEvent<Hash>) -> Self {
161 match value {
162 TransactionEvent::Validated => {
163 TransactionEventIR::NonBlock(TransactionEventNonBlockIR::Validated)
164 },
165 TransactionEvent::BestChainBlockIncluded(event) => {
166 TransactionEventIR::Block(TransactionEventBlockIR::BestChainBlockIncluded(event))
167 },
168 TransactionEvent::Finalized(event) => {
169 TransactionEventIR::Block(TransactionEventBlockIR::Finalized(event))
170 },
171 TransactionEvent::Error(event) => {
172 TransactionEventIR::NonBlock(TransactionEventNonBlockIR::Error(event))
173 },
174 TransactionEvent::Invalid(event) => {
175 TransactionEventIR::NonBlock(TransactionEventNonBlockIR::Invalid(event))
176 },
177 TransactionEvent::Dropped(event) => {
178 TransactionEventIR::NonBlock(TransactionEventNonBlockIR::Dropped(event))
179 },
180 }
181 }
182}
183
184impl<Hash> From<TransactionEventIR<Hash>> for TransactionEvent<Hash> {
185 fn from(value: TransactionEventIR<Hash>) -> Self {
186 match value {
187 TransactionEventIR::NonBlock(status) => match status {
188 TransactionEventNonBlockIR::Validated => TransactionEvent::Validated,
189 TransactionEventNonBlockIR::Error(event) => TransactionEvent::Error(event),
190 TransactionEventNonBlockIR::Invalid(event) => TransactionEvent::Invalid(event),
191 TransactionEventNonBlockIR::Dropped(event) => TransactionEvent::Dropped(event),
192 },
193 TransactionEventIR::Block(block) => match block {
194 TransactionEventBlockIR::Finalized(event) => TransactionEvent::Finalized(event),
195 TransactionEventBlockIR::BestChainBlockIncluded(event) => {
196 TransactionEvent::BestChainBlockIncluded(event)
197 },
198 },
199 }
200 }
201}
202
203#[cfg(test)]
204mod tests {
205 use super::*;
206 use subsoil::core::H256;
207
208 #[test]
209 fn validated_event() {
210 let event: TransactionEvent<()> = TransactionEvent::Validated;
211 let ser = serde_json::to_string(&event).unwrap();
212
213 let exp = r#"{"event":"validated"}"#;
214 assert_eq!(ser, exp);
215
216 let event_dec: TransactionEvent<()> = serde_json::from_str(exp).unwrap();
217 assert_eq!(event_dec, event);
218 }
219
220 #[test]
221 fn best_chain_event() {
222 let event: TransactionEvent<()> = TransactionEvent::BestChainBlockIncluded(None);
223 let ser = serde_json::to_string(&event).unwrap();
224
225 let exp = r#"{"event":"bestChainBlockIncluded","block":null}"#;
226 assert_eq!(ser, exp);
227
228 let event_dec: TransactionEvent<()> = serde_json::from_str(exp).unwrap();
229 assert_eq!(event_dec, event);
230
231 let event: TransactionEvent<H256> =
232 TransactionEvent::BestChainBlockIncluded(Some(TransactionBlock {
233 hash: H256::from_low_u64_be(1),
234 index: 2,
235 }));
236 let ser = serde_json::to_string(&event).unwrap();
237
238 let exp = r#"{"event":"bestChainBlockIncluded","block":{"hash":"0x0000000000000000000000000000000000000000000000000000000000000001","index":2}}"#;
239 assert_eq!(ser, exp);
240
241 let event_dec: TransactionEvent<H256> = serde_json::from_str(exp).unwrap();
242 assert_eq!(event_dec, event);
243 }
244
245 #[test]
246 fn finalized_event() {
247 let event: TransactionEvent<H256> = TransactionEvent::Finalized(TransactionBlock {
248 hash: H256::from_low_u64_be(1),
249 index: 10,
250 });
251 let ser = serde_json::to_string(&event).unwrap();
252
253 let exp = r#"{"event":"finalized","block":{"hash":"0x0000000000000000000000000000000000000000000000000000000000000001","index":10}}"#;
254 assert_eq!(ser, exp);
255
256 let event_dec: TransactionEvent<H256> = serde_json::from_str(exp).unwrap();
257 assert_eq!(event_dec, event);
258 }
259
260 #[test]
261 fn error_event() {
262 let event: TransactionEvent<()> =
263 TransactionEvent::Error(TransactionError { error: "abc".to_string() });
264 let ser = serde_json::to_string(&event).unwrap();
265
266 let exp = r#"{"event":"error","error":"abc"}"#;
267 assert_eq!(ser, exp);
268
269 let event_dec: TransactionEvent<()> = serde_json::from_str(exp).unwrap();
270 assert_eq!(event_dec, event);
271 }
272
273 #[test]
274 fn invalid_event() {
275 let event: TransactionEvent<()> =
276 TransactionEvent::Invalid(TransactionError { error: "abc".to_string() });
277 let ser = serde_json::to_string(&event).unwrap();
278
279 let exp = r#"{"event":"invalid","error":"abc"}"#;
280 assert_eq!(ser, exp);
281
282 let event_dec: TransactionEvent<()> = serde_json::from_str(exp).unwrap();
283 assert_eq!(event_dec, event);
284 }
285
286 #[test]
287 fn dropped_event() {
288 let event: TransactionEvent<()> =
289 TransactionEvent::Dropped(TransactionDropped { error: "abc".to_string() });
290 let ser = serde_json::to_string(&event).unwrap();
291
292 let exp = r#"{"event":"dropped","error":"abc"}"#;
293 assert_eq!(ser, exp);
294
295 let event_dec: TransactionEvent<()> = serde_json::from_str(exp).unwrap();
296 assert_eq!(event_dec, event);
297 }
298}