Skip to content

Commit

Permalink
[WIP] Improve the correctness of Eth's trace_block
Browse files Browse the repository at this point in the history
- Improve encoding/decoding of parameters and return values:
  - Encode "native" parameters and return values with Solidity ABI.
  - Correctly decode parameters to "create" calls.
  - Use the correct (ish) output for "create" calls.
  - Handle all forms of "create".
- Make robust with respect to reverts:
  - Use the actor ID/address from the trace instead of looking it up in
    the state-tree (may not exist in the state-tree due to a revert).
  - Gracefully handle failed actor/contract creation.
- Improve performance:
  - We avoid looking anything up in the state-tree when translating the
    trace, which should significantly improve performance.
- Improve code readability:
  - Remove all "backtracking" logic.
  - Use an "environment" struct to store temporary state instead of
    attaching it to the trace.
- Fix random bugs:
  - Fix an allocation bug in the "address" logic (need to set the
    capacity before modifying the slice).
  - Improved error checking/handling.
  • Loading branch information
Stebalien committed Feb 3, 2024
1 parent 1fc79fc commit 0ac3e77
Show file tree
Hide file tree
Showing 4 changed files with 447 additions and 227 deletions.
38 changes: 16 additions & 22 deletions chain/types/ethtypes/eth_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -349,17 +349,21 @@ func IsEthAddress(addr address.Address) bool {
return namespace == builtintypes.EthereumAddressManagerActorID && len(payload) == 20 && !bytes.HasPrefix(payload, maskedIDPrefix[:])
}

func EthAddressFromActorID(id abi.ActorID) EthAddress {
var ethaddr EthAddress
ethaddr[0] = 0xff
binary.BigEndian.PutUint64(ethaddr[12:], uint64(id))
return ethaddr
}

func EthAddressFromFilecoinAddress(addr address.Address) (EthAddress, error) {
switch addr.Protocol() {
case address.ID:
id, err := address.IDFromAddress(addr)
if err != nil {
return EthAddress{}, err
}
var ethaddr EthAddress
ethaddr[0] = 0xff
binary.BigEndian.PutUint64(ethaddr[12:], id)
return ethaddr, nil
return EthAddressFromActorID(abi.ActorID(id)), nil
case address.Delegated:
payload := addr.Payload()
namespace, n, err := varint.FromUvarint(payload)
Expand Down Expand Up @@ -987,13 +991,8 @@ type EthTrace struct {
Result EthTraceResult `json:"result"`
Subtraces int `json:"subtraces"`
TraceAddress []int `json:"traceAddress"`
Type string `json:"Type"`

Parent *EthTrace `json:"-"`

// if a subtrace makes a call to GetBytecode, we store a pointer to that subtrace here
// which we then lookup when checking for delegatecall (InvokeContractDelegate)
LastByteCode *EthTrace `json:"-"`
Type string `json:"type"`
Error string `json:"error,omitempty"`
}

func (t *EthTrace) SetCallType(callType string) {
Expand All @@ -1018,17 +1017,12 @@ type EthTraceReplayBlockTransaction struct {
}

type EthTraceAction struct {
CallType string `json:"callType"`
From EthAddress `json:"from"`
To EthAddress `json:"to"`
Gas EthUint64 `json:"gas"`
Input EthBytes `json:"input"`
Value EthBigInt `json:"value"`

FilecoinMethod abi.MethodNum `json:"-"`
FilecoinCodeCid cid.Cid `json:"-"`
FilecoinFrom address.Address `json:"-"`
FilecoinTo address.Address `json:"-"`
CallType string `json:"callType"`
From EthAddress `json:"from"`
To *EthAddress `json:"to"`
Gas EthUint64 `json:"gas"`
Input EthBytes `json:"input"`
Value EthBigInt `json:"value"`
}

type EthTraceResult struct {
Expand Down
56 changes: 26 additions & 30 deletions node/impl/full/eth.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import (
"github.com/filecoin-project/go-jsonrpc"
"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/go-state-types/big"
"github.com/filecoin-project/go-state-types/builtin"
builtintypes "github.com/filecoin-project/go-state-types/builtin"
"github.com/filecoin-project/go-state-types/builtin/v10/evm"
"github.com/filecoin-project/go-state-types/exitcode"
Expand Down Expand Up @@ -875,28 +874,28 @@ func (a *EthModule) EthTraceBlock(ctx context.Context, blkNum string) ([]*ethtyp
return nil, xerrors.Errorf("failed to get transaction hash by cid: %w", err)
}
if txHash == nil {
log.Warnf("cannot find transaction hash for cid %s", ir.MsgCid)
continue
return nil, xerrors.Errorf("cannot find transaction hash for cid %s", ir.MsgCid)
}

env, err := baseEnvironment(st, ir.Msg.From)
if err != nil {
return nil, xerrors.Errorf("when processing message %s: %w", err)
}

traces := []*ethtypes.EthTrace{}
err = buildTraces(&traces, nil, []int{}, ir.ExecutionTrace, int64(ts.Height()), st)
err = buildTraces(env, nil, &ir.ExecutionTrace)
if err != nil {
return nil, xerrors.Errorf("failed building traces: %w", err)
}

traceBlocks := make([]*ethtypes.EthTraceBlock, 0, len(traces))
for _, trace := range traces {
traceBlocks = append(traceBlocks, &ethtypes.EthTraceBlock{
for _, trace := range env.traces {
allTraces = append(allTraces, &ethtypes.EthTraceBlock{
EthTrace: trace,
BlockHash: blkHash,
BlockNumber: int64(ts.Height()),
TransactionHash: *txHash,
TransactionPosition: msgIdx,
})
}

allTraces = append(allTraces, traceBlocks...)
}

return allTraces, nil
Expand Down Expand Up @@ -934,34 +933,31 @@ func (a *EthModule) EthTraceReplayBlockTransactions(ctx context.Context, blkNum
return nil, xerrors.Errorf("failed to get transaction hash by cid: %w", err)
}
if txHash == nil {
log.Warnf("cannot find transaction hash for cid %s", ir.MsgCid)
continue
}

var output ethtypes.EthBytes
invokeCreateOnEAM := ir.Msg.To == builtin.EthereumAddressManagerActorAddr && (ir.Msg.Method == builtin.MethodsEAM.Create || ir.Msg.Method == builtin.MethodsEAM.Create2)
if ir.Msg.Method == builtin.MethodsEVM.InvokeContract || invokeCreateOnEAM {
output, err = decodePayload(ir.ExecutionTrace.MsgRct.Return, ir.ExecutionTrace.MsgRct.ReturnCodec)
if err != nil {
return nil, xerrors.Errorf("failed to decode payload: %w", err)
}
} else {
output = encodeFilecoinReturnAsABI(ir.ExecutionTrace.MsgRct.ExitCode, ir.ExecutionTrace.MsgRct.ReturnCodec, ir.ExecutionTrace.MsgRct.Return)
return nil, xerrors.Errorf("cannot find transaction hash for cid %s", ir.MsgCid)
}

t := ethtypes.EthTraceReplayBlockTransaction{
Output: output,
TransactionHash: *txHash,
StateDiff: nil,
VmTrace: nil,
env, err := baseEnvironment(st, ir.Msg.From)
if err != nil {
return nil, xerrors.Errorf("when processing message %s: %w", err)
}

err = buildTraces(&t.Trace, nil, []int{}, ir.ExecutionTrace, int64(ts.Height()), st)
err = buildTraces(env, nil, &ir.ExecutionTrace)
if err != nil {
return nil, xerrors.Errorf("failed building traces: %w", err)
}

allTraces = append(allTraces, &t)
var output []byte
if len(env.traces) > 0 {
output = env.traces[0].Result.Output
}

allTraces = append(allTraces, &ethtypes.EthTraceReplayBlockTransaction{
Output: output,
TransactionHash: *txHash,
Trace: env.traces,
StateDiff: nil,
VmTrace: nil,
})
}

return allTraces, nil
Expand Down
Loading

0 comments on commit 0ac3e77

Please sign in to comment.