use alloc::vec::Vec;
use gear_core_errors::ReplyCode;
use gprimitives::H256;
use parity_scale_codec::{Decode, Encode};
use scale_decode::DecodeAsType;
use scale_encode::EncodeAsType;
use scale_info::TypeInfo;
use crate::message::UserMessage;
#[derive(
Clone, Debug, Default, PartialEq, Eq, Encode, EncodeAsType, Decode, DecodeAsType, TypeInfo,
)]
#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
pub struct GasInfo {
pub min_limit: u64,
pub reserved: u64,
pub burned: u64,
pub may_be_returned: u64,
pub waited: bool,
}
#[derive(
Clone, Debug, PartialEq, Eq, Encode, EncodeAsType, Decode, DecodeAsType, TypeInfo, Hash,
)]
#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
pub struct ReplyInfo {
#[cfg_attr(feature = "std", serde(with = "impl_serde::serialize"))]
pub payload: Vec<u8>,
pub value: u128,
#[cfg_attr(feature = "std", serde(with = "serialize_reply_code"))]
pub code: ReplyCode,
}
#[derive(
Clone, Debug, PartialEq, Eq, Encode, EncodeAsType, Decode, DecodeAsType, TypeInfo, Hash,
)]
#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
pub struct CalculateReplyForHandleResult {
pub reply: ReplyInfo,
pub messages: Vec<UserMessage>,
}
impl ReplyInfo {
pub fn to_hash(&self) -> H256 {
let ReplyInfo {
payload,
value,
code,
} = self;
let bytes = [
payload.as_ref(),
value.to_be_bytes().as_ref(),
code.to_bytes().as_ref(),
]
.concat();
super::utils::hash(&bytes).into()
}
}
#[cfg(feature = "std")]
pub(crate) mod serialize_reply_code {
use super::ReplyCode;
use core::fmt::Write;
use serde::de;
pub fn serialize<S>(code: &ReplyCode, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let mut s = alloc::string::String::with_capacity(10);
s.push_str("0x");
for byte in code.to_bytes() {
write!(&mut s, "{:02x}", byte).unwrap();
}
serializer.serialize_str(&s)
}
pub fn deserialize<'de, D>(deserializer: D) -> Result<ReplyCode, D::Error>
where
D: serde::Deserializer<'de>,
{
struct Visitor;
impl<'b> de::Visitor<'b> for Visitor {
type Value = ReplyCode;
fn expecting(&self, formatter: &mut alloc::fmt::Formatter) -> alloc::fmt::Result {
formatter.write_str("a 0x-prefixed hex string representing a 4-byte ReplyCode")
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: de::Error,
{
let v = v.strip_prefix("0x").ok_or_else(|| {
E::custom("invalid format: expected a 0x-prefixed hex string")
})?;
let mut bytes = [0u8; 4];
hex::decode_to_slice(v, &mut bytes)
.map_err(|e| E::custom(alloc::format!("invalid hex string: {e}")))?;
Ok(ReplyCode::from_bytes(bytes))
}
}
deserializer.deserialize_str(Visitor)
}
}
#[derive(
Clone,
Copy,
Debug,
Default,
PartialEq,
Eq,
Encode,
EncodeAsType,
Decode,
DecodeAsType,
TypeInfo,
derive_more::From,
derive_more::Into,
)]
pub struct RpcValue(pub u128);
#[cfg(feature = "std")]
impl<'de> serde::Deserialize<'de> for RpcValue {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
use alloc::format;
use core::fmt;
use serde::de::{self, Visitor};
struct RpcValueVisitor;
impl<'de> Visitor<'de> for RpcValueVisitor {
type Value = RpcValue;
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("a numeric literal, a 0x-prefixed string with big-endian bytes, or a numeric string representing a u128; for large integer literals, consider using string options for clarity and to avoid potential parsing issues")
}
fn visit_u128<E>(self, v: u128) -> Result<Self::Value, E> {
Ok(RpcValue(v))
}
fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E> {
Ok(RpcValue(v as u128))
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: de::Error,
{
if let Some(hex) = v.strip_prefix("0x") {
let bytes = hex::decode(hex)
.map_err(|e| E::custom(format!("invalid hex string: {e}")))?;
if bytes.len() > 16 {
return Err(E::custom("invalid hex string: too long for u128"));
}
let mut padded = [0u8; 16];
padded[16 - bytes.len()..].copy_from_slice(&bytes);
Ok(RpcValue(u128::from_be_bytes(padded)))
} else {
v.parse::<u128>()
.map(RpcValue)
.map_err(|e| E::custom(format!("invalid numeric string: {e}")))
}
}
}
deserializer.deserialize_any(RpcValueVisitor)
}
}