From e938592cb3ecf31873555bccf516bff013731dc2 Mon Sep 17 00:00:00 2001 From: KamiD <44460798+KamiD@users.noreply.github.com> Date: Fri, 11 Jun 2021 14:42:33 +0800 Subject: [PATCH] =?UTF-8?q?Merge=20PR=EF=BC=9Aadd=20lru=20for=20eth=5Fcall?= =?UTF-8?q?=20(#901)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add lru for eth_call * fix the unhandled monitor * optimize code --- app/rpc/namespaces/eth/api.go | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/app/rpc/namespaces/eth/api.go b/app/rpc/namespaces/eth/api.go index a5b5842dd0..e35fe4df27 100644 --- a/app/rpc/namespaces/eth/api.go +++ b/app/rpc/namespaces/eth/api.go @@ -3,13 +3,17 @@ package eth import ( "bytes" "context" + "crypto/sha256" "errors" "fmt" - "github.com/go-kit/kit/metrics" "math/big" + "strconv" "sync" "time" + "github.com/go-kit/kit/metrics" + lru "github.com/hashicorp/golang-lru" + "github.com/okex/exchain/app/rpc/monitor" "github.com/okex/exchain/app/rpc/namespaces/eth/simulation" "github.com/okex/exchain/x/evm/watcher" @@ -49,6 +53,7 @@ import ( const ( FlagGasLimitBuffer = "gas-limit-buffer" + CacheOfEthCallLru = 40960 ) // PublicEthereumAPI is the eth_ prefixed set of APIs in the Web3 JSON-RPC spec. @@ -67,6 +72,7 @@ type PublicEthereumAPI struct { evmFactory simulation.EvmFactory txPool *TxPool Metrics map[string]metrics.Counter + cacheCall *lru.Cache } // NewAPI creates an instance of the public ETH Web3 API. @@ -79,7 +85,10 @@ func NewAPI( if err != nil { panic(err) } - + callCache, err := lru.New(CacheOfEthCallLru) + if err != nil { + panic(err) + } api := &PublicEthereumAPI{ ctx: context.Background(), clientCtx: clientCtx, @@ -91,6 +100,7 @@ func NewAPI( gasPrice: ParseGasPrice(), wrappedBackend: watcher.NewQuerier(), watcherBackend: watcher.NewWatcher(), + cacheCall: callCache, } api.evmFactory = simulation.NewEvmFactory(clientCtx.ChainID, api.wrappedBackend) @@ -657,11 +667,27 @@ func (api *PublicEthereumAPI) SendRawTransaction(data hexutil.Bytes) (common.Has return common.HexToHash(res.TxHash), nil } +func (api *PublicEthereumAPI) buildKey(args rpctypes.CallArgs) common.Hash { + latest, e := api.wrappedBackend.GetLatestBlockNumber() + if e != nil { + return common.Hash{} + } + return sha256.Sum256([]byte(args.String() + strconv.Itoa(int(latest)))) +} + // Call performs a raw contract call. func (api *PublicEthereumAPI) Call(args rpctypes.CallArgs, blockNr rpctypes.BlockNumber, _ *map[common.Address]rpctypes.Account) (hexutil.Bytes, error) { monitor := monitor.GetMonitor("eth_call", api.logger) monitor.OnBegin(api.Metrics) defer monitor.OnEnd("args", args, "block number", blockNr) + key := api.buildKey(args) + cacheData, ok := api.cacheCall.Get(key) + if ok { + ret, ok := cacheData.([]byte) + if ok { + return ret, nil + } + } simRes, err := api.doCall(args, blockNr, big.NewInt(ethermint.DefaultRPCGasLimit), false) if err != nil { return []byte{}, TransformDataError(err, "eth_call") @@ -671,8 +697,8 @@ func (api *PublicEthereumAPI) Call(args rpctypes.CallArgs, blockNr rpctypes.Bloc if err != nil { return []byte{}, TransformDataError(err, "eth_call") } - - return (hexutil.Bytes)(data.Ret), nil + api.cacheCall.Add(key, data.Ret) + return data.Ret, nil } // DoCall performs a simulated call operation through the evmtypes. It returns the