|
| 1 | +use super::run::fetch_contracts_bytecode_from_trace; |
1 | 2 | use crate::{ |
2 | 3 | Cast, |
3 | 4 | traces::TraceKind, |
4 | 5 | tx::{CastTxBuilder, SenderKind}, |
5 | 6 | }; |
6 | 7 | use alloy_ens::NameOrAddress; |
7 | | -use alloy_primitives::{Address, Bytes, TxKind, U256}; |
| 8 | +use alloy_primitives::{Address, B256, Bytes, TxKind, U256, map::HashMap}; |
8 | 9 | use alloy_provider::Provider; |
9 | 10 | use alloy_rpc_types::{ |
10 | 11 | BlockId, BlockNumberOrTag, BlockOverrides, |
@@ -35,8 +36,6 @@ use regex::Regex; |
35 | 36 | use revm::context::TransactionType; |
36 | 37 | use std::{str::FromStr, sync::LazyLock}; |
37 | 38 |
|
38 | | -use super::run::fetch_contracts_bytecode_from_trace; |
39 | | - |
40 | 39 | // matches override pattern <address>:<slot>:<value> |
41 | 40 | // e.g. 0x123:0x1:0x1234 |
42 | 41 | static OVERRIDE_PATTERN: LazyLock<Regex> = |
@@ -133,29 +132,29 @@ pub struct CallArgs { |
133 | 132 | #[arg(long, visible_alias = "la")] |
134 | 133 | pub with_local_artifacts: bool, |
135 | 134 |
|
136 | | - /// Override the balance of an account. |
137 | | - /// Format: address:balance |
138 | | - #[arg(long = "override-balance", value_name = "ADDRESS:BALANCE")] |
| 135 | + /// Override the accounts balance. |
| 136 | + /// Format: "address:balance,address:balance" |
| 137 | + #[arg(long = "override-balance", value_name = "ADDRESS:BALANCE", value_delimiter = ',')] |
139 | 138 | pub balance_overrides: Option<Vec<String>>, |
140 | 139 |
|
141 | | - /// Override the nonce of an account. |
142 | | - /// Format: address:nonce |
143 | | - #[arg(long = "override-nonce", value_name = "ADDRESS:NONCE")] |
| 140 | + /// Override the accounts nonce. |
| 141 | + /// Format: "address:nonce,address:nonce" |
| 142 | + #[arg(long = "override-nonce", value_name = "ADDRESS:NONCE", value_delimiter = ',')] |
144 | 143 | pub nonce_overrides: Option<Vec<String>>, |
145 | 144 |
|
146 | | - /// Override the code of an account. |
147 | | - /// Format: address:code |
148 | | - #[arg(long = "override-code", value_name = "ADDRESS:CODE")] |
| 145 | + /// Override the accounts code. |
| 146 | + /// Format: "address:code,address:code" |
| 147 | + #[arg(long = "override-code", value_name = "ADDRESS:CODE", value_delimiter = ',')] |
149 | 148 | pub code_overrides: Option<Vec<String>>, |
150 | 149 |
|
151 | | - /// Override the state of an account. |
152 | | - /// Format: address:slot:value |
153 | | - #[arg(long = "override-state", value_name = "ADDRESS:SLOT:VALUE")] |
| 150 | + /// Override the accounts state and replace the current state entirely with the new one. |
| 151 | + /// Format: "address:slot:value,address:slot:value" |
| 152 | + #[arg(long = "override-state", value_name = "ADDRESS:SLOT:VALUE", value_delimiter = ',')] |
154 | 153 | pub state_overrides: Option<Vec<String>>, |
155 | 154 |
|
156 | | - /// Override the state diff of an account. |
157 | | - /// Format: address:slot:value |
158 | | - #[arg(long = "override-state-diff", value_name = "ADDRESS:SLOT:VALUE")] |
| 155 | + /// Override the accounts state specific slots and preserve the rest of the state. |
| 156 | + /// Format: "address:slot:value,address:slot:value" |
| 157 | + #[arg(long = "override-state-diff", value_name = "ADDRESS:SLOT:VALUE", value_delimiter = ',')] |
159 | 158 | pub state_diff_overrides: Option<Vec<String>>, |
160 | 159 |
|
161 | 160 | /// Override the block timestamp. |
@@ -402,18 +401,29 @@ impl CallArgs { |
402 | 401 | state_overrides_builder.with_code(addr.parse()?, Bytes::from_str(code_str)?); |
403 | 402 | } |
404 | 403 |
|
405 | | - // Parse state overrides |
406 | | - for override_str in self.state_overrides.iter().flatten() { |
407 | | - let (addr, slot, value) = address_slot_value_override(override_str)?; |
408 | | - state_overrides_builder = |
409 | | - state_overrides_builder.with_state(addr, [(slot.into(), value.into())]); |
| 404 | + type StateOverrides = HashMap<Address, HashMap<B256, B256>>; |
| 405 | + let parse_state_overrides = |
| 406 | + |overrides: &Option<Vec<String>>| -> Result<StateOverrides, eyre::Report> { |
| 407 | + let mut state_overrides: StateOverrides = StateOverrides::default(); |
| 408 | + |
| 409 | + overrides.iter().flatten().try_for_each(|s| -> Result<(), eyre::Report> { |
| 410 | + let (addr, slot, value) = address_slot_value_override(s)?; |
| 411 | + state_overrides.entry(addr).or_default().insert(slot.into(), value.into()); |
| 412 | + Ok(()) |
| 413 | + })?; |
| 414 | + |
| 415 | + Ok(state_overrides) |
| 416 | + }; |
| 417 | + |
| 418 | + // Parse and apply state overrides |
| 419 | + for (addr, entries) in parse_state_overrides(&self.state_overrides)? { |
| 420 | + state_overrides_builder = state_overrides_builder.with_state(addr, entries.into_iter()); |
410 | 421 | } |
411 | 422 |
|
412 | | - // Parse state diff overrides |
413 | | - for override_str in self.state_diff_overrides.iter().flatten() { |
414 | | - let (addr, slot, value) = address_slot_value_override(override_str)?; |
| 423 | + // Parse and apply state diff overrides |
| 424 | + for (addr, entries) in parse_state_overrides(&self.state_diff_overrides)? { |
415 | 425 | state_overrides_builder = |
416 | | - state_overrides_builder.with_state_diff(addr, [(slot.into(), value.into())]); |
| 426 | + state_overrides_builder.with_state_diff(addr, entries.into_iter()) |
417 | 427 | } |
418 | 428 |
|
419 | 429 | Ok(Some(state_overrides_builder.build())) |
|
0 commit comments