Skip to content
This repository was archived by the owner on Jan 16, 2026. It is now read-only.
Closed
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
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions bin/host/src/backend/online.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use kona_preimage::{
errors::{PreimageOracleError, PreimageOracleResult},
HintRouter, PreimageFetcher, PreimageKey,
};
use kona_proof::{errors::HintParsingError, Hint};
use kona_proof::{errors::HintParsingError, EncodableHint, Hint};
use std::{collections::HashSet, hash::Hash, str::FromStr, sync::Arc};
use tokio::sync::RwLock;
use tracing::{debug, error, trace};
Expand All @@ -16,7 +16,7 @@ use tracing::{debug, error, trace};
/// [OnlineHostBackend].
pub trait OnlineHostBackendCfg {
/// The hint type describing the range of hints that can be received.
type HintType: FromStr<Err = HintParsingError> + Hash + Eq + PartialEq + Clone + Send + Sync;
type HintType: FromStr<Err = HintParsingError> + EncodableHint + Hash + Eq + PartialEq + Clone + Send + Sync;

/// The providers that are used to fetch data in response to hints.
type Providers: Send + Sync;
Expand Down
3 changes: 2 additions & 1 deletion bin/host/src/single/cfg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,8 @@ impl SingleChainHost {
kv_store.clone(),
providers,
SingleChainHintHandler,
);
)
.with_proactive_hint(HintType::L2PayloadWitness);

task::spawn(
PreimageServer::new(
Expand Down
9 changes: 4 additions & 5 deletions bin/host/src/single/handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use alloy_rpc_types::{debug::ExecutionWitness, Block, BlockTransactionsKind};
use anyhow::{anyhow, ensure, Result};
use async_trait::async_trait;
use kona_preimage::{PreimageKey, PreimageKeyType};
use kona_proof::{Hint, HintType};
use kona_proof::{Hint, HintType, PayloadWitnessHint};
use maili_protocol::BlockInfo;
use op_alloy_rpc_types_engine::OpPayloadAttributes;
use std::collections::HashMap;
Expand Down Expand Up @@ -320,16 +320,15 @@ impl HintHandler for SingleChainHintHandler {
HintType::L2PayloadWitness => {
ensure!(hint.data.len() >= 32, "Invalid hint data length");

let parent_block_hash = B256::from_slice(&hint.data.as_ref()[..32]);
let payload_attributes: OpPayloadAttributes =
serde_json::from_slice(&hint.data[32..])?;
let hint_payload: PayloadWitnessHint =
serde_json::from_slice(&hint.data)?;

let execute_payload_response: ExecutionWitness = providers
.l2
.client()
.request::<(B256, OpPayloadAttributes), ExecutionWitness>(
"debug_executePayload",
(parent_block_hash, payload_attributes),
(hint_payload.parent_block_hash, hint_payload.payload_attributes),
)
.await
.map_err(|e| anyhow!("Failed to fetch preimage: {e}"))?;
Expand Down
2 changes: 1 addition & 1 deletion crates/proof/executor/src/db/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ where
/// The [TrieDBProvider]
fetcher: F,
/// The [TrieHinter]
hinter: H,
pub hinter: H,
}

impl<F, H> TrieDB<F, H>
Expand Down
3 changes: 3 additions & 0 deletions crates/proof/executor/src/executor/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ where
db: &mut TrieDB<F, H>,
block_number: u64,
) -> Result<B256, TrieDBError> {
db.hinter.hint_account_proof(L2_TO_L1_BRIDGE, block_number).map_err(|_err| TrieDBError::MissingAccountInfo)?;
match db.storage_roots().get(&L2_TO_L1_BRIDGE) {
Some(storage_root) => Ok(storage_root.blind()),
None => Ok(db
Expand Down Expand Up @@ -137,6 +138,8 @@ where

let parent_block_hash: B256 = self.trie_db.parent_block_header().seal();

self.trie_db.hinter.hint_payload_execution(parent_block_hash, &payload).map_err(|_err| TrieDBError::MissingAccountInfo)?;

let mut state =
State::builder().with_database(&mut self.trie_db).with_bundle_update().build();

Expand Down
1 change: 1 addition & 0 deletions crates/proof/mpt/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ serde = { workspace = true, optional = true, features = ["derive", "alloc"] }
alloy-rlp.workspace = true
alloy-trie.workspace = true
alloy-primitives = { workspace = true, features = ["rlp"] }
op-alloy-rpc-types-engine.workspace = true

[dev-dependencies]
# Alloy
Expand Down
9 changes: 9 additions & 0 deletions crates/proof/mpt/src/noop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
use crate::{TrieHinter, TrieNode, TrieProvider};
use alloc::string::String;
use alloy_primitives::{Address, B256, U256};
use op_alloy_rpc_types_engine::OpPayloadAttributes;

/// The default, no-op implementation of the [TrieProvider] trait, used for testing.
#[derive(Debug, Clone, Copy)]
Expand Down Expand Up @@ -40,4 +41,12 @@ impl TrieHinter for NoopTrieHinter {
) -> Result<(), Self::Error> {
Ok(())
}

fn hint_payload_execution(
&self,
_parent_block_hash: B256,
_payload_attributes: &OpPayloadAttributes,
) -> Result<(), Self::Error> {
Ok(())
}
}
17 changes: 17 additions & 0 deletions crates/proof/mpt/src/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use crate::TrieNode;
use alloc::string::ToString;
use alloy_primitives::{Address, B256, U256};
use core::fmt::Display;
use op_alloy_rpc_types_engine::OpPayloadAttributes;

/// The [TrieProvider] trait defines the synchronous interface for fetching trie node preimages.
pub trait TrieProvider {
Expand Down Expand Up @@ -65,4 +66,20 @@ pub trait TrieHinter {
slot: U256,
block_number: u64,
) -> Result<(), Self::Error>;

/// Hints the host to fetch all trie nodes required for the execution of the given payload
/// attributes.
///
/// ## Takes
/// - `parent_block_hash` - the block hash to build the payload on
/// - `payload_attributes` - payload data including transactions
///
/// ## Returns
/// - Ok(()): If the hint was successful.
/// - Err(Self::Error): If the hint was unsuccessful.
fn hint_payload_execution(
&self,
parent_block_hash: B256,
payload_attributes: &OpPayloadAttributes,
) -> Result<(), Self::Error>;
}
8 changes: 7 additions & 1 deletion crates/proof/proof-interop/src/hint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

use alloc::{string::ToString, vec::Vec};
use core::{fmt::Display, str::FromStr};
use kona_proof::{errors::HintParsingError, Hint};
use kona_proof::{errors::HintParsingError, EncodableHint, Hint, HintEncodingType};

/// The [HintType] enum is used to specify the type of hint that was received.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
Expand Down Expand Up @@ -107,3 +107,9 @@ impl Display for HintType {
write!(f, "{}", s)
}
}

impl EncodableHint for HintType {
fn encoding_type(&self) -> HintEncodingType {
HintEncodingType::Hex
}
}
75 changes: 63 additions & 12 deletions crates/proof/proof/src/hint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,41 @@ use alloc::{
string::{String, ToString},
vec::Vec,
};
use alloy_primitives::{hex, Bytes};
use core::{fmt::Display, str::FromStr};
use alloy_primitives::{hex, Bytes, B256};
use op_alloy_rpc_types_engine::OpPayloadAttributes;
use serde::{Deserialize, Serialize};
use core::{fmt::Display, str::FromStr, str::from_utf8};
use kona_preimage::HintWriterClient;

/// JSON-serialization of hint data for payload witness hints.
#[derive(Serialize, Deserialize, Debug)]
pub struct PayloadWitnessHint {
/// Block hash to build payload on.
pub parent_block_hash: B256,

/// Payload attributes needed to build payload.
pub payload_attributes: OpPayloadAttributes,

/// Chain ID of hint.
pub chain_id: Option<u64>,
}

/// Type of encoding used for hint data
#[derive(Debug)]
pub enum HintEncodingType {
/// Data is encoded as a UTF-8 string (used for JSON encoding)
UTF8,

/// Data is encoded as a hex string (used for binary encoding)
Hex,
}

/// Allows fetching data encoding type for a specific hint type.
pub trait EncodableHint {
/// Get data encoding type for hint type.
fn encoding_type(&self) -> HintEncodingType;
}

/// A [Hint] is parsed in the format `<hint_type> <hint_data>`, where `<hint_type>` is a string that
/// represents the type of hint, and `<hint_data>` is the data associated with the hint (bytes
/// encoded as hex UTF-8).
Expand All @@ -22,7 +53,7 @@ pub struct Hint<HT> {

impl<HT> Hint<HT>
where
HT: Display,
HT: Display + EncodableHint,
{
/// Creates a new [Hint] with the specified type and data.
pub fn new<T: Into<Bytes>>(ty: HT, data: T) -> Self {
Expand Down Expand Up @@ -55,26 +86,37 @@ where

/// Encodes the hint as a string.
pub fn encode(&self) -> String {
alloc::format!("{} {}", self.ty, self.data)
let encoded_data = match self.ty.encoding_type() {
HintEncodingType::Hex => self.data.to_string(),
HintEncodingType::UTF8 => from_utf8(&self.data).map_err(|e| {
info!("got error encoding {}: {}", self.data, e);
e
}).unwrap().to_string(),
};
alloc::format!("{} {}", self.ty, encoded_data)
}
}

impl<HT> FromStr for Hint<HT>
where
HT: FromStr<Err = HintParsingError>,
HT: FromStr<Err = HintParsingError> + EncodableHint,
{
type Err = HintParsingError;

fn from_str(s: &str) -> Result<Self, Self::Err> {
let mut parts = s.split(' ').collect::<Vec<_>>();
let parts = s
.split_once(' ')
.ok_or(HintParsingError(alloc::format!("Invalid hint format: {}", s)))?;

if parts.len() != 2 {
return Err(HintParsingError(alloc::format!("Invalid hint format: {}", s)));
}
let hint_string = parts.0.to_string();
let hint_type = HT::from_str(&hint_string)?;

let hint_type = parts.remove(0).parse::<HT>()?;
let hint_data =
hex::decode(parts.remove(0)).map_err(|e| HintParsingError(e.to_string()))?.into();
let data_string = parts.1.to_string();
let hint_data = match hint_type.encoding_type() {
HintEncodingType::UTF8 => data_string.into(),
HintEncodingType::Hex => hex::decode(data_string).map_err(|e| HintParsingError(e.to_string()))?.into(),
};


Ok(Self { ty: hint_type, data: hint_data })
}
Expand Down Expand Up @@ -113,6 +155,15 @@ pub enum HintType {
L2PayloadWitness,
}

impl EncodableHint for HintType {
fn encoding_type(&self) -> HintEncodingType {
match *self {
HintType::L2PayloadWitness => HintEncodingType::UTF8,
_ => HintEncodingType::Hex,
}
}
}

impl HintType {
/// Creates a new [Hint] from `self` and the specified data. The data passed will be
/// concatenated into a single byte array before being stored in the resulting [Hint].
Expand Down
24 changes: 23 additions & 1 deletion crates/proof/proof/src/l2/chain_provider.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Contains the concrete implementation of the [L2ChainProvider] trait for the client program.

use crate::{errors::OracleProviderError, HintType};
use crate::{errors::OracleProviderError, HintType, PayloadWitnessHint};
use alloc::{boxed::Box, sync::Arc, vec::Vec};
use alloy_consensus::{BlockBody, Header};
use alloy_eips::eip2718::Decodable2718;
Expand All @@ -15,6 +15,7 @@ use kona_preimage::{CommsClient, PreimageKey, PreimageKeyType};
use maili_genesis::{RollupConfig, SystemConfig};
use maili_protocol::{to_system_config, BatchValidationProvider, L2BlockInfo};
use op_alloy_consensus::{OpBlock, OpTxEnvelope};
use op_alloy_rpc_types_engine::OpPayloadAttributes;
use spin::RwLock;

/// The oracle-backed L2 chain provider for the client program.
Expand Down Expand Up @@ -242,4 +243,25 @@ impl<T: CommsClient> TrieHinter for OracleL2ChainProvider<T> {
.await
})
}

fn hint_payload_execution(
&self,
parent_block_hash: B256,
payload_attributes: &OpPayloadAttributes,
) -> Result<(), Self::Error> {
crate::block_on(async move {
HintType::L2PayloadWitness
.with_data(&[
&serde_json::to_vec(&PayloadWitnessHint{
parent_block_hash: parent_block_hash,
payload_attributes: payload_attributes.clone(),
chain_id: None,
}).map_err(OracleProviderError::Serde)?

])
.with_data(self.chain_id.map_or_else(Vec::new, |id| id.to_be_bytes().to_vec()))
.send(self.oracle.as_ref())
.await
})
}
}
2 changes: 1 addition & 1 deletion crates/proof/proof/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ pub mod errors;
pub mod executor;

mod hint;
pub use hint::{Hint, HintType};
pub use hint::{Hint, HintType, HintEncodingType, EncodableHint, PayloadWitnessHint};

pub mod boot;
pub use boot::BootInfo;
Expand Down