alloy_consensus/receipt/
mod.rs1use alloy_primitives::Bloom;
2use alloy_rlp::BufMut;
3use core::fmt;
4
5mod envelope;
6pub use envelope::ReceiptEnvelope;
7
8mod receipts;
9pub use receipts::{Receipt, ReceiptWithBloom, Receipts};
10
11mod status;
12pub use status::Eip658Value;
13
14use alloy_eips::Typed2718;
15
16#[cfg(all(feature = "serde", feature = "serde-bincode-compat"))]
18pub(crate) mod serde_bincode_compat {
19 pub use super::receipts::serde_bincode_compat::*;
20}
21
22#[doc(alias = "TransactionReceipt")]
24#[auto_impl::auto_impl(&, Arc)]
25pub trait TxReceipt: Clone + fmt::Debug + PartialEq + Eq + Send + Sync {
26 type Log;
28
29 fn status_or_post_state(&self) -> Eip658Value;
38
39 fn status(&self) -> bool;
54
55 fn bloom(&self) -> Bloom;
58
59 fn bloom_cheap(&self) -> Option<Bloom> {
62 None
63 }
64
65 #[auto_impl(keep_default_for(&, Arc))]
68 fn with_bloom_ref(&self) -> ReceiptWithBloom<&Self> {
69 ReceiptWithBloom { logs_bloom: self.bloom(), receipt: self }
70 }
71
72 #[auto_impl(keep_default_for(&, Arc))]
75 fn into_with_bloom(self) -> ReceiptWithBloom<Self> {
76 ReceiptWithBloom { logs_bloom: self.bloom(), receipt: self }
77 }
78
79 fn cumulative_gas_used(&self) -> u64;
81
82 fn logs(&self) -> &[Self::Log];
84}
85
86#[auto_impl::auto_impl(&)]
88pub trait RlpEncodableReceipt {
89 fn rlp_encoded_length_with_bloom(&self, bloom: &Bloom) -> usize;
91
92 fn rlp_encode_with_bloom(&self, bloom: &Bloom, out: &mut dyn BufMut);
94}
95
96pub trait RlpDecodableReceipt: Sized {
98 fn rlp_decode_with_bloom(buf: &mut &[u8]) -> alloy_rlp::Result<ReceiptWithBloom<Self>>;
100}
101
102#[auto_impl::auto_impl(&)]
108pub trait Eip2718EncodableReceipt: RlpEncodableReceipt + Typed2718 {
109 fn eip2718_encoded_length_with_bloom(&self, bloom: &Bloom) -> usize;
111
112 fn eip2718_encode_with_bloom(&self, bloom: &Bloom, out: &mut dyn BufMut);
114}
115
116#[cfg(test)]
117mod tests {
118 use super::*;
119 use alloy_eips::eip2718::Encodable2718;
120 use alloy_primitives::{address, b256, bytes, hex, Log, LogData};
121 use alloy_rlp::{Decodable, Encodable};
122
123 #[test]
125 fn encode_legacy_receipt() {
126 let expected = hex!("f901668001b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f85ff85d940000000000000000000000000000000000000011f842a0000000000000000000000000000000000000000000000000000000000000deada0000000000000000000000000000000000000000000000000000000000000beef830100ff");
127
128 let mut data = vec![];
129 let receipt =
130 ReceiptEnvelope::Legacy(ReceiptWithBloom {
131 receipt: Receipt {
132 cumulative_gas_used: 0x1,
133 logs: vec![Log {
134 address: address!("0000000000000000000000000000000000000011"),
135 data: LogData::new_unchecked(
136 vec![
137 b256!("000000000000000000000000000000000000000000000000000000000000dead"),
138 b256!("000000000000000000000000000000000000000000000000000000000000beef"),
139 ],
140 bytes!("0100ff"),
141 ),
142 }],
143 status: false.into(),
144 },
145 logs_bloom: [0; 256].into(),
146 });
147
148 receipt.network_encode(&mut data);
149
150 assert_eq!(receipt.length(), expected.len());
152 assert_eq!(data, expected);
153 }
154
155 #[test]
157 fn decode_legacy_receipt() {
158 let data = hex!("f901668001b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f85ff85d940000000000000000000000000000000000000011f842a0000000000000000000000000000000000000000000000000000000000000deada0000000000000000000000000000000000000000000000000000000000000beef830100ff");
159
160 let expected =
162 ReceiptWithBloom {
163 receipt: Receipt {
164 cumulative_gas_used: 0x1,
165 logs: vec![Log {
166 address: address!("0000000000000000000000000000000000000011"),
167 data: LogData::new_unchecked(
168 vec![
169 b256!("000000000000000000000000000000000000000000000000000000000000dead"),
170 b256!("000000000000000000000000000000000000000000000000000000000000beef"),
171 ],
172 bytes!("0100ff"),
173 ),
174 }],
175 status: false.into(),
176 },
177 logs_bloom: [0; 256].into(),
178 };
179
180 let receipt = ReceiptWithBloom::decode(&mut &data[..]).unwrap();
181 assert_eq!(receipt, expected);
182 }
183
184 #[test]
185 fn gigantic_receipt() {
186 let receipt = Receipt {
187 cumulative_gas_used: 16747627,
188 status: true.into(),
189 logs: vec![
190 Log {
191 address: address!("4bf56695415f725e43c3e04354b604bcfb6dfb6e"),
192 data: LogData::new_unchecked(
193 vec![b256!(
194 "c69dc3d7ebff79e41f525be431d5cd3cc08f80eaf0f7819054a726eeb7086eb9"
195 )],
196 vec![1; 0xffffff].into(),
197 ),
198 },
199 Log {
200 address: address!("faca325c86bf9c2d5b413cd7b90b209be92229c2"),
201 data: LogData::new_unchecked(
202 vec![b256!(
203 "8cca58667b1e9ffa004720ac99a3d61a138181963b294d270d91c53d36402ae2"
204 )],
205 vec![1; 0xffffff].into(),
206 ),
207 },
208 ],
209 }
210 .with_bloom();
211
212 let len = receipt.length();
213 let mut data = Vec::with_capacity(receipt.length());
214
215 receipt.encode(&mut data);
216 assert_eq!(data.len(), len);
217 let decoded = ReceiptWithBloom::decode(&mut &data[..]).unwrap();
218
219 assert_eq!(decoded, receipt);
222 }
223
224 #[test]
225 fn can_encode_by_reference() {
226 let receipt: Receipt =
227 Receipt { cumulative_gas_used: 16747627, status: true.into(), logs: vec![] };
228
229 let encoded_ref = alloy_rlp::encode(&ReceiptWithBloom {
230 receipt: &receipt,
231 logs_bloom: receipt.bloom_slow(),
232 });
233 let encoded =
234 alloy_rlp::encode(&ReceiptWithBloom { logs_bloom: receipt.bloom_slow(), receipt });
235
236 assert_eq!(encoded, encoded_ref);
237 }
238}