mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
eip4844: use alloy TxEip4844 (#10624)
Co-authored-by: joshieDo <93316087+joshieDo@users.noreply.github.com>
This commit is contained in:
@ -419,7 +419,6 @@ mod tests {
|
||||
max_priority_fee_per_gas: 0x28f000fff,
|
||||
max_fee_per_blob_gas: 0x7,
|
||||
gas_limit: 10,
|
||||
placeholder: Some(()),
|
||||
to: Address::default(),
|
||||
value: U256::from(3_u64),
|
||||
input: Bytes::from(vec![1, 2]),
|
||||
|
||||
@ -100,7 +100,7 @@ arbitrary = [
|
||||
"reth-codec",
|
||||
]
|
||||
secp256k1 = ["dep:secp256k1"]
|
||||
c-kzg = ["dep:c-kzg", "revm-primitives/c-kzg", "dep:tempfile", "alloy-eips/kzg"]
|
||||
c-kzg = ["dep:c-kzg", "revm-primitives/c-kzg", "dep:tempfile", "alloy-eips/kzg", "alloy-consensus/kzg"]
|
||||
optimism = [
|
||||
"reth-chainspec/optimism",
|
||||
"reth-ethereum-forks/optimism",
|
||||
|
||||
@ -150,11 +150,7 @@ impl TryFrom<WithOtherFields<alloy_rpc_types::Transaction>> for Transaction {
|
||||
max_fee_per_gas: tx
|
||||
.max_fee_per_gas
|
||||
.ok_or(ConversionError::MissingMaxFeePerGas)?,
|
||||
gas_limit: tx
|
||||
.gas
|
||||
.try_into()
|
||||
.map_err(|_| ConversionError::Eip2718Error(RlpError::Overflow.into()))?,
|
||||
placeholder: tx.to.map(drop),
|
||||
gas_limit: tx.gas,
|
||||
to: tx.to.unwrap_or_default(),
|
||||
value: tx.value,
|
||||
access_list: tx.access_list.ok_or(ConversionError::MissingAccessList)?,
|
||||
|
||||
@ -64,7 +64,7 @@ impl FillTxEnv for TransactionSigned {
|
||||
tx_env.authorization_list = None;
|
||||
}
|
||||
Transaction::Eip4844(tx) => {
|
||||
tx_env.gas_limit = tx.gas_limit;
|
||||
tx_env.gas_limit = tx.gas_limit as u64;
|
||||
tx_env.gas_price = U256::from(tx.max_fee_per_gas);
|
||||
tx_env.gas_priority_fee = Some(U256::from(tx.max_priority_fee_per_gas));
|
||||
tx_env.transact_to = TxKind::Call(tx.to);
|
||||
|
||||
@ -1,324 +1 @@
|
||||
use super::access_list::AccessList;
|
||||
use crate::{
|
||||
constants::eip4844::DATA_GAS_PER_BLOB, keccak256, Address, Bytes, ChainId, Signature, TxType,
|
||||
B256, U256,
|
||||
};
|
||||
use alloy_rlp::{length_of_length, Decodable, Encodable, Header};
|
||||
use core::mem;
|
||||
|
||||
#[cfg(any(test, feature = "reth-codec"))]
|
||||
use reth_codecs::Compact;
|
||||
|
||||
/// To be used with `Option<CompactPlaceholder>` to place or replace one bit on the bitflag struct.
|
||||
pub(crate) type CompactPlaceholder = ();
|
||||
|
||||
#[cfg(feature = "c-kzg")]
|
||||
use crate::kzg::KzgSettings;
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
use alloc::vec::Vec;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// [EIP-4844 Blob Transaction](https://eips.ethereum.org/EIPS/eip-4844#blob-transaction)
|
||||
///
|
||||
/// A transaction with blob hashes and max blob fee
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Default, Serialize, Deserialize)]
|
||||
#[cfg_attr(any(test, feature = "arbitrary"), derive(arbitrary::Arbitrary))]
|
||||
#[cfg_attr(any(test, feature = "reth-codec"), derive(Compact))]
|
||||
#[cfg_attr(any(test, feature = "reth-codec"), reth_codecs::add_arbitrary_tests(compact))]
|
||||
pub struct TxEip4844 {
|
||||
/// Added as EIP-155: Simple replay attack protection
|
||||
pub chain_id: ChainId,
|
||||
|
||||
/// A scalar value equal to the number of transactions sent by the sender; formally Tn.
|
||||
pub nonce: u64,
|
||||
|
||||
/// A scalar value equal to the maximum
|
||||
/// amount of gas that should be used in executing
|
||||
/// this transaction. This is paid up-front, before any
|
||||
/// computation is done and may not be increased
|
||||
/// later; formally Tg.
|
||||
pub gas_limit: u64,
|
||||
|
||||
/// A scalar value equal to the maximum
|
||||
/// amount of gas that should be used in executing
|
||||
/// this transaction. This is paid up-front, before any
|
||||
/// computation is done and may not be increased
|
||||
/// later; formally Tg.
|
||||
///
|
||||
/// As ethereum circulation is around 120mil eth as of 2022 that is around
|
||||
/// 120000000000000000000000000 wei we are safe to use u128 as its max number is:
|
||||
/// 340282366920938463463374607431768211455
|
||||
///
|
||||
/// This is also known as `GasFeeCap`
|
||||
pub max_fee_per_gas: u128,
|
||||
|
||||
/// Max Priority fee that transaction is paying
|
||||
///
|
||||
/// As ethereum circulation is around 120mil eth as of 2022 that is around
|
||||
/// 120000000000000000000000000 wei we are safe to use u128 as its max number is:
|
||||
/// 340282366920938463463374607431768211455
|
||||
///
|
||||
/// This is also known as `GasTipCap`
|
||||
pub max_priority_fee_per_gas: u128,
|
||||
|
||||
/// TODO(debt): this should be removed if we break the DB.
|
||||
/// Makes sure that the Compact bitflag struct has one bit after the above field:
|
||||
/// <https://github.com/paradigmxyz/reth/pull/8291#issuecomment-2117545016>
|
||||
pub placeholder: Option<CompactPlaceholder>,
|
||||
|
||||
/// The 160-bit address of the message call’s recipient.
|
||||
pub to: Address,
|
||||
|
||||
/// A scalar value equal to the number of Wei to
|
||||
/// be transferred to the message call’s recipient or,
|
||||
/// in the case of contract creation, as an endowment
|
||||
/// to the newly created account; formally Tv.
|
||||
pub value: U256,
|
||||
|
||||
/// The accessList specifies a list of addresses and storage keys;
|
||||
/// these addresses and storage keys are added into the `accessed_addresses`
|
||||
/// and `accessed_storage_keys` global sets (introduced in EIP-2929).
|
||||
/// A gas cost is charged, though at a discount relative to the cost of
|
||||
/// accessing outside the list.
|
||||
pub access_list: AccessList,
|
||||
|
||||
/// It contains a vector of fixed size hash(32 bytes)
|
||||
pub blob_versioned_hashes: Vec<B256>,
|
||||
|
||||
/// Max fee per data gas
|
||||
///
|
||||
/// aka BlobFeeCap or blobGasFeeCap
|
||||
pub max_fee_per_blob_gas: u128,
|
||||
|
||||
/// Unlike other transaction types, where the `input` field has two uses depending on whether
|
||||
/// or not the `to` field is [`Create`](crate::TxKind::Create) or
|
||||
/// [`Call`](crate::TxKind::Call), EIP-4844 transactions cannot be
|
||||
/// [`Create`](crate::TxKind::Create) transactions.
|
||||
///
|
||||
/// This means the `input` field has a single use, as data: An unlimited size byte array
|
||||
/// specifying the input data of the message call, formally Td.
|
||||
pub input: Bytes,
|
||||
}
|
||||
|
||||
impl TxEip4844 {
|
||||
/// Returns the effective gas price for the given `base_fee`.
|
||||
pub const fn effective_gas_price(&self, base_fee: Option<u64>) -> u128 {
|
||||
match base_fee {
|
||||
None => self.max_fee_per_gas,
|
||||
Some(base_fee) => {
|
||||
// if the tip is greater than the max priority fee per gas, set it to the max
|
||||
// priority fee per gas + base fee
|
||||
let tip = self.max_fee_per_gas.saturating_sub(base_fee as u128);
|
||||
if tip > self.max_priority_fee_per_gas {
|
||||
self.max_priority_fee_per_gas + base_fee as u128
|
||||
} else {
|
||||
// otherwise return the max fee per gas
|
||||
self.max_fee_per_gas
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Verifies that the given blob data, commitments, and proofs are all valid for this
|
||||
/// transaction.
|
||||
///
|
||||
/// Takes as input the [`KzgSettings`], which should contain the parameters derived from the
|
||||
/// KZG trusted setup.
|
||||
///
|
||||
/// This ensures that the blob transaction payload has the same number of blob data elements,
|
||||
/// commitments, and proofs. Each blob data element is verified against its commitment and
|
||||
/// proof.
|
||||
///
|
||||
/// Returns `InvalidProof` if any blob KZG proof in the response
|
||||
/// fails to verify, or if the versioned hashes in the transaction do not match the actual
|
||||
/// commitment versioned hashes.
|
||||
#[cfg(feature = "c-kzg")]
|
||||
pub fn validate_blob(
|
||||
&self,
|
||||
sidecar: &crate::BlobTransactionSidecar,
|
||||
proof_settings: &KzgSettings,
|
||||
) -> Result<(), alloy_eips::eip4844::BlobTransactionValidationError> {
|
||||
sidecar.validate(&self.blob_versioned_hashes, proof_settings)
|
||||
}
|
||||
|
||||
/// Returns the total gas for all blobs in this transaction.
|
||||
#[inline]
|
||||
pub fn blob_gas(&self) -> u64 {
|
||||
// NOTE: we don't expect u64::MAX / DATA_GAS_PER_BLOB hashes in a single transaction
|
||||
self.blob_versioned_hashes.len() as u64 * DATA_GAS_PER_BLOB
|
||||
}
|
||||
|
||||
/// Decodes the inner [`TxEip4844`] fields from RLP bytes.
|
||||
///
|
||||
/// NOTE: This assumes a RLP header has already been decoded, and _just_ decodes the following
|
||||
/// RLP fields in the following order:
|
||||
///
|
||||
/// - `chain_id`
|
||||
/// - `nonce`
|
||||
/// - `max_priority_fee_per_gas`
|
||||
/// - `max_fee_per_gas`
|
||||
/// - `gas_limit`
|
||||
/// - `to`
|
||||
/// - `value`
|
||||
/// - `data` (`input`)
|
||||
/// - `access_list`
|
||||
/// - `max_fee_per_blob_gas`
|
||||
/// - `blob_versioned_hashes`
|
||||
pub fn decode_inner(buf: &mut &[u8]) -> alloy_rlp::Result<Self> {
|
||||
let mut tx = Self {
|
||||
chain_id: Decodable::decode(buf)?,
|
||||
nonce: Decodable::decode(buf)?,
|
||||
max_priority_fee_per_gas: Decodable::decode(buf)?,
|
||||
max_fee_per_gas: Decodable::decode(buf)?,
|
||||
gas_limit: Decodable::decode(buf)?,
|
||||
placeholder: None,
|
||||
to: Decodable::decode(buf)?,
|
||||
value: Decodable::decode(buf)?,
|
||||
input: Decodable::decode(buf)?,
|
||||
access_list: Decodable::decode(buf)?,
|
||||
max_fee_per_blob_gas: Decodable::decode(buf)?,
|
||||
blob_versioned_hashes: Decodable::decode(buf)?,
|
||||
};
|
||||
|
||||
// HACK: our arbitrary implementation sets the placeholder this way for backwards
|
||||
// compatibility, and should be removed once `placeholder` can be removed
|
||||
if tx.to != Address::default() {
|
||||
tx.placeholder = Some(())
|
||||
}
|
||||
|
||||
Ok(tx)
|
||||
}
|
||||
|
||||
/// Outputs the length of the transaction's fields, without a RLP header.
|
||||
pub(crate) fn fields_len(&self) -> usize {
|
||||
self.chain_id.length() +
|
||||
self.nonce.length() +
|
||||
self.gas_limit.length() +
|
||||
self.max_fee_per_gas.length() +
|
||||
self.max_priority_fee_per_gas.length() +
|
||||
self.to.length() +
|
||||
self.value.length() +
|
||||
self.access_list.length() +
|
||||
self.blob_versioned_hashes.length() +
|
||||
self.max_fee_per_blob_gas.length() +
|
||||
self.input.0.length()
|
||||
}
|
||||
|
||||
/// Encodes only the transaction's fields into the desired buffer, without a RLP header.
|
||||
pub(crate) fn encode_fields(&self, out: &mut dyn bytes::BufMut) {
|
||||
self.chain_id.encode(out);
|
||||
self.nonce.encode(out);
|
||||
self.max_priority_fee_per_gas.encode(out);
|
||||
self.max_fee_per_gas.encode(out);
|
||||
self.gas_limit.encode(out);
|
||||
self.to.encode(out);
|
||||
self.value.encode(out);
|
||||
self.input.0.encode(out);
|
||||
self.access_list.encode(out);
|
||||
self.max_fee_per_blob_gas.encode(out);
|
||||
self.blob_versioned_hashes.encode(out);
|
||||
}
|
||||
|
||||
/// Calculates a heuristic for the in-memory size of the [`TxEip4844`] transaction.
|
||||
#[inline]
|
||||
pub fn size(&self) -> usize {
|
||||
mem::size_of::<ChainId>() + // chain_id
|
||||
mem::size_of::<u64>() + // nonce
|
||||
mem::size_of::<u64>() + // gas_limit
|
||||
mem::size_of::<u128>() + // max_fee_per_gas
|
||||
mem::size_of::<u128>() + // max_priority_fee_per_gas
|
||||
mem::size_of::<Address>() + // to
|
||||
mem::size_of::<U256>() + // value
|
||||
self.access_list.size() + // access_list
|
||||
self.input.len() + // input
|
||||
self.blob_versioned_hashes.capacity() * mem::size_of::<B256>() + // blob hashes size
|
||||
mem::size_of::<u128>() // max_fee_per_data_gas
|
||||
}
|
||||
|
||||
/// Inner encoding function that is used for both rlp [`Encodable`] trait and for calculating
|
||||
/// hash that for eip2718 does not require rlp header
|
||||
pub(crate) fn encode_with_signature(
|
||||
&self,
|
||||
signature: &Signature,
|
||||
out: &mut dyn bytes::BufMut,
|
||||
with_header: bool,
|
||||
) {
|
||||
let payload_length = self.fields_len() + signature.payload_len();
|
||||
if with_header {
|
||||
Header {
|
||||
list: false,
|
||||
payload_length: 1 + length_of_length(payload_length) + payload_length,
|
||||
}
|
||||
.encode(out);
|
||||
}
|
||||
out.put_u8(self.tx_type() as u8);
|
||||
let header = Header { list: true, payload_length };
|
||||
header.encode(out);
|
||||
self.encode_fields(out);
|
||||
signature.encode(out);
|
||||
}
|
||||
|
||||
/// Output the length of the RLP signed transaction encoding. This encodes with a RLP header.
|
||||
pub(crate) fn payload_len_with_signature(&self, signature: &Signature) -> usize {
|
||||
let len = self.payload_len_with_signature_without_header(signature);
|
||||
length_of_length(len) + len
|
||||
}
|
||||
|
||||
/// Output the length of the RLP signed transaction encoding, _without_ a RLP header.
|
||||
pub(crate) fn payload_len_with_signature_without_header(&self, signature: &Signature) -> usize {
|
||||
let payload_length = self.fields_len() + signature.payload_len();
|
||||
// 'transaction type byte length' + 'header length' + 'payload length'
|
||||
1 + length_of_length(payload_length) + payload_length
|
||||
}
|
||||
|
||||
/// Get transaction type
|
||||
pub(crate) const fn tx_type(&self) -> TxType {
|
||||
TxType::Eip4844
|
||||
}
|
||||
|
||||
/// Encodes the EIP-4844 transaction in RLP for signing.
|
||||
///
|
||||
/// This encodes the transaction as:
|
||||
/// `tx_type || rlp(chain_id, nonce, max_priority_fee_per_gas, max_fee_per_gas, gas_limit, to,
|
||||
/// value, input, access_list, max_fee_per_blob_gas, blob_versioned_hashes)`
|
||||
///
|
||||
/// Note that there is no rlp header before the transaction type byte.
|
||||
pub(crate) fn encode_for_signing(&self, out: &mut dyn bytes::BufMut) {
|
||||
out.put_u8(self.tx_type() as u8);
|
||||
Header { list: true, payload_length: self.fields_len() }.encode(out);
|
||||
self.encode_fields(out);
|
||||
}
|
||||
|
||||
/// Outputs the length of the signature RLP encoding for the transaction.
|
||||
pub(crate) fn payload_len_for_signature(&self) -> usize {
|
||||
let payload_length = self.fields_len();
|
||||
// 'transaction type byte length' + 'header length' + 'payload length'
|
||||
1 + length_of_length(payload_length) + payload_length
|
||||
}
|
||||
|
||||
/// Outputs the signature hash of the transaction by first encoding without a signature, then
|
||||
/// hashing.
|
||||
pub(crate) fn signature_hash(&self) -> B256 {
|
||||
let mut buf = Vec::with_capacity(self.payload_len_for_signature());
|
||||
self.encode_for_signing(&mut buf);
|
||||
keccak256(&buf)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use alloy_primitives::{address, bytes};
|
||||
|
||||
#[test]
|
||||
fn backwards_compatible_txkind_test() {
|
||||
// TxEip4844 encoded with TxKind on to field
|
||||
// holesky tx hash: <0xa3b1668225bf0fbfdd6c19aa6fd071fa4ff5d09a607c67ccd458b97735f745ac>
|
||||
let tx = bytes!("224348a100426844cb2dc6c0b2d05e003b9aca0079c9109b764609df928d16fc4a91e9081f7e87db09310001019101fb28118ceccaabca22a47e35b9c3f12eb2dcb25e5c543d5b75e6cd841f0a05328d26ef16e8450000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000052000000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000000200000000000000000000000007b399987d24fc5951f3e94a4cb16e87414bf22290000000000000000000000001670090000000000000000000000000000010001302e31382e302d64657600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000420000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000009e640a6aadf4f664cf467b795c31332f44acbe6c000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000002c00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006614c2d1000000000000000000000000000000000000000000000000000000000014012c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000000093100000000000000000000000000000000000000000000000000000000000000c8000000000000000000000000000000000000000000000000000000000000093100000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041f06fd78f4dcdf089263524731620941747b9b93fd8f631557e25b23845a78b685bd82f9d36bce2f4cc812b6e5191df52479d349089461ffe76e9f2fa2848a0fe1b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000410819f04aba17677807c61ae72afdddf7737f26931ecfa8af05b7c669808b36a2587e32c90bb0ed2100266dd7797c80121a109a2b0fe941ca5a580e438988cac81c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000");
|
||||
let (tx, _) = TxEip4844::from_compact(&tx, tx.len());
|
||||
assert_eq!(tx.to, address!("79C9109b764609df928d16fC4a91e9081F7e87DB"));
|
||||
assert_eq!(tx.placeholder, Some(()));
|
||||
assert_eq!(tx.input, bytes!("ef16e8450000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000052000000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000000200000000000000000000000007b399987d24fc5951f3e94a4cb16e87414bf22290000000000000000000000001670090000000000000000000000000000010001302e31382e302d64657600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000420000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000009e640a6aadf4f664cf467b795c31332f44acbe6c000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000002c00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006614c2d1000000000000000000000000000000000000000000000000000000000014012c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000000093100000000000000000000000000000000000000000000000000000000000000c8000000000000000000000000000000000000000000000000000000000000093100000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041f06fd78f4dcdf089263524731620941747b9b93fd8f631557e25b23845a78b685bd82f9d36bce2f4cc812b6e5191df52479d349089461ffe76e9f2fa2848a0fe1b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000410819f04aba17677807c61ae72afdddf7737f26931ecfa8af05b7c669808b36a2587e32c90bb0ed2100266dd7797c80121a109a2b0fe941ca5a580e438988cac81c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"));
|
||||
}
|
||||
}
|
||||
pub use alloy_consensus::transaction::TxEip4844;
|
||||
|
||||
@ -159,7 +159,12 @@ impl<'a> arbitrary::Arbitrary<'a> for Transaction {
|
||||
tx.gas_limit = (tx.gas_limit as u64).into();
|
||||
Self::Eip1559(tx)
|
||||
}
|
||||
TxType::Eip4844 => Self::Eip4844(TxEip4844::arbitrary(u)?),
|
||||
TxType::Eip4844 => {
|
||||
let mut tx = TxEip4844::arbitrary(u)?;
|
||||
tx.gas_limit = (tx.gas_limit as u64).into();
|
||||
Self::Eip4844(tx)
|
||||
}
|
||||
|
||||
TxType::Eip7702 => Self::Eip7702(TxEip7702::arbitrary(u)?),
|
||||
#[cfg(feature = "optimism")]
|
||||
TxType::Deposit => Self::Deposit(TxDeposit::arbitrary(u)?),
|
||||
@ -238,7 +243,7 @@ impl Transaction {
|
||||
Self::Legacy(_) => TxType::Legacy,
|
||||
Self::Eip2930(_) => TxType::Eip2930,
|
||||
Self::Eip1559(_) => TxType::Eip1559,
|
||||
Self::Eip4844(blob_tx) => blob_tx.tx_type(),
|
||||
Self::Eip4844(_) => TxType::Eip4844,
|
||||
Self::Eip7702(set_code_tx) => set_code_tx.tx_type(),
|
||||
#[cfg(feature = "optimism")]
|
||||
Self::Deposit(deposit_tx) => deposit_tx.tx_type(),
|
||||
@ -302,7 +307,7 @@ impl Transaction {
|
||||
match self {
|
||||
Self::Legacy(TxLegacy { gas_limit, .. }) => *gas_limit as u64,
|
||||
Self::Eip1559(TxEip1559 { gas_limit, .. }) => *gas_limit as u64,
|
||||
Self::Eip4844(TxEip4844 { gas_limit, .. }) |
|
||||
Self::Eip4844(TxEip4844 { gas_limit, .. }) => *gas_limit as u64,
|
||||
Self::Eip7702(TxEip7702 { gas_limit, .. }) => *gas_limit,
|
||||
Self::Eip2930(TxEip2930 { gas_limit, .. }) => *gas_limit as u64,
|
||||
#[cfg(feature = "optimism")]
|
||||
@ -536,7 +541,11 @@ impl Transaction {
|
||||
out,
|
||||
with_header,
|
||||
),
|
||||
Self::Eip4844(blob_tx) => blob_tx.encode_with_signature(signature, out, with_header),
|
||||
Self::Eip4844(blob_tx) => blob_tx.encode_with_signature(
|
||||
&signature.as_signature_with_boolean_parity(),
|
||||
out,
|
||||
with_header,
|
||||
),
|
||||
Self::Eip7702(set_code_tx) => {
|
||||
set_code_tx.encode_with_signature(signature, out, with_header)
|
||||
}
|
||||
@ -551,7 +560,7 @@ impl Transaction {
|
||||
Self::Legacy(tx) => tx.gas_limit = gas_limit.into(),
|
||||
Self::Eip2930(tx) => tx.gas_limit = gas_limit.into(),
|
||||
Self::Eip1559(tx) => tx.gas_limit = gas_limit.into(),
|
||||
Self::Eip4844(tx) => tx.gas_limit = gas_limit,
|
||||
Self::Eip4844(tx) => tx.gas_limit = gas_limit.into(),
|
||||
Self::Eip7702(tx) => tx.gas_limit = gas_limit,
|
||||
#[cfg(feature = "optimism")]
|
||||
Self::Deposit(tx) => tx.gas_limit = gas_limit,
|
||||
@ -1219,7 +1228,10 @@ impl TransactionSigned {
|
||||
&self.signature.as_signature_with_boolean_parity(),
|
||||
true,
|
||||
),
|
||||
Transaction::Eip4844(blob_tx) => blob_tx.payload_len_with_signature(&self.signature),
|
||||
Transaction::Eip4844(blob_tx) => blob_tx.encoded_len_with_signature(
|
||||
&self.signature.as_signature_with_boolean_parity(),
|
||||
true,
|
||||
),
|
||||
Transaction::Eip7702(set_code_tx) => {
|
||||
set_code_tx.payload_len_with_signature(&self.signature)
|
||||
}
|
||||
@ -1348,7 +1360,7 @@ impl TransactionSigned {
|
||||
let transaction = match tx_type {
|
||||
TxType::Eip2930 => Transaction::Eip2930(TxEip2930::decode_fields(data)?),
|
||||
TxType::Eip1559 => Transaction::Eip1559(TxEip1559::decode_fields(data)?),
|
||||
TxType::Eip4844 => Transaction::Eip4844(TxEip4844::decode_inner(data)?),
|
||||
TxType::Eip4844 => Transaction::Eip4844(TxEip4844::decode_fields(data)?),
|
||||
TxType::Eip7702 => Transaction::Eip7702(TxEip7702::decode_inner(data)?),
|
||||
#[cfg(feature = "optimism")]
|
||||
TxType::Deposit => Transaction::Deposit(TxDeposit::decode_inner(data)?),
|
||||
@ -1427,9 +1439,10 @@ impl TransactionSigned {
|
||||
&self.signature.as_signature_with_boolean_parity(),
|
||||
false,
|
||||
),
|
||||
Transaction::Eip4844(blob_tx) => {
|
||||
blob_tx.payload_len_with_signature_without_header(&self.signature)
|
||||
}
|
||||
Transaction::Eip4844(blob_tx) => blob_tx.encoded_len_with_signature(
|
||||
&self.signature.as_signature_with_boolean_parity(),
|
||||
false,
|
||||
),
|
||||
Transaction::Eip7702(set_code_tx) => {
|
||||
set_code_tx.payload_len_with_signature_without_header(&self.signature)
|
||||
}
|
||||
@ -1533,11 +1546,6 @@ impl<'a> arbitrary::Arbitrary<'a> for TransactionSigned {
|
||||
transaction.set_chain_id(chain_id % (u64::MAX / 2 - 36));
|
||||
}
|
||||
|
||||
if let Transaction::Eip4844(ref mut tx_eip_4844) = transaction {
|
||||
tx_eip_4844.placeholder =
|
||||
if tx_eip_4844.to == Address::default() { None } else { Some(()) };
|
||||
}
|
||||
|
||||
#[cfg(feature = "optimism")]
|
||||
// Both `Some(0)` and `None` values are encoded as empty string byte. This introduces
|
||||
// ambiguity in roundtrip tests. Patch the mint value of deposit transaction here, so that
|
||||
|
||||
@ -7,7 +7,7 @@ use crate::{
|
||||
TransactionSigned, TransactionSignedEcRecovered, TxEip1559, TxEip2930, TxEip4844, TxHash,
|
||||
TxLegacy, B256, EIP4844_TX_TYPE_ID,
|
||||
};
|
||||
use alloy_consensus::SignableTransaction;
|
||||
use alloy_consensus::{SignableTransaction, TxEip4844WithSidecar};
|
||||
use alloy_rlp::{Decodable, Encodable, Error as RlpError, Header, EMPTY_LIST_CODE};
|
||||
use bytes::Buf;
|
||||
use derive_more::{AsRef, Deref};
|
||||
@ -102,7 +102,11 @@ impl PooledTransactionsElement {
|
||||
// If the transaction is an EIP-4844 transaction...
|
||||
TransactionSigned { transaction: Transaction::Eip4844(tx), signature, hash } => {
|
||||
// Construct a `PooledTransactionsElement::BlobTransaction` with provided sidecar.
|
||||
Self::BlobTransaction(BlobTransaction { transaction: tx, signature, hash, sidecar })
|
||||
Self::BlobTransaction(BlobTransaction {
|
||||
signature,
|
||||
hash,
|
||||
transaction: TxEip4844WithSidecar { tx, sidecar },
|
||||
})
|
||||
}
|
||||
// If the transaction is not EIP-4844, return an error with the original
|
||||
// transaction.
|
||||
@ -151,7 +155,7 @@ impl PooledTransactionsElement {
|
||||
Self::Eip2930 { transaction, .. } => transaction.nonce,
|
||||
Self::Eip1559 { transaction, .. } => transaction.nonce,
|
||||
Self::Eip7702 { transaction, .. } => transaction.nonce,
|
||||
Self::BlobTransaction(blob_tx) => blob_tx.transaction.nonce,
|
||||
Self::BlobTransaction(blob_tx) => blob_tx.transaction.tx.nonce,
|
||||
}
|
||||
}
|
||||
|
||||
@ -416,7 +420,7 @@ impl PooledTransactionsElement {
|
||||
/// Returns the [`TxEip4844`] variant if the transaction is an EIP-4844 transaction.
|
||||
pub const fn as_eip4844(&self) -> Option<&TxEip4844> {
|
||||
match self {
|
||||
Self::BlobTransaction(tx) => Some(&tx.transaction),
|
||||
Self::BlobTransaction(tx) => Some(&tx.transaction.tx),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
@ -445,7 +449,7 @@ impl PooledTransactionsElement {
|
||||
/// This is also commonly referred to as the "Blob Gas Fee Cap" (`BlobGasFeeCap`).
|
||||
pub const fn max_fee_per_blob_gas(&self) -> Option<u128> {
|
||||
match self {
|
||||
Self::BlobTransaction(tx) => Some(tx.transaction.max_fee_per_blob_gas),
|
||||
Self::BlobTransaction(tx) => Some(tx.transaction.tx.max_fee_per_blob_gas),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
@ -459,7 +463,7 @@ impl PooledTransactionsElement {
|
||||
Self::Legacy { .. } | Self::Eip2930 { .. } => None,
|
||||
Self::Eip1559 { transaction, .. } => Some(transaction.max_priority_fee_per_gas),
|
||||
Self::Eip7702 { transaction, .. } => Some(transaction.max_priority_fee_per_gas),
|
||||
Self::BlobTransaction(tx) => Some(tx.transaction.max_priority_fee_per_gas),
|
||||
Self::BlobTransaction(tx) => Some(tx.transaction.tx.max_priority_fee_per_gas),
|
||||
}
|
||||
}
|
||||
|
||||
@ -472,7 +476,7 @@ impl PooledTransactionsElement {
|
||||
Self::Eip2930 { transaction, .. } => transaction.gas_price,
|
||||
Self::Eip1559 { transaction, .. } => transaction.max_fee_per_gas,
|
||||
Self::Eip7702 { transaction, .. } => transaction.max_fee_per_gas,
|
||||
Self::BlobTransaction(tx) => tx.transaction.max_fee_per_gas,
|
||||
Self::BlobTransaction(tx) => tx.transaction.tx.max_fee_per_gas,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -691,7 +695,7 @@ impl<'a> arbitrary::Arbitrary<'a> for PooledTransactionsElement {
|
||||
match Self::try_from(tx_signed) {
|
||||
Ok(Self::BlobTransaction(mut tx)) => {
|
||||
// Successfully converted to a BlobTransaction, now generate a sidecar.
|
||||
tx.sidecar = crate::BlobTransactionSidecar::arbitrary(u)?;
|
||||
tx.transaction.sidecar = crate::BlobTransactionSidecar::arbitrary(u)?;
|
||||
Ok(Self::BlobTransaction(tx))
|
||||
}
|
||||
Ok(tx) => Ok(tx), // Successfully converted, but not a BlobTransaction.
|
||||
|
||||
@ -3,7 +3,8 @@
|
||||
use crate::{
|
||||
keccak256, Signature, Transaction, TransactionSigned, TxEip4844, TxHash, EIP4844_TX_TYPE_ID,
|
||||
};
|
||||
use alloy_rlp::{Decodable, Encodable, Error as RlpError, Header};
|
||||
use alloy_consensus::TxEip4844WithSidecar;
|
||||
use alloy_rlp::{Decodable, Error as RlpError, Header};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[doc(inline)]
|
||||
@ -24,12 +25,10 @@ use alloc::vec::Vec;
|
||||
pub struct BlobTransaction {
|
||||
/// The transaction hash.
|
||||
pub hash: TxHash,
|
||||
/// The transaction payload.
|
||||
pub transaction: TxEip4844,
|
||||
/// The transaction signature.
|
||||
pub signature: Signature,
|
||||
/// The transaction's blob sidecar.
|
||||
pub sidecar: BlobTransactionSidecar,
|
||||
/// The transaction payload with the sidecar.
|
||||
pub transaction: TxEip4844WithSidecar,
|
||||
}
|
||||
|
||||
impl BlobTransaction {
|
||||
@ -43,7 +42,11 @@ impl BlobTransaction {
|
||||
) -> Result<Self, (TransactionSigned, BlobTransactionSidecar)> {
|
||||
let TransactionSigned { transaction, signature, hash } = tx;
|
||||
match transaction {
|
||||
Transaction::Eip4844(transaction) => Ok(Self { hash, transaction, signature, sidecar }),
|
||||
Transaction::Eip4844(transaction) => Ok(Self {
|
||||
hash,
|
||||
transaction: TxEip4844WithSidecar { tx: transaction, sidecar },
|
||||
signature,
|
||||
}),
|
||||
transaction => {
|
||||
let tx = TransactionSigned { transaction, signature, hash };
|
||||
Err((tx, sidecar))
|
||||
@ -59,19 +62,19 @@ impl BlobTransaction {
|
||||
&self,
|
||||
proof_settings: &c_kzg::KzgSettings,
|
||||
) -> Result<(), BlobTransactionValidationError> {
|
||||
self.transaction.validate_blob(&self.sidecar, proof_settings)
|
||||
self.transaction.validate_blob(proof_settings)
|
||||
}
|
||||
|
||||
/// Splits the [`BlobTransaction`] into its [`TransactionSigned`] and [`BlobTransactionSidecar`]
|
||||
/// components.
|
||||
pub fn into_parts(self) -> (TransactionSigned, BlobTransactionSidecar) {
|
||||
let transaction = TransactionSigned {
|
||||
transaction: Transaction::Eip4844(self.transaction),
|
||||
transaction: Transaction::Eip4844(self.transaction.tx),
|
||||
hash: self.hash,
|
||||
signature: self.signature,
|
||||
};
|
||||
|
||||
(transaction, self.sidecar)
|
||||
(transaction, self.transaction.sidecar)
|
||||
}
|
||||
|
||||
/// Encodes the [`BlobTransaction`] fields as RLP, with a tx type. If `with_header` is `false`,
|
||||
@ -111,36 +114,8 @@ impl BlobTransaction {
|
||||
/// Note: this should be used only when implementing other RLP encoding methods, and does not
|
||||
/// represent the full RLP encoding of the blob transaction.
|
||||
pub(crate) fn encode_inner(&self, out: &mut dyn bytes::BufMut) {
|
||||
// First we construct both required list headers.
|
||||
//
|
||||
// The `transaction_payload_body` length is the length of the fields, plus the length of
|
||||
// its list header.
|
||||
let tx_header = Header {
|
||||
list: true,
|
||||
payload_length: self.transaction.fields_len() + self.signature.payload_len(),
|
||||
};
|
||||
|
||||
let tx_length = tx_header.length() + tx_header.payload_length;
|
||||
|
||||
// The payload length is the length of the `tranascation_payload_body` list, plus the
|
||||
// length of the blobs, commitments, and proofs.
|
||||
let payload_length = tx_length + self.sidecar.fields_len();
|
||||
|
||||
// First we use the payload len to construct the first list header
|
||||
let blob_tx_header = Header { list: true, payload_length };
|
||||
|
||||
// Encode the blob tx header first
|
||||
blob_tx_header.encode(out);
|
||||
|
||||
// Encode the inner tx list header, then its fields
|
||||
tx_header.encode(out);
|
||||
self.transaction.encode_fields(out);
|
||||
|
||||
// Encode the signature
|
||||
self.signature.encode(out);
|
||||
|
||||
// Encode the blobs, commitments, and proofs
|
||||
self.sidecar.encode(out);
|
||||
self.transaction
|
||||
.encode_with_signature_fields(&self.signature.as_signature_with_boolean_parity(), out);
|
||||
}
|
||||
|
||||
/// Outputs the length of the RLP encoding of the blob transaction, including the tx type byte,
|
||||
@ -181,14 +156,14 @@ impl BlobTransaction {
|
||||
// its list header.
|
||||
let tx_header = Header {
|
||||
list: true,
|
||||
payload_length: self.transaction.fields_len() + self.signature.payload_len(),
|
||||
payload_length: self.transaction.tx.fields_len() + self.signature.payload_len(),
|
||||
};
|
||||
|
||||
let tx_length = tx_header.length() + tx_header.payload_length;
|
||||
|
||||
// The payload length is the length of the `tranascation_payload_body` list, plus the
|
||||
// length of the blobs, commitments, and proofs.
|
||||
let payload_length = tx_length + self.sidecar.fields_len();
|
||||
let payload_length = tx_length + self.transaction.sidecar.fields_len();
|
||||
|
||||
// We use the calculated payload len to construct the first list header, which encompasses
|
||||
// everything in the tx - the length of the second, inner list header is part of
|
||||
@ -234,7 +209,7 @@ impl BlobTransaction {
|
||||
let inner_remaining_len = data.len();
|
||||
|
||||
// inner transaction
|
||||
let transaction = TxEip4844::decode_inner(data)?;
|
||||
let transaction = TxEip4844::decode(data)?;
|
||||
|
||||
// signature
|
||||
let signature = Signature::decode(data)?;
|
||||
@ -265,7 +240,11 @@ impl BlobTransaction {
|
||||
// Instead, we use `encode_with_signature`, which RLP encodes the transaction with a
|
||||
// signature for hashing without a header. We then hash the result.
|
||||
let mut buf = Vec::new();
|
||||
transaction.encode_with_signature(&signature, &mut buf, false);
|
||||
transaction.encode_with_signature(
|
||||
&signature.as_signature_with_boolean_parity(),
|
||||
&mut buf,
|
||||
false,
|
||||
);
|
||||
let hash = keccak256(&buf);
|
||||
|
||||
// the outer header is for the entire transaction, so we check the length here
|
||||
@ -274,7 +253,7 @@ impl BlobTransaction {
|
||||
return Err(RlpError::UnexpectedLength)
|
||||
}
|
||||
|
||||
Ok(Self { transaction, hash, signature, sidecar })
|
||||
Ok(Self { transaction: TxEip4844WithSidecar { tx: transaction, sidecar }, hash, signature })
|
||||
}
|
||||
}
|
||||
|
||||
@ -311,6 +290,7 @@ mod tests {
|
||||
use super::*;
|
||||
use crate::{hex, kzg::Blob};
|
||||
use alloy_eips::eip4844::Bytes48;
|
||||
use alloy_rlp::Encodable;
|
||||
use std::{fs, path::PathBuf, str::FromStr};
|
||||
|
||||
#[test]
|
||||
|
||||
@ -47,7 +47,6 @@ pub fn to_primitive_transaction(
|
||||
gas_limit: tx.gas_limit.to(),
|
||||
max_fee_per_gas: tx.max_fee_per_gas.to(),
|
||||
max_priority_fee_per_gas: tx.max_priority_fee_per_gas.to(),
|
||||
placeholder: Some(()),
|
||||
to: tx.to,
|
||||
value: tx.value,
|
||||
access_list: tx.access_list,
|
||||
|
||||
@ -87,7 +87,7 @@ where
|
||||
.iter()
|
||||
.filter_map(|(tx, _)| {
|
||||
if let PooledTransactionsElement::BlobTransaction(tx) = tx {
|
||||
Some(tx.transaction.blob_gas())
|
||||
Some(tx.transaction.tx.blob_gas())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
||||
96
crates/storage/codecs/src/alloy/transaction/eip4844.rs
Normal file
96
crates/storage/codecs/src/alloy/transaction/eip4844.rs
Normal file
@ -0,0 +1,96 @@
|
||||
use crate::{Compact, CompactPlaceholder};
|
||||
use alloy_consensus::transaction::TxEip4844 as AlloyTxEip4844;
|
||||
use alloy_eips::eip2930::AccessList;
|
||||
use alloy_primitives::{Address, Bytes, ChainId, B256, U256};
|
||||
use reth_codecs_derive::add_arbitrary_tests;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
use alloc::vec::Vec;
|
||||
|
||||
/// [EIP-4844 Blob Transaction](https://eips.ethereum.org/EIPS/eip-4844#blob-transaction)
|
||||
///
|
||||
/// This is a helper type to use derive on it instead of manually managing `bitfield`.
|
||||
///
|
||||
/// By deriving `Compact` here, any future changes or enhancements to the `Compact` derive
|
||||
/// will automatically apply to this type.
|
||||
///
|
||||
/// Notice: Make sure this struct is 1:1 with [`alloy_consensus::transaction::TxEip4844`]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Default, Serialize, Deserialize, Compact)]
|
||||
#[cfg_attr(test, derive(arbitrary::Arbitrary))]
|
||||
#[add_arbitrary_tests(compact)]
|
||||
pub(crate) struct TxEip4844 {
|
||||
chain_id: ChainId,
|
||||
nonce: u64,
|
||||
gas_limit: u64,
|
||||
max_fee_per_gas: u128,
|
||||
max_priority_fee_per_gas: u128,
|
||||
/// TODO(debt): this should be removed if we break the DB.
|
||||
/// Makes sure that the Compact bitflag struct has one bit after the above field:
|
||||
/// <https://github.com/paradigmxyz/reth/pull/8291#issuecomment-2117545016>
|
||||
placeholder: Option<CompactPlaceholder>,
|
||||
to: Address,
|
||||
value: U256,
|
||||
access_list: AccessList,
|
||||
blob_versioned_hashes: Vec<B256>,
|
||||
max_fee_per_blob_gas: u128,
|
||||
input: Bytes,
|
||||
}
|
||||
|
||||
impl Compact for AlloyTxEip4844 {
|
||||
fn to_compact<B>(&self, buf: &mut B) -> usize
|
||||
where
|
||||
B: bytes::BufMut + AsMut<[u8]>,
|
||||
{
|
||||
let tx = TxEip4844 {
|
||||
chain_id: self.chain_id,
|
||||
nonce: self.nonce,
|
||||
gas_limit: self.gas_limit as u64,
|
||||
max_fee_per_gas: self.max_fee_per_gas,
|
||||
max_priority_fee_per_gas: self.max_priority_fee_per_gas,
|
||||
placeholder: Some(()),
|
||||
to: self.to,
|
||||
value: self.value,
|
||||
access_list: self.access_list.clone(),
|
||||
blob_versioned_hashes: self.blob_versioned_hashes.clone(),
|
||||
max_fee_per_blob_gas: self.max_fee_per_blob_gas,
|
||||
input: self.input.clone(),
|
||||
};
|
||||
tx.to_compact(buf)
|
||||
}
|
||||
|
||||
fn from_compact(buf: &[u8], len: usize) -> (Self, &[u8]) {
|
||||
let (tx, _) = TxEip4844::from_compact(buf, len);
|
||||
let alloy_tx = Self {
|
||||
chain_id: tx.chain_id,
|
||||
nonce: tx.nonce,
|
||||
gas_limit: tx.gas_limit as u128,
|
||||
max_fee_per_gas: tx.max_fee_per_gas,
|
||||
max_priority_fee_per_gas: tx.max_priority_fee_per_gas,
|
||||
to: tx.to,
|
||||
value: tx.value,
|
||||
access_list: tx.access_list,
|
||||
blob_versioned_hashes: tx.blob_versioned_hashes,
|
||||
max_fee_per_blob_gas: tx.max_fee_per_blob_gas,
|
||||
input: tx.input,
|
||||
};
|
||||
(alloy_tx, buf)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use alloy_primitives::{address, bytes};
|
||||
|
||||
#[test]
|
||||
fn backwards_compatible_txkind_test() {
|
||||
// TxEip4844 encoded with TxKind on to field
|
||||
// holesky tx hash: <0xa3b1668225bf0fbfdd6c19aa6fd071fa4ff5d09a607c67ccd458b97735f745ac>
|
||||
let tx = bytes!("224348a100426844cb2dc6c0b2d05e003b9aca0079c9109b764609df928d16fc4a91e9081f7e87db09310001019101fb28118ceccaabca22a47e35b9c3f12eb2dcb25e5c543d5b75e6cd841f0a05328d26ef16e8450000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000052000000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000000200000000000000000000000007b399987d24fc5951f3e94a4cb16e87414bf22290000000000000000000000001670090000000000000000000000000000010001302e31382e302d64657600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000420000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000009e640a6aadf4f664cf467b795c31332f44acbe6c000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000002c00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006614c2d1000000000000000000000000000000000000000000000000000000000014012c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000000093100000000000000000000000000000000000000000000000000000000000000c8000000000000000000000000000000000000000000000000000000000000093100000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041f06fd78f4dcdf089263524731620941747b9b93fd8f631557e25b23845a78b685bd82f9d36bce2f4cc812b6e5191df52479d349089461ffe76e9f2fa2848a0fe1b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000410819f04aba17677807c61ae72afdddf7737f26931ecfa8af05b7c669808b36a2587e32c90bb0ed2100266dd7797c80121a109a2b0fe941ca5a580e438988cac81c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000");
|
||||
let (tx, _) = TxEip4844::from_compact(&tx, tx.len());
|
||||
assert_eq!(tx.to, address!("79C9109b764609df928d16fC4a91e9081F7e87DB"));
|
||||
assert_eq!(tx.placeholder, Some(()));
|
||||
assert_eq!(tx.input, bytes!("ef16e8450000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000052000000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000000200000000000000000000000007b399987d24fc5951f3e94a4cb16e87414bf22290000000000000000000000001670090000000000000000000000000000010001302e31382e302d64657600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000420000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000009e640a6aadf4f664cf467b795c31332f44acbe6c000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000002c00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006614c2d1000000000000000000000000000000000000000000000000000000000014012c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000000093100000000000000000000000000000000000000000000000000000000000000c8000000000000000000000000000000000000000000000000000000000000093100000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041f06fd78f4dcdf089263524731620941747b9b93fd8f631557e25b23845a78b685bd82f9d36bce2f4cc812b6e5191df52479d349089461ffe76e9f2fa2848a0fe1b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000410819f04aba17677807c61ae72afdddf7737f26931ecfa8af05b7c669808b36a2587e32c90bb0ed2100266dd7797c80121a109a2b0fe941ca5a580e438988cac81c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"));
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,6 @@
|
||||
mod eip1559;
|
||||
mod eip2930;
|
||||
mod eip4844;
|
||||
mod legacy;
|
||||
|
||||
#[cfg(test)]
|
||||
@ -11,10 +12,11 @@ mod tests {
|
||||
// this check is to ensure we do not inadvertently add too many fields to a struct which would
|
||||
// expand the flags field and break backwards compatibility
|
||||
|
||||
use super::{eip1559::TxEip1559, eip2930::TxEip2930, legacy::TxLegacy};
|
||||
use super::{eip1559::TxEip1559, eip2930::TxEip2930, eip4844::TxEip4844, legacy::TxLegacy};
|
||||
|
||||
#[test]
|
||||
fn test_ensure_backwards_compatibility() {
|
||||
assert_eq!(TxEip4844::bitflag_encoded_bytes(), 5);
|
||||
assert_eq!(TxLegacy::bitflag_encoded_bytes(), 3);
|
||||
assert_eq!(TxEip1559::bitflag_encoded_bytes(), 4);
|
||||
assert_eq!(TxEip2930::bitflag_encoded_bytes(), 3);
|
||||
|
||||
@ -301,9 +301,7 @@ add_wrapper_struct!((ClientVersion, CompactClientVersion));
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use reth_primitives::{
|
||||
Account, Header, Receipt, ReceiptWithBloom, SealedHeader, TxEip4844, Withdrawals,
|
||||
};
|
||||
use reth_primitives::{Account, Header, Receipt, ReceiptWithBloom, SealedHeader, Withdrawals};
|
||||
use reth_prune_types::{PruneCheckpoint, PruneMode, PruneSegment};
|
||||
use reth_stages_types::{
|
||||
AccountHashingCheckpoint, CheckpointBlockRange, EntitiesCheckpoint, ExecutionCheckpoint,
|
||||
@ -342,7 +340,6 @@ mod tests {
|
||||
assert_eq!(StoredBlockOmmers::bitflag_encoded_bytes(), 0);
|
||||
assert_eq!(StoredBlockWithdrawals::bitflag_encoded_bytes(), 0);
|
||||
assert_eq!(StorageHashingCheckpoint::bitflag_encoded_bytes(), 1);
|
||||
assert_eq!(TxEip4844::bitflag_encoded_bytes(), 5);
|
||||
assert_eq!(Withdrawals::bitflag_encoded_bytes(), 0);
|
||||
}
|
||||
|
||||
@ -372,7 +369,6 @@ mod tests {
|
||||
assert_eq!(StoredBlockOmmers::bitflag_encoded_bytes(), 0);
|
||||
assert_eq!(StoredBlockWithdrawals::bitflag_encoded_bytes(), 0);
|
||||
assert_eq!(StorageHashingCheckpoint::bitflag_encoded_bytes(), 1);
|
||||
assert_eq!(TxEip4844::bitflag_encoded_bytes(), 5);
|
||||
assert_eq!(Withdrawals::bitflag_encoded_bytes(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -178,10 +178,9 @@ impl TransactionBuilder {
|
||||
TxEip4844 {
|
||||
chain_id: self.chain_id,
|
||||
nonce: self.nonce,
|
||||
gas_limit: self.gas_limit,
|
||||
gas_limit: self.gas_limit as u128,
|
||||
max_fee_per_gas: self.max_fee_per_gas,
|
||||
max_priority_fee_per_gas: self.max_priority_fee_per_gas,
|
||||
placeholder: None,
|
||||
to: match self.to {
|
||||
TxKind::Call(to) => to,
|
||||
TxKind::Create => Address::default(),
|
||||
|
||||
@ -186,8 +186,6 @@ pub enum MockTransaction {
|
||||
max_fee_per_blob_gas: u128,
|
||||
/// The gas limit for the transaction.
|
||||
gas_limit: u64,
|
||||
/// Placeholder for backwards compatibility.
|
||||
placeholder: Option<()>,
|
||||
/// The transaction's destination.
|
||||
to: Address,
|
||||
/// The value of the transaction.
|
||||
@ -278,7 +276,6 @@ impl MockTransaction {
|
||||
max_priority_fee_per_gas: MIN_PROTOCOL_BASE_FEE as u128,
|
||||
max_fee_per_blob_gas: DATA_GAS_PER_BLOB as u128,
|
||||
gas_limit: 0,
|
||||
placeholder: Some(()),
|
||||
to: Address::random(),
|
||||
value: Default::default(),
|
||||
input: Bytes::new(),
|
||||
@ -856,7 +853,6 @@ impl TryFrom<TransactionSignedEcRecovered> for MockTransaction {
|
||||
gas_limit,
|
||||
max_fee_per_gas,
|
||||
max_priority_fee_per_gas,
|
||||
placeholder,
|
||||
to,
|
||||
value,
|
||||
input,
|
||||
@ -871,8 +867,7 @@ impl TryFrom<TransactionSignedEcRecovered> for MockTransaction {
|
||||
max_fee_per_gas,
|
||||
max_priority_fee_per_gas,
|
||||
max_fee_per_blob_gas,
|
||||
gas_limit,
|
||||
placeholder,
|
||||
gas_limit: gas_limit as u64,
|
||||
to,
|
||||
value,
|
||||
input,
|
||||
@ -989,14 +984,12 @@ impl From<MockTransaction> for Transaction {
|
||||
input,
|
||||
sidecar,
|
||||
size: _,
|
||||
placeholder,
|
||||
} => Self::Eip4844(TxEip4844 {
|
||||
chain_id,
|
||||
nonce,
|
||||
gas_limit,
|
||||
gas_limit: gas_limit.into(),
|
||||
max_fee_per_gas,
|
||||
max_priority_fee_per_gas,
|
||||
placeholder,
|
||||
to,
|
||||
value,
|
||||
access_list,
|
||||
@ -1096,7 +1089,6 @@ impl proptest::arbitrary::Arbitrary for MockTransaction {
|
||||
max_fee_per_blob_gas,
|
||||
access_list,
|
||||
blob_versioned_hashes: _,
|
||||
placeholder,
|
||||
}) => Self::Eip4844 {
|
||||
chain_id: *chain_id,
|
||||
sender,
|
||||
@ -1105,8 +1097,7 @@ impl proptest::arbitrary::Arbitrary for MockTransaction {
|
||||
max_fee_per_gas: *max_fee_per_gas,
|
||||
max_priority_fee_per_gas: *max_priority_fee_per_gas,
|
||||
max_fee_per_blob_gas: *max_fee_per_blob_gas,
|
||||
gas_limit: *gas_limit,
|
||||
placeholder: *placeholder,
|
||||
gas_limit: *gas_limit as u64,
|
||||
to: *to,
|
||||
value: *value,
|
||||
input: input.clone(),
|
||||
|
||||
Reference in New Issue
Block a user