Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions eth/api_backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import (
"github.com/ethereum/go-ethereum/eth/gasprice"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/internal/ethapi"
"github.com/ethereum/go-ethereum/miner"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rpc"
Expand Down Expand Up @@ -171,7 +172,7 @@ func (b *EthAPIBackend) StateAndHeaderByNumber(ctx context.Context, number rpc.B
return nil, nil, err
}
if header == nil {
return nil, nil, errors.New("header not found")
return nil, nil, ethapi.ErrHeaderNotFound
}
stateDb, err := b.eth.BlockChain().StateAt(header.Root)
return stateDb, header, err
Expand Down Expand Up @@ -382,8 +383,8 @@ func (b *EthAPIBackend) StateAtTransaction(ctx context.Context, block *types.Blo
return b.eth.stateAtTransaction(block, txIndex, reexec)
}

func (b *EthAPIBackend) SequencerRPCService() *rpc.Client {
return b.eth.seqRPCService
func (b *EthAPIBackend) HistoricalRPCService() *rpc.Client {
return b.eth.historicalRPCService
}

func (b *EthAPIBackend) Genesis() *types.Block {
Expand Down
101 changes: 101 additions & 0 deletions ethclient/ethclient_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,15 @@ import (
"errors"
"fmt"
"math/big"
"net"
"net/http"
"reflect"
"testing"
"time"

"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/internal/ethapi"

"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus/ethash"
Expand Down Expand Up @@ -211,7 +216,62 @@ var testTx2 = types.MustSignNewTx(testKey, types.LatestSigner(genesis.Config), &
To: &common.Address{2},
})

type mockHistoricalBackend struct{}

func (m *mockHistoricalBackend) Call(ctx context.Context, args ethapi.TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, overrides *ethapi.StateOverride) (hexutil.Bytes, error) {
num, ok := blockNrOrHash.Number()
if ok && num == 100 {
return hexutil.Bytes("test"), nil
}
return nil, ethapi.ErrHeaderNotFound
}

func (m *mockHistoricalBackend) EstimateGas(ctx context.Context, args ethapi.TransactionArgs, blockNrOrHash *rpc.BlockNumberOrHash) (hexutil.Uint64, error) {
num, ok := blockNrOrHash.Number()
if ok && num == 100 {
return hexutil.Uint64(12345), nil
}
return 0, ethapi.ErrHeaderNotFound
}

func newMockHistoricalBackend(t *testing.T) string {
s := rpc.NewServer()
err := node.RegisterApis([]rpc.API{
{
Namespace: "eth",
Service: new(mockHistoricalBackend),
Public: true,
Authenticated: false,
},
}, nil, s)
if err != nil {
t.Fatalf("error creating mock historical backend: %v", err)
}

hdlr := node.NewHTTPHandlerStack(s, []string{"*"}, []string{"*"}, nil)
mux := http.NewServeMux()
mux.Handle("/", hdlr)

listener, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
t.Fatalf("error creating mock historical backend listener: %v", err)
}

go func() {
httpS := &http.Server{Handler: mux}
httpS.Serve(listener)

t.Cleanup(func() {
httpS.Shutdown(context.Background())
})
}()

return fmt.Sprintf("http://%s", listener.Addr().String())
}

func newTestBackend(t *testing.T) (*node.Node, []*types.Block) {
histAddr := newMockHistoricalBackend(t)

// Generate test chain.
blocks := generateTestChain()

Expand All @@ -223,6 +283,7 @@ func newTestBackend(t *testing.T) (*node.Node, []*types.Block) {
// Create Ethereum Service
config := &ethconfig.Config{Genesis: genesis}
config.Ethash.PowMode = ethash.ModeFake
config.RollupHistoricalRPC = histAddr
ethservice, err := eth.New(n, config)
if err != nil {
t.Fatalf("can't create new ethereum service: %v", err)
Expand Down Expand Up @@ -294,6 +355,9 @@ func TestEthClient(t *testing.T) {
"TransactionSender": {
func(t *testing.T) { testTransactionSender(t, client) },
},
"EstimateGas": {
func(t *testing.T) { testEstimateGas(t, client) },
},
}

t.Parallel()
Expand Down Expand Up @@ -585,6 +649,14 @@ func testCallContract(t *testing.T, client *rpc.Client) {
if _, err := ec.PendingCallContract(context.Background(), msg); err != nil {
t.Fatalf("unexpected error: %v", err)
}
// Historical
histVal, err := ec.CallContract(context.Background(), msg, big.NewInt(100))
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if string(histVal) != "test" {
t.Fatalf("expected %s to equal test", string(histVal))
}
}

func testAtFunctions(t *testing.T, client *rpc.Client) {
Expand Down Expand Up @@ -692,6 +764,35 @@ func testTransactionSender(t *testing.T, client *rpc.Client) {
}
}

func testEstimateGas(t *testing.T, client *rpc.Client) {
ec := NewClient(client)

// EstimateGas
msg := ethereum.CallMsg{
From: testAddr,
To: &common.Address{},
Gas: 21000,
Value: big.NewInt(1),
}
gas, err := ec.EstimateGas(context.Background(), msg)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if gas != 21000 {
t.Fatalf("unexpected gas price: %v", gas)
}

// historical case
var res hexutil.Uint64
err = client.CallContext(context.Background(), &res, "eth_estimateGas", toCallArg(msg), rpc.BlockNumberOrHashWithNumber(100))
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if res != 12345 {
t.Fatalf("invalid result: %d", res)
}
}

func sendTransaction(ec *Client) error {
chainID, err := ec.ChainID(context.Background())
if err != nil {
Expand Down
20 changes: 18 additions & 2 deletions internal/ethapi/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ import (
"github.com/tyler-smith/go-bip39"
)

var ErrHeaderNotFound = errors.New("header not found")

// EthereumAPI provides an API to access Ethereum related information.
type EthereumAPI struct {
b Backend
Expand Down Expand Up @@ -1014,7 +1016,11 @@ func (e *revertError) ErrorData() interface{} {
// useful to execute and retrieve values.
func (s *BlockChainAPI) Call(ctx context.Context, args TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, overrides *StateOverride) (hexutil.Bytes, error) {
result, err := DoCall(ctx, s.b, args, blockNrOrHash, overrides, s.b.RPCEVMTimeout(), s.b.RPCGasCap())
if err != nil {
if errors.Is(err, ErrHeaderNotFound) && s.b.HistoricalRPCService() != nil {
var histResult hexutil.Bytes
err = s.b.HistoricalRPCService().CallContext(ctx, &histResult, "eth_call", args, blockNrOrHash, overrides)
return histResult, err
} else if err != nil {
return nil, err
}
// If the result contains a revert reason, try to unpack and return it.
Expand Down Expand Up @@ -1151,7 +1157,17 @@ func (s *BlockChainAPI) EstimateGas(ctx context.Context, args TransactionArgs, b
if blockNrOrHash != nil {
bNrOrHash = *blockNrOrHash
}
return DoEstimateGas(ctx, s.b, args, bNrOrHash, s.b.RPCGasCap())

res, err := DoEstimateGas(ctx, s.b, args, bNrOrHash, s.b.RPCGasCap())
if errors.Is(err, ErrHeaderNotFound) && s.b.HistoricalRPCService() != nil {
var result hexutil.Uint64
err := s.b.HistoricalRPCService().CallContext(ctx, &result, "eth_estimateGas", args, blockNrOrHash)
return result, err
} else if err != nil {
return 0, err
}

return res, err
}

// RPCMarshalHeader converts the given header to the RPC output .
Expand Down
2 changes: 1 addition & 1 deletion internal/ethapi/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ type Backend interface {

ChainConfig() *params.ChainConfig
Engine() consensus.Engine
SequencerRPCService() *rpc.Client
HistoricalRPCService() *rpc.Client
Genesis() *types.Block

// eth/filters needs to be initialized from this backend type, so methods needed by
Expand Down
6 changes: 3 additions & 3 deletions internal/ethapi/transaction_args_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,6 @@ func (b *backendMock) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent)
return nil
}

func (b *backendMock) Engine() consensus.Engine { return nil }
func (b *backendMock) SequencerRPCService() *rpc.Client { return nil }
func (b *backendMock) Genesis() *types.Block { return nil }
func (b *backendMock) Engine() consensus.Engine { return nil }
func (b *backendMock) HistoricalRPCService() *rpc.Client { return nil }
func (b *backendMock) Genesis() *types.Block { return nil }
4 changes: 2 additions & 2 deletions les/api_backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -330,8 +330,8 @@ func (b *LesApiBackend) StateAtTransaction(ctx context.Context, block *types.Blo
return b.eth.stateAtTransaction(ctx, block, txIndex, reexec)
}

func (b *LesApiBackend) SequencerRPCService() *rpc.Client {
return b.eth.seqRPCService
func (b *LesApiBackend) HistoricalRPCService() *rpc.Client {
return b.eth.historicalRPCService
}

func (b *LesApiBackend) Genesis() *types.Block {
Expand Down