From 0d5687761cfe17f00db0403f7876575310146cb0 Mon Sep 17 00:00:00 2001
From: Yash Atreya <44857776+yash-atreya@users.noreply.github.com>
Date: Fri, 21 Jun 2024 19:43:04 +0530
Subject: [PATCH 01/48] in-memory cache implementation
---
crates/provider/src/layers/cache.rs | 150 ++++++++++++++++++++++++++++
crates/provider/src/layers/mod.rs | 3 +
2 files changed, 153 insertions(+)
create mode 100644 crates/provider/src/layers/cache.rs
diff --git a/crates/provider/src/layers/cache.rs b/crates/provider/src/layers/cache.rs
new file mode 100644
index 00000000000..6a668338190
--- /dev/null
+++ b/crates/provider/src/layers/cache.rs
@@ -0,0 +1,150 @@
+use crate::{Provider, ProviderLayer, RootProvider};
+use alloy_json_rpc::{Request, RpcParam};
+use alloy_network::Ethereum;
+use alloy_primitives::B256;
+use alloy_rpc_types_eth::{Block, BlockNumberOrTag};
+use alloy_transport::{Transport, TransportErrorKind, TransportResult};
+use lru::LruCache;
+use std::{marker::PhantomData, num::NonZeroUsize, path::PathBuf};
+use tokio::sync::Mutex;
+
+// TODO: Populate load cache from file on initialization.
+// TODO: Add method to dump cache to file.
+/// A provider layer that caches RPC responses and serves them on subsequent requests.
+#[derive(Debug, Clone)]
+pub struct CacheLayer {
+ path: PathBuf,
+ max_items: usize,
+}
+
+impl CacheLayer {
+ /// Instantiate a new cache layer.
+ pub const fn new(path: PathBuf, max_items: usize) -> Self {
+ Self { path, max_items }
+ }
+}
+
+impl
ProviderLayer
for CacheLayer
+where
+ P: Provider,
+ T: Transport + Clone,
+{
+ type Provider = CacheProvider;
+
+ fn layer(&self, inner: P) -> Self::Provider {
+ CacheProvider::new(inner, self.path.clone(), self.max_items)
+ }
+}
+
+/// A provider that caches responses to RPC requests.
+#[derive(Debug)]
+pub struct CacheProvider
{
+ /// Inner provider.
+ inner: P,
+ /// In-memory LRU cache, mapping requests to responses.
+ cache: Mutex>,
+ /// Path to the cache file.
+ path: PathBuf,
+ /// Phantom data
+ _pd: PhantomData,
+}
+
+impl CacheProvider
+where
+ P: Provider,
+ T: Transport + Clone,
+{
+ /// Instantiate a new cache provider.
+ pub fn new(inner: P, path: PathBuf, max_items: usize) -> Self {
+ let cache =
+ Mutex::new(LruCache::::new(NonZeroUsize::new(max_items).unwrap()));
+ Self { inner, path, cache, _pd: PhantomData }
+ }
+
+ /// `keccak256` hash the request params.
+ pub fn hash_request(&self, req: Request) -> TransportResult {
+ let ser_req = req.serialize().map_err(TransportErrorKind::custom)?;
+
+ Ok(ser_req.params_hash())
+ }
+
+ /// Gets the path to the cache file.
+ pub fn path(&self) -> PathBuf {
+ self.path.clone()
+ }
+
+ /// Puts a value into the cache, and returns the old value if it existed.
+ pub async fn put(&self, key: B256, value: String) -> TransportResult