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 debug_traceTransaction bugs #3503

Merged
merged 4 commits into from
Sep 17, 2024
Merged
Show file tree
Hide file tree
Changes from 3 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
61 changes: 55 additions & 6 deletions packages/evm/jsonrpc/jsonrpctest/jsonrpc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -586,21 +586,62 @@ func TestRPCTraceTx(t *testing.T) {

require.Equal(t, creatorAddress, trace1.From)
require.Equal(t, contractAddress, *trace1.To)
require.Equal(t, big.NewInt(123), trace1.Value)
require.Equal(t, "0x7b", trace1.Value)
expectedInput, err := contractABI.Pack("sendTo", common.Address{0x1}, big.NewInt(1))
require.NoError(t, err)
require.Equal(t, expectedInput, trace1.Input)
require.Empty(t, trace1.Error)
require.Empty(t, trace1.RevertReason)
require.Equal(t, "0x0", trace1.Gas)
require.Equal(t, "0x0", trace1.GasUsed)

require.Len(t, trace1.Calls, 1)
trace2 := trace1.Calls[0]
require.Equal(t, contractAddress, trace2.From)
require.Equal(t, common.Address{0x1}, *trace2.To)
require.Equal(t, big.NewInt(1), trace2.Value)
require.Equal(t, "0x1", trace2.Value)
require.Empty(t, trace2.Input)
require.Empty(t, trace2.Error)
require.Empty(t, trace2.RevertReason)
require.Contains(t, trace2.Gas, "0x")
require.Contains(t, trace2.GasUsed, "0x")
}

func TestRPCTraceEvmDeposit(t *testing.T) {
env := newSoloTestEnv(t)
wallet, _ := env.solo.NewKeyPairWithFunds()
_, evmAddr := env.soloChain.NewEthereumAccountWithL2Funds()

err := env.soloChain.TransferAllowanceTo(
isc.NewAssetsBaseTokens(1000),
isc.NewEthereumAddressAgentID(env.soloChain.ChainID, evmAddr),
wallet)

block := env.BlockByNumber(nil)
require.NoError(t, err)
txs := block.Transactions()
tx := txs[0]

require.Equal(t, evmAddr, *tx.To())

rc, err := env.TxReceipt(txs[0].Hash())
require.NoError(t, err)
require.EqualValues(t, types.ReceiptStatusSuccessful, rc.Status)

var res1 json.RawMessage
err = env.RawClient.CallContext(
context.Background(),
&res1,
"debug_traceTransaction",
tx.Hash().Hex(),
tracers.TraceConfig{TracerConfig: []byte(`{"tracer": "callTracer"}`)},
)
require.NoError(t, err)

var trace1 []jsonrpc.CallFrame
err = json.Unmarshal(res1, &trace1)
require.NoError(t, err)
require.Len(t, trace1, 0)
}

func TestRPCTraceBlock(t *testing.T) {
Expand Down Expand Up @@ -681,39 +722,47 @@ func TestRPCTraceBlock(t *testing.T) {

require.Equal(t, creatorAddress, trace1.From)
require.Equal(t, contractAddress, *trace1.To)
require.Equal(t, big.NewInt(123), trace1.Value)
require.Equal(t, "0x7b", trace1.Value)
expectedInput, err := contractABI.Pack("sendTo", common.Address{0x1}, big.NewInt(2))
require.NoError(t, err)
require.Equal(t, expectedInput, trace1.Input)
require.Empty(t, trace1.Error)
require.Empty(t, trace1.RevertReason)
require.Equal(t, "0x0", trace1.Gas)
require.Equal(t, "0x0", trace1.GasUsed)

require.Len(t, trace1.Calls, 1)
innerCall1 := trace1.Calls[0]
require.Equal(t, contractAddress, innerCall1.From)
require.Equal(t, common.Address{0x1}, *innerCall1.To)
require.Equal(t, big.NewInt(2), innerCall1.Value)
require.Equal(t, "0x2", innerCall1.Value)
require.Empty(t, innerCall1.Input)
require.Empty(t, innerCall1.Error)
require.Empty(t, innerCall1.RevertReason)
require.Contains(t, innerCall1.Gas, "0x")
require.Contains(t, innerCall1.GasUsed, "0x")

require.Equal(t, creatorAddress2, trace2.From)
require.Equal(t, contractAddress, *trace2.To)
require.Equal(t, big.NewInt(321), trace2.Value)
require.Equal(t, "0x141", trace2.Value)
expectedInput, err = contractABI.Pack("sendTo", common.Address{0x2}, big.NewInt(3))
require.NoError(t, err)
require.Equal(t, expectedInput, trace2.Input)
require.Empty(t, trace2.Error)
require.Empty(t, trace2.RevertReason)
require.Equal(t, "0x0", trace2.Gas)
require.Equal(t, "0x0", trace2.GasUsed)

require.Len(t, trace2.Calls, 1)
innerCall2 := trace2.Calls[0]
require.Equal(t, contractAddress, innerCall2.From)
require.Equal(t, common.Address{0x2}, *innerCall2.To)
require.Equal(t, big.NewInt(3), innerCall2.Value)
require.Equal(t, "0x3", innerCall2.Value)
require.Empty(t, innerCall2.Input)
require.Empty(t, innerCall2.Error)
require.Empty(t, innerCall2.RevertReason)
require.Contains(t, innerCall2.Gas, "0x")
require.Contains(t, innerCall2.GasUsed, "0x")
}

func TestRPCBlockReceipt(t *testing.T) {
Expand Down
30 changes: 18 additions & 12 deletions packages/evm/jsonrpc/tracer_call.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"errors"
"fmt"
"math/big"
"strconv"
"sync/atomic"

"github.com/ethereum/go-ethereum/accounts/abi"
Expand Down Expand Up @@ -35,8 +36,8 @@ type callLog struct {
type CallFrame struct {
Type vm.OpCode `json:"-"`
From common.Address `json:"from"`
Gas uint64 `json:"gas"`
GasUsed uint64 `json:"gasUsed"`
Gas string `json:"gas"`
GasUsed string `json:"gasUsed"`
vitaliy-io marked this conversation as resolved.
Show resolved Hide resolved
To *common.Address `json:"to,omitempty" rlp:"optional"`
Input []byte `json:"input" rlp:"optional"`
Output []byte `json:"output,omitempty" rlp:"optional"`
Expand All @@ -46,7 +47,7 @@ type CallFrame struct {
Logs []callLog `json:"logs,omitempty" rlp:"optional"`
// Placed at end on purpose. The RLP will be decoded to 0 instead of
// nil if there are non-empty elements after in the struct.
Value *big.Int `json:"value,omitempty" rlp:"optional"`
Value string `json:"value,omitempty" rlp:"optional"`
vitaliy-io marked this conversation as resolved.
Show resolved Hide resolved
revertedSnapshot bool
}

Expand Down Expand Up @@ -161,19 +162,24 @@ func (t *callTracer) OnEnter(depth int, typ byte, from common.Address, to common

toCopy := to
call := CallFrame{
Type: vm.OpCode(typ),
From: from,
To: &toCopy,
Input: common.CopyBytes(input),
Gas: gas,
Value: value,
Type: vm.OpCode(typ),
From: from,
To: &toCopy,
Input: common.CopyBytes(input),
Gas: intToHex(int64(gas)),
Value: intToHex(value.Int64()),
GasUsed: "0x0",
}
if depth == 0 {
call.Gas = t.gasLimit
call.Gas = intToHex(int64(t.gasLimit))
}
t.callstack = append(t.callstack, call)
}

func intToHex(i int64) string {
return "0x" + strconv.FormatInt(i, 16)
}

// OnExit is called when EVM exits a scope, even if the scope didn't
// execute any code.
func (t *callTracer) OnExit(depth int, output []byte, gasUsed uint64, err error, reverted bool) {
Expand All @@ -196,7 +202,7 @@ func (t *callTracer) OnExit(depth int, output []byte, gasUsed uint64, err error,
t.callstack = t.callstack[:size-1]
size--

call.GasUsed = gasUsed
call.GasUsed = intToHex(int64(gasUsed))
call.processOutput(output, err, reverted)
// Nest call into parent.
t.callstack[size-1].Calls = append(t.callstack[size-1].Calls, call)
Expand All @@ -218,7 +224,7 @@ func (t *callTracer) OnTxEnd(receipt *types.Receipt, err error) {
if err != nil {
return
}
t.callstack[0].GasUsed = receipt.GasUsed
t.callstack[0].GasUsed = intToHex(int64(receipt.GasUsed))
if t.config.WithLog {
// Logs are not emitted when the call fails
clearFailedLogs(&t.callstack[0], false)
Expand Down
Loading