Skip to content

Commit

Permalink
fix: use non-verifying system contracts when impersonating
Browse files Browse the repository at this point in the history
  • Loading branch information
grw-ms committed Sep 19, 2023
1 parent 6b255e5 commit 4c4ebc1
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 48 deletions.
54 changes: 38 additions & 16 deletions src/hardhat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -356,39 +356,61 @@ mod tests {
}

#[tokio::test]
async fn test_send_raw_transaction() {
async fn test_impersonate_account() {
let node = InMemoryNode::<HttpForkSource>::default();
let hardhat: HardhatNamespaceImpl<HttpForkSource> =
HardhatNamespaceImpl::new(node.get_inner());

let to_impersonate =
Address::from_str("0xd8da6bf26964af9d7eed9e03e53415d37aa96045").unwrap();

// give impersonated account some balance
let result = hardhat
.impersonate_account(to_impersonate)
.set_balance(to_impersonate, U256::exp10(18))
.await
.expect("impersonate_account");
.unwrap();
assert!(result);

// impersonate the account
let result = hardhat
.set_balance(to_impersonate, U256::exp10(18))
.impersonate_account(to_impersonate)
.await
.unwrap();
.expect("impersonate_account");
assert!(result);
let balance_before = node
.get_balance(to_impersonate, None)
.await
.expect("failed fetching balance");
println!("balance before: {}", balance_before);

// testing::apply_tx() sends 1 wei from a random address to another random address
let _hash = testing::apply_tx(&node, H256::repeat_byte(0x01));
// testing::apply_tx should use the impersonated account as the sender
{
let _hash = testing::apply_tx(&node, H256::repeat_byte(0x01));
let inner = node.get_inner();
let lock = inner.read().unwrap();
let tx = lock
.tx_results
.get(&H256::repeat_byte(0x01))
.expect("tx exists");

// check that the tx was sent from the impersonated account
assert_eq!(tx.tx.initiator_account(), to_impersonate);
}

let balance_after = node
.get_balance(to_impersonate, None)
// stop impersonating the account
let result = hardhat
.stop_impersonating_account(None)
.await
.expect("failed fetching balance");
.expect("stop_impersonating_account");
assert!(result);

assert_eq!(balance_before, balance_after + U256::one());
// testing::apply_tx should use a random account as the sender
{
let _hash = testing::apply_tx(&node, H256::repeat_byte(0x02));
let inner = node.get_inner();
let lock = inner.read().unwrap();
let tx = lock
.tx_results
.get(&H256::repeat_byte(0x02))
.expect("tx exists");

// check that the tx was sent from the impersonated account
assert_ne!(tx.tx.initiator_account(), to_impersonate);
}
}
}
38 changes: 23 additions & 15 deletions src/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crate::{
console_log::ConsoleLogHandler,
fork::{ForkDetails, ForkSource, ForkStorage},
formatter,
system_contracts::{self, SystemContracts},
system_contracts::{self, Options, SystemContracts},
utils::{
adjust_l1_gas_price_for_tx, adjust_tx_initiator, derive_gas_estimation_overhead,
to_human_size, IntoBoxedFuture,
Expand Down Expand Up @@ -564,11 +564,17 @@ impl<S: std::fmt::Debug + ForkSource> InMemoryNodeInner<S> {
/// 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);

// 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;

// Restore previous SystemContracts
self.system_contracts = SystemContracts::from_options(&Options::BuiltIn);
}
}

Expand Down Expand Up @@ -755,10 +761,7 @@ impl<S: ForkSource + std::fmt::Debug> InMemoryNode<S> {
execution_mode,
);

let mut tx: Transaction = l2_tx.into();
if let Some(impersonated_account) = inner.impersonated_account {
tx = adjust_tx_initiator(tx, impersonated_account);
}
let tx: Transaction = l2_tx.into();

push_transaction_to_bootloader_memory(&mut vm, &tx, execution_mode, None);

Expand Down Expand Up @@ -969,15 +972,7 @@ impl<S: ForkSource + std::fmt::Debug> InMemoryNode<S> {
);
let spent_on_pubdata_before = vm.state.local_state.spent_pubdata_counter;

let mut tx: Transaction = l2_tx.clone().into();

if let Some(impersonated_account) = inner.impersonated_account {
tracing::info!(
"🕵️ Executing tx from impersonated account {:?}",
impersonated_account
);
tx = adjust_tx_initiator(tx, impersonated_account);
}
let tx: Transaction = l2_tx.clone().into();

push_transaction_to_bootloader_memory(&mut vm, &tx, execution_mode, None);
let tx_result = vm
Expand Down Expand Up @@ -1132,8 +1127,21 @@ impl<S: ForkSource + std::fmt::Debug> InMemoryNode<S> {
}

/// Runs L2 transaction and commits it to a new block.
fn run_l2_tx(&self, l2_tx: L2Tx, execution_mode: TxExecutionMode) -> Result<(), String> {
fn run_l2_tx(&self, mut 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 {
tracing::info!(
"🕵️ Executing tx from impersonated account {:?}",
impersonated_account
);
l2_tx = adjust_tx_initiator(l2_tx, impersonated_account);
}
}
log::info!("");
log::info!("Executing {}", format!("{:?}", tx_hash).bold());
let (keys, result, block, bytecodes) =
Expand Down
24 changes: 7 additions & 17 deletions src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use zksync_basic_types::{H256, U256};
use zksync_state::StorageView;
use zksync_state::WriteStorage;
use zksync_types::{
api::Block, zk_evm::zkevm_opcode_defs::system_params::MAX_TX_ERGS_LIMIT,
api::Block, l2::L2Tx, zk_evm::zkevm_opcode_defs::system_params::MAX_TX_ERGS_LIMIT,
ExecuteTransactionCommon, L1TxCommonData, L2TxCommonData, Transaction, MAX_TXS_IN_BLOCK,
};
use zksync_utils::{ceil_div_u256, u256_to_h256};
Expand Down Expand Up @@ -248,23 +248,13 @@ pub fn mine_empty_blocks<S: std::fmt::Debug + ForkSource>(
}

/// Adjusts the transaction initiator address.
pub fn adjust_tx_initiator(tx: Transaction, initiator: Address) -> Transaction {
match tx.common_data {
ExecuteTransactionCommon::L1(data) => Transaction {
common_data: ExecuteTransactionCommon::L1(L1TxCommonData {
sender: initiator,
..data
}),
..tx
pub fn adjust_tx_initiator(tx: L2Tx, initiator: Address) -> L2Tx {
L2Tx {
common_data: L2TxCommonData {
initiator_address: initiator,
..tx.common_data
},
ExecuteTransactionCommon::L2(data) => Transaction {
common_data: ExecuteTransactionCommon::L2(L2TxCommonData {
initiator_address: initiator,
..data
}),
..tx
},
ExecuteTransactionCommon::ProtocolUpgrade(_) => tx,
..tx
}
}

Expand Down

0 comments on commit 4c4ebc1

Please sign in to comment.