Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Cargo.lock

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

14 changes: 10 additions & 4 deletions crates/anvil/tests/it/anvil_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -881,19 +881,25 @@ async fn test_mine_blk_with_prev_timestamp() {
assert!(third_blk_timestamp > next_blk_timestamp);
}

// increase time by 0 seconds i.e next_block_timestamp = prev_block_timestamp
// api.evm_increase_time(0).unwrap();
// increase time by 0 seconds leaves the existing offset unchanged; the next block timestamp is
// pinned explicitly because the default timestamp still tracks wall-clock time.
#[tokio::test(flavor = "multi_thread")]
async fn test_increase_time_by_zero() {
let (api, handle) = spawn(NodeConfig::test()).await;
let (api, handle) = spawn(NodeConfig::test().with_genesis_timestamp(Some(1_000u64))).await;
let provider = handle.http_provider();

let init_blk = provider.get_block(BlockId::latest()).await.unwrap().unwrap();

let init_number = init_blk.header.number;
let init_timestamp = init_blk.header.timestamp;
let init_offset = api.backend.time().offset();
assert_ne!(init_offset, 0);

api.evm_set_next_block_timestamp(init_timestamp).unwrap();

let _ = api.evm_increase_time(U256::ZERO).await;
let offset = api.evm_increase_time(U256::ZERO).await.unwrap();
assert_eq!(i128::from(offset), init_offset);
assert_eq!(api.backend.time().offset(), init_offset);

api.mine_one().await;

Expand Down
18 changes: 17 additions & 1 deletion crates/anvil/tests/it/gas.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,23 @@ async fn test_can_use_fee_history() {
provider.send_transaction(tx.clone()).await.unwrap().get_receipt().await.unwrap();
assert!(receipt.inner.inner.is_success());

let fee_history_after = provider.get_fee_history(1, Default::default(), &[]).await.unwrap();
// The receipt is available before the fee history service caches the mined block, so poll
// until the history covers the receipt's block plus the next base fee.
let block_number = receipt.block_number.unwrap();
let fee_history_after = tokio::time::timeout(std::time::Duration::from_secs(5), async {
loop {
let fee_history =
provider.get_fee_history(1, Default::default(), &[]).await.unwrap();
if fee_history.oldest_block == block_number
&& fee_history.base_fee_per_gas.len() == 2
{
break fee_history;
}
tokio::time::sleep(std::time::Duration::from_millis(10)).await;
}
})
.await
.expect("fee history did not include the mined block");
let latest_fee_history_fee = *fee_history_after.base_fee_per_gas.first().unwrap() as u64;
let latest_block = provider.get_block(BlockId::latest()).await.unwrap().unwrap();

Expand Down
7 changes: 3 additions & 4 deletions crates/forge/tests/cli/install.rs
Original file line number Diff line number Diff line change
Expand Up @@ -607,18 +607,17 @@ forgetest_init!(sync_on_forge_update, |prj, cmd| {
let forge_std_path = prj.root().join("lib/forge-std");
let git = Git::new(&forge_std_path);

// Ensure we're on the release tag first (known starting point)
// Ensure we're on the pinned revision first (known starting point)
git.checkout(false, forge_std.name()).unwrap();
assert_eq!(git.head().unwrap(), forge_std.rev(), "Forge std should be at the release tag");
assert_eq!(git.head().unwrap(), forge_std.rev(), "Forge std should be at the pinned revision");

// Make sure origin/master is up to date, then resolve its commit hash deterministically.
git.fetch(false, "origin", Some("master")).unwrap();
let origin_master_head = git.get_rev("refs/remotes/origin/master", &forge_std_path).unwrap();

// Run update and assert the output matches the dynamically resolved hash.
let expected_output = format!(
"Updated dep at 'lib/forge-std', (from: tag={}@{}, to: branch=master@{})\n",
forge_std.name(),
"Updated dep at 'lib/forge-std', (from: rev={}, to: branch=master@{})\n",
forge_std.rev(),
origin_master_head
);
Expand Down
2 changes: 1 addition & 1 deletion crates/forge/tests/cli/script.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1945,7 +1945,7 @@ contract SimpleScript is Script {
])
.assert_success()
.stdout_eq(str![[r#"
{"logs":[],"returns":{"success":{"internal_type":"bool","value":"true"}},"success":true,"raw_logs":[],"traces":[["Deployment",{"arena":[{"parent":null,"children":[],"idx":0,"trace":{"depth":0,"success":true,"caller":"0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38","address":"0x5b73c5498c1e3b4dba84de0f1833c4a029d90519","maybe_precompile":false,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CREATE","value":"0x0","data":"[..]","output":"[..]","gas_used":"{...}","gas_limit":"{...}","gas_refund_counter":0,"status":"Return","steps":[],"decoded":{"label":"SimpleScript","return_data":null,"call_data":null}},"logs":[],"ordering":[]}]}],["Execution",{"arena":[{"parent":null,"children":[1,2],"idx":0,"trace":{"depth":0,"success":true,"caller":"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266","address":"0x5b73c5498c1e3b4dba84de0f1833c4a029d90519","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CALL","value":"0x0","data":"0xc0406226","output":"0x0000000000000000000000000000000000000000000000000000000000000001","gas_used":"{...}","gas_limit":1073720760,"gas_refund_counter":0,"status":"Return","steps":[],"decoded":{"label":"SimpleScript","return_data":"true","call_data":{"signature":"run()","args":[]}}},"logs":[],"ordering":[{"Call":0},{"Call":1}]},{"parent":0,"children":[],"idx":1,"trace":{"depth":1,"success":true,"caller":"0x5b73c5498c1e3b4dba84de0f1833c4a029d90519","address":"0x7109709ecfa91a80626ff3989d68f67f5b1dd12d","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CALL","value":"0x0","data":"0x7fb5297f","output":"0x","gas_used":"{...}","gas_limit":1056940999,"gas_refund_counter":0,"status":"Return","steps":[],"decoded":{"label":"VM","return_data":null,"call_data":{"signature":"startBroadcast()","args":[]}}},"logs":[],"ordering":[]},{"parent":0,"children":[],"idx":2,"trace":{"depth":1,"success":true,"caller":"0x5b73c5498c1e3b4dba84de0f1833c4a029d90519","address":"0x0000000000000000000000000000000000000000","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CALL","value":"0x0","data":"0x","output":"0x","gas_used":"{...}","gas_limit":1056940650,"gas_refund_counter":0,"status":"Stop","steps":[],"decoded":{"label":"","return_data":null,"call_data":null}},"logs":[],"ordering":[]}]}]],"gas_used":"{...}","labeled_addresses":{},"returned":"0x0000000000000000000000000000000000000000000000000000000000000001","address":null}
{"logs":[],"returns":{"success":{"internal_type":"bool","value":"true"}},"success":true,"raw_logs":[],"traces":[["Deployment",{"arena":[{"parent":null,"children":[],"idx":0,"trace":{"depth":0,"success":true,"caller":"0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38","address":"0x5b73c5498c1e3b4dba84de0f1833c4a029d90519","maybe_precompile":false,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CREATE","value":"0x0","data":"[..]","output":"[..]","gas_used":"{...}","gas_limit":"{...}","gas_refund_counter":0,"status":"Return","steps":[],"decoded":{"label":"SimpleScript","return_data":null,"call_data":null}},"logs":[],"ordering":[]}]}],["Execution",{"arena":[{"parent":null,"children":[1,2],"idx":0,"trace":{"depth":0,"success":true,"caller":"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266","address":"0x5b73c5498c1e3b4dba84de0f1833c4a029d90519","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CALL","value":"0x0","data":"0xc0406226","output":"0x0000000000000000000000000000000000000000000000000000000000000001","gas_used":"{...}","gas_limit":1073720760,"gas_refund_counter":0,"status":"Return","steps":[],"decoded":{"label":"SimpleScript","return_data":"true","call_data":{"signature":"run()","args":[]}}},"logs":[],"ordering":[{"Call":0},{"Call":1}]},{"parent":0,"children":[],"idx":1,"trace":{"depth":1,"success":true,"caller":"0x5b73c5498c1e3b4dba84de0f1833c4a029d90519","address":"0x7109709ecfa91a80626ff3989d68f67f5b1dd12d","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CALL","value":"0x0","data":"0x7fb5297f","output":"0x","gas_used":"{...}","gas_limit":1056940999,"gas_refund_counter":0,"status":"Return","steps":[],"decoded":{"label":"VM","return_data":null,"call_data":{"signature":"startBroadcast()","args":[]}}},"logs":[],"ordering":[]},{"parent":0,"children":[],"idx":2,"trace":{"depth":1,"success":true,"caller":"0x5b73c5498c1e3b4dba84de0f1833c4a029d90519","address":"0x0000000000000000000000000000000000000000","maybe_precompile":null,"selfdestruct_address":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CALL","value":"0x0","data":"0x","output":"0x","gas_used":"{...}","gas_limit":1056940650,"gas_refund_counter":0,"status":"Stop","steps":[],"decoded":{"label":null,"return_data":null,"call_data":null}},"logs":[],"ordering":[]}]}]],"gas_used":"{...}","labeled_addresses":{},"returned":"0x0000000000000000000000000000000000000000000000000000000000000001","address":null}
{"chain":31337,"estimated_gas_price":"{...}","estimated_total_gas_used":"{...}","estimated_amount_required":"{...}","token_symbol":"ETH"}
{"chain":"anvil-hardhat","status":"success","tx_hash":"0x4f78afe915fceb282c7625a68eb350bc0bf78acb59ad893e5c62b710a37f3156","contract_address":null,"block_number":1,"gas_used":"{...}","gas_price":"{...}"}
{"status":"success","transactions":"[..]/broadcast/Foo.sol/31337/run-latest.json","sensitive":"[..]/cache/Foo.sol/31337/run-latest.json"}
Expand Down
47 changes: 41 additions & 6 deletions crates/forge/tests/cli/verify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -313,16 +313,24 @@ forgetest!(can_verify_random_contract_sepolia_default_sourcify, |prj, cmd| {

// Tests that verify properly validates verifier arguments.
// <https://github.com/foundry-rs/foundry/issues/11430>
forgetest_init!(can_validate_verifier_settings, |prj, cmd| {
forgetest_async!(can_validate_verifier_settings, |prj, cmd| {
foundry_test_utils::util::initialize(prj.root());
prj.initialize_default_contracts();
// A local solc reports full build metadata; with an explicit compilation profile (which skips
// the cache lookup that drops it), verify never needs the remote solc release list.
prj.update_config(|config| {
config.solc = Some(foundry_config::SolcReq::Local(svm::version_binary(
foundry_test_utils::util::SOLC_VERSION,
)));
});
// Build the project to create the cache.
cmd.forge_fuse().arg("build").assert_success();
// No verifier URL.
cmd.forge_fuse()
.args([
"verify-contract",
"--rpc-url",
"https://rpc.sepolia-api.lisk.com",
"--chain",
"4202",
"--verifier",
"blockscout",
"0x19b248616E4964f43F611b5871CE1250f360E9d3",
Expand All @@ -338,8 +346,8 @@ Error: No verifier URL specified for verifier blockscout
cmd.forge_fuse()
.args([
"verify-contract",
"--rpc-url",
"https://rpc.sepolia-api.lisk.com",
"--chain",
"4202",
"--verifier",
"etherscan",
"0x19b248616E4964f43F611b5871CE1250f360E9d3",
Expand All @@ -353,7 +361,34 @@ Error: No known Etherscan API URL for chain `4202`. To fix this, please:

"#]]);

cmd.forge_fuse().args(["verify-contract", "--rpc-url", "https://rpc.sepolia-api.lisk.com", "--verifier", "blockscout", "--verifier-url", "https://sepolia-blockscout.lisk.com/api", "0x19b248616E4964f43F611b5871CE1250f360E9d3", "src/Counter.sol:Counter"]).assert_success().stdout_eq(str![[r#"
let app = axum::Router::new().route(
"/api",
axum::routing::get(
|axum::extract::Query(q): axum::extract::Query<
std::collections::HashMap<String, String>,
>| async move {
let expected = q.get("module").is_some_and(|m| m == "contract")
&& q.get("action").is_some_and(|a| a == "getabi")
&& q.get("address").is_some_and(|a| {
a.eq_ignore_ascii_case("0x19b248616E4964f43F611b5871CE1250f360E9d3")
});
if expected {
Ok(axum::Json(
serde_json::json!({"status": "1", "message": "OK", "result": "[]"}),
))
} else {
Err((axum::http::StatusCode::BAD_REQUEST, format!("unexpected query: {q:?}")))
}
},
),
);
let listener = tokio::net::TcpListener::bind("127.0.0.1:0").await.unwrap();
let verifier_url = format!("http://{}/api", listener.local_addr().unwrap());
tokio::spawn(async move {
axum::serve(listener, app).await.unwrap();
});

cmd.forge_fuse().args(["verify-contract", "--chain", "4202", "--verifier", "blockscout", "--verifier-url", &verifier_url, "--compilation-profile", "default", "0x19b248616E4964f43F611b5871CE1250f360E9d3", "src/Counter.sol:Counter"]).assert_success().stdout_eq(str![[r#"
Start verifying contract `0x19b248616E4964f43F611b5871CE1250f360E9d3` deployed on 4202

Contract [src/Counter.sol:Counter] "0x19b248616E4964f43F611b5871CE1250f360E9d3" is already verified. Skipping verification.
Expand Down
13 changes: 13 additions & 0 deletions crates/test-utils/src/ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,19 @@ impl ExtTester {
if !status.success() {
panic!("git checkout failed: {status}");
}

// Check out the submodules pinned by the selected revision.
if recursive {
for args in [&["sync", "--recursive"][..], &["update", "--init", "--recursive"]] {
let mut git = Command::new("git");
git.current_dir(root).arg("submodule").args(args);
test_debug!("$ {git:?}");
let status = git.status().unwrap();
if !status.success() {
panic!("git submodule {} failed: {status}", args[0]);
}
}
}
}

(prj, test_cmd)
Expand Down
17 changes: 7 additions & 10 deletions crates/test-utils/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ use std::{
fs::{self, File},
io::{IsTerminal, Read, Seek, Write},
path::{Path, PathBuf},
process::Command,
sync::LazyLock,
};

Expand Down Expand Up @@ -81,20 +80,18 @@ pub fn initialize(target: &Path) {
let (prj, mut cmd) = setup_forge("template", foundry_compilers::PathStyle::Dapptools);
test_debug!("- initializing template dir in {}", prj.root().display());

cmd.args(["init", "--force", "--empty"]).assert_success();
cmd.args(["init", "--force", "--empty", "--offline"]).assert_success();

// Install the pinned forge-std so `foundry.lock` records the checked-out revision.
cmd.forge_fuse()
.args(["install", &format!("foundry-rs/forge-std@{FORGE_STD_REVISION}")])
.assert_success();

prj.write_config(Config {
solc: Some(foundry_config::SolcReq::Version(SOLC_VERSION.parse().unwrap())),
..Default::default()
});

// Checkout forge-std.
let output = Command::new("git")
.current_dir(prj.root().join("lib/forge-std"))
.args(["checkout", FORGE_STD_REVISION])
.output()
.expect("failed to checkout forge-std");
assert!(output.status.success(), "{output:#?}");

// Build the project.
cmd.forge_fuse().arg("build").assert_success();

Expand Down
Loading