Skip to content

Commit

Permalink
feat(katana-rpc): add traceTransaction and traceBlockTransactions
Browse files Browse the repository at this point in the history
… API (#2486)
  • Loading branch information
kariy authored Sep 30, 2024
1 parent ee06e56 commit 25092b8
Show file tree
Hide file tree
Showing 7 changed files with 585 additions and 206 deletions.
7 changes: 4 additions & 3 deletions crates/katana/executor/src/implementation/blockifier/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ use katana_primitives::fee::TxFeeInfo;
use katana_primitives::state::{StateUpdates, StateUpdatesWithDeclaredClasses};
use katana_primitives::trace::{L1Gas, TxExecInfo, TxResources};
use katana_primitives::transaction::{
DeclareTx, DeployAccountTx, ExecutableTx, ExecutableTxWithHash, InvokeTx,
DeclareTx, DeployAccountTx, ExecutableTx, ExecutableTxWithHash, InvokeTx, TxType,
};
use katana_primitives::{class, event, message, trace, Felt};
use katana_provider::traits::contract::ContractClassProvider;
Expand Down Expand Up @@ -126,7 +126,7 @@ pub fn transact<S: StateReader>(
match transact_inner(state, block_context, simulation_flags, to_executor_tx(tx.clone())) {
Ok((info, fee)) => {
// get the trace and receipt from the execution info
let trace = to_exec_info(info);
let trace = to_exec_info(info, tx.r#type());
let receipt = build_receipt(tx.tx_ref(), fee, &trace);
ExecutionResult::new_success(receipt, trace)
}
Expand Down Expand Up @@ -563,8 +563,9 @@ fn starknet_api_ethaddr_to_felt(value: katana_cairo::starknet_api::core::EthAddr
Felt::from_bytes_be(&bytes)
}

pub fn to_exec_info(exec_info: TransactionExecutionInfo) -> TxExecInfo {
pub fn to_exec_info(exec_info: TransactionExecutionInfo, r#type: TxType) -> TxExecInfo {
TxExecInfo {
r#type,
validate_call_info: exec_info.validate_call_info.map(to_call_info),
execute_call_info: exec_info.execute_call_info.map(to_call_info),
fee_transfer_call_info: exec_info.fee_transfer_call_info.map(to_call_info),
Expand Down
105 changes: 104 additions & 1 deletion crates/katana/primitives/src/trace.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
use std::collections::HashSet;
use std::collections::{HashMap, HashSet};

use katana_cairo::cairo_vm::types::builtin_name::BuiltinName;
use katana_cairo::cairo_vm::vm;

use crate::class::ClassHash;
use crate::contract::ContractAddress;
use crate::event::OrderedEvent;
use crate::message::OrderedL2ToL1Message;
use crate::transaction::TxType;
use crate::Felt;

pub type ExecutionResources = vm::runners::cairo_runner::ExecutionResources;
Expand All @@ -26,6 +28,8 @@ pub struct TxExecInfo {
pub actual_resources: TxResources,
/// Error string for reverted transactions; [None] if transaction execution was successful.
pub revert_error: Option<String>,
/// The transaction type of this execution info.
pub r#type: TxType,
}

#[derive(Debug, Clone, PartialEq, Eq, Default)]
Expand Down Expand Up @@ -107,3 +111,102 @@ pub struct CallInfo {
/// True if the execution has failed, false otherwise.
pub failed: bool,
}

#[derive(Clone, Debug, Default, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct BuiltinCounters(HashMap<BuiltinName, usize>);

impl BuiltinCounters {
/// Returns the number of instances of the `output` builtin, if any.
pub fn output(&self) -> Option<u64> {
self.builtin(BuiltinName::output)
}

/// Returns the number of instances of the `range_check` builtin, if any.
pub fn range_check(&self) -> Option<u64> {
self.builtin(BuiltinName::range_check)
}

/// Returns the number of instances of the `pedersen` builtin, if any.
pub fn pedersen(&self) -> Option<u64> {
self.builtin(BuiltinName::pedersen)
}

/// Returns the number of instances of the `ecdsa` builtin, if any.
pub fn ecdsa(&self) -> Option<u64> {
self.builtin(BuiltinName::ecdsa)
}

/// Returns the number of instances of the `keccak` builtin, if any.
pub fn keccak(&self) -> Option<u64> {
self.builtin(BuiltinName::keccak)
}

/// Returns the number of instances of the `bitwise` builtin, if any.
pub fn bitwise(&self) -> Option<u64> {
self.builtin(BuiltinName::bitwise)
}

/// Returns the number of instances of the `ec_op` builtin, if any.
pub fn ec_op(&self) -> Option<u64> {
self.builtin(BuiltinName::ec_op)
}

/// Returns the number of instances of the `poseidon` builtin, if any.
pub fn poseidon(&self) -> Option<u64> {
self.builtin(BuiltinName::poseidon)
}

/// Returns the number of instances of the `segment_arena` builtin, if any.
pub fn segment_arena(&self) -> Option<u64> {
self.builtin(BuiltinName::segment_arena)
}

/// Returns the number of instances of the `range_check96` builtin, if any.
pub fn range_check96(&self) -> Option<u64> {
self.builtin(BuiltinName::range_check96)
}

/// Returns the number of instances of the `add_mod` builtin, if any.
pub fn add_mod(&self) -> Option<u64> {
self.builtin(BuiltinName::add_mod)
}

/// Returns the number of instances of the `mul_mod` builtin, if any.
pub fn mul_mod(&self) -> Option<u64> {
self.builtin(BuiltinName::mul_mod)
}

fn builtin(&self, builtin: BuiltinName) -> Option<u64> {
self.0.get(&builtin).map(|&x| x as u64)
}
}

impl From<HashMap<BuiltinName, usize>> for BuiltinCounters {
fn from(map: HashMap<BuiltinName, usize>) -> Self {
// Filter out the builtins with 0 count.
let filtered = map.into_iter().filter(|(_, count)| *count != 0).collect();
BuiltinCounters(filtered)
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_builtin_counters_from_hashmap_removes_zero_entries() {
let mut map = HashMap::new();
map.insert(BuiltinName::output, 1);
map.insert(BuiltinName::range_check, 0);
map.insert(BuiltinName::pedersen, 2);
map.insert(BuiltinName::ecdsa, 0);

let counters = BuiltinCounters::from(map);

assert_eq!(counters.output(), Some(1));
assert_eq!(counters.range_check(), None);
assert_eq!(counters.pedersen(), Some(2));
assert_eq!(counters.ecdsa(), None);
}
}
32 changes: 32 additions & 0 deletions crates/katana/primitives/src/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,29 @@ pub type TxHash = Felt;
/// The sequential number for all the transactions.
pub type TxNumber = u64;

/// The transaction types as defined by the [Starknet API].
///
/// [Starknet API]: https://github.com/starkware-libs/starknet-specs/blob/b5c43955b1868b8e19af6d1736178e02ec84e678/api/starknet_api_openrpc.json
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum TxType {
/// Invokes a function of a contract.
#[default]
Invoke,

/// Declares new contract class.
Declare,

/// Deploys new account contracts.
DeployAccount,

/// Function invocation that is instantiated from the L1.
///
/// It is only used internally for handling messages sent from L1. Therefore, it is not a
/// transaction that can be broadcasted like the other transaction types.
L1Handler,
}

#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum Tx {
Expand Down Expand Up @@ -63,6 +86,15 @@ impl ExecutableTx {
ExecutableTx::DeployAccount(tx) => TxRef::DeployAccount(tx),
}
}

pub fn r#type(&self) -> TxType {
match self {
ExecutableTx::Invoke(_) => TxType::Invoke,
ExecutableTx::Declare(_) => TxType::Declare,
ExecutableTx::L1Handler(_) => TxType::L1Handler,
ExecutableTx::DeployAccount(_) => TxType::DeployAccount,
}
}
}

#[derive(Debug, Clone, AsRef, Deref)]
Expand Down
Loading

0 comments on commit 25092b8

Please sign in to comment.