diff --git a/api/api_full.go b/api/api_full.go index ce187feef..55dcc23df 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) ([]*ethtypes.TraceBlock, error) //perm:read + EthTraceBlock(ctx context.Context, blkNum string) ([]*ethtypes.EthTraceBlock, error) //perm:read // Replays all transactions in a block returning the requested traces for each transaction - TraceReplayBlockTransactions(ctx context.Context, blkNum string, traceTypes []string) ([]*ethtypes.TraceReplayBlockTransaction, error) //perm:read + EthTraceReplayBlockTransactions(ctx context.Context, blkNum string, traceTypes []string) ([]*ethtypes.EthTraceReplayBlockTransaction, 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 fef7c2c04..08199564d 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) ([]*ethtypes.TraceBlock, error) - TraceReplayBlockTransactions(ctx context.Context, blkNum string, traceTypes []string) ([]*ethtypes.TraceReplayBlockTransaction, error) + EthTraceBlock(ctx context.Context, blkNum string) ([]*ethtypes.EthTraceBlock, error) + EthTraceReplayBlockTransactions(ctx context.Context, blkNum string, traceTypes []string) ([]*ethtypes.EthTraceReplayBlockTransaction, error) } diff --git a/api/eth_aliases.go b/api/eth_aliases.go index fe761c545..eb0c51005 100644 --- a/api/eth_aliases.go +++ b/api/eth_aliases.go @@ -40,8 +40,8 @@ func CreateEthRPCAliases(as apitypes.Aliaser) { as.AliasMethod("eth_subscribe", "Filecoin.EthSubscribe") as.AliasMethod("eth_unsubscribe", "Filecoin.EthUnsubscribe") - as.AliasMethod("trace_block", "Filecoin.TraceBlock") - as.AliasMethod("trace_replayBlockTransactions", "Filecoin.TraceReplayBlockTransactions") + as.AliasMethod("trace_block", "Filecoin.EthTraceBlock") + as.AliasMethod("trace_replayBlockTransactions", "Filecoin.EthTraceReplayBlockTransactions") as.AliasMethod("net_version", "Filecoin.NetVersion") as.AliasMethod("net_listening", "Filecoin.NetListening") diff --git a/api/mocks/mock_full.go b/api/mocks/mock_full.go index 24a7cc207..856d83813 100644 --- a/api/mocks/mock_full.go +++ b/api/mocks/mock_full.go @@ -1491,6 +1491,36 @@ func (mr *MockFullNodeMockRecorder) EthSyncing(arg0 interface{}) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthSyncing", reflect.TypeOf((*MockFullNode)(nil).EthSyncing), arg0) } +// EthTraceBlock mocks base method. +func (m *MockFullNode) EthTraceBlock(arg0 context.Context, arg1 string) ([]*ethtypes.EthTraceBlock, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "EthTraceBlock", arg0, arg1) + ret0, _ := ret[0].([]*ethtypes.EthTraceBlock) + 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) +} + +// EthTraceReplayBlockTransactions mocks base method. +func (m *MockFullNode) EthTraceReplayBlockTransactions(arg0 context.Context, arg1 string, arg2 []string) ([]*ethtypes.EthTraceReplayBlockTransaction, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "EthTraceReplayBlockTransactions", arg0, arg1, arg2) + ret0, _ := ret[0].([]*ethtypes.EthTraceReplayBlockTransaction) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// EthTraceReplayBlockTransactions indicates an expected call of EthTraceReplayBlockTransactions. +func (mr *MockFullNodeMockRecorder) EthTraceReplayBlockTransactions(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthTraceReplayBlockTransactions", reflect.TypeOf((*MockFullNode)(nil).EthTraceReplayBlockTransactions), arg0, arg1, arg2) +} + // EthUninstallFilter mocks base method. func (m *MockFullNode) EthUninstallFilter(arg0 context.Context, arg1 ethtypes.EthFilterID) (bool, error) { m.ctrl.T.Helper() @@ -4023,36 +4053,6 @@ func (mr *MockFullNodeMockRecorder) SyncValidateTipset(arg0, arg1 interface{}) * return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SyncValidateTipset", reflect.TypeOf((*MockFullNode)(nil).SyncValidateTipset), arg0, arg1) } -// TraceBlock mocks base method. -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].([]*ethtypes.TraceBlock) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// TraceBlock indicates an expected call of TraceBlock. -func (mr *MockFullNodeMockRecorder) TraceBlock(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TraceBlock", reflect.TypeOf((*MockFullNode)(nil).TraceBlock), arg0, arg1) -} - -// TraceReplayBlockTransactions mocks base method. -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].([]*ethtypes.TraceReplayBlockTransaction) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// TraceReplayBlockTransactions indicates an expected call of TraceReplayBlockTransactions. -func (mr *MockFullNodeMockRecorder) TraceReplayBlockTransactions(arg0, arg1, arg2 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TraceReplayBlockTransactions", reflect.TypeOf((*MockFullNode)(nil).TraceReplayBlockTransactions), arg0, arg1, arg2) -} - // Version mocks base method. func (m *MockFullNode) Version(arg0 context.Context) (api.APIVersion, error) { m.ctrl.T.Helper() diff --git a/api/proxy_gen.go b/api/proxy_gen.go index d3f49daf9..1082e8f4c 100644 --- a/api/proxy_gen.go +++ b/api/proxy_gen.go @@ -316,6 +316,10 @@ type FullNodeMethods struct { EthSyncing func(p0 context.Context) (ethtypes.EthSyncingResult, error) `perm:"read"` + EthTraceBlock func(p0 context.Context, p1 string) ([]*ethtypes.EthTraceBlock, error) `perm:"read"` + + EthTraceReplayBlockTransactions func(p0 context.Context, p1 string, p2 []string) ([]*ethtypes.EthTraceReplayBlockTransaction, error) `perm:"read"` + EthUninstallFilter func(p0 context.Context, p1 ethtypes.EthFilterID) (bool, error) `perm:"read"` EthUnsubscribe func(p0 context.Context, p1 ethtypes.EthSubscriptionID) (bool, error) `perm:"read"` @@ -596,10 +600,6 @@ type FullNodeMethods struct { SyncValidateTipset func(p0 context.Context, p1 types.TipSetKey) (bool, error) `perm:"read"` - TraceBlock func(p0 context.Context, p1 string) ([]*ethtypes.TraceBlock, 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"` WalletDefaultAddress func(p0 context.Context) (address.Address, error) `perm:"write"` @@ -736,6 +736,10 @@ type GatewayMethods struct { EthSyncing func(p0 context.Context) (ethtypes.EthSyncingResult, error) `` + EthTraceBlock func(p0 context.Context, p1 string) ([]*ethtypes.EthTraceBlock, error) `` + + EthTraceReplayBlockTransactions func(p0 context.Context, p1 string, p2 []string) ([]*ethtypes.EthTraceReplayBlockTransaction, error) `` + EthUninstallFilter func(p0 context.Context, p1 ethtypes.EthFilterID) (bool, error) `` EthUnsubscribe func(p0 context.Context, p1 ethtypes.EthSubscriptionID) (bool, error) `` @@ -818,10 +822,6 @@ 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) ([]*ethtypes.TraceBlock, error) `` - - TraceReplayBlockTransactions func(p0 context.Context, p1 string, p2 []string) ([]*ethtypes.TraceReplayBlockTransaction, error) `` - Version func(p0 context.Context) (APIVersion, error) `` WalletBalance func(p0 context.Context, p1 address.Address) (types.BigInt, error) `` @@ -2465,6 +2465,28 @@ func (s *FullNodeStub) EthSyncing(p0 context.Context) (ethtypes.EthSyncingResult return *new(ethtypes.EthSyncingResult), ErrNotSupported } +func (s *FullNodeStruct) EthTraceBlock(p0 context.Context, p1 string) ([]*ethtypes.EthTraceBlock, error) { + if s.Internal.EthTraceBlock == nil { + return *new([]*ethtypes.EthTraceBlock), ErrNotSupported + } + return s.Internal.EthTraceBlock(p0, p1) +} + +func (s *FullNodeStub) EthTraceBlock(p0 context.Context, p1 string) ([]*ethtypes.EthTraceBlock, error) { + return *new([]*ethtypes.EthTraceBlock), ErrNotSupported +} + +func (s *FullNodeStruct) EthTraceReplayBlockTransactions(p0 context.Context, p1 string, p2 []string) ([]*ethtypes.EthTraceReplayBlockTransaction, error) { + if s.Internal.EthTraceReplayBlockTransactions == nil { + return *new([]*ethtypes.EthTraceReplayBlockTransaction), ErrNotSupported + } + return s.Internal.EthTraceReplayBlockTransactions(p0, p1, p2) +} + +func (s *FullNodeStub) EthTraceReplayBlockTransactions(p0 context.Context, p1 string, p2 []string) ([]*ethtypes.EthTraceReplayBlockTransaction, error) { + return *new([]*ethtypes.EthTraceReplayBlockTransaction), ErrNotSupported +} + func (s *FullNodeStruct) EthUninstallFilter(p0 context.Context, p1 ethtypes.EthFilterID) (bool, error) { if s.Internal.EthUninstallFilter == nil { return false, ErrNotSupported @@ -4005,28 +4027,6 @@ func (s *FullNodeStub) SyncValidateTipset(p0 context.Context, p1 types.TipSetKey return false, ErrNotSupported } -func (s *FullNodeStruct) TraceBlock(p0 context.Context, p1 string) ([]*ethtypes.TraceBlock, error) { - if s.Internal.TraceBlock == nil { - return *new([]*ethtypes.TraceBlock), ErrNotSupported - } - return s.Internal.TraceBlock(p0, p1) -} - -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) ([]*ethtypes.TraceReplayBlockTransaction, error) { - if s.Internal.TraceReplayBlockTransactions == nil { - return *new([]*ethtypes.TraceReplayBlockTransaction), ErrNotSupported - } - return s.Internal.TraceReplayBlockTransactions(p0, p1, p2) -} - -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) { if s.Internal.WalletBalance == nil { return *new(types.BigInt), ErrNotSupported @@ -4709,6 +4709,28 @@ func (s *GatewayStub) EthSyncing(p0 context.Context) (ethtypes.EthSyncingResult, return *new(ethtypes.EthSyncingResult), ErrNotSupported } +func (s *GatewayStruct) EthTraceBlock(p0 context.Context, p1 string) ([]*ethtypes.EthTraceBlock, error) { + if s.Internal.EthTraceBlock == nil { + return *new([]*ethtypes.EthTraceBlock), ErrNotSupported + } + return s.Internal.EthTraceBlock(p0, p1) +} + +func (s *GatewayStub) EthTraceBlock(p0 context.Context, p1 string) ([]*ethtypes.EthTraceBlock, error) { + return *new([]*ethtypes.EthTraceBlock), ErrNotSupported +} + +func (s *GatewayStruct) EthTraceReplayBlockTransactions(p0 context.Context, p1 string, p2 []string) ([]*ethtypes.EthTraceReplayBlockTransaction, error) { + if s.Internal.EthTraceReplayBlockTransactions == nil { + return *new([]*ethtypes.EthTraceReplayBlockTransaction), ErrNotSupported + } + return s.Internal.EthTraceReplayBlockTransactions(p0, p1, p2) +} + +func (s *GatewayStub) EthTraceReplayBlockTransactions(p0 context.Context, p1 string, p2 []string) ([]*ethtypes.EthTraceReplayBlockTransaction, error) { + return *new([]*ethtypes.EthTraceReplayBlockTransaction), ErrNotSupported +} + func (s *GatewayStruct) EthUninstallFilter(p0 context.Context, p1 ethtypes.EthFilterID) (bool, error) { if s.Internal.EthUninstallFilter == nil { return false, ErrNotSupported @@ -5160,28 +5182,6 @@ 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) ([]*ethtypes.TraceBlock, error) { - if s.Internal.TraceBlock == nil { - return *new([]*ethtypes.TraceBlock), ErrNotSupported - } - return s.Internal.TraceBlock(p0, p1) -} - -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) ([]*ethtypes.TraceReplayBlockTransaction, error) { - if s.Internal.TraceReplayBlockTransactions == nil { - return *new([]*ethtypes.TraceReplayBlockTransaction), ErrNotSupported - } - return s.Internal.TraceReplayBlockTransactions(p0, p1, p2) -} - -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) { if s.Internal.Version == nil { return *new(APIVersion), ErrNotSupported diff --git a/chain/types/ethtypes/eth_types.go b/chain/types/ethtypes/eth_types.go index 3e0dd8724..b04d01b69 100644 --- a/chain/types/ethtypes/eth_types.go +++ b/chain/types/ethtypes/eth_types.go @@ -18,6 +18,7 @@ import ( "golang.org/x/xerrors" "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/big" builtintypes "github.com/filecoin-project/go-state-types/builtin" @@ -929,3 +930,51 @@ func (e *EthBlockNumberOrHash) UnmarshalJSON(b []byte) error { return errors.New("invalid block param") } + +type EthTrace struct { + Action EthTraceAction `json:"action"` + Result EthTraceResult `json:"result"` + Subtraces int `json:"subtraces"` + TraceAddress []int `json:"traceAddress"` + Type string `json:"Type"` + + Parent *EthTrace `json:"-"` +} + +func (t *EthTrace) SetCallType(callType string) { + t.Action.CallType = callType + t.Type = callType +} + +type EthTraceBlock struct { + *EthTrace + BlockHash EthHash `json:"blockHash"` + BlockNumber int64 `json:"blockNumber"` + TransactionHash EthHash `json:"transactionHash"` + TransactionPosition int `json:"transactionPosition"` +} + +type EthTraceReplayBlockTransaction struct { + Output string `json:"output"` + StateDiff *string `json:"stateDiff"` + Trace []*EthTrace `json:"trace"` + TransactionHash EthHash `json:"transactionHash"` + VmTrace *string `json:"vmTrace"` +} + +type EthTraceAction struct { + 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 EthTraceResult struct { + GasUsed EthUint64 `json:"gasUsed"` + Output string `json:"output"` +} diff --git a/documentation/en/api-v1-unstable-methods.md b/documentation/en/api-v1-unstable-methods.md index a488ee64b..b28e5d5ef 100644 --- a/documentation/en/api-v1-unstable-methods.md +++ b/documentation/en/api-v1-unstable-methods.md @@ -104,6 +104,8 @@ * [EthSendRawTransaction](#EthSendRawTransaction) * [EthSubscribe](#EthSubscribe) * [EthSyncing](#EthSyncing) + * [EthTraceBlock](#EthTraceBlock) + * [EthTraceReplayBlockTransactions](#EthTraceReplayBlockTransactions) * [EthUninstallFilter](#EthUninstallFilter) * [EthUnsubscribe](#EthUnsubscribe) * [Filecoin](#Filecoin) @@ -287,9 +289,6 @@ * [SyncUnmarkAllBad](#SyncUnmarkAllBad) * [SyncUnmarkBad](#SyncUnmarkBad) * [SyncValidateTipset](#SyncValidateTipset) -* [Trace](#Trace) - * [TraceBlock](#TraceBlock) - * [TraceReplayBlockTransactions](#TraceReplayBlockTransactions) * [Wallet](#Wallet) * [WalletBalance](#WalletBalance) * [WalletDefaultAddress](#WalletDefaultAddress) @@ -3086,6 +3085,99 @@ Inputs: `null` Response: `false` +### EthTraceBlock +TraceAPI related methods + +Returns traces created at given block + + +Perms: read + +Inputs: +```json +[ + "string value" +] +``` + +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 + } +] +``` + +### EthTraceReplayBlockTransactions +Replays all transactions in a block returning the requested traces for each transaction + + +Perms: read + +Inputs: +```json +[ + "string value", + [ + "string value" + ] +] +``` + +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" + } +] +``` + ### EthUninstallFilter Uninstalls a filter with given id. @@ -8823,102 +8915,6 @@ Inputs: Response: `true` -## Trace - - -### TraceBlock -TraceAPI related methods - -Returns traces created at given block - - -Perms: read - -Inputs: -```json -[ - "string value" -] -``` - -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 - - -Perms: read - -Inputs: -```json -[ - "string value", - [ - "string value" - ] -] -``` - -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 1ed846d1a..367e645c1 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) ([]*ethtypes.TraceBlock, error) - TraceReplayBlockTransactions(ctx context.Context, blkNum string, traceTypes []string) ([]*ethtypes.TraceReplayBlockTransaction, error) + EthTraceBlock(ctx context.Context, blkNum string) ([]*ethtypes.EthTraceBlock, error) + EthTraceReplayBlockTransactions(ctx context.Context, blkNum string, traceTypes []string) ([]*ethtypes.EthTraceReplayBlockTransaction, error) } var _ TargetAPI = *new(api.FullNode) // gateway depends on latest diff --git a/gateway/proxy_eth.go b/gateway/proxy_eth.go index 42e9d8e45..e6d433a17 100644 --- a/gateway/proxy_eth.go +++ b/gateway/proxy_eth.go @@ -582,7 +582,7 @@ func (gw *Node) Web3ClientVersion(ctx context.Context) (string, error) { return gw.target.Web3ClientVersion(ctx) } -func (gw *Node) TraceBlock(ctx context.Context, blkNum string) ([]*ethtypes.TraceBlock, error) { +func (gw *Node) EthTraceBlock(ctx context.Context, blkNum string) ([]*ethtypes.EthTraceBlock, error) { if err := gw.limit(ctx, stateRateLimitTokens); err != nil { return nil, err } @@ -591,10 +591,10 @@ func (gw *Node) TraceBlock(ctx context.Context, blkNum string) ([]*ethtypes.Trac return nil, err } - return gw.target.TraceBlock(ctx, blkNum) + return gw.target.EthTraceBlock(ctx, blkNum) } -func (gw *Node) TraceReplayBlockTransactions(ctx context.Context, blkNum string, traceTypes []string) ([]*ethtypes.TraceReplayBlockTransaction, error) { +func (gw *Node) EthTraceReplayBlockTransactions(ctx context.Context, blkNum string, traceTypes []string) ([]*ethtypes.EthTraceReplayBlockTransaction, error) { if err := gw.limit(ctx, stateRateLimitTokens); err != nil { return nil, err } @@ -603,7 +603,7 @@ func (gw *Node) TraceReplayBlockTransactions(ctx context.Context, blkNum string, return nil, err } - return gw.target.TraceReplayBlockTransactions(ctx, blkNum, traceTypes) + return gw.target.EthTraceReplayBlockTransactions(ctx, blkNum, traceTypes) } var EthMaxFiltersPerConn = 16 // todo make this configurable diff --git a/node/impl/full/dummy.go b/node/impl/full/dummy.go index 81481ea2c..743eadf34 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) ([]*ethtypes.TraceBlock, error) { +func (e *EthModuleDummy) EthTraceBlock(ctx context.Context, blkNum string) ([]*ethtypes.EthTraceBlock, error) { return nil, ErrModuleDisabled } -func (e *EthModuleDummy) TraceReplayBlockTransactions(ctx context.Context, blkNum string, traceTypes []string) ([]*ethtypes.TraceReplayBlockTransaction, error) { +func (e *EthModuleDummy) EthTraceReplayBlockTransactions(ctx context.Context, blkNum string, traceTypes []string) ([]*ethtypes.EthTraceReplayBlockTransaction, error) { return nil, ErrModuleDisabled } diff --git a/node/impl/full/eth.go b/node/impl/full/eth.go index 25796e864..0a0a79cd4 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) ([]*ethtypes.TraceBlock, error) - TraceReplayBlockTransactions(ctx context.Context, blkNum string, traceTypes []string) ([]*ethtypes.TraceReplayBlockTransaction, error) + EthTraceBlock(ctx context.Context, blkNum string) ([]*ethtypes.EthTraceBlock, error) + EthTraceReplayBlockTransactions(ctx context.Context, blkNum string, traceTypes []string) ([]*ethtypes.EthTraceReplayBlockTransaction, 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) ([]*ethtypes.TraceBlock, error) { +func (a *EthModule) EthTraceBlock(ctx context.Context, blkNum string) ([]*ethtypes.EthTraceBlock, error) { ts, err := getTipsetByBlockNumber(ctx, a.Chain, blkNum, false) if err != nil { return nil, xerrors.Errorf("failed to get tipset: %w", err) @@ -856,7 +856,7 @@ func (a *EthModule) TraceBlock(ctx context.Context, blkNum string) ([]*ethtypes. return nil, xerrors.Errorf("failed to parse eth hash from cid: %w", err) } - allTraces := make([]*ethtypes.TraceBlock, 0, len(trace)) + allTraces := make([]*ethtypes.EthTraceBlock, 0, len(trace)) msgIdx := 0 for _, ir := range trace { // ignore messages from system actor @@ -880,16 +880,16 @@ func (a *EthModule) TraceBlock(ctx context.Context, blkNum string) ([]*ethtypes. continue } - traces := []*ethtypes.Trace{} - err = ethtypes.BuildTraces(&traces, nil, []int{}, ir.ExecutionTrace, int64(ts.Height())) + traces := []*ethtypes.EthTrace{} + err = buildTraces(ctx, &traces, nil, []int{}, ir.ExecutionTrace, int64(ts.Height()), a.StateAPI) if err != nil { return nil, xerrors.Errorf("failed building traces: %w", err) } - traceBlocks := make([]*ethtypes.TraceBlock, 0, len(traces)) + traceBlocks := make([]*ethtypes.EthTraceBlock, 0, len(traces)) for _, trace := range traces { - traceBlocks = append(traceBlocks, ðtypes.TraceBlock{ - Trace: trace, + traceBlocks = append(traceBlocks, ðtypes.EthTraceBlock{ + EthTrace: trace, BlockHash: blkHash, BlockNumber: int64(ts.Height()), TransactionHash: *txHash, @@ -903,7 +903,7 @@ func (a *EthModule) TraceBlock(ctx context.Context, blkNum string) ([]*ethtypes. return allTraces, nil } -func (a *EthModule) TraceReplayBlockTransactions(ctx context.Context, blkNum string, traceTypes []string) ([]*ethtypes.TraceReplayBlockTransaction, error) { +func (a *EthModule) EthTraceReplayBlockTransactions(ctx context.Context, blkNum string, traceTypes []string) ([]*ethtypes.EthTraceReplayBlockTransaction, error) { if len(traceTypes) != 1 || traceTypes[0] != "trace" { return nil, fmt.Errorf("only 'trace' is supported") } @@ -918,7 +918,7 @@ func (a *EthModule) TraceReplayBlockTransactions(ctx context.Context, blkNum str return nil, xerrors.Errorf("failed when calling ExecutionTrace: %w", err) } - allTraces := make([]*ethtypes.TraceReplayBlockTransaction, 0, len(trace)) + allTraces := make([]*ethtypes.EthTraceReplayBlockTransaction, 0, len(trace)) for _, ir := range trace { // ignore messages from system actor if ir.Msg.From == builtinactors.SystemActorAddr { @@ -934,14 +934,14 @@ func (a *EthModule) TraceReplayBlockTransactions(ctx context.Context, blkNum str continue } - t := ethtypes.TraceReplayBlockTransaction{ + t := ethtypes.EthTraceReplayBlockTransaction{ Output: hex.EncodeToString(ir.MsgRct.Return), TransactionHash: *txHash, StateDiff: nil, VmTrace: nil, } - err = ethtypes.BuildTraces(&t.Trace, nil, []int{}, ir.ExecutionTrace, int64(ts.Height())) + err = buildTraces(ctx, &t.Trace, nil, []int{}, ir.ExecutionTrace, int64(ts.Height()), a.StateAPI) if err != nil { return nil, xerrors.Errorf("failed building traces: %w", err) } diff --git a/chain/types/ethtypes/eth_trace.go b/node/impl/full/eth_trace.go similarity index 71% rename from chain/types/ethtypes/eth_trace.go rename to node/impl/full/eth_trace.go index 14f7e3332..ce650b9ec 100644 --- a/chain/types/ethtypes/eth_trace.go +++ b/node/impl/full/eth_trace.go @@ -1,100 +1,49 @@ -package ethtypes +package full import ( "bytes" + "context" "encoding/binary" "encoding/hex" "fmt" "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" "github.com/filecoin-project/go-state-types/exitcode" 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"` - Subtraces int `json:"subtraces"` - TraceAddress []int `json:"traceAddress"` - Type string `json:"Type"` - - parent *Trace -} - -func (t *Trace) setCallType(callType string) { - t.Action.CallType = callType - t.Type = callType -} - -type TraceBlock struct { - *Trace - 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 EthHash `json:"transactionHash"` - VmTrace *string `json:"vmTrace"` -} - -type Action struct { - 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 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 { - trace := &Trace{ - Action: Action{ +// 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 { + trace := ðtypes.EthTrace{ + Action: ethtypes.EthTraceAction{ From: et.Msg.From.String(), To: et.Msg.To.String(), - Gas: EthUint64(et.Msg.GasLimit), + Gas: ethtypes.EthUint64(et.Msg.GasLimit), Input: hex.EncodeToString(et.Msg.Params), - Value: EthBigInt(et.Msg.Value), - method: et.Msg.Method, - codeCid: et.Msg.CodeCid, + Value: ethtypes.EthBigInt(et.Msg.Value), + Method: et.Msg.Method, + CodeCid: et.Msg.CodeCid, }, - Result: Result{ - GasUsed: EthUint64(et.SumGas().TotalGas), + Result: ethtypes.EthTraceResult{ + GasUsed: ethtypes.EthUint64(et.SumGas().TotalGas), Output: hex.EncodeToString(et.MsgRct.Return), }, Subtraces: len(et.Subcalls), TraceAddress: addr, - parent: parent, + Parent: parent, } - trace.setCallType("call") + trace.SetCallType("call") // TODO: is it OK to check this here or is this only specific to certain edge case (evm to evm)? if et.Msg.ReadOnly { - trace.setCallType("staticcall") + trace.SetCallType("staticcall") } // there are several edge cases thar require special handling when displaying the traces @@ -104,7 +53,7 @@ func BuildTraces(traces *[]*Trace, parent *Trace, addr []int, et types.Execution // 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) && + 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) @@ -124,10 +73,10 @@ func BuildTraces(traces *[]*Trace, parent *Trace, addr []int, et types.Execution // // 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 if parent.Action.To == builtin.InitActorAddr.String() && - parent.Action.method == builtin.MethodsInit.Exec && + parent.Action.Method == builtin.MethodsInit.Exec && et.Msg.Method == builtin.MethodConstructor { 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.Input = hex.EncodeToString([]byte{0x0, 0x0, 0x0, 0xFE}) parent.Result.Output = "" @@ -143,25 +92,25 @@ func BuildTraces(traces *[]*Trace, parent *Trace, addr []int, et types.Execution // 1) EVM contract A calls the EAM (Ethereum Address Manager) on method 2 (create) or 3 (create2). // 2) The EAM calls the init actor on method 3 (Exec4). // 3) The init actor creates the target actor B then calls it on method 1. - if parent.parent != nil { - calledCreateOnEAM := parent.parent.Action.To == builtin.EthereumAddressManagerActorAddr.String() && - (parent.parent.Action.method == builtin.MethodsEAM.Create || parent.parent.Action.method == builtin.MethodsEAM.Create2) + if parent.Parent != nil { + calledCreateOnEAM := parent.Parent.Action.To == builtin.EthereumAddressManagerActorAddr.String() && + (parent.Parent.Action.Method == builtin.MethodsEAM.Create || parent.Parent.Action.Method == builtin.MethodsEAM.Create2) eamCalledInitOnExec4 := parent.Action.To == builtin.InitActorAddr.String() && - parent.Action.method == builtin.MethodsInit.Exec4 - initCreatedActor := trace.Action.method == builtin.MethodConstructor + parent.Action.Method == builtin.MethodsInit.Exec4 + initCreatedActor := trace.Action.Method == builtin.MethodConstructor if calledCreateOnEAM && eamCalledInitOnExec4 && initCreatedActor { log.Debugf("EVM contract creation method:%d, code:%s, height:%d", et.Msg.Method, et.Msg.CodeCid.String(), height) - if parent.parent.Action.method == builtin.MethodsEAM.Create { - parent.parent.setCallType("create") + if parent.Parent.Action.Method == builtin.MethodsEAM.Create { + parent.Parent.SetCallType("create") } else { - parent.parent.setCallType("create2") + parent.Parent.SetCallType("create2") } // update the parent.parent to make this - parent.parent.Action.To = trace.Action.To - parent.parent.Subtraces = 0 + parent.Parent.Action.To = trace.Action.To + parent.Parent.Subtraces = 0 // delete the parent (the EAM) and skip the current trace (init) *traces = (*traces)[:len(*traces)-1] @@ -174,17 +123,17 @@ func BuildTraces(traces *[]*Trace, parent *Trace, addr []int, et types.Execution // // Any outbound call from an EVM actor on methods 1-1023 are side-effects from EVM instructions // and should be dropped from the trace. - if builtinactors.IsEvmActor(parent.Action.codeCid) && + if builtinactors.IsEvmActor(parent.Action.CodeCid) && et.Msg.Method > 0 && et.Msg.Method <= 1023 { - log.Debugf("found outbound call from an EVM actor on method 1-1023 method:%d, code:%s, height:%d", et.Msg.Method, parent.Action.codeCid.String(), height) + log.Debugf("found outbound call from an EVM actor on method 1-1023 method:%d, code:%s, height:%d", et.Msg.Method, parent.Action.CodeCid.String(), height) // TODO: if I handle this case and drop this call from the trace then I am not able to detect delegate calls } // EVM -> EVM calls // // Check for normal EVM to EVM calls and decode the params and return values - if builtinactors.IsEvmActor(parent.Action.codeCid) && + if builtinactors.IsEvmActor(parent.Action.CodeCid) && builtinactors.IsEthAccountActor(et.Msg.CodeCid) && et.Msg.Method == builtin.MethodsEVM.InvokeContract { log.Debugf("found evm to evm call, code:%s, height: %d", et.Msg.CodeCid.String(), height) @@ -206,12 +155,12 @@ func BuildTraces(traces *[]*Trace, parent *Trace, addr []int, et types.Execution // 2) Check that the previous trace calls another actor on method 3 (GetByteCode) and they are at the same level (same parent) // 3) Treat this as a delegate call to actor A. if trace.Action.From == trace.Action.To && - trace.Action.method == builtin.MethodsEVM.InvokeContractDelegate && + trace.Action.Method == builtin.MethodsEVM.InvokeContractDelegate && len(*traces) > 0 { log.Debugf("found delegate call, height: %d", height) prev := (*traces)[len(*traces)-1] - if prev.Action.From == trace.Action.From && prev.Action.method == builtin.MethodsEVM.GetBytecode && prev.parent == trace.parent { - trace.setCallType("delegatecall") + if prev.Action.From == trace.Action.From && prev.Action.Method == builtin.MethodsEVM.GetBytecode && prev.Parent == trace.Parent { + trace.SetCallType("delegatecall") trace.Action.To = prev.Action.To } } @@ -220,7 +169,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(ctx, traces, trace, append(addr, i), call, height, sa) if err != nil { return err }