Skip to content

Commit

Permalink
feat: Improve trace function
Browse files Browse the repository at this point in the history
  • Loading branch information
clint committed Sep 7, 2023
1 parent ecdea03 commit d97918a
Show file tree
Hide file tree
Showing 6 changed files with 182 additions and 61 deletions.
19 changes: 19 additions & 0 deletions examples/trace.rs
Original file line number Diff line number Diff line change
@@ -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);
}
86 changes: 30 additions & 56 deletions starknet-core/src/types/trace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<FunctionInvocation>,
/// 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<FunctionInvocation>,
/// An object describing the invocation of a specific function.
#[serde(skip_serializing_if = "Option::is_none")]
pub execute_invocation: Option<ExecuteInvocation>,
/// An object describing the invocation of a specific function.
#[serde(skip_serializing_if = "Option::is_none")]
pub function_invocation: Option<FunctionInvocation>,
/// An object describing the invocation of a specific function.
#[serde(skip_serializing_if = "Option::is_none")]
pub constructor_invocation: Option<FunctionInvocation>,
}

/// The trace of the __execute__ call or constructor call, depending on the transaction type (none for declare transactions)
Expand All @@ -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 {
Expand All @@ -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<SimulatedTransaction>,
}

#[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,
}
110 changes: 110 additions & 0 deletions starknet-providers/src/sequencer/models/conversions.rs
Original file line number Diff line number Diff line change
@@ -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::{
Expand Down Expand Up @@ -924,3 +928,109 @@ fn convert_legacy_entry_point(
selector: value.selector,
}
}

impl From<TransactionTrace> 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<CallType> for core::CallType {
fn from(value: CallType) -> Self {
match value {
CallType::Call => core::CallType::Call,
CallType::Delegate => core::CallType::LibraryCall,
}
}
}

impl From<FunctionInvocation> 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<FunctionInvocation> 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<OrderedEventResponse> 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<OrderedL2ToL1MessageResponse> 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<EntryPointType> 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<TransactionSimulationInfo> for core::SimulatedTransaction {
fn from(value: TransactionSimulationInfo) -> Self {
core::SimulatedTransaction {
fee_estimation: value.fee_estimation.into(),
transaction_trace: value.trace.into(),
}
}
}

impl From<TransactionTraceWithHash> for core::TransactionTraceWithHash {
fn from(value: TransactionTraceWithHash) -> Self {
core::TransactionTraceWithHash {
transaction_hash: value.transaction_hash,
trace_root: value.trace.into(),
}
}
}
3 changes: 2 additions & 1 deletion starknet-providers/src/sequencer/models/trace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
Expand Down
3 changes: 2 additions & 1 deletion starknet-providers/src/sequencer/models/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,12 +72,13 @@ pub struct TransactionInfo {
pub transaction_index: Option<u64>,
}

#[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,
}

Expand Down
22 changes: 19 additions & 3 deletions starknet-providers/src/sequencer/provider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -405,7 +405,19 @@ impl Provider for SequencerGatewayProvider {
I: AsRef<Vec<BroadcastedTransaction>> + Send + Sync,
S: AsRef<Vec<SimulationFlag>> + 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<H>(
Expand All @@ -415,7 +427,9 @@ impl Provider for SequencerGatewayProvider {
where
H: AsRef<FieldElement> + Send + Sync,
{
todo!()
self.get_transaction_trace(*transaction_hash.as_ref())
.await
.map(Into::into)
}

async fn trace_block_transactions<H>(
Expand All @@ -425,6 +439,8 @@ impl Provider for SequencerGatewayProvider {
where
H: AsRef<FieldElement> + 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())
}
}

0 comments on commit d97918a

Please sign in to comment.