From e6780c1ab9420c726d403f034fdd5e4e6c245a46 Mon Sep 17 00:00:00 2001 From: t00ts Date: Mon, 25 Nov 2024 17:21:00 +0400 Subject: [PATCH 1/3] feat(rpc): decouple v07 from v06 types and methods --- crates/executor/src/types.rs | 2 +- .../pathfinder/src/bin/pathfinder/config.rs | 7 +- crates/pathfinder/src/bin/pathfinder/main.rs | 3 +- crates/rpc/src/dto/simulation.rs | 167 +- crates/rpc/src/error.rs | 5 +- crates/rpc/src/lib.rs | 19 - crates/rpc/src/method/call.rs | 2 +- crates/rpc/src/method/estimate_message_fee.rs | 49 +- .../get_transaction_by_block_id_and_index.rs | 2 +- .../rpc/src/method/simulate_transactions.rs | 2118 ++++++++++------- .../src/method/trace_block_transactions.rs | 256 +- crates/rpc/src/method/trace_transaction.rs | 95 +- crates/rpc/src/types.rs | 2 + crates/rpc/src/types/receipt.rs | 166 ++ crates/rpc/src/types/transaction.rs | 836 +++++++ crates/rpc/src/v07/dto/receipt.rs | 46 +- 16 files changed, 2761 insertions(+), 1014 deletions(-) create mode 100644 crates/rpc/src/types/receipt.rs create mode 100644 crates/rpc/src/types/transaction.rs diff --git a/crates/executor/src/types.rs b/crates/executor/src/types.rs index fb5edb846d..1ee655bf56 100644 --- a/crates/executor/src/types.rs +++ b/crates/executor/src/types.rs @@ -217,7 +217,7 @@ pub struct MsgToL1 { pub from_address: Felt, } -#[derive(Debug, Clone)] +#[derive(Default, Debug, Clone)] pub struct InnerCallExecutionResources { pub l1_gas: u128, pub l2_gas: u128, diff --git a/crates/pathfinder/src/bin/pathfinder/config.rs b/crates/pathfinder/src/bin/pathfinder/config.rs index 577b184006..3fb9d92cee 100644 --- a/crates/pathfinder/src/bin/pathfinder/config.rs +++ b/crates/pathfinder/src/bin/pathfinder/config.rs @@ -86,7 +86,7 @@ Examples: default_value = "v07", env = "PATHFINDER_RPC_ROOT_VERSION" )] - rpc_root_version: RpcVersion, + rpc_root_version: RootRpcVersion, #[arg( long = "rpc.execution-concurrency", @@ -334,8 +334,7 @@ impl Color { } #[derive(clap::ValueEnum, Debug, Clone, Copy, PartialEq)] -pub enum RpcVersion { - V06, +pub enum RootRpcVersion { V07, } @@ -692,7 +691,7 @@ pub struct Config { pub ethereum: Ethereum, pub rpc_address: SocketAddr, pub rpc_cors_domains: Option, - pub rpc_root_version: RpcVersion, + pub rpc_root_version: RootRpcVersion, pub websocket: WebsocketConfig, pub monitor_address: Option, pub network: Option, diff --git a/crates/pathfinder/src/bin/pathfinder/main.rs b/crates/pathfinder/src/bin/pathfinder/main.rs index 6e8c3afc5f..cda893bb3e 100644 --- a/crates/pathfinder/src/bin/pathfinder/main.rs +++ b/crates/pathfinder/src/bin/pathfinder/main.rs @@ -247,8 +247,7 @@ Hint: This is usually caused by exceeding the file descriptor limit of your syst }; let default_version = match config.rpc_root_version { - config::RpcVersion::V06 => pathfinder_rpc::RpcVersion::V06, - config::RpcVersion::V07 => pathfinder_rpc::RpcVersion::V07, + config::RootRpcVersion::V07 => pathfinder_rpc::RpcVersion::V07, }; let rpc_server = pathfinder_rpc::RpcServer::new(config.rpc_address, context, default_version); diff --git a/crates/rpc/src/dto/simulation.rs b/crates/rpc/src/dto/simulation.rs index 786dff05af..e7901c2f8c 100644 --- a/crates/rpc/src/dto/simulation.rs +++ b/crates/rpc/src/dto/simulation.rs @@ -3,21 +3,22 @@ use pathfinder_common::{ContractAddress, ContractNonce}; use serde::ser::Error; use super::serialize::SerializeStruct; +use super::FeeEstimate; use crate::RpcVersion; #[derive(Debug)] -pub struct TransactionTrace<'a> { - pub trace: &'a pathfinder_executor::types::TransactionTrace, +pub struct TransactionTrace { + pub trace: pathfinder_executor::types::TransactionTrace, pub include_state_diff: bool, } -impl crate::dto::serialize::SerializeForVersion for TransactionTrace<'_> { +impl crate::dto::serialize::SerializeForVersion for TransactionTrace { fn serialize( &self, serializer: super::serialize::Serializer, ) -> Result { let mut serializer = serializer.serialize_struct()?; - match self.trace { + match &self.trace { pathfinder_executor::types::TransactionTrace::Declare(trace) => { serializer.serialize_field("type", &"DECLARE")?; if let Some(fee_transfer_invocation) = &trace.fee_transfer_invocation { @@ -120,7 +121,7 @@ impl crate::dto::serialize::SerializeForVersion for TransactionTrace<'_> { } #[derive(Debug)] -struct FunctionInvocation<'a>(&'a pathfinder_executor::types::FunctionInvocation); +pub(crate) struct FunctionInvocation<'a>(&'a pathfinder_executor::types::FunctionInvocation); impl crate::dto::serialize::SerializeForVersion for FunctionInvocation<'_> { fn serialize( @@ -519,3 +520,159 @@ impl crate::dto::serialize::SerializeForVersion for ExecuteInvocation<'_> { } } } + +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum CallType { + Call, + _LibraryCall, + Delegate, +} + +impl From for CallType { + fn from(value: pathfinder_executor::types::CallType) -> Self { + use pathfinder_executor::types::CallType::*; + match value { + Call => Self::Call, + Delegate => Self::Delegate, + } + } +} + +impl crate::dto::serialize::SerializeForVersion for CallType { + fn serialize( + &self, + serializer: super::serialize::Serializer, + ) -> Result { + match self { + CallType::Call => serializer.serialize_str("CALL"), + CallType::_LibraryCall => serializer.serialize_str("LIBRARY_CALL"), + CallType::Delegate => serializer.serialize_str("DELEGATE"), + } + } +} + +#[derive(Debug, Eq, PartialEq)] +pub struct SimulationFlags(pub Vec); + +#[derive(Debug, Eq, PartialEq)] +pub enum SimulationFlag { + SkipFeeCharge, + SkipValidate, +} + +impl crate::dto::DeserializeForVersion for SimulationFlag { + fn deserialize(value: crate::dto::Value) -> Result { + let value: String = value.deserialize_serde()?; + match value.as_str() { + "SKIP_FEE_CHARGE" => Ok(Self::SkipFeeCharge), + "SKIP_VALIDATE" => Ok(Self::SkipValidate), + _ => Err(serde_json::Error::custom("Invalid simulation flag")), + } + } +} + +impl crate::dto::DeserializeForVersion for SimulationFlags { + fn deserialize(value: crate::dto::Value) -> Result { + let array = value.deserialize_array(SimulationFlag::deserialize)?; + Ok(Self(array)) + } +} + +pub(crate) struct SimulatedTransaction(pub pathfinder_executor::types::TransactionSimulation); + +impl crate::dto::serialize::SerializeForVersion for SimulatedTransaction { + fn serialize( + &self, + serializer: super::serialize::Serializer, + ) -> Result { + let mut serializer = serializer.serialize_struct()?; + serializer.serialize_field("fee_estimation", &FeeEstimate(&self.0.fee_estimation))?; + serializer.serialize_field( + "transaction_trace", + &TransactionTrace { + trace: self.0.trace.clone(), + include_state_diff: false, + }, + )?; + serializer.end() + } +} + +#[cfg(test)] +mod tests { + + use pathfinder_common::macro_prelude::*; + use pathfinder_common::{ + felt, + BlockHeader, + BlockId, + CallParam, + ClassHash, + ContractAddress, + EntryPoint, + StarknetVersion, + StorageAddress, + StorageValue, + TransactionVersion, + }; + use pathfinder_crypto::Felt; + use pathfinder_storage::Storage; + use starknet_gateway_test_fixtures::class_definitions::{ + DUMMY_ACCOUNT_CLASS_HASH, + ERC20_CONTRACT_DEFINITION_CLASS_HASH, + }; + + use crate::context::RpcContext; + use crate::dto::serialize::{SerializeForVersion, Serializer}; + use crate::dto::{ + CallType, + ComputationResources, + ExecutionResources, + FeeEstimate, + FunctionInvocation, + SimulatedTransaction, + TransactionTrace, + }; + use crate::method::call::FunctionCall; + use crate::method::get_state_update::types::{DeployedContract, Nonce, StateDiff}; + use crate::method::simulate_transactions::tests::fixtures; + use crate::types::request::{ + BroadcastedDeclareTransaction, + BroadcastedDeclareTransactionV1, + BroadcastedTransaction, + }; + use crate::types::ContractClass; + use crate::RpcVersion; + + pub(crate) async fn setup_storage_with_starknet_version( + version: StarknetVersion, + ) -> ( + Storage, + BlockHeader, + ContractAddress, + ContractAddress, + StorageValue, + ) { + let test_storage_key = StorageAddress::from_name(b"my_storage_var"); + let test_storage_value = storage_value!("0x09"); + + // set test storage variable + let (storage, last_block_header, account_contract_address, universal_deployer_address) = + crate::test_setup::test_storage(version, |state_update| { + state_update.with_storage_update( + fixtures::DEPLOYED_CONTRACT_ADDRESS, + test_storage_key, + test_storage_value, + ) + }) + .await; + + ( + storage, + last_block_header, + account_contract_address, + universal_deployer_address, + test_storage_value, + ) + } +} diff --git a/crates/rpc/src/error.rs b/crates/rpc/src/error.rs index 90f34948d2..fc7e1bc6f6 100644 --- a/crates/rpc/src/error.rs +++ b/crates/rpc/src/error.rs @@ -171,9 +171,8 @@ impl ApplicationError { pub fn message(&self, version: RpcVersion) -> String { match self { ApplicationError::InsufficientResourcesForValidate => match version { - RpcVersion::V06 | RpcVersion::V07 => "Max fee is smaller than the minimal \ - transaction cost (validation plus fee \ - transfer)" + RpcVersion::V07 => "Max fee is smaller than the minimal transaction cost \ + (validation plus fee transfer)" .to_string(), _ => self.to_string(), }, diff --git a/crates/rpc/src/lib.rs b/crates/rpc/src/lib.rs index 5df688323a..0895300768 100644 --- a/crates/rpc/src/lib.rs +++ b/crates/rpc/src/lib.rs @@ -12,7 +12,6 @@ mod pending; #[cfg(test)] mod test_setup; pub mod types; -pub mod v06; pub mod v07; pub mod v08; @@ -44,7 +43,6 @@ const DEFAULT_MAX_CONNECTIONS: usize = 1024; #[derive(Copy, Clone, Debug, Default, PartialEq, PartialOrd)] pub enum RpcVersion { - V06, #[default] V07, V08, @@ -54,7 +52,6 @@ pub enum RpcVersion { impl RpcVersion { fn to_str(self) -> &'static str { match self { - RpcVersion::V06 => "v0.6", RpcVersion::V07 => "v0.7", RpcVersion::V08 => "v0.8", RpcVersion::PathfinderV01 => "v0.1", @@ -164,13 +161,11 @@ impl RpcServer { } } - let v06_routes = v06::register_routes().build(self.context.clone()); let v07_routes = v07::register_routes().build(self.context.clone()); let v08_routes = v08::register_routes().build(self.context.clone()); let pathfinder_routes = pathfinder::register_routes().build(self.context.clone()); let default_router = match self.default_version { - RpcVersion::V06 => v06_routes.clone(), RpcVersion::V07 => v07_routes.clone(), RpcVersion::V08 => v08_routes.clone(), RpcVersion::PathfinderV01 => { @@ -183,8 +178,6 @@ impl RpcServer { // used by monitoring bots to check service health. .route("/", get(empty_body).post(rpc_handler)) .with_state(default_router.clone()) - .route("/rpc/v0_6", post(rpc_handler)) - .with_state(v06_routes.clone()) .route("/rpc/v0_7", post(rpc_handler)) .with_state(v07_routes.clone()) // TODO Uncomment once RPC 0.8 is ready. @@ -198,8 +191,6 @@ impl RpcServer { router .route("/ws", get(websocket_handler)) .with_state(default_router) - .route("/ws/rpc/v0_6", get(websocket_handler)) - .with_state(v06_routes) .route("/ws/rpc/v0_7", get(websocket_handler)) .with_state(v07_routes) .route("/ws/rpc/pathfinder/v0_1", get(websocket_handler)) @@ -951,16 +942,6 @@ mod tests { #[case::v0_7_pathfinder("/rpc/v0_7", "pathfinder_rpc_api.json", &["pathfinder_version", "pathfinder_getTransactionStatus"], Api::HttpOnly)] #[case::v0_7_pathfinder_websocket("/ws/rpc/v0_7", "pathfinder_rpc_api.json", &["pathfinder_version", "pathfinder_getTransactionStatus"], Api::WebsocketOnly)] - #[case::v0_6_api("/rpc/v0_6", "v06/starknet_api_openrpc.json", &[], Api::HttpOnly)] - #[case::v0_6_api_websocket("/ws/rpc/v0_6", "v06/starknet_api_openrpc.json", &[], Api::WebsocketOnly)] - #[case::v0_6_trace("/rpc/v0_6", "v06/starknet_trace_api_openrpc.json", &[], Api::HttpOnly)] - #[case::v0_6_trace_websocket("/ws/rpc/v0_6", "v06/starknet_trace_api_openrpc.json", &[], Api::WebsocketOnly)] - #[case::v0_6_write("/rpc/v0_6", "v06/starknet_write_api.json", &[], Api::HttpOnly)] - #[case::v0_6_write_websocket("/ws/rpc/v0_6", "v06/starknet_write_api.json", &[], Api::WebsocketOnly)] - // get_transaction_status is now part of the official spec, so we are phasing it out. - #[case::v0_6_pathfinder("/rpc/v0_6", "pathfinder_rpc_api.json", &["pathfinder_version", "pathfinder_getTransactionStatus"], Api::HttpOnly)] - #[case::v0_6_pathfinder_websocket("/ws/rpc/v0_6", "pathfinder_rpc_api.json", &["pathfinder_version", "pathfinder_getTransactionStatus"], Api::WebsocketOnly)] - #[case::pathfinder("/rpc/pathfinder/v0.1", "pathfinder_rpc_api.json", &[], Api::HttpOnly)] #[case::pathfinder("/ws/rpc/pathfinder/v0_1", "pathfinder_rpc_api.json", &[], Api::WebsocketOnly)] diff --git a/crates/rpc/src/method/call.rs b/crates/rpc/src/method/call.rs index 31353c188c..eb3a0ce803 100644 --- a/crates/rpc/src/method/call.rs +++ b/crates/rpc/src/method/call.rs @@ -74,7 +74,7 @@ pub struct Input { pub block_id: BlockId, } -#[derive(serde::Deserialize, Clone, Debug, PartialEq, Eq)] +#[derive(serde::Serialize, serde::Deserialize, Clone, Debug, PartialEq, Eq)] #[serde(deny_unknown_fields)] pub struct FunctionCall { pub contract_address: ContractAddress, diff --git a/crates/rpc/src/method/estimate_message_fee.rs b/crates/rpc/src/method/estimate_message_fee.rs index f9cc925a73..2e75caa510 100644 --- a/crates/rpc/src/method/estimate_message_fee.rs +++ b/crates/rpc/src/method/estimate_message_fee.rs @@ -1,21 +1,60 @@ use std::sync::Arc; use anyhow::Context; -use pathfinder_common::{BlockId, CallParam, ChainId, TransactionNonce}; +use pathfinder_common::{ + BlockId, + CallParam, + ChainId, + ContractAddress, + EntryPoint, + EthereumAddress, + TransactionNonce, +}; use pathfinder_crypto::Felt; use pathfinder_executor::{ExecutionState, IntoStarkFelt, L1BlobDataAvailability}; use starknet_api::core::PatriciaKey; use crate::context::RpcContext; use crate::error::ApplicationError; -use crate::v06::method::estimate_message_fee as v06; + +#[derive(Debug, PartialEq, Eq)] +pub struct EstimateMessageFeeInput { + pub message: MsgFromL1, + pub block_id: BlockId, +} + +impl crate::dto::DeserializeForVersion for EstimateMessageFeeInput { + fn deserialize(value: crate::dto::Value) -> Result { + value.deserialize_map(|value| { + Ok(Self { + message: value.deserialize("message")?, + block_id: value.deserialize("block_id")?, + }) + }) + } +} + +#[derive(serde::Deserialize, Debug, PartialEq, Eq)] +pub struct MsgFromL1 { + pub from_address: EthereumAddress, + pub to_address: ContractAddress, + pub entry_point_selector: EntryPoint, + pub payload: Vec, +} + +impl crate::dto::DeserializeForVersion for MsgFromL1 { + fn deserialize(value: crate::dto::Value) -> Result { + // TODO: Replace this when DeserializeForVersion is available project-wide + value.deserialize_serde() + } +} #[derive(Debug, PartialEq, Eq)] pub struct Output(pathfinder_executor::types::FeeEstimate); pub async fn estimate_message_fee( context: RpcContext, - input: v06::EstimateMessageFeeInput, + input: EstimateMessageFeeInput, ) -> Result { let span = tracing::Span::current(); @@ -90,7 +129,7 @@ pub async fn estimate_message_fee( } fn create_executor_transaction( - input: v06::EstimateMessageFeeInput, + input: EstimateMessageFeeInput, chain_id: ChainId, ) -> anyhow::Result { let from_address = @@ -217,8 +256,8 @@ mod tests { use pretty_assertions_sorted::assert_eq; use primitive_types::H160; + use super::*; use crate::context::RpcContext; - use crate::v06::method::estimate_message_fee::*; enum Setup { Full, diff --git a/crates/rpc/src/method/get_transaction_by_block_id_and_index.rs b/crates/rpc/src/method/get_transaction_by_block_id_and_index.rs index 2a4bdb981e..89fd502014 100644 --- a/crates/rpc/src/method/get_transaction_by_block_id_and_index.rs +++ b/crates/rpc/src/method/get_transaction_by_block_id_and_index.rs @@ -2,7 +2,7 @@ use anyhow::Context; use pathfinder_common::{BlockId, TransactionIndex}; use crate::context::RpcContext; -use crate::v06::types::TransactionWithHash; +use crate::types::transaction::TransactionWithHash; #[derive(serde::Deserialize, Debug, PartialEq, Eq)] #[serde(deny_unknown_fields)] diff --git a/crates/rpc/src/method/simulate_transactions.rs b/crates/rpc/src/method/simulate_transactions.rs index 3ccee4645c..3486cf8cc3 100644 --- a/crates/rpc/src/method/simulate_transactions.rs +++ b/crates/rpc/src/method/simulate_transactions.rs @@ -4,13 +4,34 @@ use pathfinder_executor::TransactionExecutionError; use crate::context::RpcContext; use crate::executor::ExecutionStateError; -use crate::v06::method::simulate_transactions as v06; +use crate::types::request::BroadcastedTransaction; + +#[derive(Debug)] +pub struct SimulateTransactionInput { + pub block_id: BlockId, + pub transactions: Vec, + pub simulation_flags: crate::dto::SimulationFlags, +} + +impl crate::dto::DeserializeForVersion for SimulateTransactionInput { + fn deserialize(value: crate::dto::Value) -> Result { + value.deserialize_map(|value| { + Ok(Self { + block_id: value.deserialize("block_id")?, + transactions: value.deserialize_array("transactions", |value| { + BroadcastedTransaction::deserialize(value) + })?, + simulation_flags: value.deserialize("simulation_flags")?, + }) + }) + } +} pub struct Output(Vec); pub async fn simulate_transactions( context: RpcContext, - input: v06::SimulateTransactionInput, + input: SimulateTransactionInput, ) -> Result { let span = tracing::Span::current(); tokio::task::spawn_blocking(move || { @@ -20,13 +41,13 @@ pub async fn simulate_transactions( .simulation_flags .0 .iter() - .any(|flag| flag == &v06::dto::SimulationFlag::SkipValidate); + .any(|flag| flag == &crate::dto::SimulationFlag::SkipValidate); let skip_fee_charge = input .simulation_flags .0 .iter() - .any(|flag| flag == &v06::dto::SimulationFlag::SkipFeeCharge); + .any(|flag| flag == &crate::dto::SimulationFlag::SkipFeeCharge); let mut db = context .execution_storage @@ -102,7 +123,7 @@ impl crate::dto::serialize::SerializeForVersion for TransactionSimulation<'_> { serializer.serialize_field( "transaction_trace", &crate::dto::TransactionTrace { - trace: &self.0.trace, + trace: self.0.trace.clone(), include_state_diff: true, }, )?; @@ -177,19 +198,23 @@ impl From for SimulateTransactionError { #[cfg(test)] pub(crate) mod tests { + use std::collections::{BTreeMap, HashSet}; + use pathfinder_common::macro_prelude::*; use pathfinder_common::{ felt, + BlockHeader, BlockId, - CallParam, ClassHash, + ContractAddress, EntryPoint, StarknetVersion, + StorageAddress, StorageValue, TransactionVersion, }; use pathfinder_crypto::Felt; - use serde::Deserialize; + use pathfinder_storage::Storage; use starknet_gateway_test_fixtures::class_definitions::{ DUMMY_ACCOUNT_CLASS_HASH, ERC20_CONTRACT_DEFINITION_CLASS_HASH, @@ -198,19 +223,47 @@ pub(crate) mod tests { use super::simulate_transactions; use crate::context::RpcContext; use crate::dto::serialize::{SerializeForVersion, Serializer}; - use crate::method::get_state_update::types::{DeployedContract, Nonce, StateDiff}; + use crate::dto::DeserializeForVersion; + use crate::method::simulate_transactions::SimulateTransactionInput; use crate::types::request::{ BroadcastedDeclareTransaction, BroadcastedDeclareTransactionV1, BroadcastedTransaction, }; - use crate::types::ContractClass; - use crate::v06::method::call::FunctionCall; - use crate::v06::method::simulate_transactions::tests::setup_storage_with_starknet_version; - use crate::v06::method::simulate_transactions::{dto, SimulateTransactionInput}; - use crate::v06::types::PriceUnit; use crate::RpcVersion; + pub(crate) async fn setup_storage_with_starknet_version( + version: StarknetVersion, + ) -> ( + Storage, + BlockHeader, + ContractAddress, + ContractAddress, + StorageValue, + ) { + let test_storage_key = StorageAddress::from_name(b"my_storage_var"); + let test_storage_value = storage_value!("0x09"); + + // set test storage variable + let (storage, last_block_header, account_contract_address, universal_deployer_address) = + crate::test_setup::test_storage(version, |state_update| { + state_update.with_storage_update( + fixtures::DEPLOYED_CONTRACT_ADDRESS, + test_storage_key, + test_storage_value, + ) + }) + .await; + + ( + storage, + last_block_header, + account_contract_address, + universal_deployer_address, + test_storage_value, + ) + } + #[tokio::test] async fn test_simulate_transaction_with_skip_fee_charge() { let (context, _, _, _) = crate::test_setup::test_context().await; @@ -231,97 +284,95 @@ pub(crate) mod tests { ], "simulation_flags": ["SKIP_FEE_CHARGE"] }); - let input = SimulateTransactionInput::deserialize(&input_json).unwrap(); - - let expected: Vec = { - use dto::*; - let tx = - SimulatedTransaction { - fee_estimation: - FeeEstimate { - gas_consumed: 19.into(), - gas_price: 1.into(), - data_gas_consumed: Some(160.into()), - data_gas_price: Some(2.into()), - overall_fee: 339.into(), - unit: PriceUnit::Wei, - } - , - transaction_trace: - TransactionTrace::DeployAccount( - DeployAccountTxnTrace { - constructor_invocation: FunctionInvocation { - call_type: CallType::Call, - caller_address: felt!("0x0"), - calls: vec![], - class_hash: Some(DUMMY_ACCOUNT_CLASS_HASH.0), - entry_point_type: EntryPointType::Constructor, - events: vec![], - function_call: FunctionCall { - calldata: vec![], - contract_address: contract_address!("0x00798C1BFDAF2077F4900E37C8815AFFA8D217D46DB8A84C3FBA1838C8BD4A65"), - entry_point_selector: entry_point!("0x028FFE4FF0F226A9107253E17A904099AA4F63A02A5621DE0576E5AA71BC5194"), - }, - messages: vec![], - result: vec![], - execution_resources: ComputationResources::default(), - }, - validate_invocation: Some( - FunctionInvocation { - call_type: CallType::Call, - caller_address: felt!("0x0"), - calls: vec![], - class_hash: Some(DUMMY_ACCOUNT_CLASS_HASH.0), - entry_point_type: EntryPointType::External, - events: vec![], - function_call: FunctionCall { - calldata: vec![ - CallParam(DUMMY_ACCOUNT_CLASS_HASH.0), - call_param!("0x046C0D4ABF0192A788ACA261E58D7031576F7D8EA5229F452B0F23E691DD5971"), - ], - contract_address: contract_address!("0x00798C1BFDAF2077F4900E37C8815AFFA8D217D46DB8A84C3FBA1838C8BD4A65"), - entry_point_selector: entry_point!("0x036FCBF06CD96843058359E1A75928BEACFAC10727DAB22A3972F0AF8AA92895"), - }, - messages: vec![], - result: vec![], - execution_resources: ComputationResources { - steps: 13, - ..Default::default() - }, - }, - ), - fee_transfer_invocation: None, - state_diff: Some(StateDiff { - storage_diffs: vec![], - deprecated_declared_classes: vec![], - declared_classes: vec![], - deployed_contracts: vec![ - DeployedContract { - address: contract_address!("0x00798C1BFDAF2077F4900E37C8815AFFA8D217D46DB8A84C3FBA1838C8BD4A65"), - class_hash: DUMMY_ACCOUNT_CLASS_HASH - } - ], - replaced_classes: vec![], - nonces: vec![ - Nonce { - contract_address: contract_address!("0x00798C1BFDAF2077F4900E37C8815AFFA8D217D46DB8A84C3FBA1838C8BD4A65"), - nonce: contract_nonce!("0x1") - } - ] + + let value = crate::dto::Value::new(input_json, RpcVersion::V07); + let input = SimulateTransactionInput::deserialize(value).unwrap(); + + let expected = crate::method::simulate_transactions::Output(vec![ + pathfinder_executor::types::TransactionSimulation{ + fee_estimation: pathfinder_executor::types::FeeEstimate { + l1_gas_consumed: 19.into(), + l1_gas_price: 1.into(), + l1_data_gas_consumed: 160.into(), + l1_data_gas_price: 2.into(), + l2_gas_consumed: 0.into(), + l2_gas_price: 0.into(), + overall_fee: 339.into(), + unit: pathfinder_executor::types::PriceUnit::Wei, + }, + trace: pathfinder_executor::types::TransactionTrace::DeployAccount( + pathfinder_executor::types::DeployAccountTransactionTrace { + constructor_invocation: Some(pathfinder_executor::types::FunctionInvocation { + call_type: pathfinder_executor::types::CallType::Call, + caller_address: felt!("0x0"), + class_hash: Some(DUMMY_ACCOUNT_CLASS_HASH.0), + entry_point_type: pathfinder_executor::types::EntryPointType::Constructor, + events: vec![], + calldata: vec![], + contract_address: contract_address!("0x00798C1BFDAF2077F4900E37C8815AFFA8D217D46DB8A84C3FBA1838C8BD4A65"), + selector: entry_point!("0x028FFE4FF0F226A9107253E17A904099AA4F63A02A5621DE0576E5AA71BC5194").0, + messages: vec![], + result: vec![], + execution_resources: pathfinder_executor::types::InnerCallExecutionResources::default(), + internal_calls: vec![], + computation_resources: pathfinder_executor::types::ComputationResources::default(), }), - execution_resources: Some(ExecutionResources { - computation_resources: ComputationResources { + validate_invocation: Some( + pathfinder_executor::types::FunctionInvocation { + call_type: pathfinder_executor::types::CallType::Call, + caller_address: felt!("0x0"), + class_hash: Some(DUMMY_ACCOUNT_CLASS_HASH.0), + entry_point_type: pathfinder_executor::types::EntryPointType::External, + events: vec![], + calldata: vec![ + DUMMY_ACCOUNT_CLASS_HASH.0, + call_param!("0x046C0D4ABF0192A788ACA261E58D7031576F7D8EA5229F452B0F23E691DD5971").0, + ], + contract_address: contract_address!("0x00798C1BFDAF2077F4900E37C8815AFFA8D217D46DB8A84C3FBA1838C8BD4A65"), + selector: entry_point!("0x036FCBF06CD96843058359E1A75928BEACFAC10727DAB22A3972F0AF8AA92895").0, + messages: vec![], + result: vec![], + execution_resources: pathfinder_executor::types::InnerCallExecutionResources { + l1_gas: 0, + l2_gas: 0, + }, + internal_calls: vec![], + computation_resources: pathfinder_executor::types::ComputationResources{ steps: 13, ..Default::default() - }, - data_availability: DataAvailabilityResources { l1_gas: 0, l1_data_gas: 160 } - }), + } + }, + ), + fee_transfer_invocation: None, + state_diff: pathfinder_executor::types::StateDiff { + storage_diffs: BTreeMap::new(), + deprecated_declared_classes: HashSet::new(), + declared_classes: vec![], + deployed_contracts: vec![ + pathfinder_executor::types::DeployedContract { + address: contract_address!("0x00798C1BFDAF2077F4900E37C8815AFFA8D217D46DB8A84C3FBA1838C8BD4A65"), + class_hash: DUMMY_ACCOUNT_CLASS_HASH + } + ], + replaced_classes: vec![], + nonces: BTreeMap::from([( + contract_address!("0x00798C1BFDAF2077F4900E37C8815AFFA8D217D46DB8A84C3FBA1838C8BD4A65"), + contract_nonce!("0x1"), + )]), }, - ), - }; - vec![tx] - }; - let expected = serde_json::to_value(expected).unwrap(); + execution_resources: pathfinder_executor::types::ExecutionResources { + computation_resources: pathfinder_executor::types::ComputationResources{steps:13, ..Default::default()}, + data_availability: pathfinder_executor::types::DataAvailabilityResources{l1_gas:0,l1_data_gas:160}, + l1_gas: 0, + l1_data_gas: 160, + l2_gas: 0, + }, + }, + ), + } + ]).serialize(Serializer { + version: RpcVersion::V07, + }).unwrap(); let result = simulate_transactions(context, input).await.expect("result"); let result = result @@ -340,7 +391,7 @@ pub(crate) mod tests { pub const CAIRO0_HASH: ClassHash = class_hash!("02c52e7084728572ea940b4df708a2684677c19fa6296de2ea7ba5327e3a84ef"); - let contract_class = ContractClass::from_definition_bytes(CAIRO0_DEFINITION) + let contract_class = crate::types::ContractClass::from_definition_bytes(CAIRO0_DEFINITION) .unwrap() .as_cairo() .unwrap(); @@ -365,161 +416,296 @@ pub(crate) mod tests { let input = SimulateTransactionInput { block_id: last_block_header.number.into(), transactions: vec![declare], - simulation_flags: dto::SimulationFlags(vec![]), + simulation_flags: crate::dto::SimulationFlags(vec![]), }; - let result = simulate_transactions(context, input).await.unwrap(); - const OVERALL_FEE: u64 = 15720; - use dto::*; - - use crate::method::get_state_update::types::{StorageDiff, StorageEntry}; - pretty_assertions_sorted::assert_eq!( - result.serialize(Serializer { - version: RpcVersion::V07, - }).unwrap(), - serde_json::to_value( - vec![SimulatedTransaction { - fee_estimation: FeeEstimate { - gas_consumed: 15464.into(), - gas_price: 1.into(), - data_gas_consumed: Some(128.into()), - data_gas_price: Some(2.into()), - overall_fee: 15720.into(), - unit: PriceUnit::Wei, - }, - transaction_trace: TransactionTrace::Declare(DeclareTxnTrace { - fee_transfer_invocation: Some( - FunctionInvocation { - call_type: CallType::Call, - caller_address: *account_contract_address.get(), - calls: vec![], - class_hash: Some(ERC20_CONTRACT_DEFINITION_CLASS_HASH.0), - entry_point_type: EntryPointType::External, - events: vec![OrderedEvent { - order: 0, - data: vec![ - *account_contract_address.get(), - last_block_header.sequencer_address.0, - Felt::from_u64(OVERALL_FEE), - felt!("0x0"), - ], - keys: vec![felt!( - "0x0099CD8BDE557814842A3121E8DDFD433A539B8C9F14BF31EBF108D12E6196E9" - )], - }], - function_call: FunctionCall { - calldata: vec![ - CallParam(last_block_header.sequencer_address.0), - CallParam(Felt::from_u64(OVERALL_FEE)), - call_param!("0x0"), - ], - contract_address: pathfinder_executor::ETH_FEE_TOKEN_ADDRESS, - entry_point_selector: EntryPoint::hashed(b"transfer"), - }, - messages: vec![], - result: vec![felt!("0x1")], - execution_resources: ComputationResources { - steps: 1354, - memory_holes: 59, - range_check_builtin_applications: 31, - pedersen_builtin_applications: 4, - ..Default::default() - }, - } - ), - validate_invocation: Some( - FunctionInvocation { - call_type: CallType::Call, - caller_address: felt!("0x0"), - calls: vec![], - class_hash: Some(DUMMY_ACCOUNT_CLASS_HASH.0), - entry_point_type: EntryPointType::External, - events: vec![], - function_call: FunctionCall { - contract_address: account_contract_address, - entry_point_selector: EntryPoint::hashed(b"__validate_declare__"), - calldata: vec![CallParam(CAIRO0_HASH.0)], - }, - messages: vec![], - result: vec![], - execution_resources: ComputationResources { - steps: 12, - ..Default::default() - }, - } - ), - state_diff: Some(StateDiff { - storage_diffs: vec![StorageDiff { - address: pathfinder_executor::ETH_FEE_TOKEN_ADDRESS, - storage_entries: vec![ - StorageEntry { - key: storage_address!("0x032a4edd4e4cffa71ee6d0971c54ac9e62009526cd78af7404aa968c3dc3408e"), - value: storage_value!("0x000000000000000000000000000000000000ffffffffffffffffffffffffc298") - }, - StorageEntry { - key: storage_address!("0x05496768776e3db30053404f18067d81a6e06f5a2b0de326e21298fd9d569a9a"), - value: StorageValue(OVERALL_FEE.into()), - }, + let expected = crate::method::simulate_transactions::Output(vec![ + pathfinder_executor::types::TransactionSimulation{ + trace: pathfinder_executor::types::TransactionTrace::Declare(pathfinder_executor::types::DeclareTransactionTrace { + validate_invocation: Some( + pathfinder_executor::types::FunctionInvocation { + call_type: pathfinder_executor::types::CallType::Call, + caller_address: felt!("0x0"), + class_hash: Some(DUMMY_ACCOUNT_CLASS_HASH.0), + entry_point_type: pathfinder_executor::types::EntryPointType::External, + events: vec![], + contract_address: account_contract_address, + selector: EntryPoint::hashed(b"__validate_declare__").0, + calldata: vec![CAIRO0_HASH.0], + messages: vec![], + result: vec![], + execution_resources: pathfinder_executor::types::InnerCallExecutionResources::default(), + internal_calls: vec![], + computation_resources: pathfinder_executor::types::ComputationResources{ + steps: 12, + ..Default::default() + }, + } + ), + fee_transfer_invocation: Some( + pathfinder_executor::types::FunctionInvocation { + call_type: pathfinder_executor::types::CallType::Call, + caller_address: *account_contract_address.get(), + class_hash: Some(ERC20_CONTRACT_DEFINITION_CLASS_HASH.0), + entry_point_type: pathfinder_executor::types::EntryPointType::External, + events: vec![pathfinder_executor::types::Event { + order: 0, + data: vec![ + *account_contract_address.get(), + last_block_header.sequencer_address.0, + Felt::from_u64(OVERALL_FEE), + felt!("0x0"), ], + keys: vec![felt!( + "0x0099CD8BDE557814842A3121E8DDFD433A539B8C9F14BF31EBF108D12E6196E9" + )], }], - deprecated_declared_classes: vec![ - CAIRO0_HASH + calldata: vec![ + last_block_header.sequencer_address.0, + Felt::from_u64(OVERALL_FEE), + call_param!("0x0").0, ], - declared_classes: vec![], - deployed_contracts: vec![], - replaced_classes: vec![], - nonces: vec![Nonce { - contract_address: account_contract_address, - nonce: contract_nonce!("0x1"), - }], - }), - execution_resources: Some(ExecutionResources { - computation_resources: ComputationResources { - steps: 1366, + contract_address: pathfinder_executor::ETH_FEE_TOKEN_ADDRESS, + selector: EntryPoint::hashed(b"transfer").0, + messages: vec![], + result: vec![felt!("0x1")], + execution_resources: pathfinder_executor::types::InnerCallExecutionResources::default(), + internal_calls: vec![], + computation_resources: pathfinder_executor::types::ComputationResources{ + steps: 1354, memory_holes: 59, range_check_builtin_applications: 31, pedersen_builtin_applications: 4, ..Default::default() }, - data_availability: DataAvailabilityResources { - l1_gas: 0, - l1_data_gas: 128, - } - }), - }), - }] - ).unwrap() + } + ), + state_diff: pathfinder_executor::types::StateDiff { + storage_diffs: BTreeMap::from([ + (pathfinder_executor::ETH_FEE_TOKEN_ADDRESS, vec![ + pathfinder_executor::types::StorageDiff { + key: storage_address!("0x032a4edd4e4cffa71ee6d0971c54ac9e62009526cd78af7404aa968c3dc3408e"), + value: storage_value!("0x000000000000000000000000000000000000ffffffffffffffffffffffffc298"), + }, + pathfinder_executor::types::StorageDiff { + key: storage_address!("0x05496768776e3db30053404f18067d81a6e06f5a2b0de326e21298fd9d569a9a"), + value: StorageValue(OVERALL_FEE.into()), + }, + ]), + ]), + deprecated_declared_classes: HashSet::from([ + CAIRO0_HASH + ]), + declared_classes: vec![], + deployed_contracts: vec![], + replaced_classes: vec![], + nonces: BTreeMap::from([ + (account_contract_address, contract_nonce!("0x1")), + ]), + }, + execution_resources: pathfinder_executor::types::ExecutionResources{ + computation_resources: pathfinder_executor::types::ComputationResources{ + steps: 1366, + memory_holes: 59, + range_check_builtin_applications: 31, + pedersen_builtin_applications: 4, + ..Default::default() + }, + data_availability: pathfinder_executor::types::DataAvailabilityResources{ + l1_gas: 0, + l1_data_gas: 128, + }, + l1_gas: 0, + l1_data_gas: 128, + l2_gas: 0, + }, + }), + fee_estimation: pathfinder_executor::types::FeeEstimate { + l1_gas_consumed: 15464.into(), + l1_gas_price: 1.into(), + l1_data_gas_consumed: 128.into(), + l1_data_gas_price: 2.into(), + l2_gas_consumed: 0.into(), + l2_gas_price: 0.into(), + overall_fee: 15720.into(), + unit: pathfinder_executor::types::PriceUnit::Wei, + } + } + ]).serialize(Serializer { + version: RpcVersion::V07, + }).unwrap(); + + let result = simulate_transactions(context, input).await.unwrap(); + + pretty_assertions_sorted::assert_eq!( + result + .serialize(Serializer { + version: RpcVersion::V07, + }) + .unwrap(), + expected ); } pub(crate) mod fixtures { + use pathfinder_common::{CasmHash, ContractAddress, Fee}; + use super::*; - pub use crate::v06::method::simulate_transactions::tests::fixtures::{ - CASM_DEFINITION, - CASM_HASH, - DEPLOYED_CONTRACT_ADDRESS, - SIERRA_DEFINITION, - SIERRA_HASH, - UNIVERSAL_DEPLOYER_CLASS_HASH, - }; - // The input transactions are the same as in v06. + pub const SIERRA_DEFINITION: &[u8] = + include_bytes!("../../fixtures/contracts/storage_access.json"); + pub const SIERRA_HASH: ClassHash = + class_hash!("0544b92d358447cb9e50b65092b7169f931d29e05c1404a2cd08c6fd7e32ba90"); + pub const CASM_HASH: CasmHash = + casm_hash!("0x069032ff71f77284e1a0864a573007108ca5cc08089416af50f03260f5d6d4d8"); + pub const CASM_DEFINITION: &[u8] = + include_bytes!("../../fixtures/contracts/storage_access.casm"); + const MAX_FEE: Fee = Fee(Felt::from_u64(10_000_000)); + pub const DEPLOYED_CONTRACT_ADDRESS: ContractAddress = + contract_address!("0x012592426632af714f43ccb05536b6044fc3e897fa55288f658731f93590e7e7"); + pub const UNIVERSAL_DEPLOYER_CLASS_HASH: ClassHash = + class_hash!("0x06f38fb91ddbf325a0625533576bb6f6eafd9341868a9ec3faa4b01ce6c4f4dc"); + + // The input transactions are the same as in v04. pub mod input { - pub use crate::v06::method::simulate_transactions::tests::fixtures::input::*; + use pathfinder_common::{ + CallParam, + EntryPoint, + ResourceAmount, + ResourcePricePerUnit, + Tip, + }; + + use super::*; + use crate::types::request::{ + BroadcastedDeclareTransactionV2, + BroadcastedInvokeTransaction, + BroadcastedInvokeTransactionV1, + BroadcastedInvokeTransactionV3, + BroadcastedTransaction, + }; + use crate::types::{ResourceBound, ResourceBounds}; + + pub fn declare(account_contract_address: ContractAddress) -> BroadcastedTransaction { + let contract_class = + crate::types::ContractClass::from_definition_bytes(SIERRA_DEFINITION) + .unwrap() + .as_sierra() + .unwrap(); + + assert_eq!(contract_class.class_hash().unwrap().hash(), SIERRA_HASH); + + BroadcastedTransaction::Declare(BroadcastedDeclareTransaction::V2( + BroadcastedDeclareTransactionV2 { + version: TransactionVersion::TWO, + max_fee: MAX_FEE, + signature: vec![], + nonce: transaction_nonce!("0x0"), + contract_class, + sender_address: account_contract_address, + compiled_class_hash: CASM_HASH, + }, + )) + } + + pub fn universal_deployer( + account_contract_address: ContractAddress, + universal_deployer_address: ContractAddress, + ) -> BroadcastedTransaction { + BroadcastedTransaction::Invoke(BroadcastedInvokeTransaction::V1( + BroadcastedInvokeTransactionV1 { + nonce: transaction_nonce!("0x1"), + version: TransactionVersion::ONE, + max_fee: MAX_FEE, + signature: vec![], + sender_address: account_contract_address, + calldata: vec![ + CallParam(*universal_deployer_address.get()), + // Entry point selector for the called contract, i.e. + // AccountCallArray::selector + CallParam(EntryPoint::hashed(b"deployContract").0), + // Length of the call data for the called contract, i.e. + // AccountCallArray::data_len + call_param!("4"), + // classHash + CallParam(SIERRA_HASH.0), + // salt + call_param!("0x0"), + // unique + call_param!("0x0"), + // calldata_len + call_param!("0x0"), + ], + }, + )) + } + + pub fn invoke(account_contract_address: ContractAddress) -> BroadcastedTransaction { + BroadcastedTransaction::Invoke(BroadcastedInvokeTransaction::V1( + BroadcastedInvokeTransactionV1 { + nonce: transaction_nonce!("0x2"), + version: TransactionVersion::ONE, + max_fee: MAX_FEE, + signature: vec![], + sender_address: account_contract_address, + calldata: vec![ + CallParam(*DEPLOYED_CONTRACT_ADDRESS.get()), + // Entry point selector for the called contract, i.e. + // AccountCallArray::selector + CallParam(EntryPoint::hashed(b"get_data").0), + // Length of the call data for the called contract, i.e. + // AccountCallArray::data_len + call_param!("0"), + ], + }, + )) + } + + pub fn invoke_v3(account_contract_address: ContractAddress) -> BroadcastedTransaction { + BroadcastedTransaction::Invoke(BroadcastedInvokeTransaction::V3( + BroadcastedInvokeTransactionV3 { + version: TransactionVersion::THREE, + signature: vec![], + nonce: transaction_nonce!("0x3"), + resource_bounds: ResourceBounds { + l1_gas: ResourceBound { + max_amount: ResourceAmount(10000), + max_price_per_unit: ResourcePricePerUnit(100000000), + }, + l2_gas: ResourceBound { + max_amount: ResourceAmount(10000), + max_price_per_unit: ResourcePricePerUnit(100000000), + }, + l1_data_gas: None, + }, + tip: Tip(0), + paymaster_data: vec![], + account_deployment_data: vec![], + nonce_data_availability_mode: crate::types::DataAvailabilityMode::L1, + fee_data_availability_mode: crate::types::DataAvailabilityMode::L1, + sender_address: account_contract_address, + calldata: vec![ + CallParam(*DEPLOYED_CONTRACT_ADDRESS.get()), + // Entry point selector for the called contract, i.e. + // AccountCallArray::selector + CallParam(EntryPoint::hashed(b"get_data").0), + // Length of the call data for the called contract, i.e. + // AccountCallArray::data_len + call_param!("0"), + ], + }, + )) + } } pub mod expected_output_0_13_1_1 { + use pathfinder_common::{BlockHeader, ContractAddress, SierraHash, StorageValue}; - use super::dto::*; use super::*; - use crate::method::get_state_update::types::{ - DeclaredSierraClass, - StorageDiff, - StorageEntry, - }; + use crate::method::get_state_update::types::{StorageDiff, StorageEntry}; const DECLARE_OVERALL_FEE: u64 = 1262; const DECLARE_GAS_CONSUMED: u64 = 878; @@ -528,108 +714,134 @@ pub(crate) mod tests { pub fn declare( account_contract_address: ContractAddress, last_block_header: &BlockHeader, - ) -> SimulatedTransaction { - SimulatedTransaction { - fee_estimation: FeeEstimate { - gas_consumed: DECLARE_GAS_CONSUMED.into(), - gas_price: 1.into(), - data_gas_consumed: Some(DECLARE_DATA_GAS_CONSUMED.into()), - data_gas_price: Some(2.into()), + ) -> pathfinder_executor::types::TransactionSimulation { + pathfinder_executor::types::TransactionSimulation { + fee_estimation: pathfinder_executor::types::FeeEstimate { + l1_gas_consumed: DECLARE_GAS_CONSUMED.into(), + l1_gas_price: 1.into(), + l1_data_gas_consumed: DECLARE_DATA_GAS_CONSUMED.into(), + l1_data_gas_price: 2.into(), + l2_gas_consumed: 0.into(), + l2_gas_price: 0.into(), overall_fee: DECLARE_OVERALL_FEE.into(), - unit: PriceUnit::Wei, + unit: pathfinder_executor::types::PriceUnit::Wei, }, - transaction_trace: TransactionTrace::Declare(DeclareTxnTrace { - fee_transfer_invocation: Some(declare_fee_transfer( - account_contract_address, - last_block_header, - )), - validate_invocation: Some(declare_validate(account_contract_address)), - state_diff: Some(declare_state_diff( - account_contract_address, - declare_fee_transfer_storage_diffs(), - )), - execution_resources: Some(ExecutionResources { - computation_resources: declare_validate_computation_resources() - + declare_fee_transfer_computation_resources(), - data_availability: DataAvailabilityResources { + trace: pathfinder_executor::types::TransactionTrace::Declare( + pathfinder_executor::types::DeclareTransactionTrace { + fee_transfer_invocation: Some(declare_fee_transfer( + account_contract_address, + last_block_header, + )), + validate_invocation: Some(declare_validate(account_contract_address)), + state_diff: declare_state_diff( + account_contract_address, + declare_fee_transfer_storage_diffs(), + ), + execution_resources: pathfinder_executor::types::ExecutionResources { + computation_resources: declare_validate_computation_resources() + + declare_fee_transfer_computation_resources(), + data_availability: + pathfinder_executor::types::DataAvailabilityResources { + l1_gas: 0, + l1_data_gas: 192, + }, l1_gas: 0, l1_data_gas: 192, + l2_gas: 0, }, - }), - }), + }, + ), } } pub fn declare_without_fee_transfer( account_contract_address: ContractAddress, - ) -> SimulatedTransaction { - SimulatedTransaction { - fee_estimation: FeeEstimate { - gas_consumed: DECLARE_GAS_CONSUMED.into(), - gas_price: 1.into(), - data_gas_consumed: Some(DECLARE_DATA_GAS_CONSUMED.into()), - data_gas_price: Some(2.into()), + ) -> pathfinder_executor::types::TransactionSimulation { + pathfinder_executor::types::TransactionSimulation { + fee_estimation: pathfinder_executor::types::FeeEstimate { + l1_gas_consumed: DECLARE_GAS_CONSUMED.into(), + l1_gas_price: 1.into(), + l1_data_gas_consumed: DECLARE_DATA_GAS_CONSUMED.into(), + l1_data_gas_price: 2.into(), + l2_gas_consumed: 0.into(), + l2_gas_price: 0.into(), overall_fee: DECLARE_OVERALL_FEE.into(), - unit: PriceUnit::Wei, + unit: pathfinder_executor::types::PriceUnit::Wei, }, - transaction_trace: TransactionTrace::Declare(DeclareTxnTrace { - fee_transfer_invocation: None, - validate_invocation: Some(declare_validate(account_contract_address)), - state_diff: Some(declare_state_diff(account_contract_address, vec![])), - execution_resources: Some(ExecutionResources { - computation_resources: declare_validate_computation_resources(), - data_availability: DataAvailabilityResources { + trace: pathfinder_executor::types::TransactionTrace::Declare( + pathfinder_executor::types::DeclareTransactionTrace { + fee_transfer_invocation: None, + validate_invocation: Some(declare_validate(account_contract_address)), + state_diff: declare_state_diff(account_contract_address, vec![]), + execution_resources: pathfinder_executor::types::ExecutionResources { + computation_resources: declare_validate_computation_resources(), + data_availability: + pathfinder_executor::types::DataAvailabilityResources { + l1_gas: 0, + l1_data_gas: 192, + }, l1_gas: 0, l1_data_gas: 192, + l2_gas: 0, }, - }), - }), + }, + ), } } pub fn declare_without_validate( account_contract_address: ContractAddress, last_block_header: &BlockHeader, - ) -> SimulatedTransaction { - SimulatedTransaction { - fee_estimation: FeeEstimate { - gas_consumed: DECLARE_GAS_CONSUMED.into(), - gas_price: 1.into(), - data_gas_consumed: Some(DECLARE_DATA_GAS_CONSUMED.into()), - data_gas_price: Some(2.into()), + ) -> pathfinder_executor::types::TransactionSimulation { + pathfinder_executor::types::TransactionSimulation { + fee_estimation: pathfinder_executor::types::FeeEstimate { + l1_gas_consumed: DECLARE_GAS_CONSUMED.into(), + l1_gas_price: 1.into(), + l1_data_gas_consumed: DECLARE_DATA_GAS_CONSUMED.into(), + l1_data_gas_price: 2.into(), + l2_gas_consumed: 0.into(), + l2_gas_price: 0.into(), overall_fee: DECLARE_OVERALL_FEE.into(), - unit: PriceUnit::Wei, + unit: pathfinder_executor::types::PriceUnit::Wei, }, - transaction_trace: TransactionTrace::Declare(DeclareTxnTrace { - fee_transfer_invocation: Some(declare_fee_transfer( - account_contract_address, - last_block_header, - )), - validate_invocation: None, - state_diff: Some(declare_state_diff( - account_contract_address, - declare_fee_transfer_storage_diffs(), - )), - execution_resources: Some(ExecutionResources { - computation_resources: declare_fee_transfer_computation_resources(), - data_availability: DataAvailabilityResources { + trace: pathfinder_executor::types::TransactionTrace::Declare( + pathfinder_executor::types::DeclareTransactionTrace { + fee_transfer_invocation: Some(declare_fee_transfer( + account_contract_address, + last_block_header, + )), + validate_invocation: None, + state_diff: declare_state_diff( + account_contract_address, + declare_fee_transfer_storage_diffs(), + ), + execution_resources: pathfinder_executor::types::ExecutionResources { + computation_resources: declare_fee_transfer_computation_resources(), + data_availability: + pathfinder_executor::types::DataAvailabilityResources { + l1_gas: 0, + l1_data_gas: 192, + }, l1_gas: 0, l1_data_gas: 192, + l2_gas: 0, }, - }), - }), + }, + ), } } - fn declare_validate_computation_resources() -> ComputationResources { - ComputationResources { + fn declare_validate_computation_resources( + ) -> pathfinder_executor::types::ComputationResources { + pathfinder_executor::types::ComputationResources { steps: 12, ..Default::default() } } - fn declare_fee_transfer_computation_resources() -> ComputationResources { - ComputationResources { + fn declare_fee_transfer_computation_resources( + ) -> pathfinder_executor::types::ComputationResources { + pathfinder_executor::types::ComputationResources { steps: 1354, memory_holes: 59, range_check_builtin_applications: 31, @@ -641,20 +853,33 @@ pub(crate) mod tests { fn declare_state_diff( account_contract_address: ContractAddress, storage_diffs: Vec, - ) -> StateDiff { - StateDiff { - storage_diffs, - deprecated_declared_classes: vec![], - declared_classes: vec![DeclaredSierraClass { + ) -> pathfinder_executor::types::StateDiff { + pathfinder_executor::types::StateDiff { + storage_diffs: BTreeMap::from_iter( + storage_diffs + .into_iter() + .map(|diff| { + ( + diff.address, + diff.storage_entries + .into_iter() + .map(|entry| pathfinder_executor::types::StorageDiff { + key: entry.key, + value: entry.value, + }) + .collect(), + ) + }) + .collect::>(), + ), + deprecated_declared_classes: HashSet::new(), + declared_classes: vec![pathfinder_executor::types::DeclaredSierraClass { class_hash: SierraHash(SIERRA_HASH.0), compiled_class_hash: CASM_HASH, }], deployed_contracts: vec![], replaced_classes: vec![], - nonces: vec![Nonce { - contract_address: account_contract_address, - nonce: contract_nonce!("0x1"), - }], + nonces: BTreeMap::from([(account_contract_address, contract_nonce!("0x1"))]), } } @@ -677,14 +902,13 @@ pub(crate) mod tests { fn declare_fee_transfer( account_contract_address: ContractAddress, last_block_header: &BlockHeader, - ) -> FunctionInvocation { - FunctionInvocation { - call_type: CallType::Call, + ) -> pathfinder_executor::types::FunctionInvocation { + pathfinder_executor::types::FunctionInvocation { + call_type: pathfinder_executor::types::CallType::Call, caller_address: *account_contract_address.get(), - calls: vec![], class_hash: Some(ERC20_CONTRACT_DEFINITION_CLASS_HASH.0), - entry_point_type: EntryPointType::External, - events: vec![OrderedEvent { + entry_point_type: pathfinder_executor::types::EntryPointType::External, + events: vec![pathfinder_executor::types::Event { order: 0, data: vec![ *account_contract_address.get(), @@ -696,37 +920,40 @@ pub(crate) mod tests { "0x0099CD8BDE557814842A3121E8DDFD433A539B8C9F14BF31EBF108D12E6196E9" )], }], - function_call: FunctionCall { - calldata: vec![ - CallParam(last_block_header.sequencer_address.0), - CallParam(Felt::from_u64(DECLARE_OVERALL_FEE)), - call_param!("0x0"), - ], - contract_address: pathfinder_executor::ETH_FEE_TOKEN_ADDRESS, - entry_point_selector: EntryPoint::hashed(b"transfer"), - }, + calldata: vec![ + last_block_header.sequencer_address.0, + Felt::from_u64(DECLARE_OVERALL_FEE), + felt!("0x0"), + ], + contract_address: pathfinder_executor::ETH_FEE_TOKEN_ADDRESS, + selector: EntryPoint::hashed(b"transfer").0, + internal_calls: vec![], messages: vec![], result: vec![felt!("0x1")], - execution_resources: declare_fee_transfer_computation_resources(), + computation_resources: declare_fee_transfer_computation_resources(), + execution_resources: + pathfinder_executor::types::InnerCallExecutionResources::default(), } } - fn declare_validate(account_contract_address: ContractAddress) -> FunctionInvocation { - FunctionInvocation { - call_type: CallType::Call, + fn declare_validate( + account_contract_address: ContractAddress, + ) -> pathfinder_executor::types::FunctionInvocation { + pathfinder_executor::types::FunctionInvocation { + call_type: pathfinder_executor::types::CallType::Call, caller_address: felt!("0x0"), - calls: vec![], class_hash: Some(DUMMY_ACCOUNT_CLASS_HASH.0), - entry_point_type: EntryPointType::External, + entry_point_type: pathfinder_executor::types::EntryPointType::External, events: vec![], - function_call: FunctionCall { - contract_address: account_contract_address, - entry_point_selector: EntryPoint::hashed(b"__validate_declare__"), - calldata: vec![CallParam(SIERRA_HASH.0)], - }, + contract_address: account_contract_address, + selector: EntryPoint::hashed(b"__validate_declare__").0, + calldata: vec![SIERRA_HASH.0], + internal_calls: vec![], messages: vec![], result: vec![], - execution_resources: declare_validate_computation_resources(), + computation_resources: declare_validate_computation_resources(), + execution_resources: + pathfinder_executor::types::InnerCallExecutionResources::default(), } } @@ -738,88 +965,106 @@ pub(crate) mod tests { account_contract_address: ContractAddress, last_block_header: &BlockHeader, universal_deployer_address: ContractAddress, - ) -> SimulatedTransaction { - SimulatedTransaction { - fee_estimation: FeeEstimate { - gas_consumed: UNIVERSAL_DEPLOYER_GAS_CONSUMED.into(), - gas_price: 1.into(), - data_gas_consumed: Some(UNIVERSAL_DEPLOYER_DATA_GAS_CONSUMED.into()), - data_gas_price: Some(2.into()), + ) -> pathfinder_executor::types::TransactionSimulation { + pathfinder_executor::types::TransactionSimulation { + fee_estimation: pathfinder_executor::types::FeeEstimate { + l1_gas_consumed: UNIVERSAL_DEPLOYER_GAS_CONSUMED.into(), + l1_gas_price: 1.into(), + l1_data_gas_consumed: UNIVERSAL_DEPLOYER_DATA_GAS_CONSUMED.into(), + l1_data_gas_price: 2.into(), + l2_gas_consumed: 0.into(), + l2_gas_price: 0.into(), overall_fee: UNIVERSAL_DEPLOYER_OVERALL_FEE.into(), - unit: PriceUnit::Wei, + unit: pathfinder_executor::types::PriceUnit::Wei, }, - transaction_trace: TransactionTrace::Invoke(InvokeTxnTrace { - validate_invocation: Some(universal_deployer_validate( - account_contract_address, - universal_deployer_address, - )), - execute_invocation: ExecuteInvocation::FunctionInvocation( - universal_deployer_execute( + trace: pathfinder_executor::types::TransactionTrace::Invoke( + pathfinder_executor::types::InvokeTransactionTrace { + validate_invocation: Some(universal_deployer_validate( account_contract_address, universal_deployer_address, + )), + execute_invocation: + pathfinder_executor::types::ExecuteInvocation::FunctionInvocation( + Some(universal_deployer_execute( + account_contract_address, + universal_deployer_address, + )), + ), + fee_transfer_invocation: Some(universal_deployer_fee_transfer( + account_contract_address, + last_block_header, + )), + state_diff: universal_deployer_state_diff( + account_contract_address, + universal_deployer_fee_transfer_storage_diffs(), ), - ), - fee_transfer_invocation: Some(universal_deployer_fee_transfer( - account_contract_address, - last_block_header, - )), - state_diff: Some(universal_deployer_state_diff( - account_contract_address, - universal_deployer_fee_transfer_storage_diffs(), - )), - execution_resources: Some(ExecutionResources { - computation_resources: universal_deployer_validate_computation_resources( - ) - + universal_deployer_execute_computation_resources() - + universal_deployer_fee_transfer_computation_resources(), - data_availability: DataAvailabilityResources { + execution_resources: pathfinder_executor::types::ExecutionResources { + computation_resources: + universal_deployer_validate_computation_resources() + + universal_deployer_execute_computation_resources() + + universal_deployer_fee_transfer_computation_resources(), + data_availability: + pathfinder_executor::types::DataAvailabilityResources { + l1_gas: 0, + l1_data_gas: 224, + }, l1_gas: 0, l1_data_gas: 224, + l2_gas: 0, }, - }), - }), + }, + ), } } pub fn universal_deployer_without_fee_transfer( account_contract_address: ContractAddress, universal_deployer_address: ContractAddress, - ) -> SimulatedTransaction { - SimulatedTransaction { - fee_estimation: FeeEstimate { - gas_consumed: UNIVERSAL_DEPLOYER_GAS_CONSUMED.into(), - gas_price: 1.into(), - data_gas_consumed: Some(UNIVERSAL_DEPLOYER_DATA_GAS_CONSUMED.into()), - data_gas_price: Some(2.into()), + ) -> pathfinder_executor::types::TransactionSimulation { + pathfinder_executor::types::TransactionSimulation { + fee_estimation: pathfinder_executor::types::FeeEstimate { + l1_gas_consumed: UNIVERSAL_DEPLOYER_GAS_CONSUMED.into(), + l1_gas_price: 1.into(), + l1_data_gas_consumed: UNIVERSAL_DEPLOYER_DATA_GAS_CONSUMED.into(), + l1_data_gas_price: 2.into(), + l2_gas_consumed: 0.into(), + l2_gas_price: 0.into(), overall_fee: UNIVERSAL_DEPLOYER_OVERALL_FEE.into(), - unit: PriceUnit::Wei, + unit: pathfinder_executor::types::PriceUnit::Wei, }, - transaction_trace: TransactionTrace::Invoke(InvokeTxnTrace { - validate_invocation: Some(universal_deployer_validate( - account_contract_address, - universal_deployer_address, - )), - execute_invocation: ExecuteInvocation::FunctionInvocation( - universal_deployer_execute( + trace: pathfinder_executor::types::TransactionTrace::Invoke( + pathfinder_executor::types::InvokeTransactionTrace { + validate_invocation: Some(universal_deployer_validate( account_contract_address, universal_deployer_address, + )), + execute_invocation: + pathfinder_executor::types::ExecuteInvocation::FunctionInvocation( + Some(universal_deployer_execute( + account_contract_address, + universal_deployer_address, + )), + ), + fee_transfer_invocation: None, + state_diff: universal_deployer_state_diff( + account_contract_address, + vec![], ), - ), - fee_transfer_invocation: None, - state_diff: Some(universal_deployer_state_diff( - account_contract_address, - vec![], - )), - execution_resources: Some(ExecutionResources { - computation_resources: universal_deployer_validate_computation_resources( - ) - + universal_deployer_execute_computation_resources(), - data_availability: DataAvailabilityResources { + execution_resources: pathfinder_executor::types::ExecutionResources { + computation_resources: + universal_deployer_validate_computation_resources() + + universal_deployer_execute_computation_resources(), + data_availability: + pathfinder_executor::types::DataAvailabilityResources { + l1_gas: 0, + l1_data_gas: 224, + }, l1_gas: 0, l1_data_gas: 224, + l2_gas: 0, }, - }), - }), + }, + ), } } @@ -827,55 +1072,66 @@ pub(crate) mod tests { account_contract_address: ContractAddress, last_block_header: &BlockHeader, universal_deployer_address: ContractAddress, - ) -> SimulatedTransaction { - SimulatedTransaction { - fee_estimation: FeeEstimate { - gas_consumed: UNIVERSAL_DEPLOYER_GAS_CONSUMED.into(), - gas_price: 1.into(), - data_gas_consumed: Some(UNIVERSAL_DEPLOYER_DATA_GAS_CONSUMED.into()), - data_gas_price: Some(2.into()), + ) -> pathfinder_executor::types::TransactionSimulation { + pathfinder_executor::types::TransactionSimulation { + fee_estimation: pathfinder_executor::types::FeeEstimate { + l1_gas_consumed: UNIVERSAL_DEPLOYER_GAS_CONSUMED.into(), + l1_gas_price: 1.into(), + l1_data_gas_consumed: UNIVERSAL_DEPLOYER_DATA_GAS_CONSUMED.into(), + l1_data_gas_price: 2.into(), + l2_gas_consumed: 0.into(), + l2_gas_price: 0.into(), overall_fee: UNIVERSAL_DEPLOYER_OVERALL_FEE.into(), - unit: PriceUnit::Wei, + unit: pathfinder_executor::types::PriceUnit::Wei, }, - transaction_trace: TransactionTrace::Invoke(InvokeTxnTrace { - validate_invocation: None, - execute_invocation: ExecuteInvocation::FunctionInvocation( - universal_deployer_execute( + trace: pathfinder_executor::types::TransactionTrace::Invoke( + pathfinder_executor::types::InvokeTransactionTrace { + validate_invocation: None, + execute_invocation: + pathfinder_executor::types::ExecuteInvocation::FunctionInvocation( + Some(universal_deployer_execute( + account_contract_address, + universal_deployer_address, + )), + ), + fee_transfer_invocation: Some(universal_deployer_fee_transfer( account_contract_address, - universal_deployer_address, + last_block_header, + )), + state_diff: universal_deployer_state_diff( + account_contract_address, + universal_deployer_fee_transfer_storage_diffs(), ), - ), - fee_transfer_invocation: Some(universal_deployer_fee_transfer( - account_contract_address, - last_block_header, - )), - state_diff: Some(universal_deployer_state_diff( - account_contract_address, - universal_deployer_fee_transfer_storage_diffs(), - )), - execution_resources: Some(ExecutionResources { - computation_resources: - universal_deployer_fee_transfer_computation_resources() - + universal_deployer_execute_computation_resources(), - data_availability: DataAvailabilityResources { + execution_resources: pathfinder_executor::types::ExecutionResources { + computation_resources: + universal_deployer_fee_transfer_computation_resources() + + universal_deployer_execute_computation_resources(), + data_availability: + pathfinder_executor::types::DataAvailabilityResources { + l1_gas: 0, + l1_data_gas: 224, + }, l1_gas: 0, l1_data_gas: 224, + l2_gas: 0, }, - }), - }), + }, + ), } } - fn universal_deployer_validate_computation_resources() -> ComputationResources { - ComputationResources { + fn universal_deployer_validate_computation_resources( + ) -> pathfinder_executor::types::ComputationResources { + pathfinder_executor::types::ComputationResources { steps: 21, range_check_builtin_applications: 1, ..Default::default() } } - fn universal_deployer_execute_computation_resources() -> ComputationResources { - ComputationResources { + fn universal_deployer_execute_computation_resources( + ) -> pathfinder_executor::types::ComputationResources { + pathfinder_executor::types::ComputationResources { steps: 2061, memory_holes: 2, range_check_builtin_applications: 44, @@ -884,8 +1140,9 @@ pub(crate) mod tests { } } - fn universal_deployer_fee_transfer_computation_resources() -> ComputationResources { - ComputationResources { + fn universal_deployer_fee_transfer_computation_resources( + ) -> pathfinder_executor::types::ComputationResources { + pathfinder_executor::types::ComputationResources { steps: 1354, memory_holes: 59, range_check_builtin_applications: 31, @@ -897,20 +1154,33 @@ pub(crate) mod tests { fn universal_deployer_state_diff( account_contract_address: ContractAddress, storage_diffs: Vec, - ) -> StateDiff { - StateDiff { - storage_diffs, - deprecated_declared_classes: vec![], + ) -> pathfinder_executor::types::StateDiff { + pathfinder_executor::types::StateDiff { + storage_diffs: BTreeMap::from_iter( + storage_diffs + .into_iter() + .map(|diff| { + ( + diff.address, + diff.storage_entries + .into_iter() + .map(|entry| pathfinder_executor::types::StorageDiff { + key: entry.key, + value: entry.value, + }) + .collect(), + ) + }) + .collect::>(), + ), + deprecated_declared_classes: HashSet::new(), declared_classes: vec![], - deployed_contracts: vec![DeployedContract { + deployed_contracts: vec![pathfinder_executor::types::DeployedContract { address: DEPLOYED_CONTRACT_ADDRESS, class_hash: SIERRA_HASH, }], replaced_classes: vec![], - nonces: vec![Nonce { - contract_address: account_contract_address, - nonce: contract_nonce!("0x2"), - }], + nonces: BTreeMap::from([(account_contract_address, contract_nonce!("0x2"))]), } } @@ -933,71 +1203,70 @@ pub(crate) mod tests { fn universal_deployer_validate( account_contract_address: ContractAddress, universal_deployer_address: ContractAddress, - ) -> FunctionInvocation { - FunctionInvocation { - call_type: CallType::Call, + ) -> pathfinder_executor::types::FunctionInvocation { + pathfinder_executor::types::FunctionInvocation { + call_type: pathfinder_executor::types::CallType::Call, caller_address: felt!("0x0"), - calls: vec![], class_hash: Some(DUMMY_ACCOUNT_CLASS_HASH.0), - entry_point_type: EntryPointType::External, + entry_point_type: pathfinder_executor::types::EntryPointType::External, + internal_calls: vec![], events: vec![], - function_call: FunctionCall { - contract_address: account_contract_address, - entry_point_selector: EntryPoint::hashed(b"__validate__"), - calldata: vec![ - CallParam(universal_deployer_address.0), - CallParam(EntryPoint::hashed(b"deployContract").0), - // calldata_len - call_param!("0x4"), - // classHash - CallParam(SIERRA_HASH.0), - // salt - call_param!("0x0"), - // unique - call_param!("0x0"), - // calldata_len - call_param!("0x0"), - ], - }, + contract_address: account_contract_address, + selector: EntryPoint::hashed(b"__validate__").0, + calldata: vec![ + universal_deployer_address.0, + EntryPoint::hashed(b"deployContract").0, + // calldata_len + call_param!("0x4").0, + // classHash + SIERRA_HASH.0, + // salt + call_param!("0x0").0, + // unique + call_param!("0x0").0, + // calldata_len + call_param!("0x0").0, + ], messages: vec![], result: vec![], - execution_resources: universal_deployer_validate_computation_resources(), + computation_resources: universal_deployer_validate_computation_resources(), + execution_resources: + pathfinder_executor::types::InnerCallExecutionResources::default(), } } fn universal_deployer_execute( account_contract_address: ContractAddress, universal_deployer_address: ContractAddress, - ) -> FunctionInvocation { - FunctionInvocation { - call_type: CallType::Call, + ) -> pathfinder_executor::types::FunctionInvocation { + pathfinder_executor::types::FunctionInvocation { + call_type: pathfinder_executor::types::CallType::Call, caller_address: felt!("0x0"), - calls: vec![ - FunctionInvocation { - call_type: CallType::Call, + internal_calls: vec![ + pathfinder_executor::types::FunctionInvocation { + call_type: pathfinder_executor::types::CallType::Call, caller_address: *account_contract_address.get(), - calls: vec![ - FunctionInvocation { - call_type: CallType::Call, + internal_calls: vec![ + pathfinder_executor::types::FunctionInvocation { + call_type: pathfinder_executor::types::CallType::Call, caller_address: *universal_deployer_address.get(), - calls: vec![], + internal_calls: vec![], class_hash: Some(SIERRA_HASH.0), - entry_point_type: EntryPointType::Constructor, + entry_point_type: pathfinder_executor::types::EntryPointType::Constructor, events: vec![], - function_call: FunctionCall { - contract_address: DEPLOYED_CONTRACT_ADDRESS, - entry_point_selector: EntryPoint::hashed(b"constructor"), - calldata: vec![], - }, + contract_address: DEPLOYED_CONTRACT_ADDRESS, + selector: EntryPoint::hashed(b"constructor").0, + calldata: vec![], messages: vec![], result: vec![], - execution_resources: ComputationResources::default(), + computation_resources: pathfinder_executor::types::ComputationResources::default(), + execution_resources: pathfinder_executor::types::InnerCallExecutionResources::default(), }, ], class_hash: Some(UNIVERSAL_DEPLOYER_CLASS_HASH.0), - entry_point_type: EntryPointType::External, + entry_point_type: pathfinder_executor::types::EntryPointType::External, events: vec![ - OrderedEvent { + pathfinder_executor::types::Event { order: 0, data: vec![ *DEPLOYED_CONTRACT_ADDRESS.get(), @@ -1012,72 +1281,70 @@ pub(crate) mod tests { ] }, ], - function_call: FunctionCall { - contract_address: universal_deployer_address, - entry_point_selector: EntryPoint::hashed(b"deployContract"), - calldata: vec![ - // classHash - CallParam(SIERRA_HASH.0), - // salt - call_param!("0x0"), - // unique - call_param!("0x0"), - // calldata_len - call_param!("0x0"), - ], - }, + contract_address: universal_deployer_address, + selector: EntryPoint::hashed(b"deployContract").0, + calldata: vec![ + // classHash + SIERRA_HASH.0, + // salt + call_param!("0x0").0, + // unique + call_param!("0x0").0, + // calldata_len + call_param!("0x0").0, + ], messages: vec![], result: vec![ *DEPLOYED_CONTRACT_ADDRESS.get(), ], - execution_resources: ComputationResources { + computation_resources: pathfinder_executor::types::ComputationResources { steps: 1262, memory_holes: 2, range_check_builtin_applications: 23, pedersen_builtin_applications: 7, ..Default::default() }, + execution_resources: pathfinder_executor::types::InnerCallExecutionResources::default(), } ], class_hash: Some(DUMMY_ACCOUNT_CLASS_HASH.0), - entry_point_type: EntryPointType::External, + entry_point_type: pathfinder_executor::types::EntryPointType::External, events: vec![], - function_call: FunctionCall { - contract_address: account_contract_address, - entry_point_selector: EntryPoint::hashed(b"__execute__"), - calldata: vec![ - CallParam(universal_deployer_address.0), - CallParam(EntryPoint::hashed(b"deployContract").0), - call_param!("0x4"), - // classHash - CallParam(SIERRA_HASH.0), - // salt - call_param!("0x0"), - // unique - call_param!("0x0"), - // calldata_len - call_param!("0x0"), - ], - }, + contract_address: account_contract_address, + selector: EntryPoint::hashed(b"__execute__").0, + calldata: vec![ + universal_deployer_address.0, + EntryPoint::hashed(b"deployContract").0, + call_param!("0x4").0, + // classHash + SIERRA_HASH.0, + // salt + call_param!("0x0").0, + // unique + call_param!("0x0").0, + // calldata_len + call_param!("0x0").0, + ], messages: vec![], result: vec![ *DEPLOYED_CONTRACT_ADDRESS.get(), ], - execution_resources: universal_deployer_execute_computation_resources(), + computation_resources: universal_deployer_execute_computation_resources(), + execution_resources: pathfinder_executor::types::InnerCallExecutionResources::default(), } } fn universal_deployer_fee_transfer( account_contract_address: ContractAddress, last_block_header: &BlockHeader, - ) -> FunctionInvocation { - FunctionInvocation { - call_type: CallType::Call, + ) -> pathfinder_executor::types::FunctionInvocation { + pathfinder_executor::types::FunctionInvocation { + call_type: pathfinder_executor::types::CallType::Call, caller_address: *account_contract_address.get(), - calls: vec![], + internal_calls: vec![], class_hash: Some(ERC20_CONTRACT_DEFINITION_CLASS_HASH.0), - entry_point_type: EntryPointType::External, - events: vec![OrderedEvent { + entry_point_type: pathfinder_executor::types::EntryPointType::External, + events: vec![pathfinder_executor::types::Event { order: 0, data: vec![ *account_contract_address.get(), @@ -1089,19 +1356,19 @@ pub(crate) mod tests { "0x0099CD8BDE557814842A3121E8DDFD433A539B8C9F14BF31EBF108D12E6196E9" )], }], - function_call: FunctionCall { - calldata: vec![ - CallParam(last_block_header.sequencer_address.0), - CallParam(Felt::from_u64(UNIVERSAL_DEPLOYER_OVERALL_FEE)), - // calldata_len - call_param!("0x0"), - ], - contract_address: pathfinder_executor::ETH_FEE_TOKEN_ADDRESS, - entry_point_selector: EntryPoint::hashed(b"transfer"), - }, + calldata: vec![ + last_block_header.sequencer_address.0, + Felt::from_u64(UNIVERSAL_DEPLOYER_OVERALL_FEE), + // calldata_len + call_param!("0x0").0, + ], + contract_address: pathfinder_executor::ETH_FEE_TOKEN_ADDRESS, + selector: EntryPoint::hashed(b"transfer").0, messages: vec![], result: vec![felt!("0x1")], - execution_resources: universal_deployer_fee_transfer_computation_resources(), + computation_resources: universal_deployer_fee_transfer_computation_resources(), + execution_resources: + pathfinder_executor::types::InnerCallExecutionResources::default(), } } @@ -1113,73 +1380,95 @@ pub(crate) mod tests { account_contract_address: ContractAddress, last_block_header: &BlockHeader, test_storage_value: StorageValue, - ) -> SimulatedTransaction { - SimulatedTransaction { - fee_estimation: FeeEstimate { - gas_consumed: INVOKE_GAS_CONSUMED.into(), - gas_price: 1.into(), - data_gas_consumed: Some(INVOKE_DATA_GAS_CONSUMED.into()), - data_gas_price: Some(2.into()), + ) -> pathfinder_executor::types::TransactionSimulation { + pathfinder_executor::types::TransactionSimulation { + fee_estimation: pathfinder_executor::types::FeeEstimate { + l1_gas_consumed: INVOKE_GAS_CONSUMED.into(), + l1_gas_price: 1.into(), + l1_data_gas_consumed: INVOKE_DATA_GAS_CONSUMED.into(), + l1_data_gas_price: 2.into(), + l2_gas_consumed: 0.into(), + l2_gas_price: 0.into(), overall_fee: INVOKE_OVERALL_FEE.into(), - unit: PriceUnit::Wei, + unit: pathfinder_executor::types::PriceUnit::Wei, }, - transaction_trace: TransactionTrace::Invoke(InvokeTxnTrace { - validate_invocation: Some(invoke_validate(account_contract_address)), - execute_invocation: ExecuteInvocation::FunctionInvocation(invoke_execute( - account_contract_address, - test_storage_value, - )), - fee_transfer_invocation: Some(invoke_fee_transfer( - account_contract_address, - last_block_header, - )), - state_diff: Some(invoke_state_diff( - account_contract_address, - invoke_fee_transfer_storage_diffs(), - )), - execution_resources: Some(ExecutionResources { - computation_resources: invoke_validate_computation_resources() - + invoke_execute_computation_resources() - + invoke_fee_transfer_computation_resources(), - data_availability: DataAvailabilityResources { + trace: pathfinder_executor::types::TransactionTrace::Invoke( + pathfinder_executor::types::InvokeTransactionTrace { + validate_invocation: Some(invoke_validate(account_contract_address)), + execute_invocation: + pathfinder_executor::types::ExecuteInvocation::FunctionInvocation( + Some(invoke_execute( + account_contract_address, + test_storage_value, + )), + ), + fee_transfer_invocation: Some(invoke_fee_transfer( + account_contract_address, + last_block_header, + )), + state_diff: invoke_state_diff( + account_contract_address, + invoke_fee_transfer_storage_diffs(), + ), + execution_resources: pathfinder_executor::types::ExecutionResources { + computation_resources: invoke_validate_computation_resources() + + invoke_execute_computation_resources() + + invoke_fee_transfer_computation_resources(), + data_availability: + pathfinder_executor::types::DataAvailabilityResources { + l1_gas: 0, + l1_data_gas: 128, + }, l1_gas: 0, l1_data_gas: 128, + l2_gas: 0, }, - }), - }), + }, + ), } } pub fn invoke_without_fee_transfer( account_contract_address: ContractAddress, test_storage_value: StorageValue, - ) -> SimulatedTransaction { - SimulatedTransaction { - fee_estimation: FeeEstimate { - gas_consumed: INVOKE_GAS_CONSUMED.into(), - gas_price: 1.into(), - data_gas_consumed: Some(INVOKE_DATA_GAS_CONSUMED.into()), - data_gas_price: Some(2.into()), + ) -> pathfinder_executor::types::TransactionSimulation { + pathfinder_executor::types::TransactionSimulation { + fee_estimation: pathfinder_executor::types::FeeEstimate { + l1_gas_consumed: INVOKE_GAS_CONSUMED.into(), + l1_gas_price: 1.into(), + l1_data_gas_consumed: INVOKE_DATA_GAS_CONSUMED.into(), + l1_data_gas_price: 2.into(), + l2_gas_consumed: 0.into(), + l2_gas_price: 0.into(), overall_fee: INVOKE_OVERALL_FEE.into(), - unit: PriceUnit::Wei, + unit: pathfinder_executor::types::PriceUnit::Wei, }, - transaction_trace: TransactionTrace::Invoke(InvokeTxnTrace { - validate_invocation: Some(invoke_validate(account_contract_address)), - execute_invocation: ExecuteInvocation::FunctionInvocation(invoke_execute( - account_contract_address, - test_storage_value, - )), - fee_transfer_invocation: None, - state_diff: Some(invoke_state_diff(account_contract_address, vec![])), - execution_resources: Some(ExecutionResources { - computation_resources: invoke_execute_computation_resources() - + invoke_validate_computation_resources(), - data_availability: DataAvailabilityResources { - l1_gas: 0, + trace: pathfinder_executor::types::TransactionTrace::Invoke( + pathfinder_executor::types::InvokeTransactionTrace { + validate_invocation: Some(invoke_validate(account_contract_address)), + execute_invocation: + pathfinder_executor::types::ExecuteInvocation::FunctionInvocation( + Some(invoke_execute( + account_contract_address, + test_storage_value, + )), + ), + fee_transfer_invocation: None, + state_diff: invoke_state_diff(account_contract_address, vec![]), + execution_resources: pathfinder_executor::types::ExecutionResources { + computation_resources: invoke_execute_computation_resources() + + invoke_validate_computation_resources(), + data_availability: + pathfinder_executor::types::DataAvailabilityResources { + l1_gas: 0, + l1_data_gas: 128, + }, + l1_gas: 12, l1_data_gas: 128, + l2_gas: 0, }, - }), - }), + }, + ), } } @@ -1187,60 +1476,74 @@ pub(crate) mod tests { account_contract_address: ContractAddress, last_block_header: &BlockHeader, test_storage_value: StorageValue, - ) -> SimulatedTransaction { - SimulatedTransaction { - fee_estimation: FeeEstimate { - gas_consumed: INVOKE_GAS_CONSUMED.into(), - gas_price: 1.into(), - data_gas_consumed: Some(INVOKE_DATA_GAS_CONSUMED.into()), - data_gas_price: Some(2.into()), + ) -> pathfinder_executor::types::TransactionSimulation { + pathfinder_executor::types::TransactionSimulation { + fee_estimation: pathfinder_executor::types::FeeEstimate { + l1_gas_consumed: INVOKE_GAS_CONSUMED.into(), + l1_gas_price: 1.into(), + l1_data_gas_consumed: INVOKE_DATA_GAS_CONSUMED.into(), + l1_data_gas_price: 2.into(), + l2_gas_consumed: 0.into(), + l2_gas_price: 0.into(), overall_fee: INVOKE_OVERALL_FEE.into(), - unit: PriceUnit::Wei, + unit: pathfinder_executor::types::PriceUnit::Wei, }, - transaction_trace: TransactionTrace::Invoke(InvokeTxnTrace { - validate_invocation: None, - execute_invocation: ExecuteInvocation::FunctionInvocation(invoke_execute( - account_contract_address, - test_storage_value, - )), - fee_transfer_invocation: Some(invoke_fee_transfer( - account_contract_address, - last_block_header, - )), - state_diff: Some(invoke_state_diff( - account_contract_address, - invoke_fee_transfer_storage_diffs(), - )), - execution_resources: Some(ExecutionResources { - computation_resources: invoke_execute_computation_resources() - + invoke_fee_transfer_computation_resources(), - data_availability: DataAvailabilityResources { + trace: pathfinder_executor::types::TransactionTrace::Invoke( + pathfinder_executor::types::InvokeTransactionTrace { + validate_invocation: None, + execute_invocation: + pathfinder_executor::types::ExecuteInvocation::FunctionInvocation( + Some(invoke_execute( + account_contract_address, + test_storage_value, + )), + ), + fee_transfer_invocation: Some(invoke_fee_transfer( + account_contract_address, + last_block_header, + )), + state_diff: invoke_state_diff( + account_contract_address, + invoke_fee_transfer_storage_diffs(), + ), + execution_resources: pathfinder_executor::types::ExecutionResources { + computation_resources: invoke_execute_computation_resources() + + invoke_fee_transfer_computation_resources(), + data_availability: + pathfinder_executor::types::DataAvailabilityResources { + l1_gas: 0, + l1_data_gas: 128, + }, l1_gas: 0, l1_data_gas: 128, + l2_gas: 0, }, - }), - }), + }, + ), } } - fn invoke_validate_computation_resources() -> ComputationResources { - ComputationResources { + fn invoke_validate_computation_resources( + ) -> pathfinder_executor::types::ComputationResources { + pathfinder_executor::types::ComputationResources { steps: 21, range_check_builtin_applications: 1, ..Default::default() } } - fn invoke_execute_computation_resources() -> ComputationResources { - ComputationResources { + fn invoke_execute_computation_resources( + ) -> pathfinder_executor::types::ComputationResources { + pathfinder_executor::types::ComputationResources { steps: 964, range_check_builtin_applications: 24, ..Default::default() } } - fn invoke_fee_transfer_computation_resources() -> ComputationResources { - ComputationResources { + fn invoke_fee_transfer_computation_resources( + ) -> pathfinder_executor::types::ComputationResources { + pathfinder_executor::types::ComputationResources { steps: 1354, memory_holes: 59, range_check_builtin_applications: 31, @@ -1252,17 +1555,30 @@ pub(crate) mod tests { fn invoke_state_diff( account_contract_address: ContractAddress, storage_diffs: Vec, - ) -> StateDiff { - StateDiff { - storage_diffs, - deprecated_declared_classes: vec![], + ) -> pathfinder_executor::types::StateDiff { + pathfinder_executor::types::StateDiff { + storage_diffs: BTreeMap::from_iter( + storage_diffs + .into_iter() + .map(|diff| { + ( + diff.address, + diff.storage_entries + .into_iter() + .map(|entry| pathfinder_executor::types::StorageDiff { + key: entry.key, + value: entry.value, + }) + .collect(), + ) + }) + .collect::>(), + ), + deprecated_declared_classes: HashSet::new(), declared_classes: vec![], deployed_contracts: vec![], replaced_classes: vec![], - nonces: vec![Nonce { - contract_address: account_contract_address, - nonce: contract_nonce!("0x3"), - }], + nonces: BTreeMap::from([(account_contract_address, contract_nonce!("0x3"))]), } } @@ -1282,87 +1598,89 @@ pub(crate) mod tests { }] } - fn invoke_validate(account_contract_address: ContractAddress) -> FunctionInvocation { - FunctionInvocation { - call_type: CallType::Call, + fn invoke_validate( + account_contract_address: ContractAddress, + ) -> pathfinder_executor::types::FunctionInvocation { + pathfinder_executor::types::FunctionInvocation { + call_type: pathfinder_executor::types::CallType::Call, caller_address: felt!("0x0"), - calls: vec![], class_hash: Some(DUMMY_ACCOUNT_CLASS_HASH.0), - entry_point_type: EntryPointType::External, + entry_point_type: pathfinder_executor::types::EntryPointType::External, + internal_calls: vec![], events: vec![], - function_call: FunctionCall { - contract_address: account_contract_address, - entry_point_selector: EntryPoint::hashed(b"__validate__"), - calldata: vec![ - CallParam(DEPLOYED_CONTRACT_ADDRESS.0), - CallParam(EntryPoint::hashed(b"get_data").0), - // calldata_len - call_param!("0x0"), - ], - }, + contract_address: account_contract_address, + selector: EntryPoint::hashed(b"__validate__").0, + calldata: vec![ + DEPLOYED_CONTRACT_ADDRESS.0, + EntryPoint::hashed(b"get_data").0, + // calldata_len + call_param!("0x0").0, + ], messages: vec![], result: vec![], - execution_resources: invoke_validate_computation_resources(), + execution_resources: + pathfinder_executor::types::InnerCallExecutionResources::default(), + computation_resources: invoke_validate_computation_resources(), } } fn invoke_execute( account_contract_address: ContractAddress, test_storage_value: StorageValue, - ) -> FunctionInvocation { - FunctionInvocation { - call_type: CallType::Call, + ) -> pathfinder_executor::types::FunctionInvocation { + pathfinder_executor::types::FunctionInvocation { + call_type: pathfinder_executor::types::CallType::Call, caller_address: felt!("0x0"), - calls: vec![FunctionInvocation { - call_type: CallType::Call, + internal_calls: vec![pathfinder_executor::types::FunctionInvocation { + call_type: pathfinder_executor::types::CallType::Call, caller_address: *account_contract_address.get(), - calls: vec![], class_hash: Some(SIERRA_HASH.0), - entry_point_type: EntryPointType::External, + entry_point_type: pathfinder_executor::types::EntryPointType::External, events: vec![], - function_call: FunctionCall { - contract_address: DEPLOYED_CONTRACT_ADDRESS, - entry_point_selector: EntryPoint::hashed(b"get_data"), - calldata: vec![], - }, + internal_calls: vec![], + contract_address: DEPLOYED_CONTRACT_ADDRESS, + selector: EntryPoint::hashed(b"get_data").0, + calldata: vec![], messages: vec![], result: vec![test_storage_value.0], - execution_resources: ComputationResources { + computation_resources: pathfinder_executor::types::ComputationResources { steps: 165, range_check_builtin_applications: 3, ..Default::default() }, + execution_resources: + pathfinder_executor::types::InnerCallExecutionResources::default(), }], class_hash: Some(DUMMY_ACCOUNT_CLASS_HASH.0), - entry_point_type: EntryPointType::External, + entry_point_type: pathfinder_executor::types::EntryPointType::External, events: vec![], - function_call: FunctionCall { - contract_address: account_contract_address, - entry_point_selector: EntryPoint::hashed(b"__execute__"), - calldata: vec![ - CallParam(DEPLOYED_CONTRACT_ADDRESS.0), - CallParam(EntryPoint::hashed(b"get_data").0), - // calldata_len - call_param!("0x0"), - ], - }, + contract_address: account_contract_address, + selector: EntryPoint::hashed(b"__execute__").0, + calldata: vec![ + DEPLOYED_CONTRACT_ADDRESS.0, + EntryPoint::hashed(b"get_data").0, + // calldata_len + call_param!("0x0").0, + ], messages: vec![], result: vec![test_storage_value.0], - execution_resources: invoke_execute_computation_resources(), + computation_resources: invoke_execute_computation_resources(), + execution_resources: + pathfinder_executor::types::InnerCallExecutionResources::default(), } } fn invoke_fee_transfer( account_contract_address: ContractAddress, last_block_header: &BlockHeader, - ) -> FunctionInvocation { - FunctionInvocation { - call_type: CallType::Call, + ) -> pathfinder_executor::types::FunctionInvocation { + pathfinder_executor::types::FunctionInvocation { + call_type: pathfinder_executor::types::CallType::Call, caller_address: *account_contract_address.get(), - calls: vec![], class_hash: Some(ERC20_CONTRACT_DEFINITION_CLASS_HASH.0), - entry_point_type: EntryPointType::External, - events: vec![OrderedEvent { + entry_point_type: pathfinder_executor::types::EntryPointType::External, + internal_calls: vec![], + events: vec![pathfinder_executor::types::Event { order: 0, data: vec![ *account_contract_address.get(), @@ -1374,18 +1692,18 @@ pub(crate) mod tests { "0x0099CD8BDE557814842A3121E8DDFD433A539B8C9F14BF31EBF108D12E6196E9" )], }], - function_call: FunctionCall { - calldata: vec![ - CallParam(last_block_header.sequencer_address.0), - CallParam(Felt::from_u64(INVOKE_OVERALL_FEE)), - call_param!("0x0"), - ], - contract_address: pathfinder_executor::ETH_FEE_TOKEN_ADDRESS, - entry_point_selector: EntryPoint::hashed(b"transfer"), - }, + calldata: vec![ + last_block_header.sequencer_address.0, + Felt::from_u64(INVOKE_OVERALL_FEE), + call_param!("0x0").0, + ], + contract_address: pathfinder_executor::ETH_FEE_TOKEN_ADDRESS, + selector: EntryPoint::hashed(b"transfer").0, messages: vec![], result: vec![felt!("0x1")], - execution_resources: invoke_fee_transfer_computation_resources(), + computation_resources: invoke_fee_transfer_computation_resources(), + execution_resources: + pathfinder_executor::types::InnerCallExecutionResources::default(), } } @@ -1397,73 +1715,95 @@ pub(crate) mod tests { account_contract_address: ContractAddress, last_block_header: &BlockHeader, test_storage_value: StorageValue, - ) -> SimulatedTransaction { - SimulatedTransaction { - fee_estimation: FeeEstimate { - gas_consumed: INVOKE_V3_GAS_CONSUMED.into(), - gas_price: 2.into(), - data_gas_consumed: Some(INVOKE_V3_DATA_GAS_CONSUMED.into()), - data_gas_price: Some(2.into()), + ) -> pathfinder_executor::types::TransactionSimulation { + pathfinder_executor::types::TransactionSimulation { + fee_estimation: pathfinder_executor::types::FeeEstimate { + l1_gas_consumed: INVOKE_V3_GAS_CONSUMED.into(), + l1_gas_price: 2.into(), + l1_data_gas_consumed: INVOKE_V3_DATA_GAS_CONSUMED.into(), + l1_data_gas_price: 2.into(), + l2_gas_consumed: 0.into(), + l2_gas_price: 0.into(), overall_fee: INVOKE_V3_OVERALL_FEE.into(), - unit: PriceUnit::Fri, + unit: pathfinder_executor::types::PriceUnit::Fri, }, - transaction_trace: TransactionTrace::Invoke(InvokeTxnTrace { - validate_invocation: Some(invoke_validate(account_contract_address)), - execute_invocation: ExecuteInvocation::FunctionInvocation(invoke_execute( - account_contract_address, - test_storage_value, - )), - fee_transfer_invocation: Some(invoke_v3_fee_transfer( - account_contract_address, - last_block_header, - )), - state_diff: Some(invoke_v3_state_diff( - account_contract_address, - invoke_v3_fee_transfer_storage_diffs(), - )), - execution_resources: Some(ExecutionResources { - computation_resources: invoke_validate_computation_resources() - + invoke_execute_computation_resources() - + invoke_fee_transfer_computation_resources(), - data_availability: DataAvailabilityResources { + trace: pathfinder_executor::types::TransactionTrace::Invoke( + pathfinder_executor::types::InvokeTransactionTrace { + validate_invocation: Some(invoke_validate(account_contract_address)), + execute_invocation: + pathfinder_executor::types::ExecuteInvocation::FunctionInvocation( + Some(invoke_execute( + account_contract_address, + test_storage_value, + )), + ), + fee_transfer_invocation: Some(invoke_v3_fee_transfer( + account_contract_address, + last_block_header, + )), + state_diff: invoke_v3_state_diff( + account_contract_address, + invoke_v3_fee_transfer_storage_diffs(), + ), + execution_resources: pathfinder_executor::types::ExecutionResources { + computation_resources: invoke_validate_computation_resources() + + invoke_execute_computation_resources() + + invoke_fee_transfer_computation_resources(), + data_availability: + pathfinder_executor::types::DataAvailabilityResources { + l1_gas: 0, + l1_data_gas: 128, + }, l1_gas: 0, l1_data_gas: 128, + l2_gas: 0, }, - }), - }), + }, + ), } } pub fn invoke_v3_without_fee_transfer( account_contract_address: ContractAddress, test_storage_value: StorageValue, - ) -> SimulatedTransaction { - SimulatedTransaction { - fee_estimation: FeeEstimate { - gas_consumed: INVOKE_V3_GAS_CONSUMED.into(), - gas_price: 2.into(), - data_gas_consumed: Some(INVOKE_V3_DATA_GAS_CONSUMED.into()), - data_gas_price: Some(2.into()), + ) -> pathfinder_executor::types::TransactionSimulation { + pathfinder_executor::types::TransactionSimulation { + fee_estimation: pathfinder_executor::types::FeeEstimate { + l1_gas_consumed: INVOKE_V3_GAS_CONSUMED.into(), + l1_gas_price: 2.into(), + l1_data_gas_consumed: INVOKE_V3_DATA_GAS_CONSUMED.into(), + l1_data_gas_price: 2.into(), + l2_gas_consumed: 0.into(), + l2_gas_price: 0.into(), overall_fee: INVOKE_V3_OVERALL_FEE.into(), - unit: PriceUnit::Fri, + unit: pathfinder_executor::types::PriceUnit::Fri, }, - transaction_trace: TransactionTrace::Invoke(InvokeTxnTrace { - validate_invocation: Some(invoke_validate(account_contract_address)), - execute_invocation: ExecuteInvocation::FunctionInvocation(invoke_execute( - account_contract_address, - test_storage_value, - )), - fee_transfer_invocation: None, - state_diff: Some(invoke_v3_state_diff(account_contract_address, vec![])), - execution_resources: Some(ExecutionResources { - computation_resources: invoke_validate_computation_resources() - + invoke_execute_computation_resources(), - data_availability: DataAvailabilityResources { + trace: pathfinder_executor::types::TransactionTrace::Invoke( + pathfinder_executor::types::InvokeTransactionTrace { + validate_invocation: Some(invoke_validate(account_contract_address)), + execute_invocation: + pathfinder_executor::types::ExecuteInvocation::FunctionInvocation( + Some(invoke_execute( + account_contract_address, + test_storage_value, + )), + ), + fee_transfer_invocation: None, + state_diff: invoke_v3_state_diff(account_contract_address, vec![]), + execution_resources: pathfinder_executor::types::ExecutionResources { + computation_resources: invoke_validate_computation_resources() + + invoke_execute_computation_resources(), + data_availability: + pathfinder_executor::types::DataAvailabilityResources { + l1_gas: 0, + l1_data_gas: 128, + }, l1_gas: 0, l1_data_gas: 128, + l2_gas: 0, }, - }), - }), + }, + ), } } @@ -1471,53 +1811,64 @@ pub(crate) mod tests { account_contract_address: ContractAddress, last_block_header: &BlockHeader, test_storage_value: StorageValue, - ) -> SimulatedTransaction { - SimulatedTransaction { - fee_estimation: FeeEstimate { - gas_consumed: INVOKE_V3_GAS_CONSUMED.into(), - gas_price: 2.into(), - data_gas_consumed: Some(INVOKE_V3_DATA_GAS_CONSUMED.into()), - data_gas_price: Some(2.into()), + ) -> pathfinder_executor::types::TransactionSimulation { + pathfinder_executor::types::TransactionSimulation { + fee_estimation: pathfinder_executor::types::FeeEstimate { + l1_gas_consumed: INVOKE_V3_GAS_CONSUMED.into(), + l1_gas_price: 2.into(), + l1_data_gas_consumed: INVOKE_V3_DATA_GAS_CONSUMED.into(), + l1_data_gas_price: 2.into(), + l2_gas_consumed: 0.into(), + l2_gas_price: 0.into(), overall_fee: INVOKE_V3_OVERALL_FEE.into(), - unit: PriceUnit::Fri, + unit: pathfinder_executor::types::PriceUnit::Fri, }, - transaction_trace: TransactionTrace::Invoke(InvokeTxnTrace { - validate_invocation: None, - execute_invocation: ExecuteInvocation::FunctionInvocation(invoke_execute( - account_contract_address, - test_storage_value, - )), - fee_transfer_invocation: Some(invoke_v3_fee_transfer( - account_contract_address, - last_block_header, - )), - state_diff: Some(invoke_v3_state_diff( - account_contract_address, - invoke_v3_fee_transfer_storage_diffs(), - )), - execution_resources: Some(ExecutionResources { - computation_resources: invoke_execute_computation_resources() - + invoke_fee_transfer_computation_resources(), - data_availability: DataAvailabilityResources { + trace: pathfinder_executor::types::TransactionTrace::Invoke( + pathfinder_executor::types::InvokeTransactionTrace { + validate_invocation: None, + execute_invocation: + pathfinder_executor::types::ExecuteInvocation::FunctionInvocation( + Some(invoke_execute( + account_contract_address, + test_storage_value, + )), + ), + fee_transfer_invocation: Some(invoke_v3_fee_transfer( + account_contract_address, + last_block_header, + )), + state_diff: invoke_v3_state_diff( + account_contract_address, + invoke_v3_fee_transfer_storage_diffs(), + ), + execution_resources: pathfinder_executor::types::ExecutionResources { + computation_resources: invoke_execute_computation_resources() + + invoke_fee_transfer_computation_resources(), + data_availability: + pathfinder_executor::types::DataAvailabilityResources { + l1_gas: 0, + l1_data_gas: 128, + }, l1_gas: 0, l1_data_gas: 128, + l2_gas: 0, }, - }), - }), + }, + ), } } fn invoke_v3_fee_transfer( account_contract_address: ContractAddress, last_block_header: &BlockHeader, - ) -> FunctionInvocation { - FunctionInvocation { - call_type: CallType::Call, + ) -> pathfinder_executor::types::FunctionInvocation { + pathfinder_executor::types::FunctionInvocation { + call_type: pathfinder_executor::types::CallType::Call, caller_address: *account_contract_address.get(), - calls: vec![], class_hash: Some(ERC20_CONTRACT_DEFINITION_CLASS_HASH.0), - entry_point_type: EntryPointType::External, - events: vec![OrderedEvent { + entry_point_type: pathfinder_executor::types::EntryPointType::External, + internal_calls: vec![], + events: vec![pathfinder_executor::types::Event { order: 0, data: vec![ *account_contract_address.get(), @@ -1529,35 +1880,48 @@ pub(crate) mod tests { "0x0099CD8BDE557814842A3121E8DDFD433A539B8C9F14BF31EBF108D12E6196E9" )], }], - function_call: FunctionCall { - calldata: vec![ - CallParam(last_block_header.sequencer_address.0), - CallParam(Felt::from_u64(INVOKE_V3_OVERALL_FEE)), - call_param!("0x0"), - ], - contract_address: pathfinder_executor::STRK_FEE_TOKEN_ADDRESS, - entry_point_selector: EntryPoint::hashed(b"transfer"), - }, + calldata: vec![ + last_block_header.sequencer_address.0, + Felt::from_u64(INVOKE_V3_OVERALL_FEE), + felt!("0x0"), + ], + contract_address: pathfinder_executor::STRK_FEE_TOKEN_ADDRESS, + selector: EntryPoint::hashed(b"transfer").0, messages: vec![], result: vec![felt!("0x1")], - execution_resources: invoke_fee_transfer_computation_resources(), + computation_resources: invoke_fee_transfer_computation_resources(), + execution_resources: + pathfinder_executor::types::InnerCallExecutionResources::default(), } } fn invoke_v3_state_diff( account_contract_address: ContractAddress, storage_diffs: Vec, - ) -> StateDiff { - StateDiff { - storage_diffs, - deprecated_declared_classes: vec![], + ) -> pathfinder_executor::types::StateDiff { + pathfinder_executor::types::StateDiff { + storage_diffs: BTreeMap::from_iter( + storage_diffs + .into_iter() + .map(|diff| { + ( + diff.address, + diff.storage_entries + .into_iter() + .map(|entry| pathfinder_executor::types::StorageDiff { + key: entry.key, + value: entry.value, + }) + .collect(), + ) + }) + .collect::>(), + ), + deprecated_declared_classes: HashSet::new(), declared_classes: vec![], deployed_contracts: vec![], replaced_classes: vec![], - nonces: vec![Nonce { - contract_address: account_contract_address, - nonce: contract_nonce!("0x4"), - }], + nonces: BTreeMap::from([(account_contract_address, contract_nonce!("0x4"))]), } } @@ -1601,39 +1965,60 @@ pub(crate) mod tests { fixtures::input::invoke_v3(account_contract_address), ], block_id: BlockId::Number(last_block_header.number), - simulation_flags: dto::SimulationFlags(vec![]), + simulation_flags: crate::dto::SimulationFlags(vec![]), }; let result = simulate_transactions(context, input).await.unwrap(); - pretty_assertions_sorted::assert_eq!( - result - .serialize(Serializer { - version: RpcVersion::V07 - }) - .unwrap(), - serde_json::to_value(vec![ - fixtures::expected_output_0_13_1_1::declare( - account_contract_address, - &last_block_header - ), - fixtures::expected_output_0_13_1_1::universal_deployer( - account_contract_address, - &last_block_header, - universal_deployer_address, - ), - fixtures::expected_output_0_13_1_1::invoke( - account_contract_address, - &last_block_header, - test_storage_value, - ), - fixtures::expected_output_0_13_1_1::invoke_v3( - account_contract_address, - &last_block_header, - test_storage_value, - ), - ]) - .unwrap() - ); + let serializer = crate::dto::serialize::Serializer { + version: RpcVersion::V07, + }; + + let result_serializable = result + .0 + .into_iter() + .map(crate::dto::SimulatedTransaction) + .collect::>(); + + let result_serialized = serializer + .serialize_iter( + result_serializable.len(), + &mut result_serializable.into_iter(), + ) + .unwrap(); + + let expected_serializable = vec![ + fixtures::expected_output_0_13_1_1::declare( + account_contract_address, + &last_block_header, + ), + fixtures::expected_output_0_13_1_1::universal_deployer( + account_contract_address, + &last_block_header, + universal_deployer_address, + ), + fixtures::expected_output_0_13_1_1::invoke( + account_contract_address, + &last_block_header, + test_storage_value, + ), + fixtures::expected_output_0_13_1_1::invoke_v3( + account_contract_address, + &last_block_header, + test_storage_value, + ), + ] + .into_iter() + .map(crate::dto::SimulatedTransaction) + .collect::>(); + + let expected_serialized = serializer + .serialize_iter( + expected_serializable.len(), + &mut expected_serializable.into_iter(), + ) + .unwrap(); + + pretty_assertions_sorted::assert_eq!(result_serialized, expected_serialized,); } #[test_log::test(tokio::test)] @@ -1658,34 +2043,41 @@ pub(crate) mod tests { fixtures::input::invoke_v3(account_contract_address), ], block_id: BlockId::Number(last_block_header.number), - simulation_flags: dto::SimulationFlags(vec![dto::SimulationFlag::SkipFeeCharge]), + simulation_flags: crate::dto::SimulationFlags(vec![ + crate::dto::SimulationFlag::SkipFeeCharge, + ]), }; let result = simulate_transactions(context, input).await.unwrap(); + let expected = super::Output(vec![ + fixtures::expected_output_0_13_1_1::declare_without_fee_transfer( + account_contract_address, + ), + fixtures::expected_output_0_13_1_1::universal_deployer_without_fee_transfer( + account_contract_address, + universal_deployer_address, + ), + fixtures::expected_output_0_13_1_1::invoke_without_fee_transfer( + account_contract_address, + test_storage_value, + ), + fixtures::expected_output_0_13_1_1::invoke_v3_without_fee_transfer( + account_contract_address, + test_storage_value, + ), + ]); + pretty_assertions_sorted::assert_eq!( result .serialize(Serializer { version: RpcVersion::V07 }) .unwrap(), - serde_json::to_value(vec![ - fixtures::expected_output_0_13_1_1::declare_without_fee_transfer( - account_contract_address - ), - fixtures::expected_output_0_13_1_1::universal_deployer_without_fee_transfer( - account_contract_address, - universal_deployer_address, - ), - fixtures::expected_output_0_13_1_1::invoke_without_fee_transfer( - account_contract_address, - test_storage_value, - ), - fixtures::expected_output_0_13_1_1::invoke_v3_without_fee_transfer( - account_contract_address, - test_storage_value, - ), - ]) - .unwrap() + expected + .serialize(Serializer { + version: RpcVersion::V07 + }) + .unwrap(), ); } @@ -1711,8 +2103,33 @@ pub(crate) mod tests { fixtures::input::invoke_v3(account_contract_address), ], block_id: BlockId::Number(last_block_header.number), - simulation_flags: dto::SimulationFlags(vec![dto::SimulationFlag::SkipValidate]), + simulation_flags: crate::dto::SimulationFlags(vec![ + crate::dto::SimulationFlag::SkipValidate, + ]), }; + + let expected = super::Output(vec![ + fixtures::expected_output_0_13_1_1::declare_without_validate( + account_contract_address, + &last_block_header, + ), + fixtures::expected_output_0_13_1_1::universal_deployer_without_validate( + account_contract_address, + &last_block_header, + universal_deployer_address, + ), + fixtures::expected_output_0_13_1_1::invoke_without_validate( + account_contract_address, + &last_block_header, + test_storage_value, + ), + fixtures::expected_output_0_13_1_1::invoke_v3_without_validate( + account_contract_address, + &last_block_header, + test_storage_value, + ), + ]); + let result = simulate_transactions(context, input).await.unwrap(); pretty_assertions_sorted::assert_eq!( @@ -1721,28 +2138,11 @@ pub(crate) mod tests { version: RpcVersion::V07 }) .unwrap(), - serde_json::to_value(vec![ - fixtures::expected_output_0_13_1_1::declare_without_validate( - account_contract_address, - &last_block_header, - ), - fixtures::expected_output_0_13_1_1::universal_deployer_without_validate( - account_contract_address, - &last_block_header, - universal_deployer_address, - ), - fixtures::expected_output_0_13_1_1::invoke_without_validate( - account_contract_address, - &last_block_header, - test_storage_value, - ), - fixtures::expected_output_0_13_1_1::invoke_v3_without_validate( - account_contract_address, - &last_block_header, - test_storage_value, - ), - ]) - .unwrap() + expected + .serialize(Serializer { + version: RpcVersion::V07 + }) + .unwrap(), ); } } diff --git a/crates/rpc/src/method/trace_block_transactions.rs b/crates/rpc/src/method/trace_block_transactions.rs index e21e5c0870..81529cf9bb 100644 --- a/crates/rpc/src/method/trace_block_transactions.rs +++ b/crates/rpc/src/method/trace_block_transactions.rs @@ -10,9 +10,23 @@ use crate::executor::{ ExecutionStateError, VERSIONS_LOWER_THAN_THIS_SHOULD_FALL_BACK_TO_FETCHING_TRACE_FROM_GATEWAY, }; -use crate::v06::method::trace_block_transactions as v06; -pub struct Output { +#[derive(Debug, Clone)] +pub struct TraceBlockTransactionsInput { + pub block_id: BlockId, +} + +impl crate::dto::DeserializeForVersion for TraceBlockTransactionsInput { + fn deserialize(value: crate::dto::Value) -> Result { + value.deserialize_map(|value| { + Ok(Self { + block_id: value.deserialize("block_id")?, + }) + }) + } +} + +pub struct TraceBlockTransactionsOutput { traces: Vec<( pathfinder_common::TransactionHash, pathfinder_executor::types::TransactionTrace, @@ -22,10 +36,10 @@ pub struct Output { pub async fn trace_block_transactions( context: RpcContext, - input: v06::TraceBlockTransactionsInput, -) -> Result { + input: TraceBlockTransactionsInput, +) -> Result { enum LocalExecution { - Success(Output), + Success(TraceBlockTransactionsOutput), Unsupported(Vec), } @@ -115,7 +129,7 @@ pub async fn trace_block_transactions( .map(|(hash, trace)| Ok((hash, trace))) .collect::, TraceBlockTransactionsError>>()?; - Ok(LocalExecution::Success(Output { + Ok(LocalExecution::Success(TraceBlockTransactionsOutput { traces, include_state_diffs: true, })) @@ -135,7 +149,7 @@ pub async fn trace_block_transactions( .context("Forwarding to feeder gateway") .map_err(TraceBlockTransactionsError::from) .map(|trace| { - Ok(Output { + Ok(TraceBlockTransactionsOutput { traces: trace .traces .into_iter() @@ -515,7 +529,7 @@ fn map_gateway_computation_resources( } } -impl crate::dto::serialize::SerializeForVersion for Output { +impl crate::dto::serialize::SerializeForVersion for TraceBlockTransactionsOutput { fn serialize( &self, serializer: crate::dto::serialize::Serializer, @@ -532,9 +546,9 @@ impl crate::dto::serialize::SerializeForVersion for Output { } struct Trace<'a> { - transaction_hash: &'a pathfinder_common::TransactionHash, - transaction_trace: &'a pathfinder_executor::types::TransactionTrace, - include_state_diff: bool, + pub transaction_hash: &'a pathfinder_common::TransactionHash, + pub transaction_trace: &'a pathfinder_executor::types::TransactionTrace, + pub include_state_diff: bool, } impl crate::dto::serialize::SerializeForVersion for Trace<'_> { @@ -550,7 +564,7 @@ impl crate::dto::serialize::SerializeForVersion for Trace<'_> { serializer.serialize_field( "trace_root", &crate::dto::TransactionTrace { - trace: self.transaction_trace, + trace: self.transaction_trace.clone(), include_state_diff: self.include_state_diff, }, )?; @@ -614,27 +628,36 @@ pub(crate) mod tests { use pathfinder_common::receipt::Receipt; use pathfinder_common::{ block_hash, - transaction_hash, + felt, BlockHeader, - BlockId, + BlockNumber, + Chain, GasPrice, - L1DataAvailabilityMode, + SequencerAddress, SierraHash, StarknetVersion, + TransactionHash, TransactionIndex, }; - use starknet_gateway_types::reply::GasPrices; - use tokio::task::JoinSet; + use pathfinder_crypto::Felt; + use starknet_gateway_types::reply::{GasPrices, L1DataAvailabilityMode}; - use super::v06::{Trace, TraceBlockTransactionsInput, TraceBlockTransactionsOutput}; - use super::{trace_block_transactions, RpcContext}; + use super::*; use crate::dto::serialize::{SerializeForVersion, Serializer}; - use crate::v06::method::simulate_transactions::tests::setup_storage_with_starknet_version; use crate::RpcVersion; + #[derive(Debug)] + pub struct Trace { + pub transaction_hash: TransactionHash, + pub trace_root: pathfinder_executor::types::TransactionTrace, + } + pub(crate) async fn setup_multi_tx_trace_test( ) -> anyhow::Result<(RpcContext, BlockHeader, Vec)> { - use super::super::simulate_transactions::tests::fixtures; + use super::super::simulate_transactions::tests::{ + fixtures, + setup_storage_with_starknet_version, + }; let ( storage, @@ -659,20 +682,17 @@ pub(crate) mod tests { fixtures::expected_output_0_13_1_1::declare( account_contract_address, &last_block_header, - ) - .transaction_trace, + ), fixtures::expected_output_0_13_1_1::universal_deployer( account_contract_address, &last_block_header, universal_deployer_address, - ) - .transaction_trace, + ), fixtures::expected_output_0_13_1_1::invoke( account_contract_address, &last_block_header, test_storage_value, - ) - .transaction_trace, + ), ]; let next_block_header = { @@ -695,12 +715,12 @@ pub(crate) mod tests { .sequencer_address(last_block_header.sequencer_address) .timestamp(last_block_header.timestamp) .starknet_version(StarknetVersion::new(0, 13, 1, 1)) - .l1_da_mode(L1DataAvailabilityMode::Blob) + .l1_da_mode(pathfinder_common::L1DataAvailabilityMode::Blob) .finalize_with_hash(block_hash!("0x1")); tx.insert_block_header(&next_block_header)?; let dummy_receipt = Receipt { - transaction_hash: transaction_hash!("0x1"), + transaction_hash: TransactionHash(felt!("0x1")), transaction_index: TransactionIndex::new_or_panic(0), ..Default::default() }; @@ -721,15 +741,15 @@ pub(crate) mod tests { let traces = vec![ Trace { transaction_hash: transactions[0].hash, - trace_root: traces[0].clone(), + trace_root: traces[0].trace.clone(), }, Trace { transaction_hash: transactions[1].hash, - trace_root: traces[1].clone(), + trace_root: traces[1].trace.clone(), }, Trace { transaction_hash: transactions[2].hash, - trace_root: traces[2].clone(), + trace_root: traces[2].trace.clone(), }, ]; @@ -744,15 +764,25 @@ pub(crate) mod tests { block_id: next_block_header.hash.into(), }; let output = trace_block_transactions(context, input).await.unwrap(); - let expected = TraceBlockTransactionsOutput(traces); + let expected = TraceBlockTransactionsOutput { + traces: traces + .into_iter() + .map(|t| (t.transaction_hash, t.trace_root)) + .collect(), + include_state_diffs: true, + }; pretty_assertions_sorted::assert_eq!( output .serialize(Serializer { - version: RpcVersion::V06, + version: RpcVersion::V07, + }) + .unwrap(), + expected + .serialize(Serializer { + version: RpcVersion::V07, }) .unwrap(), - serde_json::to_value(expected).unwrap() ); Ok(()) } @@ -769,7 +799,7 @@ pub(crate) mod tests { let input = TraceBlockTransactionsInput { block_id: next_block_header.hash.into(), }; - let mut joins = JoinSet::new(); + let mut joins = tokio::task::JoinSet::new(); for _ in 0..NUM_REQUESTS { let input = input.clone(); let context = context.clone(); @@ -781,24 +811,38 @@ pub(crate) mod tests { output .unwrap() .serialize(Serializer { - version: RpcVersion::V06, + version: RpcVersion::V07, }) .unwrap(), ); } let mut expected = Vec::new(); for _ in 0..NUM_REQUESTS { - expected - .push(serde_json::to_value(TraceBlockTransactionsOutput(traces.clone())).unwrap()); + expected.push( + TraceBlockTransactionsOutput { + traces: traces + .iter() + .map(|t| (t.transaction_hash, t.trace_root.clone())) + .collect(), + include_state_diffs: true, + } + .serialize(Serializer { + version: RpcVersion::V07, + }) + .unwrap(), + ); } pretty_assertions_sorted::assert_eq!(outputs, expected); Ok(()) } - pub(crate) async fn setup_multi_tx_trace_pending_test( + pub(crate) async fn setup_multi_tx_trace_pending_test<'a>( ) -> anyhow::Result<(RpcContext, Vec)> { - use super::super::simulate_transactions::tests::fixtures; + use super::super::simulate_transactions::tests::{ + fixtures, + setup_storage_with_starknet_version, + }; let ( storage, @@ -823,20 +867,17 @@ pub(crate) mod tests { fixtures::expected_output_0_13_1_1::declare( account_contract_address, &last_block_header, - ) - .transaction_trace, + ), fixtures::expected_output_0_13_1_1::universal_deployer( account_contract_address, &last_block_header, universal_deployer_address, - ) - .transaction_trace, + ), fixtures::expected_output_0_13_1_1::invoke( account_contract_address, &last_block_header, test_storage_value, - ) - .transaction_trace, + ), ]; let pending_block = { @@ -851,7 +892,7 @@ pub(crate) mod tests { )?; let dummy_receipt = Receipt { - transaction_hash: transaction_hash!("0x1"), + transaction_hash: TransactionHash(felt!("0x1")), transaction_index: TransactionIndex::new_or_panic(0), ..Default::default() }; @@ -878,7 +919,7 @@ pub(crate) mod tests { transaction_receipts, transactions: transactions.iter().cloned().map(Into::into).collect(), starknet_version: last_block_header.starknet_version, - l1_da_mode: starknet_gateway_types::reply::L1DataAvailabilityMode::Blob, + l1_da_mode: L1DataAvailabilityMode::Blob, }; tx.commit()?; @@ -900,15 +941,15 @@ pub(crate) mod tests { let traces = vec![ Trace { transaction_hash: transactions[0].hash, - trace_root: traces[0].clone(), + trace_root: traces[0].trace.clone(), }, Trace { transaction_hash: transactions[1].hash, - trace_root: traces[1].clone(), + trace_root: traces[1].trace.clone(), }, Trace { transaction_hash: transactions[2].hash, - trace_root: traces[2].clone(), + trace_root: traces[2].trace.clone(), }, ]; @@ -923,16 +964,121 @@ pub(crate) mod tests { block_id: BlockId::Pending, }; let output = trace_block_transactions(context, input).await.unwrap(); - let expected = TraceBlockTransactionsOutput(traces); + + let expected = TraceBlockTransactionsOutput { + traces: traces + .into_iter() + .map(|t| (t.transaction_hash, t.trace_root)) + .collect(), + include_state_diffs: true, + }; pretty_assertions_sorted::assert_eq!( output .serialize(Serializer { - version: RpcVersion::V06, + version: RpcVersion::V07, + }) + .unwrap(), + expected + .serialize(Serializer { + version: RpcVersion::V07, }) .unwrap(), - serde_json::to_value(expected).unwrap() ); + Ok(()) } + + /// Test that tracing succeeds for a block that is not backwards-compatible + /// with blockifier. + #[tokio::test] + async fn mainnet_blockifier_backwards_incompatible_transaction_tracing() { + let context = RpcContext::for_tests_on(Chain::Mainnet); + let mut connection = context.storage.connection().unwrap(); + let transaction = connection.transaction().unwrap(); + + // Need to avoid skipping blocks for `insert_transaction_data`. + (0..619596) + .collect::>() + .chunks(pathfinder_storage::BLOCK_RANGE_LEN as usize) + .map(|range| *range.last().unwrap() as u64) + .for_each(|block| { + let block = BlockNumber::new_or_panic(block); + transaction + .insert_transaction_data(block, &[], None) + .unwrap(); + }); + + let block: starknet_gateway_types::reply::Block = + serde_json::from_str(include_str!("../../fixtures/mainnet-619596.json")).unwrap(); + let transaction_count = block.transactions.len(); + let event_count = block + .transaction_receipts + .iter() + .map(|(_, events)| events.len()) + .sum(); + let header = BlockHeader { + hash: block.block_hash, + parent_hash: block.parent_block_hash, + number: block.block_number, + timestamp: block.timestamp, + eth_l1_gas_price: block.l1_gas_price.price_in_wei, + strk_l1_gas_price: block.l1_gas_price.price_in_fri, + eth_l1_data_gas_price: block.l1_data_gas_price.price_in_wei, + strk_l1_data_gas_price: block.l1_data_gas_price.price_in_fri, + eth_l2_gas_price: GasPrice(0), // TODO: Fix when we get l2_gas_price in the gateway + strk_l2_gas_price: GasPrice(0), // TODO: Fix when we get l2_gas_price in the gateway + sequencer_address: block + .sequencer_address + .unwrap_or(SequencerAddress(Felt::ZERO)), + starknet_version: block.starknet_version, + class_commitment: Default::default(), + event_commitment: Default::default(), + state_commitment: Default::default(), + storage_commitment: Default::default(), + transaction_commitment: Default::default(), + transaction_count, + event_count, + l1_da_mode: block.l1_da_mode.into(), + receipt_commitment: Default::default(), + state_diff_commitment: Default::default(), + state_diff_length: 0, + }; + transaction + .insert_block_header(&BlockHeader { + number: block.block_number - 1, + hash: block.parent_block_hash, + ..header.clone() + }) + .unwrap(); + transaction + .insert_block_header(&BlockHeader { + number: block.block_number - 10, + hash: block_hash!("0x1"), + ..header.clone() + }) + .unwrap(); + transaction.insert_block_header(&header).unwrap(); + let (transactions_data, events_data) = block + .transactions + .into_iter() + .zip(block.transaction_receipts.into_iter()) + .map(|(tx, (receipt, events))| ((tx, receipt), events)) + .unzip::<_, _, Vec<_>, Vec<_>>(); + transaction + .insert_transaction_data(header.number, &transactions_data, Some(&events_data)) + .unwrap(); + transaction.commit().unwrap(); + drop(connection); + + // The tracing succeeds. + trace_block_transactions( + context.clone(), + TraceBlockTransactionsInput { + block_id: BlockId::Number(block.block_number), + }, + ) + .await + .unwrap(); + } } diff --git a/crates/rpc/src/method/trace_transaction.rs b/crates/rpc/src/method/trace_transaction.rs index d57fd0136a..3a78f1810c 100644 --- a/crates/rpc/src/method/trace_transaction.rs +++ b/crates/rpc/src/method/trace_transaction.rs @@ -1,26 +1,48 @@ use anyhow::Context; +use pathfinder_common::TransactionHash; use pathfinder_executor::TransactionExecutionError; use starknet_gateway_client::GatewayApi; use crate::compose_executor_transaction; use crate::context::RpcContext; +use crate::dto::TransactionTrace; use crate::error::{ApplicationError, TraceError}; use crate::executor::{ ExecutionStateError, VERSIONS_LOWER_THAN_THIS_SHOULD_FALL_BACK_TO_FETCHING_TRACE_FROM_GATEWAY, }; use crate::method::trace_block_transactions::map_gateway_trace; -use crate::v06::method::trace_transaction as v06; #[derive(Debug)] -pub struct Output { - trace: pathfinder_executor::types::TransactionTrace, - include_state_diff: bool, +pub struct Input { + pub transaction_hash: TransactionHash, } -pub async fn trace_transaction( +impl crate::dto::DeserializeForVersion for Input { + fn deserialize(value: crate::dto::Value) -> Result { + value.deserialize_map(|value| { + Ok(Self { + transaction_hash: value.deserialize("transaction_hash").map(TransactionHash)?, + }) + }) + } +} + +#[derive(Debug)] +pub struct Output(TransactionTrace); + +impl crate::dto::serialize::SerializeForVersion for Output { + fn serialize( + &self, + serializer: crate::dto::serialize::Serializer, + ) -> Result { + self.0.serialize(serializer) + } +} + +pub async fn trace_transaction<'a>( context: RpcContext, - input: v06::TraceTransactionInput, + input: Input, ) -> Result { #[allow(clippy::large_enum_variant)] enum LocalExecution { @@ -147,10 +169,10 @@ pub async fn trace_transaction( let transaction = match local { LocalExecution::Success(trace) => { - return Ok(Output { - trace, - include_state_diff: true, - }) + return Ok(Output(TransactionTrace { + trace: trace.clone(), + include_state_diff: false, + })); } LocalExecution::Unsupported(tx) => tx, }; @@ -163,24 +185,11 @@ pub async fn trace_transaction( let trace = map_gateway_trace(transaction, trace)?; - Ok(Output { - trace, + Ok(Output(TransactionTrace { + trace: trace.clone(), // State diffs are not available for traces fetched from the gateway. include_state_diff: false, - }) -} - -impl crate::dto::serialize::SerializeForVersion for Output { - fn serialize( - &self, - serializer: crate::dto::serialize::Serializer, - ) -> Result { - crate::dto::TransactionTrace { - trace: &self.trace, - include_state_diff: self.include_state_diff, - } - .serialize(serializer) - } + })) } #[derive(Debug)] @@ -251,12 +260,12 @@ impl From for ApplicationError { #[cfg(test)] pub mod tests { + use super::super::trace_block_transactions::tests::{ setup_multi_tx_trace_pending_test, setup_multi_tx_trace_test, }; - use super::v06::{TraceTransactionInput, TraceTransactionOutput}; - use super::*; + use super::{trace_transaction, Input, Output}; use crate::dto::serialize::{SerializeForVersion, Serializer}; use crate::RpcVersion; @@ -265,18 +274,25 @@ pub mod tests { let (context, _, traces) = setup_multi_tx_trace_test().await?; for trace in traces { - let input = TraceTransactionInput { + let input = Input { transaction_hash: trace.transaction_hash, }; let output = trace_transaction(context.clone(), input).await.unwrap(); - let expected = TraceTransactionOutput(trace.trace_root); + let expected = Output(crate::dto::TransactionTrace { + trace: trace.trace_root, + include_state_diff: false, + }); pretty_assertions_sorted::assert_eq!( output .serialize(Serializer { - version: RpcVersion::V06 + version: RpcVersion::V07 }) .unwrap(), - serde_json::to_value(expected).unwrap() + expected + .serialize(Serializer { + version: RpcVersion::V07 + }) + .unwrap() ); } @@ -288,18 +304,25 @@ pub mod tests { let (context, traces) = setup_multi_tx_trace_pending_test().await?; for trace in traces { - let input = TraceTransactionInput { + let input = Input { transaction_hash: trace.transaction_hash, }; let output = trace_transaction(context.clone(), input).await.unwrap(); - let expected = TraceTransactionOutput(trace.trace_root); + let expected = Output(crate::dto::TransactionTrace { + trace: trace.trace_root, + include_state_diff: false, + }); pretty_assertions_sorted::assert_eq!( output .serialize(Serializer { - version: RpcVersion::V06 + version: RpcVersion::V07 }) .unwrap(), - serde_json::to_value(expected).unwrap() + expected + .serialize(Serializer { + version: RpcVersion::V07 + }) + .unwrap() ); } diff --git a/crates/rpc/src/types.rs b/crates/rpc/src/types.rs index 5dcdcf82f0..18710ab656 100644 --- a/crates/rpc/src/types.rs +++ b/crates/rpc/src/types.rs @@ -1,7 +1,9 @@ //! Common data structures used by the JSON-RPC API methods. pub(crate) mod class; +pub(crate) mod receipt; pub mod syncing; +pub(crate) mod transaction; pub use class::*; use pathfinder_common::{ResourceAmount, ResourcePricePerUnit}; diff --git a/crates/rpc/src/types/receipt.rs b/crates/rpc/src/types/receipt.rs new file mode 100644 index 0000000000..98d4016525 --- /dev/null +++ b/crates/rpc/src/types/receipt.rs @@ -0,0 +1,166 @@ +use pathfinder_common::{ContractAddress, EventData, EventKey, L2ToL1MessagePayloadElem}; +use serde::Serialize; +use serde_with::serde_as; + +use crate::felt::{RpcFelt, RpcFelt251}; +use crate::types::reply::BlockStatus; + +#[derive(Clone, Debug, Default, Serialize, PartialEq, Eq)] +#[cfg_attr(test, derive(serde::Deserialize))] +pub struct ExecutionResourcesProperties { + pub steps: u64, + #[serde(skip_serializing_if = "is_zero")] + pub memory_holes: u64, + #[serde(skip_serializing_if = "is_zero")] + pub range_check_builtin_applications: u64, + #[serde(skip_serializing_if = "is_zero")] + pub pedersen_builtin_applications: u64, + #[serde(skip_serializing_if = "is_zero")] + pub poseidon_builtin_applications: u64, + #[serde(skip_serializing_if = "is_zero")] + pub ec_op_builtin_applications: u64, + #[serde(skip_serializing_if = "is_zero")] + pub ecdsa_builtin_applications: u64, + #[serde(skip_serializing_if = "is_zero")] + pub bitwise_builtin_applications: u64, + #[serde(skip_serializing_if = "is_zero")] + pub keccak_builtin_applications: u64, + #[serde(skip_serializing_if = "is_zero")] + pub segment_arena_builtin: u64, +} + +fn is_zero(value: &u64) -> bool { + *value == 0 +} + +impl From for ExecutionResourcesProperties { + fn from(value: pathfinder_common::receipt::ExecutionResources) -> Self { + let pathfinder_common::receipt::ExecutionResources { + builtins: + pathfinder_common::receipt::BuiltinCounters { + // Absent from the OpenRPC spec + output: _, + pedersen: pedersen_builtin, + range_check: range_check_builtin, + ecdsa: ecdsa_builtin, + bitwise: bitwise_builtin, + ec_op: ec_op_builtin, + keccak: keccak_builtin, + poseidon: poseidon_builtin, + segment_arena: segment_arena_builtin, + .. + }, + n_steps, + n_memory_holes, + .. + } = value; + + Self { + steps: n_steps, + memory_holes: n_memory_holes, + range_check_builtin_applications: range_check_builtin, + pedersen_builtin_applications: pedersen_builtin, + poseidon_builtin_applications: poseidon_builtin, + ec_op_builtin_applications: ec_op_builtin, + ecdsa_builtin_applications: ecdsa_builtin, + bitwise_builtin_applications: bitwise_builtin, + keccak_builtin_applications: keccak_builtin, + segment_arena_builtin, + } + } +} + +#[derive(Clone, Debug, Serialize, PartialEq, Eq)] +#[serde(rename_all = "SCREAMING_SNAKE_CASE")] +#[cfg_attr(test, derive(serde::Deserialize))] +pub enum ExecutionStatus { + Succeeded, + Reverted, +} + +impl From for ExecutionStatus { + fn from(value: pathfinder_common::receipt::ExecutionStatus) -> Self { + match value { + pathfinder_common::receipt::ExecutionStatus::Succeeded => Self::Succeeded, + pathfinder_common::receipt::ExecutionStatus::Reverted { .. } => Self::Reverted, + } + } +} + +#[derive(Copy, Clone, Debug, Serialize, PartialEq, Eq)] +#[serde(rename_all = "SCREAMING_SNAKE_CASE")] +#[cfg_attr(test, derive(serde::Deserialize))] +pub enum FinalityStatus { + AcceptedOnL2, + //AcceptedOnL1, +} + +/// Message sent from L2 to L1. +#[serde_as] +#[derive(Clone, Debug, Serialize, PartialEq, Eq)] +#[cfg_attr(test, derive(serde::Deserialize))] +#[serde(deny_unknown_fields)] +pub struct MessageToL1 { + pub from_address: ContractAddress, + pub to_address: ContractAddress, + #[serde_as(as = "Vec")] + pub payload: Vec, +} + +impl From for MessageToL1 { + fn from(value: pathfinder_common::receipt::L2ToL1Message) -> Self { + Self { + from_address: value.from_address, + to_address: value.to_address, + payload: value.payload, + } + } +} + +/// Event emitted as a part of a transaction. +#[serde_as] +#[derive(Clone, Debug, Serialize, PartialEq, Eq)] +#[cfg_attr(test, derive(serde::Deserialize))] +#[serde(deny_unknown_fields)] +pub struct Event { + #[serde_as(as = "RpcFelt251")] + pub from_address: ContractAddress, + #[serde_as(as = "Vec")] + pub keys: Vec, + #[serde_as(as = "Vec")] + pub data: Vec, +} + +impl From for Event { + fn from(e: pathfinder_common::event::Event) -> Self { + Self { + from_address: e.from_address, + keys: e.keys, + data: e.data, + } + } +} + +/// Represents transaction status. +#[derive(Copy, Clone, Debug, Serialize, PartialEq, Eq)] +#[cfg_attr(test, derive(serde::Deserialize))] +#[serde(deny_unknown_fields)] +pub enum TransactionStatus { + #[serde(rename = "ACCEPTED_ON_L2")] + AcceptedOnL2, + #[serde(rename = "ACCEPTED_ON_L1")] + AcceptedOnL1, + #[serde(rename = "REJECTED")] + Rejected, +} + +impl From for TransactionStatus { + fn from(status: BlockStatus) -> Self { + match status { + BlockStatus::Pending => TransactionStatus::AcceptedOnL2, + BlockStatus::AcceptedOnL2 => TransactionStatus::AcceptedOnL2, + BlockStatus::AcceptedOnL1 => TransactionStatus::AcceptedOnL1, + BlockStatus::Rejected => TransactionStatus::Rejected, + } + } +} diff --git a/crates/rpc/src/types/transaction.rs b/crates/rpc/src/types/transaction.rs new file mode 100644 index 0000000000..154fda363e --- /dev/null +++ b/crates/rpc/src/types/transaction.rs @@ -0,0 +1,836 @@ +use pathfinder_common::transaction::{ + DataAvailabilityMode, + DeclareTransactionV0V1, + DeclareTransactionV2, + DeclareTransactionV3, + DeployAccountTransactionV1, + DeployAccountTransactionV3, + DeployTransactionV0, + DeployTransactionV1, + InvokeTransactionV0, + InvokeTransactionV1, + InvokeTransactionV3, + L1HandlerTransaction, + ResourceBound, + ResourceBounds, +}; +use pathfinder_common::{ + ResourceAmount, + ResourcePricePerUnit, + Tip, + TransactionHash, + TransactionVersion, +}; +use serde::ser::SerializeStruct; +use serde::Serialize; + +/// Equivalent to the TXN type from the specification. +#[derive(PartialEq, Debug, Clone, Eq)] +pub struct Transaction(pub pathfinder_common::transaction::TransactionVariant); + +/// A transaction and its hash, a common structure used in the spec. +#[derive(serde::Serialize, PartialEq, Debug, Clone, Eq)] +pub struct TransactionWithHash { + pub transaction_hash: TransactionHash, + #[serde(flatten)] + pub txn: Transaction, +} + +impl From for TransactionWithHash { + fn from(value: pathfinder_common::transaction::Transaction) -> Self { + Self { + transaction_hash: value.hash, + txn: Transaction(value.variant), + } + } +} + +impl Serialize for Transaction { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + use pathfinder_common::transaction::TransactionVariant; + match &self.0 { + TransactionVariant::DeclareV0(x) => DeclareV0Helper(x).serialize(serializer), + TransactionVariant::DeclareV1(x) => DeclareV1Helper(x).serialize(serializer), + TransactionVariant::DeclareV2(x) => DeclareV2Helper(x).serialize(serializer), + TransactionVariant::DeclareV3(x) => DeclareV3Helper(x).serialize(serializer), + TransactionVariant::DeployV0(x) => DeployV0Helper(x).serialize(serializer), + TransactionVariant::DeployV1(x) => DeployV1Helper(x).serialize(serializer), + TransactionVariant::DeployAccountV1(x) => { + DeployAccountV1Helper(x).serialize(serializer) + } + TransactionVariant::DeployAccountV3(x) => { + DeployAccountV3Helper(x).serialize(serializer) + } + TransactionVariant::InvokeV0(x) => InvokeV0Helper(x).serialize(serializer), + TransactionVariant::InvokeV1(x) => InvokeV1Helper(x).serialize(serializer), + TransactionVariant::InvokeV3(x) => InvokeV3Helper(x).serialize(serializer), + TransactionVariant::L1Handler(x) => L1HandlerHelper(x).serialize(serializer), + } + } +} + +struct DeclareV0Helper<'a>(&'a DeclareTransactionV0V1); +struct DeclareV1Helper<'a>(&'a DeclareTransactionV0V1); +struct DeclareV2Helper<'a>(&'a DeclareTransactionV2); +struct DeclareV3Helper<'a>(&'a DeclareTransactionV3); +struct DeployV0Helper<'a>(&'a DeployTransactionV0); +struct DeployV1Helper<'a>(&'a DeployTransactionV1); + +struct DeployAccountV1Helper<'a>(&'a DeployAccountTransactionV1); +struct DeployAccountV3Helper<'a>(&'a DeployAccountTransactionV3); +struct InvokeV0Helper<'a>(&'a InvokeTransactionV0); +struct InvokeV1Helper<'a>(&'a InvokeTransactionV1); +struct InvokeV3Helper<'a>(&'a InvokeTransactionV3); +struct L1HandlerHelper<'a>(&'a L1HandlerTransaction); +struct TransactionVersionHelper<'a>(&'a TransactionVersion); +struct ResourceBoundsHelper<'a>(&'a ResourceBounds); +struct ResourceBoundHelper<'a>(&'a ResourceBound); +struct ResourceAmountHelper<'a>(&'a ResourceAmount); +struct ResourcePricePerUnitHelper<'a>(&'a ResourcePricePerUnit); +struct DataAvailabilityModeHelper<'a>(&'a DataAvailabilityMode); +struct TipHelper<'a>(&'a Tip); + +impl Serialize for DeclareV0Helper<'_> { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let mut s = serializer.serialize_struct("DeclareV0", 6)?; + s.serialize_field("type", "DECLARE")?; + s.serialize_field("sender_address", &self.0.sender_address)?; + s.serialize_field("max_fee", &self.0.max_fee)?; + s.serialize_field("version", "0x0")?; + s.serialize_field("signature", &self.0.signature)?; + s.serialize_field("class_hash", &self.0.class_hash)?; + s.end() + } +} + +impl Serialize for DeclareV1Helper<'_> { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let mut s = serializer.serialize_struct("DeclareV1", 7)?; + s.serialize_field("type", "DECLARE")?; + s.serialize_field("sender_address", &self.0.sender_address)?; + s.serialize_field("max_fee", &self.0.max_fee)?; + s.serialize_field("version", "0x1")?; + s.serialize_field("signature", &self.0.signature)?; + s.serialize_field("nonce", &self.0.nonce)?; + s.serialize_field("class_hash", &self.0.class_hash)?; + s.end() + } +} + +impl Serialize for DeclareV2Helper<'_> { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let mut s = serializer.serialize_struct("DeclareV2", 8)?; + s.serialize_field("type", "DECLARE")?; + s.serialize_field("sender_address", &self.0.sender_address)?; + s.serialize_field("compiled_class_hash", &self.0.compiled_class_hash)?; + s.serialize_field("max_fee", &self.0.max_fee)?; + s.serialize_field("version", "0x2")?; + s.serialize_field("signature", &self.0.signature)?; + s.serialize_field("nonce", &self.0.nonce)?; + s.serialize_field("class_hash", &self.0.class_hash)?; + s.end() + } +} + +impl Serialize for DeclareV3Helper<'_> { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let mut s = serializer.serialize_struct("DeclareV3", 13)?; + s.serialize_field("type", "DECLARE")?; + s.serialize_field("sender_address", &self.0.sender_address)?; + s.serialize_field("compiled_class_hash", &self.0.compiled_class_hash)?; + s.serialize_field("version", "0x3")?; + s.serialize_field("signature", &self.0.signature)?; + s.serialize_field("nonce", &self.0.nonce)?; + s.serialize_field("class_hash", &self.0.class_hash)?; + s.serialize_field( + "resource_bounds", + &ResourceBoundsHelper(&self.0.resource_bounds), + )?; + s.serialize_field("tip", &TipHelper(&self.0.tip))?; + s.serialize_field("paymaster_data", &self.0.paymaster_data)?; + s.serialize_field("account_deployment_data", &self.0.account_deployment_data)?; + s.serialize_field( + "nonce_data_availability_mode", + &DataAvailabilityModeHelper(&self.0.nonce_data_availability_mode), + )?; + s.serialize_field( + "fee_data_availability_mode", + &DataAvailabilityModeHelper(&self.0.fee_data_availability_mode), + )?; + s.end() + } +} + +impl Serialize for DeployV0Helper<'_> { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let mut s = serializer.serialize_struct("Deploy", 5)?; + s.serialize_field( + "version", + &TransactionVersionHelper(&TransactionVersion::ZERO), + )?; + s.serialize_field("type", "DEPLOY")?; + s.serialize_field("contract_address_salt", &self.0.contract_address_salt)?; + s.serialize_field("constructor_calldata", &self.0.constructor_calldata)?; + s.serialize_field("class_hash", &self.0.class_hash)?; + s.end() + } +} + +impl Serialize for DeployV1Helper<'_> { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let mut s = serializer.serialize_struct("Deploy", 5)?; + s.serialize_field( + "version", + &TransactionVersionHelper(&TransactionVersion::ONE), + )?; + s.serialize_field("type", "DEPLOY")?; + s.serialize_field("contract_address_salt", &self.0.contract_address_salt)?; + s.serialize_field("constructor_calldata", &self.0.constructor_calldata)?; + s.serialize_field("class_hash", &self.0.class_hash)?; + s.end() + } +} + +impl Serialize for DeployAccountV1Helper<'_> { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let mut s = serializer.serialize_struct("DeployAccount", 8)?; + s.serialize_field("type", "DEPLOY_ACCOUNT")?; + s.serialize_field("max_fee", &self.0.max_fee)?; + s.serialize_field("version", "0x1")?; + s.serialize_field("signature", &self.0.signature)?; + s.serialize_field("nonce", &self.0.nonce)?; + s.serialize_field("contract_address_salt", &self.0.contract_address_salt)?; + s.serialize_field("constructor_calldata", &self.0.constructor_calldata)?; + s.serialize_field("class_hash", &self.0.class_hash)?; + s.end() + } +} + +impl Serialize for DeployAccountV3Helper<'_> { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let mut s = serializer.serialize_struct("DeployAccount", 12)?; + s.serialize_field("type", "DEPLOY_ACCOUNT")?; + s.serialize_field("version", "0x3")?; + s.serialize_field("signature", &self.0.signature)?; + s.serialize_field("nonce", &self.0.nonce)?; + s.serialize_field("contract_address_salt", &self.0.contract_address_salt)?; + s.serialize_field("constructor_calldata", &self.0.constructor_calldata)?; + s.serialize_field("class_hash", &self.0.class_hash)?; + s.serialize_field( + "resource_bounds", + &ResourceBoundsHelper(&self.0.resource_bounds), + )?; + s.serialize_field("tip", &TipHelper(&self.0.tip))?; + s.serialize_field("paymaster_data", &self.0.paymaster_data)?; + s.serialize_field( + "nonce_data_availability_mode", + &DataAvailabilityModeHelper(&self.0.nonce_data_availability_mode), + )?; + s.serialize_field( + "fee_data_availability_mode", + &DataAvailabilityModeHelper(&self.0.fee_data_availability_mode), + )?; + s.end() + } +} + +impl Serialize for InvokeV0Helper<'_> { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let mut s = serializer.serialize_struct("InvokeV0", 7)?; + s.serialize_field("type", "INVOKE")?; + s.serialize_field("max_fee", &self.0.max_fee)?; + s.serialize_field("version", "0x0")?; + s.serialize_field("signature", &self.0.signature)?; + s.serialize_field("contract_address", &self.0.sender_address)?; + s.serialize_field("entry_point_selector", &self.0.entry_point_selector)?; + s.serialize_field("calldata", &self.0.calldata)?; + s.end() + } +} + +impl Serialize for InvokeV1Helper<'_> { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let mut s = serializer.serialize_struct("InvokeV1", 7)?; + s.serialize_field("type", "INVOKE")?; + s.serialize_field("sender_address", &self.0.sender_address)?; + s.serialize_field("calldata", &self.0.calldata)?; + s.serialize_field("max_fee", &self.0.max_fee)?; + s.serialize_field("version", "0x1")?; + s.serialize_field("signature", &self.0.signature)?; + s.serialize_field("nonce", &self.0.nonce)?; + s.end() + } +} + +impl Serialize for InvokeV3Helper<'_> { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let mut s = serializer.serialize_struct("InvokeV3", 12)?; + s.serialize_field("type", "INVOKE")?; + s.serialize_field("sender_address", &self.0.sender_address)?; + s.serialize_field("calldata", &self.0.calldata)?; + s.serialize_field("version", "0x3")?; + s.serialize_field("signature", &self.0.signature)?; + s.serialize_field("nonce", &self.0.nonce)?; + s.serialize_field( + "resource_bounds", + &ResourceBoundsHelper(&self.0.resource_bounds), + )?; + s.serialize_field("tip", &TipHelper(&self.0.tip))?; + s.serialize_field("paymaster_data", &self.0.paymaster_data)?; + s.serialize_field("account_deployment_data", &self.0.account_deployment_data)?; + s.serialize_field( + "nonce_data_availability_mode", + &DataAvailabilityModeHelper(&self.0.nonce_data_availability_mode), + )?; + s.serialize_field( + "fee_data_availability_mode", + &DataAvailabilityModeHelper(&self.0.fee_data_availability_mode), + )?; + s.end() + } +} + +impl Serialize for L1HandlerHelper<'_> { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let mut s = serializer.serialize_struct("L1Handler", 6)?; + s.serialize_field( + "version", + &TransactionVersionHelper(&TransactionVersion::ZERO), + )?; + s.serialize_field("type", "L1_HANDLER")?; + s.serialize_field("nonce", &self.0.nonce)?; + s.serialize_field("contract_address", &self.0.contract_address)?; + s.serialize_field("entry_point_selector", &self.0.entry_point_selector)?; + s.serialize_field("calldata", &self.0.calldata)?; + s.end() + } +} + +impl Serialize for TransactionVersionHelper<'_> { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + use pathfinder_serde::bytes_to_hex_str; + serializer.serialize_str(&bytes_to_hex_str(self.0 .0.as_be_bytes())) + } +} + +impl Serialize for ResourceBoundsHelper<'_> { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let mut s = serializer.serialize_struct("ResourceBounds", 2)?; + s.serialize_field("l1_gas", &ResourceBoundHelper(&self.0.l1_gas))?; + s.serialize_field("l2_gas", &ResourceBoundHelper(&self.0.l2_gas))?; + s.end() + } +} + +impl Serialize for ResourceBoundHelper<'_> { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let mut s = serializer.serialize_struct("ResourceBound", 2)?; + s.serialize_field("max_amount", &ResourceAmountHelper(&self.0.max_amount))?; + s.serialize_field( + "max_price_per_unit", + &ResourcePricePerUnitHelper(&self.0.max_price_per_unit), + )?; + s.end() + } +} + +impl Serialize for ResourceAmountHelper<'_> { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + use pathfinder_serde::bytes_to_hex_str; + serializer.serialize_str(&bytes_to_hex_str(&self.0 .0.to_be_bytes())) + } +} + +impl Serialize for ResourcePricePerUnitHelper<'_> { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + use pathfinder_serde::bytes_to_hex_str; + serializer.serialize_str(&bytes_to_hex_str(&self.0 .0.to_be_bytes())) + } +} + +impl Serialize for DataAvailabilityModeHelper<'_> { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + match self.0 { + DataAvailabilityMode::L1 => serializer.serialize_str("L1"), + DataAvailabilityMode::L2 => serializer.serialize_str("L2"), + } + } +} + +impl Serialize for TipHelper<'_> { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + use pathfinder_serde::bytes_to_hex_str; + serializer.serialize_str(&bytes_to_hex_str(&self.0 .0.to_be_bytes())) + } +} + +#[cfg(test)] +mod tests { + use pathfinder_common::macro_prelude::*; + + use super::*; + + mod serialization { + use pathfinder_common::transaction::*; + use pathfinder_common::{ResourceAmount, ResourcePricePerUnit, Tip}; + use pretty_assertions_sorted::assert_eq; + use serde_json::json; + + use super::*; + + #[test] + fn declare_v0() { + let original = DeclareTransactionV0V1 { + class_hash: class_hash!("0x123"), + max_fee: fee!("0x1111"), + nonce: transaction_nonce!("0xaabbcc"), + sender_address: contract_address!("0xabc"), + signature: vec![ + transaction_signature_elem!("0xa1b1"), + transaction_signature_elem!("0x1a1b"), + ], + }; + + let expected = json!({ + "type": "DECLARE", + "version": "0x0", + "sender_address": "0xabc", + "max_fee": "0x1111", + "signature": ["0xa1b1", "0x1a1b"], + "class_hash": "0x123", + }); + let uut = Transaction(TransactionVariant::DeclareV0(original)); + let result = serde_json::to_value(uut).unwrap(); + + assert_eq!(result, expected); + } + + #[test] + fn declare_v1() { + let original = DeclareTransactionV0V1 { + class_hash: class_hash!("0x123"), + max_fee: fee!("0x1111"), + nonce: transaction_nonce!("0xaabbcc"), + sender_address: contract_address!("0xabc"), + signature: vec![ + transaction_signature_elem!("0xa1b1"), + transaction_signature_elem!("0x1a1b"), + ], + }; + + let expected = json!({ + "type": "DECLARE", + "version": "0x1", + "sender_address": "0xabc", + "max_fee": "0x1111", + "signature": ["0xa1b1", "0x1a1b"], + "class_hash": "0x123", + "nonce": "0xaabbcc", + }); + let uut = Transaction(TransactionVariant::DeclareV1(original)); + let result = serde_json::to_value(uut).unwrap(); + + assert_eq!(result, expected); + } + + #[test] + fn declare_v2() { + let original: TransactionVariant = DeclareTransactionV2 { + class_hash: class_hash!("0x123"), + max_fee: fee!("0x1111"), + nonce: transaction_nonce!("0xaabbcc"), + sender_address: contract_address!("0xabc"), + signature: vec![ + transaction_signature_elem!("0xa1b1"), + transaction_signature_elem!("0x1a1b"), + ], + compiled_class_hash: casm_hash!("0xbbbbb"), + } + .into(); + + let expected = json!({ + "type": "DECLARE", + "version": "0x2", + "sender_address": "0xabc", + "max_fee": "0x1111", + "signature": ["0xa1b1", "0x1a1b"], + "class_hash": "0x123", + "nonce": "0xaabbcc", + "compiled_class_hash": "0xbbbbb", + }); + let uut = Transaction(original); + let result = serde_json::to_value(uut).unwrap(); + + assert_eq!(result, expected); + } + + #[test] + fn declare_v3() { + let original: TransactionVariant = DeclareTransactionV3 { + class_hash: class_hash!("0x123"), + nonce: transaction_nonce!("0xaabbcc"), + sender_address: contract_address!("0xabc"), + signature: vec![ + transaction_signature_elem!("0xa1b1"), + transaction_signature_elem!("0x1a1b"), + ], + compiled_class_hash: casm_hash!("0xbbbbb"), + nonce_data_availability_mode: DataAvailabilityMode::L1, + fee_data_availability_mode: DataAvailabilityMode::L1, + resource_bounds: ResourceBounds { + l1_gas: ResourceBound { + max_amount: ResourceAmount(256), + max_price_per_unit: ResourcePricePerUnit(10), + }, + l2_gas: Default::default(), + l1_data_gas: Default::default(), + }, + tip: Tip(5), + paymaster_data: vec![], + account_deployment_data: vec![], + } + .into(); + + let expected = json!({ + "type": "DECLARE", + "version": "0x3", + "sender_address": "0xabc", + "signature": ["0xa1b1", "0x1a1b"], + "class_hash": "0x123", + "nonce": "0xaabbcc", + "compiled_class_hash": "0xbbbbb", + "nonce_data_availability_mode": "L1", + "fee_data_availability_mode": "L1", + "resource_bounds": { + "l1_gas": { + "max_amount": "0x100", + "max_price_per_unit": "0xa", + }, + "l2_gas": { + "max_amount": "0x0", + "max_price_per_unit": "0x0", + } + }, + "tip": "0x5", + "paymaster_data": [], + "account_deployment_data": [], + }); + let uut = Transaction(original); + let result = serde_json::to_value(uut).unwrap(); + + assert_eq!(result, expected); + } + + #[test] + fn deploy() { + let original: TransactionVariant = DeployTransactionV0 { + contract_address: contract_address!("0xabc"), + contract_address_salt: contract_address_salt!("0xeeee"), + class_hash: class_hash!("0x123"), + constructor_calldata: vec![ + constructor_param!("0xbbb0"), + constructor_param!("0xbbb1"), + ], + } + .into(); + + let expected = json!({ + "type": "DEPLOY", + "contract_address_salt": "0xeeee", + "class_hash": "0x123", + "constructor_calldata": ["0xbbb0","0xbbb1"], + "version": "0x0", + }); + let uut = Transaction(original); + let result = serde_json::to_value(uut).unwrap(); + + assert_eq!(result, expected); + } + + #[test] + fn deploy_account_v1() { + let original: TransactionVariant = DeployAccountTransactionV1 { + contract_address: contract_address!("0xabc"), + max_fee: fee!("0x1111"), + signature: vec![ + transaction_signature_elem!("0xa1b1"), + transaction_signature_elem!("0x1a1b"), + ], + nonce: transaction_nonce!("0xaabbcc"), + contract_address_salt: contract_address_salt!("0xeeee"), + constructor_calldata: vec![call_param!("0xbbb0"), call_param!("0xbbb1")], + class_hash: class_hash!("0x123"), + } + .into(); + + let expected = json!({ + "type": "DEPLOY_ACCOUNT", + "max_fee": "0x1111", + "version": "0x1", + "signature": ["0xa1b1", "0x1a1b"], + "nonce": "0xaabbcc", + "contract_address_salt": "0xeeee", + "constructor_calldata": ["0xbbb0","0xbbb1"], + "class_hash": "0x123", + }); + let uut = Transaction(original); + let result = serde_json::to_value(uut).unwrap(); + + assert_eq!(result, expected); + } + + #[test] + fn deploy_account_v3() { + let original: TransactionVariant = DeployAccountTransactionV3 { + contract_address: contract_address!("0xabc"), + signature: vec![ + transaction_signature_elem!("0xa1b1"), + transaction_signature_elem!("0x1a1b"), + ], + nonce: transaction_nonce!("0xaabbcc"), + contract_address_salt: contract_address_salt!("0xeeee"), + constructor_calldata: vec![call_param!("0xbbb0"), call_param!("0xbbb1")], + class_hash: class_hash!("0x123"), + nonce_data_availability_mode: DataAvailabilityMode::L1, + fee_data_availability_mode: DataAvailabilityMode::L1, + resource_bounds: ResourceBounds { + l1_gas: ResourceBound { + max_amount: ResourceAmount(256), + max_price_per_unit: ResourcePricePerUnit(10), + }, + l2_gas: Default::default(), + l1_data_gas: Default::default(), + }, + tip: Tip(5), + paymaster_data: vec![], + } + .into(); + + let expected = json!({ + "type": "DEPLOY_ACCOUNT", + "version": "0x3", + "signature": ["0xa1b1", "0x1a1b"], + "nonce": "0xaabbcc", + "contract_address_salt": "0xeeee", + "constructor_calldata": ["0xbbb0","0xbbb1"], + "class_hash": "0x123", + "nonce_data_availability_mode": "L1", + "fee_data_availability_mode": "L1", + "resource_bounds": { + "l1_gas": { + "max_amount": "0x100", + "max_price_per_unit": "0xa", + }, + "l2_gas": { + "max_amount": "0x0", + "max_price_per_unit": "0x0", + } + }, + "tip": "0x5", + "paymaster_data": [], + }); + let uut = Transaction(original); + let result = serde_json::to_value(uut).unwrap(); + + assert_eq!(result, expected); + } + + #[test] + fn invoke_v0() { + let original: TransactionVariant = InvokeTransactionV0 { + calldata: vec![call_param!("0xfff1"), call_param!("0xfff0")], + sender_address: contract_address!("0xabc"), + entry_point_selector: entry_point!("0xdead"), + entry_point_type: Some(EntryPointType::External), + max_fee: fee!("0x1111"), + signature: vec![ + transaction_signature_elem!("0xa1b1"), + transaction_signature_elem!("0x1a1b"), + ], + } + .into(); + + let expected = json!({ + "type": "INVOKE", + "version": "0x0", + "calldata": ["0xfff1","0xfff0"], + "contract_address": "0xabc", + "entry_point_selector": "0xdead", + "max_fee": "0x1111", + "signature": ["0xa1b1", "0x1a1b"], + }); + let uut = Transaction(original); + let result = serde_json::to_value(uut).unwrap(); + + assert_eq!(result, expected); + } + + #[test] + fn invoke_v1() { + let original: TransactionVariant = InvokeTransactionV1 { + calldata: vec![call_param!("0xfff1"), call_param!("0xfff0")], + sender_address: contract_address!("0xabc"), + max_fee: fee!("0x1111"), + signature: vec![ + transaction_signature_elem!("0xa1b1"), + transaction_signature_elem!("0x1a1b"), + ], + nonce: transaction_nonce!("0xaabbcc"), + } + .into(); + + let expected = json!({ + "type": "INVOKE", + "version": "0x1", + "calldata": ["0xfff1","0xfff0"], + "sender_address": "0xabc", + "max_fee": "0x1111", + "signature": ["0xa1b1", "0x1a1b"], + "nonce": "0xaabbcc", + }); + let uut = Transaction(original); + let result = serde_json::to_value(uut).unwrap(); + + assert_eq!(result, expected); + } + + #[test] + fn invoke_v3() { + let original: TransactionVariant = InvokeTransactionV3 { + calldata: vec![call_param!("0xfff1"), call_param!("0xfff0")], + sender_address: contract_address!("0xabc"), + signature: vec![ + transaction_signature_elem!("0xa1b1"), + transaction_signature_elem!("0x1a1b"), + ], + nonce: transaction_nonce!("0xaabbcc"), + nonce_data_availability_mode: DataAvailabilityMode::L1, + fee_data_availability_mode: DataAvailabilityMode::L1, + resource_bounds: ResourceBounds { + l1_gas: ResourceBound { + max_amount: ResourceAmount(256), + max_price_per_unit: ResourcePricePerUnit(10), + }, + l2_gas: Default::default(), + l1_data_gas: Default::default(), + }, + tip: Tip(5), + paymaster_data: vec![], + account_deployment_data: vec![], + } + .into(); + + let expected = json!({ + "type": "INVOKE", + "version": "0x3", + "calldata": ["0xfff1","0xfff0"], + "sender_address": "0xabc", + "signature": ["0xa1b1", "0x1a1b"], + "nonce": "0xaabbcc", + "nonce_data_availability_mode": "L1", + "fee_data_availability_mode": "L1", + "resource_bounds": { + "l1_gas": { + "max_amount": "0x100", + "max_price_per_unit": "0xa", + }, + "l2_gas": { + "max_amount": "0x0", + "max_price_per_unit": "0x0", + } + }, + "tip": "0x5", + "paymaster_data": [], + "account_deployment_data": [], + }); + let uut = Transaction(original); + let result = serde_json::to_value(uut).unwrap(); + + assert_eq!(result, expected); + } + + #[test] + fn l1_handler() { + let original: TransactionVariant = L1HandlerTransaction { + contract_address: contract_address!("0xabc"), + entry_point_selector: entry_point!("0xdead"), + nonce: transaction_nonce!("0xaabbcc"), + calldata: vec![call_param!("0xfff1"), call_param!("0xfff0")], + } + .into(); + + let expected = json!({ + "type": "L1_HANDLER", + "contract_address": "0xabc", + "entry_point_selector": "0xdead", + "nonce": "0xaabbcc", + "calldata": ["0xfff1","0xfff0"], + "version": "0x0", + }); + let uut = Transaction(original); + let result = serde_json::to_value(uut).unwrap(); + + assert_eq!(result, expected); + } + } +} diff --git a/crates/rpc/src/v07/dto/receipt.rs b/crates/rpc/src/v07/dto/receipt.rs index b123469e0c..b7a6a49570 100644 --- a/crates/rpc/src/v07/dto/receipt.rs +++ b/crates/rpc/src/v07/dto/receipt.rs @@ -2,8 +2,8 @@ use pathfinder_common::prelude::*; use pathfinder_serde::H256AsNoLeadingZerosHexStr; use serde::Serialize; +use crate::types::receipt; use crate::types::reply::BlockStatus; -use crate::v06::method::get_transaction_receipt::types as v06; use crate::PendingData; #[derive(Serialize)] @@ -37,7 +37,7 @@ impl From for PendingBlockWithReceipts { .map(|(t, (r, e))| (t.clone(), r.clone(), e.clone())) .collect::>(); - let body = BlockBodyWithReceipts::from_common(body, v06::FinalityStatus::AcceptedOnL2); + let body = BlockBodyWithReceipts::from_common(body, receipt::FinalityStatus::AcceptedOnL2); Self { header: value.header().into(), @@ -54,7 +54,7 @@ struct BlockBodyWithReceipts { impl BlockBodyWithReceipts { fn from_common( value: Vec<(CommonTransaction, CommonReceipt, Vec)>, - finality_status: v06::FinalityStatus, + finality_status: receipt::FinalityStatus, ) -> Self { let transactions = value .into_iter() @@ -68,7 +68,7 @@ impl BlockBodyWithReceipts { #[derive(Serialize)] // Inner type of block with receipts struct TransactionWithReceipt { - transaction: crate::v06::types::TransactionWithHash, + transaction: crate::types::transaction::TransactionWithHash, receipt: PendingTxnReceipt, } @@ -77,7 +77,7 @@ impl TransactionWithReceipt { transaction: CommonTransaction, receipt: CommonReceipt, events: Vec, - finality_status: v06::FinalityStatus, + finality_status: receipt::FinalityStatus, ) -> Self { let receipt = PendingTxnReceipt::from_common(&transaction, receipt, events, finality_status); @@ -155,7 +155,7 @@ impl PendingTxnReceipt { transaction: &CommonTransaction, receipt: CommonReceipt, events: Vec, - finality_status: v06::FinalityStatus, + finality_status: receipt::FinalityStatus, ) -> Self { let common = PendingCommonReceiptProperties::from_common( transaction, @@ -198,11 +198,11 @@ impl PendingTxnReceipt { } #[derive(Serialize)] -pub struct ComputationResources(v06::ExecutionResourcesProperties); +pub struct ComputationResources(receipt::ExecutionResourcesProperties); impl From for ComputationResources { fn from(value: pathfinder_common::receipt::ExecutionResources) -> Self { - Self(v06::ExecutionResourcesProperties { + Self(receipt::ExecutionResourcesProperties { steps: value.n_steps, memory_holes: value.n_memory_holes, range_check_builtin_applications: value.builtins.range_check, @@ -255,26 +255,26 @@ pub struct CommonReceiptProperties { actual_fee: FeePayment, block_hash: BlockHash, block_number: BlockNumber, - messages_sent: Vec, - events: Vec, + messages_sent: Vec, + events: Vec, #[serde(skip_serializing_if = "Option::is_none")] revert_reason: Option, execution_resources: ExecutionResources, - execution_status: v06::ExecutionStatus, - finality_status: v06::FinalityStatus, + execution_status: receipt::ExecutionStatus, + finality_status: receipt::FinalityStatus, } #[derive(Serialize)] pub struct PendingCommonReceiptProperties { transaction_hash: TransactionHash, actual_fee: FeePayment, - messages_sent: Vec, - events: Vec, + messages_sent: Vec, + events: Vec, #[serde(skip_serializing_if = "Option::is_none")] revert_reason: Option, - execution_status: v06::ExecutionStatus, + execution_status: receipt::ExecutionStatus, execution_resources: ExecutionResources, - finality_status: v06::FinalityStatus, + finality_status: receipt::FinalityStatus, } impl PendingCommonReceiptProperties { @@ -282,7 +282,7 @@ impl PendingCommonReceiptProperties { transaction: &CommonTransaction, receipt: CommonReceipt, events: Vec, - finality_status: v06::FinalityStatus, + finality_status: receipt::FinalityStatus, ) -> Self { let actual_fee = FeePayment { amount: receipt.actual_fee, @@ -381,7 +381,7 @@ mod tests { revert_reason: None, execution_resources: ExecutionResources { computation_resources: ComputationResources( - v06::ExecutionResourcesProperties { + receipt::ExecutionResourcesProperties { steps: 10, memory_holes: 0, range_check_builtin_applications: 0, @@ -399,8 +399,8 @@ mod tests { l1_data_gas: 0, }, }, - execution_status: v06::ExecutionStatus::Succeeded, - finality_status: v06::FinalityStatus::AcceptedOnL2, + execution_status: receipt::ExecutionStatus::Succeeded, + finality_status: receipt::FinalityStatus::AcceptedOnL2, }, }; @@ -442,7 +442,7 @@ mod tests { revert_reason: None, execution_resources: ExecutionResources { computation_resources: ComputationResources( - v06::ExecutionResourcesProperties { + receipt::ExecutionResourcesProperties { steps: 10, memory_holes: 0, range_check_builtin_applications: 0, @@ -460,8 +460,8 @@ mod tests { l1_data_gas: 0, }, }, - execution_status: v06::ExecutionStatus::Succeeded, - finality_status: v06::FinalityStatus::AcceptedOnL2, + execution_status: receipt::ExecutionStatus::Succeeded, + finality_status: receipt::FinalityStatus::AcceptedOnL2, }, }; From 1f56822c7acfc5d4589a90f90986aa27855d5a99 Mon Sep 17 00:00:00 2001 From: sistemd Date: Tue, 10 Dec 2024 12:26:58 +0100 Subject: [PATCH 2/3] fix test failure after rebase --- crates/rpc/src/method/trace_block_transactions.rs | 13 ++++++------- .../rpc/src/v06/method/trace_block_transactions.rs | 3 ++- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/crates/rpc/src/method/trace_block_transactions.rs b/crates/rpc/src/method/trace_block_transactions.rs index 81529cf9bb..a62fb787a4 100644 --- a/crates/rpc/src/method/trace_block_transactions.rs +++ b/crates/rpc/src/method/trace_block_transactions.rs @@ -997,15 +997,14 @@ pub(crate) mod tests { let mut connection = context.storage.connection().unwrap(); let transaction = connection.transaction().unwrap(); - // Need to avoid skipping blocks for `insert_transaction_data`. + // Need to avoid skipping blocks for `insert_transaction_data` + // so that there is no gap in event filters. (0..619596) - .collect::>() - .chunks(pathfinder_storage::BLOCK_RANGE_LEN as usize) - .map(|range| *range.last().unwrap() as u64) - .for_each(|block| { - let block = BlockNumber::new_or_panic(block); + .step_by(pathfinder_storage::BLOCK_RANGE_LEN as usize) + .for_each(|block: u64| { + let block = BlockNumber::new_or_panic(block.saturating_sub(1)); transaction - .insert_transaction_data(block, &[], None) + .insert_transaction_data(block, &[], Some(&[])) .unwrap(); }); diff --git a/crates/rpc/src/v06/method/trace_block_transactions.rs b/crates/rpc/src/v06/method/trace_block_transactions.rs index dc3b9bc8e6..110a54e9d2 100644 --- a/crates/rpc/src/v06/method/trace_block_transactions.rs +++ b/crates/rpc/src/v06/method/trace_block_transactions.rs @@ -641,7 +641,8 @@ pub(crate) mod tests { let mut connection = context.storage.connection().unwrap(); let transaction = connection.transaction().unwrap(); - // Need to avoid skipping blocks for `insert_transaction_data`. + // Need to avoid skipping blocks for `insert_transaction_data` + // so that there is no gap in event filters. (0..619596) .step_by(pathfinder_storage::BLOCK_RANGE_LEN as usize) .for_each(|block: u64| { From d34861e8a0b3c47486c3e13d438dfced3f822803 Mon Sep 17 00:00:00 2001 From: t00ts Date: Fri, 13 Dec 2024 12:42:17 +0400 Subject: [PATCH 3/3] feat(rpc): remove `#[serde(Serialize)]` from our `dto`s in favor of our `SerializeForVersion` --- crates/rpc/src/felt.rs | 2 +- crates/rpc/src/method/call.rs | 33 +- .../rpc/src/method/get_block_with_receipts.rs | 2 - .../src/method/get_block_with_tx_hashes.rs | 2 - crates/rpc/src/method/get_block_with_txs.rs | 2 - crates/rpc/src/method/get_messages_status.rs | 32 +- crates/rpc/src/method/get_state_update.rs | 222 ++++++++--- .../get_transaction_by_block_id_and_index.rs | 16 +- .../rpc/src/method/get_transaction_by_hash.rs | 17 +- crates/rpc/src/types.rs | 60 +-- crates/rpc/src/types/transaction.rs | 355 ++++++++++-------- crates/rpc/src/v07/dto/receipt.rs | 191 ++++++++-- 12 files changed, 644 insertions(+), 290 deletions(-) diff --git a/crates/rpc/src/felt.rs b/crates/rpc/src/felt.rs index 29833ad8b9..0d1551c1ec 100644 --- a/crates/rpc/src/felt.rs +++ b/crates/rpc/src/felt.rs @@ -81,7 +81,7 @@ impl From for Felt { /// This can be easily accomplished by marking a field with `#[serde_as(as = /// "RpcFelt251")]`. #[derive(serde::Serialize)] -pub struct RpcFelt251(RpcFelt); +pub struct RpcFelt251(pub RpcFelt); mod serialization { //! Blanket [serde::Serialize] and [serde_with::SerializeAs] implementations diff --git a/crates/rpc/src/method/call.rs b/crates/rpc/src/method/call.rs index eb3a0ce803..5091685e99 100644 --- a/crates/rpc/src/method/call.rs +++ b/crates/rpc/src/method/call.rs @@ -67,22 +67,32 @@ impl From for ApplicationError { } } -#[derive(serde::Deserialize, Debug, PartialEq, Eq)] -#[serde(deny_unknown_fields)] +#[derive(Debug, PartialEq, Eq)] pub struct Input { pub request: FunctionCall, pub block_id: BlockId, } -#[derive(serde::Serialize, serde::Deserialize, Clone, Debug, PartialEq, Eq)] -#[serde(deny_unknown_fields)] +#[derive(Debug, PartialEq, Eq)] pub struct FunctionCall { pub contract_address: ContractAddress, pub entry_point_selector: EntryPoint, pub calldata: Vec, } -// TODO: Not used yet, just an example for now. +impl crate::dto::DeserializeForVersion for FunctionCall { + fn deserialize(value: crate::dto::Value) -> Result { + value.deserialize_map(|value| { + Ok(Self { + contract_address: value.deserialize_serde("contract_address")?, + entry_point_selector: value.deserialize_serde("entry_point_selector")?, + calldata: value + .deserialize_array("calldata", crate::dto::Value::deserialize_serde)?, + }) + }) + } +} + impl crate::dto::DeserializeForVersion for Input { fn deserialize(value: crate::dto::Value) -> Result { value.deserialize_map(|value| { @@ -181,15 +191,18 @@ mod tests { use serde_json::json; use super::*; + use crate::dto::DeserializeForVersion; #[test] fn positional_args() { - let positional = json!([ + let positional_json = json!([ { "contract_address": "0xabcde", "entry_point_selector": "0xee", "calldata": ["0x1234", "0x2345"] }, { "block_hash": "0xbbbbbbbb" } ]); - let input = serde_json::from_value::(positional).unwrap(); + let positional = crate::dto::Value::new(positional_json, crate::RpcVersion::V08); + + let input = Input::deserialize(positional).unwrap(); let expected = Input { request: FunctionCall { contract_address: contract_address!("0xabcde"), @@ -203,12 +216,14 @@ mod tests { #[test] fn named_args() { - let named = json!({ + let named_json = json!({ "request": { "contract_address": "0xabcde", "entry_point_selector": "0xee", "calldata": ["0x1234", "0x2345"] }, "block_id": { "block_hash": "0xbbbbbbbb" } }); - let input = serde_json::from_value::(named).unwrap(); + let named = crate::dto::Value::new(named_json, crate::RpcVersion::V08); + + let input = Input::deserialize(named).unwrap(); let expected = Input { request: FunctionCall { contract_address: contract_address!("0xabcde"), diff --git a/crates/rpc/src/method/get_block_with_receipts.rs b/crates/rpc/src/method/get_block_with_receipts.rs index 5779209aa9..0e48d18329 100644 --- a/crates/rpc/src/method/get_block_with_receipts.rs +++ b/crates/rpc/src/method/get_block_with_receipts.rs @@ -19,8 +19,6 @@ pub enum Output { Pending(Arc), } -#[derive(serde::Deserialize)] -#[serde(deny_unknown_fields)] pub struct Input { pub block_id: BlockId, } 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 0b9a106be6..8445ea6af5 100644 --- a/crates/rpc/src/method/get_block_with_tx_hashes.rs +++ b/crates/rpc/src/method/get_block_with_tx_hashes.rs @@ -7,8 +7,6 @@ use crate::context::RpcContext; crate::error::generate_rpc_error_subset!(Error: BlockNotFound); -#[derive(serde::Deserialize)] -#[serde(deny_unknown_fields)] pub struct Input { pub block_id: BlockId, } diff --git a/crates/rpc/src/method/get_block_with_txs.rs b/crates/rpc/src/method/get_block_with_txs.rs index e0ae1f7856..ee0818542f 100644 --- a/crates/rpc/src/method/get_block_with_txs.rs +++ b/crates/rpc/src/method/get_block_with_txs.rs @@ -8,8 +8,6 @@ use crate::context::RpcContext; crate::error::generate_rpc_error_subset!(Error: BlockNotFound); -#[derive(serde::Deserialize)] -#[serde(deny_unknown_fields)] pub struct Input { pub block_id: BlockId, } diff --git a/crates/rpc/src/method/get_messages_status.rs b/crates/rpc/src/method/get_messages_status.rs index 6c9a4de4e1..921e2a8112 100644 --- a/crates/rpc/src/method/get_messages_status.rs +++ b/crates/rpc/src/method/get_messages_status.rs @@ -1,7 +1,6 @@ use anyhow::Context; use pathfinder_common::{L1TransactionHash, TransactionHash}; use pathfinder_ethereum::EthereumApi; -use serde::{Deserialize, Serialize}; use crate::context::RpcContext; use crate::method::get_transaction_status; @@ -23,8 +22,7 @@ impl crate::dto::DeserializeForVersion for Input { } } -#[derive(Clone, Debug, Serialize, Deserialize)] -#[serde(rename_all = "SCREAMING_SNAKE_CASE")] +#[derive(Clone, Debug)] enum FinalityStatus { Received, Rejected, @@ -32,6 +30,34 @@ enum FinalityStatus { AcceptedOnL1, } +impl crate::dto::serialize::SerializeForVersion for FinalityStatus { + fn serialize( + &self, + serializer: crate::dto::serialize::Serializer, + ) -> Result { + let status_str = match self { + FinalityStatus::Received => "RECEIVED", + FinalityStatus::Rejected => "REJECTED", + FinalityStatus::AcceptedOnL2 => "ACCEPTED_ON_L2", + FinalityStatus::AcceptedOnL1 => "ACCEPTED_ON_L1", + }; + serializer.serialize_str(status_str) + } +} + +impl crate::dto::DeserializeForVersion for FinalityStatus { + fn deserialize(value: crate::dto::Value) -> Result { + let status_str: String = value.deserialize_serde()?; + match status_str.as_str() { + "RECEIVED" => Ok(Self::Received), + "REJECTED" => Ok(Self::Rejected), + "ACCEPTED_ON_L2" => Ok(Self::AcceptedOnL2), + "ACCEPTED_ON_L1" => Ok(Self::AcceptedOnL1), + _ => Err(serde::de::Error::custom("Invalid finality status")), + } + } +} + #[derive(Clone, Debug)] pub struct L1HandlerTransactionStatus { transaction_hash: TransactionHash, diff --git a/crates/rpc/src/method/get_state_update.rs b/crates/rpc/src/method/get_state_update.rs index f5e78ed698..71c5d6ddf5 100644 --- a/crates/rpc/src/method/get_state_update.rs +++ b/crates/rpc/src/method/get_state_update.rs @@ -91,30 +91,38 @@ pub(crate) mod types { StorageAddress, StorageValue, }; - use serde::Serialize; - use serde_with::skip_serializing_none; use crate::felt::{RpcFelt, RpcFelt251}; - #[serde_with::serde_as] - #[skip_serializing_none] - #[derive(Clone, Debug, Serialize, PartialEq, Eq)] + #[derive(Clone, Debug, PartialEq, Eq)] #[cfg_attr(test, derive(serde::Deserialize))] - #[serde(deny_unknown_fields)] pub struct StateUpdate { /// None for `pending` - #[serde(default)] - #[serde_as(as = "Option")] pub block_hash: Option, /// None for `pending` - #[serde(default)] - #[serde_as(as = "Option")] pub new_root: Option, - #[serde_as(as = "RpcFelt")] pub old_root: StateCommitment, pub state_diff: StateDiff, } + impl crate::dto::serialize::SerializeForVersion for StateUpdate { + fn serialize( + &self, + serializer: crate::dto::serialize::Serializer, + ) -> Result { + let mut serializer = serializer.serialize_struct()?; + if let Some(block_hash) = self.block_hash { + serializer.serialize_field("block_hash", &RpcFelt(block_hash.0))?; + } + if let Some(new_root) = self.new_root { + serializer.serialize_field("new_root", &RpcFelt(new_root.0))?; + } + serializer.serialize_field("old_root", &RpcFelt(self.old_root.0))?; + serializer.serialize_field("state_diff", &self.state_diff)?; + serializer.end() + } + } + impl From for StateUpdate { fn from(value: pathfinder_common::StateUpdate) -> Self { let mut storage_diffs = Vec::new(); @@ -211,13 +219,10 @@ pub(crate) mod types { } /// L2 state diff. - #[serde_with::serde_as] - #[derive(Clone, Debug, Serialize, PartialEq, Eq, Default)] + #[derive(Clone, Debug, PartialEq, Eq, Default)] #[cfg_attr(test, derive(serde::Deserialize))] - #[serde(deny_unknown_fields)] pub struct StateDiff { pub storage_diffs: Vec, - #[serde_as(as = "Vec")] pub deprecated_declared_classes: Vec, pub declared_classes: Vec, pub deployed_contracts: Vec, @@ -259,26 +264,83 @@ pub(crate) mod types { } } + impl crate::dto::serialize::SerializeForVersion for StateDiff { + fn serialize( + &self, + serializer: crate::dto::serialize::Serializer, + ) -> Result { + let mut serializer = serializer.serialize_struct()?; + + serializer.serialize_iter( + "storage_diffs", + self.storage_diffs.len(), + &mut self.storage_diffs.clone().into_iter(), + )?; + serializer.serialize_iter( + "deprecated_declared_classes", + self.deprecated_declared_classes.len(), + &mut self + .deprecated_declared_classes + .clone() + .into_iter() + .map(|x| RpcFelt(x.0)), + )?; + serializer.serialize_iter( + "declared_classes", + self.declared_classes.len(), + &mut self.declared_classes.clone().into_iter(), + )?; + serializer.serialize_iter( + "deployed_contracts", + self.deployed_contracts.len(), + &mut self.deployed_contracts.clone().into_iter(), + )?; + serializer.serialize_iter( + "replaced_classes", + self.replaced_classes.len(), + &mut self.replaced_classes.clone().into_iter(), + )?; + serializer.serialize_iter( + "nonces", + self.nonces.len(), + &mut self.nonces.clone().into_iter(), + )?; + + serializer.end() + } + } + /// L2 storage diff of a contract. - #[serde_with::serde_as] - #[derive(Clone, Debug, Serialize, PartialEq, Eq, PartialOrd, Ord)] + #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] #[cfg_attr(test, derive(serde::Deserialize))] - #[serde(deny_unknown_fields)] pub struct StorageDiff { - #[serde_as(as = "RpcFelt251")] pub address: ContractAddress, pub storage_entries: Vec, } + impl crate::dto::serialize::SerializeForVersion for StorageDiff { + fn serialize( + &self, + serializer: crate::dto::serialize::Serializer, + ) -> Result { + let mut serializer = serializer.serialize_struct()?; + + serializer.serialize_field("address", &RpcFelt251(RpcFelt(self.address.0)))?; + serializer.serialize_iter( + "storage_entries", + self.storage_entries.len(), + &mut self.storage_entries.clone().into_iter(), + )?; + + serializer.end() + } + } + /// A key-value entry of a storage diff. - #[serde_with::serde_as] - #[derive(Clone, Debug, Serialize, PartialEq, Eq, PartialOrd, Ord)] + #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] #[cfg_attr(test, derive(serde::Deserialize))] - #[serde(deny_unknown_fields)] pub struct StorageEntry { - #[serde_as(as = "RpcFelt251")] pub key: StorageAddress, - #[serde_as(as = "RpcFelt")] pub value: StorageValue, } @@ -300,15 +362,25 @@ pub(crate) mod types { } } + impl crate::dto::serialize::SerializeForVersion for StorageEntry { + fn serialize( + &self, + serializer: crate::dto::serialize::Serializer, + ) -> Result { + let mut serializer = serializer.serialize_struct()?; + + serializer.serialize_field("key", &RpcFelt(self.key.0))?; + serializer.serialize_field("value", &RpcFelt(self.value.0))?; + + serializer.end() + } + } + /// L2 state diff declared Sierra class item. - #[serde_with::serde_as] - #[derive(Clone, Debug, Serialize, PartialEq, Eq)] + #[derive(Clone, Debug, PartialEq, Eq)] #[cfg_attr(test, derive(serde::Deserialize))] - #[serde(deny_unknown_fields)] pub struct DeclaredSierraClass { - #[serde_as(as = "RpcFelt")] pub class_hash: SierraHash, - #[serde_as(as = "RpcFelt")] pub compiled_class_hash: CasmHash, } @@ -321,18 +393,28 @@ pub(crate) mod types { } } + impl crate::dto::serialize::SerializeForVersion for DeclaredSierraClass { + fn serialize( + &self, + serializer: crate::dto::serialize::Serializer, + ) -> Result { + let mut serializer = serializer.serialize_struct()?; + + serializer.serialize_field("class_hash", &RpcFelt(self.class_hash.0))?; + serializer + .serialize_field("compiled_class_hash", &RpcFelt(self.compiled_class_hash.0))?; + + serializer.end() + } + } + /// L2 state diff deployed contract item. - #[serde_with::serde_as] - #[derive(Clone, Debug, Serialize, PartialEq, Eq)] + #[derive(Clone, Debug, PartialEq, Eq)] #[cfg_attr(test, derive(serde::Deserialize))] - #[serde(deny_unknown_fields)] pub struct DeployedContract { - #[serde_as(as = "RpcFelt251")] pub address: ContractAddress, - #[serde_as(as = "RpcFelt")] pub class_hash: ClassHash, } - impl From for DeployedContract { fn from(d: pathfinder_executor::types::DeployedContract) -> Self { Self { @@ -342,15 +424,25 @@ pub(crate) mod types { } } + impl crate::dto::serialize::SerializeForVersion for DeployedContract { + fn serialize( + &self, + serializer: crate::dto::serialize::Serializer, + ) -> Result { + let mut serializer = serializer.serialize_struct()?; + + serializer.serialize_field("address", &RpcFelt(self.address.0))?; + serializer.serialize_field("class_hash", &RpcFelt(self.class_hash.0))?; + + serializer.end() + } + } + /// L2 state diff replaced class item. - #[serde_with::serde_as] - #[derive(Clone, Debug, Serialize, PartialEq, Eq)] + #[derive(Clone, Debug, PartialEq, Eq)] #[cfg_attr(test, derive(serde::Deserialize))] - #[serde(deny_unknown_fields)] pub struct ReplacedClass { - #[serde_as(as = "RpcFelt251")] pub contract_address: ContractAddress, - #[serde_as(as = "RpcFelt")] pub class_hash: ClassHash, } @@ -363,23 +455,48 @@ pub(crate) mod types { } } + impl crate::dto::serialize::SerializeForVersion for ReplacedClass { + fn serialize( + &self, + serializer: crate::dto::serialize::Serializer, + ) -> Result { + let mut serializer = serializer.serialize_struct()?; + + serializer.serialize_field("contract_address", &RpcFelt(self.contract_address.0))?; + serializer.serialize_field("class_hash", &RpcFelt(self.class_hash.0))?; + + serializer.end() + } + } + /// L2 state diff nonce item. - #[serde_with::serde_as] - #[derive(Clone, Debug, Serialize, PartialEq, Eq)] + #[derive(Clone, Debug, PartialEq, Eq)] #[cfg_attr(test, derive(serde::Deserialize))] - #[serde(deny_unknown_fields)] pub struct Nonce { - #[serde_as(as = "RpcFelt251")] pub contract_address: ContractAddress, - #[serde_as(as = "RpcFelt")] pub nonce: ContractNonce, } + impl crate::dto::serialize::SerializeForVersion for Nonce { + fn serialize( + &self, + serializer: crate::dto::serialize::Serializer, + ) -> Result { + let mut serializer = serializer.serialize_struct()?; + + serializer.serialize_field("contract_address", &RpcFelt(self.contract_address.0))?; + serializer.serialize_field("nonce", &RpcFelt(self.nonce.0))?; + + serializer.end() + } + } + #[cfg(test)] mod tests { use pathfinder_common::macro_prelude::*; use super::*; + use crate::RpcVersion; #[test] fn receipt() { @@ -425,7 +542,20 @@ pub(crate) mod types { let fixture = include_str!("../../fixtures/0.50.0/state_update.json").replace([' ', '\n'], ""); - pretty_assertions_sorted::assert_eq!(serde_json::to_string(&data).unwrap(), fixture); + let fixture_pretty = serde_json::to_string_pretty( + &serde_json::from_str::(&fixture).unwrap(), + ) + .unwrap(); + + let serializer = crate::dto::serialize::Serializer::new(RpcVersion::V07); + let serialized = serde_json::to_string_pretty( + &serializer + .serialize_iter(data.len(), &mut data.clone().into_iter()) + .unwrap(), + ) + .unwrap(); + + pretty_assertions_sorted::assert_eq!(serialized, fixture_pretty); pretty_assertions_sorted::assert_eq!( serde_json::from_str::>(&fixture).unwrap(), data diff --git a/crates/rpc/src/method/get_transaction_by_block_id_and_index.rs b/crates/rpc/src/method/get_transaction_by_block_id_and_index.rs index 89fd502014..f682fb0d79 100644 --- a/crates/rpc/src/method/get_transaction_by_block_id_and_index.rs +++ b/crates/rpc/src/method/get_transaction_by_block_id_and_index.rs @@ -4,8 +4,7 @@ use pathfinder_common::{BlockId, TransactionIndex}; use crate::context::RpcContext; use crate::types::transaction::TransactionWithHash; -#[derive(serde::Deserialize, Debug, PartialEq, Eq)] -#[serde(deny_unknown_fields)] +#[derive(Debug, PartialEq, Eq)] pub struct Input { block_id: BlockId, index: TransactionIndex, @@ -100,15 +99,18 @@ mod tests { use serde_json::json; use super::*; + use crate::dto::DeserializeForVersion; #[test] fn positional_args() { - let positional = json!([ + let positional_json = json!([ {"block_hash": "0xdeadbeef"}, 1 ]); - let input = serde_json::from_value::(positional).unwrap(); + let positional = crate::dto::Value::new(positional_json, crate::RpcVersion::V08); + + let input = Input::deserialize(positional).unwrap(); assert_eq!( input, Input { @@ -120,12 +122,14 @@ mod tests { #[test] fn named_args() { - let named_args = json!({ + let named_args_json = json!({ "block_id": {"block_hash": "0xdeadbeef"}, "index": 1 }); - let input = serde_json::from_value::(named_args).unwrap(); + let named = crate::dto::Value::new(named_args_json, crate::RpcVersion::V08); + + let input = Input::deserialize(named).unwrap(); assert_eq!( input, Input { diff --git a/crates/rpc/src/method/get_transaction_by_hash.rs b/crates/rpc/src/method/get_transaction_by_hash.rs index a3e15f5e61..f5c8b1f556 100644 --- a/crates/rpc/src/method/get_transaction_by_hash.rs +++ b/crates/rpc/src/method/get_transaction_by_hash.rs @@ -6,8 +6,7 @@ use pathfinder_common::TransactionHash; use crate::context::RpcContext; -#[derive(serde::Deserialize, Debug, PartialEq, Eq)] -#[serde(deny_unknown_fields)] +#[derive(Debug, PartialEq, Eq)] pub struct Input { transaction_hash: TransactionHash, } @@ -86,12 +85,15 @@ mod tests { use serde_json::json; use super::*; + use crate::dto::DeserializeForVersion; #[test] fn positional_args() { - let positional = json!(["0xdeadbeef"]); + let positional_json = json!(["0xdeadbeef"]); + + let positional = crate::dto::Value::new(positional_json, crate::RpcVersion::V08); - let input = serde_json::from_value::(positional).unwrap(); + let input = Input::deserialize(positional).unwrap(); assert_eq!( input, Input { @@ -102,10 +104,13 @@ mod tests { #[test] fn named_args() { - let named_args = json!({ + let named_args_json = json!({ "transaction_hash": "0xdeadbeef" }); - let input = serde_json::from_value::(named_args).unwrap(); + + let named = crate::dto::Value::new(named_args_json, crate::RpcVersion::V08); + + let input = Input::deserialize(named).unwrap(); assert_eq!( input, Input { diff --git a/crates/rpc/src/types.rs b/crates/rpc/src/types.rs index 18710ab656..bb9563afe8 100644 --- a/crates/rpc/src/types.rs +++ b/crates/rpc/src/types.rs @@ -20,6 +20,16 @@ pub struct ResourceBounds { pub l1_data_gas: Option, } +impl From for pathfinder_common::transaction::ResourceBounds { + fn from(resource_bounds: ResourceBounds) -> Self { + Self { + l1_gas: resource_bounds.l1_gas.into(), + l2_gas: resource_bounds.l2_gas.into(), + l1_data_gas: resource_bounds.l1_data_gas.map(|g| g.into()), + } + } +} + impl crate::dto::DeserializeForVersion for ResourceBounds { fn deserialize(value: crate::dto::Value) -> Result { value.deserialize_map(|value| { @@ -32,16 +42,6 @@ impl crate::dto::DeserializeForVersion for ResourceBounds { } } -impl From for pathfinder_common::transaction::ResourceBounds { - fn from(resource_bounds: ResourceBounds) -> Self { - Self { - l1_gas: resource_bounds.l1_gas.into(), - l2_gas: resource_bounds.l2_gas.into(), - l1_data_gas: resource_bounds.l1_data_gas.map(|g| g.into()), - } - } -} - #[serde_as] #[derive(Copy, Clone, Debug, Default, serde::Deserialize, serde::Serialize, PartialEq, Eq)] pub struct ResourceBound { @@ -51,6 +51,15 @@ pub struct ResourceBound { pub max_price_per_unit: ResourcePricePerUnit, } +impl From for pathfinder_common::transaction::ResourceBound { + fn from(resource_bound: ResourceBound) -> Self { + Self { + max_amount: resource_bound.max_amount, + max_price_per_unit: resource_bound.max_price_per_unit, + } + } +} + impl crate::dto::DeserializeForVersion for ResourceBound { fn deserialize(value: crate::dto::Value) -> Result { value.deserialize_map(|value| { @@ -64,15 +73,6 @@ impl crate::dto::DeserializeForVersion for ResourceBound { } } -impl From for pathfinder_common::transaction::ResourceBound { - fn from(resource_bound: ResourceBound) -> Self { - Self { - max_amount: resource_bound.max_amount, - max_price_per_unit: resource_bound.max_price_per_unit, - } - } -} - #[derive(Copy, Clone, Debug, Default, serde::Deserialize, serde::Serialize, PartialEq, Eq)] pub enum DataAvailabilityMode { #[default] @@ -80,17 +80,6 @@ pub enum DataAvailabilityMode { L2, } -impl crate::dto::DeserializeForVersion for DataAvailabilityMode { - fn deserialize(value: crate::dto::Value) -> Result { - let value: String = value.deserialize_serde()?; - match value.as_str() { - "L1" => Ok(Self::L1), - "L2" => Ok(Self::L2), - _ => Err(serde_json::Error::custom("invalid data availability mode")), - } - } -} - impl From for pathfinder_common::transaction::DataAvailabilityMode { fn from(data_availability_mode: DataAvailabilityMode) -> Self { match data_availability_mode { @@ -109,6 +98,17 @@ impl From for starknet_api::data_availability::DataAvailab } } +impl crate::dto::DeserializeForVersion for DataAvailabilityMode { + fn deserialize(value: crate::dto::Value) -> Result { + let value: String = value.deserialize_serde()?; + match value.as_str() { + "L1" => Ok(Self::L1), + "L2" => Ok(Self::L2), + _ => Err(serde_json::Error::custom("invalid data availability mode")), + } + } +} + /// Groups all strictly input types of the RPC API. pub mod request { use pathfinder_common::{ diff --git a/crates/rpc/src/types/transaction.rs b/crates/rpc/src/types/transaction.rs index 154fda363e..a6f7c99035 100644 --- a/crates/rpc/src/types/transaction.rs +++ b/crates/rpc/src/types/transaction.rs @@ -21,18 +21,15 @@ use pathfinder_common::{ TransactionHash, TransactionVersion, }; -use serde::ser::SerializeStruct; -use serde::Serialize; /// Equivalent to the TXN type from the specification. #[derive(PartialEq, Debug, Clone, Eq)] pub struct Transaction(pub pathfinder_common::transaction::TransactionVariant); /// A transaction and its hash, a common structure used in the spec. -#[derive(serde::Serialize, PartialEq, Debug, Clone, Eq)] +#[derive(PartialEq, Debug, Clone, Eq)] pub struct TransactionWithHash { pub transaction_hash: TransactionHash, - #[serde(flatten)] pub txn: Transaction, } @@ -45,11 +42,23 @@ impl From for TransactionWithHash { } } -impl Serialize for Transaction { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { +impl crate::dto::serialize::SerializeForVersion for TransactionWithHash { + fn serialize( + &self, + serializer: crate::dto::serialize::Serializer, + ) -> Result { + let mut serializer = serializer.serialize_struct()?; + serializer.serialize_field("transaction_hash", &self.transaction_hash)?; + serializer.flatten(&self.txn)?; + serializer.end() + } +} + +impl crate::dto::serialize::SerializeForVersion for Transaction { + fn serialize( + &self, + serializer: crate::dto::serialize::Serializer, + ) -> Result { use pathfinder_common::transaction::TransactionVariant; match &self.0 { TransactionVariant::DeclareV0(x) => DeclareV0Helper(x).serialize(serializer), @@ -93,32 +102,32 @@ struct ResourcePricePerUnitHelper<'a>(&'a ResourcePricePerUnit); struct DataAvailabilityModeHelper<'a>(&'a DataAvailabilityMode); struct TipHelper<'a>(&'a Tip); -impl Serialize for DeclareV0Helper<'_> { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - let mut s = serializer.serialize_struct("DeclareV0", 6)?; - s.serialize_field("type", "DECLARE")?; +impl crate::dto::serialize::SerializeForVersion for DeclareV0Helper<'_> { + fn serialize( + &self, + serializer: crate::dto::serialize::Serializer, + ) -> Result { + let mut s = serializer.serialize_struct()?; + s.serialize_field("type", &"DECLARE")?; s.serialize_field("sender_address", &self.0.sender_address)?; s.serialize_field("max_fee", &self.0.max_fee)?; - s.serialize_field("version", "0x0")?; + s.serialize_field("version", &"0x0")?; s.serialize_field("signature", &self.0.signature)?; s.serialize_field("class_hash", &self.0.class_hash)?; s.end() } } -impl Serialize for DeclareV1Helper<'_> { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - let mut s = serializer.serialize_struct("DeclareV1", 7)?; - s.serialize_field("type", "DECLARE")?; +impl crate::dto::serialize::SerializeForVersion for DeclareV1Helper<'_> { + fn serialize( + &self, + serializer: crate::dto::serialize::Serializer, + ) -> Result { + let mut s = serializer.serialize_struct()?; + s.serialize_field("type", &"DECLARE")?; s.serialize_field("sender_address", &self.0.sender_address)?; s.serialize_field("max_fee", &self.0.max_fee)?; - s.serialize_field("version", "0x1")?; + s.serialize_field("version", &"0x1")?; s.serialize_field("signature", &self.0.signature)?; s.serialize_field("nonce", &self.0.nonce)?; s.serialize_field("class_hash", &self.0.class_hash)?; @@ -126,17 +135,17 @@ impl Serialize for DeclareV1Helper<'_> { } } -impl Serialize for DeclareV2Helper<'_> { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - let mut s = serializer.serialize_struct("DeclareV2", 8)?; - s.serialize_field("type", "DECLARE")?; +impl crate::dto::serialize::SerializeForVersion for DeclareV2Helper<'_> { + fn serialize( + &self, + serializer: crate::dto::serialize::Serializer, + ) -> Result { + let mut s = serializer.serialize_struct()?; + s.serialize_field("type", &"DECLARE")?; s.serialize_field("sender_address", &self.0.sender_address)?; s.serialize_field("compiled_class_hash", &self.0.compiled_class_hash)?; s.serialize_field("max_fee", &self.0.max_fee)?; - s.serialize_field("version", "0x2")?; + s.serialize_field("version", &"0x2")?; s.serialize_field("signature", &self.0.signature)?; s.serialize_field("nonce", &self.0.nonce)?; s.serialize_field("class_hash", &self.0.class_hash)?; @@ -144,16 +153,16 @@ impl Serialize for DeclareV2Helper<'_> { } } -impl Serialize for DeclareV3Helper<'_> { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - let mut s = serializer.serialize_struct("DeclareV3", 13)?; - s.serialize_field("type", "DECLARE")?; +impl crate::dto::serialize::SerializeForVersion for DeclareV3Helper<'_> { + fn serialize( + &self, + serializer: crate::dto::serialize::Serializer, + ) -> Result { + let mut s = serializer.serialize_struct()?; + s.serialize_field("type", &"DECLARE")?; s.serialize_field("sender_address", &self.0.sender_address)?; s.serialize_field("compiled_class_hash", &self.0.compiled_class_hash)?; - s.serialize_field("version", "0x3")?; + s.serialize_field("version", &"0x3")?; s.serialize_field("signature", &self.0.signature)?; s.serialize_field("nonce", &self.0.nonce)?; s.serialize_field("class_hash", &self.0.class_hash)?; @@ -176,17 +185,17 @@ impl Serialize for DeclareV3Helper<'_> { } } -impl Serialize for DeployV0Helper<'_> { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - let mut s = serializer.serialize_struct("Deploy", 5)?; +impl crate::dto::serialize::SerializeForVersion for DeployV0Helper<'_> { + fn serialize( + &self, + serializer: crate::dto::serialize::Serializer, + ) -> Result { + let mut s = serializer.serialize_struct()?; s.serialize_field( "version", &TransactionVersionHelper(&TransactionVersion::ZERO), )?; - s.serialize_field("type", "DEPLOY")?; + s.serialize_field("type", &"DEPLOY")?; s.serialize_field("contract_address_salt", &self.0.contract_address_salt)?; s.serialize_field("constructor_calldata", &self.0.constructor_calldata)?; s.serialize_field("class_hash", &self.0.class_hash)?; @@ -194,17 +203,17 @@ impl Serialize for DeployV0Helper<'_> { } } -impl Serialize for DeployV1Helper<'_> { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - let mut s = serializer.serialize_struct("Deploy", 5)?; +impl crate::dto::serialize::SerializeForVersion for DeployV1Helper<'_> { + fn serialize( + &self, + serializer: crate::dto::serialize::Serializer, + ) -> Result { + let mut s = serializer.serialize_struct()?; s.serialize_field( "version", &TransactionVersionHelper(&TransactionVersion::ONE), )?; - s.serialize_field("type", "DEPLOY")?; + s.serialize_field("type", &"DEPLOY")?; s.serialize_field("contract_address_salt", &self.0.contract_address_salt)?; s.serialize_field("constructor_calldata", &self.0.constructor_calldata)?; s.serialize_field("class_hash", &self.0.class_hash)?; @@ -212,15 +221,15 @@ impl Serialize for DeployV1Helper<'_> { } } -impl Serialize for DeployAccountV1Helper<'_> { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - let mut s = serializer.serialize_struct("DeployAccount", 8)?; - s.serialize_field("type", "DEPLOY_ACCOUNT")?; +impl crate::dto::serialize::SerializeForVersion for DeployAccountV1Helper<'_> { + fn serialize( + &self, + serializer: crate::dto::serialize::Serializer, + ) -> Result { + let mut s = serializer.serialize_struct()?; + s.serialize_field("type", &"DEPLOY_ACCOUNT")?; s.serialize_field("max_fee", &self.0.max_fee)?; - s.serialize_field("version", "0x1")?; + s.serialize_field("version", &"0x1")?; s.serialize_field("signature", &self.0.signature)?; s.serialize_field("nonce", &self.0.nonce)?; s.serialize_field("contract_address_salt", &self.0.contract_address_salt)?; @@ -230,14 +239,14 @@ impl Serialize for DeployAccountV1Helper<'_> { } } -impl Serialize for DeployAccountV3Helper<'_> { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - let mut s = serializer.serialize_struct("DeployAccount", 12)?; - s.serialize_field("type", "DEPLOY_ACCOUNT")?; - s.serialize_field("version", "0x3")?; +impl crate::dto::serialize::SerializeForVersion for DeployAccountV3Helper<'_> { + fn serialize( + &self, + serializer: crate::dto::serialize::Serializer, + ) -> Result { + let mut s = serializer.serialize_struct()?; + s.serialize_field("type", &"DEPLOY_ACCOUNT")?; + s.serialize_field("version", &"0x3")?; s.serialize_field("signature", &self.0.signature)?; s.serialize_field("nonce", &self.0.nonce)?; s.serialize_field("contract_address_salt", &self.0.contract_address_salt)?; @@ -261,15 +270,15 @@ impl Serialize for DeployAccountV3Helper<'_> { } } -impl Serialize for InvokeV0Helper<'_> { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - let mut s = serializer.serialize_struct("InvokeV0", 7)?; - s.serialize_field("type", "INVOKE")?; +impl crate::dto::serialize::SerializeForVersion for InvokeV0Helper<'_> { + fn serialize( + &self, + serializer: crate::dto::serialize::Serializer, + ) -> Result { + let mut s = serializer.serialize_struct()?; + s.serialize_field("type", &"INVOKE")?; s.serialize_field("max_fee", &self.0.max_fee)?; - s.serialize_field("version", "0x0")?; + s.serialize_field("version", &"0x0")?; s.serialize_field("signature", &self.0.signature)?; s.serialize_field("contract_address", &self.0.sender_address)?; s.serialize_field("entry_point_selector", &self.0.entry_point_selector)?; @@ -278,33 +287,33 @@ impl Serialize for InvokeV0Helper<'_> { } } -impl Serialize for InvokeV1Helper<'_> { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - let mut s = serializer.serialize_struct("InvokeV1", 7)?; - s.serialize_field("type", "INVOKE")?; +impl crate::dto::serialize::SerializeForVersion for InvokeV1Helper<'_> { + fn serialize( + &self, + serializer: crate::dto::serialize::Serializer, + ) -> Result { + let mut s = serializer.serialize_struct()?; + s.serialize_field("type", &"INVOKE")?; s.serialize_field("sender_address", &self.0.sender_address)?; s.serialize_field("calldata", &self.0.calldata)?; s.serialize_field("max_fee", &self.0.max_fee)?; - s.serialize_field("version", "0x1")?; + s.serialize_field("version", &"0x1")?; s.serialize_field("signature", &self.0.signature)?; s.serialize_field("nonce", &self.0.nonce)?; s.end() } } -impl Serialize for InvokeV3Helper<'_> { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - let mut s = serializer.serialize_struct("InvokeV3", 12)?; - s.serialize_field("type", "INVOKE")?; +impl crate::dto::serialize::SerializeForVersion for InvokeV3Helper<'_> { + fn serialize( + &self, + serializer: crate::dto::serialize::Serializer, + ) -> Result { + let mut s = serializer.serialize_struct()?; + s.serialize_field("type", &"INVOKE")?; s.serialize_field("sender_address", &self.0.sender_address)?; s.serialize_field("calldata", &self.0.calldata)?; - s.serialize_field("version", "0x3")?; + s.serialize_field("version", &"0x3")?; s.serialize_field("signature", &self.0.signature)?; s.serialize_field("nonce", &self.0.nonce)?; s.serialize_field( @@ -326,17 +335,17 @@ impl Serialize for InvokeV3Helper<'_> { } } -impl Serialize for L1HandlerHelper<'_> { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - let mut s = serializer.serialize_struct("L1Handler", 6)?; +impl crate::dto::serialize::SerializeForVersion for L1HandlerHelper<'_> { + fn serialize( + &self, + serializer: crate::dto::serialize::Serializer, + ) -> Result { + let mut s = serializer.serialize_struct()?; s.serialize_field( "version", &TransactionVersionHelper(&TransactionVersion::ZERO), )?; - s.serialize_field("type", "L1_HANDLER")?; + s.serialize_field("type", &"L1_HANDLER")?; s.serialize_field("nonce", &self.0.nonce)?; s.serialize_field("contract_address", &self.0.contract_address)?; s.serialize_field("entry_point_selector", &self.0.entry_point_selector)?; @@ -345,34 +354,34 @@ impl Serialize for L1HandlerHelper<'_> { } } -impl Serialize for TransactionVersionHelper<'_> { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { +impl crate::dto::serialize::SerializeForVersion for TransactionVersionHelper<'_> { + fn serialize( + &self, + serializer: crate::dto::serialize::Serializer, + ) -> Result { use pathfinder_serde::bytes_to_hex_str; serializer.serialize_str(&bytes_to_hex_str(self.0 .0.as_be_bytes())) } } -impl Serialize for ResourceBoundsHelper<'_> { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - let mut s = serializer.serialize_struct("ResourceBounds", 2)?; +impl crate::dto::serialize::SerializeForVersion for ResourceBoundsHelper<'_> { + fn serialize( + &self, + serializer: crate::dto::serialize::Serializer, + ) -> Result { + let mut s = serializer.serialize_struct()?; s.serialize_field("l1_gas", &ResourceBoundHelper(&self.0.l1_gas))?; s.serialize_field("l2_gas", &ResourceBoundHelper(&self.0.l2_gas))?; s.end() } } -impl Serialize for ResourceBoundHelper<'_> { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - let mut s = serializer.serialize_struct("ResourceBound", 2)?; +impl crate::dto::serialize::SerializeForVersion for ResourceBoundHelper<'_> { + fn serialize( + &self, + serializer: crate::dto::serialize::Serializer, + ) -> Result { + let mut s = serializer.serialize_struct()?; s.serialize_field("max_amount", &ResourceAmountHelper(&self.0.max_amount))?; s.serialize_field( "max_price_per_unit", @@ -382,31 +391,31 @@ impl Serialize for ResourceBoundHelper<'_> { } } -impl Serialize for ResourceAmountHelper<'_> { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { +impl crate::dto::serialize::SerializeForVersion for ResourceAmountHelper<'_> { + fn serialize( + &self, + serializer: crate::dto::serialize::Serializer, + ) -> Result { use pathfinder_serde::bytes_to_hex_str; serializer.serialize_str(&bytes_to_hex_str(&self.0 .0.to_be_bytes())) } } -impl Serialize for ResourcePricePerUnitHelper<'_> { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { +impl crate::dto::serialize::SerializeForVersion for ResourcePricePerUnitHelper<'_> { + fn serialize( + &self, + serializer: crate::dto::serialize::Serializer, + ) -> Result { use pathfinder_serde::bytes_to_hex_str; serializer.serialize_str(&bytes_to_hex_str(&self.0 .0.to_be_bytes())) } } -impl Serialize for DataAvailabilityModeHelper<'_> { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { +impl crate::dto::serialize::SerializeForVersion for DataAvailabilityModeHelper<'_> { + fn serialize( + &self, + serializer: crate::dto::serialize::Serializer, + ) -> Result { match self.0 { DataAvailabilityMode::L1 => serializer.serialize_str("L1"), DataAvailabilityMode::L2 => serializer.serialize_str("L2"), @@ -414,11 +423,11 @@ impl Serialize for DataAvailabilityModeHelper<'_> { } } -impl Serialize for TipHelper<'_> { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { +impl crate::dto::serialize::SerializeForVersion for TipHelper<'_> { + fn serialize( + &self, + serializer: crate::dto::serialize::Serializer, + ) -> Result { use pathfinder_serde::bytes_to_hex_str; serializer.serialize_str(&bytes_to_hex_str(&self.0 .0.to_be_bytes())) } @@ -437,6 +446,8 @@ mod tests { use serde_json::json; use super::*; + use crate::dto::serialize::{SerializeForVersion, Serializer}; + use crate::RpcVersion; #[test] fn declare_v0() { @@ -460,7 +471,11 @@ mod tests { "class_hash": "0x123", }); let uut = Transaction(TransactionVariant::DeclareV0(original)); - let result = serde_json::to_value(uut).unwrap(); + let result = uut + .serialize(Serializer { + version: RpcVersion::V07, + }) + .unwrap(); assert_eq!(result, expected); } @@ -488,7 +503,11 @@ mod tests { "nonce": "0xaabbcc", }); let uut = Transaction(TransactionVariant::DeclareV1(original)); - let result = serde_json::to_value(uut).unwrap(); + let result = uut + .serialize(Serializer { + version: RpcVersion::V07, + }) + .unwrap(); assert_eq!(result, expected); } @@ -519,7 +538,11 @@ mod tests { "compiled_class_hash": "0xbbbbb", }); let uut = Transaction(original); - let result = serde_json::to_value(uut).unwrap(); + let result = uut + .serialize(Serializer { + version: RpcVersion::V07, + }) + .unwrap(); assert_eq!(result, expected); } @@ -576,7 +599,11 @@ mod tests { "account_deployment_data": [], }); let uut = Transaction(original); - let result = serde_json::to_value(uut).unwrap(); + let result = uut + .serialize(Serializer { + version: RpcVersion::V07, + }) + .unwrap(); assert_eq!(result, expected); } @@ -602,7 +629,11 @@ mod tests { "version": "0x0", }); let uut = Transaction(original); - let result = serde_json::to_value(uut).unwrap(); + let result = uut + .serialize(Serializer { + version: RpcVersion::V07, + }) + .unwrap(); assert_eq!(result, expected); } @@ -634,7 +665,11 @@ mod tests { "class_hash": "0x123", }); let uut = Transaction(original); - let result = serde_json::to_value(uut).unwrap(); + let result = uut + .serialize(Serializer { + version: RpcVersion::V07, + }) + .unwrap(); assert_eq!(result, expected); } @@ -690,7 +725,11 @@ mod tests { "paymaster_data": [], }); let uut = Transaction(original); - let result = serde_json::to_value(uut).unwrap(); + let result = uut + .serialize(Serializer { + version: RpcVersion::V07, + }) + .unwrap(); assert_eq!(result, expected); } @@ -720,7 +759,11 @@ mod tests { "signature": ["0xa1b1", "0x1a1b"], }); let uut = Transaction(original); - let result = serde_json::to_value(uut).unwrap(); + let result = uut + .serialize(Serializer { + version: RpcVersion::V07, + }) + .unwrap(); assert_eq!(result, expected); } @@ -749,7 +792,11 @@ mod tests { "nonce": "0xaabbcc", }); let uut = Transaction(original); - let result = serde_json::to_value(uut).unwrap(); + let result = uut + .serialize(Serializer { + version: RpcVersion::V07, + }) + .unwrap(); assert_eq!(result, expected); } @@ -804,7 +851,11 @@ mod tests { "account_deployment_data": [], }); let uut = Transaction(original); - let result = serde_json::to_value(uut).unwrap(); + let result = uut + .serialize(Serializer { + version: RpcVersion::V07, + }) + .unwrap(); assert_eq!(result, expected); } @@ -828,7 +879,11 @@ mod tests { "version": "0x0", }); let uut = Transaction(original); - let result = serde_json::to_value(uut).unwrap(); + let result = uut + .serialize(Serializer { + version: RpcVersion::V07, + }) + .unwrap(); assert_eq!(result, expected); } diff --git a/crates/rpc/src/v07/dto/receipt.rs b/crates/rpc/src/v07/dto/receipt.rs index b7a6a49570..a19e59c6e8 100644 --- a/crates/rpc/src/v07/dto/receipt.rs +++ b/crates/rpc/src/v07/dto/receipt.rs @@ -1,32 +1,38 @@ use pathfinder_common::prelude::*; -use pathfinder_serde::H256AsNoLeadingZerosHexStr; use serde::Serialize; use crate::types::receipt; use crate::types::reply::BlockStatus; use crate::PendingData; -#[derive(Serialize)] +type CommonTransaction = pathfinder_common::transaction::Transaction; +type CommonReceipt = pathfinder_common::receipt::Receipt; +type CommonEvent = pathfinder_common::event::Event; + pub struct BlockWithReceipts { status: BlockStatus, - #[serde(flatten)] header: crate::v07::dto::header::Header, - #[serde(flatten)] body: BlockBodyWithReceipts, } -#[derive(Serialize)] +impl crate::dto::serialize::SerializeForVersion for BlockWithReceipts { + fn serialize( + &self, + serializer: crate::dto::serialize::Serializer, + ) -> Result { + let mut serializer = serializer.serialize_struct()?; + serializer.serialize_field("status", &self.status)?; + serializer.flatten(&self.header)?; + serializer.flatten(&self.body)?; + serializer.end() + } +} + pub struct PendingBlockWithReceipts { - #[serde(flatten)] header: crate::v07::dto::header::PendingHeader, - #[serde(flatten)] body: BlockBodyWithReceipts, } -type CommonTransaction = pathfinder_common::transaction::Transaction; -type CommonReceipt = pathfinder_common::receipt::Receipt; -type CommonEvent = pathfinder_common::event::Event; - impl From for PendingBlockWithReceipts { fn from(value: PendingData) -> Self { let body = value @@ -46,7 +52,18 @@ impl From for PendingBlockWithReceipts { } } -#[derive(Serialize)] +impl crate::dto::serialize::SerializeForVersion for PendingBlockWithReceipts { + fn serialize( + &self, + serializer: crate::dto::serialize::Serializer, + ) -> Result { + let mut serializer = serializer.serialize_struct()?; + serializer.flatten(&self.header)?; + serializer.flatten(&self.body)?; + serializer.end() + } +} + struct BlockBodyWithReceipts { transactions: Vec, } @@ -65,7 +82,21 @@ impl BlockBodyWithReceipts { } } -#[derive(Serialize)] +impl crate::dto::serialize::SerializeForVersion for BlockBodyWithReceipts { + fn serialize( + &self, + serializer: crate::dto::serialize::Serializer, + ) -> Result { + let mut serializer = serializer.serialize_struct()?; + serializer.serialize_iter( + "transactions", + self.transactions.len(), + &mut self.transactions.iter(), + )?; + serializer.end() + } +} + // Inner type of block with receipts struct TransactionWithReceipt { transaction: crate::types::transaction::TransactionWithHash, @@ -89,67 +120,151 @@ impl TransactionWithReceipt { } } -#[serde_with::serde_as] -#[derive(Serialize)] -#[serde(tag = "type", rename_all = "SCREAMING_SNAKE_CASE")] +impl crate::dto::serialize::SerializeForVersion for &TransactionWithReceipt { + fn serialize( + &self, + serializer: crate::dto::serialize::Serializer, + ) -> Result { + let mut serializer = serializer.serialize_struct()?; + serializer.serialize_field("transaction", &self.transaction)?; + serializer.serialize_field("receipt", &self.receipt)?; + serializer.end() + } +} + #[allow(unused)] pub enum TxnReceipt { Invoke { - #[serde(flatten)] common: CommonReceiptProperties, }, L1Handler { - #[serde_as(as = "H256AsNoLeadingZerosHexStr")] + // #[serde_as(as = "H256AsNoLeadingZerosHexStr")] TODO!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! message_hash: primitive_types::H256, - #[serde(flatten)] common: CommonReceiptProperties, }, Declare { - #[serde(flatten)] common: CommonReceiptProperties, }, Deploy { contract_address: ContractAddress, - #[serde(flatten)] common: CommonReceiptProperties, }, DeployAccount { contract_address: ContractAddress, - #[serde(flatten)] common: CommonReceiptProperties, }, } -#[serde_with::serde_as] -#[derive(Serialize)] -#[serde(tag = "type", rename_all = "SCREAMING_SNAKE_CASE")] +impl crate::dto::serialize::SerializeForVersion for TxnReceipt { + fn serialize( + &self, + serializer: crate::dto::serialize::Serializer, + ) -> Result { + let mut serializer = serializer.serialize_struct()?; + match self { + Self::Invoke { common } => { + serializer.serialize_field("type", &"INVOKE")?; + serializer.flatten(common)?; + } + Self::L1Handler { + message_hash, + common, + } => { + serializer.serialize_field("type", &"L1_HANDLER")?; + serializer.serialize_field("message_hash", message_hash)?; + serializer.flatten(common)?; + } + Self::Declare { common } => { + serializer.serialize_field("type", &"DECLARE")?; + serializer.flatten(common)?; + } + Self::Deploy { + contract_address, + common, + } => { + serializer.serialize_field("type", &"DEPLOY")?; + serializer.serialize_field("contract_address", contract_address)?; + serializer.flatten(common)?; + } + Self::DeployAccount { + contract_address, + common, + } => { + serializer.serialize_field("type", &"DEPLOY_ACCOUNT")?; + serializer.serialize_field("contract_address", contract_address)?; + serializer.flatten(common)?; + } + } + serializer.end() + } +} + pub enum PendingTxnReceipt { Invoke { - #[serde(flatten)] common: PendingCommonReceiptProperties, }, L1Handler { - #[serde_as(as = "H256AsNoLeadingZerosHexStr")] + //#[serde_as(as = "H256AsNoLeadingZerosHexStr")] TODO!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! message_hash: primitive_types::H256, - #[serde(flatten)] common: PendingCommonReceiptProperties, }, Declare { - #[serde(flatten)] common: PendingCommonReceiptProperties, }, Deploy { contract_address: ContractAddress, - #[serde(flatten)] common: PendingCommonReceiptProperties, }, DeployAccount { contract_address: ContractAddress, - #[serde(flatten)] common: PendingCommonReceiptProperties, }, } +impl crate::dto::serialize::SerializeForVersion for PendingTxnReceipt { + fn serialize( + &self, + serializer: crate::dto::serialize::Serializer, + ) -> Result { + let mut serializer = serializer.serialize_struct()?; + match self { + Self::Invoke { common } => { + serializer.serialize_field("type", &"INVOKE")?; + serializer.flatten(common)?; + } + Self::L1Handler { + message_hash, + common, + } => { + serializer.serialize_field("type", &"L1_HANDLER")?; + serializer.serialize_field("message_hash", message_hash)?; + serializer.flatten(common)?; + } + Self::Declare { common } => { + serializer.serialize_field("type", &"DECLARE")?; + serializer.flatten(common)?; + } + Self::Deploy { + contract_address, + common, + } => { + serializer.serialize_field("type", &"DEPLOY")?; + serializer.serialize_field("contract_address", contract_address)?; + serializer.flatten(common)?; + } + Self::DeployAccount { + contract_address, + common, + } => { + serializer.serialize_field("type", &"DEPLOY_ACCOUNT")?; + serializer.serialize_field("contract_address", contract_address)?; + serializer.flatten(common)?; + } + } + serializer.end() + } +} + impl PendingTxnReceipt { pub fn from_common( transaction: &CommonTransaction, @@ -342,6 +457,8 @@ mod tests { use pretty_assertions_sorted::assert_eq; use super::*; + use crate::dto::serialize::{SerializeForVersion, Serializer}; + use crate::RpcVersion; #[test] fn txn_receipt() { @@ -404,7 +521,11 @@ mod tests { }, }; - let encoded = serde_json::to_value(uut).unwrap(); + let encoded = uut + .serialize(Serializer { + version: RpcVersion::V07, + }) + .unwrap(); assert_eq!(encoded, expected); } @@ -465,7 +586,11 @@ mod tests { }, }; - let encoded = serde_json::to_value(uut).unwrap(); + let encoded = uut + .serialize(Serializer { + version: RpcVersion::V07, + }) + .unwrap(); assert_eq!(encoded, expected); } }