Commit 8e4b0ee0 authored by inphi's avatar inphi

cleanup

parent c46d04cb
...@@ -3,7 +3,6 @@ package proxyd ...@@ -3,7 +3,6 @@ package proxyd
import ( import (
"context" "context"
"encoding/json" "encoding/json"
"errors"
"github.com/go-redis/redis/v8" "github.com/go-redis/redis/v8"
"github.com/golang/snappy" "github.com/golang/snappy"
...@@ -21,11 +20,6 @@ const ( ...@@ -21,11 +20,6 @@ const (
numBlockConfirmations = 50 numBlockConfirmations = 50
) )
var (
errInvalidBlockByNumberParams = errors.New("invalid eth_getBlockByNumber params")
errUnavailableBlockNumSyncer = errors.New("getLatestBlockFn not set for required RPC")
)
type cache struct { type cache struct {
lru *lru.Cache lru *lru.Cache
} }
...@@ -106,7 +100,11 @@ func (c *rpcCache) GetRPC(ctx context.Context, req *RPCReq) (*RPCRes, error) { ...@@ -106,7 +100,11 @@ func (c *rpcCache) GetRPC(ctx context.Context, req *RPCReq) (*RPCRes, error) {
if handler == nil { if handler == nil {
return nil, nil return nil, nil
} }
if !handler.IsCacheable(req) { cacheable, err := handler.IsCacheable(req)
if err != nil {
return nil, err
}
if !cacheable {
return nil, nil return nil, nil
} }
...@@ -137,10 +135,18 @@ func (c *rpcCache) PutRPC(ctx context.Context, req *RPCReq, res *RPCRes) error { ...@@ -137,10 +135,18 @@ func (c *rpcCache) PutRPC(ctx context.Context, req *RPCReq, res *RPCRes) error {
if handler == nil { if handler == nil {
return nil return nil
} }
if !handler.IsCacheable(req) { cacheable, err := handler.IsCacheable(req)
if err != nil {
return err
}
if !cacheable {
return nil return nil
} }
if handler.RequiresUnconfirmedBlocks(ctx, req) { requiresConfirmations, err := handler.RequiresUnconfirmedBlocks(ctx, req)
if err != nil {
return err
}
if requiresConfirmations {
return nil return nil
} }
......
...@@ -243,10 +243,10 @@ func TestRPCCacheEthGetBlockByNumberInvalidRequest(t *testing.T) { ...@@ -243,10 +243,10 @@ func TestRPCCacheEthGetBlockByNumberInvalidRequest(t *testing.T) {
} }
err := cache.PutRPC(ctx, req, res) err := cache.PutRPC(ctx, req, res)
require.NoError(t, err) require.Error(t, err)
cachedRes, err := cache.GetRPC(ctx, req) cachedRes, err := cache.GetRPC(ctx, req)
require.NoError(t, err) require.Error(t, err)
require.Nil(t, cachedRes) require.Nil(t, cachedRes)
} }
...@@ -269,7 +269,7 @@ func TestRPCCacheEthGetBlockRangeForRecentBlocks(t *testing.T) { ...@@ -269,7 +269,7 @@ func TestRPCCacheEthGetBlockRangeForRecentBlocks(t *testing.T) {
req: &RPCReq{ req: &RPCReq{
JSONRPC: "2.0", JSONRPC: "2.0",
Method: "eth_getBlockRange", Method: "eth_getBlockRange",
Params: []byte(`["0xfff", "0x1000", false]`), Params: []byte(`["0x1", "0x1000", false]`),
ID: ID, ID: ID,
}, },
res: &RPCRes{ res: &RPCRes{
...@@ -345,22 +345,49 @@ func TestRPCCacheEthGetBlockRangeInvalidRequest(t *testing.T) { ...@@ -345,22 +345,49 @@ func TestRPCCacheEthGetBlockRangeInvalidRequest(t *testing.T) {
cache := newRPCCache(newMemoryCache(), fn) cache := newRPCCache(newMemoryCache(), fn)
ID := []byte(strconv.Itoa(1)) ID := []byte(strconv.Itoa(1))
req := &RPCReq{ rpcs := []struct {
JSONRPC: "2.0", req *RPCReq
Method: "eth_getBlockRange", res *RPCRes
Params: []byte(`["0x1", "0x2"]`), // missing required boolean param name string
ID: ID, }{
} {
res := &RPCRes{ req: &RPCReq{
JSONRPC: "2.0", JSONRPC: "2.0",
Result: `[{"number": "0x1"}, {"number": "0x2"}]`, Method: "eth_getBlockRange",
ID: ID, Params: []byte(`["0x1", "0x2"]`), // missing required boolean param
ID: ID,
},
res: &RPCRes{
JSONRPC: "2.0",
Result: `[{"number": "0x1"}, {"number": "0x2"}]`,
ID: ID,
},
name: "missing boolean param",
},
{
req: &RPCReq{
JSONRPC: "2.0",
Method: "eth_getBlockRange",
Params: []byte(`["abc", "0x2", true]`), // invalid block hex
ID: ID,
},
res: &RPCRes{
JSONRPC: "2.0",
Result: `[{"number": "0x1"}, {"number": "0x2"}]`,
ID: ID,
},
name: "invalid block hex",
},
} }
err := cache.PutRPC(ctx, req, res) for _, rpc := range rpcs[1:] {
require.NoError(t, err) t.Run(rpc.name, func(t *testing.T) {
err := cache.PutRPC(ctx, rpc.req, rpc.res)
require.Error(t, err)
cachedRes, err := cache.GetRPC(ctx, req) cachedRes, err := cache.GetRPC(ctx, rpc.req)
require.NoError(t, err) require.Error(t, err)
require.Nil(t, cachedRes) require.Nil(t, cachedRes)
})
}
} }
...@@ -3,15 +3,18 @@ package proxyd ...@@ -3,15 +3,18 @@ package proxyd
import ( import (
"context" "context"
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/hexutil"
) )
var errInvalidRPCParams = errors.New("invalid RPC params")
type RPCMethodHandler interface { type RPCMethodHandler interface {
CacheKey(req *RPCReq) string CacheKey(req *RPCReq) string
IsCacheable(req *RPCReq) bool IsCacheable(req *RPCReq) (bool, error)
RequiresUnconfirmedBlocks(ctx context.Context, req *RPCReq) bool RequiresUnconfirmedBlocks(ctx context.Context, req *RPCReq) (bool, error)
} }
type StaticRPCMethodHandler struct { type StaticRPCMethodHandler struct {
...@@ -22,9 +25,9 @@ func (s *StaticRPCMethodHandler) CacheKey(req *RPCReq) string { ...@@ -22,9 +25,9 @@ func (s *StaticRPCMethodHandler) CacheKey(req *RPCReq) string {
return fmt.Sprintf("method:%s", s.method) return fmt.Sprintf("method:%s", s.method)
} }
func (s *StaticRPCMethodHandler) IsCacheable(*RPCReq) bool { return true } func (s *StaticRPCMethodHandler) IsCacheable(*RPCReq) (bool, error) { return true, nil }
func (s *StaticRPCMethodHandler) RequiresUnconfirmedBlocks(context.Context, *RPCReq) bool { func (s *StaticRPCMethodHandler) RequiresUnconfirmedBlocks(context.Context, *RPCReq) (bool, error) {
return false return false, nil
} }
type EthGetBlockByNumberMethod struct { type EthGetBlockByNumberMethod struct {
...@@ -39,34 +42,34 @@ func (e *EthGetBlockByNumberMethod) CacheKey(req *RPCReq) string { ...@@ -39,34 +42,34 @@ func (e *EthGetBlockByNumberMethod) CacheKey(req *RPCReq) string {
return fmt.Sprintf("method:eth_getBlockByNumber:%s:%t", input, includeTx) return fmt.Sprintf("method:eth_getBlockByNumber:%s:%t", input, includeTx)
} }
func (e *EthGetBlockByNumberMethod) IsCacheable(req *RPCReq) bool { func (e *EthGetBlockByNumberMethod) IsCacheable(req *RPCReq) (bool, error) {
blockNum, _, err := decodeGetBlockByNumberParams(req.Params) blockNum, _, err := decodeGetBlockByNumberParams(req.Params)
if err != nil { if err != nil {
return false return false, err
} }
return !isBlockDependentParam(blockNum) return !isBlockDependentParam(blockNum), nil
} }
func (e *EthGetBlockByNumberMethod) RequiresUnconfirmedBlocks(ctx context.Context, req *RPCReq) bool { func (e *EthGetBlockByNumberMethod) RequiresUnconfirmedBlocks(ctx context.Context, req *RPCReq) (bool, error) {
curBlock, err := e.getLatestBlockNumFn(ctx) curBlock, err := e.getLatestBlockNumFn(ctx)
if err != nil { if err != nil {
return false return false, err
} }
blockInput, _, err := decodeGetBlockByNumberParams(req.Params) blockInput, _, err := decodeGetBlockByNumberParams(req.Params)
if err != nil { if err != nil {
return false return false, err
} }
if isBlockDependentParam(blockInput) { if isBlockDependentParam(blockInput) {
return true return true, nil
} }
if blockInput == "earliest" { if blockInput == "earliest" {
return false return false, nil
} }
blockNum, err := decodeBlockInput(blockInput) blockNum, err := decodeBlockInput(blockInput)
if err != nil { if err != nil {
return false return false, err
} }
return curBlock <= blockNum+numBlockConfirmations return curBlock <= blockNum+numBlockConfirmations, nil
} }
type EthGetBlockRangeMethod struct { type EthGetBlockRangeMethod struct {
...@@ -81,39 +84,50 @@ func (e *EthGetBlockRangeMethod) CacheKey(req *RPCReq) string { ...@@ -81,39 +84,50 @@ func (e *EthGetBlockRangeMethod) CacheKey(req *RPCReq) string {
return fmt.Sprintf("method:eth_getBlockRange:%s:%s:%t", start, end, includeTx) return fmt.Sprintf("method:eth_getBlockRange:%s:%s:%t", start, end, includeTx)
} }
func (e *EthGetBlockRangeMethod) IsCacheable(req *RPCReq) bool { func (e *EthGetBlockRangeMethod) IsCacheable(req *RPCReq) (bool, error) {
start, end, _, err := decodeGetBlockRangeParams(req.Params) start, end, _, err := decodeGetBlockRangeParams(req.Params)
if err != nil { if err != nil {
return false return false, err
} }
return !isBlockDependentParam(start) && !isBlockDependentParam(end) return !isBlockDependentParam(start) && !isBlockDependentParam(end), nil
} }
func (e *EthGetBlockRangeMethod) RequiresUnconfirmedBlocks(ctx context.Context, req *RPCReq) bool { func (e *EthGetBlockRangeMethod) RequiresUnconfirmedBlocks(ctx context.Context, req *RPCReq) (bool, error) {
curBlock, err := e.getLatestBlockNumFn(ctx) curBlock, err := e.getLatestBlockNumFn(ctx)
if err != nil { if err != nil {
return false return false, err
} }
start, end, _, err := decodeGetBlockRangeParams(req.Params) start, end, _, err := decodeGetBlockRangeParams(req.Params)
if err != nil { if err != nil {
return false return false, err
} }
if isBlockDependentParam(start) || isBlockDependentParam(end) { if isBlockDependentParam(start) || isBlockDependentParam(end) {
return true return true, nil
} }
if start == "earliest" && end == "earliest" { if start == "earliest" && end == "earliest" {
return false return false, nil
} }
startNum, err := decodeBlockInput(start)
if err != nil { if start != "earliest" {
return false startNum, err := decodeBlockInput(start)
if err != nil {
return false, err
}
if curBlock <= startNum+numBlockConfirmations {
return true, nil
}
} }
endNum, err := decodeBlockInput(end) if end != "earliest" {
if err != nil { endNum, err := decodeBlockInput(end)
return false if err != nil {
return false, err
}
if curBlock <= endNum+numBlockConfirmations {
return true, nil
}
} }
return curBlock <= startNum+numBlockConfirmations || curBlock <= endNum+numBlockConfirmations return false, nil
} }
func isBlockDependentParam(s string) bool { func isBlockDependentParam(s string) bool {
...@@ -126,15 +140,18 @@ func decodeGetBlockByNumberParams(params json.RawMessage) (string, bool, error) ...@@ -126,15 +140,18 @@ func decodeGetBlockByNumberParams(params json.RawMessage) (string, bool, error)
return "", false, err return "", false, err
} }
if len(list) != 2 { if len(list) != 2 {
return "", false, errInvalidBlockByNumberParams return "", false, errInvalidRPCParams
} }
blockNum, ok := list[0].(string) blockNum, ok := list[0].(string)
if !ok { if !ok {
return "", false, errInvalidBlockByNumberParams return "", false, errInvalidRPCParams
} }
includeTx, ok := list[1].(bool) includeTx, ok := list[1].(bool)
if !ok { if !ok {
return "", false, errInvalidBlockByNumberParams return "", false, errInvalidRPCParams
}
if !validBlockInput(blockNum) {
return "", false, errInvalidRPCParams
} }
return blockNum, includeTx, nil return blockNum, includeTx, nil
} }
...@@ -145,19 +162,22 @@ func decodeGetBlockRangeParams(params json.RawMessage) (string, string, bool, er ...@@ -145,19 +162,22 @@ func decodeGetBlockRangeParams(params json.RawMessage) (string, string, bool, er
return "", "", false, err return "", "", false, err
} }
if len(list) != 3 { if len(list) != 3 {
return "", "", false, errInvalidBlockByNumberParams return "", "", false, errInvalidRPCParams
} }
startBlockNum, ok := list[0].(string) startBlockNum, ok := list[0].(string)
if !ok { if !ok {
return "", "", false, errInvalidBlockByNumberParams return "", "", false, errInvalidRPCParams
} }
endBlockNum, ok := list[1].(string) endBlockNum, ok := list[1].(string)
if !ok { if !ok {
return "", "", false, errInvalidBlockByNumberParams return "", "", false, errInvalidRPCParams
} }
includeTx, ok := list[2].(bool) includeTx, ok := list[2].(bool)
if !ok { if !ok {
return "", "", false, errInvalidBlockByNumberParams return "", "", false, errInvalidRPCParams
}
if !validBlockInput(startBlockNum) || !validBlockInput(endBlockNum) {
return "", "", false, errInvalidRPCParams
} }
return startBlockNum, endBlockNum, includeTx, nil return startBlockNum, endBlockNum, includeTx, nil
} }
...@@ -165,3 +185,11 @@ func decodeGetBlockRangeParams(params json.RawMessage) (string, string, bool, er ...@@ -165,3 +185,11 @@ func decodeGetBlockRangeParams(params json.RawMessage) (string, string, bool, er
func decodeBlockInput(input string) (uint64, error) { func decodeBlockInput(input string) (uint64, error) {
return hexutil.DecodeUint64(input) return hexutil.DecodeUint64(input)
} }
func validBlockInput(input string) bool {
if input == "earliest" || input == "pending" || input == "latest" {
return true
}
_, err := decodeBlockInput(input)
return err == nil
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment