11use crate :: BlockProcessingError ;
22use eth2_hashing:: { hash, hash_fixed} ;
3- use itertools:: Itertools ;
3+ use itertools:: { EitherOrBoth , Itertools } ;
44use ssz:: Decode ;
55use ssz_types:: VariableList ;
6+ use std:: slice:: Iter ;
67use std:: vec:: IntoIter ;
78use types:: consts:: eip4844:: { BLOB_TX_TYPE , VERSIONED_HASH_VERSION_KZG } ;
8- use types:: { EthSpec , ExecPayload , KzgCommitment , Transaction , Transactions , VersionedHash } ;
9+ use types:: {
10+ AbstractExecPayload , BeaconBlockBodyRef , EthSpec , ExecPayload , FullPayload , FullPayloadRef ,
11+ KzgCommitment , Transaction , Transactions , VersionedHash ,
12+ } ;
913
10- pub fn process_blob_kzg_commitments < T : EthSpec , Payload : ExecPayload < T > > (
14+ pub fn process_blob_kzg_commitments < T : EthSpec , Payload : AbstractExecPayload < T > > (
1115 block_body : BeaconBlockBodyRef < T , Payload > ,
1216) -> Result < ( ) , BlockProcessingError > {
13- if let ( Ok ( transactions ) , Ok ( kzg_commitments) ) = (
14- block_body. execution_payload_header ( ) . transactions ( ) ,
17+ if let ( Ok ( payload ) , Ok ( kzg_commitments) ) = (
18+ block_body. execution_payload ( ) ,
1519 block_body. blob_kzg_commitments ( ) ,
1620 ) {
17- if !verify_kzg_commitments_against_transactions ( transactions, kzg_commitments) {
18- return Err ( BlockProcessingError :: BlobVersionHashMismatch ) ;
21+ if let Some ( transactions) = payload. transactions ( ) {
22+ if !verify_kzg_commitments_against_transactions :: < T > ( transactions, kzg_commitments) ? {
23+ return Err ( BlockProcessingError :: BlobVersionHashMismatch ) ;
24+ }
1925 }
2026 }
2127
2228 Ok ( ( ) )
2329}
2430
2531pub fn verify_kzg_commitments_against_transactions < T : EthSpec > (
26- transactions : Transactions < T > ,
32+ transactions : & Transactions < T > ,
2733 kzg_commitments : & VariableList < KzgCommitment , T :: MaxBlobsPerBlock > ,
2834) -> Result < bool , BlockProcessingError > {
29- let tx_versioned_hashes = transactions
35+ let nested_iter = transactions
3036 . into_iter ( )
3137 . filter ( |tx| {
3238 tx. get ( 0 )
33- . map ( |tx_type| tx_type == BLOB_TX_TYPE )
39+ . map ( |tx_type| * tx_type == BLOB_TX_TYPE )
3440 . unwrap_or ( false )
3541 } )
36- . map ( |tx| tx_peek_blob_versioned_hashes ( tx) )
37- . flatten ( )
38- . collect ( ) ;
42+ . map ( |tx| tx_peek_blob_versioned_hashes :: < T > ( tx) ) ;
3943
40- //FIXME(sean) Need to check lengths are equal here, just zipping first hides if one iter is shorter
41- // and `itertools::zip_eq` panics
42- if tx_versioned_hashes. len ( ) != kzg_commitments. len ( ) {
43- return Err ( BlockProcessingError :: BlobVersionHashMismatch ) ;
44- }
44+ itertools:: process_results ( nested_iter, |mut iter| {
45+ let zipped_iter = iter
46+ . flatten ( )
47+ // Need to use `itertools::zip_longest` here because just zipping hides if one iter is shorter
48+ // and `itertools::zip_eq` panics.
49+ . zip_longest ( kzg_commitments. into_iter ( ) )
50+ . map ( |next| match next {
51+ EitherOrBoth :: Both ( hash, commitmnet) => Ok ( ( hash?, commitmnet) ) ,
52+ _ => Err ( BlockProcessingError :: BlobVersionHashMismatch ) ,
53+ } ) ;
4554
46- tx_versioned_hashes
47- . into_iter ( )
48- . zip ( kzg_commitments. into_iter ( ) )
49- . all ( |( tx_versioned_hash, commitment) | {
50- tx_versioned_hash == kzg_commitment_to_versioned_hash ( committment)
55+ itertools:: process_results ( zipped_iter, |mut iter| {
56+ iter. all ( |( tx_versioned_hash, commitment) | {
57+ tx_versioned_hash == kzg_commitment_to_versioned_hash ( commitment)
58+ } )
5159 } )
60+ } ) ?
5261}
5362
5463fn tx_peek_blob_versioned_hashes < T : EthSpec > (
55- opaque_tx : & Transaction < T > ,
56- ) -> IntoIter < VersionedHash > {
57- //FIXME(sean) there was a first byte check for blob tx type but I think it's redundant, will raise a spec PR
58-
64+ opaque_tx : & Transaction < T :: MaxBytesPerTransaction > ,
65+ ) -> Result <
66+ impl IntoIterator < Item = Result < VersionedHash , BlockProcessingError > > + ' _ ,
67+ BlockProcessingError ,
68+ > {
5969 let tx_len = opaque_tx. len ( ) ;
6070 let message_offset = 1 + u32:: from_ssz_bytes ( opaque_tx. get ( 1 ..5 ) . ok_or (
6171 BlockProcessingError :: BlobVersionHashIndexOutOfBounds {
@@ -64,30 +74,34 @@ fn tx_peek_blob_versioned_hashes<T: EthSpec>(
6474 } ,
6575 ) ?) ?;
6676
77+ let message_offset_usize = message_offset as usize ;
78+
6779 // field offset: 32 + 8 + 32 + 32 + 8 + 4 + 32 + 4 + 4 = 156
6880 let blob_versioned_hashes_offset = message_offset
6981 + u32:: from_ssz_bytes (
7082 opaque_tx
71- . get ( ( message_offset + 156 ) ..( message_offset + 160 ) )
83+ . get ( ( message_offset_usize + 156 ) ..( message_offset_usize + 160 ) )
7284 . ok_or ( BlockProcessingError :: BlobVersionHashIndexOutOfBounds {
7385 length : tx_len,
7486 index : 160 ,
7587 } ) ?,
76- ) ;
88+ ) ? ;
7789
78- opaque_tx
79- . get ( blob_versioned_hashes_offset..tx_len)
80- . ok_or ( BlockProcessingError :: BlobVersionHashIndexOutOfBounds {
81- length : tx_len,
82- index : 160 ,
83- } ) ?
84- . into_iter ( )
85- . chunks ( 32 )
86- . map ( |chunk| VersionedHash :: from ( chunk) )
90+ let num_hashes = ( tx_len - blob_versioned_hashes_offset as usize ) / 32 ;
91+
92+ Ok ( ( 0 ..num_hashes) . into_iter ( ) . map ( move |i| {
93+ let bytes = opaque_tx. get ( i..i + 32 ) . ok_or (
94+ BlockProcessingError :: BlobVersionHashIndexOutOfBounds {
95+ length : tx_len,
96+ index : i + 32 ,
97+ } ,
98+ ) ?;
99+ Ok ( VersionedHash :: from_slice ( bytes) )
100+ } ) )
87101}
88102
89- fn kzg_commitment_to_versioned_hash ( kzg_commitment : & KZGCommitment ) -> VersionedHash {
90- let mut hashed_commitment = hash_fixed ( kzg_commitment) ;
103+ fn kzg_commitment_to_versioned_hash ( kzg_commitment : & KzgCommitment ) -> VersionedHash {
104+ let mut hashed_commitment = hash_fixed ( & kzg_commitment. 0 ) ;
91105 hashed_commitment[ 0 ] = VERSIONED_HASH_VERSION_KZG ;
92106 VersionedHash :: from ( hashed_commitment)
93107}
0 commit comments