reth_codecs/alloy/
optimism.rs

1//! Compact implementations for Optimism types.
2
3use crate::Compact;
4use alloc::{borrow::Cow, vec::Vec};
5use alloy_consensus::{Receipt, TxReceipt};
6use alloy_primitives::Log;
7use op_alloy_consensus::{OpDepositReceipt, OpReceipt, OpTxType};
8use reth_codecs_derive::CompactZstd;
9
10#[derive(CompactZstd)]
11#[reth_codecs(crate = "crate")]
12#[reth_zstd(
13    compressor = reth_zstd_compressors::RECEIPT_COMPRESSOR,
14    decompressor = reth_zstd_compressors::RECEIPT_DECOMPRESSOR
15)]
16struct CompactOpReceipt<'a> {
17    tx_type: OpTxType,
18    success: bool,
19    cumulative_gas_used: u64,
20    #[expect(clippy::owned_cow)]
21    logs: Cow<'a, Vec<Log>>,
22    deposit_nonce: Option<u64>,
23    deposit_receipt_version: Option<u64>,
24}
25
26impl<'a> From<&'a OpReceipt> for CompactOpReceipt<'a> {
27    fn from(receipt: &'a OpReceipt) -> Self {
28        Self {
29            tx_type: receipt.tx_type(),
30            success: receipt.status(),
31            cumulative_gas_used: receipt.cumulative_gas_used(),
32            logs: Cow::Borrowed(&receipt.as_receipt().logs),
33            deposit_nonce: if let OpReceipt::Deposit(receipt) = receipt {
34                receipt.deposit_nonce
35            } else {
36                None
37            },
38            deposit_receipt_version: if let OpReceipt::Deposit(receipt) = receipt {
39                receipt.deposit_receipt_version
40            } else {
41                None
42            },
43        }
44    }
45}
46
47impl From<CompactOpReceipt<'_>> for OpReceipt {
48    fn from(receipt: CompactOpReceipt<'_>) -> Self {
49        let CompactOpReceipt {
50            tx_type,
51            success,
52            cumulative_gas_used,
53            logs,
54            deposit_nonce,
55            deposit_receipt_version,
56        } = receipt;
57
58        let inner =
59            Receipt { status: success.into(), cumulative_gas_used, logs: logs.into_owned() };
60
61        match tx_type {
62            OpTxType::Legacy => Self::Legacy(inner),
63            OpTxType::Eip2930 => Self::Eip2930(inner),
64            OpTxType::Eip1559 => Self::Eip1559(inner),
65            OpTxType::Eip7702 => Self::Eip7702(inner),
66            OpTxType::Deposit => {
67                Self::Deposit(OpDepositReceipt { inner, deposit_nonce, deposit_receipt_version })
68            }
69        }
70    }
71}
72
73impl Compact for OpReceipt {
74    fn to_compact<B>(&self, buf: &mut B) -> usize
75    where
76        B: bytes::BufMut + AsMut<[u8]>,
77    {
78        CompactOpReceipt::from(self).to_compact(buf)
79    }
80
81    fn from_compact(buf: &[u8], len: usize) -> (Self, &[u8]) {
82        let (receipt, buf) = CompactOpReceipt::from_compact(buf, len);
83        (receipt.into(), buf)
84    }
85}
86
87#[cfg(test)]
88mod tests {
89    use super::*;
90    use crate::{test_utils::UnusedBits, validate_bitflag_backwards_compat};
91
92    #[test]
93    fn test_ensure_backwards_compatibility() {
94        assert_eq!(CompactOpReceipt::bitflag_encoded_bytes(), 2);
95        validate_bitflag_backwards_compat!(CompactOpReceipt<'_>, UnusedBits::NotZero);
96    }
97}