Skip to content

Commit

Permalink
feat: use zk deployment sizes in gas report (#595)
Browse files Browse the repository at this point in the history
  • Loading branch information
elfedy committed Sep 27, 2024
1 parent 2aa8fa7 commit 46d9f92
Show file tree
Hide file tree
Showing 7 changed files with 97 additions and 5 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/evm/traces/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ foundry-compilers.workspace = true
foundry-linking.workspace = true
foundry-config.workspace = true
foundry-evm-core.workspace = true
foundry-zksync-compiler.workspace = true

alloy-dyn-abi = { workspace = true, features = ["arbitrary", "eip712"] }
alloy-json-abi.workspace = true
Expand Down
16 changes: 14 additions & 2 deletions crates/evm/traces/src/decoder/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,12 @@ use foundry_evm_core::{
RIPEMD_160, SHA_256,
},
};
use foundry_zksync_compiler::ZKSYNC_ARTIFACTS_DIR;
use itertools::Itertools;
use once_cell::sync::OnceCell;
use revm_inspectors::tracing::types::{DecodedCallLog, DecodedCallTrace};
use rustc_hash::FxHashMap;
use std::collections::{hash_map::Entry, BTreeMap, HashMap};
use std::collections::{hash_map::Entry, BTreeMap, HashMap, HashSet};

mod precompiles;

Expand Down Expand Up @@ -133,6 +134,9 @@ pub struct CallTraceDecoder {

/// Optional identifier of individual trace steps.
pub debug_identifier: Option<DebugTraceIdentifier>,

/// Addresses that are contracts on the ZkVm
pub zk_contracts: HashSet<Address>,
}

impl CallTraceDecoder {
Expand Down Expand Up @@ -207,6 +211,8 @@ impl CallTraceDecoder {
verbosity: 0,

debug_identifier: None,

zk_contracts: Default::default(),
}
}

Expand Down Expand Up @@ -281,7 +287,7 @@ impl CallTraceDecoder {
}

trace!(target: "evm::traces", len=identities.len(), "collecting address identities");
for AddressIdentity { address, label, contract, abi, artifact_id: _ } in identities {
for AddressIdentity { address, label, contract, abi, artifact_id } in identities {
let _span = trace_span!(target: "evm::traces", "identity", ?contract, ?label).entered();

if let Some(contract) = contract {
Expand All @@ -295,6 +301,12 @@ impl CallTraceDecoder {
if let Some(abi) = abi {
self.collect_abi(&abi, Some(&address));
}

if let Some(artifact_id) = artifact_id {
if artifact_id.path.to_string_lossy().contains(ZKSYNC_ARTIFACTS_DIR) {
self.zk_contracts.insert(address);
}
}
}
}

Expand Down
6 changes: 6 additions & 0 deletions crates/forge/src/gas_report.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,12 @@ impl GasReport {
trace!(contract_name, "adding create gas info");
contract_info.gas = trace.gas_used;
contract_info.size = trace.data.len();

if decoder.zk_contracts.contains(&node.trace.address) {
// Intercepted creates in zkvm mode will have the evm bytecode as input
// and the zkvm bytecode as output on the trace.
contract_info.size = trace.output.len();
}
} else if let Some(DecodedCallData { signature, .. }) = decoded().await.call_data {
let name = signature.split('(').next().unwrap();
// ignore any test/setup functions
Expand Down
67 changes: 67 additions & 0 deletions crates/forge/tests/cli/cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use foundry_test_utils::{
util::{pretty_err, read_string, OutputExt, TestCommand},
};
use semver::Version;
use similar_asserts::assert_eq;
use std::{
env, fs,
path::{Path, PathBuf},
Expand Down Expand Up @@ -1512,6 +1513,72 @@ contract ContractThreeTest is DSTest {
assert!(third_out.contains("foo") && third_out.contains("bar") && third_out.contains("baz"));
});

forgetest!(zk_gas_report, |prj, cmd| {
prj.insert_ds_test();
prj.add_source(
"Contracts.sol",
r#"
//SPDX-license-identifier: MIT
import "./test.sol";
contract ContractOne {
int public i;
constructor() {
i = 0;
}
function foo() public{
while(i<5){
i++;
}
}
}
contract ContractOneTest is DSTest {
ContractOne c1;
function setUp() public {
c1 = new ContractOne();
}
function testFoo() public {
c1.foo();
}
}
"#,
)
.unwrap();

prj.write_config(Config {
gas_reports: (vec!["*".to_string()]),
gas_reports_ignore: (vec![]),
..Default::default()
});
let out = cmd.arg("test").arg("--gas-report").stdout_lossy();
cmd.forge_fuse();
let out_zk = cmd.arg("test").arg("--gas-report").arg("--zksync").stdout_lossy();

let mut cells = out.split('|');
let deployment_cost: u64 = cells.nth(22).unwrap().trim().parse().unwrap();
let deployment_size: u64 = cells.next().unwrap().trim().parse().unwrap();
let function = cells.nth(12).unwrap().trim();
let gas: u64 = cells.next().unwrap().trim().parse().unwrap();

let mut cells_zk = out_zk.split('|');
let deployment_cost_zk: u64 = cells_zk.nth(22).unwrap().trim().parse().unwrap();
let deployment_size_zk: u64 = cells_zk.next().unwrap().trim().parse().unwrap();
let function_zk = cells_zk.nth(12).unwrap().trim();
let gas_zk: u64 = cells_zk.next().unwrap().trim().parse().unwrap();

assert!(deployment_cost_zk > deployment_cost);
assert!(deployment_size_zk > deployment_size);
assert!(gas_zk > gas);
assert_eq!(function, "foo");
assert_eq!(function_zk, "foo");
});

forgetest_init!(can_use_absolute_imports, |prj, cmd| {
let remapping = prj.paths().libraries[0].join("myDependency");
let config = Config {
Expand Down
6 changes: 4 additions & 2 deletions crates/forge/tests/it/test_helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ use foundry_evm::{
opts::{Env, EvmOpts},
};
use foundry_test_utils::{fd_lock, init_tracing, TestCommand, ZkSyncNode};
use foundry_zksync_compiler::{DualCompiledContracts, ZKSYNC_SOLIDITY_FILES_CACHE_FILENAME};
use foundry_zksync_compiler::{
DualCompiledContracts, ZKSYNC_ARTIFACTS_DIR, ZKSYNC_SOLIDITY_FILES_CACHE_FILENAME,
};
use once_cell::sync::Lazy;
use semver::Version;
use std::{
Expand Down Expand Up @@ -91,7 +93,7 @@ impl ForgeTestProfile {
let mut zk_project =
foundry_zksync_compiler::config_create_project(&zk_config, zk_config.cache, false)
.expect("failed creating zksync project");
zk_project.paths.artifacts = zk_config.root.as_ref().join("zk").join("zkout");
zk_project.paths.artifacts = zk_config.root.as_ref().join("zk").join(ZKSYNC_ARTIFACTS_DIR);
zk_project.paths.cache = zk_config
.root
.as_ref()
Expand Down
5 changes: 4 additions & 1 deletion crates/zksync/compiler/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ use foundry_compilers::{
/// Filename for zksync cache
pub const ZKSYNC_SOLIDITY_FILES_CACHE_FILENAME: &str = "zksync-solidity-files-cache.json";

/// Directory for zksync artifacts
pub const ZKSYNC_ARTIFACTS_DIR: &str = "zkout";

// Config overrides to create zksync specific foundry-compilers data structures

/// Returns the configured `zksolc` `Settings` that includes:
Expand Down Expand Up @@ -160,7 +163,7 @@ pub fn config_project_paths(config: &Config) -> ProjectPathsConfig<SolcLanguage>
.sources(&config.src)
.tests(&config.test)
.scripts(&config.script)
.artifacts(config.root.0.join("zkout"))
.artifacts(config.root.0.join(ZKSYNC_ARTIFACTS_DIR))
.libs(config.libs.iter())
.remappings(config.get_all_remappings())
.allowed_path(&config.root.0)
Expand Down

0 comments on commit 46d9f92

Please sign in to comment.