From 7f382906e6f2f42f20240c863018bdbfe5f0ec65 Mon Sep 17 00:00:00 2001 From: Ermal Kaleci Date: Sat, 30 Sep 2023 10:21:37 +0200 Subject: [PATCH] Fix cache config (#102) * fix cache config * fix * add test --- rpc_configs/ethereum.yml | 30 +++++++++ src/config/rpc.rs | 4 +- src/extensions/cache.rs | 2 +- src/middlewares/methods/cache.rs | 106 ++++++++++++++++++++++++++++--- 4 files changed, 129 insertions(+), 13 deletions(-) diff --git a/rpc_configs/ethereum.yml b/rpc_configs/ethereum.yml index 62019fe..ef5971b 100644 --- a/rpc_configs/ethereum.yml +++ b/rpc_configs/ethereum.yml @@ -1,5 +1,7 @@ methods: - method: eth_blockNumber + cache: + ttl_seconds: 1 - method: eth_chainId cache: @@ -43,21 +45,29 @@ methods: ty: String - method: eth_sendTransaction + cache: + size: 0 params: - name: Transaction ty: Bytes - method: eth_sendRawTransaction + cache: + size: 0 params: - name: transaction ty: Bytes - method: eth_call + cache: + ttl_seconds: 3 params: - name: transaction ty: Bytes - method: eth_getTransactionCount + cache: + ttl_seconds: 3 params: - name: address ty: Bytes @@ -102,6 +112,8 @@ methods: inject: true - method: eth_estimateGas + cache: + ttl_seconds: 3 params: - name: transaction ty: Bytes @@ -131,41 +143,59 @@ methods: ty: Bytes - method: eth_isBlockFinalized + cache: + ttl_seconds: 3 params: - name: block ty: BlockTag inject: true - method: eth_isTransactionFinalized + cache: + ttl_seconds: 3 params: - name: transactionHash ty: Bytes - method: eth_newFilter + cache: + size: 0 params: - name: Filter ty: Bytes - method: eth_newBlockFilter + cache: + size: 0 - method: eth_newPendingTransactionFilter + cache: + size: 0 - method: eth_getFilterChanges + cache: + size: 0 params: - name: address ty: Bytes - method: eth_getFilterLogs + cache: + size: 0 params: - name: address ty: Bytes - method: eth_uninstallFilter + cache: + size: 0 params: - name: FilterIdentifier ty: Bytes - method: eth_getLogs + cache: + size: 0 params: - name: Filter ty: Bytes diff --git a/src/config/rpc.rs b/src/config/rpc.rs index 8775ed2..4c2d606 100644 --- a/src/config/rpc.rs +++ b/src/config/rpc.rs @@ -4,9 +4,9 @@ use serde::Deserialize; #[derive(Clone, Deserialize, Debug, Eq, PartialEq)] pub struct CacheParams { #[serde(default)] - pub size: Option, + pub size: Option, #[serde(default)] - pub ttl_seconds: Option, + pub ttl_seconds: Option, } #[derive(Clone, Deserialize, Debug, Eq, PartialEq)] diff --git a/src/extensions/cache.rs b/src/extensions/cache.rs index 4bf5dad..1fd3d77 100644 --- a/src/extensions/cache.rs +++ b/src/extensions/cache.rs @@ -12,7 +12,7 @@ pub struct CacheConfig { // None means no cache expiration #[serde(default)] pub default_ttl_seconds: Option, - pub default_size: u32, + pub default_size: usize, } #[async_trait] diff --git a/src/middlewares/methods/cache.rs b/src/middlewares/methods/cache.rs index 2774b54..300f7cb 100644 --- a/src/middlewares/methods/cache.rs +++ b/src/middlewares/methods/cache.rs @@ -7,6 +7,7 @@ use jsonrpsee::{core::JsonValue, types::ErrorObjectOwned}; use opentelemetry::trace::FutureExt; use crate::{ + config::CacheParams, extensions::cache::Cache as CacheExtension, middleware::{Middleware, MiddlewareBuilder, NextFn, RpcMethod}, middlewares::{CallRequest, CallResult}, @@ -31,24 +32,34 @@ impl MiddlewareBuilder for CacheMiddleware { method: &RpcMethod, extensions: &TypeRegistryRef, ) -> Option>> { - let params = method.cache.as_ref()?; - if params.size == Some(0) { - return None; - } let cache_ext = extensions .read() .await .get::() .expect("Cache extension not found"); - let size = - NonZeroUsize::new(params.size.unwrap_or(cache_ext.config.default_size) as usize)?; + // do not cache if size is 0, otherwise use default size + let size = match method.cache { + Some(CacheParams { size: Some(0), .. }) => return None, + Some(CacheParams { size, .. }) => size.unwrap_or(cache_ext.config.default_size), + None => cache_ext.config.default_size, + }; + + let ttl_seconds = match method.cache { + // ttl zero means cache forever + Some(CacheParams { + ttl_seconds: Some(0), + .. + }) => None, + Some(CacheParams { ttl_seconds, .. }) => { + ttl_seconds.or(cache_ext.config.default_ttl_seconds) + } + None => cache_ext.config.default_ttl_seconds, + }; let cache = Cache::new( - size, - params - .ttl_seconds - .map(|s| std::time::Duration::from_secs(s as u64)), + NonZeroUsize::new(size)?, + ttl_seconds.map(std::time::Duration::from_secs), ); Some(Box::new(Self::new(cache))) @@ -318,4 +329,79 @@ mod tests { assert_eq!(res.unwrap(), json!(1)); assert_eq!(res2.unwrap(), json!(1)); } + + #[tokio::test] + async fn cache_builder_works() { + let ext = crate::extensions::ExtensionsConfig { + cache: Some(crate::extensions::cache::CacheConfig { + default_size: 100, + default_ttl_seconds: Some(10), + }), + ..Default::default() + } + .create_registry() + .await + .expect("Failed to create registry"); + + // disable cache with size = 0 + let cache_middleware = CacheMiddleware::build( + &RpcMethod { + method: "foo".to_string(), + cache: Some(CacheParams { + size: Some(0), + ttl_seconds: None, + }), + params: vec![], + response: None, + }, + &ext, + ) + .await; + assert!(cache_middleware.is_none(), "Cache should be disabled"); + + // size none, use default size + let cache_middleware = CacheMiddleware::build( + &RpcMethod { + method: "foo".to_string(), + cache: Some(CacheParams { + size: None, + ttl_seconds: None, + }), + params: vec![], + response: None, + }, + &ext, + ) + .await; + assert!(cache_middleware.is_some(), "Cache should be enabled"); + + // custom size + let cache_middleware = CacheMiddleware::build( + &RpcMethod { + method: "foo".to_string(), + cache: Some(CacheParams { + size: Some(1), + ttl_seconds: None, + }), + params: vec![], + response: None, + }, + &ext, + ) + .await; + assert!(cache_middleware.is_some(), "Cache should be enabled"); + + // no cache params + let cache_middleware = CacheMiddleware::build( + &RpcMethod { + method: "foo".to_string(), + cache: None, + params: vec![], + response: None, + }, + &ext, + ) + .await; + assert!(cache_middleware.is_some(), "Cache should be enabled"); + } }