Skip to content

Commit 0597b0e

Browse files
authored
fix(forge): verify bytecode should replay txes (#12068)
* fix(forge): verify bytecode should replay txes * Cleanup
1 parent 9b46351 commit 0597b0e

File tree

2 files changed

+61
-8
lines changed

2 files changed

+61
-8
lines changed

crates/verify/src/bytecode.rs

Lines changed: 54 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,12 @@ use alloy_primitives::{Address, Bytes, TxKind, U256, hex};
1111
use alloy_provider::{
1212
Provider,
1313
ext::TraceApi,
14-
network::{AnyTxEnvelope, TransactionBuilder},
14+
network::{
15+
AnyTxEnvelope, TransactionBuilder, TransactionResponse, primitives::BlockTransactions,
16+
},
1517
};
1618
use alloy_rpc_types::{
17-
BlockId, BlockNumberOrTag, TransactionInput, TransactionRequest,
19+
BlockId, BlockNumberOrTag, TransactionInput, TransactionRequest, TransactionTrait,
1820
trace::parity::{Action, CreateAction, CreateOutput, TraceOutput},
1921
};
2022
use clap::{Parser, ValueHint};
@@ -23,11 +25,14 @@ use foundry_cli::{
2325
opts::EtherscanOpts,
2426
utils::{self, LoadConfig, read_constructor_args_file},
2527
};
26-
use foundry_common::shell;
28+
use foundry_common::{SYSTEM_TRANSACTION_TYPE, is_known_system_sender, shell};
2729
use foundry_compilers::{artifacts::EvmVersion, info::ContractInfo};
2830
use foundry_config::{Config, figment, impl_figment_convert};
2931
use foundry_evm::{
30-
constants::DEFAULT_CREATE2_DEPLOYER, core::AsEnvMut, utils::configure_tx_req_env,
32+
constants::DEFAULT_CREATE2_DEPLOYER,
33+
core::AsEnvMut,
34+
executors::EvmError,
35+
utils::{configure_tx_env, configure_tx_req_env},
3136
};
3237
use revm::state::AccountInfo;
3338
use std::path::PathBuf;
@@ -323,6 +328,7 @@ impl VerifyBytecodeArgs {
323328
.ok_or_else(|| {
324329
eyre::eyre!("Transaction not found for hash {}", creation_data.transaction_hash)
325330
})?;
331+
let tx_hash = transaction.tx_hash();
326332
let receipt = provider
327333
.get_transaction_receipt(creation_data.transaction_hash)
328334
.await
@@ -478,7 +484,50 @@ impl VerifyBytecodeArgs {
478484
transaction.set_nonce(prev_block_nonce);
479485

480486
if let Some(ref block) = block {
481-
configure_env_block(&mut env.as_env_mut(), block)
487+
configure_env_block(&mut env.as_env_mut(), block);
488+
489+
let BlockTransactions::Full(ref txs) = block.transactions else {
490+
return Err(eyre::eyre!("Could not get block txs"));
491+
};
492+
493+
// Replay txes in block until the contract creation one.
494+
for tx in txs {
495+
trace!("replay tx::: {}", tx.tx_hash());
496+
if is_known_system_sender(tx.from())
497+
|| tx.transaction_type() == Some(SYSTEM_TRANSACTION_TYPE)
498+
{
499+
continue;
500+
}
501+
if tx.tx_hash() == tx_hash {
502+
break;
503+
}
504+
505+
configure_tx_env(&mut env.as_env_mut(), &tx.inner);
506+
507+
if let TxKind::Call(_) = tx.inner.kind() {
508+
executor.transact_with_env(env.clone()).wrap_err_with(|| {
509+
format!(
510+
"Failed to execute transaction: {:?} in block {}",
511+
tx.tx_hash(),
512+
env.evm_env.block_env.number
513+
)
514+
})?;
515+
} else if let Err(error) = executor.deploy_with_env(env.clone(), None) {
516+
match error {
517+
// Reverted transactions should be skipped
518+
EvmError::Execution(_) => (),
519+
error => {
520+
return Err(error).wrap_err_with(|| {
521+
format!(
522+
"Failed to deploy transaction: {:?} in block {}",
523+
tx.tx_hash(),
524+
env.evm_env.block_env.number
525+
)
526+
});
527+
}
528+
}
529+
}
530+
}
482531
}
483532

484533
// Replace the `input` with local creation code in the creation tx.

crates/verify/src/utils.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
use crate::{bytecode::VerifyBytecodeArgs, types::VerificationType};
22
use alloy_dyn_abi::DynSolValue;
33
use alloy_primitives::{Address, Bytes, TxKind, U256};
4-
use alloy_provider::{Provider, network::AnyRpcBlock};
4+
use alloy_provider::{
5+
Provider,
6+
network::{AnyNetwork, AnyRpcBlock},
7+
};
58
use alloy_rpc_types::BlockId;
69
use clap::ValueEnum;
710
use eyre::{OptionExt, Result};
@@ -17,8 +20,8 @@ use foundry_common::{
1720
use foundry_compilers::artifacts::{BytecodeHash, CompactContractBytecode, EvmVersion};
1821
use foundry_config::Config;
1922
use foundry_evm::{
20-
Env, EnvMut, constants::DEFAULT_CREATE2_DEPLOYER, executors::TracingExecutor, opts::EvmOpts,
21-
traces::TraceMode,
23+
Env, EnvMut, constants::DEFAULT_CREATE2_DEPLOYER, core::AsEnvMut, executors::TracingExecutor,
24+
opts::EvmOpts, traces::TraceMode, utils::apply_chain_and_block_specific_env_changes,
2225
};
2326
use reqwest::Url;
2427
use revm::{bytecode::Bytecode, database::Database, primitives::hardfork::SpecId};
@@ -335,6 +338,7 @@ pub fn configure_env_block(env: &mut EnvMut<'_>, block: &AnyRpcBlock) {
335338
env.block.prevrandao = Some(block.header.mix_hash.unwrap_or_default());
336339
env.block.basefee = block.header.base_fee_per_gas.unwrap_or_default();
337340
env.block.gas_limit = block.header.gas_limit;
341+
apply_chain_and_block_specific_env_changes::<AnyNetwork>(env.as_env_mut(), block);
338342
}
339343

340344
pub fn deploy_contract(

0 commit comments

Comments
 (0)