Skip to content

Commit

Permalink
fix(js): incorrect caller and contract address extracting (#244)
Browse files Browse the repository at this point in the history
fixes paradigmxyz/reth#13089

btw, this PR also fixes the incorrect caller address in delegatecall.

---------

Signed-off-by: jsvisa <[email protected]>
  • Loading branch information
jsvisa authored Dec 4, 2024
1 parent 57f6b03 commit 550b2cc
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 15 deletions.
24 changes: 11 additions & 13 deletions src/tracing/js/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -356,15 +356,15 @@ impl JsInspector {
/// Pushes a new call to the stack
fn push_call(
&mut self,
address: Address,
data: Bytes,
contract: Address,
input: Bytes,
value: U256,
kind: CallKind,
caller: Address,
gas_limit: u64,
) -> &CallStackItem {
let call = CallStackItem {
contract: Contract { caller, contract: address, value, input: data },
contract: Contract { caller, contract, value, input },
kind,
gas_limit,
};
Expand Down Expand Up @@ -453,21 +453,19 @@ where
) -> Option<CallOutcome> {
self.register_precompiles(&context.precompiles);

// determine correct `from` and `to` based on the call scheme
let (from, to) = match inputs.scheme {
CallScheme::DelegateCall | CallScheme::CallCode => {
(inputs.target_address, inputs.bytecode_address)
}
_ => (inputs.caller, inputs.bytecode_address),
// determine contract address based on the call scheme
let contract = match inputs.scheme {
CallScheme::DelegateCall | CallScheme::CallCode => inputs.target_address,
_ => inputs.bytecode_address,
};

let value = inputs.transfer_value().unwrap_or_default();
self.push_call(
to,
contract,
inputs.input.clone(),
value,
inputs.scheme.into(),
from,
inputs.caller,
inputs.gas_limit,
);

Expand Down Expand Up @@ -520,9 +518,9 @@ where

let _ = context.load_account(inputs.caller);
let nonce = context.journaled_state.account(inputs.caller).info.nonce;
let address = inputs.created_address(nonce);
let contract = inputs.created_address(nonce);
self.push_call(
address,
contract,
inputs.init_code.clone(),
inputs.value,
inputs.scheme.into(),
Expand Down
79 changes: 77 additions & 2 deletions tests/it/geth_js.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
//! Geth Js tracer tests
use crate::utils::{deploy_contract, inspect};
use alloy_primitives::{hex, Address};
use crate::utils::{deploy_contract, inspect, TestEvm};
use alloy_primitives::{address, hex, Address};
use revm::primitives::{SpecId, TransactTo, TxEnv};
use revm_inspectors::tracing::js::JsInspector;
use serde_json::json;

#[test]
fn test_geth_jstracer_revert() {
Expand Down Expand Up @@ -70,3 +71,77 @@ fn test_geth_jstracer_revert() {
// reverted operation
assert!(result["error"].as_bool().unwrap());
}

// Fix issue https://github.com/paradigmxyz/reth/issues/13089
#[test]
fn test_geth_jstracer_proxy_contract() {
/*
contract Token {
event Transfer(address indexed from, address indexed to, uint256 value);
function transfer(address to, uint256 amount) public payable {
emit Transfer(msg.sender, to, amount);
}
}
contract Proxy {
function transfer(address _contract, address _to, uint256 _amount) external payable {
(bool success, bytes memory data) =
_contract.delegatecall(abi.encodeWithSignature("transfer(address,uint256)", _to, _amount));
require(success, "failed to delegatecall");
}
}
*/

let token_code = hex!("6080604052348015600e575f80fd5b5060dd80601a5f395ff3fe608060405260043610601b575f3560e01c8063a9059cbb14601f575b5f80fd5b602e602a3660046074565b6030565b005b6040518181526001600160a01b0383169033907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a35050565b5f80604083850312156084575f80fd5b82356001600160a01b03811681146099575f80fd5b94602093909301359350505056fea2646970667358221220d81408f997c5f148e7d6afc66ccc7cda17a38396925363f11993fa885b70729b64736f6c63430008190033");

let proxy_code = hex!("6080604052348015600e575f80fd5b506101998061001c5f395ff3fe60806040526004361061001d575f3560e01c80631a69523014610021575b5f80fd5b61003461002f366004610120565b610036565b005b6040516104006024820152606560448201525f9081906001600160a01b0384169060640160408051601f198184030181529181526020820180516001600160e01b031663a9059cbb60e01b1790525161008f919061014d565b5f60405180830381855af49150503d805f81146100c7576040519150601f19603f3d011682016040523d82523d5f602084013e6100cc565b606091505b50915091508161011b5760405162461bcd60e51b815260206004820152601660248201527519985a5b1959081d1bc819195b1959d85d1958d85b1b60521b604482015260640160405180910390fd5b505050565b5f60208284031215610130575f80fd5b81356001600160a01b0381168114610146575f80fd5b9392505050565b5f82518060208501845e5f92019182525091905056fea2646970667358221220d7855999519e998c7bcef0432918ca2f5b00228a4058ba259260e327013226f764736f6c63430008190033");

let deployer = address!("f077b491b355e64048ce21e3a6fc4751eeea77fa");

let mut evm = TestEvm::new();

// Deploy Implementation(Token) contract
let token_addr = evm.simple_deploy(token_code.into());

// Deploy Proxy contract
let proxy_addr = evm.simple_deploy(proxy_code.into());

// Set input data for ProxyFactory.transfer(address)
let mut input_data = hex!("1a695230").to_vec(); // keccak256("transfer(address)")[:4]
input_data.extend_from_slice(&[0u8; 12]); // Pad with zeros
input_data.extend_from_slice(token_addr.as_slice());
println!("token {:?} proxy: {:?}", token_addr, proxy_addr);

let code = r#"
{
data: [],
fault: function(log) {},
step: function(log) {
if (log.op.toString().match(/LOG/)) {
const topic1 = log.stack.peek(2).toString(16);
const caller = toHex(log.contract.getCaller());
const token = toHex(log.contract.getAddress());
if (topic1 === "ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef") {
this.data.push({ event: "Transfer", token, caller })
}
}
},
result: function() { return this.data; }
}"#;
let mut insp = JsInspector::new(code.to_string(), serde_json::Value::Null).unwrap();
let env = evm.env_with_tx(TxEnv {
caller: deployer,
gas_limit: 1000000,
transact_to: TransactTo::Call(proxy_addr),
data: input_data.into(),
..Default::default()
});

let (res, _) = inspect(&mut evm.db, env.clone(), &mut insp).unwrap();
assert!(res.result.is_success());

let result = insp.json_result(res, &env, &evm.db).unwrap();
assert_eq!(result, json!([{"event": "Transfer", "token": proxy_addr, "caller": deployer}]));
}

0 comments on commit 550b2cc

Please sign in to comment.