alloy_consensus_any/receipt/
envelope.rs

1use alloc::vec::Vec;
2use alloy_consensus::{Eip658Value, Receipt, ReceiptWithBloom, TxReceipt};
3use alloy_eips::{
4    eip2718::{Decodable2718, Eip2718Result, Encodable2718},
5    Typed2718,
6};
7use alloy_primitives::{bytes::BufMut, Bloom, Log};
8use alloy_rlp::{Decodable, Encodable};
9use core::fmt;
10
11/// Receipt envelope, as defined in [EIP-2718].
12///
13/// This enum distinguishes between tagged and untagged legacy receipts, as the
14/// in-protocol Merkle tree may commit to EITHER 0-prefixed or raw. Therefore
15/// we must ensure that encoding returns the precise byte-array that was
16/// decoded, preserving the presence or absence of the `TransactionType` flag.
17///
18/// Transaction receipt payloads are specified in their respective EIPs.
19///
20/// [EIP-2718]: https://eips.ethereum.org/EIPS/eip-2718
21#[derive(Clone, Debug, PartialEq, Eq)]
22#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
23#[doc(alias = "AnyTransactionReceiptEnvelope", alias = "AnyTxReceiptEnvelope")]
24pub struct AnyReceiptEnvelope<T = Log> {
25    /// The receipt envelope.
26    #[cfg_attr(feature = "serde", serde(flatten))]
27    pub inner: ReceiptWithBloom<Receipt<T>>,
28    /// The transaction type.
29    #[cfg_attr(feature = "serde", serde(with = "alloy_serde::quantity"))]
30    pub r#type: u8,
31}
32
33impl<T> AnyReceiptEnvelope<T> {
34    /// Returns whether this is a legacy receipt (type 0)
35    pub const fn is_legacy(&self) -> bool {
36        self.r#type == 0
37    }
38}
39
40impl<T: Encodable> AnyReceiptEnvelope<T> {
41    /// Calculate the length of the rlp payload of the network encoded receipt.
42    pub fn rlp_payload_length(&self) -> usize {
43        let length = self.inner.length();
44        if self.is_legacy() {
45            length
46        } else {
47            length + 1
48        }
49    }
50}
51
52impl<T> AnyReceiptEnvelope<T> {
53    /// Return true if the transaction was successful.
54    ///
55    /// ## Note
56    ///
57    /// This method may not accurately reflect the status of the transaction
58    /// for transactions before [EIP-658].
59    ///
60    /// [EIP-658]: https://eips.ethereum.org/EIPS/eip-658
61    pub const fn is_success(&self) -> bool {
62        self.status()
63    }
64
65    /// Returns the success status of the receipt's transaction.
66    ///
67    /// ## Note
68    ///
69    /// This method may not accurately reflect the status of the transaction
70    /// for transactions before [EIP-658].
71    ///
72    /// [EIP-658]: https://eips.ethereum.org/EIPS/eip-658
73    pub const fn status(&self) -> bool {
74        self.inner.receipt.status.coerce_status()
75    }
76
77    /// Return the receipt's bloom.
78    pub const fn bloom(&self) -> Bloom {
79        self.inner.logs_bloom
80    }
81
82    /// Return a reference to the receipt's bloom.
83    pub const fn bloom_ref(&self) -> &Bloom {
84        &self.inner.logs_bloom
85    }
86
87    /// Returns the cumulative gas used at this receipt.
88    pub const fn cumulative_gas_used(&self) -> u64 {
89        self.inner.receipt.cumulative_gas_used
90    }
91
92    /// Return the receipt logs.
93    pub fn logs(&self) -> &[T] {
94        &self.inner.receipt.logs
95    }
96}
97
98impl<T> TxReceipt for AnyReceiptEnvelope<T>
99where
100    T: Clone + fmt::Debug + PartialEq + Eq + Send + Sync,
101{
102    type Log = T;
103
104    fn status_or_post_state(&self) -> Eip658Value {
105        self.inner.receipt.status
106    }
107
108    fn status(&self) -> bool {
109        self.status()
110    }
111
112    fn bloom(&self) -> Bloom {
113        self.bloom()
114    }
115
116    fn cumulative_gas_used(&self) -> u64 {
117        self.cumulative_gas_used()
118    }
119
120    fn logs(&self) -> &[T] {
121        Self::logs(self)
122    }
123
124    fn into_logs(self) -> Vec<Self::Log>
125    where
126        Self::Log: Clone,
127    {
128        self.inner.receipt.logs
129    }
130}
131
132impl Typed2718 for AnyReceiptEnvelope {
133    fn ty(&self) -> u8 {
134        self.r#type
135    }
136}
137
138impl Encodable2718 for AnyReceiptEnvelope {
139    fn encode_2718_len(&self) -> usize {
140        self.inner.length() + !self.is_legacy() as usize
141    }
142
143    fn encode_2718(&self, out: &mut dyn BufMut) {
144        match self.type_flag() {
145            None => {}
146            Some(ty) => out.put_u8(ty),
147        }
148        self.inner.encode(out);
149    }
150}
151
152impl Decodable2718 for AnyReceiptEnvelope {
153    fn typed_decode(ty: u8, buf: &mut &[u8]) -> Eip2718Result<Self> {
154        let receipt = Decodable::decode(buf)?;
155        Ok(Self { inner: receipt, r#type: ty })
156    }
157
158    fn fallback_decode(buf: &mut &[u8]) -> Eip2718Result<Self> {
159        Self::typed_decode(0, buf)
160    }
161}