Skip to content

Commit cb8364d

Browse files
authored
feat: added fake sig in executor (#11308)
* feat: added fake sig in executor * feat: added fake sig in executor
1 parent 1be6e5d commit cb8364d

File tree

3 files changed

+58
-3
lines changed

3 files changed

+58
-3
lines changed

crates/anvil/src/eth/backend/executor.rs

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@ use crate::{
22
PrecompileFactory,
33
eth::{
44
backend::{
5-
db::Db, env::Env, mem::op_haltreason_to_instruction_result,
5+
cheats::{CheatEcrecover, CheatsManager},
6+
db::Db,
7+
env::Env,
8+
mem::op_haltreason_to_instruction_result,
69
validate::TransactionValidator,
710
},
811
error::InvalidTransactionError,
@@ -15,7 +18,11 @@ use alloy_consensus::{
1518
Receipt, ReceiptWithBloom, constants::EMPTY_WITHDRAWALS, proofs::calculate_receipt_root,
1619
};
1720
use alloy_eips::{eip7685::EMPTY_REQUESTS_HASH, eip7840::BlobParams};
18-
use alloy_evm::{EthEvm, Evm, eth::EthEvmContext, precompiles::PrecompilesMap};
21+
use alloy_evm::{
22+
EthEvm, Evm,
23+
eth::EthEvmContext,
24+
precompiles::{DynPrecompile, Precompile, PrecompilesMap},
25+
};
1926
use alloy_op_evm::OpEvm;
2027
use alloy_primitives::{B256, Bloom, BloomInput, Log};
2128
use anvil_core::eth::{
@@ -28,7 +35,7 @@ use foundry_evm::{
2835
backend::DatabaseError,
2936
traces::{CallTraceDecoder, CallTraceNode},
3037
};
31-
use foundry_evm_core::either_evm::EitherEvm;
38+
use foundry_evm_core::{either_evm::EitherEvm, precompiles::EC_RECOVER};
3239
use op_revm::{L1BlockInfo, OpContext, precompiles::OpPrecompiles};
3340
use revm::{
3441
Database, DatabaseRef, Inspector, Journal,
@@ -127,6 +134,7 @@ pub struct TransactionExecutor<'a, Db: ?Sized, V: TransactionValidator> {
127134
/// Precompiles to inject to the EVM.
128135
pub precompile_factory: Option<Arc<dyn PrecompileFactory>>,
129136
pub blob_params: BlobParams,
137+
pub cheats: CheatsManager,
130138
}
131139

132140
impl<DB: Db + ?Sized, V: TransactionValidator> TransactionExecutor<'_, DB, V> {
@@ -344,6 +352,14 @@ impl<DB: Db + ?Sized, V: TransactionValidator> Iterator for &mut TransactionExec
344352
inject_precompiles(&mut evm, factory.precompiles());
345353
}
346354

355+
let cheats = Arc::new(self.cheats.clone());
356+
if cheats.has_recover_overrides() {
357+
let cheat_ecrecover = CheatEcrecover::new(Arc::clone(&cheats));
358+
evm.precompiles_mut().apply_precompile(&EC_RECOVER, move |_| {
359+
Some(DynPrecompile::new_stateful(move |input| cheat_ecrecover.call(input)))
360+
});
361+
}
362+
347363
trace!(target: "backend", "[{:?}] executing", transaction.hash());
348364
// transact and commit the transaction
349365
match evm.transact_commit(env.tx) {

crates/anvil/src/eth/backend/mem/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1277,6 +1277,7 @@ impl Backend {
12771277
odyssey: self.odyssey,
12781278
optimism: self.is_optimism(),
12791279
blob_params: self.blob_params(),
1280+
cheats: self.cheats().clone(),
12801281
};
12811282

12821283
// create a new pending block
@@ -1364,6 +1365,7 @@ impl Backend {
13641365
precompile_factory: self.precompile_factory.clone(),
13651366
optimism: self.is_optimism(),
13661367
blob_params: self.blob_params(),
1368+
cheats: self.cheats().clone(),
13671369
};
13681370
let executed_tx = executor.execute();
13691371

@@ -2727,6 +2729,7 @@ impl Backend {
27272729
odyssey: self.odyssey,
27282730
optimism: self.is_optimism(),
27292731
blob_params: self.blob_params(),
2732+
cheats: self.cheats().clone(),
27302733
};
27312734

27322735
let _ = executor.execute();

crates/anvil/tests/it/anvil.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use alloy_network::{ReceiptResponse, TransactionBuilder};
77
use alloy_primitives::{Address, B256, hex};
88
use alloy_provider::Provider;
99
use alloy_rpc_types::TransactionRequest;
10+
use alloy_sol_types::SolCall;
1011
use anvil::{NodeConfig, spawn};
1112

1213
#[tokio::test(flavor = "multi_thread")]
@@ -170,3 +171,38 @@ async fn test_anvil_recover_signature() {
170171
let result = contract.testRecover(fake_hash, v, r, s, expected).call().await;
171172
assert!(result.is_ok(), "ecrecover failed: {:?}", result.err());
172173
}
174+
175+
#[tokio::test(flavor = "multi_thread")]
176+
async fn test_fake_signature_transaction() {
177+
let (api, handle) = spawn(NodeConfig::test()).await;
178+
let provider = handle.http_provider();
179+
alloy_sol_types::sol! {
180+
#[sol(rpc)]
181+
contract TestRecover {
182+
function testRecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s, address expected) external pure {
183+
address recovered = ecrecover(hash, v, r, s);
184+
require(recovered == expected, "ecrecover failed: address mismatch");
185+
}
186+
}
187+
}
188+
let bytecode = hex::decode(
189+
"0x60808060405234601557610125908161001a8239f35b5f80fdfe60808060405260043610156011575f80fd5b5f3560e01c63bff0b743146023575f80fd5b3460eb5760a036600319011260eb5760243560ff811680910360eb576084356001600160a01b038116929083900360eb5760805f916020936004358252848201526044356040820152606435606082015282805260015afa1560e0575f516001600160a01b031603609057005b60405162461bcd60e51b815260206004820152602260248201527f65637265636f766572206661696c65643a2061646472657373206d69736d61746044820152610c6d60f31b6064820152608490fd5b6040513d5f823e3d90fd5b5f80fdfea264697066735822122006368b42bca31c97f2c409a1cc5186dc899d4255ecc28db7bbb0ad285dc82ae464736f6c634300081c0033",
190+
).unwrap();
191+
192+
let tx = TransactionRequest::default().with_deploy_code(bytecode);
193+
let _receipt = provider.send_transaction(tx.into()).await.unwrap().get_receipt().await.unwrap();
194+
195+
let sig = alloy_primitives::hex::decode("11".repeat(65)).unwrap();
196+
let r = B256::from_slice(&sig[0..32]);
197+
let s = B256::from_slice(&sig[32..64]);
198+
let v = sig[64];
199+
let fake_hash = B256::random();
200+
let expected = alloy_primitives::address!("0x1234567890123456789012345678901234567890");
201+
api.anvil_impersonate_signature(sig.clone().into(), expected).await.unwrap();
202+
let calldata = TestRecover::testRecoverCall { hash: fake_hash, v, r, s, expected }.abi_encode();
203+
let tx = TransactionRequest::default().with_input(calldata);
204+
let pending = provider.send_transaction(tx.into()).await.unwrap();
205+
let result = pending.get_receipt().await;
206+
207+
assert!(result.is_ok(), "ecrecover failed: {:?}", result.err());
208+
}

0 commit comments

Comments
 (0)