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/delegate call trace #2115

Merged
merged 10 commits into from
May 25, 2023
12 changes: 6 additions & 6 deletions jsonrpc/endpoints_debug.go
Original file line number Diff line number Diff line change
Expand Up @@ -216,27 +216,27 @@ func (d *DebugEndpoints) buildStructLogs(stateStructLogs []instrumentation.Struc
RefundCounter: structLog.RefundCounter,
}

stack := make([]types.ArgBig, 0, len(structLog.Stack))
if !cfg.DisableStack && len(structLog.Stack) > 0 {
if !cfg.DisableStack {
stack := make([]types.ArgBig, 0, len(structLog.Stack))
for _, stackItem := range structLog.Stack {
if stackItem != nil {
stack = append(stack, types.ArgBig(*stackItem))
}
}
structLogRes.Stack = &stack
}
structLogRes.Stack = &stack

const memoryChunkSize = 32
memory := make([]string, 0, len(structLog.Memory))
if cfg.EnableMemory {
const memoryChunkSize = 32
memory := make([]string, 0, len(structLog.Memory))
for i := 0; i < len(structLog.Memory); i = i + memoryChunkSize {
slice32Bytes := make([]byte, memoryChunkSize)
copy(slice32Bytes, structLog.Memory[i:i+memoryChunkSize])
memoryStringItem := hex.EncodeToString(slice32Bytes)
memory = append(memory, memoryStringItem)
}
structLogRes.Memory = &memory
}
structLogRes.Memory = &memory

if !cfg.DisableStorage && len(structLog.Storage) > 0 {
storage := make(map[string]string, len(structLog.Storage))
Expand Down
31 changes: 22 additions & 9 deletions state/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -452,7 +452,12 @@ func (s *State) ParseTheTraceUsingTheTracer(evm *fakevm.FakeEVM, trace instrumen
}

tracer.CaptureTxStart(contextGas.Uint64())
tracer.CaptureStart(evm, common.HexToAddress(trace.Context.From), common.HexToAddress(trace.Context.To), trace.Context.Type == "CREATE", common.Hex2Bytes(strings.TrimLeft(trace.Context.Input, "0x")), contextGas.Uint64(), value)
decodedInput, err := hex.DecodeHex(trace.Context.Input)
if err != nil {
log.Errorf("error while decoding context input from hex to bytes:, %v", err)
return nil, ErrParsingExecutorTrace
}
tracer.CaptureStart(evm, common.HexToAddress(trace.Context.From), common.HexToAddress(trace.Context.To), trace.Context.Type == "CREATE", decodedInput, contextGas.Uint64(), value)

bigStateRoot, ok := new(big.Int).SetString(trace.Context.OldStateRoot, 0)
if !ok {
Expand Down Expand Up @@ -538,15 +543,23 @@ func (s *State) ParseTheTraceUsingTheTracer(evm *fakevm.FakeEVM, trace instrumen
}
}

if step.OpCode == "CALL" || step.OpCode == "CALLCODE" || step.OpCode == "DELEGATECALL" || step.OpCode == "STATICCALL" || step.OpCode == "SELFDESTRUCT" {
tracer.CaptureEnter(fakevm.OpCode(op.Uint64()), common.HexToAddress(step.Contract.Caller), common.HexToAddress(step.Contract.Address), []byte(step.Contract.Input), gas.Uint64(), value)
if step.OpCode == "SELFDESTRUCT" {
tracer.CaptureExit(step.ReturnData, gasCost.Uint64(), stepError)
previousOpCodeCanBeSubCall := previousOpcode == "CREATE" ||
previousOpcode == "CREATE2" ||
previousOpcode == "DELEGATECALL" ||
previousOpcode == "CALL" ||
previousOpcode == "STATICCALL" ||
// deprecated ones
previousOpcode == "CALLCODE" ||
previousOpcode == "SELFDESTRUCT"

// when a sub call or create is detected, the next step contains the contract updated
if previousOpCodeCanBeSubCall {
// shadowing "value" to override its value without compromising the external code
value := value
// value is not carried over when the capture enter handles STATIC CALL
if previousOpcode == "STATICCALL" {
value = nil
}
}

// when a create2 is detected, the next step contains the contract updated
if previousOpcode == "CREATE" || previousOpcode == "CREATE2" {
tracer.CaptureEnter(fakevm.OpCode(previousOp.Uint64()), common.HexToAddress(step.Contract.Caller), common.HexToAddress(step.Contract.Address), []byte(step.Contract.Input), previousGas.Uint64(), value)
}

Expand Down
18 changes: 18 additions & 0 deletions test/contracts/auto/Called.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;

contract Called {
uint256 num;
address sender;
uint256 value;

function setVars(uint256 _num) public payable {
num = _num;
sender = msg.sender;
value = msg.value;
}

function getVars() public view returns (uint256, address, uint256) {
return (num, sender, value);
}
}
41 changes: 41 additions & 0 deletions test/contracts/auto/Caller.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;

contract Caller {
function call(address _contract, uint _num) public payable {
bool ok;
(ok, ) = _contract.call(
abi.encodeWithSignature("setVars(uint256)", _num)
);
require(ok, "failed to perform call");
}

function delegateCall(address _contract, uint _num) public payable {
bool ok;
(ok, ) = _contract.delegatecall(
abi.encodeWithSignature("setVars(uint256)", _num)
);
require(ok, "failed to perform delegate call");
}

function staticCall(address _contract) public payable {
bool ok;
bytes memory result;
(ok, result) = _contract.staticcall(
abi.encodeWithSignature("getVars()")
);
require(ok, "failed to perform static call");

uint256 num;
address sender;
uint256 value;

(num, sender, value) = abi.decode(result, (uint256, address, uint256));
}

function multiCall(address _contract, uint _num) public payable {
call(_contract, _num);
delegateCall(_contract, _num);
staticCall(_contract);
}
}
26 changes: 26 additions & 0 deletions test/contracts/auto/ChainCallLevel1.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;

contract ChainCallLevel1 {
function exec(address level2Addr, address level3Addr, address level4Addr) public payable {
bool ok;
(ok, ) = level2Addr.call(
abi.encodeWithSignature("exec(address,address)", level3Addr, level4Addr)
);
require(ok, "failed to perform call to level 2");

(ok, ) = level2Addr.delegatecall(
abi.encodeWithSignature("exec(address,address)", level3Addr, level4Addr)
);
require(ok, "failed to perform delegate call to level 2");

bytes memory result;
(ok, result) = level2Addr.staticcall(
abi.encodeWithSignature("get(address,address)", level3Addr, level4Addr)
);
require(ok, "failed to perform static call to level 2");

string memory t;
(t) = abi.decode(result, (string));
}
}
27 changes: 27 additions & 0 deletions test/contracts/auto/ChainCallLevel2.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;

contract ChainCallLevel2 {
function exec(address level3Addr, address level4Addr) public payable {
bool ok;
(ok, ) = level3Addr.call(abi.encodeWithSignature("exec(address)", level4Addr));
require(ok, "failed to perform call to level 3");

(ok, ) = level3Addr.delegatecall(abi.encodeWithSignature("exec(address)", level4Addr));
require(ok, "failed to perform delegate call to level 3");
}

function get(address level3Addr, address level4Addr) public view returns (string memory t) {
bool ok;
bytes memory result;
(ok, result) = level3Addr.staticcall(abi.encodeWithSignature("get(address)", level4Addr));
require(ok, "failed to perform static call to level 3");

t = abi.decode(result, (string));

(ok, result) = level4Addr.staticcall(abi.encodeWithSignature("get()"));
require(ok, "failed to perform static call to level 4 from level 2");

t = abi.decode(result, (string));
}
}
23 changes: 23 additions & 0 deletions test/contracts/auto/ChainCallLevel3.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;

contract ChainCallLevel3 {
function exec(address level4Addr) public payable {
bool ok;
(ok, ) = level4Addr.call(abi.encodeWithSignature("exec()"));
require(ok, "failed to perform call to level 4");

(ok, ) = level4Addr.delegatecall(abi.encodeWithSignature("exec()"));
require(ok, "failed to perform delegate call to level 4");
}

function get(address level4Addr) public view returns (string memory t) {
bool ok;
bytes memory result;

(ok, result) = level4Addr.staticcall(abi.encodeWithSignature("get()"));
require(ok, "failed to perform static call to level 4");

t = abi.decode(result, (string));
}
}
16 changes: 16 additions & 0 deletions test/contracts/auto/ChainCallLevel4.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;

contract ChainCallLevel4 {
address sender;
uint256 value;

function exec() public payable {
sender = msg.sender;
value = msg.value;
}

function get() public pure returns (string memory t) {
return "ahoy";
}
}
26 changes: 0 additions & 26 deletions test/contracts/auto/DelegatecallReceiver.sol

This file was deleted.

23 changes: 0 additions & 23 deletions test/contracts/auto/DelegatecallSender.sol

This file was deleted.

Loading