Skip to content

Commit

Permalink
feat(host): Add local key value store
Browse files Browse the repository at this point in the history
Adds the `LocalKeyValueStore` and the `SplitKeyValueStore`, which routes
request for local data to the in-memory configuration.
  • Loading branch information
clabby committed May 29, 2024
1 parent 57971b6 commit 8612491
Show file tree
Hide file tree
Showing 6 changed files with 124 additions and 7 deletions.
2 changes: 1 addition & 1 deletion bin/host/src/cli/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down
46 changes: 46 additions & 0 deletions bin/host/src/kv/local.rs
Original file line number Diff line number Diff line change
@@ -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<Vec<u8>> {
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<u8>) {
unreachable!("LocalKeyValueStore is read-only")
}
}
6 changes: 6 additions & 0 deletions bin/host/src/kv/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<RwLock<dyn KeyValueStore + Send + Sync>>;

Expand Down
47 changes: 47 additions & 0 deletions bin/host/src/kv/split.rs
Original file line number Diff line number Diff line change
@@ -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<L, R>
where
L: KeyValueStore,
R: KeyValueStore,
{
local_store: L,
remote_store: R,
}

impl<L, R> SplitKeyValueStore<L, R>
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<L, R> KeyValueStore for SplitKeyValueStore<L, R>
where
L: KeyValueStore,
R: KeyValueStore,
{
fn get(&self, key: B256) -> Option<Vec<u8>> {
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<u8>) {
self.remote_store.set(key, value);
}
}
23 changes: 18 additions & 5 deletions bin/host/src/main.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand Down Expand Up @@ -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(|| {
Expand All @@ -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(|| {
Expand Down
7 changes: 6 additions & 1 deletion crates/preimage/src/key.rs
Original file line number Diff line number Diff line change
@@ -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};

/// <https://specs.optimism.io/experimental/fault-proof/index.html#pre-image-key-types>
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash)]
Expand Down Expand Up @@ -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<PreimageKey> for [u8; 32] {
Expand Down

0 comments on commit 8612491

Please sign in to comment.