Skip to content

Commit

Permalink
fix: make impersonated_accounts a hashset instead of option
Browse files Browse the repository at this point in the history
  • Loading branch information
grw-ms committed Sep 21, 2023
1 parent 67d6e82 commit 4a58732
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 24 deletions.
38 changes: 26 additions & 12 deletions src/hardhat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,10 @@ pub trait HardhatNamespaceT {
) -> BoxFuture<Result<bool>>;

/// Hardhat Network allows you to send transactions impersonating specific account and contract addresses.
/// To impersonate an account use this method, passing the address to impersonate as its parameter:
/// To impersonate an account use this method, passing the address to impersonate as its parameter.
/// After calling this method, any transactions with this sender will be executed without verification.
/// Multiple addresses can be impersonated at once.
///
/// # Arguments
///
/// * `address` - The address to impersonate
Expand All @@ -85,17 +88,17 @@ pub trait HardhatNamespaceT {
fn impersonate_account(&self, address: Address) -> BoxFuture<Result<bool>>;

/// Use this method to stop impersonating an account after having previously used `hardhat_impersonateAccount`
/// The address parameter is included for compatibility- since we only support impersonating one account at a time, it is ignored.
/// The method returns `true` if the account was being impersonated and `false` otherwise.
///
/// # Arguments
///
/// * `address` (Optional) - The address to stop impersonating.
/// * `address` - The address to stop impersonating.
///
/// # Returns
///
/// A `BoxFuture` containing a `Result` with a `bool` representing the success of the operation.
#[rpc(name = "hardhat_stopImpersonatingAccount")]
fn stop_impersonating_account(&self, address: Option<Address>) -> BoxFuture<Result<bool>>;
fn stop_impersonating_account(&self, address: Address) -> BoxFuture<Result<bool>>;
}

impl<S: Send + Sync + 'static + ForkSource + std::fmt::Debug> HardhatNamespaceT
Expand Down Expand Up @@ -205,23 +208,34 @@ impl<S: Send + Sync + 'static + ForkSource + std::fmt::Debug> HardhatNamespaceT
Box::pin(async move {
match inner.write() {
Ok(mut inner) => {
inner.set_impersonated_account(address);
log::info!("🕵️ Account {:?} has been impersonated", address);
Ok(true)
if inner.set_impersonated_account(address) {
log::info!("🕵️ Account {:?} has been impersonated", address);
Ok(true)
} else {
log::info!("🕵️ Account {:?} was already impersonated", address);
Ok(false)
}
}
Err(_) => Err(into_jsrpc_error(Web3Error::InternalError)),
}
})
}

fn stop_impersonating_account(&self, _address: Option<Address>) -> BoxFuture<Result<bool>> {
fn stop_impersonating_account(&self, address: Address) -> BoxFuture<Result<bool>> {
let inner = Arc::clone(&self.node);
Box::pin(async move {
match inner.write() {
Ok(mut inner) => {
inner.stop_impersonating_account();
log::info!("🕵️ Stopped impersonating account");
Ok(true)
if inner.stop_impersonating_account(address) {
log::info!("🕵️ Stopped impersonating account {:?}", address);
Ok(true)
} else {
log::info!(
"🕵️ Account {:?} was not impersonated, nothing to stop",
address
);
Ok(false)
}
}
Err(_) => Err(into_jsrpc_error(Web3Error::InternalError)),
}
Expand Down Expand Up @@ -394,7 +408,7 @@ mod tests {

// stop impersonating the account
let result = hardhat
.stop_impersonating_account(None)
.stop_impersonating_account(to_impersonate)
.await
.expect("stop_impersonating_account");
assert!(result);
Expand Down
26 changes: 14 additions & 12 deletions src/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use futures::FutureExt;
use jsonrpc_core::BoxFuture;
use std::{
cmp::{self},
collections::HashMap,
collections::{HashMap, HashSet},
str::FromStr,
sync::{Arc, RwLock},
};
Expand Down Expand Up @@ -246,7 +246,7 @@ pub struct InMemoryNodeInner<S> {
pub resolve_hashes: bool,
pub console_log_handler: ConsoleLogHandler,
pub system_contracts: SystemContracts,
pub impersonated_account: Option<Address>,
pub impersonated_accounts: HashSet<Address>,
}

type L2TxResult = (
Expand Down Expand Up @@ -561,16 +561,16 @@ impl<S: std::fmt::Debug + ForkSource> InMemoryNodeInner<S> {

/// Sets the `impersonated_account` field of the node.
/// This field is used to override the `tx.initiator_account` field of the transaction in the `run_l2_tx` method.
pub fn set_impersonated_account(&mut self, address: Address) {
self.impersonated_account = Some(address);
pub fn set_impersonated_account(&mut self, address: Address) -> bool {
return self.impersonated_accounts.insert(address);

// Use SystemContracts without signature verification
self.system_contracts = SystemContracts::from_options(&Options::BuiltInWithoutSecurity);
}

/// Clears the `impersonated_account` field of the node.
pub fn stop_impersonating_account(&mut self) {
self.impersonated_account = None;
pub fn stop_impersonating_account(&mut self, address: Address) -> bool {
return self.impersonated_accounts.remove(&address);

// Restore previous SystemContracts
self.system_contracts = SystemContracts::from_options(&Options::BuiltIn);
Expand Down Expand Up @@ -653,7 +653,7 @@ impl<S: ForkSource + std::fmt::Debug> InMemoryNode<S> {
resolve_hashes,
console_log_handler: ConsoleLogHandler::default(),
system_contracts: SystemContracts::from_options(system_contracts_options),
impersonated_account: None,
impersonated_accounts: Default::default(),
}
} else {
let mut block_hashes = HashMap::<u64, H256>::new();
Expand Down Expand Up @@ -683,7 +683,7 @@ impl<S: ForkSource + std::fmt::Debug> InMemoryNode<S> {
resolve_hashes,
console_log_handler: ConsoleLogHandler::default(),
system_contracts: SystemContracts::from_options(system_contracts_options),
impersonated_account: None,
impersonated_accounts: Default::default(),
}
};

Expand Down Expand Up @@ -1126,19 +1126,21 @@ impl<S: ForkSource + std::fmt::Debug> InMemoryNode<S> {
}

/// Runs L2 transaction and commits it to a new block.
fn run_l2_tx(&self, mut l2_tx: L2Tx, execution_mode: TxExecutionMode) -> Result<(), String> {
fn run_l2_tx(&self, l2_tx: L2Tx, execution_mode: TxExecutionMode) -> Result<(), String> {
let tx_hash = l2_tx.hash();
{
let inner = self
.inner
.read()
.map_err(|e| format!("Failed to acquire read lock: {}", e))?;
if let Some(impersonated_account) = inner.impersonated_account {
if inner
.impersonated_accounts
.contains(&l2_tx.common_data.initiator_address)
{
tracing::info!(
"🕵️ Executing tx from impersonated account {:?}",
impersonated_account
l2_tx.common_data.initiator_address
);
l2_tx.common_data.initiator_address = impersonated_account;
}
}
log::info!("");
Expand Down

0 comments on commit 4a58732

Please sign in to comment.