diff --git a/.env b/.env index a36acf9..6683e25 100644 --- a/.env +++ b/.env @@ -127,6 +127,7 @@ REDIS_PASSWORD= CACHE_METHOD_HAS_BLOCK_NUMBER_PARAM_TTL_SECONDS=600 CACHE_METHOD_HAS_BLOCK_HASH_PARAM_TTL_SECONDS=600 CACHE_STATIC_METHOD_TTL_SECONDS=600 +CACHE_METHOD_HAS_TX_HASH_PARAM_TTL_SECONDS=600 # CACHE_PREFIX is used as prefix for any key in the cache, key has such structure: # :evm-request::sha256: # Possible values are testnet, mainnet, etc... diff --git a/architecture/CACHING.md b/architecture/CACHING.md index 3a8f601..f463973 100644 --- a/architecture/CACHING.md +++ b/architecture/CACHING.md @@ -38,6 +38,7 @@ As of now we have 3 different groups of cacheable EVM methods: - cacheable by block number (for ex.: `eth_getBlockByNumber`) - cacheable by block hash (for ex.: `eth_getBlockByHash`) - static methods (for ex.: `eth_chainId`, `net_version`) +- cacheable by tx hash (for ex.: `eth_getTransactionReceipt`) ### Cacheable by block number @@ -86,6 +87,14 @@ For example: {"jsonrpc":"2.0","method":"net_version","params":[],"id":67} ``` +### Cacheable by tx hash + +Cacheable by tx hash means that for specific: +- method +- params +- tx hash (which is part of params) +response won't change over time, so we can cache it indefinitely + ### Where to find list of methods for every group? It can be found in source code: https://github.com/Kava-Labs/kava-proxy-service/blob/main/decode/evm_rpc.go diff --git a/config/config.go b/config/config.go index 6ea94ac..6d91452 100644 --- a/config/config.go +++ b/config/config.go @@ -50,6 +50,7 @@ type Config struct { CacheMethodHasBlockNumberParamTTL time.Duration CacheMethodHasBlockHashParamTTL time.Duration CacheStaticMethodTTL time.Duration + CacheMethodHasTxHashParamTTL time.Duration CachePrefix string WhitelistedHeaders []string DefaultAccessControlAllowOriginValue string @@ -114,6 +115,7 @@ const ( CACHE_METHOD_HAS_BLOCK_NUMBER_PARAM_TTL_ENVIRONMENT_KEY = "CACHE_METHOD_HAS_BLOCK_NUMBER_PARAM_TTL_SECONDS" CACHE_METHOD_HAS_BLOCK_HASH_PARAM_TTL_ENVIRONMENT_KEY = "CACHE_METHOD_HAS_BLOCK_HASH_PARAM_TTL_SECONDS" CACHE_STATIC_METHOD_TTL_ENVIRONMENT_KEY = "CACHE_STATIC_METHOD_TTL_SECONDS" + CACHE_METHOD_HAS_TX_HASH_PARAM_TTL_ENVIRONMENT_KEY = "CACHE_METHOD_HAS_TX_HASH_PARAM_TTL_SECONDS" CACHE_PREFIX_ENVIRONMENT_KEY = "CACHE_PREFIX" WHITELISTED_HEADERS_ENVIRONMENT_KEY = "WHITELISTED_HEADERS" DEFAULT_ACCESS_CONTROL_ALLOW_ORIGIN_VALUE_ENVIRONMENT_KEY = "DEFAULT_ACCESS_CONTROL_ALLOW_ORIGIN_VALUE" @@ -307,6 +309,7 @@ func ReadConfig() Config { CacheMethodHasBlockNumberParamTTL: time.Duration(EnvOrDefaultInt(CACHE_METHOD_HAS_BLOCK_NUMBER_PARAM_TTL_ENVIRONMENT_KEY, 0)) * time.Second, CacheMethodHasBlockHashParamTTL: time.Duration(EnvOrDefaultInt(CACHE_METHOD_HAS_BLOCK_HASH_PARAM_TTL_ENVIRONMENT_KEY, 0)) * time.Second, CacheStaticMethodTTL: time.Duration(EnvOrDefaultInt(CACHE_STATIC_METHOD_TTL_ENVIRONMENT_KEY, 0)) * time.Second, + CacheMethodHasTxHashParamTTL: time.Duration(EnvOrDefaultInt(CACHE_METHOD_HAS_TX_HASH_PARAM_TTL_ENVIRONMENT_KEY, 0)) * time.Second, CachePrefix: os.Getenv(CACHE_PREFIX_ENVIRONMENT_KEY), WhitelistedHeaders: parsedWhitelistedHeaders, DefaultAccessControlAllowOriginValue: os.Getenv(DEFAULT_ACCESS_CONTROL_ALLOW_ORIGIN_VALUE_ENVIRONMENT_KEY), diff --git a/config/validate.go b/config/validate.go index 6f9bca5..8e87176 100644 --- a/config/validate.go +++ b/config/validate.go @@ -75,6 +75,9 @@ func Validate(config Config) error { if err := checkTTLConfig(config.CacheStaticMethodTTL, CACHE_STATIC_METHOD_TTL_ENVIRONMENT_KEY); err != nil { allErrs = errors.Join(allErrs, err) } + if err := checkTTLConfig(config.CacheMethodHasTxHashParamTTL, CACHE_METHOD_HAS_TX_HASH_PARAM_TTL_ENVIRONMENT_KEY); err != nil { + allErrs = errors.Join(allErrs, err) + } if strings.Contains(config.CachePrefix, ":") { allErrs = errors.Join(allErrs, fmt.Errorf("invalid %s specified %s, must not contain colon symbol", CACHE_PREFIX_ENVIRONMENT_KEY, config.CachePrefix)) diff --git a/decode/evm_rpc.go b/decode/evm_rpc.go index bf172bf..3b224b4 100644 --- a/decode/evm_rpc.go +++ b/decode/evm_rpc.go @@ -106,6 +106,24 @@ func IsMethodStatic(method string) bool { return false } +// CacheableByTxHashMethods is a list of EVM methods which can be cached indefinitely by transaction hash. +// It means that for specific method and params (which includes tx hash) response will never change. +var CacheableByTxHashMethods = []string{ + "eth_getTransactionReceipt", + "eth_getTransactionByHash", +} + +// MethodHasTxHashParam checks if method is cacheable by tx hash. +func MethodHasTxHashParam(method string) bool { + for _, cacheableByTxHashMethod := range CacheableByTxHashMethods { + if method == cacheableByTxHashMethod { + return true + } + } + + return false +} + // NoHistoryMethods is a list of JSON-RPC methods that rely only on the present state of the chain. // They can always be safely routed to an up-to-date pruning cluster. var NoHistoryMethods = []string{ diff --git a/service/cachemdw/cache.go b/service/cachemdw/cache.go index ee0ed8e..23c3e1e 100644 --- a/service/cachemdw/cache.go +++ b/service/cachemdw/cache.go @@ -19,6 +19,7 @@ type Config struct { CacheMethodHasBlockNumberParamTTL time.Duration CacheMethodHasBlockHashParamTTL time.Duration CacheStaticMethodTTL time.Duration + CacheMethodHasTxHashParamTTL time.Duration } // ServiceCache is responsible for caching EVM requests and provides corresponding middleware @@ -115,6 +116,10 @@ func IsCacheable( return true } + if decode.MethodHasTxHashParam(req.Method) { + return true + } + return false } @@ -132,6 +137,10 @@ func (c *ServiceCache) GetTTL(method string) (time.Duration, error) { return c.config.CacheStaticMethodTTL, nil } + if decode.MethodHasTxHashParam(method) { + return c.config.CacheMethodHasTxHashParamTTL, nil + } + return 0, ErrRequestIsNotCacheable } diff --git a/service/cachemdw/cache_test.go b/service/cachemdw/cache_test.go index 7cc0cc5..7c5bc21 100644 --- a/service/cachemdw/cache_test.go +++ b/service/cachemdw/cache_test.go @@ -28,6 +28,7 @@ var ( CacheMethodHasBlockNumberParamTTL: time.Hour, CacheMethodHasBlockHashParamTTL: time.Hour, CacheStaticMethodTTL: time.Hour, + CacheMethodHasTxHashParamTTL: time.Hour, } ) diff --git a/service/service.go b/service/service.go index f9281bb..35d1542 100644 --- a/service/service.go +++ b/service/service.go @@ -211,6 +211,7 @@ func createServiceCache( CacheMethodHasBlockNumberParamTTL: config.CacheMethodHasBlockNumberParamTTL, CacheMethodHasBlockHashParamTTL: config.CacheMethodHasBlockHashParamTTL, CacheStaticMethodTTL: config.CacheStaticMethodTTL, + CacheMethodHasTxHashParamTTL: config.CacheMethodHasTxHashParamTTL, } serviceCache := cachemdw.NewServiceCache(