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: Add Cheatcodes::AddAccount #980

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
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
13 changes: 13 additions & 0 deletions core/src/environment/instruction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,12 @@ pub enum Cheatcodes {
/// The address of the account to fetch.
address: ethers::types::Address,
},
/// An `AddAccount` is used to add a default/unfunded account.
/// If the account exists, the value is updated.
AddAccount {
/// The address of the account to be added.
address: eAddress,
},
}

/// Wrapper around [`AccountState`] that can be serialized and deserialized.
Expand Down Expand Up @@ -264,4 +270,11 @@ pub enum CheatcodesReturn {
/// Storage slots of the account.
storage: HashMap<U256, U256>,
},

/// A `AddAccount` returns nothing.
AddAccount {
/// Basic account information of inserted account like nonce, balance,
/// code hash, bytcode.
info: AccountInfo,
},
}
27 changes: 27 additions & 0 deletions core/src/environment/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,7 @@ impl Environment {
}
Cheatcodes::Deal { address, amount } => {
let recast_address = Address::from(address.as_fixed_bytes());

match db.state.write()?.accounts.get_mut(&recast_address) {
Some(account) => {
account.info.balance += U256::from_limbs(amount.0);
Expand Down Expand Up @@ -408,6 +409,23 @@ impl Environment {
}
}
}
Cheatcodes::AddAccount { address } => {
let recast_address = Address::from(address.as_fixed_bytes());

let account = revm::db::DbAccount {
info: AccountInfo::default(),
account_state: AccountState::None,
storage: HashMap::new(),
};
db.state
.write()?
.accounts
.insert(recast_address, account.clone());

outcome_sender.send(Ok(Outcome::CheatcodeReturn(
CheatcodesReturn::AddAccount { info: account.info },
)))?;
}
},
// A `Call` is not state changing and will not create events but will create
// console logs.
Expand Down Expand Up @@ -634,6 +652,15 @@ impl Environment {
self
}

/// Obtains the current underlying [`CacheDB`] instance
/// after a read lock was acquired to inspect the current execution state
pub fn db(&self) -> Result<CacheDB<EmptyDB>, ArbiterCoreError> {
match self.db.state.read() {
Ok(cache_db) => Ok(cache_db.clone()),
Err(err) => Err(ArbiterCoreError::RwLockError(err.to_string())),
}
}

/// Stops the execution of the environment and returns the [`ArbiterDB`] in
/// its final state.
pub fn stop(mut self) -> Result<ArbiterDB, ArbiterCoreError> {
Expand Down
9 changes: 8 additions & 1 deletion core/src/middleware/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -426,8 +426,15 @@ impl Middleware for ArbiterMiddleware {
Some(&to) => TransactTo::Call(to.to_fixed_bytes().into()),
None => TransactTo::Create(CreateScheme::Create),
};

// Extract `from` field if it exists
let caller = match tx.from() {
Some(&from) => from.to_fixed_bytes().into(),
None => self.address().to_fixed_bytes().into(),
};

let tx_env = TxEnv {
caller: self.address().to_fixed_bytes().into(),
caller,
gas_limit: u64::MAX,
gas_price: revm::primitives::U256::from_limbs(self.get_gas_price().await?.0),
gas_priority_fee: None,
Expand Down
9 changes: 8 additions & 1 deletion core/tests/environment_integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,13 +142,20 @@ async fn middleware_from_forked_eo() {
}

#[tokio::test]
async fn env_returns_db() {
async fn env_returns_db_after_stop() {
let (environment, client) = startup();
deploy_arbx(client).await;
let db = environment.stop().unwrap();
assert!(!db.state.read().unwrap().accounts.is_empty())
}

#[tokio::test]
async fn env_returns_db_mid_execution() {
let (environment, client) = startup();
deploy_arbx(client).await;
assert!(!environment.db().unwrap().accounts.is_empty())
}

#[tokio::test]
async fn block_logs() {
let (environment, client) = startup();
Expand Down
41 changes: 41 additions & 0 deletions core/tests/middleware_integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,47 @@
assert!(balance.is_err());
}

#[tokio::test]
async fn add_account_cheatcode() {
let (_environment, client) = startup();

// First try to add balance to the non-existent new_address account
// It should faill

Check failure on line 310 in core/tests/middleware_integration.rs

View workflow job for this annotation

GitHub Actions / codespell

faill ==> fail
client
.apply_cheatcode(Cheatcodes::Deal {
address: client.default_sender().unwrap(),
amount: eU256::from(1),
})
.await
.unwrap();
let mut new_address = client.address().0;
new_address[0] = new_address[0].wrapping_add(1);
let new_address = eAddress::from(new_address);
let balance = client.get_balance(new_address, None).await;
assert!(balance.is_err());

// Then add the new_address account
client
.apply_cheatcode(Cheatcodes::AddAccount {
address: new_address,
})
.await
.unwrap();

// And fill it up
let new_balance = eU256::from(32);
client
.apply_cheatcode(Cheatcodes::Deal {
address: new_address,
amount: new_balance,
})
.await
.unwrap();

let balance = client.get_balance(new_address, None).await.unwrap();
assert_eq!(balance, new_balance);
}

#[tokio::test]
async fn set_gas_price() {
let (_environment, client) = startup();
Expand Down
1 change: 1 addition & 0 deletions docs/src/usage/arbiter_core/environment.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ fn main() {
- `Instruction::Cheatcode`: Execute one of the `Cheatcodes` on the `Environment`'s world state.
The `Cheatcodes` include:
- `Cheatcodes::Deal`: Used to set the raw ETH balance of a user. Useful when you need to pay gas fees in a transaction.
- `Cheatcodes::AddAccount`: Initializes a new default account if it doesn't exist.
- `Cheatcodes::Load`: Gets the value of a storage slot of an account.
- `Cheatcodes::Store`: Sets the value of a storage slot of an account.
- `Cheatcodes::Access`: Gets the account at an address.
Expand Down
Loading