use crate::{abi, error::Error, host::StateMachine, module::IsmpModule, prelude::Vec};
use alloc::{boxed::Box, string::ToString};
use codec::{Decode, DecodeWithMemTracking, Encode};
use core::{fmt::Formatter, time::Duration};
#[derive(
Debug,
Clone,
Encode,
Decode,
DecodeWithMemTracking,
PartialEq,
Eq,
scale_info::TypeInfo,
serde::Deserialize,
serde::Serialize,
)]
pub struct PostRequest {
#[serde(with = "serde_hex_utils::as_string")]
pub source: StateMachine,
#[serde(with = "serde_hex_utils::as_string")]
pub dest: StateMachine,
pub nonce: u64,
#[serde(with = "serde_hex_utils::as_hex")]
pub from: Vec<u8>,
#[serde(with = "serde_hex_utils::as_hex")]
pub to: Vec<u8>,
#[serde(rename = "timeoutTimestamp")]
pub timeout_timestamp: u64,
#[serde(with = "serde_hex_utils::as_hex")]
pub body: Vec<u8>,
}
impl PostRequest {
pub fn timeout(&self) -> Duration {
get_timeout(self.timeout_timestamp)
}
pub fn timed_out(&self, proof_timestamp: Duration) -> bool {
proof_timestamp >= self.timeout()
}
}
impl core::fmt::Display for PostRequest {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
writeln!(f, "Post {{")?;
writeln!(f, " source: {:?}", self.source)?;
writeln!(f, " dest: {:?}", self.dest)?;
writeln!(f, " nonce: {}", self.nonce)?;
writeln!(f, " from: {}", hex::encode(&self.from))?;
writeln!(f, " to: {}", hex::encode(&self.to))?;
writeln!(f, " timeout_timestamp: {}", self.timeout_timestamp)?;
writeln!(f, " data: {}", hex::encode(&self.body))?;
writeln!(f, "}}")?;
Ok(())
}
}
#[derive(
Debug,
Clone,
Encode,
Decode,
DecodeWithMemTracking,
PartialEq,
Eq,
PartialOrd,
Ord,
scale_info::TypeInfo,
serde::Deserialize,
serde::Serialize,
)]
pub struct GetRequest {
#[serde(with = "serde_hex_utils::as_string")]
pub source: StateMachine,
#[serde(with = "serde_hex_utils::as_string")]
pub dest: StateMachine,
pub nonce: u64,
#[serde(with = "serde_hex_utils::as_hex")]
pub from: Vec<u8>,
#[serde(with = "serde_hex_utils::seq_of_hex")]
pub keys: Vec<Vec<u8>>,
pub height: u64,
#[serde(with = "serde_hex_utils::as_hex")]
pub context: Vec<u8>,
#[serde(rename = "timeoutTimestamp")]
pub timeout_timestamp: u64,
}
impl GetRequest {
pub fn timeout(&self) -> Duration {
get_timeout(self.timeout_timestamp)
}
pub fn timed_out(&self, proof_timestamp: Duration) -> bool {
proof_timestamp >= self.timeout()
}
}
fn get_timeout(timeout_timestamp: u64) -> Duration {
if timeout_timestamp == 0 {
Duration::from_secs(u64::MAX)
} else {
Duration::from_secs(timeout_timestamp)
}
}
#[derive(
Debug,
Clone,
Encode,
Decode,
DecodeWithMemTracking,
PartialEq,
Eq,
scale_info::TypeInfo,
derive_more::From,
serde::Deserialize,
serde::Serialize,
)]
pub enum Request {
Post(PostRequest),
Get(GetRequest),
}
impl Request {
pub fn source_chain(&self) -> StateMachine {
match self {
Request::Get(get) => get.source,
Request::Post(post) => post.source,
}
}
pub fn source_module(&self) -> Vec<u8> {
match self {
Request::Get(get) => get.from.clone(),
Request::Post(post) => post.from.clone(),
}
}
pub fn destination_module(&self) -> Vec<u8> {
match self {
Request::Get(get) => get.from.clone(),
Request::Post(post) => post.to.clone(),
}
}
pub fn dest_chain(&self) -> StateMachine {
match self {
Request::Get(get) => get.dest,
Request::Post(post) => post.dest,
}
}
pub fn nonce(&self) -> u64 {
match self {
Request::Get(get) => get.nonce,
Request::Post(post) => post.nonce,
}
}
pub fn body(&self) -> Option<Vec<u8>> {
match self {
Request::Get(_) => None,
Request::Post(post) => Some(post.body.clone()),
}
}
pub fn keys(&self) -> Option<Vec<Vec<u8>>> {
match self {
Request::Post(_) => None,
Request::Get(get) => Some(get.keys.clone()),
}
}
pub fn timeout(&self) -> Duration {
let timeout = match self {
Request::Post(post) => post.timeout_timestamp,
Request::Get(get) => get.timeout_timestamp,
};
get_timeout(timeout)
}
pub fn timed_out(&self, proof_timestamp: Duration) -> bool {
proof_timestamp >= self.timeout()
}
pub fn get_request(&self) -> Result<GetRequest, Error> {
match self {
Request::Post(_) => Err(Error::Custom("Expected Get request".to_string())),
Request::Get(get) => Ok(get.clone()),
}
}
pub fn encode(&self) -> Vec<u8> {
abi::encode_request(self)
}
}
#[derive(
Debug,
Clone,
Encode,
Decode,
DecodeWithMemTracking,
PartialEq,
Eq,
scale_info::TypeInfo,
serde::Deserialize,
serde::Serialize,
)]
pub struct GetResponse {
pub get: GetRequest,
pub values: Vec<StorageValue>,
}
impl GetResponse {
pub fn encode(&self) -> Vec<u8> {
abi::encode_get_response(self)
}
pub fn request(&self) -> Request {
Request::Get(self.get.clone())
}
pub fn destination_module(&self) -> Vec<u8> {
self.get.from.clone()
}
pub fn source_chain(&self) -> StateMachine {
self.get.dest
}
pub fn dest_chain(&self) -> StateMachine {
self.get.source
}
pub fn nonce(&self) -> u64 {
self.get.nonce
}
pub fn timed_out(&self, proof_timestamp: Duration) -> bool {
proof_timestamp >= self.get.timeout()
}
}
#[derive(
Debug,
Clone,
Encode,
Decode,
DecodeWithMemTracking,
PartialEq,
Eq,
scale_info::TypeInfo,
serde::Deserialize,
serde::Serialize,
)]
pub struct StorageValue {
#[serde(with = "serde_hex_utils::as_hex")]
pub key: Vec<u8>,
#[serde(serialize_with = "serde_hex_utils::as_hex::serialize_option")]
#[serde(deserialize_with = "serde_hex_utils::as_hex::deserialize_option")]
pub value: Option<Vec<u8>>,
}
pub trait IsmpRouter {
fn module_for_id(&self, bytes: Vec<u8>) -> Result<Box<dyn IsmpModule>, anyhow::Error>;
}