Skip to content

Commit

Permalink
db2/BigTableEthRaw: add WithFallback
Browse files Browse the repository at this point in the history
  • Loading branch information
Tangui-Bitfly committed Oct 15, 2024
1 parent 2635a45 commit dcfaba1
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 13 deletions.
56 changes: 43 additions & 13 deletions backend/pkg/commons/db2/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"io"
"math/big"
Expand All @@ -14,17 +15,50 @@ import (
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common/hexutil"

"github.com/gobitfly/beaconchain/pkg/commons/db2/store"
)

var ttl = 2 * time.Second

var ErrNotFoundInCache = fmt.Errorf("cannot find hash in cache")

type EthClient interface {
ethereum.ChainReader
ethereum.ContractCaller
bind.ContractBackend
ethereum.ChainStateReader
}

type WithFallback struct {
roundTripper http.RoundTripper
fallback http.RoundTripper
}

func NewWithFallback(roundTripper http.RoundTripper, fallback http.RoundTripper) *WithFallback {
return &WithFallback{
roundTripper: roundTripper,
fallback: fallback,
}
}

func (r WithFallback) RoundTrip(request *http.Request) (*http.Response, error) {
resp, err := r.roundTripper.RoundTrip(request)
if err == nil {
// no fallback needed
return resp, nil
}

var e1 *json.SyntaxError
if !errors.As(err, &e1) &&
!errors.Is(err, ErrNotFoundInCache) &&
!errors.Is(err, store.ErrNotFound) {
return nil, err
}

return r.fallback.RoundTrip(request)
}

type BigTableEthRaw struct {
db RawStore

Expand All @@ -50,6 +84,9 @@ func (r *BigTableEthRaw) RoundTrip(request *http.Request) (*http.Response, error
if err != nil {
return nil, err
}
defer func() {
request.Body = io.NopCloser(bytes.NewBuffer(body))
}()
var messages []*jsonrpcMessage
var isSingle bool
if err := json.NewDecoder(bytes.NewReader(body)).Decode(&messages); err != nil {
Expand All @@ -64,10 +101,7 @@ func (r *BigTableEthRaw) RoundTrip(request *http.Request) (*http.Response, error
for _, message := range messages {
resp, err := r.handle(request.Context(), message)
if err != nil {
return &http.Response{
Body: io.NopCloser(bytes.NewBufferString(err.Error())),
StatusCode: http.StatusBadRequest,
}, nil
return nil, err
}
resps = append(resps, resp)
}
Expand All @@ -94,51 +128,47 @@ func (r *BigTableEthRaw) handle(ctx context.Context, message *jsonrpcMessage) (*
return nil, err
}

b, err := r.BlockByNumber(ctx, block)
respBody, err = r.BlockByNumber(ctx, block)
if err != nil {
return nil, err
}
respBody = b

case "debug_traceBlockByNumber":
block, err := hexutil.DecodeBig(args[0].(string))
if err != nil {
return nil, err
}

b, err := r.TraceBlockByNumber(ctx, block)
respBody, err = r.TraceBlockByNumber(ctx, block)
if err != nil {
return nil, err
}
respBody = b

case "eth_getBlockReceipts":
block, err := hexutil.DecodeBig(args[0].(string))
if err != nil {
return nil, err
}

b, err := r.BlockReceipts(ctx, block)
respBody, err = r.BlockReceipts(ctx, block)
if err != nil {
return nil, err
}
respBody = b

case "eth_getUncleByBlockHashAndIndex":
number, exist := r.hashToNumber.Load(args[0].(string))
if !exist {
return nil, fmt.Errorf("cannot find hash '%s' in cache", args[0].(string))
return nil, ErrNotFoundInCache
}

index, err := hexutil.DecodeBig(args[1].(string))
if err != nil {
return nil, err
}
b, err := r.UncleByBlockNumberAndIndex(ctx, number.(*big.Int), index.Int64())
respBody, err = r.UncleByBlockNumberAndIndex(ctx, number.(*big.Int), index.Int64())
if err != nil {
return nil, err
}
respBody = b
}
var resp jsonrpcMessage
_ = json.Unmarshal(respBody, &resp)
Expand Down
61 changes: 61 additions & 0 deletions backend/pkg/commons/db2/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,67 @@ func TestBigTableClient(t *testing.T) {
}
}

func TestBigTableClientWithFallback(t *testing.T) {
node := os.Getenv("ETH1_ERIGON_ENDPOINT")
if node == "" {
t.Skip("skipping test, set ETH1_ERIGON_ENDPOINT")
}

tests := []struct {
name string
block FullBlockRawData
}{
{
name: "test block",
block: testFullBlock,
},
}

client, admin := storetest.NewBigTable(t)
bg, err := store.NewBigTableWithClient(context.Background(), client, admin, raw)
if err != nil {
t.Fatal(err)
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
rawStore := NewRawStore(store.Wrap(bg, BlocRawTable, ""))

rpcClient, err := rpc.DialOptions(context.Background(), node, rpc.WithHTTPClient(&http.Client{
Transport: NewWithFallback(NewBigTableEthRaw(rawStore, tt.block.ChainID), http.DefaultTransport),
}))
if err != nil {
t.Fatal(err)
}
ethClient := ethclient.NewClient(rpcClient)

block, err := ethClient.BlockByNumber(context.Background(), big.NewInt(tt.block.BlockNumber))
if err != nil {
t.Fatalf("BlockByNumber() error = %v", err)
}
if got, want := block.Number().Int64(), tt.block.BlockNumber; got != want {
t.Errorf("got %v, want %v", got, want)
}

receipts, err := ethClient.BlockReceipts(context.Background(), rpc.BlockNumberOrHashWithNumber(rpc.BlockNumber(tt.block.BlockNumber)))
if err != nil {
t.Fatalf("BlockReceipts() error = %v", err)
}
if len(block.Transactions()) != 0 && len(receipts) == 0 {
t.Errorf("receipts should not be empty")
}

var traces []GethTraceCallResultWrapper
if err := rpcClient.Call(&traces, "debug_traceBlockByNumber", hexutil.EncodeBig(block.Number()), gethTracerArg); err != nil {
t.Fatalf("debug_traceBlockByNumber() error = %v", err)
}
if len(block.Transactions()) != 0 && len(traces) == 0 {
t.Errorf("traces should not be empty")
}
})
}
}

// TODO import those 3 from somewhere
var gethTracerArg = map[string]string{
"tracer": "callTracer",
Expand Down
5 changes: 5 additions & 0 deletions backend/pkg/commons/db2/store/bigtable.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import (
"golang.org/x/exp/maps"
)

var ErrNotFound = fmt.Errorf("not found")

const (
timeout = time.Minute // Timeout duration for Bigtable operations
)
Expand Down Expand Up @@ -246,6 +248,9 @@ func (b BigTableStore) GetRow(table, key string) (map[string][]byte, error) {
if err != nil {
return nil, fmt.Errorf("could not read rows: %v", err)
}
if len(data) == 0 {
return nil, ErrNotFound
}

return data, nil
}
Expand Down

0 comments on commit dcfaba1

Please sign in to comment.