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

chore(anvil): migrate cheatsmanager to alloy #6767

Merged
merged 4 commits into from
Jan 12, 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
17 changes: 17 additions & 0 deletions crates/anvil/core/src/eth/transaction/ethers_compat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,23 @@ use ethers_core::types::{
};
use foundry_common::types::{ToAlloy, ToEthers};

pub fn to_alloy_signature(signature: ethers_core::types::Signature) -> alloy_rpc_types::Signature {
alloy_rpc_types::Signature {
r: signature.r.to_alloy(),
s: signature.s.to_alloy(),
v: signature.v.to_alloy().to::<rU256>(),
y_parity: None,
}
}

pub fn to_ethers_signature(signature: alloy_rpc_types::Signature) -> ethers_core::types::Signature {
ethers_core::types::Signature {
r: signature.r.to_ethers(),
s: signature.s.to_ethers(),
v: signature.v.to::<u64>(),
}
}

pub fn to_alloy_proof(proof: AccountProof) -> alloy_rpc_types::EIP1186AccountProofResponse {
alloy_rpc_types::EIP1186AccountProofResponse {
address: proof.address.to_alloy(),
Expand Down
14 changes: 9 additions & 5 deletions crates/anvil/core/src/eth/transaction/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ use crate::eth::{
receipt::Log,
utils::{enveloped, to_revm_access_list},
};
#[cfg(feature = "impersonated-tx")]
use alloy_primitives::U256 as rU256;
#[cfg(feature = "impersonated-tx")]
use alloy_rpc_types::Signature as AlloySignature;
Evalir marked this conversation as resolved.
Show resolved Hide resolved
use ethers_core::{
types::{
transaction::eip2930::{AccessList, AccessListItem},
Expand All @@ -26,14 +30,14 @@ use std::ops::Deref;
mod ethers_compat;

pub use ethers_compat::{
call_to_internal_tx_request, from_ethers_access_list, to_alloy_proof, to_ethers_access_list,
to_internal_tx_request,
call_to_internal_tx_request, from_ethers_access_list, to_alloy_proof, to_alloy_signature,
to_ethers_access_list, to_ethers_signature, to_internal_tx_request,
};

/// The signature used to bypass signing via the `eth_sendUnsignedTransaction` cheat RPC
#[cfg(feature = "impersonated-tx")]
pub const IMPERSONATED_SIGNATURE: Signature =
Signature { r: U256([0, 0, 0, 0]), s: U256([0, 0, 0, 0]), v: 0 };
pub const IMPERSONATED_SIGNATURE: AlloySignature =
AlloySignature { r: rU256::ZERO, s: rU256::ZERO, v: rU256::ZERO, y_parity: None };

/// Container type for various Ethereum transaction requests
///
Expand Down Expand Up @@ -790,7 +794,7 @@ impl TypedTransaction {
/// Returns true if the transaction was impersonated (using the impersonate Signature)
#[cfg(feature = "impersonated-tx")]
pub fn is_impersonated(&self) -> bool {
self.signature() == IMPERSONATED_SIGNATURE
to_alloy_signature(self.signature()) == IMPERSONATED_SIGNATURE
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make self.signature() return an alloy signature imo, any reason why we cannot port the typed transaction fields to be alloy?

Copy link
Member Author

@Evalir Evalir Jan 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thought about doing this, but migrating typedtransaction so early would make us migrate most of anvil in one go with a longer running pr—ideally we want to avoid this.

TypedTransaction, along with other base types are getting migrated on this PR: #6778

}

/// Returns the hash if the transaction is impersonated (using a fake signature)
Expand Down
24 changes: 16 additions & 8 deletions crates/anvil/src/eth/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ use anvil_core::{
block::BlockInfo,
transaction::{
call_to_internal_tx_request, to_alloy_proof, to_ethers_access_list,
EthTransactionRequest, LegacyTransaction, PendingTransaction, TransactionKind,
TypedTransaction, TypedTransactionRequest,
to_ethers_signature, EthTransactionRequest, LegacyTransaction, PendingTransaction,
TransactionKind, TypedTransaction, TypedTransactionRequest,
},
EthRequest,
},
Expand Down Expand Up @@ -562,9 +562,15 @@ impl EthApi {
pub fn accounts(&self) -> Result<Vec<Address>> {
node_info!("eth_accounts");
let mut unique = HashSet::new();
let mut accounts = Vec::new();
let mut accounts: Vec<Address> = Vec::new();
for signer in self.signers.iter() {
accounts.extend(signer.accounts().into_iter().filter(|acc| unique.insert(*acc)));
accounts.extend(
signer
.accounts()
.into_iter()
.map(|a| a.to_alloy())
.filter(|acc| unique.insert(*acc)),
);
}
accounts.extend(
self.backend
Expand All @@ -573,7 +579,7 @@ impl EthApi {
.into_iter()
.filter(|acc| unique.insert(*acc)),
);
Ok(accounts.into_iter().map(|acc| acc.to_alloy()).collect())
Ok(accounts.into_iter().map(|acc| acc).collect())
}

/// Returns the number of most recent block.
Expand Down Expand Up @@ -895,7 +901,8 @@ impl EthApi {
// if the sender is currently impersonated we need to "bypass" signing
let pending_transaction = if self.is_impersonated(from) {
let bypass_signature = self.backend.cheats().bypass_signature();
let transaction = sign::build_typed_transaction(request, bypass_signature)?;
let transaction =
sign::build_typed_transaction(request, to_ethers_signature(bypass_signature))?;
self.ensure_typed_transaction_supported(&transaction)?;
trace!(target : "node", ?from, "eth_sendTransaction: impersonating");
PendingTransaction::with_impersonated(transaction, from.to_ethers())
Expand Down Expand Up @@ -1985,7 +1992,8 @@ impl EthApi {
let request = self.build_typed_tx_request(request, nonce)?;

let bypass_signature = self.backend.cheats().bypass_signature();
let transaction = sign::build_typed_transaction(request, bypass_signature)?;
let transaction =
sign::build_typed_transaction(request, to_ethers_signature(bypass_signature))?;

self.ensure_typed_transaction_supported(&transaction)?;

Expand Down Expand Up @@ -2521,7 +2529,7 @@ impl EthApi {

/// Returns true if the `addr` is currently impersonated
pub fn is_impersonated(&self, addr: Address) -> bool {
self.backend.cheats().is_impersonated(addr.to_ethers())
self.backend.cheats().is_impersonated(addr)
}

/// Returns the nonce of the `address` depending on the `block_number`
Expand Down
3 changes: 2 additions & 1 deletion crates/anvil/src/eth/backend/cheats.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
//! Support for "cheat codes" / bypass functions

use alloy_primitives::Address;
use alloy_rpc_types::Signature;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@DaniPopes are we mixing types here? or should we pull signature into primitives?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do have alloy_primitives::Signature! we'll pull it in once needed when we get into actually moving types that can recover their signer (TypedTransaction, e.g) here #6778. For now we can use this type, as right now we just need an equivalence check

use anvil_core::eth::transaction::IMPERSONATED_SIGNATURE;
use ethers::types::{Address, Signature};
use foundry_evm::hashbrown::HashSet;
use parking_lot::RwLock;
use std::sync::Arc;
Expand Down
6 changes: 3 additions & 3 deletions crates/anvil/src/eth/backend/mem/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -312,20 +312,20 @@ impl Backend {
///
/// Returns `true` if the account is already impersonated
pub async fn impersonate(&self, addr: Address) -> DatabaseResult<bool> {
if self.cheats.impersonated_accounts().contains(&addr.to_ethers()) {
Evalir marked this conversation as resolved.
Show resolved Hide resolved
if self.cheats.impersonated_accounts().contains(&addr) {
return Ok(true);
}
// Ensure EIP-3607 is disabled
let mut env = self.env.write();
env.cfg.disable_eip3607 = true;
Ok(self.cheats.impersonate(addr.to_ethers()))
Ok(self.cheats.impersonate(addr))
}

/// Removes the account that from the impersonated set
///
/// If the impersonated `addr` is a contract then we also reset the code here
pub async fn stop_impersonating(&self, addr: Address) -> DatabaseResult<()> {
self.cheats.stop_impersonating(&addr.to_ethers());
self.cheats.stop_impersonating(&addr);
Ok(())
}

Expand Down
Loading