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

fix(js): incorrect caller and contract address extracting #244

Merged
merged 5 commits into from
Dec 4, 2024
Merged
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
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}]));
}
Loading