|
| 1 | +use std::fs; |
| 2 | +use std::path::PathBuf; |
| 3 | + |
| 4 | +// Will be provided by profiler crate in the future |
| 5 | +// This module will be removed! |
| 6 | +use cheatnet::state::CallTrace as InternalCallTrace; |
| 7 | +use serde::{Deserialize, Serialize}; |
| 8 | +use starknet_api::core::{ClassHash, ContractAddress, EntryPointSelector}; |
| 9 | +use starknet_api::deprecated_contract_class::EntryPointType; |
| 10 | +use starknet_api::transaction::Calldata; |
| 11 | + |
| 12 | +use crate::test_case_summary::{Single, TestCaseSummary}; |
| 13 | + |
| 14 | +pub const TRACE_DIR: &str = "snfoundry_trace"; |
| 15 | + |
| 16 | +/// Tree structure representing trace of a call. |
| 17 | +#[derive(Debug, Clone, Deserialize, Serialize)] |
| 18 | +pub struct CallTrace { |
| 19 | + pub entry_point: CallEntryPoint, |
| 20 | + pub nested_calls: Vec<CallTrace>, |
| 21 | +} |
| 22 | + |
| 23 | +impl From<InternalCallTrace> for CallTrace { |
| 24 | + fn from(value: InternalCallTrace) -> Self { |
| 25 | + CallTrace { |
| 26 | + entry_point: CallEntryPoint::from(value.entry_point), |
| 27 | + nested_calls: value |
| 28 | + .nested_calls |
| 29 | + .into_iter() |
| 30 | + .map(|c| CallTrace::from(c.borrow().clone())) |
| 31 | + .collect(), |
| 32 | + } |
| 33 | + } |
| 34 | +} |
| 35 | + |
| 36 | +#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)] |
| 37 | +pub struct CallEntryPoint { |
| 38 | + pub class_hash: Option<ClassHash>, |
| 39 | + pub code_address: Option<ContractAddress>, |
| 40 | + pub entry_point_type: EntryPointType, |
| 41 | + pub entry_point_selector: EntryPointSelector, |
| 42 | + pub calldata: Calldata, |
| 43 | + pub storage_address: ContractAddress, |
| 44 | + pub caller_address: ContractAddress, |
| 45 | + pub call_type: CallType, |
| 46 | + pub initial_gas: u64, |
| 47 | +} |
| 48 | + |
| 49 | +impl From<blockifier::execution::entry_point::CallEntryPoint> for CallEntryPoint { |
| 50 | + fn from(value: blockifier::execution::entry_point::CallEntryPoint) -> Self { |
| 51 | + let blockifier::execution::entry_point::CallEntryPoint { |
| 52 | + class_hash, |
| 53 | + code_address, |
| 54 | + entry_point_type, |
| 55 | + entry_point_selector, |
| 56 | + calldata, |
| 57 | + storage_address, |
| 58 | + caller_address, |
| 59 | + call_type, |
| 60 | + initial_gas, |
| 61 | + } = value; |
| 62 | + |
| 63 | + CallEntryPoint { |
| 64 | + class_hash, |
| 65 | + code_address, |
| 66 | + entry_point_type, |
| 67 | + entry_point_selector, |
| 68 | + calldata, |
| 69 | + storage_address, |
| 70 | + caller_address, |
| 71 | + call_type: call_type.into(), |
| 72 | + initial_gas, |
| 73 | + } |
| 74 | + } |
| 75 | +} |
| 76 | + |
| 77 | +#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq, Deserialize, Serialize)] |
| 78 | +pub enum CallType { |
| 79 | + #[default] |
| 80 | + Call = 0, |
| 81 | + Delegate = 1, |
| 82 | +} |
| 83 | + |
| 84 | +impl From<blockifier::execution::entry_point::CallType> for CallType { |
| 85 | + fn from(value: blockifier::execution::entry_point::CallType) -> Self { |
| 86 | + match value { |
| 87 | + blockifier::execution::entry_point::CallType::Call => CallType::Call, |
| 88 | + blockifier::execution::entry_point::CallType::Delegate => CallType::Delegate, |
| 89 | + } |
| 90 | + } |
| 91 | +} |
| 92 | + |
| 93 | +pub fn save_trace_data(summary: &TestCaseSummary<Single>) { |
| 94 | + if let TestCaseSummary::Passed { |
| 95 | + name, trace_data, .. |
| 96 | + } = summary |
| 97 | + { |
| 98 | + let serialized_trace = |
| 99 | + serde_json::to_string(trace_data).expect("Failed to serialize call trace"); |
| 100 | + let dir_to_save_trace = PathBuf::from(TRACE_DIR); |
| 101 | + fs::create_dir_all(&dir_to_save_trace) |
| 102 | + .expect("Failed to create a file to save call trace to"); |
| 103 | + |
| 104 | + let filename = format!("{name}.json"); |
| 105 | + fs::write(dir_to_save_trace.join(filename), serialized_trace) |
| 106 | + .expect("Failed to write call trace to a file"); |
| 107 | + } |
| 108 | +} |
0 commit comments