@@ -7,7 +7,7 @@ use superstruct::superstruct;
77use types:: beacon_block_body:: KzgCommitments ;
88use types:: blob_sidecar:: BlobsList ;
99use types:: execution_requests:: {
10- ConsolidationRequests , DepositRequests , RequestPrefix , WithdrawalRequests ,
10+ ConsolidationRequests , DepositRequests , RequestType , WithdrawalRequests ,
1111} ;
1212use types:: { Blob , FixedVector , KzgProof , Unsigned } ;
1313
@@ -341,6 +341,15 @@ impl<E: EthSpec> From<JsonExecutionPayload<E>> for ExecutionPayload<E> {
341341 }
342342}
343343
344+ #[ derive( Debug , Clone ) ]
345+ pub enum RequestsError {
346+ InvalidHex ( hex:: FromHexError ) ,
347+ EmptyRequest ( usize ) ,
348+ InvalidOrdering ,
349+ InvalidPrefix ( u8 ) ,
350+ DecodeError ( String ) ,
351+ }
352+
344353/// Format of `ExecutionRequests` received over the engine api.
345354///
346355/// Array of ssz-encoded requests list encoded as hex bytes.
@@ -355,33 +364,62 @@ impl<E: EthSpec> From<JsonExecutionPayload<E>> for ExecutionPayload<E> {
355364pub struct JsonExecutionRequests ( pub Vec < String > ) ;
356365
357366impl < E : EthSpec > TryFrom < JsonExecutionRequests > for ExecutionRequests < E > {
358- type Error = String ;
367+ type Error = RequestsError ;
359368
360369 fn try_from ( value : JsonExecutionRequests ) -> Result < Self , Self :: Error > {
361370 let mut requests = ExecutionRequests :: default ( ) ;
362-
371+ let mut prev_prefix : Option < RequestType > = None ;
363372 for ( i, request) in value. 0 . into_iter ( ) . enumerate ( ) {
364373 // hex string
365374 let decoded_bytes = hex:: decode ( request. strip_prefix ( "0x" ) . unwrap_or ( & request) )
366- . map_err ( |e| format ! ( "Invalid hex {:?}" , e) ) ?;
367- match RequestPrefix :: from_prefix ( i as u8 ) {
368- Some ( RequestPrefix :: Deposit ) => {
369- requests. deposits = DepositRequests :: < E > :: from_ssz_bytes ( & decoded_bytes)
370- . map_err ( |e| format ! ( "Failed to decode DepositRequest from EL: {:?}" , e) ) ?;
375+ . map_err ( RequestsError :: InvalidHex ) ?;
376+
377+ // The first byte of each element is the `request_type` and the remaining bytes are the `request_data`.
378+ // Elements with empty `request_data` **MUST** be excluded from the list.
379+ let Some ( ( prefix_byte, request_bytes) ) = decoded_bytes. split_first ( ) else {
380+ return Err ( RequestsError :: EmptyRequest ( i) ) ;
381+ } ;
382+ if request_bytes. is_empty ( ) {
383+ return Err ( RequestsError :: EmptyRequest ( i) ) ;
384+ }
385+ // Elements of the list **MUST** be ordered by `request_type` in ascending order
386+ let current_prefix = RequestType :: from_prefix ( * prefix_byte)
387+ . ok_or ( RequestsError :: InvalidPrefix ( * prefix_byte) ) ?;
388+ if let Some ( prev) = prev_prefix {
389+ if prev. to_prefix ( ) >= current_prefix. to_prefix ( ) {
390+ return Err ( RequestsError :: InvalidOrdering ) ;
371391 }
372- Some ( RequestPrefix :: Withdrawal ) => {
373- requests. withdrawals = WithdrawalRequests :: < E > :: from_ssz_bytes ( & decoded_bytes)
392+ }
393+ prev_prefix = Some ( current_prefix) ;
394+
395+ match current_prefix {
396+ RequestType :: Deposit => {
397+ requests. deposits = DepositRequests :: < E > :: from_ssz_bytes ( request_bytes)
374398 . map_err ( |e| {
375- format ! ( "Failed to decode WithdrawalRequest from EL: {:?}" , e)
399+ RequestsError :: DecodeError ( format ! (
400+ "Failed to decode DepositRequest from EL: {:?}" ,
401+ e
402+ ) )
376403 } ) ?;
377404 }
378- Some ( RequestPrefix :: Consolidation ) => {
405+ RequestType :: Withdrawal => {
406+ requests. withdrawals = WithdrawalRequests :: < E > :: from_ssz_bytes ( request_bytes)
407+ . map_err ( |e| {
408+ RequestsError :: DecodeError ( format ! (
409+ "Failed to decode WithdrawalRequest from EL: {:?}" ,
410+ e
411+ ) )
412+ } ) ?;
413+ }
414+ RequestType :: Consolidation => {
379415 requests. consolidations =
380- ConsolidationRequests :: < E > :: from_ssz_bytes ( & decoded_bytes) . map_err (
381- |e| format ! ( "Failed to decode ConsolidationRequest from EL: {:?}" , e) ,
382- ) ?;
416+ ConsolidationRequests :: < E > :: from_ssz_bytes ( request_bytes) . map_err ( |e| {
417+ RequestsError :: DecodeError ( format ! (
418+ "Failed to decode ConsolidationRequest from EL: {:?}" ,
419+ e
420+ ) )
421+ } ) ?;
383422 }
384- None => return Err ( "Empty requests string" . to_string ( ) ) ,
385423 }
386424 }
387425 Ok ( requests)
@@ -448,7 +486,9 @@ impl<E: EthSpec> TryFrom<JsonGetPayloadResponse<E>> for GetPayloadResponse<E> {
448486 block_value : response. block_value ,
449487 blobs_bundle : response. blobs_bundle . into ( ) ,
450488 should_override_builder : response. should_override_builder ,
451- requests : response. execution_requests . try_into ( ) ?,
489+ requests : response. execution_requests . try_into ( ) . map_err ( |e| {
490+ format ! ( "Failed to convert json to execution requests : {:?}" , e)
491+ } ) ?,
452492 } ) )
453493 }
454494 }
0 commit comments