1use std::time::Instant;
2
3use clap::Parser;
4use mega_evm::revm::{context::result::ExecutionResult, state::Bytecode, DatabaseRef};
5use tracing::{debug, info, trace, warn};
6
7use super::{load_hex, Result, RunError};
8use crate::common::{
9 print_execution_summary, print_execution_trace, EvmeOutcome, ExecutionSummary,
10};
11
12pub use crate::common::TracerType;
14
15#[derive(Parser, Debug)]
17pub struct Cmd {
18 #[arg(value_name = "CODE")]
20 pub code: Option<String>,
21
22 #[arg(long = "codefile")]
24 pub codefile: Option<String>,
25
26 #[command(flatten)]
29 pub tx_args: super::TxArgs,
30
31 #[command(flatten)]
33 pub prestate_args: super::PreStateArgs,
34
35 #[command(flatten)]
37 pub rpc_args: super::RpcArgs,
38
39 #[command(flatten)]
41 pub env_args: super::EnvArgs,
42
43 #[command(flatten)]
45 pub dump_args: super::StateDumpArgs,
46
47 #[command(flatten)]
49 pub trace_args: super::TraceArgs,
50
51 #[command(flatten)]
53 pub output_args: super::OutputArgs,
54}
55
56impl Cmd {
57 pub async fn run(&self) -> Result<()> {
59 info!("Loading bytecode");
61 let code = load_hex(self.code.clone(), self.codefile.clone())?.ok_or_else(|| {
62 RunError::InvalidInput(
63 "No code provided. Use --codefile or provide code as argument".to_string(),
64 )
65 })?;
66 debug!(code_len = code.len(), "Bytecode loaded");
67
68 info!("Setting up initial state");
70 let sender = self.tx_args.sender();
71 let (mut state, cache_store) =
72 self.prestate_args.create_initial_state(&sender, &self.rpc_args).await?;
73 debug!(sender = %sender, "State initialized");
74
75 let spec = self.env_args.spec_id()?;
77 state.deploy_system_contracts(spec);
78 debug!(spec = ?spec, "System contracts deployed");
79
80 let pre_execution_nonce = state.basic_ref(sender)?.map(|acc| acc.nonce).unwrap_or(0);
81 debug!(nonce = pre_execution_nonce, "Pre-execution nonce");
82
83 if !self.tx_args.create() && !code.is_empty() {
85 let bytecode = Bytecode::new_raw_checked(code.clone())
86 .unwrap_or_else(|_| Bytecode::new_legacy(code.clone()));
87 debug!(receiver = %self.tx_args.receiver(), "Setting code at receiver address");
88 state.set_account_code(self.tx_args.receiver(), bytecode);
89 }
90
91 info!("Executing transaction");
93 let mut tx = self.tx_args.create_tx(self.env_args.chain.chain_id)?;
94 debug!(
95 tx_type = tx.base.tx_type,
96 gas_limit = tx.base.gas_limit,
97 value = %tx.base.value,
98 "Transaction created"
99 );
100
101 if self.tx_args.create() {
103 debug!("Create mode: prepending code to input data");
104 tx.base.data = [code.as_ref(), tx.base.data.as_ref()].concat().into();
105 }
106
107 let evm_context = self.env_args.create_evm_context(&mut state)?;
109 let start = Instant::now();
110 let (exec_result, evm_state, trace_data) =
111 self.trace_args.execute_transaction(evm_context, tx)?;
112 let exec_time = start.elapsed();
113
114 match &exec_result {
116 ExecutionResult::Success { gas_used, .. } => {
117 info!(gas_used, "Execution succeeded");
118 }
119 ExecutionResult::Revert { gas_used, .. } => {
120 warn!(gas_used, "Execution reverted");
121 }
122 ExecutionResult::Halt { reason, gas_used } => {
123 warn!(?reason, gas_used, "Execution halted");
124 }
125 }
126
127 let outcome = EvmeOutcome {
128 pre_execution_nonce,
129 exec_result,
130 state: evm_state,
131 exec_time,
132 trace_data,
133 };
134
135 trace!("Writing output results");
137 self.output_results(&outcome)?;
138
139 cache_store.persist()?;
141
142 Ok(())
143 }
144
145 fn output_results(&self, outcome: &EvmeOutcome) -> Result<()> {
147 let contract_address = (self.tx_args.create() && outcome.exec_result.is_success())
149 .then(|| self.tx_args.sender().create(outcome.pre_execution_nonce));
150
151 if self.output_args.json {
152 let mut summary = ExecutionSummary::from_result(&outcome.exec_result, contract_address);
153 summary.fill_trace_and_dump(outcome, &self.trace_args, &self.dump_args)?;
154 println!(
155 "{}",
156 serde_json::to_string_pretty(&summary).expect("failed to serialize output")
157 );
158 } else {
159 print_execution_summary(&outcome.exec_result, contract_address, outcome.exec_time);
161
162 print_execution_trace(
163 outcome.trace_data.as_deref(),
164 self.trace_args.trace_output_file.as_deref(),
165 )?;
166
167 if self.dump_args.dump {
168 self.dump_args.dump_evm_state(&outcome.state)?;
169 }
170 }
171
172 Ok(())
173 }
174}