@@ -26,6 +26,11 @@ use core::iter::{FromIterator, IntoIterator};
2626/// The execution payload body response that allows for `null` values.
2727pub type ExecutionPayloadBodiesV1 = Vec < Option < ExecutionPayloadBodyV1 > > ;
2828
29+ /// The execution payload body V2 response that allows for `null` values.
30+ ///
31+ /// See also: <https://eips.ethereum.org/EIPS/eip-7928>
32+ pub type ExecutionPayloadBodiesV2 = Vec < Option < ExecutionPayloadBodyV2 > > ;
33+
2934/// And 8-byte identifier for an execution payload.
3035#[ derive( Clone , Copy , Debug , PartialEq , Eq , Hash , Default ) ]
3136#[ cfg_attr( feature = "serde" , derive( serde:: Serialize , serde:: Deserialize ) ) ]
@@ -2292,6 +2297,69 @@ impl<T: Encodable2718, H> From<Block<T, H>> for ExecutionPayloadBodyV1 {
22922297 }
22932298}
22942299
2300+ /// This structure contains a body of an execution payload (V2).
2301+ ///
2302+ /// V2 extends V1 with the `blockAccessList` field introduced in EIP-7928.
2303+ ///
2304+ /// See also: <https://eips.ethereum.org/EIPS/eip-7928>
2305+ #[ derive( Clone , Debug , PartialEq , Eq ) ]
2306+ #[ cfg_attr( feature = "serde" , derive( serde:: Serialize , serde:: Deserialize ) ) ]
2307+ #[ cfg_attr( feature = "serde" , serde( rename_all = "camelCase" ) ) ]
2308+ #[ cfg_attr( any( test, feature = "arbitrary" ) , derive( arbitrary:: Arbitrary ) ) ]
2309+ pub struct ExecutionPayloadBodyV2 {
2310+ /// Enveloped encoded transactions.
2311+ pub transactions : Vec < Bytes > ,
2312+ /// All withdrawals in the block.
2313+ ///
2314+ /// Will always be `None` if pre shanghai.
2315+ pub withdrawals : Option < Vec < Withdrawal > > ,
2316+ /// The RLP-encoded block access list.
2317+ ///
2318+ /// Will be `None` for pre-Amsterdam blocks or when data has been pruned.
2319+ pub block_access_list : Option < Bytes > ,
2320+ }
2321+
2322+ impl ExecutionPayloadBodyV2 {
2323+ /// Creates an [`ExecutionPayloadBodyV2`] from the given withdrawals, transactions, and block
2324+ /// access list.
2325+ pub fn new < ' a , T > (
2326+ withdrawals : Option < Withdrawals > ,
2327+ transactions : impl IntoIterator < Item = & ' a T > ,
2328+ block_access_list : Option < Bytes > ,
2329+ ) -> Self
2330+ where
2331+ T : Encodable2718 + ' a ,
2332+ {
2333+ Self {
2334+ transactions : transactions. into_iter ( ) . map ( |tx| tx. encoded_2718 ( ) . into ( ) ) . collect ( ) ,
2335+ withdrawals : withdrawals. map ( Withdrawals :: into_inner) ,
2336+ block_access_list,
2337+ }
2338+ }
2339+
2340+ /// Converts a [`alloy_consensus::Block`] into an execution payload body, with an optional
2341+ /// block access list.
2342+ pub fn from_block < T : Encodable2718 , H > (
2343+ block : Block < T , H > ,
2344+ block_access_list : Option < Bytes > ,
2345+ ) -> Self {
2346+ let BlockBody { withdrawals, transactions, .. } = block. into_body ( ) ;
2347+ Self :: new ( withdrawals, transactions. iter ( ) , block_access_list)
2348+ }
2349+ }
2350+
2351+ impl From < ExecutionPayloadBodyV1 > for ExecutionPayloadBodyV2 {
2352+ fn from ( v1 : ExecutionPayloadBodyV1 ) -> Self {
2353+ Self { transactions : v1. transactions , withdrawals : v1. withdrawals , block_access_list : None }
2354+ }
2355+ }
2356+
2357+ impl From < ExecutionPayloadBodyV2 > for ExecutionPayloadBodyV1 {
2358+ fn from ( v2 : ExecutionPayloadBodyV2 ) -> Self {
2359+ Self { transactions : v2. transactions , withdrawals : v2. withdrawals }
2360+ }
2361+ }
2362+
22952363/// This structure contains the attributes required to initiate a payload build process in the
22962364/// context of an `engine_forkchoiceUpdated` call.
22972365#[ derive( Clone , Debug , Default , PartialEq , Eq ) ]
@@ -3398,4 +3466,73 @@ mod tests {
33983466 assert_eq ! ( with_encoded. encoded_bytes( ) , & transaction) ;
33993467 }
34003468 }
3469+
3470+ #[ test]
3471+ #[ cfg( feature = "serde" ) ]
3472+ fn serde_execution_payload_body_v2 ( ) {
3473+ let body = ExecutionPayloadBodyV2 {
3474+ transactions : vec ! [ Bytes :: from( vec![ 0x01 , 0x02 , 0x03 ] ) ] ,
3475+ withdrawals : Some ( vec ! [ Withdrawal {
3476+ index: 1 ,
3477+ validator_index: 2 ,
3478+ address: Address :: default ( ) ,
3479+ amount: 100 ,
3480+ } ] ) ,
3481+ block_access_list : Some ( Bytes :: from ( vec ! [ 0xaa , 0xbb , 0xcc ] ) ) ,
3482+ } ;
3483+
3484+ let serialized = serde_json:: to_string ( & body) . unwrap ( ) ;
3485+ let deserialized: ExecutionPayloadBodyV2 = serde_json:: from_str ( & serialized) . unwrap ( ) ;
3486+ assert_eq ! ( deserialized, body) ;
3487+ }
3488+
3489+ #[ test]
3490+ #[ cfg( feature = "serde" ) ]
3491+ fn serde_execution_payload_body_v2_null_fields ( ) {
3492+ let body = ExecutionPayloadBodyV2 {
3493+ transactions : vec ! [ ] ,
3494+ withdrawals : None ,
3495+ block_access_list : None ,
3496+ } ;
3497+
3498+ let serialized = serde_json:: to_string ( & body) . unwrap ( ) ;
3499+ let deserialized: ExecutionPayloadBodyV2 = serde_json:: from_str ( & serialized) . unwrap ( ) ;
3500+ assert_eq ! ( deserialized, body) ;
3501+ }
3502+
3503+ #[ test]
3504+ fn execution_payload_body_v1_to_v2_conversion ( ) {
3505+ let v1 = ExecutionPayloadBodyV1 {
3506+ transactions : vec ! [ Bytes :: from( vec![ 0x01 , 0x02 ] ) ] ,
3507+ withdrawals : Some ( vec ! [ Withdrawal {
3508+ index: 1 ,
3509+ validator_index: 2 ,
3510+ address: Address :: default ( ) ,
3511+ amount: 100 ,
3512+ } ] ) ,
3513+ } ;
3514+
3515+ let v2: ExecutionPayloadBodyV2 = v1. clone ( ) . into ( ) ;
3516+ assert_eq ! ( v2. transactions, v1. transactions) ;
3517+ assert_eq ! ( v2. withdrawals, v1. withdrawals) ;
3518+ assert_eq ! ( v2. block_access_list, None ) ;
3519+ }
3520+
3521+ #[ test]
3522+ fn execution_payload_body_v2_to_v1_conversion ( ) {
3523+ let v2 = ExecutionPayloadBodyV2 {
3524+ transactions : vec ! [ Bytes :: from( vec![ 0x01 , 0x02 ] ) ] ,
3525+ withdrawals : Some ( vec ! [ Withdrawal {
3526+ index: 1 ,
3527+ validator_index: 2 ,
3528+ address: Address :: default ( ) ,
3529+ amount: 100 ,
3530+ } ] ) ,
3531+ block_access_list : Some ( Bytes :: from ( vec ! [ 0xaa , 0xbb ] ) ) ,
3532+ } ;
3533+
3534+ let v1: ExecutionPayloadBodyV1 = v2. clone ( ) . into ( ) ;
3535+ assert_eq ! ( v1. transactions, v2. transactions) ;
3536+ assert_eq ! ( v1. withdrawals, v2. withdrawals) ;
3537+ }
34013538}
0 commit comments