Skip to content

Commit

Permalink
feat(forge): use signature instead of function name (foundry-rs#2356)
Browse files Browse the repository at this point in the history
* feat(forge): use signature instead of function name

* chore: run fmt

* review changes
  • Loading branch information
lonerapier authored Jul 19, 2022
1 parent 9f0e97e commit 007b4d6
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 36 deletions.
9 changes: 7 additions & 2 deletions evm/src/trace/decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,8 @@ impl CallTraceDecoder {
if let Some(funcs) = self.functions.get(&bytes[0..4]) {
node.decode_function(funcs, &self.labels, &self.errors);
} else if node.trace.address == DEFAULT_CREATE2_DEPLOYER {
node.trace.data = RawOrDecodedCall::Decoded("create2".to_string(), vec![]);
node.trace.data =
RawOrDecodedCall::Decoded("create2".to_string(), String::new(), vec![]);
} else if let Some(identifier) = &self.signature_identifier {
if let Some(function) =
identifier.write().await.identify_function(&bytes[0..4]).await
Expand All @@ -265,7 +266,11 @@ impl CallTraceDecoder {
}
}
} else {
node.trace.data = RawOrDecodedCall::Decoded("fallback".to_string(), Vec::new());
node.trace.data = RawOrDecodedCall::Decoded(
"fallback".to_string(),
String::new(),
Vec::new(),
);

if let RawOrDecodedReturnData::Raw(bytes) = &node.trace.output {
if !node.trace.success {
Expand Down
10 changes: 5 additions & 5 deletions evm/src/trace/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -223,16 +223,16 @@ pub enum RawOrDecodedCall {
Raw(Vec<u8>),
/// Decoded calldata.
///
/// The first element in the tuple is the function name, and the second element is a vector of
/// decoded parameters.
Decoded(String, Vec<String>),
/// The first element in the tuple is the function name, second is the function signature and
/// the third element is a vector of decoded parameters.
Decoded(String, String, Vec<String>),
}

impl RawOrDecodedCall {
pub fn to_raw(&self) -> Vec<u8> {
match self {
RawOrDecodedCall::Raw(raw) => raw.clone(),
RawOrDecodedCall::Decoded(_, _) => {
RawOrDecodedCall::Decoded(_, _, _) => {
vec![]
}
}
Expand Down Expand Up @@ -385,7 +385,7 @@ impl fmt::Display for CallTrace {
assert!(bytes.len() >= 4);
(hex::encode(&bytes[0..4]), hex::encode(&bytes[4..]))
}
RawOrDecodedCall::Decoded(func, inputs) => (func.clone(), inputs.join(", ")),
RawOrDecodedCall::Decoded(func, _, inputs) => (func.clone(), inputs.join(", ")),
};

let action = match self.kind {
Expand Down
6 changes: 5 additions & 1 deletion evm/src/trace/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,10 @@ impl CallTraceNode {
} else {
Vec::new()
};
self.trace.data = RawOrDecodedCall::Decoded(func.name.clone(), inputs);

// add signature to decoded calls for better calls filtering
self.trace.data =
RawOrDecodedCall::Decoded(func.name.clone(), func.signature(), inputs);

if let RawOrDecodedReturnData::Raw(bytes) = &self.trace.output {
if !bytes.is_empty() {
Expand Down Expand Up @@ -164,6 +167,7 @@ impl CallTraceNode {
self.trace.label = Some("PRECOMPILE".to_string());
self.trace.data = RawOrDecodedCall::Decoded(
precompile_fn.name.clone(),
precompile_fn.signature(),
precompile_fn.decode_input(&bytes[..]).map_or_else(
|_| vec![hex::encode(&bytes)],
|tokens| tokens.iter().map(|token| utils::label(token, labels)).collect(),
Expand Down
66 changes: 38 additions & 28 deletions forge/src/gas_report.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ pub struct GasReport {
pub struct ContractInfo {
pub gas: U256,
pub size: U256,
pub functions: BTreeMap<String, GasInfo>,
pub functions: BTreeMap<String, BTreeMap<String, GasInfo>>,
}

#[derive(Debug, Serialize, Deserialize, Default)]
Expand Down Expand Up @@ -65,13 +65,15 @@ impl GasReport {
contract_report.size = bytes.len().into();
}
// TODO: More robust test contract filtering
RawOrDecodedCall::Decoded(func, _)
RawOrDecodedCall::Decoded(func, sig, _)
if !func.starts_with("test") && func != "setUp" =>
{
let function_report = contract_report
.functions
.entry(func.clone())
.or_insert_with(Default::default);
.or_default()
.entry(sig.clone())
.or_default();
function_report.calls.push(trace.gas_cost.into());
}
_ => (),
Expand All @@ -87,23 +89,25 @@ impl GasReport {
#[must_use]
pub fn finalize(mut self) -> Self {
self.contracts.iter_mut().for_each(|(_, contract)| {
contract.functions.iter_mut().for_each(|(_, func)| {
func.calls.sort();
func.min = func.calls.first().cloned().unwrap_or_default();
func.max = func.calls.last().cloned().unwrap_or_default();
func.mean =
func.calls.iter().fold(U256::zero(), |acc, x| acc + x) / func.calls.len();

let len = func.calls.len();
func.median = if len > 0 {
if len % 2 == 0 {
(func.calls[len / 2 - 1] + func.calls[len / 2]) / 2
contract.functions.iter_mut().for_each(|(_, sigs)| {
sigs.iter_mut().for_each(|(_, func)| {
func.calls.sort();
func.min = func.calls.first().cloned().unwrap_or_default();
func.max = func.calls.last().cloned().unwrap_or_default();
func.mean =
func.calls.iter().fold(U256::zero(), |acc, x| acc + x) / func.calls.len();

let len = func.calls.len();
func.median = if len > 0 {
if len % 2 == 0 {
(func.calls[len / 2 - 1] + func.calls[len / 2]) / 2
} else {
func.calls[len / 2]
}
} else {
func.calls[len / 2]
}
} else {
0.into()
};
0.into()
};
});
});
});
self
Expand Down Expand Up @@ -136,15 +140,21 @@ impl Display for GasReport {
Cell::new("max").add_attribute(Attribute::Bold).fg(Color::Red),
Cell::new("# calls").add_attribute(Attribute::Bold),
]);
contract.functions.iter().for_each(|(fname, function)| {
table.add_row(vec![
Cell::new(fname.to_string()).add_attribute(Attribute::Bold),
Cell::new(function.min.to_string()).fg(Color::Green),
Cell::new(function.mean.to_string()).fg(Color::Yellow),
Cell::new(function.median.to_string()).fg(Color::Yellow),
Cell::new(function.max.to_string()).fg(Color::Red),
Cell::new(function.calls.len().to_string()),
]);
contract.functions.iter().for_each(|(fname, sigs)| {
sigs.iter().for_each(|(sig, function)| {
// show function signature if overloaded else name
let fn_display =
if sigs.len() == 1 { fname.clone() } else { sig.replace(':', "") };

table.add_row(vec![
Cell::new(fn_display).add_attribute(Attribute::Bold),
Cell::new(function.min.to_string()).fg(Color::Green),
Cell::new(function.mean.to_string()).fg(Color::Yellow),
Cell::new(function.median.to_string()).fg(Color::Yellow),
Cell::new(function.max.to_string()).fg(Color::Red),
Cell::new(function.calls.len().to_string()),
]);
})
});
writeln!(f, "{}", table)?
}
Expand Down

0 comments on commit 007b4d6

Please sign in to comment.