From d97918aa4c60b8c7c070f78065a52ef6f00534a7 Mon Sep 17 00:00:00 2001 From: clint Date: Fri, 8 Sep 2023 02:31:13 +0800 Subject: [PATCH] feat: Improve trace function --- examples/trace.rs | 19 +++ starknet-core/src/types/trace.rs | 86 +++++--------- .../src/sequencer/models/conversions.rs | 110 ++++++++++++++++++ .../src/sequencer/models/trace.rs | 3 +- .../src/sequencer/models/transaction.rs | 3 +- starknet-providers/src/sequencer/provider.rs | 22 +++- 6 files changed, 182 insertions(+), 61 deletions(-) create mode 100644 examples/trace.rs diff --git a/examples/trace.rs b/examples/trace.rs new file mode 100644 index 00000000..d10c5fec --- /dev/null +++ b/examples/trace.rs @@ -0,0 +1,19 @@ +use starknet_macros::felt; +use starknet_providers::{Provider, SequencerGatewayProvider}; + +#[tokio::main] +async fn main() { + let provider = SequencerGatewayProvider::starknet_alpha_goerli(); + + // https://testnet.starkscan.co/tx/0x023cffcb294f338aad5c8351e0a5d49db6625f09e1df6ac5ebc06649bfbd1345#overview + let hash = felt!("0x023cffcb294f338aad5c8351e0a5d49db6625f09e1df6ac5ebc06649bfbd1345"); + let tx_trace = provider.trace_transaction(hash).await.unwrap(); + println!("{:?}", tx_trace); + dbg!(tx_trace); + + // https://testnet.starkscan.co/block/0x7991a152b4a8d4e9a2d424808a93ad5ae2f4698a6b8e04d0c043f7e4996aabf + let hash = felt!("0x7991a152b4a8d4e9a2d424808a93ad5ae2f4698a6b8e04d0c043f7e4996aabf"); + let block_trace = provider.trace_block_transactions(hash).await.unwrap(); + println!("{:?}", block_trace); + dbg!(block_trace); +} diff --git a/starknet-core/src/types/trace.rs b/starknet-core/src/types/trace.rs index f0deedb6..2c0fd26a 100644 --- a/starknet-core/src/types/trace.rs +++ b/starknet-core/src/types/trace.rs @@ -10,65 +10,24 @@ use super::{FieldElement, UfeHex}; use serde::{Deserialize, Serialize}; use serde_with::serde_as; -#[serde_as] -#[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] -pub struct TransactionTraceWithHash { - #[serde_as(as = "UfeHex")] - pub transaction_hash: FieldElement, - pub trace_root: TransactionTrace, -} - -/// the execution trace of an invoke transaction -#[serde_as] -#[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] -pub struct InvokeTransactionTrace { - /// An object describing the invocation of validation. - pub validate_invocation: FunctionInvocation, - /// An object describing the invocation of a specific function. - pub execute_invocation: ExecuteInvocation, - /// An object describing the invocation of a fee transfer. - pub fee_transfer_invocation: FunctionInvocation, -} - -/// The execution trace of a declare transaction -#[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] -pub struct DeclareTransactionTrace { - /// An object describing the invocation of validation. - pub validate_invocation: FunctionInvocation, - /// An object describing the invocation of a fee transfer. - pub fee_transfer_invocation: FunctionInvocation, -} - -/// The execution trace of a deploy account transaction #[derive(Debug, Clone, Serialize, Deserialize)] #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] -pub struct DeployAccountTransactionTrace { +pub struct TransactionTrace { /// An object describing the invocation of validation. - pub validate_invocation: FunctionInvocation, - /// The trace of the __execute__ call or constructor call, depending on the transaction type (none for declare transactions) - pub constructor_invocation: FunctionInvocation, + #[serde(skip_serializing_if = "Option::is_none")] + pub validate_invocation: Option, /// An object describing the invocation of a fee transfer. - pub fee_transfer_invocation: FunctionInvocation, -} - -/// The execution trace of an L1 handler transaction -#[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] -pub struct L1HandlerTransactionTrace { - /// the trace of the __execute__ call or constructor call, depending on the transaction type (none for declare transactions). - pub function_invocation: FunctionInvocation, -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -#[serde(untagged)] -pub enum TransactionTrace { - Invoke(InvokeTransactionTrace), - Declare(DeclareTransactionTrace), - DeployAccount(DeployAccountTransactionTrace), - L1Handler(L1HandlerTransactionTrace), + #[serde(skip_serializing_if = "Option::is_none")] + pub fee_transfer_invocation: Option, + /// An object describing the invocation of a specific function. + #[serde(skip_serializing_if = "Option::is_none")] + pub execute_invocation: Option, + /// An object describing the invocation of a specific function. + #[serde(skip_serializing_if = "Option::is_none")] + pub function_invocation: Option, + /// An object describing the invocation of a specific function. + #[serde(skip_serializing_if = "Option::is_none")] + pub constructor_invocation: Option, } /// The trace of the __execute__ call or constructor call, depending on the transaction type (none for declare transactions) @@ -81,7 +40,6 @@ pub enum ExecuteInvocation { Reverted(String), } -/// The execution trace and consuemd resources of the required transactions #[derive(Debug, Clone, Serialize, Deserialize)] #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] pub struct SimulatedTransaction { @@ -90,3 +48,19 @@ pub struct SimulatedTransaction { /// The transaction's resources and fee pub fee_estimation: FeeEstimate, } + +/// The execution trace and consuemd resources of the required transactions +#[derive(Debug, Clone, Serialize, Deserialize)] +#[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] +pub struct SimulatedTransactions { + pub simulated_transactions: Vec, +} + +#[serde_as] +#[derive(Debug, Clone, Serialize, Deserialize)] +#[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] +pub struct TransactionTraceWithHash { + #[serde_as(as = "UfeHex")] + pub transaction_hash: FieldElement, + pub trace_root: TransactionTrace, +} diff --git a/starknet-providers/src/sequencer/models/conversions.rs b/starknet-providers/src/sequencer/models/conversions.rs index 2900728a..693390cb 100644 --- a/starknet-providers/src/sequencer/models/conversions.rs +++ b/starknet-providers/src/sequencer/models/conversions.rs @@ -1,5 +1,9 @@ use std::sync::Arc; +use crate::sequencer::models::trace::{ + CallType, FunctionInvocation, OrderedEventResponse, OrderedL2ToL1MessageResponse, + TransactionTraceWithHash, +}; use starknet_core::types::{self as core, contract::legacy as contract_legacy, FieldElement}; use super::{ @@ -924,3 +928,109 @@ fn convert_legacy_entry_point( selector: value.selector, } } + +impl From for core::TransactionTrace { + fn from(value: TransactionTrace) -> Self { + core::TransactionTrace { + validate_invocation: value.validate_invocation.map(Into::into), + fee_transfer_invocation: value.fee_transfer_invocation.map(Into::into), + execute_invocation: None, + function_invocation: value.function_invocation.map(Into::into), + constructor_invocation: None, + } + } +} + +impl From for core::CallType { + fn from(value: CallType) -> Self { + match value { + CallType::Call => core::CallType::Call, + CallType::Delegate => core::CallType::LibraryCall, + } + } +} + +impl From for core::FunctionInvocation { + fn from(value: FunctionInvocation) -> Self { + core::FunctionInvocation { + contract_address: value.contract_address, + entry_point_selector: value.selector.unwrap_or_default().into(), + calldata: value.calldata.clone(), + caller_address: value.caller_address, + class_hash: value.class_hash.unwrap_or_default(), + entry_point_type: value.entry_point_type.unwrap_or_default().into(), + call_type: value.call_type.unwrap_or_default().into(), + result: value.result.clone(), + calls: value.internal_calls.into_iter().map(Into::into).collect(), + events: value.events.into_iter().map(Into::into).collect(), + messages: value.messages.into_iter().map(Into::into).collect(), + } + } +} + +impl From for core::NestedCall { + fn from(value: FunctionInvocation) -> Self { + core::NestedCall { + contract_address: value.contract_address, + entry_point_selector: value.selector.unwrap_or_default().into(), + calldata: value.calldata.clone(), + caller_address: value.caller_address, + class_hash: value.class_hash.unwrap_or_default(), + entry_point_type: value.entry_point_type.unwrap_or_default().into(), + call_type: value.call_type.unwrap_or_default().into(), + result: value.result.clone(), + calls: value.internal_calls.into_iter().map(Into::into).collect(), + events: value.events.into_iter().map(Into::into).collect(), + messages: value.messages.into_iter().map(Into::into).collect(), + } + } +} + +impl From for core::Event { + fn from(value: OrderedEventResponse) -> Self { + core::Event { + from_address: value.order.into(), + keys: value.keys.clone(), + data: value.data.clone(), + } + } +} + +impl From for core::MsgToL1 { + fn from(value: OrderedL2ToL1MessageResponse) -> Self { + core::MsgToL1 { + from_address: value.order.into(), + to_address: FieldElement::from_byte_slice_be(value.to_address.as_bytes()) + .unwrap_or_default(), + payload: value.payload.clone(), + } + } +} + +impl From for core::EntryPointType { + fn from(value: EntryPointType) -> Self { + match value { + EntryPointType::External => core::EntryPointType::External, + EntryPointType::L1Handler => core::EntryPointType::L1Handler, + EntryPointType::Constructor => core::EntryPointType::Constructor, + } + } +} + +impl From for core::SimulatedTransaction { + fn from(value: TransactionSimulationInfo) -> Self { + core::SimulatedTransaction { + fee_estimation: value.fee_estimation.into(), + transaction_trace: value.trace.into(), + } + } +} + +impl From for core::TransactionTraceWithHash { + fn from(value: TransactionTraceWithHash) -> Self { + core::TransactionTraceWithHash { + transaction_hash: value.transaction_hash, + trace_root: value.trace.into(), + } + } +} diff --git a/starknet-providers/src/sequencer/models/trace.rs b/starknet-providers/src/sequencer/models/trace.rs index 922f68b3..efbecf48 100644 --- a/starknet-providers/src/sequencer/models/trace.rs +++ b/starknet-providers/src/sequencer/models/trace.rs @@ -39,10 +39,11 @@ pub struct TransactionTraceWithHash { pub transaction_hash: FieldElement, } -#[derive(Debug, Deserialize, PartialEq, Eq)] +#[derive(Debug, Deserialize, PartialEq, Eq, Default)] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] pub enum CallType { + #[default] Call, Delegate, } diff --git a/starknet-providers/src/sequencer/models/transaction.rs b/starknet-providers/src/sequencer/models/transaction.rs index 118e58c3..d64da55f 100644 --- a/starknet-providers/src/sequencer/models/transaction.rs +++ b/starknet-providers/src/sequencer/models/transaction.rs @@ -72,12 +72,13 @@ pub struct TransactionInfo { pub transaction_index: Option, } -#[derive(Debug, Deserialize, PartialEq, Eq)] +#[derive(Debug, Deserialize, PartialEq, Eq, Default)] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] pub enum EntryPointType { External, L1Handler, + #[default] Constructor, } diff --git a/starknet-providers/src/sequencer/provider.rs b/starknet-providers/src/sequencer/provider.rs index bc0e5123..895fcdf6 100644 --- a/starknet-providers/src/sequencer/provider.rs +++ b/starknet-providers/src/sequencer/provider.rs @@ -405,7 +405,19 @@ impl Provider for SequencerGatewayProvider { I: AsRef> + Send + Sync, S: AsRef> + Send + Sync, { - todo!() + let tx = transactions.as_ref().first().unwrap(); + let skip_validate = simulation_flags + .as_ref() + .iter() + .find(|item| matches!(item, SimulationFlag::SkipValidate)); + let result = self + .simulate_transaction( + tx.clone().try_into()?, + block_id.as_ref().clone().into(), + skip_validate.is_some(), + ) + .await?; + Ok(vec![result.into()]) } async fn trace_transaction( @@ -415,7 +427,9 @@ impl Provider for SequencerGatewayProvider { where H: AsRef + Send + Sync, { - todo!() + self.get_transaction_trace(*transaction_hash.as_ref()) + .await + .map(Into::into) } async fn trace_block_transactions( @@ -425,6 +439,8 @@ impl Provider for SequencerGatewayProvider { where H: AsRef + Send + Sync, { - todo!() + self.get_block_traces(super::BlockId::Hash(block_hash.as_ref().clone())) + .await + .map(|trace| trace.traces.into_iter().map(Into::into).collect()) } }