Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(evm, forge): use alloy TransactionRequest for saving BroadcastableTransactions #6876

Merged
merged 5 commits into from
Jan 22, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
145 changes: 72 additions & 73 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion crates/anvil/src/eth/backend/fork.rs
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ impl ClientFork {
index: U256,
number: Option<BlockNumber>,
) -> Result<StorageValue, TransportError> {
self.provider().get_storage_at(address, index, number.map(Into::into)).await
self.provider().get_storage_at(address, index.into(), number.map(Into::into)).await
}

pub async fn logs(&self, filter: &Filter) -> Result<Vec<Log>, TransportError> {
Expand Down
42 changes: 20 additions & 22 deletions crates/cheatcodes/src/inspector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,11 @@ use crate::{
},
CheatsConfig, CheatsCtxt, Error, Result, Vm,
};
use alloy_primitives::{Address, Bytes, B256, U256};
use alloy_primitives::{Address, Bytes, B256, U256, U64};
use alloy_rpc_types::request::TransactionRequest;
use alloy_sol_types::{SolInterface, SolValue};
use ethers_core::types::{
transaction::eip2718::TypedTransaction, NameOrAddress, TransactionRequest,
};
use ethers_signers::LocalWallet;
use foundry_common::{evm::Breakpoints, provider::alloy::RpcUrl, types::ToEthers};
use foundry_common::{evm::Breakpoints, provider::alloy::RpcUrl};
use foundry_evm_core::{
backend::{DatabaseError, DatabaseExt, RevertDiagnostic},
constants::{CHEATCODE_ADDRESS, DEFAULT_CREATE2_DEPLOYER, HARDHAT_CONSOLE_ADDRESS},
Expand Down Expand Up @@ -80,7 +78,7 @@ pub struct BroadcastableTransaction {
/// The optional RPC URL.
pub rpc: Option<RpcUrl>,
/// The transaction to broadcast.
pub transaction: TypedTransaction,
pub transaction: TransactionRequest,
}

/// List of transactions that can be broadcasted.
Expand Down Expand Up @@ -834,19 +832,19 @@ impl<DB: DatabaseExt> Inspector<DB> for Cheatcodes {

self.broadcastable_transactions.push_back(BroadcastableTransaction {
rpc: data.db.active_fork_url(),
transaction: TypedTransaction::Legacy(TransactionRequest {
from: Some(broadcast.new_origin.to_ethers()),
to: Some(NameOrAddress::Address(call.contract.to_ethers())),
value: Some(call.transfer.value.to_ethers()),
data: Some(call.input.clone().to_ethers()),
nonce: Some(account.info.nonce.into()),
transaction: TransactionRequest {
from: Some(broadcast.new_origin),
to: Some(call.contract),
value: Some(call.transfer.value),
data: Some(call.input.clone()),
nonce: Some(U64::from(account.info.nonce)),
gas: if is_fixed_gas_limit {
Some(call.gas_limit.into())
Some(U256::from(call.gas_limit))
} else {
None
},
..Default::default()
}),
},
});
debug!(target: "cheatcodes", tx=?self.broadcastable_transactions.back().unwrap(), "broadcastable call");

Expand Down Expand Up @@ -1220,19 +1218,19 @@ impl<DB: DatabaseExt> Inspector<DB> for Cheatcodes {

self.broadcastable_transactions.push_back(BroadcastableTransaction {
rpc: data.db.active_fork_url(),
transaction: TypedTransaction::Legacy(TransactionRequest {
from: Some(broadcast.new_origin.to_ethers()),
to: to.map(|a| NameOrAddress::Address(a.to_ethers())),
value: Some(call.value.to_ethers()),
data: Some(bytecode.to_ethers()),
nonce: Some(nonce.into()),
transaction: TransactionRequest {
from: Some(broadcast.new_origin),
to,
value: Some(call.value),
data: Some(bytecode),
nonce: Some(U64::from(nonce)),
gas: if is_fixed_gas_limit {
Some(call.gas_limit.into())
Some(U256::from(call.gas_limit))
} else {
None
},
..Default::default()
}),
},
});
let kind = match call.scheme {
CreateScheme::Create => "create",
Expand Down
6 changes: 4 additions & 2 deletions crates/evm/core/src/fork/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,8 +179,10 @@ where
let provider = self.provider.clone();
let block_id = self.block_id;
let fut = Box::pin(async move {
let storage =
provider.get_storage_at(address, idx, block_id).await.map_err(Into::into);
let storage = provider
.get_storage_at(address, idx.into(), block_id)
.await
.map_err(Into::into);
(storage, address, idx)
});
self.pending_requests.push(ProviderRequest::Storage(fut));
Expand Down
3 changes: 2 additions & 1 deletion crates/forge/bin/cmd/script/broadcast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use super::{
sequence::ScriptSequence, transaction::TransactionWithMetadata, verify::VerifyBundle, *,
};
use alloy_primitives::{utils::format_units, TxHash};
use ethers_core::types::transaction::eip2718::TypedTransaction;
use ethers_providers::{JsonRpcClient, Middleware, Provider};
use ethers_signers::Signer;
use eyre::{bail, ContextCompat, Result, WrapErr};
Expand Down Expand Up @@ -407,7 +408,7 @@ impl ScriptArgs {
shell::println("\nSKIPPING ON CHAIN SIMULATION.")?;
txs.into_iter()
.map(|btx| {
let mut tx = TransactionWithMetadata::from_typed_transaction(btx.transaction);
let mut tx = TransactionWithMetadata::from_tx_request(btx.transaction);
tx.rpc = btx.rpc;
tx
})
Expand Down
6 changes: 3 additions & 3 deletions crates/forge/bin/cmd/script/cmd.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use super::{multi::MultiChainSequence, sequence::ScriptSequence, verify::VerifyBundle, *};
use alloy_primitives::Bytes;
use ethers_core::types::transaction::eip2718::TypedTransaction;

use ethers_providers::Middleware;
use ethers_signers::Signer;
use eyre::Result;
Expand Down Expand Up @@ -171,7 +171,7 @@ impl ScriptArgs {
for tx in txs.iter() {
lib_deploy.push_back(BroadcastableTransaction {
rpc: tx.rpc.clone(),
transaction: TypedTransaction::Legacy(tx.transaction.clone().into()),
transaction: tx.transaction.clone(),
});
}
*txs = lib_deploy;
Expand Down Expand Up @@ -336,7 +336,7 @@ impl ScriptArgs {
for new_tx in new_txs.iter() {
txs.push_back(BroadcastableTransaction {
rpc: new_tx.rpc.clone(),
transaction: TypedTransaction::Legacy(new_tx.transaction.clone().into()),
transaction: new_tx.transaction.clone(),
});
}
}
Expand Down
25 changes: 9 additions & 16 deletions crates/forge/bin/cmd/script/executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use super::{
*,
};
use alloy_primitives::{Address, Bytes, U256};
use ethers_core::types::transaction::eip2718::TypedTransaction;

Evalir marked this conversation as resolved.
Show resolved Hide resolved
use eyre::Result;
use forge::{
backend::Backend,
Expand All @@ -14,11 +14,7 @@ use forge::{
traces::CallTraceDecoder,
};
use foundry_cli::utils::{ensure_clean_constructor, needs_setup};
use foundry_common::{
provider::ethers::RpcUrl,
shell,
types::{ToAlloy, ToEthers},
};
use foundry_common::{provider::ethers::RpcUrl, shell};
use foundry_compilers::artifacts::CompactContractBytecode;
use futures::future::join_all;
use parking_lot::RwLock;
Expand Down Expand Up @@ -142,17 +138,14 @@ impl ScriptArgs {
let rpc = transaction.rpc.as_ref().expect("missing broadcastable tx rpc url");
let mut runner = runners.get(rpc).expect("invalid rpc url").write();

let TypedTransaction::Legacy(mut tx) = transaction.transaction else {
unreachable!()
};
let mut tx = transaction.transaction;
let result = runner
.simulate(
tx.from
.expect("transaction doesn't have a `from` address at execution time")
.to_alloy(),
tx.to.clone(),
tx.data.clone().map(|b| b.to_alloy()),
tx.value.map(|v| v.to_alloy()),
.expect("transaction doesn't have a `from` address at execution time"),
tx.to,
tx.data.clone(),
tx.value,
)
.wrap_err("Internal EVM error during simulation")?;

Expand Down Expand Up @@ -191,12 +184,12 @@ impl ScriptArgs {
// We inflate the gas used by the user specified percentage
None => {
let gas = U256::from(result.gas_used * self.gas_estimate_multiplier / 100);
tx.gas = Some(gas.to_ethers());
tx.gas = Some(gas);
}
}

let tx = TransactionWithMetadata::new(
tx.into(),
tx,
transaction.rpc,
&result,
&address_to_abi,
Expand Down
50 changes: 21 additions & 29 deletions crates/forge/bin/cmd/script/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,10 @@ use self::{build::BuildOutput, runner::ScriptRunner};
use super::{build::BuildArgs, retry::RetryArgs};
use alloy_dyn_abi::FunctionExt;
use alloy_json_abi::{Function, InternalType, JsonAbi};
use alloy_primitives::{Address, Bytes, Log, U256};
use alloy_primitives::{Address, Bytes, Log, U256, U64};
use alloy_rpc_types::request::TransactionRequest;
use clap::{Parser, ValueHint};
use dialoguer::Confirm;
use ethers_core::types::{
transaction::eip2718::TypedTransaction, NameOrAddress, TransactionRequest,
};
use ethers_providers::{Http, Middleware};
use ethers_signers::LocalWallet;
use eyre::{ContextCompat, Result, WrapErr};
Expand All @@ -29,9 +27,7 @@ use foundry_common::{
evm::{Breakpoints, EvmArgs},
fmt::{format_token, format_token_raw},
provider::ethers::RpcUrl,
shell,
types::{ToAlloy, ToEthers},
ContractsByArtifact, CONTRACT_MAX_SIZE, SELECTOR_LEN,
shell, ContractsByArtifact, CONTRACT_MAX_SIZE, SELECTOR_LEN,
};
use foundry_compilers::{
artifacts::{ContractBytecodeSome, Libraries},
Expand Down Expand Up @@ -387,21 +383,16 @@ impl ScriptArgs {
// If the user passed a `--sender` don't check anything.
if !predeploy_libraries.is_empty() && self.evm_opts.sender.is_none() {
for tx in txs.iter() {
match &tx.transaction {
TypedTransaction::Legacy(tx) => {
if tx.to.is_none() {
let sender = tx.from.expect("no sender").to_alloy();
if let Some(ns) = new_sender {
if sender != ns {
shell::println("You have more than one deployer who could predeploy libraries. Using `--sender` instead.")?;
return Ok(None);
}
} else if sender != evm_opts.sender {
new_sender = Some(sender);
}
if tx.transaction.to.is_none() {
let sender = tx.transaction.from.expect("no sender");
if let Some(ns) = new_sender {
if sender != ns {
shell::println("You have more than one deployer who could predeploy libraries. Using `--sender` instead.")?;
return Ok(None);
}
} else if sender != evm_opts.sender {
new_sender = Some(sender);
}
_ => unreachable!(),
}
}
}
Expand All @@ -422,12 +413,12 @@ impl ScriptArgs {
.enumerate()
.map(|(i, bytes)| BroadcastableTransaction {
rpc: fork_url.clone(),
transaction: TypedTransaction::Legacy(TransactionRequest {
from: Some(from.to_ethers()),
data: Some(bytes.clone().to_ethers()),
nonce: Some((nonce + i as u64).into()),
transaction: TransactionRequest {
from: Some(from),
data: Some(bytes.clone()),
nonce: Some(U64::from(nonce + i as u64)),
..Default::default()
}),
},
})
.collect()
}
Expand Down Expand Up @@ -519,16 +510,17 @@ impl ScriptArgs {
for (data, to) in result.transactions.iter().flat_map(|txes| {
txes.iter().filter_map(|tx| {
tx.transaction
.data()
.data
.clone()
.filter(|data| data.len() > max_size)
.map(|data| (data, tx.transaction.to()))
.map(|data| (data, tx.transaction.to))
})
}) {
let mut offset = 0;

// Find if it's a CREATE or CREATE2. Otherwise, skip transaction.
if let Some(NameOrAddress::Address(to)) = to {
if to.to_alloy() == DEFAULT_CREATE2_DEPLOYER {
if let Some(to) = to {
if to == DEFAULT_CREATE2_DEPLOYER {
// Size of the salt prefix.
offset = 32;
}
Expand Down
13 changes: 3 additions & 10 deletions crates/forge/bin/cmd/script/runner.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use super::*;
use alloy_primitives::{Address, Bytes, U256};
use ethers_core::types::NameOrAddress;
use eyre::Result;
use forge::{
constants::CALLER,
Expand Down Expand Up @@ -204,18 +203,12 @@ impl ScriptRunner {
pub fn simulate(
&mut self,
from: Address,
to: Option<NameOrAddress>,
to: Option<Address>,
calldata: Option<Bytes>,
value: Option<U256>,
) -> Result<ScriptResult> {
if let Some(NameOrAddress::Address(to)) = to {
self.call(
from,
to.to_alloy(),
calldata.unwrap_or_default(),
value.unwrap_or(U256::ZERO),
true,
)
if let Some(to) = to {
self.call(from, to, calldata.unwrap_or_default(), value.unwrap_or(U256::ZERO), true)
} else if to.is_none() {
let (address, gas_used, logs, traces, debug) = match self.executor.deploy(
from,
Expand Down
27 changes: 22 additions & 5 deletions crates/forge/bin/cmd/script/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@ use super::{artifacts::ArtifactInfo, ScriptResult};
use alloy_dyn_abi::JsonAbiExt;
use alloy_json_abi::Function;
use alloy_primitives::{Address, Bytes, B256};
use ethers_core::types::{transaction::eip2718::TypedTransaction, NameOrAddress};
use alloy_rpc_types::request::TransactionRequest;
use ethers_core::types::{
transaction::eip2718::TypedTransaction, NameOrAddress,
TransactionRequest as EthersTransactionRequest,
};
use eyre::{ContextCompat, Result, WrapErr};
use foundry_common::{
fmt::format_token_raw,
Expand Down Expand Up @@ -59,20 +63,33 @@ fn default_vec_of_strings() -> Option<Vec<String>> {
}

impl TransactionWithMetadata {
pub fn from_typed_transaction(transaction: TypedTransaction) -> Self {
Self { transaction, ..Default::default() }
pub fn from_tx_request(transaction: TransactionRequest) -> Self {
Self {
transaction: TypedTransaction::Legacy(EthersTransactionRequest {
from: transaction.from.map(ToEthers::to_ethers),
to: transaction.to.map(ToEthers::to_ethers).map(Into::into),
value: transaction.value.map(ToEthers::to_ethers),
data: transaction.data.map(ToEthers::to_ethers),
nonce: transaction.nonce.map(|n| n.to::<u64>().into()),
gas: transaction.gas.map(ToEthers::to_ethers),
..Default::default()
}),
..Default::default()
}
}

pub fn new(
transaction: TypedTransaction,
transaction: TransactionRequest,
rpc: Option<RpcUrl>,
result: &ScriptResult,
local_contracts: &BTreeMap<Address, ArtifactInfo>,
decoder: &CallTraceDecoder,
additional_contracts: Vec<AdditionalContract>,
is_fixed_gas_limit: bool,
) -> Result<Self> {
let mut metadata = Self { transaction, rpc, is_fixed_gas_limit, ..Default::default() };
let mut metadata = Self::from_tx_request(transaction);
metadata.rpc = rpc;
metadata.is_fixed_gas_limit = is_fixed_gas_limit;

// Specify if any contract was directly created with this transaction
if let Some(NameOrAddress::Address(to)) = metadata.transaction.to().cloned() {
Expand Down
Loading