Skip to content

Commit a439b46

Browse files
authored
kona: Remove IndexedBlobHash usage and simplify blob handling (#19081)
* Refactor blob handling to remove indexed blob references * Refactor Blob Hint Tests to Improve Clarity and Readability * Add doc comment formatting fix to blob provider * Fix rustdoc syntax for trait documentation
1 parent ce852f9 commit a439b46

File tree

10 files changed

+191
-138
lines changed

10 files changed

+191
-138
lines changed

rust/kona/bin/host/src/interop/handler.rs

Lines changed: 11 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,7 @@ use crate::{
66
backend::util::store_ordered_trie,
77
};
88
use alloy_consensus::{Header, Sealed};
9-
use alloy_eips::{
10-
eip2718::Encodable2718,
11-
eip4844::{BlobTransactionSidecarItem, FIELD_ELEMENTS_PER_BLOB, IndexedBlobHash},
12-
};
9+
use alloy_eips::{eip2718::Encodable2718, eip4844::FIELD_ELEMENTS_PER_BLOB};
1310
use alloy_op_evm::OpEvmFactory;
1411
use alloy_primitives::{Address, B256, Bytes, keccak256};
1512
use alloy_provider::Provider;
@@ -34,6 +31,7 @@ use kona_proof::{
3431
};
3532
use kona_proof_interop::{HintType, PreState};
3633
use kona_protocol::{BlockInfo, OutputRoot, Predeploys};
34+
use kona_providers_alloy::BlobWithCommitmentAndProof;
3735
use kona_registry::{L1_CONFIGS, ROLLUP_CONFIGS};
3836
use std::sync::Arc;
3937
use tokio::task;
@@ -91,36 +89,26 @@ impl HintHandler for InteropHintHandler {
9189
store_ordered_trie(kv.as_ref(), raw_receipts.as_slice()).await?;
9290
}
9391
HintType::L1Blob => {
94-
ensure!(hint.data.len() == 48, "Invalid hint data length");
95-
96-
let hash_data_bytes: [u8; 32] = hint.data[0..32].try_into()?;
97-
let index_data_bytes: [u8; 8] = hint.data[32..40].try_into()?;
98-
let timestamp_data_bytes: [u8; 8] = hint.data[40..48].try_into()?;
99-
100-
let hash: B256 = hash_data_bytes.into();
101-
let index = u64::from_be_bytes(index_data_bytes);
102-
let timestamp = u64::from_be_bytes(timestamp_data_bytes);
92+
let (hash, timestamp) = crate::single::parse_blob_hint(&hint.data)?;
10393

10494
let partial_block_ref = BlockInfo { timestamp, ..Default::default() };
105-
let indexed_hash = IndexedBlobHash { index, hash };
10695

107-
// Fetch the blob sidecar from the blob provider.
108-
let mut sidecars = providers
96+
// Fetch the blob with proof from the blob provider.
97+
let mut blobs = providers
10998
.blobs
110-
.fetch_filtered_blob_sidecars(&partial_block_ref, &[indexed_hash])
99+
.fetch_blobs_with_proofs(&partial_block_ref, &[hash])
111100
.await
112-
.map_err(|e| anyhow!("Failed to fetch blob sidecars: {e}"))?;
101+
.map_err(|e| anyhow!("Failed to fetch blobs with proofs: {e}"))?;
113102

114-
if sidecars.len() != 1 {
115-
anyhow::bail!("Expected 1 sidecar, got {}", sidecars.len());
103+
if blobs.len() != 1 {
104+
anyhow::bail!("Expected 1 blob, got {}", blobs.len());
116105
}
117106

118-
let BlobTransactionSidecarItem {
107+
let BlobWithCommitmentAndProof {
119108
blob,
120109
kzg_proof: proof,
121110
kzg_commitment: commitment,
122-
..
123-
} = sidecars.pop().expect("Expected 1 sidecar");
111+
} = blobs.pop().expect("Expected 1 blob");
124112

125113
// Acquire a lock on the key-value store and set the preimages.
126114
let mut kv_lock = kv.write().await;

rust/kona/bin/host/src/single/handler.rs

Lines changed: 93 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,7 @@ use crate::{
55
single::cfg::SingleChainHost,
66
};
77
use alloy_consensus::Header;
8-
use alloy_eips::{
9-
eip2718::Encodable2718,
10-
eip4844::{BlobTransactionSidecarItem, FIELD_ELEMENTS_PER_BLOB, IndexedBlobHash},
11-
};
8+
use alloy_eips::{eip2718::Encodable2718, eip4844::FIELD_ELEMENTS_PER_BLOB};
129
use alloy_primitives::{Address, B256, Bytes, keccak256};
1310
use alloy_provider::Provider;
1411
use alloy_rlp::Decodable;
@@ -19,9 +16,49 @@ use async_trait::async_trait;
1916
use kona_preimage::{PreimageKey, PreimageKeyType};
2017
use kona_proof::{Hint, HintType, l1::ROOTS_OF_UNITY};
2118
use kona_protocol::{BlockInfo, OutputRoot, Predeploys};
19+
use kona_providers_alloy::BlobWithCommitmentAndProof;
2220
use op_alloy_rpc_types_engine::OpPayloadAttributes;
2321
use tracing::warn;
2422

23+
/// Parses a blob hint, supporting both legacy (48-byte) and new (40-byte) formats.
24+
///
25+
/// Returns the blob hash and timestamp.
26+
///
27+
/// ## Formats
28+
/// - Legacy: hash (32 bytes) + index (8 bytes) + timestamp (8 bytes) = 48 bytes
29+
/// - New: hash (32 bytes) + timestamp (8 bytes) = 40 bytes
30+
///
31+
/// The legacy index field is parsed but ignored.
32+
pub fn parse_blob_hint(hint_data: &[u8]) -> Result<(B256, u64)> {
33+
match hint_data.len() {
34+
48 => {
35+
// Legacy format: hash (32) + index (8) + timestamp (8)
36+
let hash_data_bytes: [u8; 32] = hint_data[0..32].try_into()?;
37+
let _index_data_bytes: [u8; 8] = hint_data[32..40].try_into()?; // index no longer used
38+
let timestamp_data_bytes: [u8; 8] = hint_data[40..48].try_into()?;
39+
40+
let hash: B256 = hash_data_bytes.into();
41+
let timestamp = u64::from_be_bytes(timestamp_data_bytes);
42+
Ok((hash, timestamp))
43+
}
44+
40 => {
45+
// New format: hash (32) + timestamp (8)
46+
let hash_data_bytes: [u8; 32] = hint_data[0..32].try_into()?;
47+
let timestamp_data_bytes: [u8; 8] = hint_data[32..40].try_into()?;
48+
49+
let hash: B256 = hash_data_bytes.into();
50+
let timestamp = u64::from_be_bytes(timestamp_data_bytes);
51+
Ok((hash, timestamp))
52+
}
53+
_ => {
54+
anyhow::bail!(
55+
"Invalid blob hint length: expected 40 or 48 bytes, got {}",
56+
hint_data.len()
57+
);
58+
}
59+
}
60+
}
61+
2562
/// The [`HintHandler`] for the [`SingleChainHost`].
2663
#[derive(Debug, Clone, Copy)]
2764
pub struct SingleChainHintHandler;
@@ -74,33 +111,23 @@ impl HintHandler for SingleChainHintHandler {
74111
store_ordered_trie(kv.as_ref(), raw_receipts.as_slice()).await?;
75112
}
76113
HintType::L1Blob => {
77-
ensure!(hint.data.len() == 48, "Invalid hint data length");
78-
79-
let hash_data_bytes: [u8; 32] = hint.data[0..32].try_into()?;
80-
let index_data_bytes: [u8; 8] = hint.data[32..40].try_into()?;
81-
let timestamp_data_bytes: [u8; 8] = hint.data[40..48].try_into()?;
82-
83-
let hash: B256 = hash_data_bytes.into();
84-
let index = u64::from_be_bytes(index_data_bytes);
85-
let timestamp = u64::from_be_bytes(timestamp_data_bytes);
114+
let (hash, timestamp) = parse_blob_hint(&hint.data)?;
86115

87116
let partial_block_ref = BlockInfo { timestamp, ..Default::default() };
88-
let indexed_hash = IndexedBlobHash { index, hash };
89117

90118
// Fetch the blobs from the blob provider.
91119
let mut blobs = providers
92120
.blobs
93-
.fetch_filtered_blob_sidecars(&partial_block_ref, &[indexed_hash])
121+
.fetch_blobs_with_proofs(&partial_block_ref, &[hash])
94122
.await
95-
.map_err(|e| anyhow!("Failed to fetch blob sidecars: {e}"))?;
123+
.map_err(|e| anyhow!("Failed to fetch blobs with proofs: {e}"))?;
96124
if blobs.len() != 1 {
97125
anyhow::bail!("Expected 1 blob, got {}", blobs.len());
98126
}
99-
let BlobTransactionSidecarItem {
127+
let BlobWithCommitmentAndProof {
100128
blob,
101129
kzg_proof: proof,
102130
kzg_commitment: commitment,
103-
..
104131
} = blobs.pop().expect("Expected 1 blob");
105132

106133
// Acquire a lock on the key-value store and set the preimages.
@@ -382,3 +409,51 @@ impl HintHandler for SingleChainHintHandler {
382409
Ok(())
383410
}
384411
}
412+
413+
#[cfg(test)]
414+
mod tests {
415+
use super::*;
416+
417+
const TEST_HASH: B256 = B256::new([0x42u8; 32]);
418+
const TEST_TIMESTAMP: u64 = 1234567890;
419+
420+
// Legacy format: hash (32 bytes) + index (8 bytes) + timestamp (8 bytes) = 48 bytes
421+
const LEGACY_HINT: [u8; 48] = [
422+
0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
423+
0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
424+
0x42, 0x42, // Hash (32 bytes):
425+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFA, 0xCA, // Index (8 bytes, ignored)
426+
0x00, 0x00, 0x00, 0x00, 0x49, 0x96, 0x02, 0xD2, // Timestamp (8 bytes): 1234567890
427+
];
428+
429+
// New format: hash (32 bytes) + timestamp (8 bytes) = 40 bytes
430+
const NEW_HINT: [u8; 40] = [
431+
0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
432+
0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
433+
0x42, 0x42, // Hash (32 bytes)
434+
0x00, 0x00, 0x00, 0x00, 0x49, 0x96, 0x02, 0xD2, // Timestamp (8 bytes): 1234567890
435+
];
436+
437+
#[test]
438+
fn test_parse_blob_hint_formats() {
439+
let (legacy_hash, legacy_timestamp) = parse_blob_hint(&LEGACY_HINT).unwrap();
440+
let (new_hash, new_timestamp) = parse_blob_hint(&NEW_HINT).unwrap();
441+
442+
assert_eq!(legacy_hash, TEST_HASH);
443+
assert_eq!(legacy_timestamp, TEST_TIMESTAMP);
444+
assert_eq!(new_hash, TEST_HASH);
445+
assert_eq!(new_timestamp, TEST_TIMESTAMP);
446+
}
447+
448+
#[test]
449+
fn test_parse_blob_hint_invalid_length() {
450+
let hint_data = vec![0u8; 35];
451+
let result = parse_blob_hint(&hint_data);
452+
453+
assert!(result.is_err());
454+
let err_msg = result.unwrap_err().to_string();
455+
assert!(err_msg.contains("Invalid blob hint length"));
456+
assert!(err_msg.contains("expected 40 or 48 bytes"));
457+
assert!(err_msg.contains("got 35"));
458+
}
459+
}

rust/kona/bin/host/src/single/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,4 @@ mod local_kv;
77
pub use local_kv::SingleChainLocalInputs;
88

99
mod handler;
10-
pub use handler::SingleChainHintHandler;
10+
pub use handler::{SingleChainHintHandler, parse_blob_hint};

rust/kona/crates/proof/proof/src/l1/blob_provider.rs

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
use crate::{HintType, errors::OracleProviderError};
44
use alloc::{boxed::Box, sync::Arc, vec::Vec};
55
use alloy_consensus::Blob;
6-
use alloy_eips::eip4844::{FIELD_ELEMENTS_PER_BLOB, IndexedBlobHash};
7-
use alloy_primitives::keccak256;
6+
use alloy_eips::eip4844::FIELD_ELEMENTS_PER_BLOB;
7+
use alloy_primitives::{B256, keccak256};
88
use ark_bls12_381::Fr;
99
use ark_ff::{AdditiveGroup, BigInteger, BigInteger256, Field, PrimeField};
1010
use async_trait::async_trait;
@@ -39,20 +39,19 @@ impl<T: CommsClient> OracleBlobProvider<T> {
3939
async fn get_blob(
4040
&self,
4141
block_ref: &BlockInfo,
42-
blob_hash: &IndexedBlobHash,
42+
blob_hash: &B256,
4343
) -> Result<Blob, OracleProviderError> {
44-
let mut blob_req_meta = [0u8; 48];
45-
blob_req_meta[0..32].copy_from_slice(blob_hash.hash.as_ref());
46-
blob_req_meta[32..40].copy_from_slice((blob_hash.index).to_be_bytes().as_ref());
47-
blob_req_meta[40..48].copy_from_slice(block_ref.timestamp.to_be_bytes().as_ref());
44+
let mut blob_req_meta = [0u8; 40];
45+
blob_req_meta[0..32].copy_from_slice(blob_hash.as_ref());
46+
blob_req_meta[32..40].copy_from_slice(block_ref.timestamp.to_be_bytes().as_ref());
4847

4948
// Send a hint for the blob commitment and field elements.
5049
HintType::L1Blob.with_data(&[blob_req_meta.as_ref()]).send(self.oracle.as_ref()).await?;
5150

5251
// Fetch the blob commitment.
5352
let mut commitment = [0u8; 48];
5453
self.oracle
55-
.get_exact(PreimageKey::new(*blob_hash.hash, PreimageKeyType::Sha256), &mut commitment)
54+
.get_exact(PreimageKey::new(**blob_hash, PreimageKeyType::Sha256), &mut commitment)
5655
.await
5756
.map_err(OracleProviderError::Preimage)?;
5857

@@ -77,8 +76,7 @@ impl<T: CommsClient> OracleBlobProvider<T> {
7776

7877
tracing::info!(
7978
target: "client_blob_oracle",
80-
index = blob_hash.index,
81-
hash = ?blob_hash.hash,
79+
hash = ?blob_hash,
8280
"Retrieved blob"
8381
);
8482

@@ -94,7 +92,7 @@ impl<T: CommsClient + Sync + Send> BlobProvider for OracleBlobProvider<T> {
9492
async fn get_and_validate_blobs(
9593
&mut self,
9694
block_ref: &BlockInfo,
97-
blob_hashes: &[IndexedBlobHash],
95+
blob_hashes: &[B256],
9896
) -> Result<Vec<Box<Blob>>, Self::Error> {
9997
let mut blobs = Vec::with_capacity(blob_hashes.len());
10098
for hash in blob_hashes {

rust/kona/crates/protocol/derive/src/sources/blobs.rs

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,7 @@ use alloc::{boxed::Box, string::ToString, vec::Vec};
88
use alloy_consensus::{
99
Transaction, TxEip4844Variant, TxEnvelope, TxType, transaction::SignerRecoverable,
1010
};
11-
use alloy_eips::eip4844::IndexedBlobHash;
12-
use alloy_primitives::{Address, Bytes};
11+
use alloy_primitives::{Address, B256, Bytes};
1312
use async_trait::async_trait;
1413
use kona_protocol::BlockInfo;
1514

@@ -46,8 +45,7 @@ where
4645
&self,
4746
txs: Vec<TxEnvelope>,
4847
batcher_address: Address,
49-
) -> (Vec<BlobData>, Vec<IndexedBlobHash>) {
50-
let mut index: u64 = 0;
48+
) -> (Vec<BlobData>, Vec<B256>) {
5149
let mut data = Vec::new();
5250
let mut hashes = Vec::new();
5351
for tx in txs {
@@ -69,11 +67,9 @@ where
6967
let Some(to) = tx_kind else { continue };
7068

7169
if to != self.batcher_address {
72-
index += blob_hashes.map_or(0, |h| h.len() as u64);
7370
continue;
7471
}
7572
if tx.recover_signer().unwrap_or_default() != batcher_address {
76-
index += blob_hashes.map_or(0, |h| h.len() as u64);
7773
continue;
7874
}
7975
if tx.tx_type() != TxType::Eip4844 {
@@ -97,10 +93,8 @@ where
9793
continue;
9894
};
9995
for hash in blob_hashes {
100-
let indexed = IndexedBlobHash { hash, index };
101-
hashes.push(indexed);
96+
hashes.push(hash);
10297
data.push(BlobData::default());
103-
index += 1;
10498
}
10599
}
106100
#[cfg(feature = "metrics")]

rust/kona/crates/protocol/derive/src/test_utils/blob_provider.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
33
use crate::{BlobProvider, errors::BlobProviderError};
44
use alloc::{boxed::Box, vec::Vec};
5-
use alloy_eips::eip4844::{Blob, IndexedBlobHash};
5+
use alloy_eips::eip4844::Blob;
66
use alloy_primitives::{B256, map::HashMap};
77
use async_trait::async_trait;
88
use kona_protocol::BlockInfo;
@@ -35,14 +35,14 @@ impl BlobProvider for TestBlobProvider {
3535
async fn get_and_validate_blobs(
3636
&mut self,
3737
_block_ref: &BlockInfo,
38-
blob_hashes: &[IndexedBlobHash],
38+
blob_hashes: &[B256],
3939
) -> Result<Vec<Box<Blob>>, Self::Error> {
4040
if self.should_error {
4141
return Err(BlobProviderError::SlotDerivation);
4242
}
4343
let mut blobs = Vec::new();
4444
for blob_hash in blob_hashes {
45-
if let Some(data) = self.blobs.get(&blob_hash.hash) {
45+
if let Some(data) = self.blobs.get(blob_hash) {
4646
blobs.push(Box::new(*data));
4747
}
4848
}

rust/kona/crates/protocol/derive/src/traits/data_sources.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
44
use crate::{PipelineErrorKind, PipelineResult};
55
use alloc::{boxed::Box, fmt::Debug, string::ToString, vec::Vec};
6-
use alloy_eips::eip4844::{Blob, IndexedBlobHash};
7-
use alloy_primitives::{Address, Bytes};
6+
use alloy_eips::eip4844::Blob;
7+
use alloy_primitives::{Address, B256, Bytes};
88
use async_trait::async_trait;
99
use core::fmt::Display;
1010
use kona_protocol::BlockInfo;
@@ -19,7 +19,7 @@ pub trait BlobProvider {
1919
async fn get_and_validate_blobs(
2020
&mut self,
2121
block_ref: &BlockInfo,
22-
blob_hashes: &[IndexedBlobHash],
22+
blob_hashes: &[B256],
2323
) -> Result<Vec<Box<Blob>>, Self::Error>;
2424
}
2525

0 commit comments

Comments
 (0)