-
Notifications
You must be signed in to change notification settings - Fork 53
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore(host): Consolidate fetchers into
HintHandler
s
- Loading branch information
Showing
21 changed files
with
1,122 additions
and
1,576 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
//! Backend for the preimage server. | ||
mod offline; | ||
pub use offline::OfflineHostBackend; | ||
|
||
mod online; | ||
pub use online::{HintHandler, OnlineHostBackend, OnlineHostBackendCfg}; | ||
|
||
pub(crate) mod util; |
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
//! Contains the [OnlineHostBackend] definition. | ||
use crate::SharedKeyValueStore; | ||
use anyhow::Result; | ||
use async_trait::async_trait; | ||
use kona_preimage::{ | ||
errors::{PreimageOracleError, PreimageOracleResult}, | ||
HintRouter, PreimageFetcher, PreimageKey, | ||
}; | ||
use std::{hash::Hash, str::FromStr, sync::Arc}; | ||
use tokio::sync::RwLock; | ||
use tracing::{error, trace, warn}; | ||
|
||
/// The [OnlineHostBackendCfg] trait is used to define the type configuration for the | ||
/// [OnlineHostBackend]. | ||
pub trait OnlineHostBackendCfg { | ||
/// The hint type describing the range of hints that can be received. | ||
type Hint: FromStr + Hash + Eq + PartialEq + Send + Sync; | ||
|
||
/// The providers that are used to fetch data in response to hints. | ||
type Providers: Send + Sync; | ||
} | ||
|
||
/// A [HintHandler] is an interface for receiving hints, fetching remote data, and storing it in the | ||
/// key-value store. | ||
#[async_trait] | ||
pub trait HintHandler { | ||
/// The type configuration for the [HintHandler]. | ||
type Cfg: OnlineHostBackendCfg; | ||
|
||
/// Fetches data in response to a hint. | ||
async fn fetch_hint( | ||
hint: <Self::Cfg as OnlineHostBackendCfg>::Hint, | ||
cfg: &Self::Cfg, | ||
providers: &<Self::Cfg as OnlineHostBackendCfg>::Providers, | ||
kv: SharedKeyValueStore, | ||
) -> Result<()>; | ||
} | ||
|
||
/// The [OnlineHostBackend] is a [HintRouter] and [PreimageFetcher] that is used to fetch data from | ||
/// remote sources in response to hints. | ||
/// | ||
/// [PreimageKey]: kona_preimage::PreimageKey | ||
#[allow(missing_debug_implementations)] | ||
pub struct OnlineHostBackend<C, H> | ||
where | ||
C: OnlineHostBackendCfg, | ||
H: HintHandler, | ||
{ | ||
/// The configuration that is used to route hints. | ||
cfg: C, | ||
/// The key-value store that is used to store preimages. | ||
kv: SharedKeyValueStore, | ||
/// The providers that are used to fetch data in response to hints. | ||
providers: C::Providers, | ||
/// The last hint that was received. | ||
last_hint: Arc<RwLock<Option<String>>>, | ||
/// Phantom marker for the [HintHandler]. | ||
_hint_handler: std::marker::PhantomData<H>, | ||
} | ||
|
||
impl<C, H> OnlineHostBackend<C, H> | ||
where | ||
C: OnlineHostBackendCfg, | ||
H: HintHandler, | ||
{ | ||
/// Creates a new [HintHandler] with the given configuration, key-value store, providers, and | ||
/// external configuration. | ||
pub fn new(cfg: C, kv: SharedKeyValueStore, providers: C::Providers, _: H) -> Self { | ||
Self { | ||
cfg, | ||
kv, | ||
providers, | ||
last_hint: Arc::new(RwLock::new(None)), | ||
_hint_handler: std::marker::PhantomData, | ||
} | ||
} | ||
} | ||
|
||
#[async_trait] | ||
impl<C, H> HintRouter for OnlineHostBackend<C, H> | ||
where | ||
C: OnlineHostBackendCfg + Send + Sync, | ||
H: HintHandler<Cfg = C> + Send + Sync, | ||
{ | ||
/// Set the last hint to be received. | ||
async fn route_hint(&self, hint: String) -> PreimageOracleResult<()> { | ||
trace!(target: "host-backend", "Received hint: {hint}"); | ||
let mut hint_lock = self.last_hint.write().await; | ||
hint_lock.replace(hint); | ||
Ok(()) | ||
} | ||
} | ||
|
||
#[async_trait] | ||
impl<C, H> PreimageFetcher for OnlineHostBackend<C, H> | ||
where | ||
C: OnlineHostBackendCfg + Send + Sync, | ||
H: HintHandler<Cfg = C> + Send + Sync, | ||
{ | ||
/// Get the preimage for the given key. | ||
async fn get_preimage(&self, key: PreimageKey) -> PreimageOracleResult<Vec<u8>> { | ||
trace!(target: "host-backend", "Pre-image requested. Key: {key}"); | ||
|
||
// Acquire a read lock on the key-value store. | ||
let kv_lock = self.kv.read().await; | ||
let mut preimage = kv_lock.get(key.into()); | ||
|
||
// Drop the read lock before beginning the retry loop. | ||
drop(kv_lock); | ||
|
||
// Use a loop to keep retrying the prefetch as long as the key is not found | ||
while preimage.is_none() { | ||
if let Some(hint) = self.last_hint.read().await.as_ref() { | ||
let parsed_hint = | ||
hint.parse::<C::Hint>().map_err(|_| PreimageOracleError::KeyNotFound)?; | ||
let value = | ||
H::fetch_hint(parsed_hint, &self.cfg, &self.providers, self.kv.clone()).await; | ||
|
||
if let Err(e) = value { | ||
error!(target: "host-backend", "Failed to prefetch hint: {e}"); | ||
warn!(target: "host-backend", "Retrying hint fetch: {hint}"); | ||
continue; | ||
} | ||
|
||
let kv_lock = self.kv.read().await; | ||
preimage = kv_lock.get(key.into()); | ||
} | ||
} | ||
|
||
preimage.ok_or(PreimageOracleError::KeyNotFound) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
//! Utilities for the preimage server backend. | ||
use crate::KeyValueStore; | ||
use alloy_consensus::EMPTY_ROOT_HASH; | ||
use alloy_primitives::keccak256; | ||
use alloy_rlp::EMPTY_STRING_CODE; | ||
use anyhow::Result; | ||
use kona_preimage::{PreimageKey, PreimageKeyType}; | ||
use tokio::sync::RwLock; | ||
|
||
/// Constructs a merkle patricia trie from the ordered list passed and stores all encoded | ||
/// intermediate nodes of the trie in the [KeyValueStore]. | ||
pub(crate) async fn store_ordered_trie<KV: KeyValueStore + ?Sized, T: AsRef<[u8]>>( | ||
kv: &RwLock<KV>, | ||
values: &[T], | ||
) -> Result<()> { | ||
let mut kv_write_lock = kv.write().await; | ||
|
||
// If the list of nodes is empty, store the empty root hash and exit early. | ||
// The `HashBuilder` will not push the preimage of the empty root hash to the | ||
// `ProofRetainer` in the event that there are no leaves inserted. | ||
if values.is_empty() { | ||
let empty_key = PreimageKey::new(*EMPTY_ROOT_HASH, PreimageKeyType::Keccak256); | ||
return kv_write_lock.set(empty_key.into(), [EMPTY_STRING_CODE].into()); | ||
} | ||
|
||
let mut hb = kona_mpt::ordered_trie_with_encoder(values, |node, buf| { | ||
buf.put_slice(node.as_ref()); | ||
}); | ||
hb.root(); | ||
let intermediates = hb.take_proof_nodes().into_inner(); | ||
|
||
for (_, value) in intermediates.into_iter() { | ||
let value_hash = keccak256(value.as_ref()); | ||
let key = PreimageKey::new(*value_hash, PreimageKeyType::Keccak256); | ||
|
||
kv_write_lock.set(key.into(), value.into())?; | ||
} | ||
|
||
Ok(()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.