Skip to content

Commit

Permalink
added scripts
Browse files Browse the repository at this point in the history
  • Loading branch information
GreatSoshiant committed Sep 20, 2024
1 parent 752612b commit bfb35db
Show file tree
Hide file tree
Showing 2 changed files with 164 additions and 4 deletions.
68 changes: 65 additions & 3 deletions main/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
use alloy_primitives::TxHash;
use clap::{ArgGroup, Args, CommandFactory, Parser, Subcommand};
use constants::DEFAULT_ENDPOINT;
use ethers::types::H160;
use ethers::types::{H160, U256};
use eyre::{bail, eyre, Context, Result};
use std::path::PathBuf;
use std::{fmt, path::Path};
Expand Down Expand Up @@ -97,6 +97,9 @@ enum Apis {
/// Trace a transaction.
#[command(visible_alias = "t")]
Trace(TraceArgs),
/// Simulate a transaction.
#[command(visible_alias = "s")]
Simulate(SimulateArgs),
}

#[derive(Args, Clone, Debug)]
Expand Down Expand Up @@ -266,6 +269,45 @@ struct TraceArgs {
use_native_tracer: bool,
}

#[derive(Args, Clone, Debug)]
pub struct SimulateArgs {
/// RPC endpoint.
#[arg(short, long, default_value = "http://localhost:8547")]
endpoint: String,

/// From address.
#[arg(short, long)]
from: Option<H160>,

/// To address.
#[arg(short, long)]
to: Option<H160>,

/// Gas limit.
#[arg(long)]
gas: Option<u64>,

/// Gas price.
#[arg(long)]
gas_price: Option<U256>,

/// Value to send with the transaction.
#[arg(short, long)]
value: Option<U256>,

/// Data to send with the transaction, as a hex string (with or without '0x' prefix).
#[arg(short, long)]
data: Option<String>,

/// Project path.
#[arg(short, long, default_value = ".")]
project: PathBuf,

/// If set, use the native tracer instead of the JavaScript one.
#[arg(short, long, default_value_t = false)]
use_native_tracer: bool,
}

#[derive(Clone, Debug, Args)]
#[clap(group(ArgGroup::new("key").required(true).args(&["private_key_path", "private_key", "keystore_path"])))]
struct AuthOpts {
Expand Down Expand Up @@ -415,9 +457,9 @@ fn main() -> Result<()> {
_ => {}
};

// see if custom extension exists
// see if custom extension exists and is not a deprecated extension
let custom = format!("cargo-stylus-{arg}");
if sys::command_exists(&custom) {
if sys::command_exists(&custom) && !is_deprecated_extension(&arg) {
let mut command = sys::new_command(&custom);
command.arg(arg).args(args);

Expand All @@ -440,6 +482,16 @@ fn main() -> Result<()> {
runtime.block_on(main_impl(opts))
}

// Checks if a cargo stylus extension is an old, deprecated extension which is no longer
// supported. These extensions are now incorporated as part of the `cargo-stylus` command itself and
// will be the preferred method of running them.
fn is_deprecated_extension(subcommand: &str) -> bool {
match subcommand {
"cargo-stylus-check" | "cargo-stylus-cgen" | "cargo-stylus-replay" => true,
_ => false,
}

Check warning on line 492 in main/src/main.rs

View workflow job for this annotation

GitHub Actions / clippy

match expression looks like `matches!` macro

warning: match expression looks like `matches!` macro --> main/src/main.rs:489:5 | 489 | / match subcommand { 490 | | "cargo-stylus-check" | "cargo-stylus-cgen" | "cargo-stylus-replay" => true, 491 | | _ => false, 492 | | } | |_____^ help: try: `matches!(subcommand, "cargo-stylus-check" | "cargo-stylus-cgen" | "cargo-stylus-replay")` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#match_like_matches_macro = note: `#[warn(clippy::match_like_matches_macro)]` on by default
}

async fn main_impl(args: Opts) -> Result<()> {
macro_rules! run {
($expr:expr, $($msg:expr),+) => {
Expand All @@ -463,6 +515,9 @@ async fn main_impl(args: Opts) -> Result<()> {
"stylus activate failed"
);
}
Apis::Simulate(args) => {
run!(simulate(args).await, "failed to simulate transaction");
}
Apis::Cgen { input, out_dir } => {
run!(gen::c_gen(&input, &out_dir), "failed to generate c code");
}
Expand Down Expand Up @@ -547,6 +602,13 @@ async fn trace(args: TraceArgs) -> Result<()> {
Ok(())
}

async fn simulate(args: SimulateArgs) -> Result<()> {
let provider = sys::new_provider(&args.endpoint)?;
let trace = Trace::simulate(provider, &args).await?;
println!("{}", trace.json);
Ok(())
}

async fn replay(args: ReplayArgs) -> Result<()> {
if !args.child {
let rust_gdb = sys::command_exists("rust-gdb");
Expand Down
100 changes: 99 additions & 1 deletion main/src/trace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,14 @@
#![allow(clippy::redundant_closure_call)]

use crate::util::color::{Color, DebugColor};
use crate::SimulateArgs;
use alloy_primitives::{Address, TxHash, B256, U256};
use ethers::{
providers::{JsonRpcClient, Middleware, Provider},
types::{GethDebugTracerType, GethDebugTracingOptions, GethTrace, Transaction},
types::{
BlockId, GethDebugTracerType, GethDebugTracingCallOptions, GethDebugTracingOptions,
GethTrace, Transaction, TransactionRequest,
},
utils::__serde_json::{from_value, Value},
};
use eyre::{bail, OptionExt, Result, WrapErr};
Expand Down Expand Up @@ -77,6 +81,100 @@ impl Trace {
frame: self.top_frame,
}
}
pub async fn simulate<T: JsonRpcClient>(
provider: Provider<T>,
args: &SimulateArgs,
) -> Result<Self> {
// Build the transaction request
let mut tx_request = TransactionRequest::new();

if let Some(from) = args.from {
tx_request = tx_request.from(from);
}
if let Some(to) = args.to {
tx_request = tx_request.to(to);
}
if let Some(gas) = args.gas {
tx_request = tx_request.gas(gas);
}
if let Some(gas_price) = args.gas_price {
tx_request = tx_request.gas_price(gas_price);
}
if let Some(value) = args.value {
tx_request = tx_request.value(value);
}
if let Some(data) = &args.data {
let data_bytes = hex::decode(data.trim_start_matches("0x"))?;
tx_request = tx_request.data(data_bytes);
}

// Use the same tracer as in Trace::new
let query = if args.use_native_tracer {
"stylusTracer"
} else {
include_str!("query.js")
};

// Corrected construction of tracer_options
let tracer_options = GethDebugTracingCallOptions {
tracing_options: GethDebugTracingOptions {
tracer: Some(GethDebugTracerType::JsTracer(query.to_owned())),
..Default::default()
},
..Default::default()
};

// Use the latest block; alternatively, this can be made configurable
let block_id = None::<BlockId>;

let GethTrace::Unknown(json) = provider
.debug_trace_call(tx_request, block_id, tracer_options)
.await?
else {
bail!("Malformed tracing result");
};

if let Value::Array(arr) = json.clone() {
if arr.is_empty() {
bail!("No trace frames found.");
}
}
// Since this is a simulated transaction, we create a dummy Transaction object
let tx = Transaction {
from: args.from.unwrap_or_default(),
to: args.to,
gas: args
.gas
.map(|gas| {
let bytes = [0u8; 32]; // U256 in both libraries is 32 bytes
gas.to_be_bytes().copy_from_slice(&bytes[..8]); // Convert alloy_primitives::U256 to bytes
ethers::types::U256::from_big_endian(&bytes) // Convert bytes to ethers::types::U256
})
.unwrap_or_else(|| ethers::types::U256::zero()), // Default to 0 if no gas is provided

Check warning on line 153 in main/src/trace.rs

View workflow job for this annotation

GitHub Actions / clippy

redundant closure

warning: redundant closure --> main/src/trace.rs:153:33 | 153 | .unwrap_or_else(|| ethers::types::U256::zero()), // Default to 0 if no gas is provided | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `ethers::types::U256::zero` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure = note: `#[warn(clippy::redundant_closure)]` on by default
gas_price: args.gas_price,
value: args.value.unwrap_or_else(|| ethers::types::U256::zero()),

Check warning on line 155 in main/src/trace.rs

View workflow job for this annotation

GitHub Actions / clippy

redundant closure

warning: redundant closure --> main/src/trace.rs:155:46 | 155 | value: args.value.unwrap_or_else(|| ethers::types::U256::zero()), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `ethers::types::U256::zero` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure
input: args
.data
.as_ref()
.map(|d| {
hex::decode(d.strip_prefix("0x").unwrap_or(&d))

Check warning on line 160 in main/src/trace.rs

View workflow job for this annotation

GitHub Actions / clippy

this expression creates a reference which is immediately dereferenced by the compiler

warning: this expression creates a reference which is immediately dereferenced by the compiler --> main/src/trace.rs:160:64 | 160 | hex::decode(d.strip_prefix("0x").unwrap_or(&d)) | ^^ help: change this to: `d` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow = note: `#[warn(clippy::needless_borrow)]` on by default
.unwrap_or_default()
.into()
})
.unwrap_or_default(),
// Default values for other fields
..Default::default()
};

// Parse the trace frames
let top_frame = TraceFrame::parse_frame(None, json.clone())?;

Ok(Self {
top_frame,
tx,
json,
})
}
}

#[derive(Serialize, Deserialize)]
Expand Down

0 comments on commit bfb35db

Please sign in to comment.