diff --git a/Cargo.lock b/Cargo.lock index 14aa128..a9b49d3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1277,7 +1277,7 @@ dependencies = [ [[package]] name = "cairo-native" version = "0.2.0-alpha.4" -source = "git+https://github.com/lambdaclass//cairo_native.git?rev=355c250f37cf0977ef2776b1aae2cb2e87c9da3d#355c250f37cf0977ef2776b1aae2cb2e87c9da3d" +source = "git+https://github.com/lambdaclass//cairo_native.git?rev=ab478323d6aee5e0424712bbde98de443b8cc72f#ab478323d6aee5e0424712bbde98de443b8cc72f" dependencies = [ "anyhow", "aquamarine", @@ -1330,7 +1330,7 @@ dependencies = [ [[package]] name = "cairo-native-runtime" version = "0.2.0-alpha.4" -source = "git+https://github.com/lambdaclass//cairo_native.git?rev=355c250f37cf0977ef2776b1aae2cb2e87c9da3d#355c250f37cf0977ef2776b1aae2cb2e87c9da3d" +source = "git+https://github.com/lambdaclass//cairo_native.git?rev=ab478323d6aee5e0424712bbde98de443b8cc72f#ab478323d6aee5e0424712bbde98de443b8cc72f" dependencies = [ "cairo-lang-sierra-gas", "itertools 0.13.0", diff --git a/Cargo.toml b/Cargo.toml index 847a0fb..b24ac51 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,4 +20,4 @@ blockifier = { git = "https://github.com/lambdaclass/sequencer", rev = "1b1b95ca starknet_gateway = { git = "https://github.com/lambdaclass/sequencer", rev = "1b1b95cae7ae07b9bc778443ca75ee18008a6bc8"} [patch.'https://github.com/lambdaclass/cairo_native'] -cairo-native = { git = "https://github.com/lambdaclass//cairo_native.git", rev = "355c250f37cf0977ef2776b1aae2cb2e87c9da3d" } +cairo-native = { git = "https://github.com/lambdaclass//cairo_native.git", rev = "ab478323d6aee5e0424712bbde98de443b8cc72f" } diff --git a/README.md b/README.md index 91fb871..6215aaf 100644 --- a/README.md +++ b/README.md @@ -118,3 +118,25 @@ To compare the outputs, you can use the following scripts. Some of them required ```bash > ./scripts/delta_state_dumps.sh ``` + +### Plotting + +In the `plotting` directory, you can find python scripts to plot relevant information. Before using them, you must first execute the replay with the `structured_logging` feature, and redirect the output to a file. You should do it with both Native execution and VM execution. + +Make sure to erase the `compiled_programs` directory, then run: + +```bash +cargo run --features benchmark,structured_logging bench-block-range 724000 724000 mainnet 1 | tee native-logs +cargo run --features benchmark,structured_logging,only_cairo_vm bench-block-range 724000 724000 mainnet 1 | tee vm-logs +``` + +Once you have done this, you can use the plotting scripts: + +- `python ./plotting/plot_compilation_memory.py native-logs`: Size of the compiled native libraries, by contract class. +- `python ./plotting/plot_compilation_memory_corr.py native-logs vm-logs`: Size of the compiled native libraries, by the associated Casm contract size. +- `python ./plotting/plot_compilation_memory_trend.py native-logs vm-logs`: Size of the compiled native and casm contracts, by the sierra contract size. +- `python ./plotting/plot_compilation_time.py native-logs`: Native compilation time, by contract class +- `python ./plotting/plot_compilation_time_trend.py native-logs vm-logs`: Native and Casm compilation time, by the sierra contract size. +- `python ./plotting/plot_execution_time.py native-logs vm-logs`: Plots the execution time of Native vs VM, by contract class. +- `python ./plotting/plot_compilation_time_finer.py native-logs`: Native compilation time, with fine-grained stage separation, by contract class. + diff --git a/plotting/plot_compilation_memory.py b/plotting/plot_compilation_memory.py new file mode 100644 index 0000000..b0eac16 --- /dev/null +++ b/plotting/plot_compilation_memory.py @@ -0,0 +1,47 @@ +from argparse import ArgumentParser + +argument_parser = ArgumentParser('Stress Test Plotter') +argument_parser.add_argument("native_logs_path") +arguments = argument_parser.parse_args() + +import matplotlib.pyplot as plt +import pandas as pd +import seaborn as sns + +dataset = pd.read_json(arguments.native_logs_path, lines=True, typ="series") + +def canonicalize_compilation_time(event): + if "contract compilation finished" not in event["fields"]["message"]: + return None + + compilation_span = find_span(event, "contract compilation") + if compilation_span is None: + return None + + return { + "class hash": compilation_span["class_hash"], + "size": event["fields"]["size"] / (1024 * 1024), + } + +def find_span(event, name): + for span in event["spans"]: + if name in span["name"]: + return span + return None + +def format_hash(class_hash): + return f"0x{class_hash[:6]}..." + + +dataset = dataset.apply(canonicalize_compilation_time).dropna().apply(pd.Series) + +figure, ax = plt.subplots() + +sns.set_color_codes("bright") +sns.barplot(ax=ax, y="class hash", x="size", data=dataset, formatter=format_hash) # type: ignore + +ax.set_xlabel("Library Size (MiB)") +ax.set_ylabel("Class Hash") +ax.set_title("Library Size by Contract") + +plt.show() diff --git a/plotting/plot_compilation_memory_corr.py b/plotting/plot_compilation_memory_corr.py new file mode 100644 index 0000000..36169ab --- /dev/null +++ b/plotting/plot_compilation_memory_corr.py @@ -0,0 +1,71 @@ +from argparse import ArgumentParser + +argument_parser = ArgumentParser('Stress Test Plotter') +argument_parser.add_argument("native_logs_path") +argument_parser.add_argument("vm_logs_path") +arguments = argument_parser.parse_args() + +import matplotlib.pyplot as plt +import pandas as pd +import seaborn as sns + +dataset_native = pd.read_json(arguments.native_logs_path, lines=True, typ="series") +dataset_vm = pd.read_json(arguments.vm_logs_path, lines=True, typ="series") + +def canonicalize_compilation_time(event): + if "contract compilation finished" not in event["fields"]["message"]: + return None + + compilation_span = find_span(event, "contract compilation") + if compilation_span is None: + return None + + return { + "class hash": compilation_span["class_hash"], + "size": event["fields"]["size"] / 1024, + } + +def find_span(event, name): + for span in event["spans"]: + if name in span["name"]: + return span + return None + +def format_hash(class_hash): + return f"0x{class_hash[:6]}..." + + +dataset_native = dataset_native.apply(canonicalize_compilation_time).dropna().apply(pd.Series) +dataset_vm = dataset_vm.apply(canonicalize_compilation_time).dropna().apply(pd.Series) + +dataset_native = dataset_native.set_index("class hash") +dataset_vm = dataset_vm.set_index("class hash") + +dataset = dataset_native.join(dataset_vm, lsuffix="_native", rsuffix="_casm") + +figure, ax = plt.subplots() + +sns.set_color_codes("bright") + +sns.regplot( + x="size_native", + y="size_casm", + label = "Native (<1000)", + data=dataset[dataset["size_native"] < 1000], + ax = ax, +) +sns.regplot( + x="size_native", + y="size_casm", + label = "Native (>=1000)", + data=dataset[dataset["size_native"] >= 1000], + ax = ax, +) + +ax.set_xlabel("Native Compilation Size (KiB)") +ax.set_ylabel("Casm Compilation Size (KiB)") +ax.set_title("Compilation Size Correlation") + +ax.legend() + +plt.show() diff --git a/plotting/plot_compilation_memory_trend.py b/plotting/plot_compilation_memory_trend.py new file mode 100644 index 0000000..d3a5fb3 --- /dev/null +++ b/plotting/plot_compilation_memory_trend.py @@ -0,0 +1,76 @@ +from argparse import ArgumentParser + +argument_parser = ArgumentParser('Stress Test Plotter') +argument_parser.add_argument("native_logs_path") +argument_parser.add_argument("vm_logs_path") +arguments = argument_parser.parse_args() + +import matplotlib.pyplot as plt +import pandas as pd +import seaborn as sns + +dataset_native = pd.read_json(arguments.native_logs_path, lines=True, typ="series") +dataset_vm = pd.read_json(arguments.vm_logs_path, lines=True, typ="series") + +def canonicalize_compilation_time(event): + if "contract compilation finished" not in event["fields"]["message"]: + return None + + compilation_span = find_span(event, "contract compilation") + if compilation_span is None: + return None + + return { + "class hash": compilation_span["class_hash"], + "length": compilation_span["length"] / 1024, + "size": event["fields"]["size"] / 1024, + } + +def find_span(event, name): + for span in event["spans"]: + if name in span["name"]: + return span + return None + +def format_hash(class_hash): + return f"0x{class_hash[:6]}..." + + +dataset_native = dataset_native.apply(canonicalize_compilation_time).dropna().apply(pd.Series) +dataset_vm = dataset_vm.apply(canonicalize_compilation_time).dropna().apply(pd.Series) + +figure, ax = plt.subplots() + +sns.set_color_codes("bright") + +sns.regplot( + x="length", + y="size", + label = "Native (<1000)", + data=dataset_native[dataset_native["size"] < 1000], + ax = ax, +) +sns.regplot( + x="length", + y="size", + label = "Native (>=1000)", + data=dataset_native[dataset_native["size"] >= 1000], + ax = ax, +) +sns.regplot( + x="length", + y="size", + label = "Casm", + data=dataset_vm, + ax = ax, +) + +ax.set_xlabel("Sierra size (KiB)") +ax.set_ylabel("Compiled size (KiB)") +ax.set_title("Compilation Size Trend") +ax.ticklabel_format(style="plain") + + +ax.legend() + +plt.show() diff --git a/plotting/plot_compilation_time.py b/plotting/plot_compilation_time.py new file mode 100644 index 0000000..425188b --- /dev/null +++ b/plotting/plot_compilation_time.py @@ -0,0 +1,47 @@ +from argparse import ArgumentParser + +argument_parser = ArgumentParser('Stress Test Plotter') +argument_parser.add_argument("native_logs_path") +arguments = argument_parser.parse_args() + +import matplotlib.pyplot as plt +import pandas as pd +import seaborn as sns + +dataset = pd.read_json(arguments.native_logs_path, lines=True, typ="series") + +def canonicalize_compilation_time(event): + # keep contract compilation finished logs + if "contract compilation finished" not in event["fields"]["message"]: + return None + + compilation_span = find_span(event, "contract compilation") + if compilation_span is None: + return None + + return { + "class hash": compilation_span["class_hash"], + "time": float(event["fields"]["time"]), + } + +def find_span(event, name): + for span in event["spans"]: + if name in span["name"]: + return span + return None + +def format_hash(class_hash): + return f"0x{class_hash[:6]}..." + +dataset = dataset.apply(canonicalize_compilation_time).dropna().apply(pd.Series) + +figure, ax = plt.subplots() + +sns.set_color_codes("bright") +sns.barplot(ax=ax, y="class hash", x="time", data=dataset, formatter=format_hash) # type: ignore + +ax.set_xlabel("Compilation Time (ms)") +ax.set_ylabel("Class Hash") +ax.set_title("Native Compilation Time") + +plt.show() diff --git a/plotting/plot_compilation_time_finer.py b/plotting/plot_compilation_time_finer.py new file mode 100644 index 0000000..0fceefd --- /dev/null +++ b/plotting/plot_compilation_time_finer.py @@ -0,0 +1,112 @@ +from argparse import ArgumentParser +import matplotlib.pyplot as plt +import pandas as pd +import seaborn as sns +import numpy as np + +argument_parser = ArgumentParser("Stress Test Plotter") +argument_parser.add_argument("native_logs_path") +arguments = argument_parser.parse_args() + + +dataset = pd.read_json(arguments.native_logs_path, lines=True, typ="series") + + +def canonicalize_compilation_time(event): + # keep contract compilation finished logs + compilation_span = find_span(event, "contract compilation") + if compilation_span is None: + return None + + class_hash = compilation_span["class_hash"] + class_length = compilation_span["length"] + + if "contract compilation finished" in event["fields"]["message"]: + return { + "class hash": class_hash, + "length": class_length, + "type": "Total", + "time": float(event["fields"]["time"]), + } + elif "sierra to mlir compilation finished" in event["fields"]["message"]: + return { + "class hash": class_hash, + "length": class_length, + "type": "Sierra to MLIR", + "time": float(event["fields"]["time"]), + } + elif "mlir passes finished" in event["fields"]["message"]: + return { + "class hash": class_hash, + "length": class_length, + "type": "MLIR passes", + "time": float(event["fields"]["time"]), + } + elif "mlir to llvm finished" in event["fields"]["message"]: + return { + "class hash": class_hash, + "length": class_length, + "type": "MLIR to LLVM", + "time": float(event["fields"]["time"]), + } + elif "llvm passes finished" in event["fields"]["message"]: + return { + "class hash": class_hash, + "length": class_length, + "type": "LLVM passes", + "time": float(event["fields"]["time"]), + } + elif "llvm to object compilation finished" in event["fields"]["message"]: + return { + "class hash": class_hash, + "length": class_length, + "type": "LLVM to object", + "time": float(event["fields"]["time"]), + } + elif "linking finished" in event["fields"]["message"]: + return { + "class hash": class_hash, + "length": class_length, + "type": "Linking", + "time": float(event["fields"]["time"]), + } + return None + + +def find_span(event, name): + for span in event["spans"]: + if name in span["name"]: + return span + return None + + +def format_hash(class_hash): + return f"0x{class_hash[:6]}..." + + +dataset = dataset.apply(canonicalize_compilation_time).dropna().apply(pd.Series) +dataset = dataset.pivot(index = ["class hash"], columns = "type", values = "time") + +pd.set_option('display.max_columns', None) + +figure, ax = plt.subplots() + +sns.set_color_codes("pastel") +sns.barplot(data=dataset, y="class hash", x="Total", label="Other", ax=ax, formatter=format_hash) + +bottom = np.zeros(len(dataset)) +sections = ["Linking", "LLVM to object", "LLVM passes", "MLIR to LLVM", "MLIR passes", "Sierra to MLIR"] + +for section in sections: + bottom += dataset[section] + +for section in sections: + sns.barplot(y=dataset.index, x=bottom, ax=ax, label=section, formatter=format_hash, orient="h") + bottom -= dataset[section] + +ax.set_xlabel("Compilation Time (ms)") +ax.set_ylabel("Class Hash") +ax.set_title("Native Compilation Time") +ax.legend() + +plt.show() diff --git a/plotting/plot_compilation_time_trend.py b/plotting/plot_compilation_time_trend.py new file mode 100644 index 0000000..ea8bbef --- /dev/null +++ b/plotting/plot_compilation_time_trend.py @@ -0,0 +1,74 @@ +from argparse import ArgumentParser +import matplotlib.pyplot as plt +import pandas as pd +import seaborn as sns + +argument_parser = ArgumentParser("Stress Test Plotter") +argument_parser.add_argument("native_logs_path") +argument_parser.add_argument("vm_logs_path") +arguments = argument_parser.parse_args() + + +dataset_native = pd.read_json(arguments.native_logs_path, lines=True, typ="series") +dataset_vm = pd.read_json(arguments.vm_logs_path, lines=True, typ="series") + + +def canonicalize_compilation_time(event): + # keep contract compilation finished logs + if "contract compilation finished" not in event["fields"]["message"]: + return None + + compilation_span = find_span(event, "contract compilation") + if compilation_span is None: + return None + + class_hash = compilation_span["class_hash"] + class_length = float(compilation_span["length"]) + + return { + "class hash": class_hash, + "length": class_length / 1024, + "time": float(event["fields"]["time"]), + } + + +def find_span(event, name): + for span in event["spans"]: + if name in span["name"]: + return span + return None + + +def format_hash(class_hash): + return f"0x{class_hash[:6]}..." + + +dataset_native = dataset_native.apply(canonicalize_compilation_time).dropna().apply(pd.Series) +dataset_vm = dataset_vm.apply(canonicalize_compilation_time).dropna().apply(pd.Series) + +fig, ax = plt.subplots() + +sns.set_theme() +sns.set_color_codes("bright") + +sns.regplot( + x="length", + y="time", + label = "Native", + data=dataset_native, + ax = ax, +) +sns.regplot( + x="length", + y="time", + label = "Casm", + data=dataset_vm, + ax = ax, +) + +ax.set_xlabel("Sierra size (KiB)") +ax.set_ylabel("Compilation Time (ms)") +ax.set_title("Native Compilation Time Trend") +ax.legend() + +plt.show() diff --git a/plotting/plot_execution_time.py b/plotting/plot_execution_time.py new file mode 100644 index 0000000..14cd90f --- /dev/null +++ b/plotting/plot_execution_time.py @@ -0,0 +1,55 @@ +from argparse import ArgumentParser + +argument_parser = ArgumentParser('Stress Test Plotter') +argument_parser.add_argument("native_logs_path") +argument_parser.add_argument("vm_logs_path") +arguments = argument_parser.parse_args() + +import matplotlib.pyplot as plt +import pandas as pd +import seaborn as sns + +datasetNative = pd.read_json(arguments.native_logs_path, lines=True, typ="series") +datasetVM = pd.read_json(arguments.vm_logs_path, lines=True, typ="series") + +def canonicalize_execution_time_by_contract_class(event): + # skip caching logs + if find_span(event, "caching block range") != None: + return None + + # keep contract execution finished logs + if "contract execution finished" not in event["fields"]["message"]: + return None + + return { + "class hash": event["span"]["class_hash"], + "time": float(event["fields"]["time"]), + } + +def find_span(event, name): + for span in event["spans"]: + if name in span["name"]: + return span + return None + +def format_hash(class_hash): + return f"0x{class_hash[:6]}..." + +datasetNative = datasetNative.apply(canonicalize_execution_time_by_contract_class).dropna().apply(pd.Series) +datasetVM = datasetVM.apply(canonicalize_execution_time_by_contract_class).dropna().apply(pd.Series) + +datasetNative = datasetNative.groupby("class hash").mean() +datasetVM = datasetVM.groupby("class hash").mean() + +figure, ax = plt.subplots() + +sns.set_color_codes("bright") + +sns.barplot(ax=ax, y="class hash", x="time", data=datasetVM, formatter=format_hash, label="VM Execution Time", color="r", alpha = 0.75) # type: ignore +sns.barplot(ax=ax, y="class hash", x="time", data=datasetNative, formatter=format_hash, label="Native Execution Time", color="b", alpha = 0.75) # type: ignore + +ax.set_xlabel("Mean Time (ms)") +ax.set_ylabel("Class Hash") +ax.set_title("Native vs. VM by Contract Class") + +plt.show() diff --git a/replay/Cargo.toml b/replay/Cargo.toml index a0ed56c..b4f715f 100644 --- a/replay/Cargo.toml +++ b/replay/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" benchmark = [] # The only_cairo_vm feature is designed to avoid executing transitions with cairo_native and instead use cairo_vm exclusively only_cairo_vm = ["rpc-state-reader/only_casm"] -# Records state diff of every tx executed to disk +structured_logging = [] state_dump = ["dep:serde", "dep:serde_json", "dep:serde_with", "dep:starknet-types-core"] [dependencies] diff --git a/replay/src/benchmark.rs b/replay/src/benchmark.rs index 1e9e7ff..de2f245 100644 --- a/replay/src/benchmark.rs +++ b/replay/src/benchmark.rs @@ -81,7 +81,8 @@ pub fn execute_block_range(block_range_data: &mut Vec) { transaction_hash = transaction_hash.to_string(), ) .entered(); - info!("starting tx execution"); + + info!("tx execution started"); let pre_execution_instant = Instant::now(); let result = execute_tx_with_blockifier( @@ -95,17 +96,16 @@ pub fn execute_block_range(block_range_data: &mut Vec) { match result { Ok(info) => { info!( + time = ?execution_time, succeeded = info.revert_error.is_none(), - "tx execution status" + "tx execution finished" ) } Err(_) => error!( - transaction_hash = transaction_hash.to_string(), + time = ?execution_time, "tx execution failed" ), } - - info!(time = ?execution_time, "finished tx execution"); } } } diff --git a/replay/src/main.rs b/replay/src/main.rs index ba63dd2..63f7513 100644 --- a/replay/src/main.rs +++ b/replay/src/main.rs @@ -1,5 +1,3 @@ -use std::str::FromStr; - use blockifier::state::cached_state::CachedState; use blockifier::state::errors::StateError; use clap::{Parser, Subcommand}; @@ -9,7 +7,6 @@ use rpc_state_reader::reader::{RpcChain, RpcStateReader}; use starknet_api::block::BlockNumber; use starknet_api::transaction::{TransactionExecutionStatus, TransactionHash}; use tracing::{debug, error, info, info_span}; -use tracing_subscriber::filter::Directive; use tracing_subscriber::{util::SubscriberInitExt, EnvFilter}; #[cfg(feature = "benchmark")] @@ -406,22 +403,26 @@ fn get_transaction_hashes( } fn set_global_subscriber() { - let default_directive = Directive::from_str("replay=info").expect("should be valid"); + #[cfg(not(feature = "structured_logging"))] + let default_env_filter = + EnvFilter::try_new("replay=info").expect("hard-coded env filter should be valid"); + + #[cfg(feature = "structured_logging")] + let default_env_filter = + EnvFilter::try_new("replay=info,blockifier=info,rpc_state_reader=info,cairo_native=info") + .expect("hard-coded env filter should be valid"); + + let env_filter = EnvFilter::try_from_default_env().unwrap_or(default_env_filter); let subscriber = tracing_subscriber::fmt() - .with_env_filter({ - EnvFilter::builder() - .with_default_directive(default_directive) - .from_env_lossy() - }) + .with_env_filter(env_filter) .with_file(false) .with_line_number(false); - #[cfg(feature = "benchmark")] - let subscriber = subscriber.json(); - - #[cfg(not(feature = "benchmark"))] + #[cfg(not(feature = "structured_logging"))] let subscriber = subscriber.pretty(); + #[cfg(feature = "structured_logging")] + let subscriber = subscriber.json(); subscriber.finish().init(); } diff --git a/rpc-state-reader/src/reader.rs b/rpc-state-reader/src/reader.rs index 36bec1c..f5c7314 100644 --- a/rpc-state-reader/src/reader.rs +++ b/rpc-state-reader/src/reader.rs @@ -1,4 +1,10 @@ -use std::{env, fmt, num::NonZeroU128, sync::Arc, thread, time::Duration}; +use std::{ + env, fmt, + num::NonZeroU128, + sync::Arc, + thread, + time::{Duration, Instant}, +}; use blockifier::{ blockifier::block::{BlockInfo, GasPrices}, @@ -7,6 +13,7 @@ use blockifier::{ }, state::state_api::{StateReader, StateResult}, }; +use cairo_lang_utils::bigint::BigUintAsHex; use cairo_vm::types::program::Program; use serde::Serialize; use serde_json::Value; @@ -26,6 +33,7 @@ use starknet_gateway::{ }, rpc_state_reader::RpcStateReader as GatewayRpcStateReader, }; +use tracing::{info, info_span}; use ureq::json; use crate::{ @@ -312,9 +320,29 @@ fn compile_sierra_cc( abi: None, }; + let _span = info_span!( + "contract compilation", + class_hash = class_hash.to_string(), + length = bytecode_size(&sierra_cc.sierra_program) + ) + .entered(); + if cfg!(feature = "only_casm") { + info!("starting vm contract compilation"); + + let pre_compilation_instant = Instant::now(); + let casm_cc = cairo_lang_starknet_classes::casm_contract_class::CasmContractClass::from_contract_class(sierra_cc, false, usize::MAX).unwrap(); + + let compilation_time = pre_compilation_instant.elapsed().as_millis(); + + tracing::info!( + time = compilation_time, + size = bytecode_size(&casm_cc.bytecode), + "vm contract compilation finished" + ); + ContractClass::V1(casm_cc.try_into().unwrap()) } else { let program = sierra_cc.extract_sierra_program().unwrap(); @@ -362,6 +390,10 @@ fn retry(f: impl Fn() -> RPCStateReaderResult) -> RPCStateReaderResult usize { + data.iter().map(|n| n.value.to_bytes_be().len()).sum() +} + #[cfg(test)] mod tests { use std::num::NonZeroU128; diff --git a/rpc-state-reader/src/utils.rs b/rpc-state-reader/src/utils.rs index 6aa5e8f..422a252 100644 --- a/rpc-state-reader/src/utils.rs +++ b/rpc-state-reader/src/utils.rs @@ -1,8 +1,10 @@ use std::{ collections::HashMap, + fs, io::{self, Read}, path::PathBuf, sync::{Arc, OnceLock, RwLock}, + time::Instant, }; use cairo_lang_sierra::program::Program; @@ -16,6 +18,7 @@ use starknet_api::{ deprecated_contract_class::{EntryPoint, EntryPointOffset, EntryPointType}, hash::StarkHash, }; +use tracing::info; #[derive(Debug, Deserialize)] pub struct MiddleSierraContractClass { @@ -93,11 +96,23 @@ pub fn get_native_executor(program: Program, class_hash: ClassHash) -> Arc