use crate::pack_bridge::{ConversionError, IntoValue, Value};
use crate::replay::HostFunctionCall;
use serde::{Deserialize, Serialize};
use crate::chain::ChainEvent;
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "category")]
pub enum ChainEventPayload {
HostFunction(HostFunctionCall),
Wasm(wasm::WasmEventData),
ReplaySummary(replay::ReplaySummary),
}
impl From<HostFunctionCall> for ChainEventPayload {
fn from(event: HostFunctionCall) -> Self {
ChainEventPayload::HostFunction(event)
}
}
impl From<wasm::WasmEventData> for ChainEventPayload {
fn from(event: wasm::WasmEventData) -> Self {
ChainEventPayload::Wasm(event)
}
}
impl From<replay::ReplaySummary> for ChainEventPayload {
fn from(event: replay::ReplaySummary) -> Self {
ChainEventPayload::ReplaySummary(event)
}
}
impl IntoValue for ChainEventPayload {
fn into_value(self) -> Value {
match self {
ChainEventPayload::HostFunction(call) => Value::Variant {
type_name: String::from("chain-event-payload"),
case_name: String::from("host-function"),
tag: 0,
payload: vec![call.into_value()],
},
ChainEventPayload::Wasm(data) => Value::Variant {
type_name: String::from("chain-event-payload"),
case_name: String::from("wasm"),
tag: 1,
payload: vec![data.into_value()],
},
ChainEventPayload::ReplaySummary(summary) => Value::Variant {
type_name: String::from("chain-event-payload"),
case_name: String::from("replay-summary"),
tag: 2,
payload: vec![summary.into_value()],
},
}
}
}
impl TryFrom<Value> for ChainEventPayload {
type Error = ConversionError;
fn try_from(v: Value) -> Result<Self, Self::Error> {
match v {
Value::Variant {
case_name, payload, ..
} => {
let inner = payload
.into_iter()
.next()
.ok_or_else(|| ConversionError::MissingField("payload".into()))?;
match case_name.as_str() {
"host-function" => Ok(ChainEventPayload::HostFunction(
HostFunctionCall::try_from(inner)?,
)),
"wasm" => Ok(ChainEventPayload::Wasm(wasm::WasmEventData::try_from(
inner,
)?)),
"replay-summary" => Ok(ChainEventPayload::ReplaySummary(
replay::ReplaySummary::try_from(inner)?,
)),
other => Err(ConversionError::ExpectedVariant(format!(
"unknown chain-event-payload case: {other}"
))),
}
}
other => Err(ConversionError::ExpectedVariant(format!("{:?}", other))),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ChainEventData {
pub event_type: String,
pub data: ChainEventPayload,
}
impl ChainEventData {
#[allow(dead_code)]
pub fn event_type(&self) -> String {
self.event_type.clone()
}
#[allow(dead_code)]
pub fn to_json(&self) -> Result<Vec<u8>, serde_json::Error> {
serde_json::to_vec(self)
}
pub fn to_chain_event(&self, parent_hash: Option<Vec<u8>>) -> ChainEvent {
let encoded_data =
packr::abi::encode(&self.data.clone().into_value()).unwrap_or_else(|_| vec![]);
ChainEvent {
parent_hash,
hash: vec![],
event_type: self.event_type.clone(),
data: encoded_data,
}
}
}
pub fn decode_chain_event_payload(data: &[u8]) -> Option<ChainEventPayload> {
let value = packr::abi::decode(data).ok()?;
ChainEventPayload::try_from(value).ok()
}
pub fn decode_host_function_call(data: &[u8]) -> Option<HostFunctionCall> {
let payload = decode_chain_event_payload(data)?;
match payload {
ChainEventPayload::HostFunction(call) => Some(call),
_ => None,
}
}
pub mod replay;
pub mod runtime;
pub mod theater_runtime;
pub mod wasm;