feat(storage): Implement Compact for OpTxEnvelope from op_alloy using blanket impl (#15230)

This commit is contained in:
Roman Hodulák
2025-03-24 14:05:16 +01:00
committed by GitHub
parent c3b7c1e442
commit 0200ad6ee0
3 changed files with 189 additions and 12 deletions

View File

@@ -778,3 +778,37 @@ pub mod serde_bincode_compat {
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use proptest::proptest;
use proptest_arbitrary_interop::arb;
use reth_codecs::Compact;
proptest! {
#[test]
fn test_roundtrip_compact_encode_envelope(reth_tx in arb::<OpTransactionSigned>()) {
let mut expected_buf = Vec::<u8>::new();
let expected_len = reth_tx.to_compact(&mut expected_buf);
let mut actual_but = Vec::<u8>::new();
let alloy_tx = OpTxEnvelope::from(reth_tx);
let actual_len = alloy_tx.to_compact(&mut actual_but);
assert_eq!(actual_but, expected_buf);
assert_eq!(actual_len, expected_len);
}
#[test]
fn test_roundtrip_compact_decode_envelope(reth_tx in arb::<OpTransactionSigned>()) {
let mut buf = Vec::<u8>::new();
let len = reth_tx.to_compact(&mut buf);
let (actual_tx, _) = OpTxEnvelope::from_compact(&buf, len);
let expected_tx = OpTxEnvelope::from(reth_tx);
assert_eq!(actual_tx, expected_tx);
}
}
}

View File

@@ -14,7 +14,7 @@ use bytes::{Buf, BufMut};
/// serialized separately.
///
/// See [`ToTxCompact::to_tx_compact`].
trait ToTxCompact {
pub(super) trait ToTxCompact {
/// Serializes inner transaction using [`Compact`] encoding. Writes the result into `buf`.
///
/// The written bytes do not contain signature and transaction type. This information be needs
@@ -30,14 +30,20 @@ trait ToTxCompact {
/// separately.
///
/// See [`FromTxCompact::from_tx_compact`].
trait FromTxCompact {
pub(super) trait FromTxCompact {
type TxType;
/// Deserializes inner transaction using [`Compact`] encoding. The concrete type is determined
/// by `tx_type`. The `signature` is added to create typed and signed transaction.
///
/// Returns a tuple of 2 elements. The first element is the deserialized value and the second
/// is a byte slice created from `buf` with a starting position advanced by the exact amount
/// of bytes consumed for this process.
fn from_tx_compact(buf: &[u8], tx_type: TxType, signature: PrimitiveSignature) -> (Self, &[u8])
fn from_tx_compact(
buf: &[u8],
tx_type: Self::TxType,
signature: PrimitiveSignature,
) -> (Self, &[u8])
where
Self: Sized;
}
@@ -55,6 +61,8 @@ impl<Eip4844: Compact + Transaction> ToTxCompact for EthereumTxEnvelope<Eip4844>
}
impl<Eip4844: Compact + Transaction> FromTxCompact for EthereumTxEnvelope<Eip4844> {
type TxType = TxType;
fn from_tx_compact(
buf: &[u8],
tx_type: TxType,
@@ -90,9 +98,39 @@ impl<Eip4844: Compact + Transaction> FromTxCompact for EthereumTxEnvelope<Eip484
}
}
impl<Eip4844: Compact + RlpEcdsaEncodableTx + Transaction + Send + Sync> Compact
pub(super) trait Envelope: FromTxCompact<TxType: Compact> {
fn signature(&self) -> &PrimitiveSignature;
fn tx_type(&self) -> Self::TxType;
}
impl<Eip4844: Compact + Transaction + RlpEcdsaEncodableTx> Envelope
for EthereumTxEnvelope<Eip4844>
{
fn signature(&self) -> &PrimitiveSignature {
Self::signature(self)
}
fn tx_type(&self) -> Self::TxType {
Self::tx_type(self)
}
}
pub(super) trait CompactEnvelope: Sized {
/// Takes a buffer which can be written to. *Ideally*, it returns the length written to.
fn to_compact<B>(&self, buf: &mut B) -> usize
where
B: BufMut + AsMut<[u8]>;
/// Takes a buffer which can be read from. Returns the object and `buf` with its internal cursor
/// advanced (eg.`.advance(len)`).
///
/// `len` can either be the `buf` remaining length, or the length of the compacted type.
///
/// It will panic, if `len` is smaller than `buf.len()`.
fn from_compact(buf: &[u8], len: usize) -> (Self, &[u8]);
}
impl<T: Envelope + ToTxCompact + Transaction + Send + Sync> CompactEnvelope for T {
fn to_compact<B>(&self, buf: &mut B) -> usize
where
B: BufMut + AsMut<[u8]>,
@@ -147,7 +185,7 @@ impl<Eip4844: Compact + RlpEcdsaEncodableTx + Transaction + Send + Sync> Compact
let zstd_bit = flags >> 3;
let (signature, buf) = PrimitiveSignature::from_compact(buf, sig_bit);
let (tx_type, buf) = TxType::from_compact(buf, tx_bits);
let (tx_type, buf) = T::TxType::from_compact(buf, tx_bits);
let (transaction, buf) = if zstd_bit != 0 {
#[cfg(feature = "std")]
@@ -177,3 +215,18 @@ impl<Eip4844: Compact + RlpEcdsaEncodableTx + Transaction + Send + Sync> Compact
(transaction, buf)
}
}
impl<Eip4844: Compact + RlpEcdsaEncodableTx + Transaction + Send + Sync> Compact
for EthereumTxEnvelope<Eip4844>
{
fn to_compact<B>(&self, buf: &mut B) -> usize
where
B: BufMut + AsMut<[u8]>,
{
<Self as CompactEnvelope>::to_compact(self, buf)
}
fn from_compact(buf: &[u8], len: usize) -> (Self, &[u8]) {
<Self as CompactEnvelope>::from_compact(buf, len)
}
}

View File

@@ -1,12 +1,21 @@
//! Compact implementation for [`AlloyTxDeposit`]
use alloy_consensus::constants::EIP7702_TX_TYPE_ID;
use crate::Compact;
use alloy_primitives::{Address, Bytes, TxKind, B256, U256};
use op_alloy_consensus::{OpTxType, OpTypedTransaction, TxDeposit as AlloyTxDeposit};
use crate::{
alloy::transaction::ethereum::{CompactEnvelope, Envelope, FromTxCompact, ToTxCompact},
generate_tests,
txtype::{
COMPACT_EXTENDED_IDENTIFIER_FLAG, COMPACT_IDENTIFIER_EIP1559, COMPACT_IDENTIFIER_EIP2930,
COMPACT_IDENTIFIER_LEGACY,
},
Compact,
};
use alloy_consensus::{
constants::EIP7702_TX_TYPE_ID, Signed, TxEip1559, TxEip2930, TxEip7702, TxLegacy,
};
use alloy_primitives::{Address, Bytes, PrimitiveSignature, Sealed, TxKind, B256, U256};
use bytes::BufMut;
use op_alloy_consensus::{OpTxEnvelope, OpTxType, OpTypedTransaction, TxDeposit as AlloyTxDeposit};
use reth_codecs_derive::add_arbitrary_tests;
use crate::txtype::{COMPACT_EXTENDED_IDENTIFIER_FLAG, COMPACT_IDENTIFIER_EIP1559, COMPACT_IDENTIFIER_EIP2930, COMPACT_IDENTIFIER_LEGACY};
use crate::generate_tests;
/// Deposit transactions, also known as deposits are initiated on L1, and executed on L2.
///
@@ -69,7 +78,6 @@ impl Compact for AlloyTxDeposit {
}
}
impl crate::Compact for OpTxType {
fn to_compact<B>(&self, buf: &mut B) -> usize
where
@@ -160,4 +168,86 @@ impl Compact for OpTypedTransaction {
}
}
impl ToTxCompact for OpTxEnvelope {
fn to_tx_compact(&self, buf: &mut (impl BufMut + AsMut<[u8]>)) {
match self {
Self::Legacy(tx) => tx.tx().to_compact(buf),
Self::Eip2930(tx) => tx.tx().to_compact(buf),
Self::Eip1559(tx) => tx.tx().to_compact(buf),
Self::Eip7702(tx) => tx.tx().to_compact(buf),
Self::Deposit(tx) => tx.to_compact(buf),
};
}
}
impl FromTxCompact for OpTxEnvelope {
type TxType = OpTxType;
fn from_tx_compact(
buf: &[u8],
tx_type: OpTxType,
signature: PrimitiveSignature,
) -> (Self, &[u8]) {
match tx_type {
OpTxType::Legacy => {
let (tx, buf) = TxLegacy::from_compact(buf, buf.len());
let tx = Signed::new_unhashed(tx, signature);
(Self::Legacy(tx), buf)
}
OpTxType::Eip2930 => {
let (tx, buf) = TxEip2930::from_compact(buf, buf.len());
let tx = Signed::new_unhashed(tx, signature);
(Self::Eip2930(tx), buf)
}
OpTxType::Eip1559 => {
let (tx, buf) = TxEip1559::from_compact(buf, buf.len());
let tx = Signed::new_unhashed(tx, signature);
(Self::Eip1559(tx), buf)
}
OpTxType::Eip7702 => {
let (tx, buf) = TxEip7702::from_compact(buf, buf.len());
let tx = Signed::new_unhashed(tx, signature);
(Self::Eip7702(tx), buf)
}
OpTxType::Deposit => {
let (tx, buf) = op_alloy_consensus::TxDeposit::from_compact(buf, buf.len());
let tx = Sealed::new(tx);
(Self::Deposit(tx), buf)
}
}
}
}
const DEPOSIT_SIGNATURE: PrimitiveSignature =
PrimitiveSignature::new(U256::ZERO, U256::ZERO, false);
impl Envelope for OpTxEnvelope {
fn signature(&self) -> &PrimitiveSignature {
match self {
Self::Legacy(tx) => tx.signature(),
Self::Eip2930(tx) => tx.signature(),
Self::Eip1559(tx) => tx.signature(),
Self::Eip7702(tx) => tx.signature(),
Self::Deposit(_) => &DEPOSIT_SIGNATURE,
}
}
fn tx_type(&self) -> Self::TxType {
Self::tx_type(self)
}
}
impl Compact for OpTxEnvelope {
fn to_compact<B>(&self, buf: &mut B) -> usize
where
B: BufMut + AsMut<[u8]>,
{
CompactEnvelope::to_compact(self, buf)
}
fn from_compact(buf: &[u8], len: usize) -> (Self, &[u8]) {
CompactEnvelope::from_compact(buf, len)
}
}
generate_tests!(#[crate, compact] OpTypedTransaction, OpTypedTransactionTests);