geth debug tracing boilerplate

This commit is contained in:
i-norden 2023-11-12 11:30:10 -06:00
parent 7344dd5eb3
commit 3a1abdab0f
10 changed files with 247 additions and 0 deletions

View File

@ -874,6 +874,11 @@ type FullNode interface {
// Replays all transactions in a block returning the requested traces for each transaction
EthTraceReplayBlockTransactions(ctx context.Context, blkNum string, traceTypes []string) ([]*ethtypes.EthTraceReplayBlockTransaction, error) //perm:read
// go-ethereum "debug" trace endpoints
EthDebugTraceCall(ctx context.Context, args ethtypes.EthTxArgs, blockNrOrHash ethtypes.EthBlockNumberOrHash, config *ethtypes.TraceCallConfig) (interface{}, error)
EthDebugTraceBlockByNumber(ctx context.Context, number string, config *ethtypes.TraceConfig) ([]*ethtypes.TxTraceResult, error)
EthDebugTraceBlockByHash(ctx context.Context, hash ethtypes.EthHash, config *ethtypes.TraceConfig) ([]*ethtypes.TxTraceResult, error)
// CreateBackup creates node backup onder the specified file name. The
// method requires that the lotus daemon is running with the
// LOTUS_BACKUP_BASE_PATH environment variable set to some path, and that

View File

@ -129,4 +129,7 @@ type Gateway interface {
Web3ClientVersion(ctx context.Context) (string, error)
EthTraceBlock(ctx context.Context, blkNum string) ([]*ethtypes.EthTraceBlock, error)
EthTraceReplayBlockTransactions(ctx context.Context, blkNum string, traceTypes []string) ([]*ethtypes.EthTraceReplayBlockTransaction, error)
EthDebugTraceCall(ctx context.Context, args ethtypes.EthTxArgs, blockNrOrHash ethtypes.EthBlockNumberOrHash, config *ethtypes.TraceCallConfig) (interface{}, error)
EthDebugTraceBlockByNumber(ctx context.Context, number string, config *ethtypes.TraceConfig) ([]*ethtypes.TxTraceResult, error)
EthDebugTraceBlockByHash(ctx context.Context, hash ethtypes.EthHash, config *ethtypes.TraceConfig) ([]*ethtypes.TxTraceResult, error)
}

View File

@ -43,6 +43,10 @@ func CreateEthRPCAliases(as apitypes.Aliaser) {
as.AliasMethod("trace_block", "Filecoin.EthTraceBlock")
as.AliasMethod("trace_replayBlockTransactions", "Filecoin.EthTraceReplayBlockTransactions")
as.AliasMethod("debug_traceCall", "Filecoin.EthDebugTraceCall")
as.AliasMethod("debug_traceBlockByHash", "Filecoin.EthDebugTraceBlockByHash")
as.AliasMethod("debug_traceBlockByNumber", "Filecoin.EthDebugTraceBlockByNumber")
as.AliasMethod("net_version", "Filecoin.NetVersion")
as.AliasMethod("net_listening", "Filecoin.NetListening")

View File

@ -1500,12 +1500,57 @@ func (m *MockFullNode) EthTraceBlock(arg0 context.Context, arg1 string) ([]*etht
return ret0, ret1
}
// EthDebugTraceCall mocks base method.
func (m *MockFullNode) EthDebugTraceCall(ctx context.Context, arg0 ethtypes.EthTxArgs, arg1 ethtypes.EthBlockNumberOrHash, arg2 *ethtypes.TraceCallConfig) (interface{}, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "EthDebugTraceCall", arg0, arg1, arg2)
ret0, _ := ret[0].(interface{})
ret1, _ := ret[1].(error)
return ret0, ret1
}
// EthDebugTraceBlockByNumber mocks base method.
func (m *MockFullNode) EthDebugTraceBlockByNumber(ctx context.Context, arg0 string, arg1 *ethtypes.TraceConfig) ([]*ethtypes.TxTraceResult, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "EthDebugTraceBlockByNumber", arg0, arg1)
ret0, _ := ret[0].([]*ethtypes.TxTraceResult)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// EthDebugTraceBlockByHash mocks base method.
func (m *MockFullNode) EthDebugTraceBlockByHash(ctx context.Context, arg0 ethtypes.EthHash, arg1 *ethtypes.TraceConfig) ([]*ethtypes.TxTraceResult, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "EthDebugTraceBlockByHash", arg0, arg1)
ret0, _ := ret[0].([]*ethtypes.TxTraceResult)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// EthTraceBlock indicates an expected call of EthTraceBlock.
func (mr *MockFullNodeMockRecorder) EthTraceBlock(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthTraceBlock", reflect.TypeOf((*MockFullNode)(nil).EthTraceBlock), arg0, arg1)
}
// EthDebugTraceCall indicates an expected of EthDebugTraceCall
func (mr *MockFullNodeMockRecorder) EthDebugTraceCall(arg0, arg1, arg2 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthDebugTraceCall", reflect.TypeOf((*MockFullNode)(nil).EthDebugTraceCall), arg0, arg1, arg2)
}
// EthDebugTraceBlockByHash indicates an expected of EthDebugTraceBlockByHash
func (mr *MockFullNodeMockRecorder) EthDebugTraceBlockByHash(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthDebugTraceBlockByHash", reflect.TypeOf((*MockFullNode)(nil).EthDebugTraceBlockByHash), arg0, arg1)
}
// EthDebugTraceBlockByNumber indicates an expected of EthDebugTraceBlockByHash
func (mr *MockFullNodeMockRecorder) EthDebugTraceBlockByNumber(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthDebugTraceBlockByNumber", reflect.TypeOf((*MockFullNode)(nil).EthDebugTraceBlockByNumber), arg0, arg1)
}
// EthTraceReplayBlockTransactions mocks base method.
func (m *MockFullNode) EthTraceReplayBlockTransactions(arg0 context.Context, arg1 string, arg2 []string) ([]*ethtypes.EthTraceReplayBlockTransaction, error) {
m.ctrl.T.Helper()

View File

@ -102,6 +102,10 @@ func (e EthBigInt) MarshalJSON() ([]byte, error) {
return json.Marshal(e.String())
}
func (e EthBigInt) ToInt() big.Int {
return (big.Int)(e)
}
func (e *EthBigInt) UnmarshalJSON(b []byte) error {
var s string
if err := json.Unmarshal(b, &s); err != nil {

View File

@ -0,0 +1,120 @@
package ethtypes
import (
"encoding/json"
"math/big"
logger "github.com/ipfs/go-log/v2"
)
// TraceConfig holds extra parameters to trace functions.
type TraceConfig struct {
*logger.Config
Tracer *string
Timeout *string
Reexec *uint64
// Config specific to given tracer. Note struct logger
// config are historically embedded in main object.
TracerConfig json.RawMessage
}
// TraceCallConfig is the config for traceCall API. It holds one more
// field to override the state for tracing.
type TraceCallConfig struct {
TraceConfig
StateOverrides *StateOverride
BlockOverrides *BlockOverrides
}
// OverrideAccount indicates the overriding fields of account during the execution
// of a message call.
// Note, state and stateDiff can't be specified at the same time. If state is
// set, message execution will only use the data in the given state. Otherwise
// if statDiff is set, all diff will be applied first and then execute the call
// message.
type OverrideAccount struct {
Nonce *EthUint64 `json:"nonce"`
Code *EthBytes `json:"code"`
Balance **EthBigInt `json:"balance"`
State *map[EthHash]EthHash `json:"state"`
StateDiff *map[EthHash]EthHash `json:"stateDiff"`
}
// StateOverride is the collection of overridden accounts.
type StateOverride map[EthHash]OverrideAccount
// BlockOverrides is a set of header fields to override.
type BlockOverrides struct {
Number *EthBigInt
Difficulty *EthBigInt
Time *EthUint64
GasLimit *EthUint64
Coinbase *EthAddress
Random *EthHash
BaseFee *EthUint64
}
// Apply overrides the given header fields into the given block context.
func (diff *BlockOverrides) Apply(blockCtx *BlockContext) {
if diff == nil {
return
}
if diff.Number != nil {
blockCtx.BlockNumber = diff.Number.Int
}
if diff.Difficulty != nil {
blockCtx.Difficulty = diff.Difficulty.Int
}
if diff.Time != nil {
blockCtx.Time = uint64(*diff.Time)
}
if diff.GasLimit != nil {
blockCtx.GasLimit = uint64(*diff.GasLimit)
}
if diff.Coinbase != nil {
blockCtx.Coinbase = *diff.Coinbase
}
if diff.Random != nil {
blockCtx.Random = diff.Random
}
if diff.BaseFee != nil {
blockCtx.BaseFee = new(big.Int).SetUint64((uint64)(*diff.BaseFee))
}
}
type (
// CanTransferFunc is the signature of a transfer guard function
CanTransferFunc func(StateDB, EthAddress, *big.Int) bool
// TransferFunc is the signature of a transfer function
TransferFunc func(StateDB, EthAddress, EthAddress, *big.Int)
// GetHashFunc returns the n'th block hash in the blockchain
// and is used by the BLOCKHASH EVM op code.
GetHashFunc func(uint64) EthAddress
)
// BlockContext provides the EVM with auxiliary information. Once provided
// it shouldn't be modified.
type BlockContext struct {
// CanTransfer returns whether the account contains
// sufficient ether to transfer the value
CanTransfer CanTransferFunc
// Transfer transfers ether from one account to the other
Transfer TransferFunc
// GetHash returns the hash corresponding to n
GetHash GetHashFunc
// Block information
Coinbase EthAddress // Provides information for COINBASE
GasLimit uint64 // Provides information for GASLIMIT
BlockNumber *big.Int // Provides information for NUMBER
Time uint64 // Provides information for TIME
Difficulty *big.Int // Provides information for DIFFICULTY
BaseFee *big.Int // Provides information for BASEFEE
Random *EthHash // Provides information for PREVRANDAO
}
// TxTraceResult is the result of a single transaction trace.
type TxTraceResult struct {
Result interface{} `json:"result,omitempty"` // Trace results produced by the tracer
Error string `json:"error,omitempty"` // Trace failure produced by the tracer
}

View File

@ -146,6 +146,9 @@ type TargetAPI interface {
Web3ClientVersion(ctx context.Context) (string, error)
EthTraceBlock(ctx context.Context, blkNum string) ([]*ethtypes.EthTraceBlock, error)
EthTraceReplayBlockTransactions(ctx context.Context, blkNum string, traceTypes []string) ([]*ethtypes.EthTraceReplayBlockTransaction, error)
EthDebugTraceCall(ctx context.Context, args ethtypes.EthTxArgs, blockNrOrHash ethtypes.EthBlockNumberOrHash, config *ethtypes.TraceCallConfig) (interface{}, error)
EthDebugTraceBlockByNumber(ctx context.Context, number string, config *ethtypes.TraceConfig) ([]*ethtypes.TxTraceResult, error)
EthDebugTraceBlockByHash(ctx context.Context, hash ethtypes.EthHash, config *ethtypes.TraceConfig) ([]*ethtypes.TxTraceResult, error)
}
var _ TargetAPI = *new(api.FullNode) // gateway depends on latest

View File

@ -606,6 +606,42 @@ func (gw *Node) EthTraceReplayBlockTransactions(ctx context.Context, blkNum stri
return gw.target.EthTraceReplayBlockTransactions(ctx, blkNum, traceTypes)
}
func (gw *Node) EthDebugTraceCall(ctx context.Context, args ethtypes.EthTxArgs, blockNrOrHash ethtypes.EthBlockNumberOrHash, config *ethtypes.TraceCallConfig) (interface{}, error) {
if err := gw.limit(ctx, stateRateLimitTokens); err != nil {
return nil, err
}
if err := gw.checkEthBlockParam(ctx, blockNrOrHash, 0); err != nil {
return nil, err
}
return gw.target.EthDebugTraceCall(ctx, args, blockNrOrHash, config)
}
func (gw *Node) EthDebugTraceBlockByHash(ctx context.Context, hash ethtypes.EthHash, config *ethtypes.TraceConfig) ([]*ethtypes.TxTraceResult, error) {
if err := gw.limit(ctx, stateRateLimitTokens); err != nil {
return nil, err
}
if err := gw.checkBlkHash(ctx, hash); err != nil {
return nil, err
}
return gw.target.EthDebugTraceBlockByHash(ctx, hash, config)
}
func (gw *Node) EthDebugTraceBlockByNumber(ctx context.Context, number string, config *ethtypes.TraceConfig) ([]*ethtypes.TxTraceResult, error) {
if err := gw.limit(ctx, stateRateLimitTokens); err != nil {
return nil, err
}
if err := gw.checkBlkParam(ctx, number, 0); err != nil {
return nil, err
}
return gw.target.EthDebugTraceBlockByNumber(ctx, number, config)
}
var EthMaxFiltersPerConn = 16 // todo make this configurable
func addUserFilterLimited(ctx context.Context, cb func() (ethtypes.EthFilterID, error)) (ethtypes.EthFilterID, error) {

View File

@ -186,5 +186,17 @@ func (e *EthModuleDummy) EthTraceReplayBlockTransactions(ctx context.Context, bl
return nil, ErrModuleDisabled
}
func (e *EthModuleDummy) EthDebugTraceBlockByHash(ctx context.Context, hash ethtypes.EthHash, config *ethtypes.TraceConfig) ([]*ethtypes.TxTraceResult, error) {
return nil, ErrModuleDisabled
}
func (e *EthModuleDummy) EthDebugTraceBlockByNumber(ctx context.Context, number string, config *ethtypes.TraceConfig) ([]*ethtypes.TxTraceResult, error) {
return nil, ErrModuleDisabled
}
func (e *EthModuleDummy) EthDebugTraceCall(ctx context.Context, args ethtypes.EthTxArgs, blockNrOrHash ethtypes.EthBlockNumberOrHash, config *ethtypes.TraceCallConfig) (interface{}, error) {
return nil, ErrModuleDisabled
}
var _ EthModuleAPI = &EthModuleDummy{}
var _ EthEventAPI = &EthModuleDummy{}

View File

@ -73,6 +73,9 @@ type EthModuleAPI interface {
Web3ClientVersion(ctx context.Context) (string, error)
EthTraceBlock(ctx context.Context, blkNum string) ([]*ethtypes.EthTraceBlock, error)
EthTraceReplayBlockTransactions(ctx context.Context, blkNum string, traceTypes []string) ([]*ethtypes.EthTraceReplayBlockTransaction, error)
EthDebugTraceCall(ctx context.Context, args ethtypes.EthTxArgs, blockNrOrHash ethtypes.EthBlockNumberOrHash, config *ethtypes.TraceCallConfig) (interface{}, error)
EthDebugTraceBlockByNumber(ctx context.Context, number string, config *ethtypes.TraceConfig) ([]*ethtypes.TxTraceResult, error)
EthDebugTraceBlockByHash(ctx context.Context, hash ethtypes.EthHash, config *ethtypes.TraceConfig) ([]*ethtypes.TxTraceResult, error)
}
type EthEventAPI interface {
@ -969,6 +972,18 @@ func (a *EthModule) EthTraceReplayBlockTransactions(ctx context.Context, blkNum
return allTraces, nil
}
func (a *EthModule) EthDebugTraceCall(ctx context.Context, args ethtypes.EthTxArgs, blockNrOrHash ethtypes.EthBlockNumberOrHash, config *ethtypes.TraceCallConfig) (interface{}, error) {
panic("implement me")
}
func (a *EthModule) EthDebugTraceBlockByNumber(ctx context.Context, number string, config *ethtypes.TraceConfig) ([]*ethtypes.TxTraceResult, error) {
panic("implement me")
}
func (a *EthModule) EthDebugTraceBlockByHash(ctx context.Context, hash ethtypes.EthHash, config *ethtypes.TraceConfig) ([]*ethtypes.TxTraceResult, error) {
panic("implement me")
}
func (a *EthModule) applyMessage(ctx context.Context, msg *types.Message, tsk types.TipSetKey) (res *api.InvocResult, err error) {
ts, err := a.Chain.GetTipSetFromKey(ctx, tsk)
if err != nil {