Skip to content

Commit

Permalink
Add historical endpoint to TraceTransaction (ethereum#20)
Browse files Browse the repository at this point in the history
Co-authored-by: Matthew Slipper <[email protected]>
  • Loading branch information
2 people authored and protolambda committed Nov 4, 2022
1 parent a6b467f commit 5333920
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 13 deletions.
34 changes: 29 additions & 5 deletions eth/tracers/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
"sync"
"time"

"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/consensus"
Expand Down Expand Up @@ -137,7 +138,7 @@ func (api *API) blockByNumber(ctx context.Context, number rpc.BlockNumber) (*typ
return nil, err
}
if block == nil {
return nil, fmt.Errorf("block #%d not found", number)
return nil, fmt.Errorf("block #%d %w", number, ethereum.NotFound)
}
return block, nil
}
Expand All @@ -150,7 +151,7 @@ func (api *API) blockByHash(ctx context.Context, hash common.Hash) (*types.Block
return nil, err
}
if block == nil {
return nil, fmt.Errorf("block %s not found", hash.Hex())
return nil, fmt.Errorf("block %s %w", hash.Hex(), ethereum.NotFound)
}
return block, nil
}
Expand Down Expand Up @@ -455,7 +456,14 @@ func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed
// EVM and returns them as a JSON object.
func (api *API) TraceBlockByNumber(ctx context.Context, number rpc.BlockNumber, config *TraceConfig) ([]*txTraceResult, error) {
block, err := api.blockByNumber(ctx, number)
if err != nil {
if errors.Is(err, ethereum.NotFound) && api.backend.HistoricalRPCService() != nil {
var histResult []*txTraceResult
err = api.backend.HistoricalRPCService().CallContext(ctx, &histResult, "debug_traceBlockByNumber", number, config)
if err != nil && err.Error() == "not found" {
return nil, fmt.Errorf("block #%d %w", number, ethereum.NotFound)
}
return histResult, err
} else if err != nil {
return nil, err
}
return api.traceBlock(ctx, block, config)
Expand All @@ -465,7 +473,14 @@ func (api *API) TraceBlockByNumber(ctx context.Context, number rpc.BlockNumber,
// EVM and returns them as a JSON object.
func (api *API) TraceBlockByHash(ctx context.Context, hash common.Hash, config *TraceConfig) ([]*txTraceResult, error) {
block, err := api.blockByHash(ctx, hash)
if err != nil {
if errors.Is(err, ethereum.NotFound) && api.backend.HistoricalRPCService() != nil {
var histResult []*txTraceResult
err = api.backend.HistoricalRPCService().CallContext(ctx, &histResult, "debug_traceBlockByHash", hash, config)
if err != nil && err.Error() == "not found" {
return nil, fmt.Errorf("block #%d %w", hash, ethereum.NotFound)
}
return histResult, err
} else if err != nil {
return nil, err
}
return api.traceBlock(ctx, block, config)
Expand Down Expand Up @@ -807,10 +822,19 @@ func containsTx(block *types.Block, hash common.Hash) bool {
// TraceTransaction returns the structured logs created during the execution of EVM
// and returns them as a JSON object.
func (api *API) TraceTransaction(ctx context.Context, hash common.Hash, config *TraceConfig) (interface{}, error) {
_, blockHash, blockNumber, index, err := api.backend.GetTransaction(ctx, hash)
// GetTransaction returns 0 for the blocknumber if the transaction is not found
tx, blockHash, blockNumber, index, err := api.backend.GetTransaction(ctx, hash)
if err != nil {
return nil, err
}
if tx == nil {
var histResult []*txTraceResult
err = api.backend.HistoricalRPCService().CallContext(ctx, &histResult, "debug_traceTransaction", hash, config)
if err != nil && err.Error() == "not found" {
return nil, fmt.Errorf("transaction %s %w", hash, ethereum.NotFound)
}
return histResult, err
}
// It shouldn't happen in practice.
if blockNumber == 0 {
return nil, errors.New("genesis is not traceable")
Expand Down
56 changes: 48 additions & 8 deletions eth/tracers/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,6 @@ import (
"testing"
"time"

"github.com/ethereum/go-ethereum/node"

"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
Expand All @@ -48,25 +46,50 @@ import (
"github.com/ethereum/go-ethereum/eth/tracers/logger"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/internal/ethapi"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rpc"
)

var (
errStateNotFound = errors.New("state not found")
errBlockNotFound = errors.New("block not found")
errTransactionNotFound = errors.New("transaction not found")
errStateNotFound = errors.New("state not found")
errBlockNotFound = errors.New("block not found")
)

type mockHistoricalBackend struct{}

func (m *mockHistoricalBackend) Dummy() {} // dummy RPC method
func (m *mockHistoricalBackend) TraceBlockByHash(ctx context.Context, hash common.Hash, config *TraceConfig) ([]*txTraceResult, error) {
if hash == common.HexToHash("0xabba") {
result := make([]*txTraceResult, 1)
result[0] = &txTraceResult{Result: "0xabba"}
return result, nil
}
return nil, ethereum.NotFound
}

func (m *mockHistoricalBackend) TraceBlockByNumber(ctx context.Context, number rpc.BlockNumber, config *TraceConfig) ([]*txTraceResult, error) {
if number == 999 {
result := make([]*txTraceResult, 1)
result[0] = &txTraceResult{Result: "0xabba"}
return result, nil
}
return nil, ethereum.NotFound
}

func (m *mockHistoricalBackend) TraceTransaction(ctx context.Context, hash common.Hash, config *TraceConfig) (interface{}, error) {
if hash == common.HexToHash("0xACDC") {
result := make([]*txTraceResult, 1)
result[0] = &txTraceResult{Result: "0x8888"}
return result, nil
}
return nil, ethereum.NotFound
}

func newMockHistoricalBackend(t *testing.T) string {
s := rpc.NewServer()
err := node.RegisterApis([]rpc.API{
{
Namespace: "eth",
Namespace: "debug",
Service: new(mockHistoricalBackend),
Public: true,
Authenticated: false,
Expand Down Expand Up @@ -172,7 +195,7 @@ func (b *testBackend) BlockByNumber(ctx context.Context, number rpc.BlockNumber)
func (b *testBackend) GetTransaction(ctx context.Context, txHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error) {
tx, hash, blockNumber, index := rawdb.ReadTransaction(b.chaindb, txHash)
if tx == nil {
return nil, common.Hash{}, 0, 0, errTransactionNotFound
return nil, common.Hash{}, 0, 0, nil
}
return tx, hash, blockNumber, index, nil
}
Expand Down Expand Up @@ -424,6 +447,18 @@ func TestTraceTransaction(t *testing.T) {
}) {
t.Error("Transaction tracing result is different")
}

// test TraceTransaction for a historical transaction
result2, err := api.TraceTransaction(context.Background(), common.HexToHash("0xACDC"), nil)
resBytes, _ := json.Marshal(result2)
have2 := string(resBytes)
if err != nil {
t.Errorf("want no error, have %v", err)
}
want2 := `[{"result":"0x8888"}]`
if have2 != want2 {
t.Errorf("test result mismatch, have\n%v\n, want\n%v\n", have2, want2)
}
}

func TestTraceBlock(t *testing.T) {
Expand Down Expand Up @@ -472,6 +507,11 @@ func TestTraceBlock(t *testing.T) {
blockNumber: rpc.BlockNumber(genBlocks + 1),
expectErr: fmt.Errorf("block #%d %w", genBlocks+1, ethereum.NotFound),
},
// Optimism: Trace block on the historical chain
{
blockNumber: rpc.BlockNumber(999),
want: `[{"result":"0xabba"}]`,
},
// Trace latest block
{
blockNumber: rpc.LatestBlockNumber,
Expand Down

0 comments on commit 5333920

Please sign in to comment.