From 490624b25e2a60ef8e9ad894b029690f2c948847 Mon Sep 17 00:00:00 2001 From: Felipe Andrade Date: Mon, 15 May 2023 19:20:08 -0700 Subject: [PATCH] refactor(proxy): cache only immutable and hash-based methods --- proxyd/proxyd/cache.go | 32 +- proxyd/proxyd/cache_test.go | 620 +++--------------- .../proxyd/integration_tests/caching_test.go | 103 ++- .../integration_tests/testdata/caching.toml | 7 + proxyd/proxyd/methods.go | 393 +---------- proxyd/proxyd/metrics.go | 12 + proxyd/proxyd/proxyd.go | 21 +- 7 files changed, 234 insertions(+), 954 deletions(-) diff --git a/proxyd/proxyd/cache.go b/proxyd/proxyd/cache.go index 73b7fd8..59b8cef 100644 --- a/proxyd/proxyd/cache.go +++ b/proxyd/proxyd/cache.go @@ -116,15 +116,17 @@ type rpcCache struct { handlers map[string]RPCMethodHandler } -func newRPCCache(cache Cache, getLatestBlockNumFn GetLatestBlockNumFn, getLatestGasPriceFn GetLatestGasPriceFn, numBlockConfirmations int) RPCCache { +func newRPCCache(cache Cache) RPCCache { handlers := map[string]RPCMethodHandler{ - "eth_chainId": &StaticMethodHandler{}, - "net_version": &StaticMethodHandler{}, - "eth_getBlockByNumber": &EthGetBlockByNumberMethodHandler{cache, getLatestBlockNumFn, numBlockConfirmations}, - "eth_getBlockRange": &EthGetBlockRangeMethodHandler{cache, getLatestBlockNumFn, numBlockConfirmations}, - "eth_blockNumber": &EthBlockNumberMethodHandler{getLatestBlockNumFn}, - "eth_gasPrice": &EthGasPriceMethodHandler{getLatestGasPriceFn}, - "eth_call": &EthCallMethodHandler{cache, getLatestBlockNumFn, numBlockConfirmations}, + "eth_chainId": &StaticMethodHandler{cache: cache}, + "net_version": &StaticMethodHandler{cache: cache}, + "eth_getBlockTransactionCountByHash": &StaticMethodHandler{cache: cache}, + "eth_getUncleCountByBlockHash": &StaticMethodHandler{cache: cache}, + "eth_getBlockByHash": &StaticMethodHandler{cache: cache}, + "eth_getTransactionByHash": &StaticMethodHandler{cache: cache}, + "eth_getTransactionByBlockHashAndIndex": &StaticMethodHandler{cache: cache}, + "eth_getUncleByBlockHashAndIndex": &StaticMethodHandler{cache: cache}, + "eth_getTransactionReceipt": &StaticMethodHandler{cache: cache}, } return &rpcCache{ cache: cache, @@ -138,12 +140,14 @@ func (c *rpcCache) GetRPC(ctx context.Context, req *RPCReq) (*RPCRes, error) { return nil, nil } res, err := handler.GetRPCMethod(ctx, req) - if res != nil { - if res == nil { - RecordCacheMiss(req.Method) - } else { - RecordCacheHit(req.Method) - } + if err != nil { + RecordCacheError(req.Method) + return nil, err + } + if res == nil { + RecordCacheMiss(req.Method) + } else { + RecordCacheHit(req.Method) } return res, err } diff --git a/proxyd/proxyd/cache_test.go b/proxyd/proxyd/cache_test.go index 294d0f5..0deb0e3 100644 --- a/proxyd/proxyd/cache_test.go +++ b/proxyd/proxyd/cache_test.go @@ -2,23 +2,16 @@ package proxyd import ( "context" - "math" "strconv" "testing" "github.com/stretchr/testify/require" ) -const numBlockConfirmations = 10 - func TestRPCCacheImmutableRPCs(t *testing.T) { - const blockHead = math.MaxUint64 ctx := context.Background() - getBlockNum := func(ctx context.Context) (uint64, error) { - return blockHead, nil - } - cache := newRPCCache(newMemoryCache(), getBlockNum, nil, numBlockConfirmations) + cache := newRPCCache(newMemoryCache()) ID := []byte(strconv.Itoa(1)) rpcs := []struct { @@ -55,98 +48,100 @@ func TestRPCCacheImmutableRPCs(t *testing.T) { { req: &RPCReq{ JSONRPC: "2.0", - Method: "eth_getBlockByNumber", - Params: []byte(`["0x1", false]`), + Method: "eth_getBlockTransactionCountByHash", + Params: mustMarshalJSON([]string{"0xb903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238"}), ID: ID, }, res: &RPCRes{ JSONRPC: "2.0", - Result: `{"difficulty": "0x1", "number": "0x1"}`, + Result: `{"eth_getBlockTransactionCountByHash":"!"}`, ID: ID, }, - name: "eth_getBlockByNumber", + name: "eth_getBlockTransactionCountByHash", }, { req: &RPCReq{ JSONRPC: "2.0", - Method: "eth_getBlockByNumber", - Params: []byte(`["earliest", false]`), + Method: "eth_getUncleCountByBlockHash", + Params: mustMarshalJSON([]string{"0xb903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238"}), ID: ID, }, res: &RPCRes{ JSONRPC: "2.0", - Result: `{"difficulty": "0x1", "number": "0x1"}`, + Result: `{"eth_getUncleCountByBlockHash":"!"}`, ID: ID, }, - name: "eth_getBlockByNumber earliest", + name: "eth_getUncleCountByBlockHash", }, { req: &RPCReq{ JSONRPC: "2.0", - Method: "eth_getBlockByNumber", - Params: []byte(`["safe", false]`), - ID: ID, - }, - res: nil, - name: "eth_getBlockByNumber safe", - }, - { - req: &RPCReq{ - JSONRPC: "2.0", - Method: "eth_getBlockByNumber", - Params: []byte(`["finalized", false]`), - ID: ID, - }, - res: nil, - name: "eth_getBlockByNumber finalized", - }, - { - req: &RPCReq{ - JSONRPC: "2.0", - Method: "eth_getBlockByNumber", - Params: []byte(`["pending", false]`), - ID: ID, - }, - res: nil, - name: "eth_getBlockByNumber pending", - }, - { - req: &RPCReq{ - JSONRPC: "2.0", - Method: "eth_getBlockByNumber", - Params: []byte(`["latest", false]`), - ID: ID, - }, - res: nil, - name: "eth_getBlockByNumber latest", - }, - { - req: &RPCReq{ - JSONRPC: "2.0", - Method: "eth_getBlockRange", - Params: []byte(`["0x1", "0x2", false]`), + Method: "eth_getBlockByHash", + Params: mustMarshalJSON([]string{"0xc6ef2fc5426d6ad6fd9e2a26abeab0aa2411b7ab17f30a99d3cb96aed1d1055b", "false"}), ID: ID, }, res: &RPCRes{ JSONRPC: "2.0", - Result: `[{"number": "0x1"}, {"number": "0x2"}]`, + Result: `{"eth_getBlockByHash":"!"}`, ID: ID, }, - name: "eth_getBlockRange", + name: "eth_getBlockByHash", }, { req: &RPCReq{ JSONRPC: "2.0", - Method: "eth_getBlockRange", - Params: []byte(`["earliest", "0x2", false]`), + Method: "eth_getTransactionByHash", + Params: mustMarshalJSON([]string{"0x88df016429689c079f3b2f6ad39fa052532c56795b733da78a91ebe6a713944b"}), ID: ID, }, res: &RPCRes{ JSONRPC: "2.0", - Result: `[{"number": "0x1"}, {"number": "0x2"}]`, + Result: `{"eth_getTransactionByHash":"!"}`, ID: ID, }, - name: "eth_getBlockRange earliest", + name: "eth_getTransactionByHash", + }, + { + req: &RPCReq{ + JSONRPC: "2.0", + Method: "eth_getTransactionByBlockHashAndIndex", + Params: mustMarshalJSON([]string{"0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331", "0x55"}), + ID: ID, + }, + res: &RPCRes{ + JSONRPC: "2.0", + Result: `{"eth_getTransactionByBlockHashAndIndex":"!"}`, + ID: ID, + }, + name: "eth_getTransactionByBlockHashAndIndex", + }, + { + req: &RPCReq{ + JSONRPC: "2.0", + Method: "eth_getUncleByBlockHashAndIndex", + Params: mustMarshalJSON([]string{"0xb903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238", "0x90"}), + ID: ID, + }, + res: &RPCRes{ + JSONRPC: "2.0", + Result: `{"eth_getUncleByBlockHashAndIndex":"!"}`, + ID: ID, + }, + name: "eth_getUncleByBlockHashAndIndex", + }, + { + req: &RPCReq{ + JSONRPC: "2.0", + Method: "eth_getTransactionReceipt", + Params: mustMarshalJSON([]string{"0x85d995eba9763907fdf35cd2034144dd9d53ce32cbec21349d4b12823c6860c5"}), + ID: ID, + }, + res: &RPCRes{ + JSONRPC: "2.0", + Result: `{"eth_getTransactionReceipt":"!"}`, + ID: ID, + }, + name: "eth_getTransactionReceipt", }, } @@ -162,215 +157,70 @@ func TestRPCCacheImmutableRPCs(t *testing.T) { } } -func TestRPCCacheBlockNumber(t *testing.T) { - var blockHead uint64 = 0x1000 - var gasPrice uint64 = 0x100 - ctx := context.Background() - ID := []byte(strconv.Itoa(1)) - - getGasPrice := func(ctx context.Context) (uint64, error) { - return gasPrice, nil - } - getBlockNum := func(ctx context.Context) (uint64, error) { - return blockHead, nil - } - cache := newRPCCache(newMemoryCache(), getBlockNum, getGasPrice, numBlockConfirmations) - - req := &RPCReq{ - JSONRPC: "2.0", - Method: "eth_blockNumber", - ID: ID, - } - res := &RPCRes{ - JSONRPC: "2.0", - Result: `0x1000`, - ID: ID, - } - - err := cache.PutRPC(ctx, req, res) - require.NoError(t, err) - - cachedRes, err := cache.GetRPC(ctx, req) - require.NoError(t, err) - require.Equal(t, res, cachedRes) - - blockHead = 0x1001 - cachedRes, err = cache.GetRPC(ctx, req) - require.NoError(t, err) - require.Equal(t, &RPCRes{JSONRPC: "2.0", Result: `0x1001`, ID: ID}, cachedRes) -} - -func TestRPCCacheGasPrice(t *testing.T) { - var blockHead uint64 = 0x1000 - var gasPrice uint64 = 0x100 - ctx := context.Background() - ID := []byte(strconv.Itoa(1)) - - getGasPrice := func(ctx context.Context) (uint64, error) { - return gasPrice, nil - } - getBlockNum := func(ctx context.Context) (uint64, error) { - return blockHead, nil - } - cache := newRPCCache(newMemoryCache(), getBlockNum, getGasPrice, numBlockConfirmations) - - req := &RPCReq{ - JSONRPC: "2.0", - Method: "eth_gasPrice", - ID: ID, - } - res := &RPCRes{ - JSONRPC: "2.0", - Result: `0x100`, - ID: ID, - } - - err := cache.PutRPC(ctx, req, res) - require.NoError(t, err) - - cachedRes, err := cache.GetRPC(ctx, req) - require.NoError(t, err) - require.Equal(t, res, cachedRes) - - gasPrice = 0x101 - cachedRes, err = cache.GetRPC(ctx, req) - require.NoError(t, err) - require.Equal(t, &RPCRes{JSONRPC: "2.0", Result: `0x101`, ID: ID}, cachedRes) -} - func TestRPCCacheUnsupportedMethod(t *testing.T) { - const blockHead = math.MaxUint64 ctx := context.Background() - fn := func(ctx context.Context) (uint64, error) { - return blockHead, nil - } - cache := newRPCCache(newMemoryCache(), fn, nil, numBlockConfirmations) - ID := []byte(strconv.Itoa(1)) - - req := &RPCReq{ - JSONRPC: "2.0", - Method: "eth_syncing", - ID: ID, - } - res := &RPCRes{ - JSONRPC: "2.0", - Result: false, - ID: ID, - } - - err := cache.PutRPC(ctx, req, res) - require.NoError(t, err) - - cachedRes, err := cache.GetRPC(ctx, req) - require.NoError(t, err) - require.Nil(t, cachedRes) -} - -func TestRPCCacheEthGetBlockByNumber(t *testing.T) { - ctx := context.Background() - - var blockHead uint64 - fn := func(ctx context.Context) (uint64, error) { - return blockHead, nil - } - makeCache := func() RPCCache { return newRPCCache(newMemoryCache(), fn, nil, numBlockConfirmations) } - ID := []byte(strconv.Itoa(1)) - - req := &RPCReq{ - JSONRPC: "2.0", - Method: "eth_getBlockByNumber", - Params: []byte(`["0xa", false]`), - ID: ID, - } - res := &RPCRes{ - JSONRPC: "2.0", - Result: `{"difficulty": "0x1", "number": "0x1"}`, - ID: ID, - } - req2 := &RPCReq{ - JSONRPC: "2.0", - Method: "eth_getBlockByNumber", - Params: []byte(`["0xb", false]`), - ID: ID, - } - res2 := &RPCRes{ - JSONRPC: "2.0", - Result: `{"difficulty": "0x2", "number": "0x2"}`, - ID: ID, - } - - t.Run("set multiple finalized blocks", func(t *testing.T) { - blockHead = 100 - cache := makeCache() - require.NoError(t, cache.PutRPC(ctx, req, res)) - require.NoError(t, cache.PutRPC(ctx, req2, res2)) - cachedRes, err := cache.GetRPC(ctx, req) - require.NoError(t, err) - require.Equal(t, res, cachedRes) - cachedRes, err = cache.GetRPC(ctx, req2) - require.NoError(t, err) - require.Equal(t, res2, cachedRes) - }) - - t.Run("unconfirmed block", func(t *testing.T) { - blockHead = 0xc - cache := makeCache() - require.NoError(t, cache.PutRPC(ctx, req, res)) - cachedRes, err := cache.GetRPC(ctx, req) - require.NoError(t, err) - require.Nil(t, cachedRes) - }) -} - -func TestRPCCacheEthGetBlockByNumberForRecentBlocks(t *testing.T) { - ctx := context.Background() - - var blockHead uint64 = 2 - fn := func(ctx context.Context) (uint64, error) { - return blockHead, nil - } - cache := newRPCCache(newMemoryCache(), fn, nil, numBlockConfirmations) + cache := newRPCCache(newMemoryCache()) ID := []byte(strconv.Itoa(1)) rpcs := []struct { req *RPCReq - res *RPCRes name string }{ { + name: "eth_syncing", + req: &RPCReq{ + JSONRPC: "2.0", + Method: "eth_syncing", + ID: ID, + }, + }, + { + name: "eth_blockNumber", + req: &RPCReq{ + JSONRPC: "2.0", + Method: "eth_blockNumber", + ID: ID, + }, + }, + { + name: "eth_getBlockByNumber", req: &RPCReq{ JSONRPC: "2.0", Method: "eth_getBlockByNumber", - Params: []byte(`["latest", false]`), ID: ID, }, - res: &RPCRes{ - JSONRPC: "2.0", - Result: `{"difficulty": "0x1", "number": "0x1"}`, - ID: ID, - }, - name: "latest block", }, { + name: "eth_getBlockRange", req: &RPCReq{ JSONRPC: "2.0", - Method: "eth_getBlockByNumber", - Params: []byte(`["pending", false]`), + Method: "eth_getBlockRange", ID: ID, }, - res: &RPCRes{ + }, + { + name: "eth_gasPrice", + req: &RPCReq{ JSONRPC: "2.0", - Result: `{"difficulty": "0x1", "number": "0x1"}`, + Method: "eth_gasPrice", + ID: ID, + }, + }, + { + name: "eth_call", + req: &RPCReq{ + JSONRPC: "2.0", + Method: "eth_gasPrice", ID: ID, }, - name: "pending block", }, } for _, rpc := range rpcs { t.Run(rpc.name, func(t *testing.T) { - err := cache.PutRPC(ctx, rpc.req, rpc.res) + fakeval := mustMarshalJSON([]string{rpc.name}) + err := cache.PutRPC(ctx, rpc.req, &RPCRes{Result: fakeval}) require.NoError(t, err) cachedRes, err := cache.GetRPC(ctx, rpc.req) @@ -378,285 +228,5 @@ func TestRPCCacheEthGetBlockByNumberForRecentBlocks(t *testing.T) { require.Nil(t, cachedRes) }) } -} - -func TestRPCCacheEthGetBlockByNumberInvalidRequest(t *testing.T) { - ctx := context.Background() - - const blockHead = math.MaxUint64 - fn := func(ctx context.Context) (uint64, error) { - return blockHead, nil - } - cache := newRPCCache(newMemoryCache(), fn, nil, numBlockConfirmations) - ID := []byte(strconv.Itoa(1)) - - req := &RPCReq{ - JSONRPC: "2.0", - Method: "eth_getBlockByNumber", - Params: []byte(`["0x1"]`), // missing required boolean param - ID: ID, - } - res := &RPCRes{ - JSONRPC: "2.0", - Result: `{"difficulty": "0x1", "number": "0x1"}`, - ID: ID, - } - - err := cache.PutRPC(ctx, req, res) - require.Error(t, err) - - cachedRes, err := cache.GetRPC(ctx, req) - require.Error(t, err) - require.Nil(t, cachedRes) -} - -func TestRPCCacheEthGetBlockRange(t *testing.T) { - ctx := context.Background() - - var blockHead uint64 - fn := func(ctx context.Context) (uint64, error) { - return blockHead, nil - } - makeCache := func() RPCCache { return newRPCCache(newMemoryCache(), fn, nil, numBlockConfirmations) } - ID := []byte(strconv.Itoa(1)) - - t.Run("finalized block", func(t *testing.T) { - req := &RPCReq{ - JSONRPC: "2.0", - Method: "eth_getBlockRange", - Params: []byte(`["0x1", "0x10", false]`), - ID: ID, - } - res := &RPCRes{ - JSONRPC: "2.0", - Result: `[{"number": "0x1"}, {"number": "0x10"}]`, - ID: ID, - } - blockHead = 0x1000 - cache := makeCache() - require.NoError(t, cache.PutRPC(ctx, req, res)) - cachedRes, err := cache.GetRPC(ctx, req) - require.NoError(t, err) - require.Equal(t, res, cachedRes) - }) - - t.Run("unconfirmed block", func(t *testing.T) { - cache := makeCache() - req := &RPCReq{ - JSONRPC: "2.0", - Method: "eth_getBlockRange", - Params: []byte(`["0x1", "0x1000", false]`), - ID: ID, - } - res := &RPCRes{ - JSONRPC: "2.0", - Result: `[{"number": "0x1"}, {"number": "0x2"}]`, - ID: ID, - } - require.NoError(t, cache.PutRPC(ctx, req, res)) - cachedRes, err := cache.GetRPC(ctx, req) - require.NoError(t, err) - require.Nil(t, cachedRes) - }) -} - -func TestRPCCacheEthGetBlockRangeForRecentBlocks(t *testing.T) { - ctx := context.Background() - - var blockHead uint64 = 0x1000 - fn := func(ctx context.Context) (uint64, error) { - return blockHead, nil - } - cache := newRPCCache(newMemoryCache(), fn, nil, numBlockConfirmations) - ID := []byte(strconv.Itoa(1)) - - rpcs := []struct { - req *RPCReq - res *RPCRes - name string - }{ - { - req: &RPCReq{ - JSONRPC: "2.0", - Method: "eth_getBlockRange", - Params: []byte(`["0x1", "latest", false]`), - ID: ID, - }, - res: &RPCRes{ - JSONRPC: "2.0", - Result: `[{"number": "0x1"}, {"number": "0x2"}]`, - ID: ID, - }, - name: "latest block", - }, - { - req: &RPCReq{ - JSONRPC: "2.0", - Method: "eth_getBlockRange", - Params: []byte(`["0x1", "pending", false]`), - ID: ID, - }, - res: &RPCRes{ - JSONRPC: "2.0", - Result: `[{"number": "0x1"}, {"number": "0x2"}]`, - ID: ID, - }, - name: "pending block", - }, - { - req: &RPCReq{ - JSONRPC: "2.0", - Method: "eth_getBlockRange", - Params: []byte(`["latest", "0x1000", false]`), - ID: ID, - }, - res: &RPCRes{ - JSONRPC: "2.0", - Result: `[{"number": "0x1"}, {"number": "0x2"}]`, - ID: ID, - }, - name: "latest block 2", - }, - } - - for _, rpc := range rpcs { - t.Run(rpc.name, func(t *testing.T) { - err := cache.PutRPC(ctx, rpc.req, rpc.res) - require.NoError(t, err) - - cachedRes, err := cache.GetRPC(ctx, rpc.req) - require.NoError(t, err) - require.Nil(t, cachedRes) - }) - } -} - -func TestRPCCacheEthGetBlockRangeInvalidRequest(t *testing.T) { - ctx := context.Background() - - const blockHead = math.MaxUint64 - fn := func(ctx context.Context) (uint64, error) { - return blockHead, nil - } - cache := newRPCCache(newMemoryCache(), fn, nil, numBlockConfirmations) - ID := []byte(strconv.Itoa(1)) - - rpcs := []struct { - req *RPCReq - res *RPCRes - name string - }{ - { - req: &RPCReq{ - JSONRPC: "2.0", - Method: "eth_getBlockRange", - 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", - }, - } - - for _, rpc := range rpcs { - 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, rpc.req) - require.Error(t, err) - require.Nil(t, cachedRes) - }) - } -} - -func TestRPCCacheEthCall(t *testing.T) { - ctx := context.Background() - - var blockHead uint64 - fn := func(ctx context.Context) (uint64, error) { - return blockHead, nil - } - - makeCache := func() RPCCache { return newRPCCache(newMemoryCache(), fn, nil, numBlockConfirmations) } - ID := []byte(strconv.Itoa(1)) - - req := &RPCReq{ - JSONRPC: "2.0", - Method: "eth_call", - Params: []byte(`[{"to": "0xDEADBEEF", "data": "0x1"}, "0x10"]`), - ID: ID, - } - res := &RPCRes{ - JSONRPC: "2.0", - Result: `0x0`, - ID: ID, - } - - t.Run("finalized block", func(t *testing.T) { - blockHead = 0x100 - cache := makeCache() - err := cache.PutRPC(ctx, req, res) - require.NoError(t, err) - cachedRes, err := cache.GetRPC(ctx, req) - require.NoError(t, err) - require.Equal(t, res, cachedRes) - }) - - t.Run("unconfirmed block", func(t *testing.T) { - blockHead = 0x10 - cache := makeCache() - require.NoError(t, cache.PutRPC(ctx, req, res)) - cachedRes, err := cache.GetRPC(ctx, req) - require.NoError(t, err) - require.Nil(t, cachedRes) - }) - - t.Run("latest block", func(t *testing.T) { - blockHead = 0x100 - req := &RPCReq{ - JSONRPC: "2.0", - Method: "eth_call", - Params: []byte(`[{"to": "0xDEADBEEF", "data": "0x1"}, "latest"]`), - ID: ID, - } - cache := makeCache() - require.NoError(t, cache.PutRPC(ctx, req, res)) - cachedRes, err := cache.GetRPC(ctx, req) - require.NoError(t, err) - require.Nil(t, cachedRes) - }) - - t.Run("pending block", func(t *testing.T) { - blockHead = 0x100 - req := &RPCReq{ - JSONRPC: "2.0", - Method: "eth_call", - Params: []byte(`[{"to": "0xDEADBEEF", "data": "0x1"}, "pending"]`), - ID: ID, - } - cache := makeCache() - require.NoError(t, cache.PutRPC(ctx, req, res)) - cachedRes, err := cache.GetRPC(ctx, req) - require.NoError(t, err) - require.Nil(t, cachedRes) - }) + } diff --git a/proxyd/proxyd/integration_tests/caching_test.go b/proxyd/proxyd/integration_tests/caching_test.go index b0a2f20..a69ec4f 100644 --- a/proxyd/proxyd/integration_tests/caching_test.go +++ b/proxyd/proxyd/integration_tests/caching_test.go @@ -18,15 +18,19 @@ func TestCaching(t *testing.T) { defer redis.Close() hdlr := NewBatchRPCResponseRouter() + /* cacheable */ hdlr.SetRoute("eth_chainId", "999", "0x420") hdlr.SetRoute("net_version", "999", "0x1234") - hdlr.SetRoute("eth_blockNumber", "999", "0x64") - hdlr.SetRoute("eth_getBlockByNumber", "999", "dummy_block") - hdlr.SetRoute("eth_call", "999", "dummy_call") - - // mock LVC requests - hdlr.SetFallbackRoute("eth_blockNumber", "0x64") - hdlr.SetFallbackRoute("eth_gasPrice", "0x420") + hdlr.SetRoute("eth_getBlockTransactionCountByHash", "999", "eth_getBlockTransactionCountByHash") + hdlr.SetRoute("eth_getBlockByHash", "999", "eth_getBlockByHash") + hdlr.SetRoute("eth_getTransactionByHash", "999", "eth_getTransactionByHash") + hdlr.SetRoute("eth_getTransactionByBlockHashAndIndex", "999", "eth_getTransactionByBlockHashAndIndex") + hdlr.SetRoute("eth_getUncleByBlockHashAndIndex", "999", "eth_getUncleByBlockHashAndIndex") + hdlr.SetRoute("eth_getTransactionReceipt", "999", "eth_getTransactionReceipt") + /* not cacheable */ + hdlr.SetRoute("eth_getBlockByNumber", "999", "eth_getBlockByNumber") + hdlr.SetRoute("eth_blockNumber", "999", "eth_blockNumber") + hdlr.SetRoute("eth_call", "999", "eth_call") backend := NewMockBackend(hdlr) defer backend.Close() @@ -48,6 +52,7 @@ func TestCaching(t *testing.T) { response string backendCalls int }{ + /* cacheable */ { "eth_chainId", nil, @@ -60,14 +65,51 @@ func TestCaching(t *testing.T) { "{\"jsonrpc\": \"2.0\", \"result\": \"0x1234\", \"id\": 999}", 1, }, + { + "eth_getBlockTransactionCountByHash", + []interface{}{"0xb903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238"}, + "{\"jsonrpc\": \"2.0\", \"result\": \"eth_getBlockTransactionCountByHash\", \"id\": 999}", + 1, + }, + { + "eth_getBlockByHash", + []interface{}{"0xc6ef2fc5426d6ad6fd9e2a26abeab0aa2411b7ab17f30a99d3cb96aed1d1055b", "false"}, + "{\"jsonrpc\": \"2.0\", \"result\": \"eth_getBlockByHash\", \"id\": 999}", + 1, + }, + { + "eth_getTransactionByHash", + []interface{}{"0x88df016429689c079f3b2f6ad39fa052532c56795b733da78a91ebe6a713944b"}, + "{\"jsonrpc\": \"2.0\", \"result\": \"eth_getTransactionByHash\", \"id\": 999}", + 1, + }, + { + "eth_getTransactionByBlockHashAndIndex", + []interface{}{"0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331", "0x55"}, + "{\"jsonrpc\": \"2.0\", \"result\": \"eth_getTransactionByBlockHashAndIndex\", \"id\": 999}", + 1, + }, + { + "eth_getUncleByBlockHashAndIndex", + []interface{}{"0xb903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238", "0x90"}, + "{\"jsonrpc\": \"2.0\", \"result\": \"eth_getUncleByBlockHashAndIndex\", \"id\": 999}", + 1, + }, + { + "eth_getTransactionReceipt", + []interface{}{"0x85d995eba9763907fdf35cd2034144dd9d53ce32cbec21349d4b12823c6860c5"}, + "{\"jsonrpc\": \"2.0\", \"result\": \"eth_getTransactionReceipt\", \"id\": 999}", + 1, + }, + /* not cacheable */ { "eth_getBlockByNumber", []interface{}{ "0x1", true, }, - "{\"jsonrpc\": \"2.0\", \"result\": \"dummy_block\", \"id\": 999}", - 1, + "{\"jsonrpc\": \"2.0\", \"result\": \"eth_getBlockByNumber\", \"id\": 999}", + 2, }, { "eth_call", @@ -79,14 +121,14 @@ func TestCaching(t *testing.T) { }, "0x60", }, - "{\"id\":999,\"jsonrpc\":\"2.0\",\"result\":\"dummy_call\"}", - 1, + "{\"jsonrpc\": \"2.0\", \"result\": \"eth_call\", \"id\": 999}", + 2, }, { "eth_blockNumber", nil, - "{\"id\":999,\"jsonrpc\":\"2.0\",\"result\":\"0x64\"}", - 0, + "{\"jsonrpc\": \"2.0\", \"result\": \"eth_blockNumber\", \"id\": 999}", + 2, }, { "eth_call", @@ -98,7 +140,7 @@ func TestCaching(t *testing.T) { }, "latest", }, - "{\"id\":999,\"jsonrpc\":\"2.0\",\"result\":\"dummy_call\"}", + "{\"jsonrpc\": \"2.0\", \"result\": \"eth_call\", \"id\": 999}", 2, }, { @@ -111,7 +153,7 @@ func TestCaching(t *testing.T) { }, "pending", }, - "{\"id\":999,\"jsonrpc\":\"2.0\",\"result\":\"dummy_call\"}", + "{\"jsonrpc\": \"2.0\", \"result\": \"eth_call\", \"id\": 999}", 2, }, } @@ -128,24 +170,15 @@ func TestCaching(t *testing.T) { }) } - t.Run("block numbers update", func(t *testing.T) { - hdlr.SetFallbackRoute("eth_blockNumber", "0x100") - time.Sleep(1500 * time.Millisecond) - resRaw, _, err := client.SendRPC("eth_blockNumber", nil) - require.NoError(t, err) - RequireEqualJSON(t, []byte("{\"id\":999,\"jsonrpc\":\"2.0\",\"result\":\"0x100\"}"), resRaw) - backend.Reset() - }) - t.Run("nil responses should not be cached", func(t *testing.T) { - hdlr.SetRoute("eth_getBlockByNumber", "999", nil) - resRaw, _, err := client.SendRPC("eth_getBlockByNumber", []interface{}{"0x123"}) + hdlr.SetRoute("eth_getBlockByHash", "999", nil) + resRaw, _, err := client.SendRPC("eth_getBlockByHash", []interface{}{"0x123"}) require.NoError(t, err) - resCache, _, err := client.SendRPC("eth_getBlockByNumber", []interface{}{"0x123"}) + resCache, _, err := client.SendRPC("eth_getBlockByHash", []interface{}{"0x123"}) require.NoError(t, err) RequireEqualJSON(t, []byte("{\"id\":999,\"jsonrpc\":\"2.0\",\"result\":null}"), resRaw) RequireEqualJSON(t, resRaw, resCache) - require.Equal(t, 2, countRequests(backend, "eth_getBlockByNumber")) + require.Equal(t, 2, countRequests(backend, "eth_getBlockByHash")) }) } @@ -158,10 +191,7 @@ func TestBatchCaching(t *testing.T) { hdlr.SetRoute("eth_chainId", "1", "0x420") hdlr.SetRoute("net_version", "1", "0x1234") hdlr.SetRoute("eth_call", "1", "dummy_call") - - // mock LVC requests - hdlr.SetFallbackRoute("eth_blockNumber", "0x64") - hdlr.SetFallbackRoute("eth_gasPrice", "0x420") + hdlr.SetRoute("eth_getBlockByHash", "1", "eth_getBlockByHash") backend := NewMockBackend(hdlr) defer backend.Close() @@ -181,26 +211,31 @@ func TestBatchCaching(t *testing.T) { goodChainIdResponse := "{\"jsonrpc\": \"2.0\", \"result\": \"0x420\", \"id\": 1}" goodNetVersionResponse := "{\"jsonrpc\": \"2.0\", \"result\": \"0x1234\", \"id\": 1}" goodEthCallResponse := "{\"jsonrpc\": \"2.0\", \"result\": \"dummy_call\", \"id\": 1}" + goodEthGetBlockByHash := "{\"jsonrpc\": \"2.0\", \"result\": \"eth_getBlockByHash\", \"id\": 1}" res, _, err := client.SendBatchRPC( NewRPCReq("1", "eth_chainId", nil), NewRPCReq("1", "net_version", nil), + NewRPCReq("1", "eth_getBlockByHash", []interface{}{"0xc6ef2fc5426d6ad6fd9e2a26abeab0aa2411b7ab17f30a99d3cb96aed1d1055b", "false"}), ) require.NoError(t, err) - RequireEqualJSON(t, []byte(asArray(goodChainIdResponse, goodNetVersionResponse)), res) + RequireEqualJSON(t, []byte(asArray(goodChainIdResponse, goodNetVersionResponse, goodEthGetBlockByHash)), res) require.Equal(t, 1, countRequests(backend, "eth_chainId")) require.Equal(t, 1, countRequests(backend, "net_version")) + require.Equal(t, 1, countRequests(backend, "eth_getBlockByHash")) backend.Reset() res, _, err = client.SendBatchRPC( NewRPCReq("1", "eth_chainId", nil), NewRPCReq("1", "eth_call", []interface{}{`{"to":"0x1234"}`, "pending"}), NewRPCReq("1", "net_version", nil), + NewRPCReq("1", "eth_getBlockByHash", []interface{}{"0xc6ef2fc5426d6ad6fd9e2a26abeab0aa2411b7ab17f30a99d3cb96aed1d1055b", "false"}), ) require.NoError(t, err) - RequireEqualJSON(t, []byte(asArray(goodChainIdResponse, goodEthCallResponse, goodNetVersionResponse)), res) + RequireEqualJSON(t, []byte(asArray(goodChainIdResponse, goodEthCallResponse, goodNetVersionResponse, goodEthGetBlockByHash)), res) require.Equal(t, 0, countRequests(backend, "eth_chainId")) require.Equal(t, 0, countRequests(backend, "net_version")) + require.Equal(t, 0, countRequests(backend, "eth_getBlockByHash")) require.Equal(t, 1, countRequests(backend, "eth_call")) } diff --git a/proxyd/proxyd/integration_tests/testdata/caching.toml b/proxyd/proxyd/integration_tests/testdata/caching.toml index cd14ff3..530d220 100644 --- a/proxyd/proxyd/integration_tests/testdata/caching.toml +++ b/proxyd/proxyd/integration_tests/testdata/caching.toml @@ -27,3 +27,10 @@ net_version = "main" eth_getBlockByNumber = "main" eth_blockNumber = "main" eth_call = "main" +eth_getBlockTransactionCountByHash = "main" +eth_getUncleCountByBlockHash = "main" +eth_getBlockByHash = "main" +eth_getTransactionByHash = "main" +eth_getTransactionByBlockHashAndIndex = "main" +eth_getUncleByBlockHashAndIndex = "main" +eth_getTransactionReceipt = "main" diff --git a/proxyd/proxyd/methods.go b/proxyd/proxyd/methods.go index 1cba58e..82f6138 100644 --- a/proxyd/proxyd/methods.go +++ b/proxyd/proxyd/methods.go @@ -3,15 +3,9 @@ package proxyd import ( "context" "encoding/json" - "errors" - "fmt" + "github.com/ethereum/go-ethereum/log" + "strings" "sync" - - "github.com/ethereum/go-ethereum/common/hexutil" -) - -var ( - errInvalidRPCParams = errors.New("invalid RPC params") ) type RPCMethodHandler interface { @@ -20,366 +14,27 @@ type RPCMethodHandler interface { } type StaticMethodHandler struct { - cache interface{} + cache Cache m sync.RWMutex } +func (e *StaticMethodHandler) key(req *RPCReq) string { + // signature is a cache-friendly base64-encoded string with json.RawMessage param contents + signature := string(req.Params) + return strings.Join([]string{"cache", req.Method, signature}, ":") +} + func (e *StaticMethodHandler) GetRPCMethod(ctx context.Context, req *RPCReq) (*RPCRes, error) { - e.m.RLock() - cache := e.cache - e.m.RUnlock() - - if cache == nil { - return nil, nil - } - return &RPCRes{ - JSONRPC: req.JSONRPC, - Result: cache, - ID: req.ID, - }, nil -} - -func (e *StaticMethodHandler) PutRPCMethod(ctx context.Context, req *RPCReq, res *RPCRes) error { - e.m.Lock() if e.cache == nil { - e.cache = res.Result - } - e.m.Unlock() - return nil -} - -type EthGetBlockByNumberMethodHandler struct { - cache Cache - getLatestBlockNumFn GetLatestBlockNumFn - numBlockConfirmations int -} - -func (e *EthGetBlockByNumberMethodHandler) cacheKey(req *RPCReq) string { - input, includeTx, err := decodeGetBlockByNumberParams(req.Params) - if err != nil { - return "" - } - return fmt.Sprintf("method:eth_getBlockByNumber:%s:%t", input, includeTx) -} - -func (e *EthGetBlockByNumberMethodHandler) cacheable(req *RPCReq) (bool, error) { - blockNum, _, err := decodeGetBlockByNumberParams(req.Params) - if err != nil { - return false, err - } - return !isBlockDependentParam(blockNum), nil -} - -func (e *EthGetBlockByNumberMethodHandler) GetRPCMethod(ctx context.Context, req *RPCReq) (*RPCRes, error) { - if ok, err := e.cacheable(req); !ok || err != nil { - return nil, err - } - key := e.cacheKey(req) - return getImmutableRPCResponse(ctx, e.cache, key, req) -} - -func (e *EthGetBlockByNumberMethodHandler) PutRPCMethod(ctx context.Context, req *RPCReq, res *RPCRes) error { - if ok, err := e.cacheable(req); !ok || err != nil { - return err - } - - blockInput, _, err := decodeGetBlockByNumberParams(req.Params) - if err != nil { - return err - } - if isBlockDependentParam(blockInput) { - return nil - } - if blockInput != "earliest" { - curBlock, err := e.getLatestBlockNumFn(ctx) - if err != nil { - return err - } - blockNum, err := decodeBlockInput(blockInput) - if err != nil { - return err - } - if curBlock <= blockNum+uint64(e.numBlockConfirmations) { - return nil - } - } - - key := e.cacheKey(req) - return putImmutableRPCResponse(ctx, e.cache, key, req, res) -} - -type EthGetBlockRangeMethodHandler struct { - cache Cache - getLatestBlockNumFn GetLatestBlockNumFn - numBlockConfirmations int -} - -func (e *EthGetBlockRangeMethodHandler) cacheKey(req *RPCReq) string { - start, end, includeTx, err := decodeGetBlockRangeParams(req.Params) - if err != nil { - return "" - } - return fmt.Sprintf("method:eth_getBlockRange:%s:%s:%t", start, end, includeTx) -} - -func (e *EthGetBlockRangeMethodHandler) cacheable(req *RPCReq) (bool, error) { - start, end, _, err := decodeGetBlockRangeParams(req.Params) - if err != nil { - return false, err - } - return !isBlockDependentParam(start) && !isBlockDependentParam(end), nil -} - -func (e *EthGetBlockRangeMethodHandler) GetRPCMethod(ctx context.Context, req *RPCReq) (*RPCRes, error) { - if ok, err := e.cacheable(req); !ok || err != nil { - return nil, err - } - - key := e.cacheKey(req) - return getImmutableRPCResponse(ctx, e.cache, key, req) -} - -func (e *EthGetBlockRangeMethodHandler) PutRPCMethod(ctx context.Context, req *RPCReq, res *RPCRes) error { - if ok, err := e.cacheable(req); !ok || err != nil { - return err - } - - start, end, _, err := decodeGetBlockRangeParams(req.Params) - if err != nil { - return err - } - curBlock, err := e.getLatestBlockNumFn(ctx) - if err != nil { - return err - } - if start != "earliest" { - startNum, err := decodeBlockInput(start) - if err != nil { - return err - } - if curBlock <= startNum+uint64(e.numBlockConfirmations) { - return nil - } - } - if end != "earliest" { - endNum, err := decodeBlockInput(end) - if err != nil { - return err - } - if curBlock <= endNum+uint64(e.numBlockConfirmations) { - return nil - } - } - - key := e.cacheKey(req) - return putImmutableRPCResponse(ctx, e.cache, key, req, res) -} - -type EthCallMethodHandler struct { - cache Cache - getLatestBlockNumFn GetLatestBlockNumFn - numBlockConfirmations int -} - -func (e *EthCallMethodHandler) cacheable(params *ethCallParams, blockTag string) bool { - if isBlockDependentParam(blockTag) { - return false - } - if params.From != "" || params.Gas != "" { - return false - } - if params.Value != "" && params.Value != "0x0" { - return false - } - return true -} - -func (e *EthCallMethodHandler) cacheKey(params *ethCallParams, blockTag string) string { - keyParams := fmt.Sprintf("%s:%s:%s", params.To, params.Data, blockTag) - return fmt.Sprintf("method:eth_call:%s", keyParams) -} - -func (e *EthCallMethodHandler) GetRPCMethod(ctx context.Context, req *RPCReq) (*RPCRes, error) { - params, blockTag, err := decodeEthCallParams(req) - if err != nil { - return nil, err - } - if !e.cacheable(params, blockTag) { return nil, nil } - key := e.cacheKey(params, blockTag) - return getImmutableRPCResponse(ctx, e.cache, key, req) -} + e.m.RLock() + defer e.m.RUnlock() -func (e *EthCallMethodHandler) PutRPCMethod(ctx context.Context, req *RPCReq, res *RPCRes) error { - params, blockTag, err := decodeEthCallParams(req) - if err != nil { - return err - } - if !e.cacheable(params, blockTag) { - return nil - } - - if blockTag != "earliest" { - curBlock, err := e.getLatestBlockNumFn(ctx) - if err != nil { - return err - } - blockNum, err := decodeBlockInput(blockTag) - if err != nil { - return err - } - if curBlock <= blockNum+uint64(e.numBlockConfirmations) { - return nil - } - } - - key := e.cacheKey(params, blockTag) - return putImmutableRPCResponse(ctx, e.cache, key, req, res) -} - -type EthBlockNumberMethodHandler struct { - getLatestBlockNumFn GetLatestBlockNumFn -} - -func (e *EthBlockNumberMethodHandler) GetRPCMethod(ctx context.Context, req *RPCReq) (*RPCRes, error) { - blockNum, err := e.getLatestBlockNumFn(ctx) - if err != nil { - return nil, err - } - return makeRPCRes(req, hexutil.EncodeUint64(blockNum)), nil -} - -func (e *EthBlockNumberMethodHandler) PutRPCMethod(context.Context, *RPCReq, *RPCRes) error { - return nil -} - -type EthGasPriceMethodHandler struct { - getLatestGasPrice GetLatestGasPriceFn -} - -func (e *EthGasPriceMethodHandler) GetRPCMethod(ctx context.Context, req *RPCReq) (*RPCRes, error) { - gasPrice, err := e.getLatestGasPrice(ctx) - if err != nil { - return nil, err - } - return makeRPCRes(req, hexutil.EncodeUint64(gasPrice)), nil -} - -func (e *EthGasPriceMethodHandler) PutRPCMethod(context.Context, *RPCReq, *RPCRes) error { - return nil -} - -func isBlockDependentParam(s string) bool { - return s == "latest" || - s == "pending" || - s == "finalized" || - s == "safe" -} - -func decodeGetBlockByNumberParams(params json.RawMessage) (string, bool, error) { - var list []interface{} - if err := json.Unmarshal(params, &list); err != nil { - return "", false, err - } - if len(list) != 2 { - return "", false, errInvalidRPCParams - } - blockNum, ok := list[0].(string) - if !ok { - return "", false, errInvalidRPCParams - } - includeTx, ok := list[1].(bool) - if !ok { - return "", false, errInvalidRPCParams - } - if !validBlockInput(blockNum) { - return "", false, errInvalidRPCParams - } - return blockNum, includeTx, nil -} - -func decodeGetBlockRangeParams(params json.RawMessage) (string, string, bool, error) { - var list []interface{} - if err := json.Unmarshal(params, &list); err != nil { - return "", "", false, err - } - if len(list) != 3 { - return "", "", false, errInvalidRPCParams - } - startBlockNum, ok := list[0].(string) - if !ok { - return "", "", false, errInvalidRPCParams - } - endBlockNum, ok := list[1].(string) - if !ok { - return "", "", false, errInvalidRPCParams - } - includeTx, ok := list[2].(bool) - if !ok { - return "", "", false, errInvalidRPCParams - } - if !validBlockInput(startBlockNum) || !validBlockInput(endBlockNum) { - return "", "", false, errInvalidRPCParams - } - return startBlockNum, endBlockNum, includeTx, nil -} - -func decodeBlockInput(input string) (uint64, error) { - return hexutil.DecodeUint64(input) -} - -type ethCallParams struct { - From string `json:"from"` - To string `json:"to"` - Gas string `json:"gas"` - GasPrice string `json:"gasPrice"` - Value string `json:"value"` - Data string `json:"data"` -} - -func decodeEthCallParams(req *RPCReq) (*ethCallParams, string, error) { - var input []json.RawMessage - if err := json.Unmarshal(req.Params, &input); err != nil { - return nil, "", err - } - if len(input) != 2 { - return nil, "", fmt.Errorf("invalid eth_call parameters") - } - params := new(ethCallParams) - if err := json.Unmarshal(input[0], params); err != nil { - return nil, "", err - } - var blockTag string - if err := json.Unmarshal(input[1], &blockTag); err != nil { - return nil, "", err - } - return params, blockTag, nil -} - -func validBlockInput(input string) bool { - if input == "earliest" || - input == "latest" || - input == "pending" || - input == "finalized" || - input == "safe" { - return true - } - _, err := decodeBlockInput(input) - return err == nil -} - -func makeRPCRes(req *RPCReq, result interface{}) *RPCRes { - return &RPCRes{ - JSONRPC: JSONRPCVersion, - ID: req.ID, - Result: result, - } -} - -func getImmutableRPCResponse(ctx context.Context, cache Cache, key string, req *RPCReq) (*RPCRes, error) { - val, err := cache.Get(ctx, key) + key := e.key(req) + val, err := e.cache.Get(ctx, key) if err != nil { + log.Error("error reading from cache", "key", key, "method", req.Method, "err", err) return nil, err } if val == "" { @@ -388,6 +43,7 @@ func getImmutableRPCResponse(ctx context.Context, cache Cache, key string, req * var result interface{} if err := json.Unmarshal([]byte(val), &result); err != nil { + log.Error("error unmarshalling value from cache", "key", key, "method", req.Method, "err", err) return nil, err } return &RPCRes{ @@ -397,10 +53,21 @@ func getImmutableRPCResponse(ctx context.Context, cache Cache, key string, req * }, nil } -func putImmutableRPCResponse(ctx context.Context, cache Cache, key string, req *RPCReq, res *RPCRes) error { - if key == "" { +func (e *StaticMethodHandler) PutRPCMethod(ctx context.Context, req *RPCReq, res *RPCRes) error { + if e.cache == nil { return nil } - val := mustMarshalJSON(res.Result) - return cache.Put(ctx, key, string(val)) + + e.m.Lock() + defer e.m.Unlock() + + key := e.key(req) + value := mustMarshalJSON(res.Result) + + err := e.cache.Put(ctx, key, string(value)) + if err != nil { + log.Error("error marshalling value to put into cache", "key", key, "method", req.Method, "err", err) + return err + } + return nil } diff --git a/proxyd/proxyd/metrics.go b/proxyd/proxyd/metrics.go index efc36ac..66c1358 100644 --- a/proxyd/proxyd/metrics.go +++ b/proxyd/proxyd/metrics.go @@ -182,6 +182,14 @@ var ( "method", }) + cacheErrorsTotal = promauto.NewCounterVec(prometheus.CounterOpts{ + Namespace: MetricsNamespace, + Name: "cache_errors_total", + Help: "Number of cache errors.", + }, []string{ + "method", + }) + lvcErrorsTotal = promauto.NewCounterVec(prometheus.CounterOpts{ Namespace: MetricsNamespace, Name: "lvc_errors_total", @@ -374,6 +382,10 @@ func RecordCacheMiss(method string) { cacheMissesTotal.WithLabelValues(method).Inc() } +func RecordCacheError(method string) { + cacheMissesTotal.WithLabelValues(method).Inc() +} + func RecordBatchSize(size int) { batchSizeHistogram.Observe(float64(size)) } diff --git a/proxyd/proxyd/proxyd.go b/proxyd/proxyd/proxyd.go index fa0371b..a49f84e 100644 --- a/proxyd/proxyd/proxyd.go +++ b/proxyd/proxyd/proxyd.go @@ -213,17 +213,10 @@ func Start(config *Config) (*Server, func(), error) { } var ( - rpcCache RPCCache - blockNumLVC *EthLastValueCache - gasPriceLVC *EthLastValueCache + cache Cache + rpcCache RPCCache ) if config.Cache.Enabled { - var ( - cache Cache - blockNumFn GetLatestBlockNumFn - gasPriceFn GetLatestGasPriceFn - ) - if config.Cache.BlockSyncRPCURL == "" { return nil, nil, fmt.Errorf("block sync node required for caching") } @@ -245,9 +238,7 @@ func Start(config *Config) (*Server, func(), error) { } defer ethClient.Close() - blockNumLVC, blockNumFn = makeGetLatestBlockNumFn(ethClient, cache) - gasPriceLVC, gasPriceFn = makeGetLatestGasPriceFn(ethClient, cache) - rpcCache = newRPCCache(newCacheWithCompression(cache), blockNumFn, gasPriceFn, config.Cache.NumBlockConfirmations) + rpcCache = newRPCCache(newCacheWithCompression(cache)) } srv, err := NewServer( @@ -345,12 +336,6 @@ func Start(config *Config) (*Server, func(), error) { shutdownFunc := func() { log.Info("shutting down proxyd") - if blockNumLVC != nil { - blockNumLVC.Stop() - } - if gasPriceLVC != nil { - gasPriceLVC.Stop() - } srv.Shutdown() if err := lim.FlushBackendWSConns(backendNames); err != nil { log.Error("error flushing backend ws conns", "err", err)