Skip to content

Commit 2544793

Browse files
authored
feat: cast decode-eof & forge inspect <contract> eof (#8478)
* feat: cast decode-eof & forge inspect <contract> eof * add docs * clippy * fix tests * review fixes
1 parent fe2acca commit 2544793

File tree

12 files changed

+169
-17
lines changed

12 files changed

+169
-17
lines changed

Cargo.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,3 +263,4 @@ tower-http = "0.5"
263263
soldeer = "0.2.19"
264264

265265
proptest = "1"
266+
comfy-table = "7"

crates/cast/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ foundry-cli.workspace = true
6868
clap = { version = "4", features = ["derive", "env", "unicode", "wrap_help"] }
6969
clap_complete = "4"
7070
clap_complete_fig = "4"
71-
comfy-table = "7"
71+
comfy-table.workspace = true
7272
dunce.workspace = true
7373
indicatif = "0.17"
7474
itertools.workspace = true

crates/cast/bin/main.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -567,6 +567,10 @@ async fn main() -> Result<()> {
567567

568568
println!("{}", serde_json::to_string_pretty(&tx)?);
569569
}
570+
CastSubcommand::DecodeEof { eof } => {
571+
let eof = stdin::unwrap_line(eof)?;
572+
println!("{}", SimpleCast::decode_eof(&eof)?);
573+
}
570574
};
571575
Ok(())
572576
}

crates/cast/bin/opts.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -905,7 +905,7 @@ pub enum CastSubcommand {
905905
},
906906

907907
/// Decodes a raw signed EIP 2718 typed transaction
908-
#[command(visible_alias = "dt")]
908+
#[command(visible_aliases = &["dt", "decode-tx"])]
909909
DecodeTransaction { tx: Option<String> },
910910

911911
/// Extracts function selectors and arguments from bytecode
@@ -918,6 +918,10 @@ pub enum CastSubcommand {
918918
#[arg(long, short)]
919919
resolve: bool,
920920
},
921+
922+
/// Decodes EOF container bytes
923+
#[command()]
924+
DecodeEof { eof: Option<String> },
921925
}
922926

923927
/// CLI arguments for `cast --to-base`.

crates/cast/src/lib.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ use foundry_compilers::flatten::Flattener;
3434
use foundry_config::Chain;
3535
use futures::{future::Either, FutureExt, StreamExt};
3636
use rayon::prelude::*;
37+
use revm::primitives::Eof;
3738
use std::{
3839
borrow::Cow,
3940
io,
@@ -1990,6 +1991,24 @@ impl SimpleCast {
19901991
let tx = TxEnvelope::decode_2718(&mut tx_hex.as_slice())?;
19911992
Ok(tx)
19921993
}
1994+
1995+
/// Decodes EOF container bytes
1996+
/// Pretty prints the decoded EOF container contents
1997+
///
1998+
/// # Example
1999+
///
2000+
/// ```
2001+
/// use cast::SimpleCast as Cast;
2002+
///
2003+
/// let eof = "0xef0001010004020001005604002000008000046080806040526004361015e100035f80fd5f3560e01c63773d45e01415e1ffee6040600319360112e10028600435906024358201809211e100066020918152f3634e487b7160e01b5f52601160045260245ffd5f80fd0000000000000000000000000124189fc71496f8660db5189f296055ed757632";
2004+
/// let decoded = Cast::decode_eof(&eof)?;
2005+
/// println!("{}", decoded);
2006+
/// # Ok::<(), eyre::Report>(())
2007+
pub fn decode_eof(eof: &str) -> Result<String> {
2008+
let eof_hex = hex::decode(eof)?;
2009+
let eof = Eof::decode(eof_hex.into())?;
2010+
Ok(pretty_eof(&eof)?)
2011+
}
19932012
}
19942013

19952014
fn strip_0x(s: &str) -> &str {

crates/common/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ tower.workspace = true
4646

4747
async-trait.workspace = true
4848
clap = { version = "4", features = ["derive", "env", "unicode", "wrap_help"] }
49-
comfy-table = "7"
49+
comfy-table.workspace = true
5050
dunce.workspace = true
5151
eyre.workspace = true
5252
num-format.workspace = true

crates/common/fmt/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ alloy-serde.workspace = true
2525
serde.workspace = true
2626
serde_json.workspace = true
2727
chrono.workspace = true
28+
revm-primitives.workspace = true
29+
comfy-table.workspace = true
2830

2931
[dev-dependencies]
3032
foundry-macros.workspace = true

crates/common/fmt/src/eof.rs

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
use comfy_table::{ContentArrangement, Table};
2+
use revm_primitives::{
3+
eof::{EofBody, EofHeader},
4+
Eof,
5+
};
6+
use std::fmt::{self, Write};
7+
8+
pub fn pretty_eof(eof: &Eof) -> Result<String, fmt::Error> {
9+
let Eof {
10+
header:
11+
EofHeader {
12+
types_size,
13+
code_sizes,
14+
container_sizes,
15+
data_size,
16+
sum_code_sizes: _,
17+
sum_container_sizes: _,
18+
},
19+
body:
20+
EofBody { types_section, code_section, container_section, data_section, is_data_filled: _ },
21+
raw: _,
22+
} = eof;
23+
24+
let mut result = String::new();
25+
26+
let mut table = Table::new();
27+
table.add_row(vec!["type_size", &types_size.to_string()]);
28+
table.add_row(vec!["num_code_sections", &code_sizes.len().to_string()]);
29+
if !code_sizes.is_empty() {
30+
table.add_row(vec!["code_sizes", &format!("{code_sizes:?}")]);
31+
}
32+
table.add_row(vec!["num_container_sections", &container_sizes.len().to_string()]);
33+
if !container_sizes.is_empty() {
34+
table.add_row(vec!["container_sizes", &format!("{container_sizes:?}")]);
35+
}
36+
table.add_row(vec!["data_size", &data_size.to_string()]);
37+
38+
write!(result, "Header:\n{table}")?;
39+
40+
if !code_section.is_empty() {
41+
let mut table = Table::new();
42+
table.set_content_arrangement(ContentArrangement::Dynamic);
43+
table.set_header(vec!["", "Inputs", "Outputs", "Max stack height", "Code"]);
44+
for (idx, (code, type_section)) in code_section.iter().zip(types_section).enumerate() {
45+
table.add_row(vec![
46+
&idx.to_string(),
47+
&type_section.inputs.to_string(),
48+
&type_section.outputs.to_string(),
49+
&type_section.max_stack_size.to_string(),
50+
&code.to_string(),
51+
]);
52+
}
53+
54+
write!(result, "\n\nCode sections:\n{table}")?;
55+
}
56+
57+
if !container_section.is_empty() {
58+
let mut table = Table::new();
59+
table.set_content_arrangement(ContentArrangement::Dynamic);
60+
for (idx, container) in container_section.iter().enumerate() {
61+
table.add_row(vec![&idx.to_string(), &container.to_string()]);
62+
}
63+
64+
write!(result, "\n\nContainer sections:\n{table}")?;
65+
}
66+
67+
if !data_section.is_empty() {
68+
let mut table = Table::new();
69+
table.set_content_arrangement(ContentArrangement::Dynamic);
70+
table.add_row(vec![&data_section.to_string()]);
71+
write!(result, "\n\nData section:\n{table}")?;
72+
}
73+
74+
Ok(result)
75+
}

crates/common/fmt/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,6 @@ pub use exp::{format_int_exp, format_uint_exp, to_exp_notation};
1111

1212
mod ui;
1313
pub use ui::{get_pretty_block_attr, get_pretty_tx_attr, EthValue, UIfmt};
14+
15+
mod eof;
16+
pub use eof::pretty_eof;

0 commit comments

Comments
 (0)