From 51594cb1c04abb6d90103b20f2b6edb9a5e4f1c0 Mon Sep 17 00:00:00 2001 From: Bryan Stitt Date: Tue, 31 Oct 2023 19:04:20 -0700 Subject: [PATCH] split cache_block and to_block --- web3_proxy/src/block_number.rs | 78 ++++++++++++++++++++------------ web3_proxy/src/response_cache.rs | 8 ++-- 2 files changed, 53 insertions(+), 33 deletions(-) diff --git a/web3_proxy/src/block_number.rs b/web3_proxy/src/block_number.rs index f497b1a2..ff74e8f3 100644 --- a/web3_proxy/src/block_number.rs +++ b/web3_proxy/src/block_number.rs @@ -228,13 +228,21 @@ impl BlockNumOrHash { } } +impl From<&Web3ProxyBlock> for BlockNumOrHash { + fn from(value: &Web3ProxyBlock) -> Self { + Self::And(value.into()) + } +} + /// TODO: change this to also return the hash needed? /// this replaces any "latest" identifiers in the JsonRpcRequest with the current block number which feels like the data is structured wrong #[derive(Debug, Default, Hash, Eq, PartialEq)] pub enum CacheMode { SuccessForever, Standard { - block: BlockNumAndHash, + /// TODO: i don't think i'm using this correctly everywhere. i think we return an error if this can't be found when we should just allow the number + block_needed: BlockNumOrHash, + cache_block: BlockNumAndHash, /// cache jsonrpc errors (server errors are never cached) cache_errors: bool, }, @@ -305,7 +313,8 @@ impl CacheMode { if let Some(head_block) = head_block { Self::Standard { - block: head_block.into(), + block_needed: head_block.into(), + cache_block: head_block.into(), cache_errors: true, } } else { @@ -320,18 +329,6 @@ impl CacheMode { ) -> Web3ProxyResult { let params = &mut request.params; - if matches!(params, serde_json::Value::Null) { - // no params given. cache with the head block - if let Some(head_block) = head_block { - return Ok(Self::Standard { - block: head_block.into(), - cache_errors: true, - }); - } else { - return Ok(Self::Never); - } - } - if head_block.is_none() { // since we don't have a head block, i don't trust our anything enough to cache return Ok(Self::Never); @@ -339,11 +336,21 @@ impl CacheMode { let head_block = head_block.expect("head_block was just checked above"); + if matches!(params, serde_json::Value::Null) { + // no params given. cache with the head block + return Ok(Self::Standard { + block_needed: head_block.into(), + cache_block: head_block.into(), + cache_errors: true, + }); + } + if let Some(params) = params.as_array() { if params.is_empty() { // no params given. cache with the head block return Ok(Self::Standard { - block: head_block.into(), + block_needed: head_block.into(), + cache_block: head_block.into(), cache_errors: true, }); } @@ -354,10 +361,7 @@ impl CacheMode { // TODO: make sure re-orgs work properly! Ok(Self::SuccessForever) } - "eth_gasPrice" => Ok(Self::Standard { - block: head_block.into(), - cache_errors: false, - }), + "eth_gasPrice" => Ok(Self::Never), "eth_getBlockByHash" => { // TODO: double check that any node can serve this // TODO: can a block change? like what if it gets orphaned? @@ -369,7 +373,8 @@ impl CacheMode { // TODO: CacheSuccessForever if the block is old enough // TODO: make sure re-orgs work properly! Ok(Self::Standard { - block: head_block.into(), + block_needed: head_block.into(), + cache_block: head_block.into(), cache_errors: true, }) } @@ -483,10 +488,7 @@ impl CacheMode { } "eth_maxPriorityFeePerGas" => { // TODO: this might be too aggressive. i think it can change before a block is mined - Ok(Self::Standard { - block: head_block.into(), - cache_errors: false, - }) + Ok(Self::Never) } "eth_sendRawTransaction" => Ok(Self::Never), "net_listening" => Ok(Self::SuccessForever), @@ -496,7 +498,8 @@ impl CacheMode { let block = clean_block_number(params, block_param_id, head_block, app).await?; Ok(Self::Standard { - block, + block_needed: BlockNumOrHash::And(block.clone()), + cache_block: block, cache_errors: true, }) } @@ -530,13 +533,26 @@ impl CacheMode { !matches!(self, Self::Never) } - /// get the to_block used **for caching**. This may be the to_block in the request, or it might be the current head block. #[inline] - pub fn to_block(&self) -> Option<&BlockNumAndHash> { + pub fn to_block(&self) -> Option<&BlockNumOrHash> { match self { Self::SuccessForever => None, Self::Never => None, - Self::Standard { block, .. } => Some(block), + Self::Standard { + block_needed: block, + .. + } => Some(block), + Self::Range { to_block, .. } => Some(to_block), + } + } + + /// get the to_block used **for caching**. This may be the to_block in the request, or it might be the current head block. + #[inline] + pub fn cache_block(&self) -> Option<&BlockNumAndHash> { + match self { + Self::SuccessForever => None, + Self::Never => None, + Self::Standard { cache_block, .. } => Some(cache_block), Self::Range { cache_block, .. } => Some(cache_block), } } @@ -579,7 +595,8 @@ mod test { assert_eq!( x, CacheMode::Standard { - block: (&head_block).into(), + block_needed: (&head_block).into(), + cache_block: (&head_block).into(), cache_errors: true } ); @@ -616,7 +633,8 @@ mod test { assert_eq!( x, CacheMode::Standard { - block: (&head_block).into(), + block_needed: (&head_block).into(), + cache_block: (&head_block).into(), cache_errors: true } ); diff --git a/web3_proxy/src/response_cache.rs b/web3_proxy/src/response_cache.rs index dadfbed0..cf0f2604 100644 --- a/web3_proxy/src/response_cache.rs +++ b/web3_proxy/src/response_cache.rs @@ -1,5 +1,5 @@ use crate::{ - block_number::{BlockNumAndHash, BlockNumOrHash, CacheMode}, + block_number::{BlockNumOrHash, CacheMode}, errors::{Web3ProxyError, Web3ProxyResult}, frontend::authorization::RequestOrMethod, jsonrpc::{self, JsonRpcErrorData, ResponsePayload}, @@ -23,7 +23,7 @@ pub struct JsonRpcQueryCacheKey<'a> { /// this is probably a premature optimization hash: u64, from_block: Option<&'a BlockNumOrHash>, - to_block: Option<&'a BlockNumAndHash>, + to_block: Option<&'a BlockNumOrHash>, cache_jsonrpc_errors: bool, } @@ -64,17 +64,19 @@ impl<'a> JsonRpcQueryCacheKey<'a> { // TODO: do this without clone let from_block = cache_mode.from_block(); let to_block = cache_mode.to_block(); + let cache_block = cache_mode.cache_block(); let cache_jsonrpc_errors = cache_mode.cache_jsonrpc_errors(); let mut hasher = DefaultHashBuilder::default().build_hasher(); from_block.hash(&mut hasher); to_block.hash(&mut hasher); + cache_block.hash(&mut hasher); request.method().hash(&mut hasher); // TODO: make sure preserve_order feature is OFF - // TODO: is there a faster way to do this? + // TODO: is there a faster way to do this? can we serialize directly into the hasher? request.params().to_string().hash(&mut hasher); cache_jsonrpc_errors.hash(&mut hasher);