fix: only accept rpc enveloped format for transactions in payload (#4928)

This commit is contained in:
Dan Cline
2023-10-06 13:40:38 -04:00
committed by GitHub
parent 9c8eca6a49
commit c825aafbc8
6 changed files with 175 additions and 32 deletions

View File

@ -10,8 +10,8 @@ use reth_rpc_types::engine::{
PayloadId, PayloadId,
}; };
use reth_rpc_types_compat::engine::payload::{ use reth_rpc_types_compat::engine::payload::{
convert_block_to_payload_field_v2, convert_standalonewithdraw_to_withdrawal, block_to_payload_v3, convert_block_to_payload_field_v2,
try_block_to_payload_v1, try_block_to_payload_v3, convert_standalone_withdraw_to_withdrawal, try_block_to_payload_v1,
}; };
use revm_primitives::{BlobExcessGasAndPrice, BlockEnv, CfgEnv, SpecId}; use revm_primitives::{BlobExcessGasAndPrice, BlockEnv, CfgEnv, SpecId};
/// Contains the built payload. /// Contains the built payload.
@ -100,7 +100,7 @@ impl From<BuiltPayload> for ExecutionPayloadEnvelopeV3 {
let BuiltPayload { block, fees, sidecars, .. } = value; let BuiltPayload { block, fees, sidecars, .. } = value;
ExecutionPayloadEnvelopeV3 { ExecutionPayloadEnvelopeV3 {
execution_payload: try_block_to_payload_v3(block), execution_payload: block_to_payload_v3(block),
block_value: fees, block_value: fees,
// From the engine API spec: // From the engine API spec:
// //
@ -148,7 +148,7 @@ impl PayloadBuilderAttributes {
|withdrawals: Vec<reth_rpc_types::engine::payload::Withdrawal>| { |withdrawals: Vec<reth_rpc_types::engine::payload::Withdrawal>| {
withdrawals withdrawals
.into_iter() .into_iter()
.map(convert_standalonewithdraw_to_withdrawal) // Removed the parentheses here .map(convert_standalone_withdraw_to_withdrawal) // Removed the parentheses here
.collect::<Vec<_>>() .collect::<Vec<_>>()
}, },
); );

View File

@ -876,7 +876,7 @@ impl TransactionSigned {
/// ///
/// For legacy transactions, it encodes the RLP of the transaction into the buffer: `rlp(tx)` /// For legacy transactions, it encodes the RLP of the transaction into the buffer: `rlp(tx)`
/// For EIP-2718 typed it encodes the type of the transaction followed by the rlp of the /// For EIP-2718 typed it encodes the type of the transaction followed by the rlp of the
/// transaction: `type` + `rlp(tx)` /// transaction: `type || rlp(tx)`
pub fn encode_enveloped(&self, out: &mut dyn bytes::BufMut) { pub fn encode_enveloped(&self, out: &mut dyn bytes::BufMut) {
self.encode_inner(out, false) self.encode_inner(out, false)
} }
@ -927,6 +927,9 @@ impl TransactionSigned {
/// Decodes legacy transaction from the data buffer into a tuple. /// Decodes legacy transaction from the data buffer into a tuple.
/// ///
/// This expects `rlp(legacy_tx)` /// This expects `rlp(legacy_tx)`
///
/// Refer to the docs for [Self::decode_rlp_legacy_transaction] for details on the exact
/// format expected.
// TODO: make buf advancement semantics consistent with `decode_enveloped_typed_transaction`, // TODO: make buf advancement semantics consistent with `decode_enveloped_typed_transaction`,
// so decoding methods do not need to manually advance the buffer // so decoding methods do not need to manually advance the buffer
pub(crate) fn decode_rlp_legacy_transaction_tuple( pub(crate) fn decode_rlp_legacy_transaction_tuple(
@ -956,6 +959,12 @@ impl TransactionSigned {
/// Decodes legacy transaction from the data buffer. /// Decodes legacy transaction from the data buffer.
/// ///
/// This should be used _only_ be used in general transaction decoding methods, which have
/// already ensured that the input is a legacy transaction with the following format:
/// `rlp(legacy_tx)`
///
/// Legacy transactions are encoded as lists, so the input should start with a RLP list header.
///
/// This expects `rlp(legacy_tx)` /// This expects `rlp(legacy_tx)`
// TODO: make buf advancement semantics consistent with `decode_enveloped_typed_transaction`, // TODO: make buf advancement semantics consistent with `decode_enveloped_typed_transaction`,
// so decoding methods do not need to manually advance the buffer // so decoding methods do not need to manually advance the buffer
@ -969,7 +978,14 @@ impl TransactionSigned {
/// Decodes en enveloped EIP-2718 typed transaction. /// Decodes en enveloped EIP-2718 typed transaction.
/// ///
/// CAUTION: this expects that `data` is `[id, rlp(tx)]` /// This should be used _only_ be used internally in general transaction decoding methods,
/// which have already ensured that the input is a typed transaction with the following format:
/// `tx_type || rlp(tx)`
///
/// Note that this format does not start with any RLP header, and instead starts with a single
/// byte indicating the transaction type.
///
/// CAUTION: this expects that `data` is `tx_type || rlp(tx)`
pub fn decode_enveloped_typed_transaction( pub fn decode_enveloped_typed_transaction(
data: &mut &[u8], data: &mut &[u8],
) -> alloy_rlp::Result<TransactionSigned> { ) -> alloy_rlp::Result<TransactionSigned> {
@ -1003,12 +1019,23 @@ impl TransactionSigned {
Ok(signed) Ok(signed)
} }
/// Decodes the "raw" format of transaction (e.g. `eth_sendRawTransaction`). /// Decodes the "raw" format of transaction (similar to `eth_sendRawTransaction`).
/// ///
/// The raw transaction is either a legacy transaction or EIP-2718 typed transaction /// This should be used for any RPC method that accepts a raw transaction, **excluding** raw
/// For legacy transactions, the format is encoded as: `rlp(tx)` /// EIP-4844 transactions in `eth_sendRawTransaction`. Currently, this includes:
/// For EIP-2718 typed transaction, the format is encoded as the type of the transaction /// * `eth_sendRawTransaction` for non-EIP-4844 transactions.
/// followed by the rlp of the transaction: `type` + `rlp(tx)` /// * All versions of `engine_newPayload`, in the `transactions` field.
///
/// A raw transaction is either a legacy transaction or EIP-2718 typed transaction.
///
/// For legacy transactions, the format is encoded as: `rlp(tx)`. This format will start with a
/// RLP list header.
///
/// For EIP-2718 typed transactions, the format is encoded as the type of the transaction
/// followed by the rlp of the transaction: `type || rlp(tx)`.
///
/// To decode EIP-4844 transactions in `eth_sendRawTransaction`, use
/// [PooledTransactionsElement::decode_enveloped].
pub fn decode_enveloped(tx: Bytes) -> alloy_rlp::Result<Self> { pub fn decode_enveloped(tx: Bytes) -> alloy_rlp::Result<Self> {
let mut data = tx.as_ref(); let mut data = tx.as_ref();
@ -1045,7 +1072,24 @@ impl Encodable for TransactionSigned {
/// This `Decodable` implementation only supports decoding rlp encoded transactions as it's used by /// This `Decodable` implementation only supports decoding rlp encoded transactions as it's used by
/// p2p. /// p2p.
/// ///
/// CAUTION: this expects that the given buf contains rlp /// The p2p encoding format always includes an RLP header, although the type RLP header depends on
/// whether or not the transaction is a legacy transaction.
///
/// If the transaction is a legacy transaction, it is just encoded as a RLP list: `rlp(tx)`.
///
/// If the transaction is a typed transaction, it is encoded as a RLP string:
/// `rlp(type || rlp(tx))`
///
/// This cannot be used for decoding EIP-4844 transactions in p2p, since the EIP-4844 variant of
/// [TransactionSigned] does not include the blob sidecar. For a general purpose decoding method
/// suitable for decoding transactions from p2p, see [PooledTransactionsElement].
///
/// CAUTION: Due to a quirk in [Header::decode], this method will succeed even if a typed
/// transaction is encoded in the RPC format, and does not start with a RLP header. This is because
/// [Header::decode] does not advance the buffer, and returns a length-1 string header if the first
/// byte is less than `0xf7`. This causes this decode implementation to pass unaltered buffer to
/// [TransactionSigned::decode_enveloped_typed_transaction], which expects the RPC format. Despite
/// this quirk, this should **not** be used for RPC methods that accept raw transactions.
impl Decodable for TransactionSigned { impl Decodable for TransactionSigned {
fn decode(buf: &mut &[u8]) -> alloy_rlp::Result<Self> { fn decode(buf: &mut &[u8]) -> alloy_rlp::Result<Self> {
// decode header // decode header

View File

@ -109,12 +109,28 @@ impl PooledTransactionsElement {
/// Decodes the "raw" format of transaction (e.g. `eth_sendRawTransaction`). /// Decodes the "raw" format of transaction (e.g. `eth_sendRawTransaction`).
/// ///
/// The raw transaction is either a legacy transaction or EIP-2718 typed transaction /// This should be used for `eth_sendRawTransaction`, for any transaction type. Blob
/// For legacy transactions, the format is encoded as: `rlp(tx)` /// transactions **must** include the blob sidecar as part of the raw encoding.
/// For EIP-2718 typed transaction, the format is encoded as the type of the transaction
/// followed by the rlp of the transaction: `type` + `rlp(tx)`
/// ///
/// For encoded EIP-4844 transactions, the blob sidecar _must_ be included. /// This method can not be used for decoding the `transactions` field of `engine_newPayload`,
/// because EIP-4844 transactions for that method do not include the blob sidecar. The blobs
/// are supplied in an argument separate from the payload.
///
/// A raw transaction is either a legacy transaction or EIP-2718 typed transaction, with a
/// special case for EIP-4844 transactions.
///
/// For legacy transactions, the format is encoded as: `rlp(tx)`. This format will start with a
/// RLP list header.
///
/// For EIP-2718 typed transactions, the format is encoded as the type of the transaction
/// followed by the rlp of the transaction: `type || rlp(tx)`.
///
/// For EIP-4844 transactions, the format includes a blob sidecar (the blobs, commitments, and
/// proofs) after the transaction:
/// `type || rlp([tx_payload_body, blobs, commitments, proofs])`
///
/// Where `tx_payload_body` is encoded as a RLP list:
/// `[chain_id, nonce, max_priority_fee_per_gas, ..., y_parity, r, s]`
pub fn decode_enveloped(tx: Bytes) -> alloy_rlp::Result<Self> { pub fn decode_enveloped(tx: Bytes) -> alloy_rlp::Result<Self> {
let mut data = tx.as_ref(); let mut data = tx.as_ref();

View File

@ -13,7 +13,7 @@ use reth_rpc_types::engine::{
ExecutionPayload, ExecutionPayloadBodyV1, ExecutionPayloadV1, PayloadError, ExecutionPayload, ExecutionPayloadBodyV1, ExecutionPayloadV1, PayloadError,
}; };
use reth_rpc_types_compat::engine::payload::{ use reth_rpc_types_compat::engine::payload::{
convert_standalonewithdraw_to_withdrawal, convert_to_payload_body_v1, try_block_to_payload, convert_standalone_withdraw_to_withdrawal, convert_to_payload_body_v1, try_block_to_payload,
try_block_to_payload_v1, try_into_sealed_block, try_payload_v1_to_block, try_block_to_payload_v1, try_into_sealed_block, try_payload_v1_to_block,
}; };
@ -49,7 +49,7 @@ fn payload_body_roundtrip() {
let withdraw = payload_body.withdrawals.map(|withdrawals| { let withdraw = payload_body.withdrawals.map(|withdrawals| {
withdrawals withdrawals
.into_iter() .into_iter()
.map(convert_standalonewithdraw_to_withdrawal) .map(convert_standalone_withdraw_to_withdrawal)
.collect::<Vec<_>>() .collect::<Vec<_>>()
}); });
assert_eq!(block.withdrawals, withdraw); assert_eq!(block.withdrawals, withdraw);

View File

@ -1,6 +1,6 @@
//! Standalone functions for engine specific rpc type conversions //! Standalone functions for engine specific rpc type conversions
pub mod payload; pub mod payload;
pub use payload::{ pub use payload::{
convert_standalonewithdraw_to_withdrawal, convert_withdrawal_to_standalonewithdraw, convert_standalone_withdraw_to_withdrawal, convert_withdrawal_to_standalone_withdraw,
try_block_to_payload_v1, try_into_sealed_block, try_payload_v1_to_block, try_block_to_payload_v1, try_into_sealed_block, try_payload_v1_to_block,
}; };

View File

@ -1,6 +1,5 @@
//! Standalone Conversion Functions for Handling Different Versions of Execution Payloads in //! Standalone Conversion Functions for Handling Different Versions of Execution Payloads in
//! Ethereum's Engine //! Ethereum's Engine
use alloy_rlp::Decodable;
use reth_primitives::{ use reth_primitives::{
constants::{MAXIMUM_EXTRA_DATA_SIZE, MIN_PROTOCOL_BASE_FEE_U256}, constants::{MAXIMUM_EXTRA_DATA_SIZE, MIN_PROTOCOL_BASE_FEE_U256},
proofs::{self, EMPTY_LIST_HASH}, proofs::{self, EMPTY_LIST_HASH},
@ -23,8 +22,8 @@ pub fn try_payload_v1_to_block(payload: ExecutionPayloadV1) -> Result<Block, Pay
let transactions = payload let transactions = payload
.transactions .transactions
.iter() .into_iter()
.map(|tx| TransactionSigned::decode(&mut tx.as_ref())) .map(TransactionSigned::decode_enveloped)
.collect::<Result<Vec<_>, _>>()?; .collect::<Result<Vec<_>, _>>()?;
let transactions_root = proofs::calculate_transaction_root(&transactions); let transactions_root = proofs::calculate_transaction_root(&transactions);
@ -68,7 +67,7 @@ pub fn try_payload_v2_to_block(payload: ExecutionPayloadV2) -> Result<Block, Pay
let withdrawals: Vec<_> = payload let withdrawals: Vec<_> = payload
.withdrawals .withdrawals
.iter() .iter()
.map(|w| convert_standalonewithdraw_to_withdrawal(w.clone())) .map(|w| convert_standalone_withdraw_to_withdrawal(w.clone()))
.collect(); .collect();
let withdrawals_root = proofs::calculate_withdrawals_root(&withdrawals); let withdrawals_root = proofs::calculate_withdrawals_root(&withdrawals);
base_sealed_block.withdrawals = Some(withdrawals); base_sealed_block.withdrawals = Some(withdrawals);
@ -92,7 +91,7 @@ pub fn try_payload_v3_to_block(payload: ExecutionPayloadV3) -> Result<Block, Pay
pub fn try_block_to_payload(value: SealedBlock) -> ExecutionPayload { pub fn try_block_to_payload(value: SealedBlock) -> ExecutionPayload {
if value.header.parent_beacon_block_root.is_some() { if value.header.parent_beacon_block_root.is_some() {
// block with parent beacon block root: V3 // block with parent beacon block root: V3
ExecutionPayload::V3(try_block_to_payload_v3(value)) ExecutionPayload::V3(block_to_payload_v3(value))
} else if value.withdrawals.is_some() { } else if value.withdrawals.is_some() {
// block with withdrawals: V2 // block with withdrawals: V2
ExecutionPayload::V2(try_block_to_payload_v2(value)) ExecutionPayload::V2(try_block_to_payload_v2(value))
@ -147,7 +146,7 @@ pub fn try_block_to_payload_v2(value: SealedBlock) -> ExecutionPayloadV2 {
.clone() .clone()
.unwrap_or_default() .unwrap_or_default()
.into_iter() .into_iter()
.map(convert_withdrawal_to_standalonewithdraw) .map(convert_withdrawal_to_standalone_withdraw)
.collect(); .collect();
ExecutionPayloadV2 { ExecutionPayloadV2 {
@ -172,7 +171,7 @@ pub fn try_block_to_payload_v2(value: SealedBlock) -> ExecutionPayloadV2 {
} }
/// Converts [SealedBlock] to [ExecutionPayloadV3] /// Converts [SealedBlock] to [ExecutionPayloadV3]
pub fn try_block_to_payload_v3(value: SealedBlock) -> ExecutionPayloadV3 { pub fn block_to_payload_v3(value: SealedBlock) -> ExecutionPayloadV3 {
let transactions = value let transactions = value
.body .body
.iter() .iter()
@ -188,7 +187,7 @@ pub fn try_block_to_payload_v3(value: SealedBlock) -> ExecutionPayloadV3 {
.clone() .clone()
.unwrap_or_default() .unwrap_or_default()
.into_iter() .into_iter()
.map(convert_withdrawal_to_standalonewithdraw) .map(convert_withdrawal_to_standalone_withdraw)
.collect(); .collect();
ExecutionPayloadV3 { ExecutionPayloadV3 {
@ -249,7 +248,7 @@ pub fn convert_payload_input_v2_to_payload(value: ExecutionPayloadInputV2) -> Ex
/// Converts [SealedBlock] to [ExecutionPayloadInputV2] /// Converts [SealedBlock] to [ExecutionPayloadInputV2]
pub fn convert_block_to_payload_input_v2(value: SealedBlock) -> ExecutionPayloadInputV2 { pub fn convert_block_to_payload_input_v2(value: SealedBlock) -> ExecutionPayloadInputV2 {
let withdraw = value.withdrawals.clone().map(|withdrawals| { let withdraw = value.withdrawals.clone().map(|withdrawals| {
withdrawals.into_iter().map(convert_withdrawal_to_standalonewithdraw).collect::<Vec<_>>() withdrawals.into_iter().map(convert_withdrawal_to_standalone_withdraw).collect::<Vec<_>>()
}); });
ExecutionPayloadInputV2 { ExecutionPayloadInputV2 {
withdrawals: withdraw, withdrawals: withdraw,
@ -321,7 +320,7 @@ pub fn validate_block_hash(
} }
/// Converts [Withdrawal] to [reth_rpc_types::engine::payload::Withdrawal] /// Converts [Withdrawal] to [reth_rpc_types::engine::payload::Withdrawal]
pub fn convert_withdrawal_to_standalonewithdraw( pub fn convert_withdrawal_to_standalone_withdraw(
withdrawal: Withdrawal, withdrawal: Withdrawal,
) -> reth_rpc_types::engine::payload::Withdrawal { ) -> reth_rpc_types::engine::payload::Withdrawal {
reth_rpc_types::engine::payload::Withdrawal { reth_rpc_types::engine::payload::Withdrawal {
@ -333,7 +332,7 @@ pub fn convert_withdrawal_to_standalonewithdraw(
} }
/// Converts [reth_rpc_types::engine::payload::Withdrawal] to [Withdrawal] /// Converts [reth_rpc_types::engine::payload::Withdrawal] to [Withdrawal]
pub fn convert_standalonewithdraw_to_withdrawal( pub fn convert_standalone_withdraw_to_withdrawal(
standalone: reth_rpc_types::engine::payload::Withdrawal, standalone: reth_rpc_types::engine::payload::Withdrawal,
) -> Withdrawal { ) -> Withdrawal {
Withdrawal { Withdrawal {
@ -355,8 +354,92 @@ pub fn convert_to_payload_body_v1(value: Block) -> ExecutionPayloadBodyV1 {
value.withdrawals.map(|withdrawals| { value.withdrawals.map(|withdrawals| {
withdrawals withdrawals
.into_iter() .into_iter()
.map(convert_withdrawal_to_standalonewithdraw) .map(convert_withdrawal_to_standalone_withdraw)
.collect::<Vec<_>>() .collect::<Vec<_>>()
}); });
ExecutionPayloadBodyV1 { transactions: transactions.collect(), withdrawals: withdraw } ExecutionPayloadBodyV1 { transactions: transactions.collect(), withdrawals: withdraw }
} }
#[cfg(test)]
mod tests {
use reth_primitives::{hex, Bytes, U256, U64};
use reth_rpc_types::{engine::ExecutionPayloadV3, ExecutionPayloadV1, ExecutionPayloadV2};
use super::{block_to_payload_v3, try_payload_v3_to_block};
#[test]
fn roundtrip_payload_to_block() {
let first_transaction_raw = Bytes::from_static(&hex!("02f9017a8501a1f0ff438211cc85012a05f2008512a05f2000830249f094d5409474fd5a725eab2ac9a8b26ca6fb51af37ef80b901040cc7326300000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000001bdd2ed4b616c800000000000000000000000000001e9ee781dd4b97bdef92e5d1785f73a1f931daa20000000000000000000000007a40026a3b9a41754a95eec8c92c6b99886f440c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000009ae80eb647dd09968488fa1d7e412bf8558a0b7a0000000000000000000000000f9815537d361cb02befd9918c95c97d4d8a4a2bc001a0ba8f1928bb0efc3fcd01524a2039a9a2588fa567cd9a7cc18217e05c615e9d69a0544bfd11425ac7748e76b3795b57a5563e2b0eff47b5428744c62ff19ccfc305")[..]);
let second_transaction_raw = Bytes::from_static(&hex!("03f901388501a1f0ff430c843b9aca00843b9aca0082520894e7249813d8ccf6fa95a2203f46a64166073d58878080c005f8c6a00195f6dff17753fc89b60eac6477026a805116962c9e412de8015c0484e661c1a001aae314061d4f5bbf158f15d9417a238f9589783f58762cd39d05966b3ba2fba0013f5be9b12e7da06f0dd11a7bdc4e0db8ef33832acc23b183bd0a2c1408a757a0019d9ac55ea1a615d92965e04d960cb3be7bff121a381424f1f22865bd582e09a001def04412e76df26fefe7b0ed5e10580918ae4f355b074c0cfe5d0259157869a0011c11a415db57e43db07aef0de9280b591d65ca0cce36c7002507f8191e5d4a80a0c89b59970b119187d97ad70539f1624bbede92648e2dc007890f9658a88756c5a06fb2e3d4ce2c438c0856c2de34948b7032b1aadc4642a9666228ea8cdc7786b7")[..]);
let new_payload = ExecutionPayloadV3 {
payload_inner: ExecutionPayloadV2 {
payload_inner: ExecutionPayloadV1 {
base_fee_per_gas: U256::from(7u64),
block_number: U64::from(0xa946u64),
block_hash: hex!("a5ddd3f286f429458a39cafc13ffe89295a7efa8eb363cf89a1a4887dbcf272b").into(),
logs_bloom: hex!("00200004000000000000000080000000000200000000000000000000000000000000200000000000000000000000000000000000800000000200000000000000000000000000000000000008000000200000000000000000000001000000000000000000000000000000800000000000000000000100000000000030000000000000000040000000000000000000000000000000000800080080404000000000000008000000000008200000000000200000000000000000000000000000000000000002000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000100000000000000000000").into(),
extra_data: hex!("d883010d03846765746888676f312e32312e31856c696e7578").into(),
gas_limit: U64::from(0x1c9c380),
gas_used: U64::from(0x1f4a9),
timestamp: U64::from(0x651f35b8),
fee_recipient: hex!("f97e180c050e5ab072211ad2c213eb5aee4df134").into(),
parent_hash: hex!("d829192799c73ef28a7332313b3c03af1f2d5da2c36f8ecfafe7a83a3bfb8d1e").into(),
prev_randao: hex!("753888cc4adfbeb9e24e01c84233f9d204f4a9e1273f0e29b43c4c148b2b8b7e").into(),
receipts_root: hex!("4cbc48e87389399a0ea0b382b1c46962c4b8e398014bf0cc610f9c672bee3155").into(),
state_root: hex!("017d7fa2b5adb480f5e05b2c95cb4186e12062eed893fc8822798eed134329d1").into(),
transactions: vec![first_transaction_raw, second_transaction_raw],
},
withdrawals: vec![],
},
blob_gas_used: U64::from(0xc0000),
excess_blob_gas: U64::from(0x580000),
};
let mut block = try_payload_v3_to_block(new_payload.clone()).unwrap();
// this newPayload came with a parent beacon block root, we need to manually insert it
// before hashing
let parent_beacon_block_root =
hex!("531cd53b8e68deef0ea65edfa3cda927a846c307b0907657af34bc3f313b5871");
block.header.parent_beacon_block_root = Some(parent_beacon_block_root.into());
let converted_payload = block_to_payload_v3(block.seal_slow());
// ensure the payloads are the same
assert_eq!(new_payload, converted_payload);
}
#[test]
fn payload_to_block_rejects_network_encoded_tx() {
let first_transaction_raw = Bytes::from_static(&hex!("b9017e02f9017a8501a1f0ff438211cc85012a05f2008512a05f2000830249f094d5409474fd5a725eab2ac9a8b26ca6fb51af37ef80b901040cc7326300000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000001bdd2ed4b616c800000000000000000000000000001e9ee781dd4b97bdef92e5d1785f73a1f931daa20000000000000000000000007a40026a3b9a41754a95eec8c92c6b99886f440c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000009ae80eb647dd09968488fa1d7e412bf8558a0b7a0000000000000000000000000f9815537d361cb02befd9918c95c97d4d8a4a2bc001a0ba8f1928bb0efc3fcd01524a2039a9a2588fa567cd9a7cc18217e05c615e9d69a0544bfd11425ac7748e76b3795b57a5563e2b0eff47b5428744c62ff19ccfc305")[..]);
let second_transaction_raw = Bytes::from_static(&hex!("b9013c03f901388501a1f0ff430c843b9aca00843b9aca0082520894e7249813d8ccf6fa95a2203f46a64166073d58878080c005f8c6a00195f6dff17753fc89b60eac6477026a805116962c9e412de8015c0484e661c1a001aae314061d4f5bbf158f15d9417a238f9589783f58762cd39d05966b3ba2fba0013f5be9b12e7da06f0dd11a7bdc4e0db8ef33832acc23b183bd0a2c1408a757a0019d9ac55ea1a615d92965e04d960cb3be7bff121a381424f1f22865bd582e09a001def04412e76df26fefe7b0ed5e10580918ae4f355b074c0cfe5d0259157869a0011c11a415db57e43db07aef0de9280b591d65ca0cce36c7002507f8191e5d4a80a0c89b59970b119187d97ad70539f1624bbede92648e2dc007890f9658a88756c5a06fb2e3d4ce2c438c0856c2de34948b7032b1aadc4642a9666228ea8cdc7786b7")[..]);
let new_payload = ExecutionPayloadV3 {
payload_inner: ExecutionPayloadV2 {
payload_inner: ExecutionPayloadV1 {
base_fee_per_gas: U256::from(7u64),
block_number: U64::from(0xa946u64),
block_hash: hex!("a5ddd3f286f429458a39cafc13ffe89295a7efa8eb363cf89a1a4887dbcf272b").into(),
logs_bloom: hex!("00200004000000000000000080000000000200000000000000000000000000000000200000000000000000000000000000000000800000000200000000000000000000000000000000000008000000200000000000000000000001000000000000000000000000000000800000000000000000000100000000000030000000000000000040000000000000000000000000000000000800080080404000000000000008000000000008200000000000200000000000000000000000000000000000000002000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000100000000000000000000").into(),
extra_data: hex!("d883010d03846765746888676f312e32312e31856c696e7578").into(),
gas_limit: U64::from(0x1c9c380),
gas_used: U64::from(0x1f4a9),
timestamp: U64::from(0x651f35b8),
fee_recipient: hex!("f97e180c050e5ab072211ad2c213eb5aee4df134").into(),
parent_hash: hex!("d829192799c73ef28a7332313b3c03af1f2d5da2c36f8ecfafe7a83a3bfb8d1e").into(),
prev_randao: hex!("753888cc4adfbeb9e24e01c84233f9d204f4a9e1273f0e29b43c4c148b2b8b7e").into(),
receipts_root: hex!("4cbc48e87389399a0ea0b382b1c46962c4b8e398014bf0cc610f9c672bee3155").into(),
state_root: hex!("017d7fa2b5adb480f5e05b2c95cb4186e12062eed893fc8822798eed134329d1").into(),
transactions: vec![first_transaction_raw, second_transaction_raw],
},
withdrawals: vec![],
},
blob_gas_used: U64::from(0xc0000),
excess_blob_gas: U64::from(0x580000),
};
let _block = try_payload_v3_to_block(new_payload.clone())
.expect_err("execution payload conversion requires typed txs without a rlp header");
}
}