Add new tracing API
This commit is contained in:
parent
c4214e23bf
commit
1b0f54a61b
@ -868,6 +868,13 @@ type FullNode interface {
|
|||||||
// Returns the client version
|
// Returns the client version
|
||||||
Web3ClientVersion(ctx context.Context) (string, error) //perm:read
|
Web3ClientVersion(ctx context.Context) (string, error) //perm:read
|
||||||
|
|
||||||
|
// TraceAPI related methods
|
||||||
|
//
|
||||||
|
// Returns traces created at given block
|
||||||
|
TraceBlock(ctx context.Context, blkNum string) (interface{}, 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
|
||||||
|
|
||||||
// CreateBackup creates node backup onder the specified file name. The
|
// CreateBackup creates node backup onder the specified file name. The
|
||||||
// method requires that the lotus daemon is running with the
|
// method requires that the lotus daemon is running with the
|
||||||
// LOTUS_BACKUP_BASE_PATH environment variable set to some path, and that
|
// LOTUS_BACKUP_BASE_PATH environment variable set to some path, and that
|
||||||
|
@ -127,4 +127,6 @@ type Gateway interface {
|
|||||||
EthSubscribe(ctx context.Context, params jsonrpc.RawParams) (ethtypes.EthSubscriptionID, error)
|
EthSubscribe(ctx context.Context, params jsonrpc.RawParams) (ethtypes.EthSubscriptionID, error)
|
||||||
EthUnsubscribe(ctx context.Context, id ethtypes.EthSubscriptionID) (bool, error)
|
EthUnsubscribe(ctx context.Context, id ethtypes.EthSubscriptionID) (bool, error)
|
||||||
Web3ClientVersion(ctx context.Context) (string, 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)
|
||||||
}
|
}
|
||||||
|
@ -40,6 +40,9 @@ func CreateEthRPCAliases(as apitypes.Aliaser) {
|
|||||||
as.AliasMethod("eth_subscribe", "Filecoin.EthSubscribe")
|
as.AliasMethod("eth_subscribe", "Filecoin.EthSubscribe")
|
||||||
as.AliasMethod("eth_unsubscribe", "Filecoin.EthUnsubscribe")
|
as.AliasMethod("eth_unsubscribe", "Filecoin.EthUnsubscribe")
|
||||||
|
|
||||||
|
as.AliasMethod("trace_block", "Filecoin.TraceBlock")
|
||||||
|
as.AliasMethod("trace_replayBlockTransactions", "Filecoin.TraceReplayBlockTransactions")
|
||||||
|
|
||||||
as.AliasMethod("net_version", "Filecoin.NetVersion")
|
as.AliasMethod("net_version", "Filecoin.NetVersion")
|
||||||
as.AliasMethod("net_listening", "Filecoin.NetListening")
|
as.AliasMethod("net_listening", "Filecoin.NetListening")
|
||||||
|
|
||||||
|
@ -4023,6 +4023,36 @@ func (mr *MockFullNodeMockRecorder) SyncValidateTipset(arg0, arg1 interface{}) *
|
|||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SyncValidateTipset", reflect.TypeOf((*MockFullNode)(nil).SyncValidateTipset), arg0, arg1)
|
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) (interface{}, error) {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "TraceBlock", arg0, arg1)
|
||||||
|
ret0, _ := ret[0].(interface{})
|
||||||
|
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) (interface{}, error) {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "TraceReplayBlockTransactions", arg0, arg1, arg2)
|
||||||
|
ret0, _ := ret[0].(interface{})
|
||||||
|
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.
|
// Version mocks base method.
|
||||||
func (m *MockFullNode) Version(arg0 context.Context) (api.APIVersion, error) {
|
func (m *MockFullNode) Version(arg0 context.Context) (api.APIVersion, error) {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
|
@ -596,6 +596,10 @@ type FullNodeMethods struct {
|
|||||||
|
|
||||||
SyncValidateTipset func(p0 context.Context, p1 types.TipSetKey) (bool, error) `perm:"read"`
|
SyncValidateTipset func(p0 context.Context, p1 types.TipSetKey) (bool, error) `perm:"read"`
|
||||||
|
|
||||||
|
TraceBlock func(p0 context.Context, p1 string) (interface{}, error) `perm:"read"`
|
||||||
|
|
||||||
|
TraceReplayBlockTransactions func(p0 context.Context, p1 string, p2 []string) (interface{}, error) `perm:"read"`
|
||||||
|
|
||||||
WalletBalance func(p0 context.Context, p1 address.Address) (types.BigInt, 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"`
|
WalletDefaultAddress func(p0 context.Context) (address.Address, error) `perm:"write"`
|
||||||
@ -814,6 +818,10 @@ type GatewayMethods struct {
|
|||||||
|
|
||||||
StateWaitMsg func(p0 context.Context, p1 cid.Cid, p2 uint64, p3 abi.ChainEpoch, p4 bool) (*MsgLookup, error) ``
|
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) ``
|
||||||
|
|
||||||
|
TraceReplayBlockTransactions func(p0 context.Context, p1 string, p2 []string) (interface{}, error) ``
|
||||||
|
|
||||||
Version func(p0 context.Context) (APIVersion, error) ``
|
Version func(p0 context.Context) (APIVersion, error) ``
|
||||||
|
|
||||||
WalletBalance func(p0 context.Context, p1 address.Address) (types.BigInt, error) ``
|
WalletBalance func(p0 context.Context, p1 address.Address) (types.BigInt, error) ``
|
||||||
@ -3997,6 +4005,28 @@ func (s *FullNodeStub) SyncValidateTipset(p0 context.Context, p1 types.TipSetKey
|
|||||||
return false, ErrNotSupported
|
return false, ErrNotSupported
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *FullNodeStruct) TraceBlock(p0 context.Context, p1 string) (interface{}, error) {
|
||||||
|
if s.Internal.TraceBlock == nil {
|
||||||
|
return nil, ErrNotSupported
|
||||||
|
}
|
||||||
|
return s.Internal.TraceBlock(p0, p1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *FullNodeStub) TraceBlock(p0 context.Context, p1 string) (interface{}, error) {
|
||||||
|
return nil, ErrNotSupported
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *FullNodeStruct) TraceReplayBlockTransactions(p0 context.Context, p1 string, p2 []string) (interface{}, error) {
|
||||||
|
if s.Internal.TraceReplayBlockTransactions == nil {
|
||||||
|
return nil, 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 *FullNodeStruct) WalletBalance(p0 context.Context, p1 address.Address) (types.BigInt, error) {
|
func (s *FullNodeStruct) WalletBalance(p0 context.Context, p1 address.Address) (types.BigInt, error) {
|
||||||
if s.Internal.WalletBalance == nil {
|
if s.Internal.WalletBalance == nil {
|
||||||
return *new(types.BigInt), ErrNotSupported
|
return *new(types.BigInt), ErrNotSupported
|
||||||
@ -5130,6 +5160,28 @@ func (s *GatewayStub) StateWaitMsg(p0 context.Context, p1 cid.Cid, p2 uint64, p3
|
|||||||
return nil, ErrNotSupported
|
return nil, ErrNotSupported
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *GatewayStruct) TraceBlock(p0 context.Context, p1 string) (interface{}, error) {
|
||||||
|
if s.Internal.TraceBlock == nil {
|
||||||
|
return nil, ErrNotSupported
|
||||||
|
}
|
||||||
|
return s.Internal.TraceBlock(p0, p1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *GatewayStub) TraceBlock(p0 context.Context, p1 string) (interface{}, error) {
|
||||||
|
return nil, ErrNotSupported
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *GatewayStruct) TraceReplayBlockTransactions(p0 context.Context, p1 string, p2 []string) (interface{}, error) {
|
||||||
|
if s.Internal.TraceReplayBlockTransactions == nil {
|
||||||
|
return nil, 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 *GatewayStruct) Version(p0 context.Context) (APIVersion, error) {
|
func (s *GatewayStruct) Version(p0 context.Context) (APIVersion, error) {
|
||||||
if s.Internal.Version == nil {
|
if s.Internal.Version == nil {
|
||||||
return *new(APIVersion), ErrNotSupported
|
return *new(APIVersion), ErrNotSupported
|
||||||
|
@ -2289,7 +2289,7 @@ func (t *GasTrace) UnmarshalCBOR(r io.Reader) (err error) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var lengthBufMessageTrace = []byte{134}
|
var lengthBufMessageTrace = []byte{137}
|
||||||
|
|
||||||
func (t *MessageTrace) MarshalCBOR(w io.Writer) error {
|
func (t *MessageTrace) MarshalCBOR(w io.Writer) error {
|
||||||
if t == nil {
|
if t == nil {
|
||||||
@ -2343,6 +2343,23 @@ func (t *MessageTrace) MarshalCBOR(w io.Writer) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// t.GasLimit (uint64) (uint64)
|
||||||
|
|
||||||
|
if err := cw.WriteMajorTypeHeader(cbg.MajUnsignedInt, uint64(t.GasLimit)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// t.ReadOnly (bool) (bool)
|
||||||
|
if err := cbg.WriteBool(w, t.ReadOnly); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// t.CodeCid (cid.Cid) (struct)
|
||||||
|
|
||||||
|
if err := cbg.WriteCid(cw, t.CodeCid); err != nil {
|
||||||
|
return xerrors.Errorf("failed to write cid field t.CodeCid: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2365,7 +2382,7 @@ func (t *MessageTrace) UnmarshalCBOR(r io.Reader) (err error) {
|
|||||||
return fmt.Errorf("cbor input should be of type array")
|
return fmt.Errorf("cbor input should be of type array")
|
||||||
}
|
}
|
||||||
|
|
||||||
if extra != 6 {
|
if extra != 9 {
|
||||||
return fmt.Errorf("cbor input had wrong number of fields")
|
return fmt.Errorf("cbor input had wrong number of fields")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2444,6 +2461,49 @@ func (t *MessageTrace) UnmarshalCBOR(r io.Reader) (err error) {
|
|||||||
}
|
}
|
||||||
t.ParamsCodec = uint64(extra)
|
t.ParamsCodec = uint64(extra)
|
||||||
|
|
||||||
|
}
|
||||||
|
// t.GasLimit (uint64) (uint64)
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
maj, extra, err = cr.ReadHeader()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if maj != cbg.MajUnsignedInt {
|
||||||
|
return fmt.Errorf("wrong type for uint64 field")
|
||||||
|
}
|
||||||
|
t.GasLimit = uint64(extra)
|
||||||
|
|
||||||
|
}
|
||||||
|
// t.ReadOnly (bool) (bool)
|
||||||
|
|
||||||
|
maj, extra, err = cr.ReadHeader()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if maj != cbg.MajOther {
|
||||||
|
return fmt.Errorf("booleans must be major type 7")
|
||||||
|
}
|
||||||
|
switch extra {
|
||||||
|
case 20:
|
||||||
|
t.ReadOnly = false
|
||||||
|
case 21:
|
||||||
|
t.ReadOnly = true
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("booleans are either major type 7, value 20 or 21 (got %d)", extra)
|
||||||
|
}
|
||||||
|
// t.CodeCid (cid.Cid) (struct)
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
c, err := cbg.ReadCid(cr)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("failed to read cid field t.CodeCid: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.CodeCid = c
|
||||||
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,8 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/ipfs/go-cid"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-address"
|
"github.com/filecoin-project/go-address"
|
||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
"github.com/filecoin-project/go-state-types/exitcode"
|
"github.com/filecoin-project/go-state-types/exitcode"
|
||||||
@ -24,6 +26,9 @@ type MessageTrace struct {
|
|||||||
Method abi.MethodNum
|
Method abi.MethodNum
|
||||||
Params []byte
|
Params []byte
|
||||||
ParamsCodec uint64
|
ParamsCodec uint64
|
||||||
|
GasLimit uint64
|
||||||
|
ReadOnly bool
|
||||||
|
CodeCid cid.Cid
|
||||||
}
|
}
|
||||||
|
|
||||||
type ReturnTrace struct {
|
type ReturnTrace struct {
|
||||||
|
@ -4873,7 +4873,12 @@ Response:
|
|||||||
"Value": "0",
|
"Value": "0",
|
||||||
"Method": 1,
|
"Method": 1,
|
||||||
"Params": "Ynl0ZSBhcnJheQ==",
|
"Params": "Ynl0ZSBhcnJheQ==",
|
||||||
"ParamsCodec": 42
|
"ParamsCodec": 42,
|
||||||
|
"GasLimit": 42,
|
||||||
|
"ReadOnly": true,
|
||||||
|
"CodeCid": {
|
||||||
|
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"MsgRct": {
|
"MsgRct": {
|
||||||
"ExitCode": 0,
|
"ExitCode": 0,
|
||||||
@ -4897,7 +4902,12 @@ Response:
|
|||||||
"Value": "0",
|
"Value": "0",
|
||||||
"Method": 1,
|
"Method": 1,
|
||||||
"Params": "Ynl0ZSBhcnJheQ==",
|
"Params": "Ynl0ZSBhcnJheQ==",
|
||||||
"ParamsCodec": 42
|
"ParamsCodec": 42,
|
||||||
|
"GasLimit": 42,
|
||||||
|
"ReadOnly": true,
|
||||||
|
"CodeCid": {
|
||||||
|
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"MsgRct": {
|
"MsgRct": {
|
||||||
"ExitCode": 0,
|
"ExitCode": 0,
|
||||||
@ -5103,7 +5113,12 @@ Response:
|
|||||||
"Value": "0",
|
"Value": "0",
|
||||||
"Method": 1,
|
"Method": 1,
|
||||||
"Params": "Ynl0ZSBhcnJheQ==",
|
"Params": "Ynl0ZSBhcnJheQ==",
|
||||||
"ParamsCodec": 42
|
"ParamsCodec": 42,
|
||||||
|
"GasLimit": 42,
|
||||||
|
"ReadOnly": true,
|
||||||
|
"CodeCid": {
|
||||||
|
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"MsgRct": {
|
"MsgRct": {
|
||||||
"ExitCode": 0,
|
"ExitCode": 0,
|
||||||
@ -5127,7 +5142,12 @@ Response:
|
|||||||
"Value": "0",
|
"Value": "0",
|
||||||
"Method": 1,
|
"Method": 1,
|
||||||
"Params": "Ynl0ZSBhcnJheQ==",
|
"Params": "Ynl0ZSBhcnJheQ==",
|
||||||
"ParamsCodec": 42
|
"ParamsCodec": 42,
|
||||||
|
"GasLimit": 42,
|
||||||
|
"ReadOnly": true,
|
||||||
|
"CodeCid": {
|
||||||
|
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"MsgRct": {
|
"MsgRct": {
|
||||||
"ExitCode": 0,
|
"ExitCode": 0,
|
||||||
@ -6493,7 +6513,12 @@ Response:
|
|||||||
"Value": "0",
|
"Value": "0",
|
||||||
"Method": 1,
|
"Method": 1,
|
||||||
"Params": "Ynl0ZSBhcnJheQ==",
|
"Params": "Ynl0ZSBhcnJheQ==",
|
||||||
"ParamsCodec": 42
|
"ParamsCodec": 42,
|
||||||
|
"GasLimit": 42,
|
||||||
|
"ReadOnly": true,
|
||||||
|
"CodeCid": {
|
||||||
|
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"MsgRct": {
|
"MsgRct": {
|
||||||
"ExitCode": 0,
|
"ExitCode": 0,
|
||||||
@ -6517,7 +6542,12 @@ Response:
|
|||||||
"Value": "0",
|
"Value": "0",
|
||||||
"Method": 1,
|
"Method": 1,
|
||||||
"Params": "Ynl0ZSBhcnJheQ==",
|
"Params": "Ynl0ZSBhcnJheQ==",
|
||||||
"ParamsCodec": 42
|
"ParamsCodec": 42,
|
||||||
|
"GasLimit": 42,
|
||||||
|
"ReadOnly": true,
|
||||||
|
"CodeCid": {
|
||||||
|
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"MsgRct": {
|
"MsgRct": {
|
||||||
"ExitCode": 0,
|
"ExitCode": 0,
|
||||||
|
@ -287,6 +287,9 @@
|
|||||||
* [SyncUnmarkAllBad](#SyncUnmarkAllBad)
|
* [SyncUnmarkAllBad](#SyncUnmarkAllBad)
|
||||||
* [SyncUnmarkBad](#SyncUnmarkBad)
|
* [SyncUnmarkBad](#SyncUnmarkBad)
|
||||||
* [SyncValidateTipset](#SyncValidateTipset)
|
* [SyncValidateTipset](#SyncValidateTipset)
|
||||||
|
* [Trace](#Trace)
|
||||||
|
* [TraceBlock](#TraceBlock)
|
||||||
|
* [TraceReplayBlockTransactions](#TraceReplayBlockTransactions)
|
||||||
* [Wallet](#Wallet)
|
* [Wallet](#Wallet)
|
||||||
* [WalletBalance](#WalletBalance)
|
* [WalletBalance](#WalletBalance)
|
||||||
* [WalletDefaultAddress](#WalletDefaultAddress)
|
* [WalletDefaultAddress](#WalletDefaultAddress)
|
||||||
@ -6312,7 +6315,12 @@ Response:
|
|||||||
"Value": "0",
|
"Value": "0",
|
||||||
"Method": 1,
|
"Method": 1,
|
||||||
"Params": "Ynl0ZSBhcnJheQ==",
|
"Params": "Ynl0ZSBhcnJheQ==",
|
||||||
"ParamsCodec": 42
|
"ParamsCodec": 42,
|
||||||
|
"GasLimit": 42,
|
||||||
|
"ReadOnly": true,
|
||||||
|
"CodeCid": {
|
||||||
|
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"MsgRct": {
|
"MsgRct": {
|
||||||
"ExitCode": 0,
|
"ExitCode": 0,
|
||||||
@ -6336,7 +6344,12 @@ Response:
|
|||||||
"Value": "0",
|
"Value": "0",
|
||||||
"Method": 1,
|
"Method": 1,
|
||||||
"Params": "Ynl0ZSBhcnJheQ==",
|
"Params": "Ynl0ZSBhcnJheQ==",
|
||||||
"ParamsCodec": 42
|
"ParamsCodec": 42,
|
||||||
|
"GasLimit": 42,
|
||||||
|
"ReadOnly": true,
|
||||||
|
"CodeCid": {
|
||||||
|
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"MsgRct": {
|
"MsgRct": {
|
||||||
"ExitCode": 0,
|
"ExitCode": 0,
|
||||||
@ -6542,7 +6555,12 @@ Response:
|
|||||||
"Value": "0",
|
"Value": "0",
|
||||||
"Method": 1,
|
"Method": 1,
|
||||||
"Params": "Ynl0ZSBhcnJheQ==",
|
"Params": "Ynl0ZSBhcnJheQ==",
|
||||||
"ParamsCodec": 42
|
"ParamsCodec": 42,
|
||||||
|
"GasLimit": 42,
|
||||||
|
"ReadOnly": true,
|
||||||
|
"CodeCid": {
|
||||||
|
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"MsgRct": {
|
"MsgRct": {
|
||||||
"ExitCode": 0,
|
"ExitCode": 0,
|
||||||
@ -6566,7 +6584,12 @@ Response:
|
|||||||
"Value": "0",
|
"Value": "0",
|
||||||
"Method": 1,
|
"Method": 1,
|
||||||
"Params": "Ynl0ZSBhcnJheQ==",
|
"Params": "Ynl0ZSBhcnJheQ==",
|
||||||
"ParamsCodec": 42
|
"ParamsCodec": 42,
|
||||||
|
"GasLimit": 42,
|
||||||
|
"ReadOnly": true,
|
||||||
|
"CodeCid": {
|
||||||
|
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"MsgRct": {
|
"MsgRct": {
|
||||||
"ExitCode": 0,
|
"ExitCode": 0,
|
||||||
@ -8061,7 +8084,12 @@ Response:
|
|||||||
"Value": "0",
|
"Value": "0",
|
||||||
"Method": 1,
|
"Method": 1,
|
||||||
"Params": "Ynl0ZSBhcnJheQ==",
|
"Params": "Ynl0ZSBhcnJheQ==",
|
||||||
"ParamsCodec": 42
|
"ParamsCodec": 42,
|
||||||
|
"GasLimit": 42,
|
||||||
|
"ReadOnly": true,
|
||||||
|
"CodeCid": {
|
||||||
|
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"MsgRct": {
|
"MsgRct": {
|
||||||
"ExitCode": 0,
|
"ExitCode": 0,
|
||||||
@ -8085,7 +8113,12 @@ Response:
|
|||||||
"Value": "0",
|
"Value": "0",
|
||||||
"Method": 1,
|
"Method": 1,
|
||||||
"Params": "Ynl0ZSBhcnJheQ==",
|
"Params": "Ynl0ZSBhcnJheQ==",
|
||||||
"ParamsCodec": 42
|
"ParamsCodec": 42,
|
||||||
|
"GasLimit": 42,
|
||||||
|
"ReadOnly": true,
|
||||||
|
"CodeCid": {
|
||||||
|
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"MsgRct": {
|
"MsgRct": {
|
||||||
"ExitCode": 0,
|
"ExitCode": 0,
|
||||||
@ -8790,6 +8823,44 @@ Inputs:
|
|||||||
|
|
||||||
Response: `true`
|
Response: `true`
|
||||||
|
|
||||||
|
## Trace
|
||||||
|
|
||||||
|
|
||||||
|
### TraceBlock
|
||||||
|
TraceAPI related methods
|
||||||
|
|
||||||
|
Returns traces created at given block
|
||||||
|
|
||||||
|
|
||||||
|
Perms: read
|
||||||
|
|
||||||
|
Inputs:
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
"string value"
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
Response: `{}`
|
||||||
|
|
||||||
|
### TraceReplayBlockTransactions
|
||||||
|
Replays all transactions in a block returning the requested traces for each transaction
|
||||||
|
|
||||||
|
|
||||||
|
Perms: read
|
||||||
|
|
||||||
|
Inputs:
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
"string value",
|
||||||
|
[
|
||||||
|
"string value"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
Response: `{}`
|
||||||
|
|
||||||
## Wallet
|
## Wallet
|
||||||
|
|
||||||
|
|
||||||
|
@ -144,6 +144,8 @@ type TargetAPI interface {
|
|||||||
EthSubscribe(ctx context.Context, params jsonrpc.RawParams) (ethtypes.EthSubscriptionID, error)
|
EthSubscribe(ctx context.Context, params jsonrpc.RawParams) (ethtypes.EthSubscriptionID, error)
|
||||||
EthUnsubscribe(ctx context.Context, id ethtypes.EthSubscriptionID) (bool, error)
|
EthUnsubscribe(ctx context.Context, id ethtypes.EthSubscriptionID) (bool, error)
|
||||||
Web3ClientVersion(ctx context.Context) (string, 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)
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ TargetAPI = *new(api.FullNode) // gateway depends on latest
|
var _ TargetAPI = *new(api.FullNode) // gateway depends on latest
|
||||||
|
@ -21,14 +21,6 @@ import (
|
|||||||
"github.com/filecoin-project/lotus/chain/types/ethtypes"
|
"github.com/filecoin-project/lotus/chain/types/ethtypes"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (gw *Node) Web3ClientVersion(ctx context.Context) (string, error) {
|
|
||||||
if err := gw.limit(ctx, basicRateLimitTokens); err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
return gw.target.Web3ClientVersion(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (gw *Node) EthAccounts(ctx context.Context) ([]ethtypes.EthAddress, error) {
|
func (gw *Node) EthAccounts(ctx context.Context) ([]ethtypes.EthAddress, error) {
|
||||||
// gateway provides public API, so it can't hold user accounts
|
// gateway provides public API, so it can't hold user accounts
|
||||||
return []ethtypes.EthAddress{}, nil
|
return []ethtypes.EthAddress{}, nil
|
||||||
@ -582,6 +574,38 @@ func (gw *Node) EthUnsubscribe(ctx context.Context, id ethtypes.EthSubscriptionI
|
|||||||
return ok, nil
|
return ok, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (gw *Node) Web3ClientVersion(ctx context.Context) (string, error) {
|
||||||
|
if err := gw.limit(ctx, basicRateLimitTokens); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return gw.target.Web3ClientVersion(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gw *Node) TraceBlock(ctx context.Context, blkNum string) (interface{}, error) {
|
||||||
|
if err := gw.limit(ctx, stateRateLimitTokens); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := gw.checkBlkParam(ctx, blkNum, 0); err != nil {
|
||||||
|
return ethtypes.EthBlock{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return gw.target.TraceBlock(ctx, blkNum)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gw *Node) TraceReplayBlockTransactions(ctx context.Context, blkNum string, traceTypes []string) (interface{}, error) {
|
||||||
|
if err := gw.limit(ctx, stateRateLimitTokens); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := gw.checkBlkParam(ctx, blkNum, 0); err != nil {
|
||||||
|
return ethtypes.EthBlock{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return gw.target.TraceReplayBlockTransactions(ctx, blkNum, traceTypes)
|
||||||
|
}
|
||||||
|
|
||||||
var EthMaxFiltersPerConn = 16 // todo make this configurable
|
var EthMaxFiltersPerConn = 16 // todo make this configurable
|
||||||
|
|
||||||
func addUserFilterLimited(ctx context.Context, cb func() (ethtypes.EthFilterID, error)) (ethtypes.EthFilterID, error) {
|
func addUserFilterLimited(ctx context.Context, cb func() (ethtypes.EthFilterID, error)) (ethtypes.EthFilterID, error) {
|
||||||
|
@ -155,6 +155,7 @@ var ChainNode = Options(
|
|||||||
Override(new(stmgr.StateManagerAPI), rpcstmgr.NewRPCStateManager),
|
Override(new(stmgr.StateManagerAPI), rpcstmgr.NewRPCStateManager),
|
||||||
Override(new(full.EthModuleAPI), From(new(api.Gateway))),
|
Override(new(full.EthModuleAPI), From(new(api.Gateway))),
|
||||||
Override(new(full.EthEventAPI), From(new(api.Gateway))),
|
Override(new(full.EthEventAPI), From(new(api.Gateway))),
|
||||||
|
Override(new(full.EthTraceAPI), From(new(api.Gateway))),
|
||||||
),
|
),
|
||||||
|
|
||||||
// Full node API / service startup
|
// Full node API / service startup
|
||||||
@ -270,10 +271,12 @@ func ConfigFullNode(c interface{}) Option {
|
|||||||
If(cfg.Fevm.EnableEthRPC,
|
If(cfg.Fevm.EnableEthRPC,
|
||||||
Override(new(full.EthModuleAPI), modules.EthModuleAPI(cfg.Fevm)),
|
Override(new(full.EthModuleAPI), modules.EthModuleAPI(cfg.Fevm)),
|
||||||
Override(new(full.EthEventAPI), modules.EthEventAPI(cfg.Fevm)),
|
Override(new(full.EthEventAPI), modules.EthEventAPI(cfg.Fevm)),
|
||||||
|
Override(new(full.EthTraceAPI), modules.EthTraceAPI()),
|
||||||
),
|
),
|
||||||
If(!cfg.Fevm.EnableEthRPC,
|
If(!cfg.Fevm.EnableEthRPC,
|
||||||
Override(new(full.EthModuleAPI), &full.EthModuleDummy{}),
|
Override(new(full.EthModuleAPI), &full.EthModuleDummy{}),
|
||||||
Override(new(full.EthEventAPI), &full.EthModuleDummy{}),
|
Override(new(full.EthEventAPI), &full.EthModuleDummy{}),
|
||||||
|
Override(new(full.EthTraceAPI), &full.EthModuleDummy{}),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
|
@ -36,6 +36,7 @@ type FullNodeAPI struct {
|
|||||||
full.SyncAPI
|
full.SyncAPI
|
||||||
full.RaftAPI
|
full.RaftAPI
|
||||||
full.EthAPI
|
full.EthAPI
|
||||||
|
full.EthTraceAPI
|
||||||
|
|
||||||
DS dtypes.MetadataDS
|
DS dtypes.MetadataDS
|
||||||
NetworkName dtypes.NetworkName
|
NetworkName dtypes.NetworkName
|
||||||
|
@ -178,5 +178,14 @@ func (e *EthModuleDummy) EthUnsubscribe(ctx context.Context, id ethtypes.EthSubs
|
|||||||
return false, ErrModuleDisabled
|
return false, ErrModuleDisabled
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e *EthModuleDummy) TraceBlock(ctx context.Context, blkNum string) (interface{}, error) {
|
||||||
|
return nil, ErrModuleDisabled
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *EthModuleDummy) TraceReplayBlockTransactions(ctx context.Context, blkNum string, traceTypes []string) (interface{}, error) {
|
||||||
|
return nil, ErrModuleDisabled
|
||||||
|
}
|
||||||
|
|
||||||
var _ EthModuleAPI = &EthModuleDummy{}
|
var _ EthModuleAPI = &EthModuleDummy{}
|
||||||
var _ EthEventAPI = &EthModuleDummy{}
|
var _ EthEventAPI = &EthModuleDummy{}
|
||||||
|
var _ EthTraceAPI = &EthModuleDummy{}
|
||||||
|
273
node/impl/full/trace.go
Normal file
273
node/impl/full/trace.go
Normal file
@ -0,0 +1,273 @@
|
|||||||
|
package full
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"go.uber.org/fx"
|
||||||
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/api"
|
||||||
|
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||||
|
"github.com/filecoin-project/lotus/chain/store"
|
||||||
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
|
"github.com/filecoin-project/lotus/chain/types/ethtypes"
|
||||||
|
)
|
||||||
|
|
||||||
|
type EthTraceAPI interface {
|
||||||
|
TraceBlock(ctx context.Context, blkNum string) (interface{}, error)
|
||||||
|
TraceReplayBlockTransactions(ctx context.Context, blkNum string, traceTypes []string) (interface{}, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
_ EthTraceAPI = *new(api.FullNode)
|
||||||
|
)
|
||||||
|
|
||||||
|
type EthTrace struct {
|
||||||
|
fx.In
|
||||||
|
|
||||||
|
Chain *store.ChainStore
|
||||||
|
StateManager *stmgr.StateManager
|
||||||
|
|
||||||
|
ChainAPI
|
||||||
|
EthModuleAPI
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ EthTraceAPI = (*EthTrace)(nil)
|
||||||
|
|
||||||
|
type Trace struct {
|
||||||
|
Action Action `json:"action"`
|
||||||
|
Result Result `json:"result"`
|
||||||
|
Subtraces int `json:"subtraces"`
|
||||||
|
TraceAddress []int `json:"traceAddress"`
|
||||||
|
Type string `json:"Type"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type TraceBlock struct {
|
||||||
|
*Trace
|
||||||
|
BlockHash ethtypes.EthHash `json:"blockHash"`
|
||||||
|
BlockNumber int64 `json:"blockNumber"`
|
||||||
|
TransactionHash ethtypes.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"`
|
||||||
|
}
|
||||||
|
|
||||||
|
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"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Result struct {
|
||||||
|
GasUsed ethtypes.EthUint64 `json:"gasUsed"`
|
||||||
|
Output string `json:"output"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *EthTrace) TraceBlock(ctx context.Context, blkNum string) (interface{}, error) {
|
||||||
|
ts, err := e.getTipsetByBlockNr(ctx, blkNum, false)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, trace, err := e.StateManager.ExecutionTrace(ctx, ts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("failed to compute base state: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
tsParent, err := e.ChainAPI.ChainGetTipSetByHeight(ctx, ts.Height()+1, e.Chain.GetHeaviestTipSet().Key())
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("cannot get tipset at height: %v", ts.Height()+1)
|
||||||
|
}
|
||||||
|
|
||||||
|
msgs, err := e.ChainGetParentMessages(ctx, tsParent.Blocks()[0].Cid())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
cid, err := ts.Key().Cid()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
blkHash, err := ethtypes.EthHashFromCid(cid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
allTraces := make([]*TraceBlock, 0, len(trace))
|
||||||
|
for _, ir := range trace {
|
||||||
|
// ignore messages from f00
|
||||||
|
if ir.Msg.From.String() == "f00" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
idx := -1
|
||||||
|
for msgIdx, msg := range msgs {
|
||||||
|
if ir.Msg.From == msg.Message.From {
|
||||||
|
idx = msgIdx
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if idx == -1 {
|
||||||
|
log.Warnf("cannot resolve message index for cid: %s", ir.MsgCid)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
txHash, err := e.EthGetTransactionHashByCid(ctx, ir.MsgCid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if txHash == nil {
|
||||||
|
log.Warnf("cannot find transaction hash for cid %s", ir.MsgCid)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
traces := []*Trace{}
|
||||||
|
buildTraces(&traces, []int{}, ir.ExecutionTrace)
|
||||||
|
|
||||||
|
traceBlocks := make([]*TraceBlock, 0, len(trace))
|
||||||
|
for _, trace := range traces {
|
||||||
|
traceBlocks = append(traceBlocks, &TraceBlock{
|
||||||
|
Trace: trace,
|
||||||
|
BlockHash: blkHash,
|
||||||
|
BlockNumber: int64(ts.Height()),
|
||||||
|
TransactionHash: *txHash,
|
||||||
|
TransactionPosition: idx,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
allTraces = append(allTraces, traceBlocks...)
|
||||||
|
}
|
||||||
|
|
||||||
|
return allTraces, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *EthTrace) TraceReplayBlockTransactions(ctx context.Context, blkNum string, traceTypes []string) (interface{}, error) {
|
||||||
|
if len(traceTypes) != 1 || traceTypes[0] != "trace" {
|
||||||
|
return nil, fmt.Errorf("only 'trace' is supported")
|
||||||
|
}
|
||||||
|
|
||||||
|
ts, err := e.getTipsetByBlockNr(ctx, blkNum, false)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, trace, err := e.StateManager.ExecutionTrace(ctx, ts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("failed when calling ExecutionTrace: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
allTraces := make([]*TraceReplayBlockTransaction, 0, len(trace))
|
||||||
|
for _, ir := range trace {
|
||||||
|
// ignore messages from f00
|
||||||
|
if ir.Msg.From.String() == "f00" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
txHash, err := e.EthGetTransactionHashByCid(ctx, ir.MsgCid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if txHash == nil {
|
||||||
|
log.Warnf("cannot find transaction hash for cid %s", ir.MsgCid)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
t := TraceReplayBlockTransaction{
|
||||||
|
Output: hex.EncodeToString(ir.MsgRct.Return),
|
||||||
|
TransactionHash: *txHash,
|
||||||
|
StateDiff: nil,
|
||||||
|
VmTrace: nil,
|
||||||
|
}
|
||||||
|
|
||||||
|
buildTraces(&t.Trace, []int{}, ir.ExecutionTrace)
|
||||||
|
|
||||||
|
allTraces = append(allTraces, &t)
|
||||||
|
}
|
||||||
|
|
||||||
|
return allTraces, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// buildTraces recursively builds the traces for a given ExecutionTrace by walking the subcalls
|
||||||
|
func buildTraces(traces *[]*Trace, addr []int, et types.ExecutionTrace) {
|
||||||
|
callType := "call"
|
||||||
|
if et.Msg.ReadOnly {
|
||||||
|
callType = "staticcall"
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: add check for determining if this this should be delegatecall
|
||||||
|
if false {
|
||||||
|
callType = "delegatecall"
|
||||||
|
}
|
||||||
|
|
||||||
|
*traces = append(*traces, &Trace{
|
||||||
|
Action: Action{
|
||||||
|
CallType: callType,
|
||||||
|
From: et.Msg.From.String(),
|
||||||
|
To: et.Msg.To.String(),
|
||||||
|
Gas: ethtypes.EthUint64(et.Msg.GasLimit),
|
||||||
|
Input: hex.EncodeToString(et.Msg.Params),
|
||||||
|
Value: ethtypes.EthBigInt(et.Msg.Value),
|
||||||
|
},
|
||||||
|
Result: Result{
|
||||||
|
GasUsed: ethtypes.EthUint64(et.SumGas().TotalGas),
|
||||||
|
Output: hex.EncodeToString(et.MsgRct.Return),
|
||||||
|
},
|
||||||
|
Subtraces: len(et.Subcalls),
|
||||||
|
TraceAddress: addr,
|
||||||
|
Type: callType,
|
||||||
|
})
|
||||||
|
|
||||||
|
for i, call := range et.Subcalls {
|
||||||
|
buildTraces(traces, append(addr, i), call)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: refactor this to be shared code
|
||||||
|
func (e *EthTrace) getTipsetByBlockNr(ctx context.Context, blkParam string, strict bool) (*types.TipSet, error) {
|
||||||
|
if blkParam == "earliest" {
|
||||||
|
return nil, fmt.Errorf("block param \"earliest\" is not supported")
|
||||||
|
}
|
||||||
|
|
||||||
|
head := e.Chain.GetHeaviestTipSet()
|
||||||
|
switch blkParam {
|
||||||
|
case "pending":
|
||||||
|
return head, nil
|
||||||
|
case "latest":
|
||||||
|
parent, err := e.Chain.GetTipSetFromKey(ctx, head.Parents())
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("cannot get parent tipset")
|
||||||
|
}
|
||||||
|
return parent, nil
|
||||||
|
default:
|
||||||
|
var num ethtypes.EthUint64
|
||||||
|
err := num.UnmarshalJSON([]byte(`"` + blkParam + `"`))
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("cannot parse block number: %v", err)
|
||||||
|
}
|
||||||
|
if abi.ChainEpoch(num) > head.Height()-1 {
|
||||||
|
return nil, fmt.Errorf("requested a future epoch (beyond 'latest')")
|
||||||
|
}
|
||||||
|
ts, err := e.ChainAPI.ChainGetTipSetByHeight(ctx, abi.ChainEpoch(num), head.Key())
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("cannot get tipset at height: %v", num)
|
||||||
|
}
|
||||||
|
if strict && ts.Height() != abi.ChainEpoch(num) {
|
||||||
|
return nil, ErrNullRound
|
||||||
|
}
|
||||||
|
return ts, nil
|
||||||
|
}
|
||||||
|
}
|
19
node/modules/trace.go
Normal file
19
node/modules/trace.go
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
package modules
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||||
|
"github.com/filecoin-project/lotus/chain/store"
|
||||||
|
"github.com/filecoin-project/lotus/node/impl/full"
|
||||||
|
)
|
||||||
|
|
||||||
|
func EthTraceAPI() func(*store.ChainStore, *stmgr.StateManager, full.EthModuleAPI, full.ChainAPI) (*full.EthTrace, error) {
|
||||||
|
return func(cs *store.ChainStore, sm *stmgr.StateManager, evapi full.EthModuleAPI, chainapi full.ChainAPI) (*full.EthTrace, error) {
|
||||||
|
return &full.EthTrace{
|
||||||
|
Chain: cs,
|
||||||
|
StateManager: sm,
|
||||||
|
|
||||||
|
ChainAPI: chainapi,
|
||||||
|
EthModuleAPI: evapi,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user