From 677d06a22d555025c3e257d09063d5947ce367cf Mon Sep 17 00:00:00 2001 From: t00ts Date: Tue, 7 Jan 2025 13:43:09 +0400 Subject: [PATCH] feat(rpc): remove `SerializationForVersion ` blanket implementation for serde --- crates/common/src/lib.rs | 8 + crates/common/src/macros.rs | 1 + crates/executor/src/types.rs | 4 +- crates/rpc/src/dto.rs | 55 +- crates/rpc/src/dto/class.rs | 49 +- crates/rpc/src/dto/event.rs | 6 +- crates/rpc/src/dto/primitives.rs | 810 ++++++++++++++---- crates/rpc/src/dto/receipt.rs | 8 +- crates/rpc/src/dto/simulation.rs | 19 +- crates/rpc/src/dto/transaction.rs | 6 - crates/rpc/src/jsonrpc/error.rs | 2 +- crates/rpc/src/jsonrpc/response.rs | 4 +- crates/rpc/src/jsonrpc/router.rs | 12 +- crates/rpc/src/jsonrpc/websocket/data.rs | 141 ++- crates/rpc/src/lib.rs | 11 +- .../rpc/src/method/add_declare_transaction.rs | 7 +- .../method/add_deploy_account_transaction.rs | 10 +- .../rpc/src/method/add_invoke_transaction.rs | 5 +- .../rpc/src/method/block_hash_and_number.rs | 4 +- crates/rpc/src/method/block_number.rs | 2 +- crates/rpc/src/method/call.rs | 5 +- crates/rpc/src/method/chain_id.rs | 2 +- crates/rpc/src/method/estimate_fee.rs | 5 +- crates/rpc/src/method/estimate_message_fee.rs | 2 +- .../rpc/src/method/get_block_with_receipts.rs | 7 +- .../src/method/get_block_with_tx_hashes.rs | 8 +- crates/rpc/src/method/get_block_with_txs.rs | 8 +- crates/rpc/src/method/get_class.rs | 6 +- crates/rpc/src/method/get_class_at.rs | 11 +- crates/rpc/src/method/get_class_hash_at.rs | 2 +- crates/rpc/src/method/get_compiled_casm.rs | 8 +- crates/rpc/src/method/get_events.rs | 11 +- crates/rpc/src/method/get_nonce.rs | 2 +- crates/rpc/src/method/get_storage_at.rs | 2 +- .../rpc/src/method/simulate_transactions.rs | 12 +- crates/rpc/src/method/subscribe_new_heads.rs | 2 +- crates/rpc/src/method/syncing.rs | 2 +- .../src/method/trace_block_transactions.rs | 5 +- .../rpc/src/pathfinder/methods/get_proof.rs | 78 ++ crates/rpc/src/types.rs | 55 +- crates/rpc/src/types/class.rs | 6 +- crates/rpc/src/types/syncing.rs | 20 +- crates/rpc/src/types/transaction.rs | 45 + crates/rpc/src/v07/dto/header.rs | 100 ++- crates/rpc/src/v07/dto/receipt.rs | 8 +- 45 files changed, 1182 insertions(+), 394 deletions(-) diff --git a/crates/common/src/lib.rs b/crates/common/src/lib.rs index 9a39d03860..bfa8da74cb 100644 --- a/crates/common/src/lib.rs +++ b/crates/common/src/lib.rs @@ -169,6 +169,10 @@ macros::i64_backed_u64::serdes!(TransactionIndex); #[derive(Debug, Copy, Clone, PartialEq, Eq, Deserialize, Serialize, Default, Dummy)] pub struct GasPrice(pub u128); +/// A hex representation of a [GasPrice]. +#[derive(Debug, Copy, Clone, PartialEq, Eq, Deserialize, Serialize, Default, Dummy)] +pub struct GasPriceHex(pub GasPrice); + /// Starknet resource bound: amount. #[derive(Debug, Copy, Clone, PartialEq, Eq, Deserialize, Serialize, Default, Dummy)] pub struct ResourceAmount(pub u64); @@ -178,6 +182,10 @@ pub struct ResourceAmount(pub u64); #[derive(Debug, Copy, Clone, PartialEq, Eq, Deserialize, Serialize, Default, Dummy)] pub struct Tip(pub u64); +// A hex representation of a [Tip]. +#[derive(Debug, Copy, Clone, PartialEq, Eq, Default, Dummy)] +pub struct TipHex(pub Tip); + /// Starknet resource bound: price per unit. #[derive(Debug, Copy, Clone, PartialEq, Eq, Deserialize, Serialize, Default, Dummy)] pub struct ResourcePricePerUnit(pub u128); diff --git a/crates/common/src/macros.rs b/crates/common/src/macros.rs index 8d59215ae0..987bcc24d0 100644 --- a/crates/common/src/macros.rs +++ b/crates/common/src/macros.rs @@ -292,6 +292,7 @@ macro_rules! felt { ($hex:expr) => {{ // This forces const evaluation of the macro call. Without this the invocation // will only be evaluated at runtime. + use ::pathfinder_crypto; const CONST_FELT: pathfinder_crypto::Felt = match pathfinder_crypto::Felt::from_hex_str($hex) { Ok(f) => f, diff --git a/crates/executor/src/types.rs b/crates/executor/src/types.rs index 1ee655bf56..430292709e 100644 --- a/crates/executor/src/types.rs +++ b/crates/executor/src/types.rs @@ -16,7 +16,7 @@ use pathfinder_crypto::Felt; use super::felt::IntoFelt; -#[derive(Debug, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq)] pub struct FeeEstimate { pub l1_gas_consumed: primitive_types::U256, pub l1_gas_price: primitive_types::U256, @@ -85,7 +85,7 @@ impl FeeEstimate { } } -#[derive(Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq)] pub enum PriceUnit { Wei, Fri, diff --git a/crates/rpc/src/dto.rs b/crates/rpc/src/dto.rs index d29d092a67..bdd08b3ba8 100644 --- a/crates/rpc/src/dto.rs +++ b/crates/rpc/src/dto.rs @@ -43,14 +43,15 @@ pub trait SerializeForVersion { fn serialize(&self, serializer: Serializer) -> Result; } -// This blanket implementation should be removed once all existing DTOs have -// been migrated. -impl SerializeForVersion for T -where - T: serde::Serialize, -{ +impl SerializeForVersion for serde_json::Value { fn serialize(&self, _serializer: Serializer) -> Result { - self.serialize(BaseSerializer {}) + Ok(self.clone()) + } +} + +impl SerializeForVersion for &serde_json::Value { + fn serialize(&self, _serializer: Serializer) -> Result { + Ok((*self).clone()) } } @@ -63,16 +64,41 @@ impl Serializer { value.serialize(self) } + pub fn serialize_unit(self) -> Result { + use serde::Serializer; + BaseSerializer {}.serialize_unit() + } + pub fn serialize_str(self, value: &str) -> Result { use serde::Serializer; BaseSerializer {}.serialize_str(value) } + pub fn serialize_i32(self, value: i32) -> Result { + use serde::Serializer; + BaseSerializer {}.serialize_i32(value) + } + + pub fn serialize_i64(self, value: i64) -> Result { + use serde::Serializer; + BaseSerializer {}.serialize_i64(value) + } + + pub fn serialize_u32(self, value: u32) -> Result { + use serde::Serializer; + BaseSerializer {}.serialize_u32(value) + } + pub fn serialize_u64(self, value: u64) -> Result { use serde::Serializer; BaseSerializer {}.serialize_u64(value) } + pub fn serialize_u128(self, value: u128) -> Result { + use serde::Serializer; + BaseSerializer {}.serialize_u128(value) + } + pub fn serialize_bool(self, value: bool) -> Result { use serde::Serializer; BaseSerializer {}.serialize_bool(value) @@ -136,6 +162,21 @@ impl SerializeStruct { Ok(()) } + /// Serializes optional value as null if its [`None`]. + pub fn serialize_optional_with_null( + &mut self, + key: &'static str, + value: Option, + ) -> Result<(), Error> { + if let Some(value) = value { + self.serialize_field(key, &value)?; + } else { + self.serialize_field(key, &serde_json::Value::Null)?; + } + + Ok(()) + } + pub fn flatten(&mut self, value: &dyn SerializeForVersion) -> Result<(), Error> { let value = value.serialize(Serializer::new(self.version))?; diff --git a/crates/rpc/src/dto/class.rs b/crates/rpc/src/dto/class.rs index 1c9311e1b1..58c9d9b2a1 100644 --- a/crates/rpc/src/dto/class.rs +++ b/crates/rpc/src/dto/class.rs @@ -42,7 +42,7 @@ impl SerializeForVersion for types::CairoContractClass { serializer.serialize_field("program", &self.program)?; serializer.serialize_field("entry_points_by_type", &self.entry_points_by_type)?; - serializer.serialize_optional("abi", self.abi)?; + serializer.serialize_optional_with_null("abi", self.abi.clone())?; serializer.end() } @@ -95,13 +95,13 @@ impl SerializeForVersion for types::SierraContractClass { // ABI is optional, so skip if its empty. let abi = (!self.abi.is_empty()).then_some(&self.abi); - serializer.serialize_optional("abi", abi)?; + serializer.serialize_optional_with_null("abi", abi)?; serializer.end() } } -impl SerializeForVersion for types::ContractEntryPoint { +impl SerializeForVersion for &types::ContractEntryPoint { fn serialize( &self, serializer: crate::dto::Serializer, @@ -115,7 +115,7 @@ impl SerializeForVersion for types::ContractEntryPoint { } } -impl SerializeForVersion for types::SierraEntryPoint { +impl SerializeForVersion for &types::SierraEntryPoint { fn serialize( &self, serializer: crate::dto::Serializer, @@ -138,7 +138,16 @@ impl SerializeForVersion for [types::ContractAbiEntry] { } } -impl SerializeForVersion for types::ContractAbiEntry { +impl SerializeForVersion for Vec { + fn serialize( + &self, + serializer: crate::dto::Serializer, + ) -> Result { + serializer.serialize_iter(self.len(), &mut self.iter()) + } +} + +impl SerializeForVersion for &types::ContractAbiEntry { fn serialize( &self, serializer: crate::dto::Serializer, @@ -151,7 +160,7 @@ impl SerializeForVersion for types::ContractAbiEntry { } } -impl SerializeForVersion for types::FunctionAbiEntry { +impl SerializeForVersion for &types::FunctionAbiEntry { fn serialize( &self, serializer: crate::dto::Serializer, @@ -178,7 +187,7 @@ impl SerializeForVersion for types::FunctionAbiEntry { } } -impl SerializeForVersion for types::EventAbiEntry { +impl SerializeForVersion for &types::EventAbiEntry { fn serialize( &self, serializer: crate::dto::Serializer, @@ -198,7 +207,7 @@ impl SerializeForVersion for types::EventAbiEntry { } } -impl SerializeForVersion for types::StructAbiEntry { +impl SerializeForVersion for &types::StructAbiEntry { fn serialize( &self, serializer: crate::dto::Serializer, @@ -263,35 +272,35 @@ impl SerializeForVersion for FunctionStateMutability { } } -impl SerializeForVersion for types::TypedParameter { +impl SerializeForVersion for &types::StructMember { fn serialize( &self, serializer: crate::dto::Serializer, ) -> Result { let mut serializer = serializer.serialize_struct()?; - serializer.serialize_field("name", &self.name)?; - serializer.serialize_field("type", &self.r#type)?; + // FIXME: these clones could be removed if the types::* definitions were + // smarter. + let parameter = &types::TypedParameter { + name: self.typed_parameter_name.clone(), + r#type: self.typed_parameter_type.clone(), + }; + serializer.flatten(¶meter)?; + serializer.serialize_field("offset", &self.offset)?; serializer.end() } } -impl SerializeForVersion for types::StructMember { +impl SerializeForVersion for &types::TypedParameter { fn serialize( &self, serializer: crate::dto::Serializer, ) -> Result { let mut serializer = serializer.serialize_struct()?; - // FIXME: these clones could be removed if the types::* definitions were - // smarter. - let parameter = types::TypedParameter { - name: self.typed_parameter_name.clone(), - r#type: self.typed_parameter_type.clone(), - }; - serializer.flatten(¶meter)?; - serializer.serialize_field("offset", &self.offset)?; + serializer.serialize_field("name", &self.name)?; + serializer.serialize_field("type", &self.r#type)?; serializer.end() } diff --git a/crates/rpc/src/dto/event.rs b/crates/rpc/src/dto/event.rs index 24ff581fc4..ba9478ad58 100644 --- a/crates/rpc/src/dto/event.rs +++ b/crates/rpc/src/dto/event.rs @@ -18,7 +18,7 @@ impl SerializeForVersion for Event<'_> { fn serialize(&self, serializer: Serializer) -> Result { let mut serializer = serializer.serialize_struct()?; - serializer.serialize_field("from_address", &self.address)?; + serializer.serialize_field("from_address", self.address)?; serializer.flatten(&EventContext { keys: self.keys, data: self.data, @@ -32,8 +32,8 @@ impl SerializeForVersion for EventContext<'_> { fn serialize(&self, serializer: Serializer) -> Result { let mut serializer = serializer.serialize_struct()?; - serializer.serialize_iter("keys", self.keys.len(), &mut self.keys.iter().map(|x| &x.0))?; - serializer.serialize_iter("data", self.data.len(), &mut self.data.iter().map(|x| &x.0))?; + serializer.serialize_iter("keys", self.keys.len(), &mut self.keys.iter().map(|x| x.0))?; + serializer.serialize_iter("data", self.data.len(), &mut self.data.iter().map(|x| x.0))?; serializer.end() } diff --git a/crates/rpc/src/dto/primitives.rs b/crates/rpc/src/dto/primitives.rs index 2fe8c44533..90867d372b 100644 --- a/crates/rpc/src/dto/primitives.rs +++ b/crates/rpc/src/dto/primitives.rs @@ -1,30 +1,9 @@ -use pathfinder_common::{ContractAddress, L1TransactionHash}; -use primitive_types::{H160, H256}; -use serde::de::Error; - -use super::{DeserializeForVersion, SerializeForVersion, Value}; -use crate::dto::{self, Serializer}; - -pub struct SyncStatus<'a>(pub &'a crate::types::syncing::Status); - -pub struct BlockHash<'a>(pub &'a pathfinder_common::BlockHash); -pub struct ChainId<'a>(pub &'a pathfinder_common::ChainId); -pub struct BlockNumber(pub pathfinder_common::BlockNumber); - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct U64Hex(pub u64); - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct U128Hex(pub u128); - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct H256Hex(pub primitive_types::H256); - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct U256Hex(pub primitive_types::U256); - -pub struct Address<'a>(pub &'a ContractAddress); -pub struct EthAddress<'a>(pub &'a pathfinder_common::EthereumAddress); +pub use boolean::*; +pub use numerics::*; +pub use pathfinder_common_types::*; +pub use pathfinder_crypto::*; +pub use pathfinder_primitives::*; +pub use strings::*; pub mod hex_str { use std::borrow::Cow; @@ -150,231 +129,699 @@ pub mod hex_str { Ok(buf) } } -impl DeserializeForVersion for u64 { - fn deserialize(value: Value) -> Result { - match &value.data { - serde_json::Value::Number(n) => n - .as_u64() - .ok_or_else(|| serde_json::Error::custom("invalid u64 value")), - _ => Err(serde_json::Error::custom("expected number")), + +mod boolean { + use serde::de::Error; + + use crate::dto::{self, DeserializeForVersion, SerializeForVersion, Serializer, Value}; + + impl SerializeForVersion for bool { + fn serialize(&self, serializer: Serializer) -> Result { + serializer.serialize_bool(*self) } } -} -impl DeserializeForVersion for u32 { - fn deserialize(value: Value) -> Result { - match &value.data { - serde_json::Value::Number(n) => n - .as_u64() - .and_then(|n| u32::try_from(n).ok()) - .ok_or_else(|| serde_json::Error::custom("value is too large for u32")), - _ => Err(serde_json::Error::custom("expected number")), + impl DeserializeForVersion for bool { + fn deserialize(value: Value) -> Result { + match &value.data { + serde_json::Value::Bool(b) => Ok(*b), + _ => Err(serde_json::Error::custom("expected boolean")), + } } } } -impl DeserializeForVersion for i32 { - fn deserialize(value: Value) -> Result { - match &value.data { - serde_json::Value::Number(n) => n - .as_i64() - .and_then(|n| i32::try_from(n).ok()) - .ok_or_else(|| serde_json::Error::custom("value is outside i32 range")), - _ => Err(serde_json::Error::custom("expected number")), +mod numerics { + use std::num::NonZeroU64; + + use serde::de::Error; + + use crate::dto::{self, DeserializeForVersion, SerializeForVersion, Serializer, Value}; + + impl SerializeForVersion for u128 { + fn serialize(&self, serializer: Serializer) -> Result { + serializer.serialize_u128(*self) } } -} -impl DeserializeForVersion for usize { - fn deserialize(value: Value) -> Result { - match &value.data { - serde_json::Value::Number(n) => n - .as_u64() - .and_then(|n| usize::try_from(n).ok()) - .ok_or_else(|| serde_json::Error::custom("value is outside usize range")), - _ => Err(serde_json::Error::custom("expected number")), + impl SerializeForVersion for u64 { + fn serialize(&self, serializer: Serializer) -> Result { + serializer.serialize_u64(*self) } } -} -impl DeserializeForVersion for bool { - fn deserialize(value: Value) -> Result { - match &value.data { - serde_json::Value::Bool(b) => Ok(*b), - _ => Err(serde_json::Error::custom("expected boolean")), + impl SerializeForVersion for &u64 { + fn serialize(&self, serializer: Serializer) -> Result { + serializer.serialize_u64(**self) + } + } + + impl DeserializeForVersion for u64 { + fn deserialize(value: Value) -> Result { + match &value.data { + serde_json::Value::Number(n) => n + .as_u64() + .ok_or_else(|| serde_json::Error::custom("invalid u64 value")), + _ => Err(serde_json::Error::custom("expected number")), + } } } -} -impl DeserializeForVersion for String { - fn deserialize(value: Value) -> Result { - match &value.data { - serde_json::Value::String(s) => Ok(s.clone()), - _ => Err(serde_json::Error::custom("expected string")), + impl SerializeForVersion for u32 { + fn serialize(&self, serializer: Serializer) -> Result { + serializer.serialize_u32(*self) } } -} -impl DeserializeForVersion for U64Hex { - fn deserialize(value: Value) -> Result { - match &value.data { - serde_json::Value::String(s) => { - let bytes = hex_str::bytes_from_hex_str_stripped::<8>(s).map_err(|e| { - serde_json::Error::custom(format!("failed to parse hex string as u64: {}", e)) - })?; - Ok(Self(u64::from_be_bytes(bytes))) + impl DeserializeForVersion for u32 { + fn deserialize(value: Value) -> Result { + match &value.data { + serde_json::Value::Number(n) => n + .as_u64() + .and_then(|n| u32::try_from(n).ok()) + .ok_or_else(|| serde_json::Error::custom("value is too large for u32")), + _ => Err(serde_json::Error::custom("expected number")), } - _ => Err(serde_json::Error::custom("expected hex string")), } } -} -impl SerializeForVersion for crate::types::syncing::Status { - fn serialize(&self, serializer: Serializer) -> Result { - let mut serializer = serializer.serialize_struct()?; - serializer.serialize_field("starting_block_hash", &self.starting.hash)?; - serializer.serialize_field("starting_block_num", &self.starting.number)?; - serializer.serialize_field("current_block_hash", &self.current.hash)?; - serializer.serialize_field("current_block_num", &self.current.number)?; - serializer.serialize_field("highest_block_hash", &self.highest.hash)?; - serializer.serialize_field("highest_block_num", &self.highest.number)?; - serializer.end() + impl SerializeForVersion for i64 { + fn serialize(&self, serializer: Serializer) -> Result { + serializer.serialize_i64(*self) + } } -} -impl SerializeForVersion for pathfinder_crypto::Felt { - fn serialize(&self, serializer: Serializer) -> Result { - let hex_str = hex_str::bytes_to_hex_str_stripped(self.as_be_bytes()); - serializer.serialize_str(&hex_str) + impl SerializeForVersion for i32 { + fn serialize(&self, serializer: Serializer) -> Result { + serializer.serialize_i32(*self) + } } -} -impl DeserializeForVersion for pathfinder_crypto::Felt { - fn deserialize(value: Value) -> Result { - match &value.data { - serde_json::Value::String(hex_str) => { - let bytes = hex_str::bytes_from_hex_str_stripped::<32>(hex_str).map_err(|e| { - serde_json::Error::custom(format!("failed to parse hex string: {}", e)) - })?; - Self::from_be_bytes(bytes).map_err(|_| serde_json::Error::custom("felt overflow")) + impl DeserializeForVersion for i32 { + fn deserialize(value: Value) -> Result { + match &value.data { + serde_json::Value::Number(n) => n + .as_i64() + .and_then(|n| i32::try_from(n).ok()) + .ok_or_else(|| serde_json::Error::custom("value is outside i32 range")), + _ => Err(serde_json::Error::custom("expected number")), } - _ => Err(serde_json::Error::custom("expected hex string")), } } -} -impl SerializeForVersion for pathfinder_common::BlockHash { - fn serialize(&self, serializer: Serializer) -> Result { - serializer.serialize(&self.0) + impl SerializeForVersion for usize { + fn serialize(&self, serializer: Serializer) -> Result { + serializer.serialize_u64(*self as u64) + } } -} -impl SerializeForVersion for pathfinder_common::ChainId { - fn serialize(&self, serializer: Serializer) -> Result { - let hex_str = hex_str::bytes_to_hex_str_stripped(self.0.as_be_bytes()); - serializer.serialize_str(&hex_str) + impl DeserializeForVersion for usize { + fn deserialize(value: Value) -> Result { + match &value.data { + serde_json::Value::Number(n) => n + .as_u64() + .and_then(|n| usize::try_from(n).ok()) + .ok_or_else(|| serde_json::Error::custom("value is outside usize range")), + _ => Err(serde_json::Error::custom("expected number")), + } + } } -} -impl SerializeForVersion for BlockNumber { - fn serialize(&self, serializer: Serializer) -> Result { - serializer.serialize_u64(self.0.get()) + impl SerializeForVersion for NonZeroU64 { + fn serialize(&self, serializer: Serializer) -> Result { + serializer.serialize_u64(self.get()) + } } } -impl SerializeForVersion for U64Hex { - fn serialize(&self, serializer: Serializer) -> Result { - serializer.serialize_str(&hex_str::bytes_to_hex_str_stripped(&self.0.to_be_bytes())) +mod strings { + use serde::de::Error; + + use crate::dto::{self, DeserializeForVersion, SerializeForVersion, Serializer, Value}; + + impl SerializeForVersion for String { + fn serialize(&self, serializer: Serializer) -> Result { + serializer.serialize_str(self) + } } -} -impl SerializeForVersion for U128Hex { - fn serialize(&self, serializer: Serializer) -> Result { - serializer.serialize_str(&hex_str::bytes_to_hex_str_stripped(&self.0.to_be_bytes())) + impl SerializeForVersion for &String { + fn serialize(&self, serializer: Serializer) -> Result { + serializer.serialize_str(self) + } } -} -impl DeserializeForVersion for U128Hex { - fn deserialize(value: Value) -> Result { - match &value.data { - serde_json::Value::String(s) => { - let bytes = hex_str::bytes_from_hex_str_stripped::<16>(s).map_err(|e| { - serde_json::Error::custom(format!("failed to parse hex string as u128: {}", e)) - })?; - Ok(Self(u128::from_be_bytes(bytes))) + impl DeserializeForVersion for String { + fn deserialize(value: Value) -> Result { + match &value.data { + serde_json::Value::String(s) => Ok(s.clone()), + _ => Err(serde_json::Error::custom("expected string")), } - _ => Err(serde_json::Error::custom("expected hex string")), } } -} -impl SerializeForVersion for H256Hex { - fn serialize(&self, serializer: Serializer) -> Result { - serializer.serialize_str(&hex_str::bytes_to_hex_str_stripped(self.0.as_bytes())) + impl SerializeForVersion for &str { + fn serialize(&self, serializer: Serializer) -> Result { + serializer.serialize_str(self) + } } } -impl SerializeForVersion for U256Hex { - fn serialize(&self, serializer: Serializer) -> Result { - serializer.serialize_str(&hex_str::bytes_to_hex_str_stripped(&<[u8; 32]>::from( - self.0, - ))) +mod pathfinder_primitives { + use primitive_types::H256; + use serde::de::Error; + + use super::hex_str; + use crate::dto::{self, DeserializeForVersion, SerializeForVersion, Serializer, Value}; + + #[derive(Clone, Debug, PartialEq, Eq)] + pub struct U64Hex(pub u64); + + #[derive(Clone, Debug, PartialEq, Eq)] + pub struct U128Hex(pub u128); + + #[derive(Clone, Debug, PartialEq, Eq)] + pub struct H256Hex(pub primitive_types::H256); + + #[derive(Clone, Debug, PartialEq, Eq)] + pub struct U256Hex(pub primitive_types::U256); + + impl SerializeForVersion for U64Hex { + fn serialize(&self, serializer: Serializer) -> Result { + serializer.serialize_str(&hex_str::bytes_to_hex_str_stripped(&self.0.to_be_bytes())) + } } -} -impl DeserializeForVersion for H256 { - fn deserialize(value: Value) -> Result { - match &value.data { - serde_json::Value::String(hex_str) => { - let bytes = hex_str::bytes_from_hex_str_stripped::<32>(hex_str).map_err(|e| { - serde_json::Error::custom(format!("failed to parse hex string as u256: {}", e)) - })?; - Ok(H256(bytes)) + impl DeserializeForVersion for U64Hex { + fn deserialize(value: Value) -> Result { + match &value.data { + serde_json::Value::String(s) => { + let s = s.strip_prefix("0x").unwrap_or(s); + u64::from_str_radix(s, 16).map(Self).map_err(|e| { + serde_json::Error::custom(format!("invalid hex value for u64: {}", e)) + }) + } + _ => Err(serde_json::Error::custom("expected hex string")), } - _ => Err(serde_json::Error::custom("expected hex string")), } } -} -impl DeserializeForVersion for pathfinder_common::EthereumAddress { - fn deserialize(value: Value) -> Result { - match &value.data { - serde_json::Value::String(hex_str) => { - let bytes = hex_str::bytes_from_hex_str_stripped::<20>(hex_str).map_err(|e| { - serde_json::Error::custom(format!( - "failed to parse hex string as ethereum address: {}", - e - )) - })?; - Ok(Self(H160::from(bytes))) + impl SerializeForVersion for U128Hex { + fn serialize(&self, serializer: Serializer) -> Result { + serializer.serialize_str(&hex_str::bytes_to_hex_str_stripped(&self.0.to_be_bytes())) + } + } + + impl DeserializeForVersion for U128Hex { + fn deserialize(value: Value) -> Result { + match &value.data { + serde_json::Value::String(s) => { + let bytes = hex_str::bytes_from_hex_str_stripped::<16>(s).map_err(|e| { + serde_json::Error::custom(format!( + "failed to parse hex string as u128: {}", + e + )) + })?; + Ok(Self(u128::from_be_bytes(bytes))) + } + _ => Err(serde_json::Error::custom("expected hex string")), + } + } + } + + impl SerializeForVersion for H256Hex { + fn serialize(&self, serializer: Serializer) -> Result { + serializer.serialize_str(&hex_str::bytes_to_hex_str_stripped(self.0.as_bytes())) + } + } + + impl SerializeForVersion for U256Hex { + fn serialize(&self, serializer: Serializer) -> Result { + serializer.serialize_str(&hex_str::bytes_to_hex_str_stripped(&<[u8; 32]>::from( + self.0, + ))) + } + } + + impl DeserializeForVersion for H256 { + fn deserialize(value: Value) -> Result { + match &value.data { + serde_json::Value::String(hex_str) => { + let bytes = + hex_str::bytes_from_hex_str_stripped::<32>(hex_str).map_err(|e| { + serde_json::Error::custom(format!( + "failed to parse hex string as u256: {}", + e + )) + })?; + Ok(H256(bytes)) + } + _ => Err(serde_json::Error::custom("expected hex string")), } - _ => Err(serde_json::Error::custom("expected hex string")), } } } -impl SerializeForVersion for pathfinder_common::ContractAddress { - fn serialize(&self, serializer: Serializer) -> Result { - serializer.serialize(&self.0) +mod pathfinder_crypto { + use serde::de::Error; + + use super::hex_str; + use crate::dto::{DeserializeForVersion, SerializeForVersion, Serializer, Value}; + + impl SerializeForVersion for pathfinder_crypto::Felt { + fn serialize(&self, serializer: Serializer) -> Result { + let hex_str = hex_str::bytes_to_hex_str_stripped(self.as_be_bytes()); + serializer.serialize_str(&hex_str) + } + } + + impl SerializeForVersion for &pathfinder_crypto::Felt { + fn serialize(&self, serializer: Serializer) -> Result { + let hex_str = hex_str::bytes_to_hex_str_stripped(self.as_be_bytes()); + serializer.serialize_str(&hex_str) + } + } + + impl DeserializeForVersion for pathfinder_crypto::Felt { + fn deserialize(value: Value) -> Result { + match &value.data { + serde_json::Value::String(hex_str) => { + let bytes = + hex_str::bytes_from_hex_str_stripped::<32>(hex_str).map_err(|e| { + serde_json::Error::custom(format!("failed to parse hex string: {}", e)) + })?; + Self::from_be_bytes(bytes) + .map_err(|_| serde_json::Error::custom("felt overflow")) + } + _ => Err(serde_json::Error::custom("expected hex string")), + } + } + } + + impl SerializeForVersion for crate::felt::RpcFelt { + fn serialize(&self, serializer: Serializer) -> Result { + // StarkHash has a leading "0x" and at most 64 digits + let mut buf = [0u8; 2 + 64]; + let s = self.0.as_hex_str(&mut buf); + serializer.serialize_str(s) + } + } + + impl DeserializeForVersion for crate::felt::RpcFelt { + fn deserialize(value: Value) -> Result { + match &value.data { + serde_json::Value::String(s) => { + // Enforce 0x prefix + match s.as_bytes() { + &[b'0', b'x', ..] => pathfinder_crypto::Felt::from_hex_str(s) + .map_err(serde_json::Error::custom) + .map(crate::felt::RpcFelt), + _missing_prefix => Err(serde_json::Error::custom("Missing '0x' prefix")), + } + } + _ => Err(serde_json::Error::custom("expected hex string")), + } + } + } + + impl SerializeForVersion for crate::felt::RpcFelt251 { + fn serialize(&self, serializer: Serializer) -> Result { + // Delegate to inner RpcFelt's serialization + self.0.serialize(serializer) + } + } + + impl DeserializeForVersion for crate::felt::RpcFelt251 { + fn deserialize(value: Value) -> Result { + let felt: crate::felt::RpcFelt = DeserializeForVersion::deserialize(value)?; + + if felt.0.has_more_than_251_bits() { + return Err(serde_json::Error::custom("Value exceeded 251 bits")); + } + + Ok(crate::felt::RpcFelt251(felt)) + } } } -impl SerializeForVersion for EthAddress<'_> { - fn serialize(&self, serializer: Serializer) -> Result { - let hex_str = hex_str::bytes_to_hex_str_full(self.0 .0.as_bytes()); - serializer.serialize_str(&hex_str) +mod pathfinder_common_types { + use pathfinder_serde::bytes_as_hex_str; + use primitive_types::H160; + use serde::de::Error; + + use super::hex_str; + use crate::dto::{self, DeserializeForVersion, SerializeForVersion, Serializer, Value}; + + impl SerializeForVersion for &pathfinder_common::AccountDeploymentDataElem { + fn serialize(&self, serializer: Serializer) -> Result { + serializer.serialize_str(&hex_str::bytes_to_hex_str_stripped(self.0.as_be_bytes())) + } + } + + impl SerializeForVersion for pathfinder_common::BlockNumber { + fn serialize(&self, serializer: Serializer) -> Result { + serializer.serialize_u64(self.get()) + } + } + + impl SerializeForVersion for pathfinder_common::BlockHash { + fn serialize(&self, serializer: Serializer) -> Result { + let hex_str = hex_str::bytes_to_hex_str_stripped(self.0.as_be_bytes()); + serializer.serialize_str(&hex_str) + } + } + + impl SerializeForVersion for pathfinder_common::BlockTimestamp { + fn serialize(&self, serializer: Serializer) -> Result { + serializer.serialize_u64(self.get()) + } + } + + impl SerializeForVersion for pathfinder_common::ChainId { + fn serialize(&self, serializer: Serializer) -> Result { + let hex_str = hex_str::bytes_to_hex_str_stripped(self.0.as_be_bytes()); + serializer.serialize_str(&hex_str) + } + } + + impl SerializeForVersion for &pathfinder_common::CallParam { + fn serialize(&self, serializer: Serializer) -> Result { + let hex_str = hex_str::bytes_to_hex_str_stripped(self.0.as_be_bytes()); + serializer.serialize_str(&hex_str) + } + } + + impl SerializeForVersion for &pathfinder_common::CallResultValue { + fn serialize(&self, serializer: Serializer) -> Result { + serializer.serialize_str(&hex_str::bytes_to_hex_str_stripped(self.0.as_be_bytes())) + } + } + + impl SerializeForVersion for pathfinder_common::CasmHash { + fn serialize(&self, serializer: Serializer) -> Result { + let hex_str = hex_str::bytes_to_hex_str_stripped(self.0.as_be_bytes()); + serializer.serialize_str(&hex_str) + } + } + + impl SerializeForVersion for &pathfinder_common::CasmHash { + fn serialize(&self, serializer: Serializer) -> Result { + let hex_str = hex_str::bytes_to_hex_str_stripped(self.0.as_be_bytes()); + serializer.serialize_str(&hex_str) + } + } + + impl SerializeForVersion for pathfinder_common::ClassCommitment { + fn serialize(&self, serializer: Serializer) -> Result { + let hex_str = hex_str::bytes_to_hex_str_stripped(self.0.as_be_bytes()); + serializer.serialize_str(&hex_str) + } + } + + impl SerializeForVersion for pathfinder_common::ClassHash { + fn serialize(&self, serializer: Serializer) -> Result { + let hex_str = hex_str::bytes_to_hex_str_stripped(self.0.as_be_bytes()); + serializer.serialize_str(&hex_str) + } + } + + impl SerializeForVersion for &pathfinder_common::ClassHash { + fn serialize(&self, serializer: Serializer) -> Result { + let hex_str = hex_str::bytes_to_hex_str_stripped(self.0.as_be_bytes()); + serializer.serialize_str(&hex_str) + } + } + + impl SerializeForVersion for pathfinder_common::ContractAddress { + fn serialize(&self, serializer: Serializer) -> Result { + let hex_str = hex_str::bytes_to_hex_str_stripped(self.0.as_be_bytes()); + serializer.serialize_str(&hex_str) + } + } + + impl SerializeForVersion for &pathfinder_common::ContractAddress { + fn serialize(&self, serializer: Serializer) -> Result { + let hex_str = hex_str::bytes_to_hex_str_stripped(self.0.as_be_bytes()); + serializer.serialize_str(&hex_str) + } + } + + impl SerializeForVersion for pathfinder_common::ContractAddressSalt { + fn serialize(&self, serializer: Serializer) -> Result { + let hex_str = hex_str::bytes_to_hex_str_stripped(self.0.as_be_bytes()); + serializer.serialize_str(&hex_str) + } + } + + impl SerializeForVersion for pathfinder_common::ContractNonce { + fn serialize(&self, serializer: Serializer) -> Result { + let hex_str = hex_str::bytes_to_hex_str_stripped(self.0.as_be_bytes()); + serializer.serialize_str(&hex_str) + } + } + + impl SerializeForVersion for pathfinder_common::ContractRoot { + fn serialize(&self, serializer: Serializer) -> Result { + let hex_str = hex_str::bytes_to_hex_str_stripped(self.0.as_be_bytes()); + serializer.serialize_str(&hex_str) + } + } + + impl SerializeForVersion for &pathfinder_common::ConstructorParam { + fn serialize(&self, serializer: Serializer) -> Result { + let hex_str = hex_str::bytes_to_hex_str_stripped(self.0.as_be_bytes()); + serializer.serialize_str(&hex_str) + } + } + + impl SerializeForVersion for pathfinder_common::EntryPoint { + fn serialize(&self, serializer: Serializer) -> Result { + let hex_str = hex_str::bytes_to_hex_str_stripped(self.0.as_be_bytes()); + serializer.serialize_str(&hex_str) + } + } + + impl SerializeForVersion for pathfinder_common::EthereumAddress { + fn serialize(&self, serializer: Serializer) -> Result { + let hex_str = hex_str::bytes_to_hex_str_full(self.0.as_bytes()); + serializer.serialize_str(&hex_str) + } + } + + impl SerializeForVersion for pathfinder_common::EventCommitment { + fn serialize(&self, serializer: Serializer) -> Result { + serializer.serialize_str(&hex_str::bytes_to_hex_str_stripped(self.0.as_be_bytes())) + } + } + + impl SerializeForVersion for &pathfinder_common::EventData { + fn serialize(&self, serializer: Serializer) -> Result { + serializer.serialize_str(&hex_str::bytes_to_hex_str_stripped(self.0.as_be_bytes())) + } + } + + impl SerializeForVersion for &pathfinder_common::EventKey { + fn serialize(&self, serializer: Serializer) -> Result { + serializer.serialize_str(&hex_str::bytes_to_hex_str_stripped(self.0.as_be_bytes())) + } + } + + impl DeserializeForVersion for pathfinder_common::EthereumAddress { + fn deserialize(value: Value) -> Result { + match &value.data { + serde_json::Value::String(hex_str) => { + let bytes = + hex_str::bytes_from_hex_str_stripped::<20>(hex_str).map_err(|e| { + serde_json::Error::custom(format!( + "failed to parse hex string as ethereum address: {}", + e + )) + })?; + Ok(Self(H160::from(bytes))) + } + _ => Err(serde_json::Error::custom("expected hex string")), + } + } + } + + impl SerializeForVersion for pathfinder_common::Fee { + fn serialize(&self, serializer: Serializer) -> Result { + serializer.serialize_str(&hex_str::bytes_to_hex_str_stripped(self.0.as_be_bytes())) + } + } + + impl SerializeForVersion for pathfinder_common::GasPrice { + fn serialize(&self, serializer: Serializer) -> Result { + serializer.serialize_u128(self.0) + } + } + + impl SerializeForVersion for pathfinder_common::GasPriceHex { + fn serialize(&self, serializer: Serializer) -> Result { + let mut buf = [0u8; 2 + 32]; + let bytes = self.0.to_be_bytes(); + let s = bytes_as_hex_str(&bytes, &mut buf); + serializer.serialize_str(s) + } + } + + impl SerializeForVersion for &pathfinder_common::L2ToL1MessagePayloadElem { + fn serialize(&self, serializer: Serializer) -> Result { + serializer.serialize_str(&hex_str::bytes_to_hex_str_stripped(self.0.as_be_bytes())) + } + } + + impl SerializeForVersion for pathfinder_common::receipt::L2Gas { + fn serialize(&self, serializer: Serializer) -> Result { + serializer.serialize_u128(self.0) + } + } + + impl SerializeForVersion for pathfinder_common::L1DataAvailabilityMode { + fn serialize(&self, serializer: Serializer) -> Result { + match self { + pathfinder_common::L1DataAvailabilityMode::Calldata => { + serializer.serialize_str("CALLDATA") + } + pathfinder_common::L1DataAvailabilityMode::Blob => serializer.serialize_str("BLOB"), + } + } + } + + impl SerializeForVersion for pathfinder_common::ReceiptCommitment { + fn serialize(&self, serializer: Serializer) -> Result { + serializer.serialize_str(&hex_str::bytes_to_hex_str_stripped(self.0.as_be_bytes())) + } + } + + impl SerializeForVersion for pathfinder_common::ResourceAmount { + fn serialize(&self, serializer: Serializer) -> Result { + let bytes = self.0.to_be_bytes(); + let hex_str = pathfinder_serde::bytes_to_hex_str(&bytes); + serializer.serialize_str(&hex_str) + } + } + + impl SerializeForVersion for pathfinder_common::ResourcePricePerUnit { + fn serialize(&self, serializer: Serializer) -> Result { + let bytes = self.0.to_be_bytes(); + let hex_str = pathfinder_serde::bytes_to_hex_str(&bytes); + serializer.serialize_str(&hex_str) + } + } + + impl SerializeForVersion for pathfinder_common::SierraHash { + fn serialize(&self, serializer: Serializer) -> Result { + serializer.serialize_str(&hex_str::bytes_to_hex_str_stripped(self.0.as_be_bytes())) + } + } + + impl SerializeForVersion for pathfinder_common::StarknetVersion { + fn serialize( + &self, + serializer: crate::dto::Serializer, + ) -> Result { + serializer.serialize_str(&self.to_string()) + } + } + + impl SerializeForVersion for pathfinder_common::StateCommitment { + fn serialize(&self, serializer: Serializer) -> Result { + serializer.serialize_str(&hex_str::bytes_to_hex_str_stripped(self.0.as_be_bytes())) + } + } + + impl SerializeForVersion for pathfinder_common::StorageAddress { + fn serialize(&self, serializer: Serializer) -> Result { + serializer.serialize_str(&hex_str::bytes_to_hex_str_stripped(self.0.as_be_bytes())) + } + } + + impl SerializeForVersion for pathfinder_common::StorageCommitment { + fn serialize(&self, serializer: Serializer) -> Result { + serializer.serialize_str(&hex_str::bytes_to_hex_str_stripped(self.0.as_be_bytes())) + } + } + + impl SerializeForVersion for pathfinder_common::StorageValue { + fn serialize(&self, serializer: Serializer) -> Result { + serializer.serialize_str(&hex_str::bytes_to_hex_str_stripped(self.0.as_be_bytes())) + } + } + + impl SerializeForVersion for pathfinder_common::SequencerAddress { + fn serialize(&self, serializer: Serializer) -> Result { + serializer.serialize_str(&hex_str::bytes_to_hex_str_stripped(self.0.as_be_bytes())) + } + } + + impl SerializeForVersion for pathfinder_common::Tip { + fn serialize(&self, serializer: Serializer) -> Result { + serializer.serialize_u64(self.0) + } + } + + impl SerializeForVersion for pathfinder_common::TipHex { + fn serialize(&self, serializer: Serializer) -> Result { + let bytes = self.0 .0.to_be_bytes(); + let hex_str = pathfinder_serde::bytes_to_hex_str(&bytes); + serializer.serialize_str(&hex_str) + } + } + + impl SerializeForVersion for pathfinder_common::TransactionCommitment { + fn serialize(&self, serializer: Serializer) -> Result { + serializer.serialize_str(&hex_str::bytes_to_hex_str_stripped(self.0.as_be_bytes())) + } + } + + impl SerializeForVersion for pathfinder_common::TransactionHash { + fn serialize(&self, serializer: Serializer) -> Result { + serializer.serialize_str(&hex_str::bytes_to_hex_str_stripped(self.0.as_be_bytes())) + } + } + + impl SerializeForVersion for &pathfinder_common::TransactionHash { + fn serialize(&self, serializer: Serializer) -> Result { + serializer.serialize_str(&hex_str::bytes_to_hex_str_stripped(self.0.as_be_bytes())) + } + } + + impl SerializeForVersion for pathfinder_common::TransactionNonce { + fn serialize(&self, serializer: Serializer) -> Result { + serializer.serialize_str(&hex_str::bytes_to_hex_str_stripped(self.0.as_be_bytes())) + } + } + + impl SerializeForVersion for &pathfinder_common::TransactionSignatureElem { + fn serialize(&self, serializer: Serializer) -> Result { + serializer.serialize_str(&hex_str::bytes_to_hex_str_stripped(self.0.as_be_bytes())) + } + } + + impl SerializeForVersion for pathfinder_common::TransactionVersion { + fn serialize(&self, serializer: Serializer) -> Result { + serializer.serialize_str(&hex_str::bytes_to_hex_str_stripped(self.0.as_be_bytes())) + } + } + + impl SerializeForVersion for &pathfinder_common::PaymasterDataElem { + fn serialize(&self, serializer: Serializer) -> Result { + serializer.serialize_str(&hex_str::bytes_to_hex_str_stripped(self.0.as_be_bytes())) + } } } #[cfg(test)] mod tests { use pathfinder_common::macro_prelude::*; + use pathfinder_common::{BlockNumber, ChainId, EthereumAddress}; use pretty_assertions_sorted::assert_eq; use primitive_types::H160; use serde_json::json; use super::*; - use crate::dto::Serializer; + use crate::dto::{SerializeForVersion, Serializer}; #[test] fn felt() { @@ -396,7 +843,7 @@ mod tests { #[test] fn block_number() { - let number = pathfinder_common::BlockNumber::new_or_panic(1234); + let number = BlockNumber::new_or_panic(1234); let expected = json!(1234); let encoded = number.serialize(Default::default()).unwrap(); @@ -439,7 +886,7 @@ mod tests { #[test] fn chain_id() { - let uut = pathfinder_common::ChainId(felt!("0x1234")); + let uut = ChainId(felt!("0x1234")); let expected = json!("0x1234"); let encoded = uut.serialize(Default::default()).unwrap(); @@ -474,8 +921,7 @@ mod tests { bytes[18] = 0x12; bytes[19] = 0x34; - let uut = pathfinder_common::EthereumAddress(H160(bytes)); - let uut = EthAddress(&uut); + let uut = EthereumAddress(H160(bytes)); let expected = json!("0x0000000000000000000000000000000000001234"); let encoded = uut.serialize(Default::default()).unwrap(); diff --git a/crates/rpc/src/dto/receipt.rs b/crates/rpc/src/dto/receipt.rs index 68894b02cd..236342a1e8 100644 --- a/crates/rpc/src/dto/receipt.rs +++ b/crates/rpc/src/dto/receipt.rs @@ -157,7 +157,7 @@ impl SerializeForVersion for TxnReceiptWithBlockInfo<'_> { finality: *finality, })?; - serializer.serialize_optional("block_hash", *block_hash)?; + serializer.serialize_optional("block_hash", block_hash.cloned())?; serializer.serialize_optional("block_number", *block_number)?; serializer.end() @@ -211,7 +211,7 @@ impl SerializeForVersion for DeployTxnReceipt<'_> { serializer.flatten(&CommonReceiptProperties(self.0))?; serializer.serialize_field("type", &"DEPLOY")?; - serializer.serialize_field("contract_address", &contract_address)?; + serializer.serialize_field("contract_address", contract_address)?; serializer.end() } @@ -241,7 +241,7 @@ impl SerializeForVersion for DeployAccountTxnReceipt<'_> { serializer.flatten(&CommonReceiptProperties(self.0))?; serializer.serialize_field("type", &"DEPLOY_ACCOUNT")?; - serializer.serialize_field("contract_address", &contract_address)?; + serializer.serialize_field("contract_address", contract_address)?; serializer.end() } @@ -336,7 +336,7 @@ impl SerializeForVersion for FeePayment<'_> { fn serialize(&self, serializer: Serializer) -> Result { let mut serializer = serializer.serialize_struct()?; - serializer.serialize_field("amount", &self.amount)?; + serializer.serialize_field("amount", self.amount)?; serializer.serialize_field("unit", &PriceUnit(self.transaction_version))?; serializer.end() diff --git a/crates/rpc/src/dto/simulation.rs b/crates/rpc/src/dto/simulation.rs index 6d375386af..2f6fa722c6 100644 --- a/crates/rpc/src/dto/simulation.rs +++ b/crates/rpc/src/dto/simulation.rs @@ -237,6 +237,23 @@ impl crate::dto::SerializeForVersion for InnerCallExecutionResources<'_> { } } +impl crate::dto::SerializeForVersion + for ( + &pathfinder_common::ContractAddress, + &pathfinder_common::ContractNonce, + ) +{ + fn serialize( + &self, + serializer: crate::dto::Serializer, + ) -> Result { + let mut serializer = serializer.serialize_struct()?; + serializer.serialize_field("contract_address", &self.0)?; + serializer.serialize_field("nonce", self.1)?; + serializer.end() + } +} + impl crate::dto::SerializeForVersion for pathfinder_executor::types::StateDiff { fn serialize( &self, @@ -349,7 +366,7 @@ impl crate::dto::SerializeForVersion for Nonce<'_> { ) -> Result { let mut serializer = serializer.serialize_struct()?; serializer.serialize_field("contract_address", &self.0 .0)?; - serializer.serialize_field("nonce", &self.0 .1)?; + serializer.serialize_field("nonce", self.0 .1)?; serializer.end() } } diff --git a/crates/rpc/src/dto/transaction.rs b/crates/rpc/src/dto/transaction.rs index 0ab2e5b2c4..bf5ca3c048 100644 --- a/crates/rpc/src/dto/transaction.rs +++ b/crates/rpc/src/dto/transaction.rs @@ -8,12 +8,6 @@ use crate::dto::{SerializeForVersion, Serializer}; pub struct TransactionWithHash<'a>(pub &'a pathfinder_common::transaction::Transaction); -impl SerializeForVersion for pathfinder_common::TransactionHash { - fn serialize(&self, serializer: Serializer) -> Result { - self.0.serialize(serializer) - } -} - impl SerializeForVersion for pathfinder_common::transaction::Transaction { fn serialize(&self, serializer: Serializer) -> Result { let mut s = serializer.serialize_struct()?; diff --git a/crates/rpc/src/jsonrpc/error.rs b/crates/rpc/src/jsonrpc/error.rs index 0a048dedda..9f01082443 100644 --- a/crates/rpc/src/jsonrpc/error.rs +++ b/crates/rpc/src/jsonrpc/error.rs @@ -81,7 +81,7 @@ impl crate::dto::SerializeForVersion for RpcError { ) -> Result { let mut obj = serializer.serialize_struct()?; obj.serialize_field("code", &self.code())?; - obj.serialize_field("message", &self.message(serializer.version))?; + obj.serialize_field("message", &self.message(serializer.version).as_ref())?; if let Some(data) = self.data(serializer.version) { obj.serialize_field("data", &data)?; diff --git a/crates/rpc/src/jsonrpc/response.rs b/crates/rpc/src/jsonrpc/response.rs index 574ae478ba..3df78450dd 100644 --- a/crates/rpc/src/jsonrpc/response.rs +++ b/crates/rpc/src/jsonrpc/response.rs @@ -72,7 +72,7 @@ impl crate::dto::SerializeForVersion for RpcResponse { }; match &self.id { - RequestId::Number(x) => obj.serialize_field("id", &x)?, + RequestId::Number(x) => obj.serialize_field("id", x)?, RequestId::String(x) => obj.serialize_field("id", &x)?, RequestId::Null => obj.serialize_field("id", &Value::Null)?, RequestId::Notification => {} @@ -96,7 +96,7 @@ impl crate::dto::SerializeForVersion for &RpcResponse { }; match &self.id { - RequestId::Number(x) => obj.serialize_field("id", &x)?, + RequestId::Number(x) => obj.serialize_field("id", x)?, RequestId::String(x) => obj.serialize_field("id", &x)?, RequestId::Null => obj.serialize_field("id", &Value::Null)?, RequestId::Notification => {} diff --git a/crates/rpc/src/jsonrpc/router.rs b/crates/rpc/src/jsonrpc/router.rs index b386a20969..0710848e92 100644 --- a/crates/rpc/src/jsonrpc/router.rs +++ b/crates/rpc/src/jsonrpc/router.rs @@ -254,7 +254,7 @@ impl crate::dto::SerializeForVersion for RpcResponses { serializer: crate::dto::Serializer, ) -> Result { match self { - Self::Empty => serializer.serialize(&()), + Self::Empty => serializer.serialize_unit(), Self::Single(response) => serializer.serialize(response), Self::Multiple(responses) => { serializer.serialize_iter(responses.len(), &mut responses.iter()) @@ -487,6 +487,16 @@ mod tests { ])) } + impl crate::dto::SerializeForVersion for GetDataOutput { + fn serialize( + &self, + serializer: crate::dto::Serializer, + ) -> Result { + let value = serde_json::to_value(&self.0).unwrap(); + serializer.serialize(&value) + } + } + RpcRouter::builder(RpcVersion::default()) .register("subtract", subtract) .register("sum", sum) diff --git a/crates/rpc/src/jsonrpc/websocket/data.rs b/crates/rpc/src/jsonrpc/websocket/data.rs index 065e422f41..c0a0600671 100644 --- a/crates/rpc/src/jsonrpc/websocket/data.rs +++ b/crates/rpc/src/jsonrpc/websocket/data.rs @@ -14,6 +14,7 @@ use serde::ser::Error; use serde::Deserialize; use serde_json::Value; +use crate::dto::SerializeForVersion; use crate::jsonrpc::router::RpcResponses; use crate::jsonrpc::{RequestId, RpcError, RpcResponse}; @@ -52,6 +53,44 @@ pub(super) struct SubscriptionItem { pub(super) item: T, } +impl SerializeForVersion for SubscriptionItem { + fn serialize( + &self, + base_serializer: crate::dto::Serializer, + ) -> Result { + struct ResultHelper<'a, U: SerializeForVersion> { + subscription: u32, + result: &'a U, + } + impl<'a, T: SerializeForVersion> SerializeForVersion for ResultHelper<'a, T> { + fn serialize( + &self, + serializer: crate::dto::Serializer, + ) -> Result { + let mut s = serializer.serialize_struct()?; + s.serialize_field("subscription", &self.subscription)?; + s.serialize_field("result", self.result)?; + s.end() + } + } + + let mut serializer = base_serializer.serialize_struct()?; + + serializer.serialize_field("jsonrpc", &"2.0")?; + serializer.serialize_field("method", &"pathfinder_subscription")?; + serializer.serialize_field( + "result", + &ResultHelper { + subscription: self.subscription_id, + result: &self.item, + }, + )?; + + serializer.end() + } +} + +/* impl serde::Serialize for SubscriptionItem { fn serialize(&self, serializer: S) -> Result where @@ -77,6 +116,7 @@ impl serde::Serialize for SubscriptionItem { obj.end() } } +*/ #[derive(Debug)] pub(super) enum ResponseEvent { @@ -103,8 +143,7 @@ pub(super) enum ResponseEvent { } /// Describes an emitted event returned by starknet_getEvents -#[serde_with::skip_serializing_none] -#[derive(Clone, Debug, serde::Serialize, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq)] pub struct EmittedEvent { pub data: Vec, pub keys: Vec, @@ -116,8 +155,23 @@ pub struct EmittedEvent { pub transaction_hash: TransactionHash, } -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, serde::Serialize)] -#[serde(rename_all = "SCREAMING_SNAKE_CASE")] +impl SerializeForVersion for EmittedEvent { + fn serialize( + &self, + serializer: crate::dto::Serializer, + ) -> Result { + let mut obj = serializer.serialize_struct()?; + obj.serialize_iter("data", self.data.len(), &mut self.data.iter())?; + obj.serialize_iter("keys", self.keys.len(), &mut self.keys.iter())?; + obj.serialize_field("from_address", &self.from_address)?; + obj.serialize_optional("block_hash", self.block_hash)?; + obj.serialize_optional("block_number", self.block_number)?; + obj.serialize_field("transaction_hash", &self.transaction_hash)?; + obj.end() + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub enum TransactionStatusUpdate { Received = 0, Rejected = 1, @@ -125,6 +179,21 @@ pub enum TransactionStatusUpdate { Reverted = 3, } +impl crate::dto::SerializeForVersion for TransactionStatusUpdate { + fn serialize( + &self, + serializer: crate::dto::Serializer, + ) -> Result { + match self { + TransactionStatusUpdate::Received => "RECEIVED", + TransactionStatusUpdate::Rejected => "REJECTED", + TransactionStatusUpdate::Succeeded => "SUCCEEDED", + TransactionStatusUpdate::Reverted => "REVERTED", + } + .serialize(serializer) + } +} + impl ResponseEvent { pub(super) fn kind(&self) -> &'static str { match self { @@ -160,18 +229,30 @@ impl crate::dto::SerializeForVersion for ResponseEvent { RpcResponse::internal_error(request_id.clone(), e.to_string(), serializer.version) .serialize(serializer) } - ResponseEvent::Header(header) => header.serialize(serializer), - ResponseEvent::Event(event) => event.serialize(serializer), + ResponseEvent::Header(header) => { + let si = SubscriptionItem { + subscription_id: header.subscription_id, + item: (*header.item).clone(), + }; + si.serialize(serializer) + } + ResponseEvent::Event(event) => { + let si = SubscriptionItem { + subscription_id: event.subscription_id, + item: (*event.item).clone(), + }; + si.serialize(serializer) + } ResponseEvent::Subscribed { subscription_id, request_id, - } => successful_response(&subscription_id, request_id.clone(), serializer.version) + } => successful_response(subscription_id, request_id.clone(), serializer.version) .map_err(|_json_err| Error::custom("Payload serialization failed"))? .serialize(serializer), ResponseEvent::Unsubscribed { success, request_id, - } => successful_response(&success, request_id.clone(), serializer.version) + } => successful_response(success, request_id.clone(), serializer.version) .map_err(|_json_err| Error::custom("Payload serialization failed"))? .serialize(serializer), ResponseEvent::SubscriptionClosed { @@ -187,7 +268,13 @@ impl crate::dto::SerializeForVersion for ResponseEvent { } .serialize(serializer), ResponseEvent::Responses(responses) => responses.serialize(serializer), - ResponseEvent::TransactionStatus(status) => status.serialize(serializer), + ResponseEvent::TransactionStatus(status) => { + let si = SubscriptionItem { + subscription_id: status.subscription_id, + item: *status.item, + }; + si.serialize(serializer) + } ResponseEvent::RpcError(error) => error.serialize(serializer), } } @@ -199,9 +286,9 @@ pub(super) fn successful_response

( version: crate::RpcVersion, ) -> Result where - P: serde::Serialize, + P: SerializeForVersion, { - let payload = serde_json::to_value(payload)?; + let payload = payload.serialize(crate::dto::Serializer::new(version))?; Ok(RpcResponse { output: Ok(payload), id: request_id, @@ -275,3 +362,35 @@ impl serde::Serialize for BlockHeader { map.end() } } + +impl SerializeForVersion for BlockHeader { + fn serialize( + &self, + serializer: crate::dto::Serializer, + ) -> Result { + let mut obj = serializer.serialize_struct()?; + + let header = &self.0; + obj.serialize_field("hash", &header.hash)?; + obj.serialize_field("parent_hash", &header.parent_hash)?; + obj.serialize_field("number", &header.number)?; + obj.serialize_field("timestamp", &header.timestamp)?; + obj.serialize_field("eth_l1_gas_price", &header.eth_l1_gas_price)?; + obj.serialize_field("strk_l1_gas_price", &header.strk_l1_gas_price)?; + obj.serialize_field("eth_l1_data_gas_price", &header.eth_l1_data_gas_price)?; + obj.serialize_field("strk_l1_data_gas_price", &header.strk_l1_data_gas_price)?; + obj.serialize_field("eth_l2_gas_price", &header.eth_l2_gas_price)?; + obj.serialize_field("strk_l2_gas_price", &header.strk_l2_gas_price)?; + obj.serialize_field("sequencer_address", &header.sequencer_address)?; + obj.serialize_field("starknet_version", &header.starknet_version.to_string())?; + obj.serialize_field("event_commitment", &header.event_commitment)?; + obj.serialize_field("state_commitment", &header.state_commitment)?; + obj.serialize_field("transaction_commitment", &header.transaction_commitment)?; + obj.serialize_field("transaction_count", &header.transaction_count)?; + obj.serialize_field("event_count", &header.event_count)?; + obj.serialize_field("l1_da_mode", &header.l1_da_mode)?; + obj.serialize_field("receipt_commitment", &header.receipt_commitment)?; + + obj.end() + } +} diff --git a/crates/rpc/src/lib.rs b/crates/rpc/src/lib.rs index 8c8a781ac0..028c9c8cba 100644 --- a/crates/rpc/src/lib.rs +++ b/crates/rpc/src/lib.rs @@ -827,11 +827,10 @@ pub mod test_utils { #[cfg(test)] mod tests { - use dto::{DeserializeForVersion, SerializeForVersion}; + use dto::DeserializeForVersion; use serde_json::json; use super::*; - use crate::dto::Serializer; #[test] fn roundtrip_syncing() { @@ -856,15 +855,7 @@ mod tests { RpcVersion::V07, )) .unwrap(); - let output = parsed.serialize(Serializer::new(RpcVersion::V07)).unwrap(); - assert_eq!(parsed, expected, "example from line {line}"); - - // Compare parsed JSON values instead of strings - let output_value: serde_json::Value = - serde_json::from_str(&output.to_string()).unwrap(); - let input_value: serde_json::Value = serde_json::from_str(input).unwrap(); - assert_eq!(output_value, input_value, "example from line {line}"); } } diff --git a/crates/rpc/src/method/add_declare_transaction.rs b/crates/rpc/src/method/add_declare_transaction.rs index 278f140417..21281071e5 100644 --- a/crates/rpc/src/method/add_declare_transaction.rs +++ b/crates/rpc/src/method/add_declare_transaction.rs @@ -288,11 +288,8 @@ impl crate::dto::SerializeForVersion for Output { serializer: crate::dto::Serializer, ) -> Result { let mut serializer = serializer.serialize_struct()?; - serializer.serialize_field( - "transaction_hash", - &crate::dto::Felt(&self.transaction_hash.0), - )?; - serializer.serialize_field("class_hash", &crate::dto::Felt(&self.class_hash.0))?; + serializer.serialize_field("transaction_hash", &self.transaction_hash)?; + serializer.serialize_field("class_hash", &self.class_hash)?; serializer.end() } } diff --git a/crates/rpc/src/method/add_deploy_account_transaction.rs b/crates/rpc/src/method/add_deploy_account_transaction.rs index c38f84e13c..e27951eba0 100644 --- a/crates/rpc/src/method/add_deploy_account_transaction.rs +++ b/crates/rpc/src/method/add_deploy_account_transaction.rs @@ -221,14 +221,8 @@ impl crate::dto::SerializeForVersion for Output { serializer: crate::dto::Serializer, ) -> Result { let mut serializer = serializer.serialize_struct()?; - serializer.serialize_field( - "transaction_hash", - &crate::dto::Felt(&self.transaction_hash.0), - )?; - serializer.serialize_field( - "contract_address", - &crate::dto::Felt(&self.contract_address.0), - )?; + serializer.serialize_field("transaction_hash", &self.transaction_hash)?; + serializer.serialize_field("contract_address", &self.contract_address)?; serializer.end() } } diff --git a/crates/rpc/src/method/add_invoke_transaction.rs b/crates/rpc/src/method/add_invoke_transaction.rs index cd5cd11c79..5c18cbe2f2 100644 --- a/crates/rpc/src/method/add_invoke_transaction.rs +++ b/crates/rpc/src/method/add_invoke_transaction.rs @@ -202,10 +202,7 @@ impl crate::dto::SerializeForVersion for Output { serializer: crate::dto::Serializer, ) -> Result { let mut serializer = serializer.serialize_struct()?; - serializer.serialize_field( - "transaction_hash", - &crate::dto::Felt(&self.transaction_hash.0), - )?; + serializer.serialize_field("transaction_hash", &self.transaction_hash)?; serializer.end() } } diff --git a/crates/rpc/src/method/block_hash_and_number.rs b/crates/rpc/src/method/block_hash_and_number.rs index 4812ddb24c..d2f5b8d537 100644 --- a/crates/rpc/src/method/block_hash_and_number.rs +++ b/crates/rpc/src/method/block_hash_and_number.rs @@ -36,8 +36,8 @@ impl crate::dto::SerializeForVersion for Output { serializer: crate::dto::Serializer, ) -> Result { let mut serializer = serializer.serialize_struct()?; - serializer.serialize_field("block_hash", &crate::dto::BlockHash(&self.hash))?; - serializer.serialize_field("block_number", &crate::dto::BlockNumber(self.number))?; + serializer.serialize_field("block_hash", &self.hash)?; + serializer.serialize_field("block_number", &self.number)?; serializer.end() } } diff --git a/crates/rpc/src/method/block_number.rs b/crates/rpc/src/method/block_number.rs index b2f573d323..f8e0ed91c7 100644 --- a/crates/rpc/src/method/block_number.rs +++ b/crates/rpc/src/method/block_number.rs @@ -32,6 +32,6 @@ impl crate::dto::SerializeForVersion for Output { &self, serializer: crate::dto::Serializer, ) -> Result { - serializer.serialize(&crate::dto::BlockNumber(self.0)) + serializer.serialize(&self.0) } } diff --git a/crates/rpc/src/method/call.rs b/crates/rpc/src/method/call.rs index 11b15535f3..add563bf3b 100644 --- a/crates/rpc/src/method/call.rs +++ b/crates/rpc/src/method/call.rs @@ -167,10 +167,7 @@ impl crate::dto::SerializeForVersion for Output { &self, serializer: crate::dto::Serializer, ) -> Result { - serializer.serialize_iter( - self.0.len(), - &mut self.0.iter().map(|v| crate::dto::Felt(&v.0)), - ) + serializer.serialize_iter(self.0.len(), &mut self.0.iter()) } } diff --git a/crates/rpc/src/method/chain_id.rs b/crates/rpc/src/method/chain_id.rs index 8f94d7b1c7..fd7d12101c 100644 --- a/crates/rpc/src/method/chain_id.rs +++ b/crates/rpc/src/method/chain_id.rs @@ -14,7 +14,7 @@ impl crate::dto::SerializeForVersion for Output { &self, serializer: crate::dto::Serializer, ) -> Result { - serializer.serialize(&crate::dto::ChainId(&self.0)) + serializer.serialize(&self.0) } } diff --git a/crates/rpc/src/method/estimate_fee.rs b/crates/rpc/src/method/estimate_fee.rs index 1fb32c01dc..b07fe9b2a8 100644 --- a/crates/rpc/src/method/estimate_fee.rs +++ b/crates/rpc/src/method/estimate_fee.rs @@ -176,10 +176,7 @@ impl crate::dto::SerializeForVersion for Output { &self, serializer: crate::dto::Serializer, ) -> Result { - serializer.serialize_iter( - self.0.len(), - &mut self.0.iter().map(crate::dto::FeeEstimate), - ) + serializer.serialize_iter(self.0.len(), &mut self.0.iter().cloned()) } } diff --git a/crates/rpc/src/method/estimate_message_fee.rs b/crates/rpc/src/method/estimate_message_fee.rs index 6bfc82005e..137a193b0d 100644 --- a/crates/rpc/src/method/estimate_message_fee.rs +++ b/crates/rpc/src/method/estimate_message_fee.rs @@ -187,7 +187,7 @@ impl crate::dto::SerializeForVersion for Output { &self, serializer: crate::dto::Serializer, ) -> Result { - crate::dto::FeeEstimate(&self.0).serialize(serializer) + self.0.serialize(serializer) } } diff --git a/crates/rpc/src/method/get_block_with_receipts.rs b/crates/rpc/src/method/get_block_with_receipts.rs index a688175e79..4082b8da87 100644 --- a/crates/rpc/src/method/get_block_with_receipts.rs +++ b/crates/rpc/src/method/get_block_with_receipts.rs @@ -107,7 +107,7 @@ impl crate::dto::SerializeForVersion for Output { "ACCEPTED_ON_L2" }, )?; - serializer.flatten(&crate::dto::BlockHeader(header))?; + serializer.flatten(header.as_ref())?; serializer.serialize_iter( "transactions", body.len(), @@ -122,7 +122,7 @@ impl crate::dto::SerializeForVersion for Output { )?; } Output::Pending(block) => { - serializer.flatten(&crate::dto::PendingBlockHeader(block))?; + serializer.flatten(block.as_ref())?; serializer.serialize_iter( "transactions", block.transactions.len(), @@ -164,8 +164,7 @@ impl crate::dto::SerializeForVersion for TransactionWithReceipt<'_> { )?; } _ => { - serializer - .serialize_field("transaction", &crate::dto::Transaction(self.transaction))?; + serializer.serialize_field("transaction", self.transaction)?; } } serializer.serialize_field( diff --git a/crates/rpc/src/method/get_block_with_tx_hashes.rs b/crates/rpc/src/method/get_block_with_tx_hashes.rs index fc527133f8..1bc80f8951 100644 --- a/crates/rpc/src/method/get_block_with_tx_hashes.rs +++ b/crates/rpc/src/method/get_block_with_tx_hashes.rs @@ -98,11 +98,11 @@ impl crate::dto::SerializeForVersion for Output { transactions, } => { let mut serializer = serializer.serialize_struct()?; - serializer.flatten(&crate::dto::PendingBlockHeader(header))?; + serializer.flatten(header.as_ref())?; serializer.serialize_iter( "transactions", transactions.len(), - &mut transactions.iter().map(crate::dto::TxnHash), + &mut transactions.iter(), )?; serializer.end() } @@ -112,11 +112,11 @@ impl crate::dto::SerializeForVersion for Output { l1_accepted, } => { let mut serializer = serializer.serialize_struct()?; - serializer.flatten(&crate::dto::BlockHeader(header))?; + serializer.flatten(header.as_ref())?; serializer.serialize_iter( "transactions", transactions.len(), - &mut transactions.iter().map(crate::dto::TxnHash), + &mut transactions.iter(), )?; serializer.serialize_field( "status", diff --git a/crates/rpc/src/method/get_block_with_txs.rs b/crates/rpc/src/method/get_block_with_txs.rs index 5068dc7f47..6cf77366fa 100644 --- a/crates/rpc/src/method/get_block_with_txs.rs +++ b/crates/rpc/src/method/get_block_with_txs.rs @@ -108,11 +108,11 @@ impl crate::dto::SerializeForVersion for Output { transactions, } => { let mut serializer = serializer.serialize_struct()?; - serializer.flatten(&crate::dto::PendingBlockHeader(header))?; + serializer.flatten(header.as_ref())?; serializer.serialize_iter( "transactions", transactions.len(), - &mut transactions.iter().map(crate::dto::TransactionWithHash), + &mut transactions.iter().cloned(), )?; serializer.end() } @@ -122,11 +122,11 @@ impl crate::dto::SerializeForVersion for Output { l1_accepted, } => { let mut serializer = serializer.serialize_struct()?; - serializer.flatten(&crate::dto::BlockHeader(header))?; + serializer.flatten(header.as_ref())?; serializer.serialize_iter( "transactions", transactions.len(), - &mut transactions.iter().map(crate::dto::TransactionWithHash), + &mut transactions.iter().cloned(), )?; serializer.serialize_field( "status", diff --git a/crates/rpc/src/method/get_class.rs b/crates/rpc/src/method/get_class.rs index 6a03642ac0..6dce01139f 100644 --- a/crates/rpc/src/method/get_class.rs +++ b/crates/rpc/src/method/get_class.rs @@ -100,10 +100,8 @@ pub async fn get_class(context: RpcContext, input: Input) -> Result Result { match self { - Output::DeprecatedClass(cairo) => { - dto::DeprecatedContractClass(cairo).serialize(serializer) - } - Output::Class(sierra) => dto::ContractClass(sierra).serialize(serializer), + Output::DeprecatedClass(cairo) => cairo.serialize(serializer), + Output::Class(sierra) => sierra.serialize(serializer), } } } diff --git a/crates/rpc/src/method/get_class_at.rs b/crates/rpc/src/method/get_class_at.rs index 61c55cbe12..77ada1f77a 100644 --- a/crates/rpc/src/method/get_class_at.rs +++ b/crates/rpc/src/method/get_class_at.rs @@ -43,16 +43,14 @@ impl From for Output { impl SerializeForVersion for Output { fn serialize(&self, serializer: dto::Serializer) -> Result { match self { - Output::DeprecatedClass(cairo) => { - dto::DeprecatedContractClass(cairo).serialize(serializer) - } - Output::Class(sierra) => dto::ContractClass(sierra).serialize(serializer), + Output::DeprecatedClass(cairo) => cairo.serialize(serializer), + Output::Class(sierra) => sierra.serialize(serializer), } } } /// Get a contract class. -pub async fn get_class_at(context: RpcContext, input: Input) -> Result { +pub async fn get_class_at(context: RpcContext, input: Input) -> Result { let span = tracing::Span::current(); let jh = util::task::spawn_blocking(move |_| { let _g = span.enter(); @@ -103,7 +101,8 @@ pub async fn get_class_at(context: RpcContext, input: Input) -> Result Result { - serializer.serialize(&crate::dto::Felt(&self.0 .0)) + serializer.serialize(&self.0) } } diff --git a/crates/rpc/src/method/get_compiled_casm.rs b/crates/rpc/src/method/get_compiled_casm.rs index 1fed6eb597..31f86511d7 100644 --- a/crates/rpc/src/method/get_compiled_casm.rs +++ b/crates/rpc/src/method/get_compiled_casm.rs @@ -28,7 +28,13 @@ impl crate::dto::SerializeForVersion for Output { &self, serializer: crate::dto::Serializer, ) -> Result { - self.0.serialize(serializer) + use serde::de::Error; + let mut s = serializer.serialize_struct()?; + // Convert CasmContractClass to a serde_json::Value first + let json_value = serde_json::to_value(&self.0).map_err(serde_json::Error::custom)?; + // Serialize it as a field + s.serialize_field("casm", &json_value)?; + s.end() } } diff --git a/crates/rpc/src/method/get_events.rs b/crates/rpc/src/method/get_events.rs index b83cda89cd..6166e89c0c 100644 --- a/crates/rpc/src/method/get_events.rs +++ b/crates/rpc/src/method/get_events.rs @@ -577,11 +577,10 @@ impl SerializeForVersion for EmittedEvent { serializer.serialize_iter("data", self.data.len(), &mut self.data.iter().map(|d| d.0))?; serializer.serialize_iter("keys", self.keys.len(), &mut self.keys.iter().map(|d| d.0))?; - serializer.serialize_field("from_address", &dto::Address(&self.from_address))?; - serializer - .serialize_optional("block_hash", self.block_hash.as_ref().map(dto::BlockHash))?; - serializer.serialize_optional("block_number", self.block_number.map(dto::BlockNumber))?; - serializer.serialize_field("transaction_hash", &dto::TxnHash(&self.transaction_hash))?; + serializer.serialize_field("from_address", &self.from_address)?; + serializer.serialize_optional("block_hash", self.block_hash)?; + serializer.serialize_optional("block_number", self.block_number)?; + serializer.serialize_field("transaction_hash", &self.transaction_hash)?; serializer.end() } @@ -598,7 +597,7 @@ impl SerializeForVersion for GetEventsResult { let mut serializer = serializer.serialize_struct()?; serializer.serialize_iter("events", self.events.len(), &mut self.events.iter())?; - serializer.serialize_optional("continuation_token", self.continuation_token.as_ref())?; + serializer.serialize_optional("continuation_token", self.continuation_token.clone())?; serializer.end() } diff --git a/crates/rpc/src/method/get_nonce.rs b/crates/rpc/src/method/get_nonce.rs index d5657c3430..2c336fd8f7 100644 --- a/crates/rpc/src/method/get_nonce.rs +++ b/crates/rpc/src/method/get_nonce.rs @@ -88,7 +88,7 @@ impl crate::dto::SerializeForVersion for Output { &self, serializer: crate::dto::Serializer, ) -> Result { - serializer.serialize(&crate::dto::Felt(&self.0 .0)) + serializer.serialize(&self.0) } } diff --git a/crates/rpc/src/method/get_storage_at.rs b/crates/rpc/src/method/get_storage_at.rs index 0cdc0ad2ee..dc483ea45a 100644 --- a/crates/rpc/src/method/get_storage_at.rs +++ b/crates/rpc/src/method/get_storage_at.rs @@ -85,7 +85,7 @@ impl crate::dto::SerializeForVersion for Output { &self, serializer: crate::dto::Serializer, ) -> Result { - serializer.serialize(&crate::dto::Felt(&self.0 .0)) + serializer.serialize(&self.0) } } diff --git a/crates/rpc/src/method/simulate_transactions.rs b/crates/rpc/src/method/simulate_transactions.rs index 67f435d2cb..946021fcdf 100644 --- a/crates/rpc/src/method/simulate_transactions.rs +++ b/crates/rpc/src/method/simulate_transactions.rs @@ -116,10 +116,7 @@ impl crate::dto::SerializeForVersion for TransactionSimulation<'_> { serializer: crate::dto::Serializer, ) -> Result { let mut serializer = serializer.serialize_struct()?; - serializer.serialize_field( - "fee_estimation", - &crate::dto::FeeEstimate(&self.0.fee_estimation), - )?; + serializer.serialize_field("fee_estimation", &self.0.fee_estimation)?; serializer.serialize_field( "transaction_trace", &crate::dto::TransactionTrace { @@ -1972,11 +1969,7 @@ pub(crate) mod tests { version: RpcVersion::V07, }; - let result_serializable = result - .0 - .into_iter() - .map(crate::dto::SimulatedTransaction) - .collect::>(); + let result_serializable = result.0.into_iter().collect::>(); let result_serialized = serializer .serialize_iter( @@ -2007,7 +2000,6 @@ pub(crate) mod tests { ), ] .into_iter() - .map(crate::dto::SimulatedTransaction) .collect::>(); let expected_serialized = serializer diff --git a/crates/rpc/src/method/subscribe_new_heads.rs b/crates/rpc/src/method/subscribe_new_heads.rs index ce331dc1a7..6f2c2e0e85 100644 --- a/crates/rpc/src/method/subscribe_new_heads.rs +++ b/crates/rpc/src/method/subscribe_new_heads.rs @@ -43,7 +43,7 @@ impl crate::dto::SerializeForVersion for Notification { serializer: crate::dto::Serializer, ) -> Result { match self { - Self::BlockHeader(header) => crate::dto::BlockHeader(header).serialize(serializer), + Self::BlockHeader(header) => header.serialize(serializer), Self::Reorg(reorg) => reorg.serialize(serializer), } } diff --git a/crates/rpc/src/method/syncing.rs b/crates/rpc/src/method/syncing.rs index 13cca551ff..05624b3070 100644 --- a/crates/rpc/src/method/syncing.rs +++ b/crates/rpc/src/method/syncing.rs @@ -29,7 +29,7 @@ impl crate::dto::SerializeForVersion for Output { ) -> Result { match self.0 { Syncing::False => serializer.serialize_bool(false), - Syncing::Status(status) => serializer.serialize(&crate::dto::SyncStatus(&status)), + Syncing::Status(status) => serializer.serialize(&status), } } } diff --git a/crates/rpc/src/method/trace_block_transactions.rs b/crates/rpc/src/method/trace_block_transactions.rs index a718027e3b..99a38a32f4 100644 --- a/crates/rpc/src/method/trace_block_transactions.rs +++ b/crates/rpc/src/method/trace_block_transactions.rs @@ -557,10 +557,7 @@ impl crate::dto::SerializeForVersion for Trace<'_> { serializer: crate::dto::Serializer, ) -> Result { let mut serializer = serializer.serialize_struct()?; - serializer.serialize_field( - "transaction_hash", - &crate::dto::TxnHash(self.transaction_hash), - )?; + serializer.serialize_field("transaction_hash", self.transaction_hash)?; serializer.serialize_field( "trace_root", &crate::dto::TransactionTrace { diff --git a/crates/rpc/src/pathfinder/methods/get_proof.rs b/crates/rpc/src/pathfinder/methods/get_proof.rs index 82470ce330..534417f7da 100644 --- a/crates/rpc/src/pathfinder/methods/get_proof.rs +++ b/crates/rpc/src/pathfinder/methods/get_proof.rs @@ -98,6 +98,18 @@ struct PathWrapper { len: usize, } +impl crate::dto::SerializeForVersion for PathWrapper { + fn serialize( + &self, + serializer: crate::dto::Serializer, + ) -> Result { + let mut obj = serializer.serialize_struct()?; + obj.serialize_field("value", &self.value)?; + obj.serialize_field("len", &self.len)?; + obj.end() + } +} + /// Wrapper around [`Vec`] as we don't control [TrieNode] in this /// crate. #[derive(Clone, Debug, PartialEq)] @@ -155,6 +167,50 @@ impl Serialize for ProofNodes { } } +impl crate::dto::SerializeForVersion for ProofNodes { + fn serialize( + &self, + serializer: crate::dto::Serializer, + ) -> Result { + serializer.serialize_iter( + self.0.len(), + &mut self.0.iter().map(|node| { + struct SerProofNode<'a>(&'a TrieNode); + + impl crate::dto::SerializeForVersion for SerProofNode<'_> { + fn serialize( + &self, + serializer: crate::dto::Serializer, + ) -> Result { + let mut s = serializer.serialize_struct()?; + match self.0 { + TrieNode::Binary { left, right } => { + s.serialize_field("type", &"binary")?; + s.serialize_field("left", left)?; + s.serialize_field("right", right)?; + } + TrieNode::Edge { child, path } => { + let value = Felt::from_bits(path).unwrap(); + let path = PathWrapper { + value, + len: path.len(), + }; + + s.serialize_field("type", &"edge")?; + s.serialize_field("path", &path)?; + s.serialize_field("child", child)?; + } + } + s.end() + } + } + + SerProofNode(node) + }), + ) + } +} + /// Holds the data and proofs for a specific contract. #[derive(Clone, Debug, Serialize)] pub struct ContractData { @@ -174,6 +230,28 @@ pub struct ContractData { storage_proofs: Vec, } +impl crate::dto::SerializeForVersion for ContractData { + fn serialize( + &self, + serializer: crate::dto::Serializer, + ) -> Result { + let mut obj = serializer.serialize_struct()?; + obj.serialize_field("class_hash", &self.class_hash)?; + obj.serialize_field("nonce", &self.nonce)?; + obj.serialize_field("root", &self.root)?; + obj.serialize_field( + "contract_state_hash_version", + &self.contract_state_hash_version, + )?; + obj.serialize_iter( + "storage_proofs", + self.storage_proofs.len(), + &mut self.storage_proofs.iter().cloned(), + )?; + obj.end() + } +} + /// Holds the membership/non-membership of a contract and its associated /// contract contract if the contract exists. #[derive(Debug)] diff --git a/crates/rpc/src/types.rs b/crates/rpc/src/types.rs index 8a7cebbb4b..b4e829d061 100644 --- a/crates/rpc/src/types.rs +++ b/crates/rpc/src/types.rs @@ -7,7 +7,6 @@ pub(crate) mod transaction; pub use class::*; use pathfinder_common::{ResourceAmount, ResourcePricePerUnit}; -use pathfinder_serde::bytes_to_hex_str; use serde::de::Error; use crate::dto::{U128Hex, U64Hex}; @@ -75,10 +74,8 @@ impl crate::dto::SerializeForVersion for ResourceBound { serializer: crate::dto::Serializer, ) -> Result { let mut serializer = serializer.serialize_struct()?; - let max_amount_hex = bytes_to_hex_str(&self.max_amount.0.to_be_bytes()); - serializer.serialize_field("max_amount", &max_amount_hex)?; - let max_price_hex = bytes_to_hex_str(&self.max_price_per_unit.0.to_be_bytes()); - serializer.serialize_field("max_price_per_unit", &max_price_hex)?; + serializer.serialize_field("max_amount", &self.max_amount)?; + serializer.serialize_field("max_price_per_unit", &self.max_price_per_unit)?; serializer.end() } } @@ -158,11 +155,11 @@ pub mod request { Fee, PaymasterDataElem, Tip, + TipHex, TransactionNonce, TransactionSignatureElem, TransactionVersion, }; - use pathfinder_serde::bytes_to_hex_str; use serde::de::Error; use serde::Deserialize; use serde_with::serde_as; @@ -605,8 +602,7 @@ pub mod request { serializer.serialize_field("signature", &self.signature)?; serializer.serialize_field("nonce", &self.nonce)?; serializer.serialize_field("resource_bounds", &self.resource_bounds)?; - let tip_hex = bytes_to_hex_str(&self.tip.0.to_be_bytes()); - serializer.serialize_field("tip", &tip_hex)?; + serializer.serialize_field("tip", &TipHex(self.tip))?; serializer.serialize_field("paymaster_data", &self.paymaster_data)?; serializer.serialize_field("account_deployment_data", &self.account_deployment_data)?; serializer.serialize_field( @@ -879,8 +875,7 @@ pub mod request { serializer.serialize_field("signature", &self.signature)?; serializer.serialize_field("nonce", &self.nonce)?; serializer.serialize_field("resource_bounds", &self.resource_bounds)?; - let tip_hex = bytes_to_hex_str(&self.tip.0.to_be_bytes()); - serializer.serialize_field("tip", &tip_hex)?; + serializer.serialize_field("tip", &TipHex(self.tip))?; serializer.serialize_field("paymaster_data", &self.paymaster_data)?; serializer.serialize_field( "nonce_data_availability_mode", @@ -1203,8 +1198,7 @@ pub mod request { serializer.serialize_field("signature", &self.signature)?; serializer.serialize_field("nonce", &self.nonce)?; serializer.serialize_field("resource_bounds", &self.resource_bounds)?; - let tip_hex = bytes_to_hex_str(&self.tip.0.to_be_bytes()); - serializer.serialize_field("tip", &tip_hex)?; + serializer.serialize_field("tip", &TipHex(self.tip))?; serializer.serialize_field("paymaster_data", &self.paymaster_data)?; serializer.serialize_field("account_deployment_data", &self.account_deployment_data)?; serializer.serialize_field( @@ -1619,20 +1613,14 @@ pub mod request { /// Groups all strictly output types of the RPC API. pub mod reply { - use serde::Serialize; + use serde::de::Error; /// L2 Block status as returned by the RPC API. - #[derive(Copy, Clone, Debug, Serialize, PartialEq, Eq)] - #[cfg_attr(test, derive(serde::Deserialize))] - #[serde(deny_unknown_fields)] + #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum BlockStatus { - #[serde(rename = "PENDING")] Pending, - #[serde(rename = "ACCEPTED_ON_L2")] AcceptedOnL2, - #[serde(rename = "ACCEPTED_ON_L1")] AcceptedOnL1, - #[serde(rename = "REJECTED")] Rejected, } @@ -1642,6 +1630,33 @@ pub mod reply { } } + impl crate::dto::SerializeForVersion for BlockStatus { + fn serialize( + &self, + serializer: crate::dto::Serializer, + ) -> Result { + serializer.serialize_str(match self { + Self::Pending => "PENDING", + Self::AcceptedOnL2 => "ACCEPTED_ON_L2", + Self::AcceptedOnL1 => "ACCEPTED_ON_L1", + Self::Rejected => "REJECTED", + }) + } + } + + impl crate::dto::DeserializeForVersion for BlockStatus { + fn deserialize(value: crate::dto::Value) -> Result { + let status: String = value.deserialize()?; + match status.as_str() { + "PENDING" => Ok(Self::Pending), + "ACCEPTED_ON_L2" => Ok(Self::AcceptedOnL2), + "ACCEPTED_ON_L1" => Ok(Self::AcceptedOnL1), + "REJECTED" => Ok(Self::Rejected), + _ => Err(serde_json::Error::custom("Invalid block status")), + } + } + } + impl From for BlockStatus { fn from(status: starknet_gateway_types::reply::Status) -> Self { use starknet_gateway_types::reply::Status::*; diff --git a/crates/rpc/src/types/class.rs b/crates/rpc/src/types/class.rs index ef2efa3849..3f4cc7a5b5 100644 --- a/crates/rpc/src/types/class.rs +++ b/crates/rpc/src/types/class.rs @@ -6,8 +6,7 @@ use pathfinder_serde::U64AsHexStr; use serde::{Deserialize, Serialize}; use starknet_gateway_types::class_hash::{compute_class_hash, ComputedClassHash}; -#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)] -#[serde(untagged)] +#[derive(Clone, Debug, PartialEq, Eq)] pub enum ContractClass { Cairo(CairoContractClass), Sierra(SierraContractClass), @@ -203,6 +202,7 @@ impl TryFrom pub struct CairoContractClass { pub program: String, pub entry_points_by_type: ContractEntryPoints, + #[serde(skip_serializing_if = "Option::is_none")] pub abi: Option>, } @@ -426,7 +426,7 @@ pub struct TypedParameter { /// Also matches the gateway representation, which means it /// can be used to deserialize directly from storage. #[serde_with::serde_as] -#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)] #[serde(deny_unknown_fields)] pub struct SierraContractClass { #[serde_as(as = "Vec")] diff --git a/crates/rpc/src/types/syncing.rs b/crates/rpc/src/types/syncing.rs index b630a24f77..1c6417ad56 100644 --- a/crates/rpc/src/types/syncing.rs +++ b/crates/rpc/src/types/syncing.rs @@ -1,5 +1,4 @@ use pathfinder_common::{BlockHash, BlockNumber}; -use pathfinder_serde::block_number_as_hex_str; use serde_with::serde_as; use crate::dto::U64Hex; @@ -55,10 +54,6 @@ pub struct Status { pub highest: NumberedBlock, } -serde_with::with_prefix!(prefix_starting "starting_"); -serde_with::with_prefix!(prefix_current "current_"); -serde_with::with_prefix!(prefix_highest "highest_"); - impl std::fmt::Display for Status { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!( @@ -76,20 +71,11 @@ impl crate::dto::SerializeForVersion for Status { ) -> Result { let mut serializer = serializer.serialize_struct()?; serializer.serialize_field("starting_block_hash", &self.starting.hash)?; - serializer.serialize_field( - "starting_block_num", - &block_number_as_hex_str(&self.starting.number), - )?; + serializer.serialize_field("starting_block_num", &self.starting.number)?; serializer.serialize_field("current_block_hash", &self.current.hash)?; - serializer.serialize_field( - "current_block_num", - &block_number_as_hex_str(&self.current.number), - )?; + serializer.serialize_field("current_block_num", &self.current.number)?; serializer.serialize_field("highest_block_hash", &self.highest.hash)?; - serializer.serialize_field( - "highest_block_num", - &block_number_as_hex_str(&self.highest.number), - )?; + serializer.serialize_field("highest_block_num", &self.highest.number)?; serializer.end() } } diff --git a/crates/rpc/src/types/transaction.rs b/crates/rpc/src/types/transaction.rs index 8e069412ea..a80f9d21b1 100644 --- a/crates/rpc/src/types/transaction.rs +++ b/crates/rpc/src/types/transaction.rs @@ -102,6 +102,51 @@ struct ResourcePricePerUnitHelper<'a>(&'a ResourcePricePerUnit); struct DataAvailabilityModeHelper<'a>(&'a DataAvailabilityMode); struct TipHelper<'a>(&'a Tip); +impl crate::dto::SerializeForVersion for Vec { + fn serialize( + &self, + serializer: crate::dto::Serializer, + ) -> Result { + serializer.serialize_iter(self.len(), &mut self.iter()) + } +} + +impl crate::dto::SerializeForVersion for Vec { + fn serialize( + &self, + serializer: crate::dto::Serializer, + ) -> Result { + serializer.serialize_iter(self.len(), &mut self.iter()) + } +} + +impl crate::dto::SerializeForVersion for Vec { + fn serialize( + &self, + serializer: crate::dto::Serializer, + ) -> Result { + serializer.serialize_iter(self.len(), &mut self.iter()) + } +} + +impl crate::dto::SerializeForVersion for Vec { + fn serialize( + &self, + serializer: crate::dto::Serializer, + ) -> Result { + serializer.serialize_iter(self.len(), &mut self.iter()) + } +} + +impl crate::dto::SerializeForVersion for Vec { + fn serialize( + &self, + serializer: crate::dto::Serializer, + ) -> Result { + serializer.serialize_iter(self.len(), &mut self.iter()) + } +} + impl crate::dto::SerializeForVersion for DeclareV0Helper<'_> { fn serialize( &self, diff --git a/crates/rpc/src/v07/dto/header.rs b/crates/rpc/src/v07/dto/header.rs index 0f30b051ed..81d62efdf3 100644 --- a/crates/rpc/src/v07/dto/header.rs +++ b/crates/rpc/src/v07/dto/header.rs @@ -1,9 +1,5 @@ use pathfinder_common::prelude::*; -use serde::Serialize; -use serde_with::{serde_as, DisplayFromStr}; - -#[serde_as] -#[derive(Serialize)] +use pathfinder_common::GasPriceHex; pub struct Header { block_hash: BlockHash, parent_hash: BlockHash, @@ -12,12 +8,31 @@ pub struct Header { timestamp: BlockTimestamp, sequencer_address: SequencerAddress, l1_gas_price: ResourcePrice, - #[serde_as(as = "DisplayFromStr")] starknet_version: StarknetVersion, l1_data_gas_price: ResourcePrice, l1_da_mode: L1DaMode, } +impl crate::dto::SerializeForVersion for Header { + fn serialize( + &self, + serializer: crate::dto::Serializer, + ) -> Result { + let mut serializer = serializer.serialize_struct()?; + serializer.serialize_field("block_hash", &self.block_hash)?; + serializer.serialize_field("parent_hash", &self.parent_hash)?; + serializer.serialize_field("block_number", &self.block_number)?; + serializer.serialize_field("new_root", &self.new_root)?; + serializer.serialize_field("timestamp", &self.timestamp)?; + serializer.serialize_field("sequencer_address", &self.sequencer_address)?; + serializer.serialize_field("l1_gas_price", &self.l1_gas_price)?; + serializer.serialize_field("starknet_version", &self.starknet_version)?; + serializer.serialize_field("l1_data_gas_price", &self.l1_data_gas_price)?; + serializer.serialize_field("l1_da_mode", &self.l1_da_mode)?; + serializer.end() + } +} + impl From for Header { fn from(value: pathfinder_common::BlockHeader) -> Self { let l1_gas_price = ResourcePrice { @@ -44,14 +59,11 @@ impl From for Header { } } -#[serde_as] -#[derive(Serialize)] pub struct PendingHeader { parent_hash: BlockHash, timestamp: BlockTimestamp, sequencer_address: SequencerAddress, l1_gas_price: ResourcePrice, - #[serde_as(as = "DisplayFromStr")] starknet_version: StarknetVersion, l1_data_gas_price: ResourcePrice, l1_da_mode: L1DaMode, @@ -80,17 +92,40 @@ impl From for PendingHeader { } } -#[serde_as] -#[derive(Serialize)] +impl crate::dto::SerializeForVersion for PendingHeader { + fn serialize( + &self, + serializer: crate::dto::Serializer, + ) -> Result { + let mut serializer = serializer.serialize_struct()?; + serializer.serialize_field("parent_hash", &self.parent_hash)?; + serializer.serialize_field("timestamp", &self.timestamp)?; + serializer.serialize_field("sequencer_address", &self.sequencer_address)?; + serializer.serialize_field("l1_gas_price", &self.l1_gas_price)?; + serializer.serialize_field("starknet_version", &self.starknet_version)?; + serializer.serialize_field("l1_data_gas_price", &self.l1_data_gas_price)?; + serializer.serialize_field("l1_da_mode", &self.l1_da_mode)?; + serializer.end() + } +} + struct ResourcePrice { - #[serde_as(as = "pathfinder_serde::GasPriceAsHexStr")] pub price_in_wei: GasPrice, - #[serde_as(as = "pathfinder_serde::GasPriceAsHexStr")] pub price_in_fri: GasPrice, } -#[derive(Serialize)] -#[serde(rename_all = "SCREAMING_SNAKE_CASE")] +impl crate::dto::SerializeForVersion for ResourcePrice { + fn serialize( + &self, + serializer: crate::dto::Serializer, + ) -> Result { + let mut serializer = serializer.serialize_struct()?; + serializer.serialize_field("price_in_wei", &GasPriceHex(self.price_in_wei))?; + serializer.serialize_field("price_in_fri", &GasPriceHex(self.price_in_fri))?; + serializer.end() + } +} + enum L1DaMode { Blob, Calldata, @@ -105,6 +140,18 @@ impl From for L1DaMode { } } +impl crate::dto::SerializeForVersion for L1DaMode { + fn serialize( + &self, + serializer: crate::dto::Serializer, + ) -> Result { + serializer.serialize_str(match self { + L1DaMode::Blob => "BLOB", + L1DaMode::Calldata => "CALLDATA", + }) + } +} + #[cfg(test)] mod tests { use pathfinder_common::macro_prelude::*; @@ -113,6 +160,7 @@ mod tests { use serde_json::json; use super::*; + use crate::dto::SerializeForVersion; #[test] fn pending_header() { @@ -145,8 +193,9 @@ mod tests { ..Default::default() }; let uut = PendingHeader::from(uut); - - let encoded = serde_json::to_value(uut).unwrap(); + let encoded = uut + .serialize(crate::dto::Serializer::new(crate::RpcVersion::V07)) + .unwrap(); assert_eq!(encoded, expected); } @@ -188,8 +237,9 @@ mod tests { ..Default::default() }; let uut = Header::from(uut); - - let encoded = serde_json::to_value(uut).unwrap(); + let encoded = uut + .serialize(crate::dto::Serializer::new(crate::RpcVersion::V07)) + .unwrap(); assert_eq!(encoded, expected); } @@ -197,11 +247,15 @@ mod tests { #[test] fn l1_data_availability_mode() { let calldata = L1DaMode::from(pathfinder_common::L1DataAvailabilityMode::Calldata); - let encoded = serde_json::to_value(calldata).unwrap(); + let encoded = calldata + .serialize(crate::dto::Serializer::new(crate::RpcVersion::V07)) + .unwrap(); assert_eq!(encoded, json!("CALLDATA")); let blob = L1DaMode::from(pathfinder_common::L1DataAvailabilityMode::Blob); - let encoded = serde_json::to_value(blob).unwrap(); + let encoded = blob + .serialize(crate::dto::Serializer::new(crate::RpcVersion::V07)) + .unwrap(); assert_eq!(encoded, json!("BLOB")); } @@ -217,7 +271,9 @@ mod tests { price_in_fri: GasPrice(0x123), }; - let encoded = serde_json::to_value(uut).unwrap(); + let encoded = uut + .serialize(crate::dto::Serializer::new(crate::RpcVersion::V07)) + .unwrap(); assert_eq!(encoded, expected); } diff --git a/crates/rpc/src/v07/dto/receipt.rs b/crates/rpc/src/v07/dto/receipt.rs index b4dbccbabe..d43200cf8b 100644 --- a/crates/rpc/src/v07/dto/receipt.rs +++ b/crates/rpc/src/v07/dto/receipt.rs @@ -185,7 +185,7 @@ impl crate::dto::SerializeForVersion for TxnReceipt { common, } => { serializer.serialize_field("type", &"DEPLOY")?; - serializer.serialize_field("contract_address", contract_address)?; + serializer.serialize_field("contract_address", &contract_address)?; serializer.flatten(common)?; } Self::DeployAccount { @@ -193,7 +193,7 @@ impl crate::dto::SerializeForVersion for TxnReceipt { common, } => { serializer.serialize_field("type", &"DEPLOY_ACCOUNT")?; - serializer.serialize_field("contract_address", contract_address)?; + serializer.serialize_field("contract_address", &contract_address)?; serializer.flatten(common)?; } } @@ -253,7 +253,7 @@ impl crate::dto::SerializeForVersion for PendingTxnReceipt { common, } => { serializer.serialize_field("type", &"DEPLOY")?; - serializer.serialize_field("contract_address", contract_address)?; + serializer.serialize_field("contract_address", &contract_address)?; serializer.flatten(common)?; } Self::DeployAccount { @@ -261,7 +261,7 @@ impl crate::dto::SerializeForVersion for PendingTxnReceipt { common, } => { serializer.serialize_field("type", &"DEPLOY_ACCOUNT")?; - serializer.serialize_field("contract_address", contract_address)?; + serializer.serialize_field("contract_address", &contract_address)?; serializer.flatten(common)?; } }