use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct TransactionBlock<Hash> {
pub hash: Hash,
pub index: usize,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct TransactionError {
pub error: String,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct TransactionDropped {
pub error: String,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(bound(
serialize = "Hash: Serialize + Clone",
deserialize = "Hash: Deserialize<'de> + Clone"
))]
#[serde(into = "TransactionEventIR<Hash>", from = "TransactionEventIR<Hash>")]
pub enum TransactionEvent<Hash> {
Validated,
BestChainBlockIncluded(Option<TransactionBlock<Hash>>),
Finalized(TransactionBlock<Hash>),
Error(TransactionError),
Invalid(TransactionError),
Dropped(TransactionDropped),
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
#[serde(tag = "event", content = "block")]
enum TransactionEventBlockIR<Hash> {
BestChainBlockIncluded(Option<TransactionBlock<Hash>>),
Finalized(TransactionBlock<Hash>),
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
#[serde(tag = "event")]
enum TransactionEventNonBlockIR {
Validated,
Error(TransactionError),
Invalid(TransactionError),
Dropped(TransactionDropped),
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(bound(serialize = "Hash: Serialize", deserialize = "Hash: Deserialize<'de>"))]
#[serde(rename_all = "camelCase")]
#[serde(untagged)]
enum TransactionEventIR<Hash> {
Block(TransactionEventBlockIR<Hash>),
NonBlock(TransactionEventNonBlockIR),
}
impl<Hash> From<TransactionEvent<Hash>> for TransactionEventIR<Hash> {
fn from(value: TransactionEvent<Hash>) -> Self {
match value {
TransactionEvent::Validated =>
TransactionEventIR::NonBlock(TransactionEventNonBlockIR::Validated),
TransactionEvent::BestChainBlockIncluded(event) =>
TransactionEventIR::Block(TransactionEventBlockIR::BestChainBlockIncluded(event)),
TransactionEvent::Finalized(event) =>
TransactionEventIR::Block(TransactionEventBlockIR::Finalized(event)),
TransactionEvent::Error(event) =>
TransactionEventIR::NonBlock(TransactionEventNonBlockIR::Error(event)),
TransactionEvent::Invalid(event) =>
TransactionEventIR::NonBlock(TransactionEventNonBlockIR::Invalid(event)),
TransactionEvent::Dropped(event) =>
TransactionEventIR::NonBlock(TransactionEventNonBlockIR::Dropped(event)),
}
}
}
impl<Hash> From<TransactionEventIR<Hash>> for TransactionEvent<Hash> {
fn from(value: TransactionEventIR<Hash>) -> Self {
match value {
TransactionEventIR::NonBlock(status) => match status {
TransactionEventNonBlockIR::Validated => TransactionEvent::Validated,
TransactionEventNonBlockIR::Error(event) => TransactionEvent::Error(event),
TransactionEventNonBlockIR::Invalid(event) => TransactionEvent::Invalid(event),
TransactionEventNonBlockIR::Dropped(event) => TransactionEvent::Dropped(event),
},
TransactionEventIR::Block(block) => match block {
TransactionEventBlockIR::Finalized(event) => TransactionEvent::Finalized(event),
TransactionEventBlockIR::BestChainBlockIncluded(event) =>
TransactionEvent::BestChainBlockIncluded(event),
},
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use sp_core::H256;
#[test]
fn validated_event() {
let event: TransactionEvent<()> = TransactionEvent::Validated;
let ser = serde_json::to_string(&event).unwrap();
let exp = r#"{"event":"validated"}"#;
assert_eq!(ser, exp);
let event_dec: TransactionEvent<()> = serde_json::from_str(exp).unwrap();
assert_eq!(event_dec, event);
}
#[test]
fn best_chain_event() {
let event: TransactionEvent<()> = TransactionEvent::BestChainBlockIncluded(None);
let ser = serde_json::to_string(&event).unwrap();
let exp = r#"{"event":"bestChainBlockIncluded","block":null}"#;
assert_eq!(ser, exp);
let event_dec: TransactionEvent<()> = serde_json::from_str(exp).unwrap();
assert_eq!(event_dec, event);
let event: TransactionEvent<H256> =
TransactionEvent::BestChainBlockIncluded(Some(TransactionBlock {
hash: H256::from_low_u64_be(1),
index: 2,
}));
let ser = serde_json::to_string(&event).unwrap();
let exp = r#"{"event":"bestChainBlockIncluded","block":{"hash":"0x0000000000000000000000000000000000000000000000000000000000000001","index":2}}"#;
assert_eq!(ser, exp);
let event_dec: TransactionEvent<H256> = serde_json::from_str(exp).unwrap();
assert_eq!(event_dec, event);
}
#[test]
fn finalized_event() {
let event: TransactionEvent<H256> = TransactionEvent::Finalized(TransactionBlock {
hash: H256::from_low_u64_be(1),
index: 10,
});
let ser = serde_json::to_string(&event).unwrap();
let exp = r#"{"event":"finalized","block":{"hash":"0x0000000000000000000000000000000000000000000000000000000000000001","index":10}}"#;
assert_eq!(ser, exp);
let event_dec: TransactionEvent<H256> = serde_json::from_str(exp).unwrap();
assert_eq!(event_dec, event);
}
#[test]
fn error_event() {
let event: TransactionEvent<()> =
TransactionEvent::Error(TransactionError { error: "abc".to_string() });
let ser = serde_json::to_string(&event).unwrap();
let exp = r#"{"event":"error","error":"abc"}"#;
assert_eq!(ser, exp);
let event_dec: TransactionEvent<()> = serde_json::from_str(exp).unwrap();
assert_eq!(event_dec, event);
}
#[test]
fn invalid_event() {
let event: TransactionEvent<()> =
TransactionEvent::Invalid(TransactionError { error: "abc".to_string() });
let ser = serde_json::to_string(&event).unwrap();
let exp = r#"{"event":"invalid","error":"abc"}"#;
assert_eq!(ser, exp);
let event_dec: TransactionEvent<()> = serde_json::from_str(exp).unwrap();
assert_eq!(event_dec, event);
}
#[test]
fn dropped_event() {
let event: TransactionEvent<()> =
TransactionEvent::Dropped(TransactionDropped { error: "abc".to_string() });
let ser = serde_json::to_string(&event).unwrap();
let exp = r#"{"event":"dropped","error":"abc"}"#;
assert_eq!(ser, exp);
let event_dec: TransactionEvent<()> = serde_json::from_str(exp).unwrap();
assert_eq!(event_dec, event);
}
}