sc_rpc_spec_v2/transaction/
event.rs1use serde::{Deserialize, Serialize};
22
23#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
25#[serde(rename_all = "camelCase")]
26pub struct TransactionBlock<Hash> {
27	pub hash: Hash,
29	pub index: usize,
31}
32
33#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
35#[serde(rename_all = "camelCase")]
36pub struct TransactionError {
37	pub error: String,
39}
40
41#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
43#[serde(rename_all = "camelCase")]
44pub struct TransactionDropped {
45	pub error: String,
47}
48
49#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
71#[serde(bound(
74	serialize = "Hash: Serialize + Clone",
75	deserialize = "Hash: Deserialize<'de> + Clone"
76))]
77#[serde(into = "TransactionEventIR<Hash>", from = "TransactionEventIR<Hash>")]
78pub enum TransactionEvent<Hash> {
79	Validated,
81	BestChainBlockIncluded(Option<TransactionBlock<Hash>>),
88	Finalized(TransactionBlock<Hash>),
90	Error(TransactionError),
92	Invalid(TransactionError),
94	Dropped(TransactionDropped),
96}
97
98impl<Hash> TransactionEvent<Hash> {
99	pub fn is_final(&self) -> bool {
101		matches!(
102			&self,
103			TransactionEvent::Finalized(_) |
104				TransactionEvent::Error(_) |
105				TransactionEvent::Invalid(_) |
106				TransactionEvent::Dropped(_)
107		)
108	}
109}
110
111#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
124#[serde(rename_all = "camelCase")]
125#[serde(tag = "event", content = "block")]
126enum TransactionEventBlockIR<Hash> {
127	BestChainBlockIncluded(Option<TransactionBlock<Hash>>),
129	Finalized(TransactionBlock<Hash>),
131}
132
133#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
146#[serde(rename_all = "camelCase")]
147#[serde(tag = "event")]
148enum TransactionEventNonBlockIR {
149	Validated,
150	Error(TransactionError),
151	Invalid(TransactionError),
152	Dropped(TransactionDropped),
153}
154
155#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
163#[serde(bound(serialize = "Hash: Serialize", deserialize = "Hash: Deserialize<'de>"))]
164#[serde(rename_all = "camelCase")]
165#[serde(untagged)]
166enum TransactionEventIR<Hash> {
167	Block(TransactionEventBlockIR<Hash>),
168	NonBlock(TransactionEventNonBlockIR),
169}
170
171impl<Hash> From<TransactionEvent<Hash>> for TransactionEventIR<Hash> {
172	fn from(value: TransactionEvent<Hash>) -> Self {
173		match value {
174			TransactionEvent::Validated =>
175				TransactionEventIR::NonBlock(TransactionEventNonBlockIR::Validated),
176			TransactionEvent::BestChainBlockIncluded(event) =>
177				TransactionEventIR::Block(TransactionEventBlockIR::BestChainBlockIncluded(event)),
178			TransactionEvent::Finalized(event) =>
179				TransactionEventIR::Block(TransactionEventBlockIR::Finalized(event)),
180			TransactionEvent::Error(event) =>
181				TransactionEventIR::NonBlock(TransactionEventNonBlockIR::Error(event)),
182			TransactionEvent::Invalid(event) =>
183				TransactionEventIR::NonBlock(TransactionEventNonBlockIR::Invalid(event)),
184			TransactionEvent::Dropped(event) =>
185				TransactionEventIR::NonBlock(TransactionEventNonBlockIR::Dropped(event)),
186		}
187	}
188}
189
190impl<Hash> From<TransactionEventIR<Hash>> for TransactionEvent<Hash> {
191	fn from(value: TransactionEventIR<Hash>) -> Self {
192		match value {
193			TransactionEventIR::NonBlock(status) => match status {
194				TransactionEventNonBlockIR::Validated => TransactionEvent::Validated,
195				TransactionEventNonBlockIR::Error(event) => TransactionEvent::Error(event),
196				TransactionEventNonBlockIR::Invalid(event) => TransactionEvent::Invalid(event),
197				TransactionEventNonBlockIR::Dropped(event) => TransactionEvent::Dropped(event),
198			},
199			TransactionEventIR::Block(block) => match block {
200				TransactionEventBlockIR::Finalized(event) => TransactionEvent::Finalized(event),
201				TransactionEventBlockIR::BestChainBlockIncluded(event) =>
202					TransactionEvent::BestChainBlockIncluded(event),
203			},
204		}
205	}
206}
207
208#[cfg(test)]
209mod tests {
210	use super::*;
211	use sp_core::H256;
212
213	#[test]
214	fn validated_event() {
215		let event: TransactionEvent<()> = TransactionEvent::Validated;
216		let ser = serde_json::to_string(&event).unwrap();
217
218		let exp = r#"{"event":"validated"}"#;
219		assert_eq!(ser, exp);
220
221		let event_dec: TransactionEvent<()> = serde_json::from_str(exp).unwrap();
222		assert_eq!(event_dec, event);
223	}
224
225	#[test]
226	fn best_chain_event() {
227		let event: TransactionEvent<()> = TransactionEvent::BestChainBlockIncluded(None);
228		let ser = serde_json::to_string(&event).unwrap();
229
230		let exp = r#"{"event":"bestChainBlockIncluded","block":null}"#;
231		assert_eq!(ser, exp);
232
233		let event_dec: TransactionEvent<()> = serde_json::from_str(exp).unwrap();
234		assert_eq!(event_dec, event);
235
236		let event: TransactionEvent<H256> =
237			TransactionEvent::BestChainBlockIncluded(Some(TransactionBlock {
238				hash: H256::from_low_u64_be(1),
239				index: 2,
240			}));
241		let ser = serde_json::to_string(&event).unwrap();
242
243		let exp = r#"{"event":"bestChainBlockIncluded","block":{"hash":"0x0000000000000000000000000000000000000000000000000000000000000001","index":2}}"#;
244		assert_eq!(ser, exp);
245
246		let event_dec: TransactionEvent<H256> = serde_json::from_str(exp).unwrap();
247		assert_eq!(event_dec, event);
248	}
249
250	#[test]
251	fn finalized_event() {
252		let event: TransactionEvent<H256> = TransactionEvent::Finalized(TransactionBlock {
253			hash: H256::from_low_u64_be(1),
254			index: 10,
255		});
256		let ser = serde_json::to_string(&event).unwrap();
257
258		let exp = r#"{"event":"finalized","block":{"hash":"0x0000000000000000000000000000000000000000000000000000000000000001","index":10}}"#;
259		assert_eq!(ser, exp);
260
261		let event_dec: TransactionEvent<H256> = serde_json::from_str(exp).unwrap();
262		assert_eq!(event_dec, event);
263	}
264
265	#[test]
266	fn error_event() {
267		let event: TransactionEvent<()> =
268			TransactionEvent::Error(TransactionError { error: "abc".to_string() });
269		let ser = serde_json::to_string(&event).unwrap();
270
271		let exp = r#"{"event":"error","error":"abc"}"#;
272		assert_eq!(ser, exp);
273
274		let event_dec: TransactionEvent<()> = serde_json::from_str(exp).unwrap();
275		assert_eq!(event_dec, event);
276	}
277
278	#[test]
279	fn invalid_event() {
280		let event: TransactionEvent<()> =
281			TransactionEvent::Invalid(TransactionError { error: "abc".to_string() });
282		let ser = serde_json::to_string(&event).unwrap();
283
284		let exp = r#"{"event":"invalid","error":"abc"}"#;
285		assert_eq!(ser, exp);
286
287		let event_dec: TransactionEvent<()> = serde_json::from_str(exp).unwrap();
288		assert_eq!(event_dec, event);
289	}
290
291	#[test]
292	fn dropped_event() {
293		let event: TransactionEvent<()> =
294			TransactionEvent::Dropped(TransactionDropped { error: "abc".to_string() });
295		let ser = serde_json::to_string(&event).unwrap();
296
297		let exp = r#"{"event":"dropped","error":"abc"}"#;
298		assert_eq!(ser, exp);
299
300		let event_dec: TransactionEvent<()> = serde_json::from_str(exp).unwrap();
301		assert_eq!(event_dec, event);
302	}
303}