Skip to content

Commit

Permalink
Merge branch 'main' into yash/jwt-auth-layer
Browse files Browse the repository at this point in the history
  • Loading branch information
yash-atreya committed Sep 25, 2024
2 parents eb35c02 + 241bc6e commit 9fa3ae3
Show file tree
Hide file tree
Showing 23 changed files with 426 additions and 423 deletions.
8 changes: 4 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,8 @@ alloy-eip2930 = { version = "0.1.0", default-features = false }
alloy-eip7702 = { version = "0.1.0", default-features = false }

# ethereum
ethereum_ssz_derive = "0.7.1"
ethereum_ssz = "0.7.1"
ethereum_ssz_derive = "0.8"
ethereum_ssz = "0.8"

# crypto
c-kzg = { version = "1.0", default-features = false }
Expand All @@ -112,7 +112,7 @@ rustls = { version = "0.23", default-features = false, features = [
"tls12",
] }
tokio-test = "0.4"
tokio-tungstenite = "0.23"
tokio-tungstenite = "0.24"
tower = { version = "0.5", features = ["util"] }

# tracing
Expand Down Expand Up @@ -155,4 +155,4 @@ assert_matches = "1.5"
serial_test = "3.0"
similar-asserts = "1.5"
tempfile = "3.10"
tower-http = "0.5.2"
tower-http = "0.6.1"
96 changes: 96 additions & 0 deletions crates/consensus/src/block.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
//! Genesic Block Type
use crate::{Header, Requests};
use alloc::vec::Vec;
use alloy_eips::eip4895::Withdrawal;
use alloy_rlp::{Decodable, Encodable, RlpDecodable, RlpEncodable};

/// Ethereum full block.
///
/// Withdrawals can be optionally included at the end of the RLP encoded message.
///
/// Taken from [reth-primitives](https://github.com/paradigmxyz/reth)
///
/// See p2p block encoding reference: <https://github.com/ethereum/devp2p/blob/master/caps/eth.md#block-encoding-and-validity>
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct Block<T> {
/// Block header.
pub header: Header,
/// Block body.
pub body: BlockBody<T>,
}

/// A response to `GetBlockBodies`, containing bodies if any bodies were found.
///
/// Withdrawals can be optionally included at the end of the RLP encoded message.
#[derive(Debug, Clone, PartialEq, Eq, Default, RlpEncodable, RlpDecodable)]
#[rlp(trailing)]
pub struct BlockBody<T> {
/// Transactions in this block.
pub transactions: Vec<T>,
/// Ommers/uncles header.
pub ommers: Vec<Header>,
/// Block withdrawals.
pub withdrawals: Option<Vec<Withdrawal>>,
/// Block requests
pub requests: Option<Requests>,
}

/// We need to implement RLP traits manually because we currently don't have a way to flatten
/// [`BlockBody`] into [`Block`].
mod block_rlp {
use super::*;

#[derive(RlpDecodable)]
#[rlp(trailing)]
struct Helper<T> {
header: Header,
transactions: Vec<T>,
ommers: Vec<Header>,
withdrawals: Option<Vec<Withdrawal>>,
requests: Option<Requests>,
}

#[derive(RlpEncodable)]
#[rlp(trailing)]
struct HelperRef<'a, T> {
header: &'a Header,
transactions: &'a Vec<T>,
ommers: &'a Vec<Header>,
withdrawals: Option<&'a Vec<Withdrawal>>,
requests: Option<&'a Requests>,
}

impl<'a, T> From<&'a Block<T>> for HelperRef<'a, T> {
fn from(block: &'a Block<T>) -> Self {
let Block { header, body: BlockBody { transactions, ommers, withdrawals, requests } } =
block;
Self {
header,
transactions,
ommers,
withdrawals: withdrawals.as_ref(),
requests: requests.as_ref(),
}
}
}

impl<T: Encodable> Encodable for Block<T> {
fn length(&self) -> usize {
let helper: HelperRef<'_, T> = self.into();
helper.length()
}

fn encode(&self, out: &mut dyn alloy_rlp::bytes::BufMut) {
let helper: HelperRef<'_, T> = self.into();
helper.encode(out)
}
}

impl<T: Decodable> Decodable for Block<T> {
fn decode(b: &mut &[u8]) -> alloy_rlp::Result<Self> {
let Helper { header, transactions, ommers, withdrawals, requests } = Helper::decode(b)?;
Ok(Self { header, body: BlockBody { transactions, ommers, withdrawals, requests } })
}
}
}
9 changes: 9 additions & 0 deletions crates/consensus/src/header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -345,10 +345,19 @@ impl Header {
}

/// Returns the parent block's number and hash
///
/// Note: for the genesis block the parent number is 0 and the parent hash is the zero hash.
pub const fn parent_num_hash(&self) -> BlockNumHash {
BlockNumHash { number: self.number.saturating_sub(1), hash: self.parent_hash }
}

/// Returns the block's number and hash.
///
/// Note: this hashes the header.
pub fn num_hash_slow(&self) -> BlockNumHash {
BlockNumHash { number: self.number, hash: self.hash_slow() }
}

/// Checks if the block's difficulty is set to zero, indicating a Proof-of-Stake header.
///
/// This function is linked to EIP-3675, proposing the consensus upgrade to Proof-of-Stake:
Expand Down
3 changes: 3 additions & 0 deletions crates/consensus/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ extern crate alloc;
mod account;
pub use account::Account;

mod block;
pub use block::{Block, BlockBody};

pub mod constants;

mod encodable_signature;
Expand Down
14 changes: 14 additions & 0 deletions crates/eips/src/eip4844/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,20 @@ pub const BYTES_PER_PROOF: usize = 48;
/// A Blob serialized as 0x-prefixed hex string
pub type Blob = FixedBytes<BYTES_PER_BLOB>;

/// Helper function to deserialize boxed blobs.
#[cfg(feature = "serde")]
pub fn deserialize_blob<'de, D>(deserializer: D) -> Result<alloc::boxed::Box<Blob>, D::Error>
where
D: serde::de::Deserializer<'de>,
{
use serde::Deserialize;
let raw_blob = <alloy_primitives::Bytes>::deserialize(deserializer)?;
let blob = alloc::boxed::Box::new(
Blob::try_from(raw_blob.as_ref()).map_err(serde::de::Error::custom)?,
);
Ok(blob)
}

/// A commitment/proof serialized as 0x-prefixed hex string
pub type Bytes48 = FixedBytes<48>;

Expand Down
101 changes: 96 additions & 5 deletions crates/eips/src/eip4844/sidecar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
use crate::eip4844::{
kzg_to_versioned_hash, Blob, Bytes48, BYTES_PER_BLOB, BYTES_PER_COMMITMENT, BYTES_PER_PROOF,
};
use alloc::boxed::Box;
use alloy_primitives::{bytes::BufMut, B256};
use alloy_rlp::{Decodable, Encodable};

Expand All @@ -12,6 +13,10 @@ use crate::eip4844::MAX_BLOBS_PER_BLOCK;
#[cfg(not(feature = "std"))]
use alloc::vec::Vec;

/// The versioned hash version for KZG.
#[cfg(feature = "kzg")]
pub(crate) const VERSIONED_HASH_VERSION_KZG: u8 = 0x01;

/// This represents a set of blobs, and its corresponding commitments and proofs.
///
/// This type encodes and decodes the fields without an rlp header.
Expand All @@ -32,6 +37,96 @@ pub struct BlobTransactionSidecar {
pub proofs: Vec<Bytes48>,
}

impl IntoIterator for BlobTransactionSidecar {
type Item = BlobTransactionSidecarItem;
type IntoIter = alloc::vec::IntoIter<BlobTransactionSidecarItem>;

fn into_iter(self) -> Self::IntoIter {
self.blobs
.into_iter()
.zip(self.commitments)
.zip(self.proofs)
.enumerate()
.map(|(index, ((blob, commitment), proof))| BlobTransactionSidecarItem {
index,
blob: Box::new(blob),
kzg_commitment: commitment,
kzg_proof: proof,
})
.collect::<Vec<_>>()
.into_iter()
}
}

/// A single blob sidecar.
#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
#[repr(C)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct BlobTransactionSidecarItem {
/// The index of this item within the [BlobTransactionSidecar].
pub index: usize,
/// The blob in this sidecar item.
#[cfg_attr(feature = "serde", serde(deserialize_with = "super::deserialize_blob"))]
pub blob: Box<Blob>,
/// The KZG commitment.
pub kzg_commitment: Bytes48,
/// The KZG proof.
pub kzg_proof: Bytes48,
}

#[cfg(feature = "kzg")]
impl BlobTransactionSidecarItem {
/// `VERSIONED_HASH_VERSION_KZG ++ sha256(commitment)[1..]`
pub fn to_kzg_versioned_hash(&self) -> [u8; 32] {
use sha2::Digest;
let commitment = self.kzg_commitment.as_slice();
let mut hash: [u8; 32] = sha2::Sha256::digest(commitment).into();
hash[0] = VERSIONED_HASH_VERSION_KZG;
hash
}

/// Verifies the KZG proof of a blob to ensure its integrity and correctness.
pub fn verify_blob_kzg_proof(&self) -> Result<(), BlobTransactionValidationError> {
let binding = crate::eip4844::env_settings::EnvKzgSettings::Default;
let settings = binding.get();

let blob = c_kzg::Blob::from_bytes(self.blob.as_slice())
.map_err(BlobTransactionValidationError::KZGError)?;

let commitment = c_kzg::Bytes48::from_bytes(self.kzg_commitment.as_slice())
.map_err(BlobTransactionValidationError::KZGError)?;

let proof = c_kzg::Bytes48::from_bytes(self.kzg_proof.as_slice())
.map_err(BlobTransactionValidationError::KZGError)?;

let result = c_kzg::KzgProof::verify_blob_kzg_proof(&blob, &commitment, &proof, settings)
.map_err(BlobTransactionValidationError::KZGError)?;

result.then_some(()).ok_or(BlobTransactionValidationError::InvalidProof)
}

/// Verify the blob sidecar against its [crate::NumHash].
pub fn verify_blob(&self, hash: &crate::NumHash) -> Result<(), BlobTransactionValidationError> {
if self.index != hash.number as usize {
let blob_hash_part = B256::from_slice(&self.blob[0..32]);
return Err(BlobTransactionValidationError::WrongVersionedHash {
have: blob_hash_part,
expected: hash.hash,
});
}

let computed_hash = self.to_kzg_versioned_hash();
if computed_hash != hash.hash {
return Err(BlobTransactionValidationError::WrongVersionedHash {
have: computed_hash.into(),
expected: hash.hash,
});
}

self.verify_blob_kzg_proof()
}
}

#[cfg(any(test, feature = "arbitrary"))]
impl<'a> arbitrary::Arbitrary<'a> for BlobTransactionSidecar {
fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
Expand Down Expand Up @@ -139,11 +234,7 @@ impl BlobTransactionSidecar {
}
.map_err(BlobTransactionValidationError::KZGError)?;

if res {
Ok(())
} else {
Err(BlobTransactionValidationError::InvalidProof)
}
res.then_some(()).ok_or(BlobTransactionValidationError::InvalidProof)
}

/// Returns an iterator over the versioned hashes of the commitments.
Expand Down
Loading

0 comments on commit 9fa3ae3

Please sign in to comment.