Decode eth param/return values and change them to ethbytes type
This commit is contained in:
parent
cb5e6e0cd1
commit
cf255127a4
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -967,7 +967,7 @@ type EthTraceAction struct {
|
|||||||
From string `json:"from"`
|
From string `json:"from"`
|
||||||
To string `json:"to"`
|
To string `json:"to"`
|
||||||
Gas EthUint64 `json:"gas"`
|
Gas EthUint64 `json:"gas"`
|
||||||
Input string `json:"input"`
|
Input EthBytes `json:"input"`
|
||||||
Value EthBigInt `json:"value"`
|
Value EthBigInt `json:"value"`
|
||||||
|
|
||||||
Method abi.MethodNum `json:"-"`
|
Method abi.MethodNum `json:"-"`
|
||||||
@ -976,5 +976,5 @@ type EthTraceAction struct {
|
|||||||
|
|
||||||
type EthTraceResult struct {
|
type EthTraceResult struct {
|
||||||
GasUsed EthUint64 `json:"gasUsed"`
|
GasUsed EthUint64 `json:"gasUsed"`
|
||||||
Output string `json:"output"`
|
Output EthBytes `json:"output"`
|
||||||
}
|
}
|
||||||
|
@ -3109,12 +3109,12 @@ Response:
|
|||||||
"from": "string value",
|
"from": "string value",
|
||||||
"to": "string value",
|
"to": "string value",
|
||||||
"gas": "0x5",
|
"gas": "0x5",
|
||||||
"input": "string value",
|
"input": "0x07",
|
||||||
"value": "0x0"
|
"value": "0x0"
|
||||||
},
|
},
|
||||||
"result": {
|
"result": {
|
||||||
"gasUsed": "0x5",
|
"gasUsed": "0x5",
|
||||||
"output": "string value"
|
"output": "0x07"
|
||||||
},
|
},
|
||||||
"subtraces": 123,
|
"subtraces": 123,
|
||||||
"traceAddress": [
|
"traceAddress": [
|
||||||
@ -3158,12 +3158,12 @@ Response:
|
|||||||
"from": "string value",
|
"from": "string value",
|
||||||
"to": "string value",
|
"to": "string value",
|
||||||
"gas": "0x5",
|
"gas": "0x5",
|
||||||
"input": "string value",
|
"input": "0x07",
|
||||||
"value": "0x0"
|
"value": "0x0"
|
||||||
},
|
},
|
||||||
"result": {
|
"result": {
|
||||||
"gasUsed": "0x5",
|
"gasUsed": "0x5",
|
||||||
"output": "string value"
|
"output": "0x07"
|
||||||
},
|
},
|
||||||
"subtraces": 123,
|
"subtraces": 123,
|
||||||
"traceAddress": [
|
"traceAddress": [
|
||||||
|
@ -4,29 +4,59 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"encoding/hex"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
|
"github.com/multiformats/go-multicodec"
|
||||||
|
cbg "github.com/whyrusleeping/cbor-gen"
|
||||||
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
"github.com/filecoin-project/go-state-types/builtin"
|
"github.com/filecoin-project/go-state-types/builtin"
|
||||||
"github.com/filecoin-project/go-state-types/exitcode"
|
"github.com/filecoin-project/go-state-types/exitcode"
|
||||||
"golang.org/x/xerrors"
|
|
||||||
|
|
||||||
builtinactors "github.com/filecoin-project/lotus/chain/actors/builtin"
|
builtinactors "github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
"github.com/filecoin-project/lotus/chain/types/ethtypes"
|
"github.com/filecoin-project/lotus/chain/types/ethtypes"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func decodePayload(payload []byte, codec uint64) (ethtypes.EthBytes, error) {
|
||||||
|
if len(payload) == 0 {
|
||||||
|
return ethtypes.EthBytes(nil), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
switch multicodec.Code(codec) {
|
||||||
|
case multicodec.Identity:
|
||||||
|
return ethtypes.EthBytes(nil), nil
|
||||||
|
case multicodec.DagCbor, multicodec.Cbor:
|
||||||
|
buf, err := cbg.ReadByteArray(bytes.NewReader(payload), uint64(len(payload)))
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("decodePayload: failed to decode cbor payload: %w", err)
|
||||||
|
}
|
||||||
|
return buf, nil
|
||||||
|
case multicodec.Raw:
|
||||||
|
return ethtypes.EthBytes(payload), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, xerrors.Errorf("decodePayload: unsupported codec: %d", codec)
|
||||||
|
}
|
||||||
|
|
||||||
// buildTraces recursively builds the traces for a given ExecutionTrace by walking the subcalls
|
// buildTraces recursively builds the traces for a given ExecutionTrace by walking the subcalls
|
||||||
func buildTraces(ctx context.Context, traces *[]*ethtypes.EthTrace, parent *ethtypes.EthTrace, addr []int, et types.ExecutionTrace, height int64, sa StateAPI) error {
|
func buildTraces(ctx context.Context, traces *[]*ethtypes.EthTrace, parent *ethtypes.EthTrace, addr []int, et types.ExecutionTrace, height int64, sa StateAPI) error {
|
||||||
|
// lookup the eth address from the from/to addresses. Note that this may fail but to support
|
||||||
|
// this we need to include the ActorID in the trace. For now, just log a warning and skip
|
||||||
|
// this trace.
|
||||||
|
//
|
||||||
|
// TODO: Add ActorID in trace, see https://github.com/filecoin-project/lotus/pull/11100#discussion_r1302442288
|
||||||
from, err := lookupEthAddress(ctx, et.Msg.From, sa)
|
from, err := lookupEthAddress(ctx, et.Msg.From, sa)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return xerrors.Errorf("buildTraces: failed to lookup from address %s: %w", et.Msg.From, err)
|
log.Warnf("buildTraces: failed to lookup from address %s: %v", et.Msg.From, err)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
to, err := lookupEthAddress(ctx, et.Msg.To, sa)
|
to, err := lookupEthAddress(ctx, et.Msg.To, sa)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return xerrors.Errorf("buildTraces: failed to lookup to address %s: %w", et.Msg.To, err)
|
log.Warnf("buildTraces: failed to lookup to address %s: %w", et.Msg.To, err)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
trace := ðtypes.EthTrace{
|
trace := ðtypes.EthTrace{
|
||||||
@ -34,14 +64,14 @@ func buildTraces(ctx context.Context, traces *[]*ethtypes.EthTrace, parent *etht
|
|||||||
From: from.String(),
|
From: from.String(),
|
||||||
To: to.String(),
|
To: to.String(),
|
||||||
Gas: ethtypes.EthUint64(et.Msg.GasLimit),
|
Gas: ethtypes.EthUint64(et.Msg.GasLimit),
|
||||||
Input: hex.EncodeToString(et.Msg.Params),
|
Input: nil,
|
||||||
Value: ethtypes.EthBigInt(et.Msg.Value),
|
Value: ethtypes.EthBigInt(et.Msg.Value),
|
||||||
Method: et.Msg.Method,
|
Method: et.Msg.Method,
|
||||||
CodeCid: et.Msg.CodeCid,
|
CodeCid: et.Msg.CodeCid,
|
||||||
},
|
},
|
||||||
Result: ethtypes.EthTraceResult{
|
Result: ethtypes.EthTraceResult{
|
||||||
GasUsed: ethtypes.EthUint64(et.SumGas().TotalGas),
|
GasUsed: ethtypes.EthUint64(et.SumGas().TotalGas),
|
||||||
Output: hex.EncodeToString(et.MsgRct.Return),
|
Output: nil,
|
||||||
},
|
},
|
||||||
Subtraces: len(et.Subcalls),
|
Subtraces: len(et.Subcalls),
|
||||||
TraceAddress: addr,
|
TraceAddress: addr,
|
||||||
@ -51,6 +81,48 @@ func buildTraces(ctx context.Context, traces *[]*ethtypes.EthTrace, parent *etht
|
|||||||
|
|
||||||
trace.SetCallType("call")
|
trace.SetCallType("call")
|
||||||
|
|
||||||
|
if parent != nil && builtinactors.IsEvmActor(parent.Action.CodeCid) && et.Msg.Method == builtin.MethodsEVM.InvokeContract {
|
||||||
|
log.Debugf("found InvokeContract call at height: %d", height)
|
||||||
|
trace.Action.Input, err = decodePayload(et.Msg.Params, et.Msg.ParamsCodec)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("buildTraces: %w", err)
|
||||||
|
}
|
||||||
|
trace.Result.Output, err = decodePayload(et.MsgRct.Return, et.MsgRct.ReturnCodec)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("buildTraces: %w", err)
|
||||||
|
}
|
||||||
|
} else if et.Msg.To == builtin.EthereumAddressManagerActorAddr &&
|
||||||
|
et.Msg.Method == builtin.MethodsEAM.CreateExternal {
|
||||||
|
log.Debugf("found CreateExternal call at height: %d", height)
|
||||||
|
trace.Action.Input, err = decodePayload(et.Msg.Params, et.Msg.ParamsCodec)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("buildTraces: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if et.MsgRct.ExitCode.IsSuccess() {
|
||||||
|
// ignore return value
|
||||||
|
trace.Result.Output = nil
|
||||||
|
} else {
|
||||||
|
// return value is the error message
|
||||||
|
trace.Result.Output, err = decodePayload(et.MsgRct.Return, et.MsgRct.ReturnCodec)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("buildTraces: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// treat this as a contract creation
|
||||||
|
trace.SetCallType("create")
|
||||||
|
} else {
|
||||||
|
trace.Action.Input, err = handleFilecoinMethodInput(et.Msg.Method, et.Msg.ParamsCodec, et.Msg.Params)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("buildTraces: %w", err)
|
||||||
|
}
|
||||||
|
trace.Result.Output, err = handleFilecoinMethodOutput(et.MsgRct.ExitCode, et.MsgRct.ReturnCodec, et.MsgRct.Return)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("buildTraces: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: is it OK to check this here or is this only specific to certain edge case (evm to evm)?
|
// TODO: is it OK to check this here or is this only specific to certain edge case (evm to evm)?
|
||||||
if et.Msg.ReadOnly {
|
if et.Msg.ReadOnly {
|
||||||
trace.SetCallType("staticcall")
|
trace.SetCallType("staticcall")
|
||||||
@ -58,27 +130,6 @@ func buildTraces(ctx context.Context, traces *[]*ethtypes.EthTrace, parent *etht
|
|||||||
|
|
||||||
// there are several edge cases thar require special handling when displaying the traces
|
// there are several edge cases thar require special handling when displaying the traces
|
||||||
if parent != nil {
|
if parent != nil {
|
||||||
// Handle Native calls
|
|
||||||
//
|
|
||||||
// When an EVM actor is invoked with a method number above 1023 that's not frc42(InvokeEVM)
|
|
||||||
// then we need to format native calls in a way that makes sense to Ethereum tooling (convert
|
|
||||||
// the input & output to solidity ABI format).
|
|
||||||
if builtinactors.IsEvmActor(parent.Action.CodeCid) &&
|
|
||||||
et.Msg.Method > 1023 &&
|
|
||||||
et.Msg.Method != builtin.MethodsEVM.InvokeContract {
|
|
||||||
log.Debugf("found Native call! method:%d, code:%s, height:%d", et.Msg.Method, et.Msg.CodeCid.String(), height)
|
|
||||||
input, err := handleFilecoinMethodInput(et.Msg.Method, et.Msg.ParamsCodec, et.Msg.Params)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
trace.Action.Input = hex.EncodeToString(input)
|
|
||||||
output, err := handleFilecoinMethodOutput(et.MsgRct.ExitCode, et.MsgRct.ReturnCodec, et.MsgRct.Return)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
trace.Result.Output = hex.EncodeToString(output)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle Native actor creation
|
// Handle Native actor creation
|
||||||
//
|
//
|
||||||
// Actor A calls to the init actor on method 2 and The init actor creates the target actor B then calls it on method 1
|
// Actor A calls to the init actor on method 2 and The init actor creates the target actor B then calls it on method 1
|
||||||
@ -88,8 +139,8 @@ func buildTraces(ctx context.Context, traces *[]*ethtypes.EthTrace, parent *etht
|
|||||||
log.Debugf("Native actor creation! method:%d, code:%s, height:%d", et.Msg.Method, et.Msg.CodeCid.String(), height)
|
log.Debugf("Native actor creation! method:%d, code:%s, height:%d", et.Msg.Method, et.Msg.CodeCid.String(), height)
|
||||||
parent.SetCallType("create")
|
parent.SetCallType("create")
|
||||||
parent.Action.To = et.Msg.To.String()
|
parent.Action.To = et.Msg.To.String()
|
||||||
parent.Action.Input = hex.EncodeToString([]byte{0x0, 0x0, 0x0, 0xFE})
|
parent.Action.Input = []byte{0x0, 0x0, 0x0, 0xFE}
|
||||||
parent.Result.Output = ""
|
parent.Result.Output = nil
|
||||||
|
|
||||||
// there should never be any subcalls when creating a native actor
|
// there should never be any subcalls when creating a native actor
|
||||||
return nil
|
return nil
|
||||||
@ -151,12 +202,12 @@ func buildTraces(ctx context.Context, traces *[]*ethtypes.EthTrace, parent *etht
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
trace.Action.Input = hex.EncodeToString(input)
|
trace.Action.Input = input
|
||||||
output, err := handleFilecoinMethodOutput(et.MsgRct.ExitCode, et.MsgRct.ReturnCodec, et.MsgRct.Return)
|
output, err := handleFilecoinMethodOutput(et.MsgRct.ExitCode, et.MsgRct.ReturnCodec, et.MsgRct.Return)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
trace.Result.Output = hex.EncodeToString(output)
|
trace.Result.Output = output
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle delegate calls
|
// Handle delegate calls
|
||||||
|
Loading…
Reference in New Issue
Block a user