alloy_consensus_any/receipt/
envelope.rs

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