diff --git a/api/api_full.go b/api/api_full.go index 95d86ce6f..ce187feef 100644 --- a/api/api_full.go +++ b/api/api_full.go @@ -871,9 +871,9 @@ type FullNode interface { // TraceAPI related methods // // Returns traces created at given block - TraceBlock(ctx context.Context, blkNum string) (interface{}, error) //perm:read + TraceBlock(ctx context.Context, blkNum string) ([]*ethtypes.TraceBlock, error) //perm:read // Replays all transactions in a block returning the requested traces for each transaction - TraceReplayBlockTransactions(ctx context.Context, blkNum string, traceTypes []string) (interface{}, error) //perm:read + TraceReplayBlockTransactions(ctx context.Context, blkNum string, traceTypes []string) ([]*ethtypes.TraceReplayBlockTransaction, error) //perm:read // CreateBackup creates node backup onder the specified file name. The // method requires that the lotus daemon is running with the diff --git a/api/api_gateway.go b/api/api_gateway.go index 0f2e66709..fef7c2c04 100644 --- a/api/api_gateway.go +++ b/api/api_gateway.go @@ -127,6 +127,6 @@ type Gateway interface { EthSubscribe(ctx context.Context, params jsonrpc.RawParams) (ethtypes.EthSubscriptionID, error) EthUnsubscribe(ctx context.Context, id ethtypes.EthSubscriptionID) (bool, error) Web3ClientVersion(ctx context.Context) (string, error) - TraceBlock(ctx context.Context, blkNum string) (interface{}, error) - TraceReplayBlockTransactions(ctx context.Context, blkNum string, traceTypes []string) (interface{}, error) + TraceBlock(ctx context.Context, blkNum string) ([]*ethtypes.TraceBlock, error) + TraceReplayBlockTransactions(ctx context.Context, blkNum string, traceTypes []string) ([]*ethtypes.TraceReplayBlockTransaction, error) } diff --git a/api/mocks/mock_full.go b/api/mocks/mock_full.go index 882aacebb..24a7cc207 100644 --- a/api/mocks/mock_full.go +++ b/api/mocks/mock_full.go @@ -4024,10 +4024,10 @@ func (mr *MockFullNodeMockRecorder) SyncValidateTipset(arg0, arg1 interface{}) * } // TraceBlock mocks base method. -func (m *MockFullNode) TraceBlock(arg0 context.Context, arg1 string) (interface{}, error) { +func (m *MockFullNode) TraceBlock(arg0 context.Context, arg1 string) ([]*ethtypes.TraceBlock, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "TraceBlock", arg0, arg1) - ret0, _ := ret[0].(interface{}) + ret0, _ := ret[0].([]*ethtypes.TraceBlock) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -4039,10 +4039,10 @@ func (mr *MockFullNodeMockRecorder) TraceBlock(arg0, arg1 interface{}) *gomock.C } // TraceReplayBlockTransactions mocks base method. -func (m *MockFullNode) TraceReplayBlockTransactions(arg0 context.Context, arg1 string, arg2 []string) (interface{}, error) { +func (m *MockFullNode) TraceReplayBlockTransactions(arg0 context.Context, arg1 string, arg2 []string) ([]*ethtypes.TraceReplayBlockTransaction, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "TraceReplayBlockTransactions", arg0, arg1, arg2) - ret0, _ := ret[0].(interface{}) + ret0, _ := ret[0].([]*ethtypes.TraceReplayBlockTransaction) ret1, _ := ret[1].(error) return ret0, ret1 } diff --git a/api/proxy_gen.go b/api/proxy_gen.go index 6f0487b0b..d3f49daf9 100644 --- a/api/proxy_gen.go +++ b/api/proxy_gen.go @@ -596,9 +596,9 @@ type FullNodeMethods struct { SyncValidateTipset func(p0 context.Context, p1 types.TipSetKey) (bool, error) `perm:"read"` - TraceBlock func(p0 context.Context, p1 string) (interface{}, error) `perm:"read"` + TraceBlock func(p0 context.Context, p1 string) ([]*ethtypes.TraceBlock, error) `perm:"read"` - TraceReplayBlockTransactions func(p0 context.Context, p1 string, p2 []string) (interface{}, error) `perm:"read"` + TraceReplayBlockTransactions func(p0 context.Context, p1 string, p2 []string) ([]*ethtypes.TraceReplayBlockTransaction, error) `perm:"read"` WalletBalance func(p0 context.Context, p1 address.Address) (types.BigInt, error) `perm:"read"` @@ -818,9 +818,9 @@ type GatewayMethods struct { StateWaitMsg func(p0 context.Context, p1 cid.Cid, p2 uint64, p3 abi.ChainEpoch, p4 bool) (*MsgLookup, error) `` - TraceBlock func(p0 context.Context, p1 string) (interface{}, error) `` + TraceBlock func(p0 context.Context, p1 string) ([]*ethtypes.TraceBlock, error) `` - TraceReplayBlockTransactions func(p0 context.Context, p1 string, p2 []string) (interface{}, error) `` + TraceReplayBlockTransactions func(p0 context.Context, p1 string, p2 []string) ([]*ethtypes.TraceReplayBlockTransaction, error) `` Version func(p0 context.Context) (APIVersion, error) `` @@ -4005,26 +4005,26 @@ func (s *FullNodeStub) SyncValidateTipset(p0 context.Context, p1 types.TipSetKey return false, ErrNotSupported } -func (s *FullNodeStruct) TraceBlock(p0 context.Context, p1 string) (interface{}, error) { +func (s *FullNodeStruct) TraceBlock(p0 context.Context, p1 string) ([]*ethtypes.TraceBlock, error) { if s.Internal.TraceBlock == nil { - return nil, ErrNotSupported + return *new([]*ethtypes.TraceBlock), ErrNotSupported } return s.Internal.TraceBlock(p0, p1) } -func (s *FullNodeStub) TraceBlock(p0 context.Context, p1 string) (interface{}, error) { - return nil, ErrNotSupported +func (s *FullNodeStub) TraceBlock(p0 context.Context, p1 string) ([]*ethtypes.TraceBlock, error) { + return *new([]*ethtypes.TraceBlock), ErrNotSupported } -func (s *FullNodeStruct) TraceReplayBlockTransactions(p0 context.Context, p1 string, p2 []string) (interface{}, error) { +func (s *FullNodeStruct) TraceReplayBlockTransactions(p0 context.Context, p1 string, p2 []string) ([]*ethtypes.TraceReplayBlockTransaction, error) { if s.Internal.TraceReplayBlockTransactions == nil { - return nil, ErrNotSupported + return *new([]*ethtypes.TraceReplayBlockTransaction), ErrNotSupported } return s.Internal.TraceReplayBlockTransactions(p0, p1, p2) } -func (s *FullNodeStub) TraceReplayBlockTransactions(p0 context.Context, p1 string, p2 []string) (interface{}, error) { - return nil, ErrNotSupported +func (s *FullNodeStub) TraceReplayBlockTransactions(p0 context.Context, p1 string, p2 []string) ([]*ethtypes.TraceReplayBlockTransaction, error) { + return *new([]*ethtypes.TraceReplayBlockTransaction), ErrNotSupported } func (s *FullNodeStruct) WalletBalance(p0 context.Context, p1 address.Address) (types.BigInt, error) { @@ -5160,26 +5160,26 @@ func (s *GatewayStub) StateWaitMsg(p0 context.Context, p1 cid.Cid, p2 uint64, p3 return nil, ErrNotSupported } -func (s *GatewayStruct) TraceBlock(p0 context.Context, p1 string) (interface{}, error) { +func (s *GatewayStruct) TraceBlock(p0 context.Context, p1 string) ([]*ethtypes.TraceBlock, error) { if s.Internal.TraceBlock == nil { - return nil, ErrNotSupported + return *new([]*ethtypes.TraceBlock), ErrNotSupported } return s.Internal.TraceBlock(p0, p1) } -func (s *GatewayStub) TraceBlock(p0 context.Context, p1 string) (interface{}, error) { - return nil, ErrNotSupported +func (s *GatewayStub) TraceBlock(p0 context.Context, p1 string) ([]*ethtypes.TraceBlock, error) { + return *new([]*ethtypes.TraceBlock), ErrNotSupported } -func (s *GatewayStruct) TraceReplayBlockTransactions(p0 context.Context, p1 string, p2 []string) (interface{}, error) { +func (s *GatewayStruct) TraceReplayBlockTransactions(p0 context.Context, p1 string, p2 []string) ([]*ethtypes.TraceReplayBlockTransaction, error) { if s.Internal.TraceReplayBlockTransactions == nil { - return nil, ErrNotSupported + return *new([]*ethtypes.TraceReplayBlockTransaction), ErrNotSupported } return s.Internal.TraceReplayBlockTransactions(p0, p1, p2) } -func (s *GatewayStub) TraceReplayBlockTransactions(p0 context.Context, p1 string, p2 []string) (interface{}, error) { - return nil, ErrNotSupported +func (s *GatewayStub) TraceReplayBlockTransactions(p0 context.Context, p1 string, p2 []string) ([]*ethtypes.TraceReplayBlockTransaction, error) { + return *new([]*ethtypes.TraceReplayBlockTransaction), ErrNotSupported } func (s *GatewayStruct) Version(p0 context.Context) (APIVersion, error) { diff --git a/node/impl/full/eth_trace.go b/chain/types/ethtypes/eth_trace.go similarity index 88% rename from node/impl/full/eth_trace.go rename to chain/types/ethtypes/eth_trace.go index 3e3b48c90..66fb860b6 100644 --- a/node/impl/full/eth_trace.go +++ b/chain/types/ethtypes/eth_trace.go @@ -1,4 +1,4 @@ -package full +package ethtypes import ( "bytes" @@ -8,6 +8,7 @@ import ( "io" "github.com/ipfs/go-cid" + logging "github.com/ipfs/go-log/v2" "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/builtin" @@ -15,9 +16,10 @@ import ( builtinactors "github.com/filecoin-project/lotus/chain/actors/builtin" "github.com/filecoin-project/lotus/chain/types" - "github.com/filecoin-project/lotus/chain/types/ethtypes" ) +var log = logging.Logger("traceapi") + type Trace struct { Action Action `json:"action"` Result Result `json:"result"` @@ -35,51 +37,51 @@ func (t *Trace) setCallType(callType string) { type TraceBlock struct { *Trace - BlockHash ethtypes.EthHash `json:"blockHash"` - BlockNumber int64 `json:"blockNumber"` - TransactionHash ethtypes.EthHash `json:"transactionHash"` - TransactionPosition int `json:"transactionPosition"` + BlockHash EthHash `json:"blockHash"` + BlockNumber int64 `json:"blockNumber"` + TransactionHash EthHash `json:"transactionHash"` + TransactionPosition int `json:"transactionPosition"` } type TraceReplayBlockTransaction struct { - Output string `json:"output"` - StateDiff *string `json:"stateDiff"` - Trace []*Trace `json:"trace"` - TransactionHash ethtypes.EthHash `json:"transactionHash"` - VmTrace *string `json:"vmTrace"` + Output string `json:"output"` + StateDiff *string `json:"stateDiff"` + Trace []*Trace `json:"trace"` + TransactionHash EthHash `json:"transactionHash"` + VmTrace *string `json:"vmTrace"` } type Action struct { - CallType string `json:"callType"` - From string `json:"from"` - To string `json:"to"` - Gas ethtypes.EthUint64 `json:"gas"` - Input string `json:"input"` - Value ethtypes.EthBigInt `json:"value"` + CallType string `json:"callType"` + From string `json:"from"` + To string `json:"to"` + Gas EthUint64 `json:"gas"` + Input string `json:"input"` + Value EthBigInt `json:"value"` method abi.MethodNum `json:"-"` codeCid cid.Cid `json:"-"` } type Result struct { - GasUsed ethtypes.EthUint64 `json:"gasUsed"` - Output string `json:"output"` + GasUsed EthUint64 `json:"gasUsed"` + Output string `json:"output"` } -// buildTraces recursively builds the traces for a given ExecutionTrace by walking the subcalls -func buildTraces(traces *[]*Trace, parent *Trace, addr []int, et types.ExecutionTrace, height int64) error { +// BuildTraces recursively builds the traces for a given ExecutionTrace by walking the subcalls +func BuildTraces(traces *[]*Trace, parent *Trace, addr []int, et types.ExecutionTrace, height int64) error { trace := &Trace{ Action: Action{ From: et.Msg.From.String(), To: et.Msg.To.String(), - Gas: ethtypes.EthUint64(et.Msg.GasLimit), + Gas: EthUint64(et.Msg.GasLimit), Input: hex.EncodeToString(et.Msg.Params), - Value: ethtypes.EthBigInt(et.Msg.Value), + Value: EthBigInt(et.Msg.Value), method: et.Msg.Method, codeCid: et.Msg.CodeCid, }, Result: Result{ - GasUsed: ethtypes.EthUint64(et.SumGas().TotalGas), + GasUsed: EthUint64(et.SumGas().TotalGas), Output: hex.EncodeToString(et.MsgRct.Return), }, Subtraces: len(et.Subcalls), @@ -218,7 +220,7 @@ func buildTraces(traces *[]*Trace, parent *Trace, addr []int, et types.Execution *traces = append(*traces, trace) for i, call := range et.Subcalls { - err := buildTraces(traces, trace, append(addr, i), call, height) + err := BuildTraces(traces, trace, append(addr, i), call, height) if err != nil { return err } diff --git a/documentation/en/api-v1-unstable-methods.md b/documentation/en/api-v1-unstable-methods.md index 273f20dc9..a488ee64b 100644 --- a/documentation/en/api-v1-unstable-methods.md +++ b/documentation/en/api-v1-unstable-methods.md @@ -8841,7 +8841,34 @@ Inputs: ] ``` -Response: `{}` +Response: +```json +[ + { + "action": { + "callType": "string value", + "from": "string value", + "to": "string value", + "gas": "0x5", + "input": "string value", + "value": "0x0" + }, + "result": { + "gasUsed": "0x5", + "output": "string value" + }, + "subtraces": 123, + "traceAddress": [ + 123 + ], + "Type": "string value", + "blockHash": "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e", + "blockNumber": 9, + "transactionHash": "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e", + "transactionPosition": 123 + } +] +``` ### TraceReplayBlockTransactions Replays all transactions in a block returning the requested traces for each transaction @@ -8859,7 +8886,38 @@ Inputs: ] ``` -Response: `{}` +Response: +```json +[ + { + "output": "string value", + "stateDiff": "string value", + "trace": [ + { + "action": { + "callType": "string value", + "from": "string value", + "to": "string value", + "gas": "0x5", + "input": "string value", + "value": "0x0" + }, + "result": { + "gasUsed": "0x5", + "output": "string value" + }, + "subtraces": 123, + "traceAddress": [ + 123 + ], + "Type": "string value" + } + ], + "transactionHash": "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e", + "vmTrace": "string value" + } +] +``` ## Wallet diff --git a/gateway/node.go b/gateway/node.go index bbda71fcf..1ed846d1a 100644 --- a/gateway/node.go +++ b/gateway/node.go @@ -144,8 +144,8 @@ type TargetAPI interface { EthSubscribe(ctx context.Context, params jsonrpc.RawParams) (ethtypes.EthSubscriptionID, error) EthUnsubscribe(ctx context.Context, id ethtypes.EthSubscriptionID) (bool, error) Web3ClientVersion(ctx context.Context) (string, error) - TraceBlock(ctx context.Context, blkNum string) (interface{}, error) - TraceReplayBlockTransactions(ctx context.Context, blkNum string, traceTypes []string) (interface{}, error) + TraceBlock(ctx context.Context, blkNum string) ([]*ethtypes.TraceBlock, error) + TraceReplayBlockTransactions(ctx context.Context, blkNum string, traceTypes []string) ([]*ethtypes.TraceReplayBlockTransaction, error) } var _ TargetAPI = *new(api.FullNode) // gateway depends on latest diff --git a/gateway/proxy_eth.go b/gateway/proxy_eth.go index f8b950011..42e9d8e45 100644 --- a/gateway/proxy_eth.go +++ b/gateway/proxy_eth.go @@ -582,25 +582,25 @@ func (gw *Node) Web3ClientVersion(ctx context.Context) (string, error) { return gw.target.Web3ClientVersion(ctx) } -func (gw *Node) TraceBlock(ctx context.Context, blkNum string) (interface{}, error) { +func (gw *Node) TraceBlock(ctx context.Context, blkNum string) ([]*ethtypes.TraceBlock, error) { if err := gw.limit(ctx, stateRateLimitTokens); err != nil { - return 0, err + return nil, err } if err := gw.checkBlkParam(ctx, blkNum, 0); err != nil { - return ethtypes.EthBlock{}, err + return nil, err } return gw.target.TraceBlock(ctx, blkNum) } -func (gw *Node) TraceReplayBlockTransactions(ctx context.Context, blkNum string, traceTypes []string) (interface{}, error) { +func (gw *Node) TraceReplayBlockTransactions(ctx context.Context, blkNum string, traceTypes []string) ([]*ethtypes.TraceReplayBlockTransaction, error) { if err := gw.limit(ctx, stateRateLimitTokens); err != nil { - return 0, err + return nil, err } if err := gw.checkBlkParam(ctx, blkNum, 0); err != nil { - return ethtypes.EthBlock{}, err + return nil, err } return gw.target.TraceReplayBlockTransactions(ctx, blkNum, traceTypes) diff --git a/node/impl/full/dummy.go b/node/impl/full/dummy.go index c06e5c084..81481ea2c 100644 --- a/node/impl/full/dummy.go +++ b/node/impl/full/dummy.go @@ -178,11 +178,11 @@ func (e *EthModuleDummy) EthUnsubscribe(ctx context.Context, id ethtypes.EthSubs return false, ErrModuleDisabled } -func (e *EthModuleDummy) TraceBlock(ctx context.Context, blkNum string) (interface{}, error) { +func (e *EthModuleDummy) TraceBlock(ctx context.Context, blkNum string) ([]*ethtypes.TraceBlock, error) { return nil, ErrModuleDisabled } -func (e *EthModuleDummy) TraceReplayBlockTransactions(ctx context.Context, blkNum string, traceTypes []string) (interface{}, error) { +func (e *EthModuleDummy) TraceReplayBlockTransactions(ctx context.Context, blkNum string, traceTypes []string) ([]*ethtypes.TraceReplayBlockTransaction, error) { return nil, ErrModuleDisabled } diff --git a/node/impl/full/eth.go b/node/impl/full/eth.go index df27ad4eb..bbf98f0aa 100644 --- a/node/impl/full/eth.go +++ b/node/impl/full/eth.go @@ -71,8 +71,8 @@ type EthModuleAPI interface { EthMaxPriorityFeePerGas(ctx context.Context) (ethtypes.EthBigInt, error) EthSendRawTransaction(ctx context.Context, rawTx ethtypes.EthBytes) (ethtypes.EthHash, error) Web3ClientVersion(ctx context.Context) (string, error) - TraceBlock(ctx context.Context, blkNum string) (interface{}, error) - TraceReplayBlockTransactions(ctx context.Context, blkNum string, traceTypes []string) (interface{}, error) + TraceBlock(ctx context.Context, blkNum string) ([]*ethtypes.TraceBlock, error) + TraceReplayBlockTransactions(ctx context.Context, blkNum string, traceTypes []string) ([]*ethtypes.TraceReplayBlockTransaction, error) } type EthEventAPI interface { @@ -825,7 +825,7 @@ func (a *EthModule) Web3ClientVersion(ctx context.Context) (string, error) { return build.UserVersion(), nil } -func (a *EthModule) TraceBlock(ctx context.Context, blkNum string) (interface{}, error) { +func (a *EthModule) TraceBlock(ctx context.Context, blkNum string) ([]*ethtypes.TraceBlock, error) { ts, err := getTipsetByBlockNr(ctx, a.Chain, blkNum, false) if err != nil { return nil, err @@ -856,7 +856,7 @@ func (a *EthModule) TraceBlock(ctx context.Context, blkNum string) (interface{}, return nil, err } - allTraces := make([]*TraceBlock, 0, len(trace)) + allTraces := make([]*ethtypes.TraceBlock, 0, len(trace)) for _, ir := range trace { // ignore messages from f00 if ir.Msg.From.String() == "f00" { @@ -884,15 +884,15 @@ func (a *EthModule) TraceBlock(ctx context.Context, blkNum string) (interface{}, continue } - traces := []*Trace{} - err = buildTraces(&traces, nil, []int{}, ir.ExecutionTrace, int64(ts.Height())) + traces := []*ethtypes.Trace{} + err = ethtypes.BuildTraces(&traces, nil, []int{}, ir.ExecutionTrace, int64(ts.Height())) if err != nil { return nil, xerrors.Errorf("failed when building traces: %w", err) } - traceBlocks := make([]*TraceBlock, 0, len(trace)) + traceBlocks := make([]*ethtypes.TraceBlock, 0, len(trace)) for _, trace := range traces { - traceBlocks = append(traceBlocks, &TraceBlock{ + traceBlocks = append(traceBlocks, ðtypes.TraceBlock{ Trace: trace, BlockHash: blkHash, BlockNumber: int64(ts.Height()), @@ -907,7 +907,7 @@ func (a *EthModule) TraceBlock(ctx context.Context, blkNum string) (interface{}, return allTraces, nil } -func (a *EthModule) TraceReplayBlockTransactions(ctx context.Context, blkNum string, traceTypes []string) (interface{}, error) { +func (a *EthModule) TraceReplayBlockTransactions(ctx context.Context, blkNum string, traceTypes []string) ([]*ethtypes.TraceReplayBlockTransaction, error) { if len(traceTypes) != 1 || traceTypes[0] != "trace" { return nil, fmt.Errorf("only 'trace' is supported") } @@ -922,7 +922,7 @@ func (a *EthModule) TraceReplayBlockTransactions(ctx context.Context, blkNum str return nil, xerrors.Errorf("failed when calling ExecutionTrace: %w", err) } - allTraces := make([]*TraceReplayBlockTransaction, 0, len(trace)) + allTraces := make([]*ethtypes.TraceReplayBlockTransaction, 0, len(trace)) for _, ir := range trace { // ignore messages from f00 if ir.Msg.From.String() == "f00" { @@ -938,14 +938,14 @@ func (a *EthModule) TraceReplayBlockTransactions(ctx context.Context, blkNum str continue } - t := TraceReplayBlockTransaction{ + t := ethtypes.TraceReplayBlockTransaction{ Output: hex.EncodeToString(ir.MsgRct.Return), TransactionHash: *txHash, StateDiff: nil, VmTrace: nil, } - err = buildTraces(&t.Trace, nil, []int{}, ir.ExecutionTrace, int64(ts.Height())) + err = ethtypes.BuildTraces(&t.Trace, nil, []int{}, ir.ExecutionTrace, int64(ts.Height())) if err != nil { return nil, xerrors.Errorf("failed when building traces: %w", err) }