diff --git a/client/client.go b/client/client.go index 7c543ad0..b55854ae 100644 --- a/client/client.go +++ b/client/client.go @@ -25,6 +25,7 @@ type Client interface { TransactionByHash(context.Context, ethcommon.Hash) (*ethtypes.Transaction, bool, error) TransactionReceipt(context.Context, ethcommon.Hash) (*ethtypes.Receipt, error) TraceTransaction(context.Context, string) (*Call, []*FlatCall, error) + TraceBlockByHash(context.Context, string) ([]*Call, [][]*FlatCall, error) SendTransaction(context.Context, *ethtypes.Transaction) error BalanceAt(context.Context, ethcommon.Address, *big.Int) (*big.Int, error) NonceAt(context.Context, ethcommon.Address, *big.Int) (uint64, error) diff --git a/client/eth.go b/client/eth.go index 928bb63c..779c40a3 100644 --- a/client/eth.go +++ b/client/eth.go @@ -54,13 +54,35 @@ func (c *EthClient) TxPoolContent(ctx context.Context) (*TxPoolContent, error) { // TraceTransaction returns a transaction trace func (c *EthClient) TraceTransaction(ctx context.Context, hash string) (*Call, []*FlatCall, error) { - result := &Call{} + var result Call args := []interface{}{hash, c.traceConfig} - err := c.rpc.SendJSONRPCRequest(ctx, prefixEth, "debug_traceTransaction", args, &result) - if err != nil { + if err := c.rpc.SendJSONRPCRequest(ctx, prefixEth, "debug_traceTransaction", args, &result); err != nil { return nil, nil, err } + flattened := result.init() + + return &result, flattened, nil +} + +// TraceBlockByHash returns the transaction traces of all transactions in the block +func (c *EthClient) TraceBlockByHash(ctx context.Context, hash string) ([]*Call, [][]*FlatCall, error) { + var raw []struct { + *Call `json:"result"` + } + + args := []interface{}{hash, c.traceConfig} + if err := c.rpc.SendJSONRPCRequest(ctx, prefixEth, "debug_traceBlockByHash", args, &raw); err != nil { + return nil, nil, err + } + + result := make([]*Call, len(raw)) + flattened := make([][]*FlatCall, len(raw)) + for i, tx := range raw { + result[i] = tx.Call + flattened[i] = tx.Call.init() + } + return result, flattened, nil } diff --git a/mocks/client/client.go b/mocks/client/client.go index 28936509..e6327f3a 100644 --- a/mocks/client/client.go +++ b/mocks/client/client.go @@ -352,6 +352,38 @@ func (_m *Client) SuggestGasPrice(_a0 context.Context) (*big.Int, error) { return r0, r1 } +// TraceBlockByHash provides a mock function with given fields: _a0, _a1 +func (_m *Client) TraceBlockByHash(_a0 context.Context, _a1 string) ([]*client.Call, [][]*client.FlatCall, error) { + ret := _m.Called(_a0, _a1) + + var r0 []*client.Call + if rf, ok := ret.Get(0).(func(context.Context, string) []*client.Call); ok { + r0 = rf(_a0, _a1) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*client.Call) + } + } + + var r1 [][]*client.FlatCall + if rf, ok := ret.Get(1).(func(context.Context, string) [][]*client.FlatCall); ok { + r1 = rf(_a0, _a1) + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).([][]*client.FlatCall) + } + } + + var r2 error + if rf, ok := ret.Get(2).(func(context.Context, string) error); ok { + r2 = rf(_a0, _a1) + } else { + r2 = ret.Error(2) + } + + return r0, r1, r2 +} + // TraceTransaction provides a mock function with given fields: _a0, _a1 func (_m *Client) TraceTransaction(_a0 context.Context, _a1 string) (*client.Call, []*client.FlatCall, error) { ret := _m.Called(_a0, _a1) diff --git a/service/service_block.go b/service/service_block.go index 20ae0a61..6c98602d 100644 --- a/service/service_block.go +++ b/service/service_block.go @@ -141,8 +141,13 @@ func (s *BlockService) BlockTransaction( return nil, nil } - transaction, terr := s.fetchTransaction(ctx, tx, header) + trace, flattened, err := s.client.TraceTransaction(ctx, tx.Hash().String()) if err != nil { + return nil, wrapError(errClientError, err) + } + + transaction, terr := s.fetchTransaction(ctx, tx, header, trace, flattened) + if terr != nil { return nil, terr } @@ -157,11 +162,17 @@ func (s *BlockService) fetchTransactions( ) ([]*types.Transaction, *types.Error) { transactions := []*types.Transaction{} - for _, tx := range block.Transactions() { - transaction, err := s.fetchTransaction(ctx, tx, block.Header()) - if err != nil { - return nil, err + trace, flattened, err := s.client.TraceBlockByHash(ctx, block.Hash().String()) + if err != nil { + return nil, wrapError(errClientError, err) + } + + for i, tx := range block.Transactions() { + transaction, terr := s.fetchTransaction(ctx, tx, block.Header(), trace[i], flattened[i]) + if terr != nil { + return nil, terr } + transactions = append(transactions, transaction) } @@ -172,6 +183,8 @@ func (s *BlockService) fetchTransaction( ctx context.Context, tx *corethTypes.Transaction, header *corethTypes.Header, + trace *client.Call, + flattened []*client.FlatCall, ) (*types.Transaction, *types.Error) { msg, err := tx.AsMessage(s.config.Signer(), header.BaseFee) if err != nil { @@ -183,11 +196,6 @@ func (s *BlockService) fetchTransaction( return nil, wrapError(errClientError, err) } - trace, flattened, err := s.client.TraceTransaction(ctx, tx.Hash().String()) - if err != nil { - return nil, wrapError(errClientError, err) - } - transaction, err := mapper.Transaction(header, tx, &msg, receipt, trace, flattened, s.client, s.config.IsAnalyticsMode(), s.config.TokenWhiteList, s.config.IndexUnknownTokens) if err != nil { return nil, wrapError(errInternalError, err)