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        self.inner.receipt.logs
126    }
127}
128
129impl Typed2718 for AnyReceiptEnvelope {
130    fn ty(&self) -> u8 {
131        self.r#type
132    }
133}
134
135impl Encodable2718 for AnyReceiptEnvelope {
136    fn encode_2718_len(&self) -> usize {
137        self.inner.length() + !self.is_legacy() as usize
138    }
139
140    fn encode_2718(&self, out: &mut dyn BufMut) {
141        match self.type_flag() {
142            None => {}
143            Some(ty) => out.put_u8(ty),
144        }
145        self.inner.encode(out);
146    }
147}
148
149impl Decodable2718 for AnyReceiptEnvelope {
150    fn typed_decode(ty: u8, buf: &mut &[u8]) -> Eip2718Result<Self> {
151        let receipt = Decodable::decode(buf)?;
152        Ok(Self { inner: receipt, r#type: ty })
153    }
154
155    fn fallback_decode(buf: &mut &[u8]) -> Eip2718Result<Self> {
156        Self::typed_decode(0, buf)
157    }
158}