From 8612491655d9ba8a7c14b334c9ea30660f542a0d Mon Sep 17 00:00:00 2001 From: clabby Date: Wed, 29 May 2024 14:56:17 -0400 Subject: [PATCH] feat(host): Add local key value store Adds the `LocalKeyValueStore` and the `SplitKeyValueStore`, which routes request for local data to the in-memory configuration. --- bin/host/src/cli/mod.rs | 2 +- bin/host/src/kv/local.rs | 46 +++++++++++++++++++++++++++++++++++++ bin/host/src/kv/mod.rs | 6 +++++ bin/host/src/kv/split.rs | 47 ++++++++++++++++++++++++++++++++++++++ bin/host/src/main.rs | 23 +++++++++++++++---- crates/preimage/src/key.rs | 7 +++++- 6 files changed, 124 insertions(+), 7 deletions(-) create mode 100644 bin/host/src/kv/local.rs create mode 100644 bin/host/src/kv/split.rs diff --git a/bin/host/src/cli/mod.rs b/bin/host/src/cli/mod.rs index 24a306dee..e844eefaf 100644 --- a/bin/host/src/cli/mod.rs +++ b/bin/host/src/cli/mod.rs @@ -15,7 +15,7 @@ mod tracing_util; pub(crate) use tracing_util::init_tracing_subscriber; /// The host binary CLI application arguments. -#[derive(Parser, Serialize)] +#[derive(Parser, Serialize, Clone)] pub struct HostCli { /// Verbosity level (0-4) #[arg(long, short, help = "Verbosity level (0-4)", action = ArgAction::Count)] diff --git a/bin/host/src/kv/local.rs b/bin/host/src/kv/local.rs new file mode 100644 index 000000000..ec7eb8723 --- /dev/null +++ b/bin/host/src/kv/local.rs @@ -0,0 +1,46 @@ +//! Contains a concrete implementation of the [KeyValueStore] trait that stores data on disk. + +use super::KeyValueStore; +use crate::cli::HostCli; +use alloy_primitives::{B256, U256}; +use kona_preimage::PreimageKey; + +pub(crate) const L1_HEAD_KEY: U256 = U256::from_be_slice(&[1]); +pub(crate) const L2_OUTPUT_ROOT_KEY: U256 = U256::from_be_slice(&[2]); +pub(crate) const L2_CLAIM_KEY: U256 = U256::from_be_slice(&[3]); +pub(crate) const L2_CLAIM_BLOCK_NUMBER_KEY: U256 = U256::from_be_slice(&[4]); +pub(crate) const L2_CHAIN_ID_KEY: U256 = U256::from_be_slice(&[5]); +pub(crate) const L2_CHAIN_CONFIG_KEY: U256 = U256::from_be_slice(&[6]); +pub(crate) const L2_ROLLUP_CONFIG_KEY: U256 = U256::from_be_slice(&[7]); + +/// A simple, synchronous key-value store that returns data from a [HostCli] config. +pub struct LocalKeyValueStore { + cfg: HostCli, +} + +impl LocalKeyValueStore { + /// Create a new [LocalKeyValueStore] with the given [HostCli] config. + pub fn new(cfg: HostCli) -> Self { + Self { cfg } + } +} + +impl KeyValueStore for LocalKeyValueStore { + fn get(&self, key: B256) -> Option> { + let preimage_key = PreimageKey::try_from(*key).ok()?; + match preimage_key.key_value() { + L1_HEAD_KEY => Some(self.cfg.l1_head.to_vec()), + L2_OUTPUT_ROOT_KEY => Some(self.cfg.l2_output_root.to_vec()), + L2_CLAIM_KEY => Some(self.cfg.l2_claim.to_vec()), + L2_CLAIM_BLOCK_NUMBER_KEY => Some(self.cfg.l2_block_number.to_be_bytes().to_vec()), + L2_CHAIN_ID_KEY => todo!(), + L2_CHAIN_CONFIG_KEY => todo!(), + L2_ROLLUP_CONFIG_KEY => todo!(), + _ => None, + } + } + + fn set(&mut self, _: B256, _: Vec) { + unreachable!("LocalKeyValueStore is read-only") + } +} diff --git a/bin/host/src/kv/mod.rs b/bin/host/src/kv/mod.rs index 6264781c8..8b996d517 100644 --- a/bin/host/src/kv/mod.rs +++ b/bin/host/src/kv/mod.rs @@ -10,6 +10,12 @@ pub use mem::MemoryKeyValueStore; mod disk; pub use disk::DiskKeyValueStore; +mod split; +pub use split::SplitKeyValueStore; + +mod local; +pub use local::LocalKeyValueStore; + /// A type alias for a shared key-value store. pub type SharedKeyValueStore = Arc>; diff --git a/bin/host/src/kv/split.rs b/bin/host/src/kv/split.rs new file mode 100644 index 000000000..b404e16f5 --- /dev/null +++ b/bin/host/src/kv/split.rs @@ -0,0 +1,47 @@ +//! Contains a concrete implementation of the [KeyValueStore] trait that splits between two separate +//! [KeyValueStore]s depending on [PreimageKeyType]. + +use alloy_primitives::B256; +use kona_preimage::PreimageKeyType; + +use super::KeyValueStore; + +/// A split implementation of the [KeyValueStore] trait that splits between two separate +/// [KeyValueStore]s. +#[derive(Clone)] +pub struct SplitKeyValueStore +where + L: KeyValueStore, + R: KeyValueStore, +{ + local_store: L, + remote_store: R, +} + +impl SplitKeyValueStore +where + L: KeyValueStore, + R: KeyValueStore, +{ + /// Create a new [SplitKeyValueStore] with the given left and right [KeyValueStore]s. + pub fn new(local_store: L, remote_store: R) -> Self { + Self { local_store, remote_store } + } +} + +impl KeyValueStore for SplitKeyValueStore +where + L: KeyValueStore, + R: KeyValueStore, +{ + fn get(&self, key: B256) -> Option> { + match PreimageKeyType::try_from(key[0]).ok()? { + PreimageKeyType::Local => self.local_store.get(key), + _ => self.remote_store.get(key), + } + } + + fn set(&mut self, key: B256, value: Vec) { + self.remote_store.set(key, value); + } +} diff --git a/bin/host/src/main.rs b/bin/host/src/main.rs index d69aaef64..81d1b3475 100644 --- a/bin/host/src/main.rs +++ b/bin/host/src/main.rs @@ -1,6 +1,9 @@ use crate::{ cli::{init_tracing_subscriber, HostCli}, - kv::{DiskKeyValueStore, MemoryKeyValueStore, SharedKeyValueStore}, + kv::{ + DiskKeyValueStore, LocalKeyValueStore, MemoryKeyValueStore, SharedKeyValueStore, + SplitKeyValueStore, + }, server::PreimageServer, }; use anyhow::{anyhow, Result}; @@ -49,10 +52,15 @@ async fn start_server(cfg: HostCli) -> Result<()> { let oracle_server = OracleServer::new(preimage_pipe); let hint_reader = HintReader::new(hint_pipe); + let local_kv_store = LocalKeyValueStore::new(cfg.clone()); let kv_store: SharedKeyValueStore = if let Some(ref data_dir) = cfg.data_dir { - Arc::new(RwLock::new(DiskKeyValueStore::new(data_dir.clone()))) + let disk_kv_store = DiskKeyValueStore::new(data_dir.clone()); + let split_kv_store = SplitKeyValueStore::new(local_kv_store, disk_kv_store); + Arc::new(RwLock::new(split_kv_store)) } else { - Arc::new(RwLock::new(MemoryKeyValueStore::new())) + let mem_kv_store = MemoryKeyValueStore::new(); + let split_kv_store = SplitKeyValueStore::new(local_kv_store, mem_kv_store); + Arc::new(RwLock::new(split_kv_store)) }; let fetcher = (!cfg.is_offline()).then(|| { @@ -77,10 +85,15 @@ async fn start_server_and_native_client(cfg: HostCli) -> Result<()> { let oracle_server = OracleServer::new(preimage_pipe); let hint_reader = HintReader::new(hint_pipe); + let local_kv_store = LocalKeyValueStore::new(cfg.clone()); let kv_store: SharedKeyValueStore = if let Some(ref data_dir) = cfg.data_dir { - Arc::new(RwLock::new(DiskKeyValueStore::new(data_dir.clone()))) + let disk_kv_store = DiskKeyValueStore::new(data_dir.clone()); + let split_kv_store = SplitKeyValueStore::new(local_kv_store, disk_kv_store); + Arc::new(RwLock::new(split_kv_store)) } else { - Arc::new(RwLock::new(MemoryKeyValueStore::new())) + let mem_kv_store = MemoryKeyValueStore::new(); + let split_kv_store = SplitKeyValueStore::new(local_kv_store, mem_kv_store); + Arc::new(RwLock::new(split_kv_store)) }; let fetcher = (!cfg.is_offline()).then(|| { diff --git a/crates/preimage/src/key.rs b/crates/preimage/src/key.rs index b0a05b4d8..1ba26b15c 100644 --- a/crates/preimage/src/key.rs +++ b/crates/preimage/src/key.rs @@ -1,7 +1,7 @@ //! Contains the [PreimageKey] type, which is used to identify preimages that may be fetched from //! the preimage oracle. -use alloy_primitives::B256; +use alloy_primitives::{B256, U256}; /// #[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash)] @@ -80,6 +80,11 @@ impl PreimageKey { pub fn key_type(&self) -> PreimageKeyType { self.key_type } + + /// Returns the value of the [PreimageKey] as a [U256]. + pub fn key_value(&self) -> U256 { + U256::from_be_slice(self.data.as_slice()) + } } impl From for [u8; 32] {