Skip to content

Commit

Permalink
feat: CheatcodesExecutor + vm.deployCode (#8181)
Browse files Browse the repository at this point in the history
* wip

* wip

* wip

* clean up

* fix vm.transact traces

* clean up

* clippy

* cargo cheats

* review fixes

* clippy

* tests

* clippy

* cargo cheats

* const -> static

* fmt

* clippy

* fix doc

* chore: fmt

* fix: doc

* fix: doc

* increase depth for failing test

* review fixes

* reduce diff

* rename

* call_with_executor

* chore: keep dbext methods with auto_impl attribute

---------

Co-authored-by: DaniPopes <[email protected]>
  • Loading branch information
klkvr and DaniPopes authored Jun 26, 2024
1 parent fbd2251 commit c8db1e4
Show file tree
Hide file tree
Showing 26 changed files with 788 additions and 254 deletions.
40 changes: 40 additions & 0 deletions crates/cheatcodes/assets/cheatcodes.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions crates/cheatcodes/spec/src/vm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1474,6 +1474,18 @@ interface Vm {
#[cheatcode(group = Filesystem)]
function getCode(string calldata artifactPath) external view returns (bytes memory creationBytecode);

/// Deploys a contract from an artifact file. Takes in the relative path to the json file or the path to the
/// artifact in the form of <path>:<contract>:<version> where <contract> and <version> parts are optional.
#[cheatcode(group = Filesystem)]
function deployCode(string calldata artifactPath) external returns (address deployedAddress);

/// Deploys a contract from an artifact file. Takes in the relative path to the json file or the path to the
/// artifact in the form of <path>:<contract>:<version> where <contract> and <version> parts are optional.
///
/// Additionaly accepts abi-encoded constructor arguments.
#[cheatcode(group = Filesystem)]
function deployCode(string calldata artifactPath, bytes calldata constructorArgs) external returns (address deployedAddress);

/// Gets the deployed bytecode from an artifact file. Takes in the relative path to the json file or the path to the
/// artifact in the form of <path>:<contract>:<version> where <contract> and <version> parts are optional.
#[cheatcode(group = Filesystem)]
Expand Down
72 changes: 36 additions & 36 deletions crates/cheatcodes/src/evm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,14 +67,14 @@ impl Cheatcode for addrCall {
}

impl Cheatcode for getNonce_0Call {
fn apply_full<DB: DatabaseExt>(&self, ccx: &mut CheatsCtxt<DB>) -> Result {
fn apply_stateful<DB: DatabaseExt>(&self, ccx: &mut CheatsCtxt<DB>) -> Result {
let Self { account } = self;
get_nonce(ccx, account)
}
}

impl Cheatcode for loadCall {
fn apply_full<DB: DatabaseExt>(&self, ccx: &mut CheatsCtxt<DB>) -> Result {
fn apply_stateful<DB: DatabaseExt>(&self, ccx: &mut CheatsCtxt<DB>) -> Result {
let Self { target, slot } = *self;
ensure_not_precompile!(&target, ccx);
ccx.ecx.load_account(target)?;
Expand All @@ -84,7 +84,7 @@ impl Cheatcode for loadCall {
}

impl Cheatcode for loadAllocsCall {
fn apply_full<DB: DatabaseExt>(&self, ccx: &mut CheatsCtxt<DB>) -> Result {
fn apply_stateful<DB: DatabaseExt>(&self, ccx: &mut CheatsCtxt<DB>) -> Result {
let Self { pathToAllocsJson } = self;

let path = Path::new(pathToAllocsJson);
Expand All @@ -110,7 +110,7 @@ impl Cheatcode for loadAllocsCall {
}

impl Cheatcode for dumpStateCall {
fn apply_full<DB: DatabaseExt>(&self, ccx: &mut CheatsCtxt<DB>) -> Result {
fn apply_stateful<DB: DatabaseExt>(&self, ccx: &mut CheatsCtxt<DB>) -> Result {
let Self { pathToStateJson } = self;
let path = Path::new(pathToStateJson);

Expand Down Expand Up @@ -156,28 +156,28 @@ impl Cheatcode for dumpStateCall {
}

impl Cheatcode for sign_0Call {
fn apply_full<DB: DatabaseExt>(&self, _: &mut CheatsCtxt<DB>) -> Result {
fn apply_stateful<DB: DatabaseExt>(&self, _: &mut CheatsCtxt<DB>) -> Result {
let Self { privateKey, digest } = self;
super::utils::sign(privateKey, digest)
}
}

impl Cheatcode for sign_1Call {
fn apply_full<DB: DatabaseExt>(&self, ccx: &mut CheatsCtxt<DB>) -> Result {
fn apply_stateful<DB: DatabaseExt>(&self, ccx: &mut CheatsCtxt<DB>) -> Result {
let Self { digest } = self;
super::utils::sign_with_wallet(ccx, None, digest)
}
}

impl Cheatcode for sign_2Call {
fn apply_full<DB: DatabaseExt>(&self, ccx: &mut CheatsCtxt<DB>) -> Result {
fn apply_stateful<DB: DatabaseExt>(&self, ccx: &mut CheatsCtxt<DB>) -> Result {
let Self { signer, digest } = self;
super::utils::sign_with_wallet(ccx, Some(*signer), digest)
}
}

impl Cheatcode for signP256Call {
fn apply_full<DB: DatabaseExt>(&self, ccx: &mut CheatsCtxt<DB>) -> Result {
fn apply_stateful<DB: DatabaseExt>(&self, ccx: &mut CheatsCtxt<DB>) -> Result {
let Self { privateKey, digest } = self;
super::utils::sign_p256(privateKey, digest, ccx.state)
}
Expand Down Expand Up @@ -255,7 +255,7 @@ impl Cheatcode for lastCallGasCall {
}

impl Cheatcode for chainIdCall {
fn apply_full<DB: DatabaseExt>(&self, ccx: &mut CheatsCtxt<DB>) -> Result {
fn apply_stateful<DB: DatabaseExt>(&self, ccx: &mut CheatsCtxt<DB>) -> Result {
let Self { newChainId } = self;
ensure!(*newChainId <= U256::from(u64::MAX), "chain ID must be less than 2^64 - 1");
ccx.ecx.env.cfg.chain_id = newChainId.to();
Expand All @@ -264,15 +264,15 @@ impl Cheatcode for chainIdCall {
}

impl Cheatcode for coinbaseCall {
fn apply_full<DB: DatabaseExt>(&self, ccx: &mut CheatsCtxt<DB>) -> Result {
fn apply_stateful<DB: DatabaseExt>(&self, ccx: &mut CheatsCtxt<DB>) -> Result {
let Self { newCoinbase } = self;
ccx.ecx.env.block.coinbase = *newCoinbase;
Ok(Default::default())
}
}

impl Cheatcode for difficultyCall {
fn apply_full<DB: DatabaseExt>(&self, ccx: &mut CheatsCtxt<DB>) -> Result {
fn apply_stateful<DB: DatabaseExt>(&self, ccx: &mut CheatsCtxt<DB>) -> Result {
let Self { newDifficulty } = self;
ensure!(
ccx.ecx.spec_id() < SpecId::MERGE,
Expand All @@ -285,15 +285,15 @@ impl Cheatcode for difficultyCall {
}

impl Cheatcode for feeCall {
fn apply_full<DB: DatabaseExt>(&self, ccx: &mut CheatsCtxt<DB>) -> Result {
fn apply_stateful<DB: DatabaseExt>(&self, ccx: &mut CheatsCtxt<DB>) -> Result {
let Self { newBasefee } = self;
ccx.ecx.env.block.basefee = *newBasefee;
Ok(Default::default())
}
}

impl Cheatcode for prevrandao_0Call {
fn apply_full<DB: DatabaseExt>(&self, ccx: &mut CheatsCtxt<DB>) -> Result {
fn apply_stateful<DB: DatabaseExt>(&self, ccx: &mut CheatsCtxt<DB>) -> Result {
let Self { newPrevrandao } = self;
ensure!(
ccx.ecx.spec_id() >= SpecId::MERGE,
Expand All @@ -306,7 +306,7 @@ impl Cheatcode for prevrandao_0Call {
}

impl Cheatcode for prevrandao_1Call {
fn apply_full<DB: DatabaseExt>(&self, ccx: &mut CheatsCtxt<DB>) -> Result {
fn apply_stateful<DB: DatabaseExt>(&self, ccx: &mut CheatsCtxt<DB>) -> Result {
let Self { newPrevrandao } = self;
ensure!(
ccx.ecx.spec_id() >= SpecId::MERGE,
Expand All @@ -319,7 +319,7 @@ impl Cheatcode for prevrandao_1Call {
}

impl Cheatcode for blobhashesCall {
fn apply_full<DB: DatabaseExt>(&self, ccx: &mut CheatsCtxt<DB>) -> Result {
fn apply_stateful<DB: DatabaseExt>(&self, ccx: &mut CheatsCtxt<DB>) -> Result {
let Self { hashes } = self;
ensure!(
ccx.ecx.spec_id() >= SpecId::CANCUN,
Expand All @@ -332,7 +332,7 @@ impl Cheatcode for blobhashesCall {
}

impl Cheatcode for getBlobhashesCall {
fn apply_full<DB: DatabaseExt>(&self, ccx: &mut CheatsCtxt<DB>) -> Result {
fn apply_stateful<DB: DatabaseExt>(&self, ccx: &mut CheatsCtxt<DB>) -> Result {
let Self {} = self;
ensure!(
ccx.ecx.spec_id() >= SpecId::CANCUN,
Expand All @@ -344,45 +344,45 @@ impl Cheatcode for getBlobhashesCall {
}

impl Cheatcode for rollCall {
fn apply_full<DB: DatabaseExt>(&self, ccx: &mut CheatsCtxt<DB>) -> Result {
fn apply_stateful<DB: DatabaseExt>(&self, ccx: &mut CheatsCtxt<DB>) -> Result {
let Self { newHeight } = self;
ccx.ecx.env.block.number = *newHeight;
Ok(Default::default())
}
}

impl Cheatcode for getBlockNumberCall {
fn apply_full<DB: DatabaseExt>(&self, ccx: &mut CheatsCtxt<DB>) -> Result {
fn apply_stateful<DB: DatabaseExt>(&self, ccx: &mut CheatsCtxt<DB>) -> Result {
let Self {} = self;
Ok(ccx.ecx.env.block.number.abi_encode())
}
}

impl Cheatcode for txGasPriceCall {
fn apply_full<DB: DatabaseExt>(&self, ccx: &mut CheatsCtxt<DB>) -> Result {
fn apply_stateful<DB: DatabaseExt>(&self, ccx: &mut CheatsCtxt<DB>) -> Result {
let Self { newGasPrice } = self;
ccx.ecx.env.tx.gas_price = *newGasPrice;
Ok(Default::default())
}
}

impl Cheatcode for warpCall {
fn apply_full<DB: DatabaseExt>(&self, ccx: &mut CheatsCtxt<DB>) -> Result {
fn apply_stateful<DB: DatabaseExt>(&self, ccx: &mut CheatsCtxt<DB>) -> Result {
let Self { newTimestamp } = self;
ccx.ecx.env.block.timestamp = *newTimestamp;
Ok(Default::default())
}
}

impl Cheatcode for getBlockTimestampCall {
fn apply_full<DB: DatabaseExt>(&self, ccx: &mut CheatsCtxt<DB>) -> Result {
fn apply_stateful<DB: DatabaseExt>(&self, ccx: &mut CheatsCtxt<DB>) -> Result {
let Self {} = self;
Ok(ccx.ecx.env.block.timestamp.abi_encode())
}
}

impl Cheatcode for blobBaseFeeCall {
fn apply_full<DB: DatabaseExt>(&self, ccx: &mut CheatsCtxt<DB>) -> Result {
fn apply_stateful<DB: DatabaseExt>(&self, ccx: &mut CheatsCtxt<DB>) -> Result {
let Self { newBlobBaseFee } = self;
ensure!(
ccx.ecx.spec_id() >= SpecId::CANCUN,
Expand All @@ -395,14 +395,14 @@ impl Cheatcode for blobBaseFeeCall {
}

impl Cheatcode for getBlobBaseFeeCall {
fn apply_full<DB: DatabaseExt>(&self, ccx: &mut CheatsCtxt<DB>) -> Result {
fn apply_stateful<DB: DatabaseExt>(&self, ccx: &mut CheatsCtxt<DB>) -> Result {
let Self {} = self;
Ok(ccx.ecx.env.block.get_blob_excess_gas().unwrap_or(0).abi_encode())
}
}

impl Cheatcode for dealCall {
fn apply_full<DB: DatabaseExt>(&self, ccx: &mut CheatsCtxt<DB>) -> Result {
fn apply_stateful<DB: DatabaseExt>(&self, ccx: &mut CheatsCtxt<DB>) -> Result {
let Self { account: address, newBalance: new_balance } = *self;
let account = journaled_account(ccx.ecx, address)?;
let old_balance = std::mem::replace(&mut account.info.balance, new_balance);
Expand All @@ -413,7 +413,7 @@ impl Cheatcode for dealCall {
}

impl Cheatcode for etchCall {
fn apply_full<DB: DatabaseExt>(&self, ccx: &mut CheatsCtxt<DB>) -> Result {
fn apply_stateful<DB: DatabaseExt>(&self, ccx: &mut CheatsCtxt<DB>) -> Result {
let Self { target, newRuntimeBytecode } = self;
ensure_not_precompile!(target, ccx);
ccx.ecx.load_account(*target)?;
Expand All @@ -424,7 +424,7 @@ impl Cheatcode for etchCall {
}

impl Cheatcode for resetNonceCall {
fn apply_full<DB: DatabaseExt>(&self, ccx: &mut CheatsCtxt<DB>) -> Result {
fn apply_stateful<DB: DatabaseExt>(&self, ccx: &mut CheatsCtxt<DB>) -> Result {
let Self { account } = self;
let account = journaled_account(ccx.ecx, *account)?;
// Per EIP-161, EOA nonces start at 0, but contract nonces
Expand All @@ -439,7 +439,7 @@ impl Cheatcode for resetNonceCall {
}

impl Cheatcode for setNonceCall {
fn apply_full<DB: DatabaseExt>(&self, ccx: &mut CheatsCtxt<DB>) -> Result {
fn apply_stateful<DB: DatabaseExt>(&self, ccx: &mut CheatsCtxt<DB>) -> Result {
let Self { account, newNonce } = *self;
let account = journaled_account(ccx.ecx, account)?;
// nonce must increment only
Expand All @@ -455,7 +455,7 @@ impl Cheatcode for setNonceCall {
}

impl Cheatcode for setNonceUnsafeCall {
fn apply_full<DB: DatabaseExt>(&self, ccx: &mut CheatsCtxt<DB>) -> Result {
fn apply_stateful<DB: DatabaseExt>(&self, ccx: &mut CheatsCtxt<DB>) -> Result {
let Self { account, newNonce } = *self;
let account = journaled_account(ccx.ecx, account)?;
account.info.nonce = newNonce;
Expand All @@ -464,7 +464,7 @@ impl Cheatcode for setNonceUnsafeCall {
}

impl Cheatcode for storeCall {
fn apply_full<DB: DatabaseExt>(&self, ccx: &mut CheatsCtxt<DB>) -> Result {
fn apply_stateful<DB: DatabaseExt>(&self, ccx: &mut CheatsCtxt<DB>) -> Result {
let Self { target, slot, value } = *self;
ensure_not_precompile!(&target, ccx);
// ensure the account is touched
Expand All @@ -475,7 +475,7 @@ impl Cheatcode for storeCall {
}

impl Cheatcode for coolCall {
fn apply_full<DB: DatabaseExt>(&self, ccx: &mut CheatsCtxt<DB>) -> Result {
fn apply_stateful<DB: DatabaseExt>(&self, ccx: &mut CheatsCtxt<DB>) -> Result {
let Self { target } = self;
if let Some(account) = ccx.ecx.journaled_state.state.get_mut(target) {
account.unmark_touch();
Expand All @@ -486,21 +486,21 @@ impl Cheatcode for coolCall {
}

impl Cheatcode for readCallersCall {
fn apply_full<DB: DatabaseExt>(&self, ccx: &mut CheatsCtxt<DB>) -> Result {
fn apply_stateful<DB: DatabaseExt>(&self, ccx: &mut CheatsCtxt<DB>) -> Result {
let Self {} = self;
read_callers(ccx.state, &ccx.ecx.env.tx.caller)
}
}

impl Cheatcode for snapshotCall {
fn apply_full<DB: DatabaseExt>(&self, ccx: &mut CheatsCtxt<DB>) -> Result {
fn apply_stateful<DB: DatabaseExt>(&self, ccx: &mut CheatsCtxt<DB>) -> Result {
let Self {} = self;
Ok(ccx.ecx.db.snapshot(&ccx.ecx.journaled_state, &ccx.ecx.env).abi_encode())
}
}

impl Cheatcode for revertToCall {
fn apply_full<DB: DatabaseExt>(&self, ccx: &mut CheatsCtxt<DB>) -> Result {
fn apply_stateful<DB: DatabaseExt>(&self, ccx: &mut CheatsCtxt<DB>) -> Result {
let Self { snapshotId } = self;
let result = if let Some(journaled_state) = ccx.ecx.db.revert(
*snapshotId,
Expand All @@ -519,7 +519,7 @@ impl Cheatcode for revertToCall {
}

impl Cheatcode for revertToAndDeleteCall {
fn apply_full<DB: DatabaseExt>(&self, ccx: &mut CheatsCtxt<DB>) -> Result {
fn apply_stateful<DB: DatabaseExt>(&self, ccx: &mut CheatsCtxt<DB>) -> Result {
let Self { snapshotId } = self;
let result = if let Some(journaled_state) = ccx.ecx.db.revert(
*snapshotId,
Expand All @@ -538,14 +538,14 @@ impl Cheatcode for revertToAndDeleteCall {
}

impl Cheatcode for deleteSnapshotCall {
fn apply_full<DB: DatabaseExt>(&self, ccx: &mut CheatsCtxt<DB>) -> Result {
fn apply_stateful<DB: DatabaseExt>(&self, ccx: &mut CheatsCtxt<DB>) -> Result {
let Self { snapshotId } = self;
let result = ccx.ecx.db.delete_snapshot(*snapshotId);
Ok(result.abi_encode())
}
}
impl Cheatcode for deleteSnapshotsCall {
fn apply_full<DB: DatabaseExt>(&self, ccx: &mut CheatsCtxt<DB>) -> Result {
fn apply_stateful<DB: DatabaseExt>(&self, ccx: &mut CheatsCtxt<DB>) -> Result {
let Self {} = self;
ccx.ecx.db.delete_snapshots();
Ok(Default::default())
Expand Down
Loading

0 comments on commit c8db1e4

Please sign in to comment.