Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(host): Add local key value store #189

Merged
merged 1 commit into from
May 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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!(),
Comment on lines +36 to +38
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We'll need standard definitions of the rollup / chain configuration per-chain. Might actually be time to make those superchain-registry bindings 🫠

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's open up a ticket for this so we track and just merge this as is for now to not block

_ => 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
Loading