-
Notifications
You must be signed in to change notification settings - Fork 265
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: Add Blob type that behaves like Bytes #1912
base: main
Are you sure you want to change the base?
Changes from all commits
78ccc3e
0df533e
f377075
ebdd2ae
95b6db5
0aea4d6
3f1705f
b66ab79
5a228c8
6e93f64
650eda5
7ed54e9
569633e
930a37b
f68ff14
efb9cab
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,15 +14,20 @@ pub mod builder; | |
pub mod utils; | ||
|
||
mod engine; | ||
use core::hash::Hash; | ||
|
||
use alloy_rlp::{RlpDecodable, RlpEncodable}; | ||
use arbitrary::{Arbitrary, Unstructured}; | ||
pub use engine::*; | ||
|
||
/// Contains sidecar related types | ||
#[cfg(feature = "kzg-sidecar")] | ||
mod sidecar; | ||
|
||
#[cfg(feature = "kzg-sidecar")] | ||
pub use sidecar::*; | ||
|
||
use alloy_primitives::{b256, FixedBytes, B256, U256}; | ||
use alloy_primitives::{b256, Bytes, FixedBytes, B256, U256}; | ||
|
||
use crate::eip7840; | ||
|
||
|
@@ -86,9 +91,146 @@ pub const BYTES_PER_COMMITMENT: usize = 48; | |
|
||
/// How many bytes are in a proof | ||
pub const BYTES_PER_PROOF: usize = 48; | ||
/// A fixed-size container for binary data, designed to hold exactly 131,072 bytes. | ||
#[derive(Clone, Debug, RlpEncodable, RlpDecodable, Hash, PartialEq, Eq)] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. RlpDecodable we can't derive but must impl manually because we also need to enforce length |
||
#[cfg_attr(feature = "ssz", derive(ssz_derive::Encode, ssz_derive::Decode))] | ||
pub struct Blob { | ||
inner: Bytes, | ||
} | ||
#[cfg(any(test, feature = "arbitrary"))] | ||
impl<'a> Arbitrary<'a> for Blob { | ||
fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> { | ||
let data: [u8; BYTES_PER_BLOB] = u.arbitrary()?; | ||
Ok(Self { inner: Bytes::from(data.to_vec()) }) | ||
} | ||
} | ||
impl Default for Blob { | ||
fn default() -> Self { | ||
let default_bytes = Bytes::from(vec![0u8; BYTES_PER_BLOB]); | ||
Self { inner: default_bytes } | ||
} | ||
} | ||
|
||
impl From<[u8; BYTES_PER_BLOB]> for Blob { | ||
fn from(array: [u8; BYTES_PER_BLOB]) -> Self { | ||
Self { inner: Bytes::from(array.to_vec()) } | ||
} | ||
} | ||
#[cfg(feature = "serde")] | ||
impl serde::Serialize for Blob { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. actually this we can derive |
||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> | ||
where | ||
S: serde::Serializer, | ||
{ | ||
if self.inner.len() != BYTES_PER_BLOB { | ||
return Err(serde::ser::Error::custom(format!( | ||
"Invalid blob length: expected {}, got {}", | ||
BYTES_PER_BLOB, | ||
self.inner.len() | ||
))); | ||
} | ||
serializer.serialize_bytes(&self.inner) | ||
} | ||
} | ||
|
||
#[cfg(feature = "serde")] | ||
impl<'de> serde::Deserialize<'de> for Blob { | ||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> | ||
where | ||
D: serde::Deserializer<'de>, | ||
{ | ||
let data: Vec<u8> = serde::Deserialize::deserialize(deserializer)?; | ||
if data.len() != BYTES_PER_BLOB { | ||
return Err(serde::de::Error::custom(format!( | ||
"Invalid blob length: expected {}, got {}", | ||
BYTES_PER_BLOB, | ||
data.len() | ||
))); | ||
} | ||
Ok(Self { inner: Bytes::from(data) }) | ||
} | ||
} | ||
|
||
impl Blob { | ||
/// Creates a new `Blob` from `data` if it is exactly 131,072 bytes. | ||
pub fn new(data: Bytes) -> Result<Self, String> { | ||
if data.len() != BYTES_PER_BLOB { | ||
return Err(format!( | ||
"Invalid blob length: expected {}, got {}", | ||
BYTES_PER_BLOB, | ||
data.len() | ||
)); | ||
} | ||
Ok(Self { inner: data }) | ||
} | ||
|
||
/// A Blob serialized as 0x-prefixed hex string | ||
pub type Blob = FixedBytes<BYTES_PER_BLOB>; | ||
/// Creates a new `Blob` filled with the same byte, repeated 131,072 times. | ||
pub fn repeat_byte(byte: u8) -> Result<Self, String> { | ||
let data = vec![byte; BYTES_PER_BLOB]; | ||
Self::new(Bytes::from(data)) | ||
} | ||
|
||
/// Returns an immutable reference to the underlying `Bytes`. | ||
pub const fn as_bytes(&self) -> &Bytes { | ||
&self.inner | ||
} | ||
|
||
/// Returns a copy of the underlying bytes (as a `Vec<u8>`). | ||
pub fn to_vec(&self) -> Vec<u8> { | ||
self.inner.to_vec() | ||
} | ||
|
||
/// Overwrite this Blob with the provided bytes. | ||
pub fn update_bytes(&mut self, new_data: Vec<u8>) -> Result<(), String> { | ||
if new_data.len() != BYTES_PER_BLOB { | ||
return Err(format!( | ||
"Invalid blob length: expected {}, got {}", | ||
BYTES_PER_BLOB, | ||
new_data.len() | ||
)); | ||
} | ||
self.inner = Bytes::from(new_data); | ||
Ok(()) | ||
} | ||
|
||
/// Returns the number of bytes in this blob . | ||
pub fn len(&self) -> usize { | ||
self.inner.len() | ||
} | ||
|
||
/// Returns true if this blob is empty. | ||
pub fn is_empty(&self) -> bool { | ||
self.inner.is_empty() | ||
} | ||
|
||
/// Returns the data as a standard slice. | ||
pub fn as_slice(&self) -> &[u8] { | ||
&self.inner | ||
} | ||
} | ||
/// Converts a `Vec<u8>` into a `Blob`. | ||
impl TryFrom<Vec<u8>> for Blob { | ||
type Error = String; | ||
|
||
fn try_from(data: Vec<u8>) -> Result<Self, Self::Error> { | ||
Self::try_from(data.as_slice()) | ||
} | ||
} | ||
/// Converts a slice (`&[u8]`) into a `Blob`. | ||
impl TryFrom<&[u8]> for Blob { | ||
type Error = String; | ||
|
||
fn try_from(data: &[u8]) -> Result<Self, Self::Error> { | ||
if data.len() != BYTES_PER_BLOB { | ||
return Err(format!( | ||
"Invalid blob length: expected {}, got {}", | ||
BYTES_PER_BLOB, | ||
data.len() | ||
)); | ||
} | ||
Ok(Self { inner: Bytes::copy_from_slice(data) }) | ||
} | ||
} | ||
|
||
/// Helper function to deserialize boxed blobs. | ||
#[cfg(feature = "serde")] | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same I want to focus only on the additional type first |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let's undo all of the changes here