1use alloy_consensus::{
2 proofs::ordered_trie_root_with_encoder, Eip2718EncodableReceipt, Eip658Value, Receipt,
3 ReceiptWithBloom, RlpDecodableReceipt, RlpEncodableReceipt, TxReceipt, Typed2718,
4};
5use alloy_eips::{eip2718::Eip2718Result, Decodable2718, Encodable2718};
6use alloy_primitives::{Bloom, Log, B256};
7use alloy_rlp::{BufMut, Decodable, Encodable, Header};
8use reth_primitives_traits::InMemorySize;
9use seismic_alloy_consensus::SeismicTxType;
10
11#[derive(Clone, Debug, PartialEq, Eq)]
14#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
15#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
16pub enum SeismicReceipt {
17 Legacy(Receipt),
19 Eip2930(Receipt),
21 Eip1559(Receipt),
23 Eip4844(Receipt),
25 Eip7702(Receipt),
27 Seismic(Receipt),
29}
30
31impl Default for SeismicReceipt {
32 fn default() -> Self {
33 Self::Legacy(Default::default())
34 }
35}
36
37impl SeismicReceipt {
38 pub const fn tx_type(&self) -> SeismicTxType {
40 match self {
41 Self::Legacy(_) => SeismicTxType::Legacy,
42 Self::Eip2930(_) => SeismicTxType::Eip2930,
43 Self::Eip1559(_) => SeismicTxType::Eip1559,
44 Self::Eip4844(_) => SeismicTxType::Eip4844,
45 Self::Eip7702(_) => SeismicTxType::Eip7702,
46 Self::Seismic(_) => SeismicTxType::Seismic,
47 }
48 }
49
50 pub const fn as_receipt(&self) -> &Receipt {
52 match self {
53 Self::Legacy(receipt) |
54 Self::Eip2930(receipt) |
55 Self::Eip1559(receipt) |
56 Self::Eip4844(receipt) |
57 Self::Eip7702(receipt) |
58 Self::Seismic(receipt) => receipt,
59 }
60 }
61
62 pub const fn as_receipt_mut(&mut self) -> &mut Receipt {
64 match self {
65 Self::Legacy(receipt) |
66 Self::Eip2930(receipt) |
67 Self::Eip1559(receipt) |
68 Self::Eip4844(receipt) |
69 Self::Eip7702(receipt) |
70 Self::Seismic(receipt) => receipt,
71 }
72 }
73
74 pub fn into_receipt(self) -> Receipt {
76 match self {
77 Self::Legacy(receipt) |
78 Self::Eip2930(receipt) |
79 Self::Eip1559(receipt) |
80 Self::Eip4844(receipt) |
81 Self::Eip7702(receipt) |
82 Self::Seismic(receipt) => receipt,
83 }
84 }
85
86 pub fn rlp_encoded_fields_length(&self, bloom: &Bloom) -> usize {
88 match self {
89 Self::Legacy(receipt) |
90 Self::Eip2930(receipt) |
91 Self::Eip1559(receipt) |
92 Self::Eip4844(receipt) |
93 Self::Eip7702(receipt) |
94 Self::Seismic(receipt) => receipt.rlp_encoded_fields_length_with_bloom(bloom),
95 }
96 }
97
98 pub fn rlp_encode_fields(&self, bloom: &Bloom, out: &mut dyn BufMut) {
100 match self {
101 Self::Legacy(receipt) |
102 Self::Eip2930(receipt) |
103 Self::Eip1559(receipt) |
104 Self::Eip4844(receipt) |
105 Self::Eip7702(receipt) |
106 Self::Seismic(receipt) => receipt.rlp_encode_fields_with_bloom(bloom, out),
107 }
108 }
109
110 pub fn rlp_header_inner(&self, bloom: &Bloom) -> Header {
112 Header { list: true, payload_length: self.rlp_encoded_fields_length(bloom) }
113 }
114
115 pub fn rlp_header_inner_without_bloom(&self) -> Header {
117 Header { list: true, payload_length: self.rlp_encoded_fields_length_without_bloom() }
118 }
119
120 pub fn rlp_decode_inner(
123 buf: &mut &[u8],
124 tx_type: SeismicTxType,
125 ) -> alloy_rlp::Result<ReceiptWithBloom<Self>> {
126 match tx_type {
127 SeismicTxType::Legacy => {
128 let ReceiptWithBloom { receipt, logs_bloom } =
129 RlpDecodableReceipt::rlp_decode_with_bloom(buf)?;
130 Ok(ReceiptWithBloom { receipt: Self::Legacy(receipt), logs_bloom })
131 }
132 SeismicTxType::Eip2930 => {
133 let ReceiptWithBloom { receipt, logs_bloom } =
134 RlpDecodableReceipt::rlp_decode_with_bloom(buf)?;
135 Ok(ReceiptWithBloom { receipt: Self::Eip2930(receipt), logs_bloom })
136 }
137 SeismicTxType::Eip1559 => {
138 let ReceiptWithBloom { receipt, logs_bloom } =
139 RlpDecodableReceipt::rlp_decode_with_bloom(buf)?;
140 Ok(ReceiptWithBloom { receipt: Self::Eip1559(receipt), logs_bloom })
141 }
142 SeismicTxType::Eip4844 => {
143 let ReceiptWithBloom { receipt, logs_bloom } =
144 RlpDecodableReceipt::rlp_decode_with_bloom(buf)?;
145 Ok(ReceiptWithBloom { receipt: Self::Eip4844(receipt), logs_bloom })
146 }
147 SeismicTxType::Eip7702 => {
148 let ReceiptWithBloom { receipt, logs_bloom } =
149 RlpDecodableReceipt::rlp_decode_with_bloom(buf)?;
150 Ok(ReceiptWithBloom { receipt: Self::Eip7702(receipt), logs_bloom })
151 }
152 SeismicTxType::Seismic => {
153 let ReceiptWithBloom { receipt, logs_bloom } =
154 RlpDecodableReceipt::rlp_decode_with_bloom(buf)?;
155 Ok(ReceiptWithBloom { receipt: Self::Seismic(receipt), logs_bloom })
156 }
157 }
158 }
159
160 pub fn rlp_encode_fields_without_bloom(&self, out: &mut dyn BufMut) {
162 match self {
163 Self::Legacy(receipt) |
164 Self::Eip2930(receipt) |
165 Self::Eip1559(receipt) |
166 Self::Eip4844(receipt) |
167 Self::Eip7702(receipt) |
168 Self::Seismic(receipt) => {
169 receipt.status.encode(out);
170 receipt.cumulative_gas_used.encode(out);
171 receipt.logs.encode(out);
172 }
173 }
174 }
175
176 pub fn rlp_encoded_fields_length_without_bloom(&self) -> usize {
178 match self {
179 Self::Legacy(receipt) |
180 Self::Eip2930(receipt) |
181 Self::Eip1559(receipt) |
182 Self::Eip4844(receipt) |
183 Self::Eip7702(receipt) |
184 Self::Seismic(receipt) => {
185 receipt.status.length() +
186 receipt.cumulative_gas_used.length() +
187 receipt.logs.length()
188 }
189 }
190 }
191
192 pub fn rlp_decode_inner_without_bloom(
194 buf: &mut &[u8],
195 tx_type: SeismicTxType,
196 ) -> alloy_rlp::Result<Self> {
197 let header = Header::decode(buf)?;
198 if !header.list {
199 return Err(alloy_rlp::Error::UnexpectedString);
200 }
201
202 let remaining = buf.len();
203 let status = Decodable::decode(buf)?;
204 let cumulative_gas_used = Decodable::decode(buf)?;
205 let logs = Decodable::decode(buf)?;
206
207 if buf.len() + header.payload_length != remaining {
208 return Err(alloy_rlp::Error::UnexpectedLength);
209 }
210
211 match tx_type {
212 SeismicTxType::Legacy => {
213 Ok(Self::Legacy(Receipt { status, cumulative_gas_used, logs }))
214 }
215 SeismicTxType::Eip2930 => {
216 Ok(Self::Eip2930(Receipt { status, cumulative_gas_used, logs }))
217 }
218 SeismicTxType::Eip1559 => {
219 Ok(Self::Eip1559(Receipt { status, cumulative_gas_used, logs }))
220 }
221 SeismicTxType::Eip4844 => {
222 Ok(Self::Eip4844(Receipt { status, cumulative_gas_used, logs }))
223 }
224 SeismicTxType::Eip7702 => {
225 Ok(Self::Eip7702(Receipt { status, cumulative_gas_used, logs }))
226 }
227 SeismicTxType::Seismic => {
228 Ok(Self::Seismic(Receipt { status, cumulative_gas_used, logs }))
229 }
230 }
231 }
232
233 pub fn calculate_receipt_root_no_memo(receipts: &[Self]) -> B256 {
237 ordered_trie_root_with_encoder(receipts, |r, buf| r.with_bloom_ref().encode_2718(buf))
238 }
239}
240
241impl Eip2718EncodableReceipt for SeismicReceipt {
242 fn eip2718_encoded_length_with_bloom(&self, bloom: &Bloom) -> usize {
243 !self.tx_type().is_legacy() as usize + self.rlp_header_inner(bloom).length_with_payload()
244 }
245
246 fn eip2718_encode_with_bloom(&self, bloom: &Bloom, out: &mut dyn BufMut) {
247 if !self.tx_type().is_legacy() {
248 out.put_u8(self.tx_type() as u8);
249 }
250 self.rlp_header_inner(bloom).encode(out);
251 self.rlp_encode_fields(bloom, out);
252 }
253}
254
255impl RlpEncodableReceipt for SeismicReceipt {
256 fn rlp_encoded_length_with_bloom(&self, bloom: &Bloom) -> usize {
257 let mut len = self.eip2718_encoded_length_with_bloom(bloom);
258 if !self.tx_type().is_legacy() {
259 len += Header {
260 list: false,
261 payload_length: self.eip2718_encoded_length_with_bloom(bloom),
262 }
263 .length();
264 }
265
266 len
267 }
268
269 fn rlp_encode_with_bloom(&self, bloom: &Bloom, out: &mut dyn BufMut) {
270 if !self.tx_type().is_legacy() {
271 Header { list: false, payload_length: self.eip2718_encoded_length_with_bloom(bloom) }
272 .encode(out);
273 }
274 self.eip2718_encode_with_bloom(bloom, out);
275 }
276}
277
278impl RlpDecodableReceipt for SeismicReceipt {
279 fn rlp_decode_with_bloom(buf: &mut &[u8]) -> alloy_rlp::Result<ReceiptWithBloom<Self>> {
280 let header_buf = &mut &**buf;
281 let header = Header::decode(header_buf)?;
282
283 if header.list {
285 return Self::rlp_decode_inner(buf, SeismicTxType::Legacy)
286 }
287
288 *buf = *header_buf;
290
291 let remaining = buf.len();
292 let tx_type = SeismicTxType::decode(buf)?;
293 let this = Self::rlp_decode_inner(buf, tx_type)?;
294
295 if buf.len() + header.payload_length != remaining {
296 return Err(alloy_rlp::Error::UnexpectedLength);
297 }
298
299 Ok(this)
300 }
301}
302
303impl Encodable2718 for SeismicReceipt {
304 fn encode_2718_len(&self) -> usize {
305 !self.tx_type().is_legacy() as usize +
306 self.rlp_header_inner_without_bloom().length_with_payload()
307 }
308
309 fn encode_2718(&self, out: &mut dyn BufMut) {
310 if !self.tx_type().is_legacy() {
311 out.put_u8(self.tx_type() as u8);
312 }
313 self.rlp_header_inner_without_bloom().encode(out);
314 self.rlp_encode_fields_without_bloom(out);
315 }
316}
317
318impl Decodable2718 for SeismicReceipt {
319 fn typed_decode(ty: u8, buf: &mut &[u8]) -> Eip2718Result<Self> {
320 Ok(Self::rlp_decode_inner_without_bloom(buf, SeismicTxType::try_from(ty)?)?)
321 }
322
323 fn fallback_decode(buf: &mut &[u8]) -> Eip2718Result<Self> {
324 Ok(Self::rlp_decode_inner_without_bloom(buf, SeismicTxType::Legacy)?)
325 }
326}
327
328impl Encodable for SeismicReceipt {
329 fn encode(&self, out: &mut dyn BufMut) {
330 self.network_encode(out);
331 }
332
333 fn length(&self) -> usize {
334 self.network_len()
335 }
336}
337
338impl Decodable for SeismicReceipt {
339 fn decode(buf: &mut &[u8]) -> alloy_rlp::Result<Self> {
340 Ok(Self::network_decode(buf)?)
341 }
342}
343
344impl TxReceipt for SeismicReceipt {
345 type Log = Log;
346
347 fn status_or_post_state(&self) -> Eip658Value {
348 self.as_receipt().status_or_post_state()
349 }
350
351 fn status(&self) -> bool {
352 self.as_receipt().status()
353 }
354
355 fn bloom(&self) -> Bloom {
356 self.as_receipt().bloom()
357 }
358
359 fn cumulative_gas_used(&self) -> u64 {
360 self.as_receipt().cumulative_gas_used()
361 }
362
363 fn logs(&self) -> &[Log] {
364 self.as_receipt().logs()
365 }
366}
367
368impl Typed2718 for SeismicReceipt {
369 fn ty(&self) -> u8 {
370 self.tx_type().into()
371 }
372}
373
374impl InMemorySize for SeismicReceipt {
375 fn size(&self) -> usize {
376 self.as_receipt().size()
377 }
378}
379
380impl reth_primitives_traits::Receipt for SeismicReceipt {}
381
382#[cfg(feature = "reth-codec")]
383mod compact {
384 use super::*;
385 use alloc::borrow::Cow;
386 use reth_codecs::Compact;
387
388 #[derive(reth_codecs::CompactZstd)]
389 #[reth_zstd(
390 compressor = reth_zstd_compressors::RECEIPT_COMPRESSOR,
391 decompressor = reth_zstd_compressors::RECEIPT_DECOMPRESSOR
392 )]
393 struct CompactSeismicReceipt<'a> {
394 tx_type: SeismicTxType,
395 success: bool,
396 cumulative_gas_used: u64,
397 #[expect(clippy::owned_cow)]
398 logs: Cow<'a, Vec<Log>>,
399 }
400
401 impl<'a> From<&'a SeismicReceipt> for CompactSeismicReceipt<'a> {
402 fn from(receipt: &'a SeismicReceipt) -> Self {
403 Self {
404 tx_type: receipt.tx_type(),
405 success: receipt.status(),
406 cumulative_gas_used: receipt.cumulative_gas_used(),
407 logs: Cow::Borrowed(&receipt.as_receipt().logs),
408 }
409 }
410 }
411
412 impl From<CompactSeismicReceipt<'_>> for SeismicReceipt {
413 fn from(receipt: CompactSeismicReceipt<'_>) -> Self {
414 let CompactSeismicReceipt { tx_type, success, cumulative_gas_used, logs } = receipt;
415
416 let inner =
417 Receipt { status: success.into(), cumulative_gas_used, logs: logs.into_owned() };
418
419 match tx_type {
420 SeismicTxType::Legacy => Self::Legacy(inner),
421 SeismicTxType::Eip2930 => Self::Eip2930(inner),
422 SeismicTxType::Eip1559 => Self::Eip1559(inner),
423 SeismicTxType::Eip4844 => Self::Eip4844(inner),
424 SeismicTxType::Eip7702 => Self::Eip7702(inner),
425 SeismicTxType::Seismic => Self::Seismic(inner),
426 }
427 }
428 }
429
430 impl Compact for SeismicReceipt {
431 fn to_compact<B>(&self, buf: &mut B) -> usize
432 where
433 B: bytes::BufMut + AsMut<[u8]>,
434 {
435 CompactSeismicReceipt::from(self).to_compact(buf)
436 }
437
438 fn from_compact(buf: &[u8], len: usize) -> (Self, &[u8]) {
439 let (receipt, buf) = CompactSeismicReceipt::from_compact(buf, len);
440 (receipt.into(), buf)
441 }
442 }
443}
444
445#[cfg(all(feature = "serde", feature = "serde-bincode-compat"))]
446pub(super) mod serde_bincode_compat {
447 use serde::{Deserialize, Deserializer, Serialize, Serializer};
448 use serde_with::{DeserializeAs, SerializeAs};
449
450 #[derive(Debug, Serialize, Deserialize)]
466 pub enum SeismicReceipt<'a> {
467 Legacy(alloy_consensus::serde_bincode_compat::Receipt<'a, alloy_primitives::Log>),
469 Eip2930(alloy_consensus::serde_bincode_compat::Receipt<'a, alloy_primitives::Log>),
471 Eip1559(alloy_consensus::serde_bincode_compat::Receipt<'a, alloy_primitives::Log>),
473 Eip4844(alloy_consensus::serde_bincode_compat::Receipt<'a, alloy_primitives::Log>),
475 Eip7702(alloy_consensus::serde_bincode_compat::Receipt<'a, alloy_primitives::Log>),
477 Seismic(alloy_consensus::serde_bincode_compat::Receipt<'a, alloy_primitives::Log>),
479 }
480
481 impl<'a> From<&'a super::SeismicReceipt> for SeismicReceipt<'a> {
482 fn from(value: &'a super::SeismicReceipt) -> Self {
483 match value {
484 super::SeismicReceipt::Legacy(receipt) => Self::Legacy(receipt.into()),
485 super::SeismicReceipt::Eip2930(receipt) => Self::Eip2930(receipt.into()),
486 super::SeismicReceipt::Eip1559(receipt) => Self::Eip1559(receipt.into()),
487 super::SeismicReceipt::Eip4844(receipt) => Self::Eip4844(receipt.into()),
488 super::SeismicReceipt::Eip7702(receipt) => Self::Eip7702(receipt.into()),
489 super::SeismicReceipt::Seismic(receipt) => Self::Seismic(receipt.into()),
490 }
491 }
492 }
493
494 impl<'a> From<SeismicReceipt<'a>> for super::SeismicReceipt {
495 fn from(value: SeismicReceipt<'a>) -> Self {
496 match value {
497 SeismicReceipt::Legacy(receipt) => Self::Legacy(receipt.into()),
498 SeismicReceipt::Eip2930(receipt) => Self::Eip2930(receipt.into()),
499 SeismicReceipt::Eip1559(receipt) => Self::Eip1559(receipt.into()),
500 SeismicReceipt::Eip4844(receipt) => Self::Eip4844(receipt.into()),
501 SeismicReceipt::Eip7702(receipt) => Self::Eip7702(receipt.into()),
502 SeismicReceipt::Seismic(receipt) => Self::Seismic(receipt.into()),
503 }
504 }
505 }
506
507 impl SerializeAs<super::SeismicReceipt> for SeismicReceipt<'_> {
508 fn serialize_as<S>(source: &super::SeismicReceipt, serializer: S) -> Result<S::Ok, S::Error>
509 where
510 S: Serializer,
511 {
512 SeismicReceipt::<'_>::from(source).serialize(serializer)
513 }
514 }
515
516 impl<'de> DeserializeAs<'de, super::SeismicReceipt> for SeismicReceipt<'de> {
517 fn deserialize_as<D>(deserializer: D) -> Result<super::SeismicReceipt, D::Error>
518 where
519 D: Deserializer<'de>,
520 {
521 SeismicReceipt::<'_>::deserialize(deserializer).map(Into::into)
522 }
523 }
524
525 impl reth_primitives_traits::serde_bincode_compat::SerdeBincodeCompat for super::SeismicReceipt {
526 type BincodeRepr<'a> = SeismicReceipt<'a>;
527
528 fn as_repr(&self) -> Self::BincodeRepr<'_> {
529 self.into()
530 }
531
532 fn from_repr(repr: Self::BincodeRepr<'_>) -> Self {
533 repr.into()
534 }
535 }
536
537 #[cfg(test)]
538 mod tests {
539 use crate::{receipt::serde_bincode_compat, SeismicReceipt};
540 use arbitrary::Arbitrary;
541 use rand::Rng;
542 use serde::{Deserialize, Serialize};
543 use serde_with::serde_as;
544
545 #[test]
546 fn test_tx_bincode_roundtrip() {
547 #[serde_as]
548 #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
549 struct Data {
550 #[serde_as(as = "serde_bincode_compat::SeismicReceipt<'_>")]
551 reseipt: SeismicReceipt,
552 }
553
554 let mut bytes = [0u8; 1024];
555 rand::rng().fill(bytes.as_mut_slice());
556 let mut data = Data {
557 reseipt: SeismicReceipt::arbitrary(&mut arbitrary::Unstructured::new(&bytes))
558 .unwrap(),
559 };
560 let success = data.reseipt.as_receipt_mut().status.coerce_status();
561 data.reseipt.as_receipt_mut().status = success.into();
563
564 let encoded = bincode::serialize(&data).unwrap();
565 let decoded: Data = bincode::deserialize(&encoded).unwrap();
566 assert_eq!(decoded, data);
567 }
568 }
569}
570
571#[cfg(test)]
572mod tests {
573 use super::*;
574 use alloy_eips::eip2718::Encodable2718;
575 use alloy_primitives::{address, b256, bytes, hex_literal::hex};
576 use alloy_rlp::Encodable;
577
578 #[test]
579 #[cfg(feature = "reth-codec")]
580 fn test_decode_receipt() {
582 reth_codecs::test_utils::test_decode::<SeismicReceipt>(&hex!(
583 "c428b52ffd23fc42696156b10200f034792b6a94c3850215c2fef7aea361a0c31b79d9a32652eefc0d4e2e730036061cff7344b6fc6132b50cda0ed810a991ae58ef013150c12b2522533cb3b3a8b19b7786a8b5ff1d3cdc84225e22b02def168c8858df"
584 ));
585 }
586
587 #[test]
590 fn encode_legacy_receipt() {
591 let expected = hex!("f901668001b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f85ff85d940000000000000000000000000000000000000011f842a0000000000000000000000000000000000000000000000000000000000000deada0000000000000000000000000000000000000000000000000000000000000beef830100ff");
592
593 let mut data = Vec::with_capacity(expected.length());
594 let receipt = ReceiptWithBloom {
595 receipt: SeismicReceipt::Legacy(Receipt {
596 status: Eip658Value::Eip658(false),
597 cumulative_gas_used: 0x1,
598 logs: vec![Log::new_unchecked(
599 address!("0x0000000000000000000000000000000000000011"),
600 vec![
601 b256!("0x000000000000000000000000000000000000000000000000000000000000dead"),
602 b256!("0x000000000000000000000000000000000000000000000000000000000000beef"),
603 ],
604 bytes!("0100ff"),
605 )],
606 }),
607 logs_bloom: [0; 256].into(),
608 };
609
610 receipt.encode(&mut data);
611
612 assert_eq!(receipt.length(), expected.len());
614 assert_eq!(data, expected);
615 }
616
617 #[test]
620 fn decode_legacy_receipt() {
621 let data = hex!("f901668001b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f85ff85d940000000000000000000000000000000000000011f842a0000000000000000000000000000000000000000000000000000000000000deada0000000000000000000000000000000000000000000000000000000000000beef830100ff");
622
623 let expected = ReceiptWithBloom {
625 receipt: SeismicReceipt::Legacy(Receipt {
626 status: Eip658Value::Eip658(false),
627 cumulative_gas_used: 0x1,
628 logs: vec![Log::new_unchecked(
629 address!("0x0000000000000000000000000000000000000011"),
630 vec![
631 b256!("0x000000000000000000000000000000000000000000000000000000000000dead"),
632 b256!("0x000000000000000000000000000000000000000000000000000000000000beef"),
633 ],
634 bytes!("0100ff"),
635 )],
636 }),
637 logs_bloom: [0; 256].into(),
638 };
639
640 let receipt = ReceiptWithBloom::decode(&mut &data[..]).unwrap();
641 assert_eq!(receipt, expected);
642 }
643
644 #[test]
645 fn test_encode_2718_length() {
646 let receipt = ReceiptWithBloom {
647 receipt: SeismicReceipt::Eip1559(Receipt {
648 status: Eip658Value::Eip658(true),
649 cumulative_gas_used: 21000,
650 logs: vec![],
651 }),
652 logs_bloom: Bloom::default(),
653 };
654
655 let encoded = receipt.encoded_2718();
656 assert_eq!(
657 encoded.len(),
658 receipt.encode_2718_len(),
659 "Encoded length should match the actual encoded data length"
660 );
661
662 let legacy_receipt = ReceiptWithBloom {
664 receipt: SeismicReceipt::Legacy(Receipt {
665 status: Eip658Value::Eip658(true),
666 cumulative_gas_used: 21000,
667 logs: vec![],
668 }),
669 logs_bloom: Bloom::default(),
670 };
671
672 let legacy_encoded = legacy_receipt.encoded_2718();
673 assert_eq!(
674 legacy_encoded.len(),
675 legacy_receipt.encode_2718_len(),
676 "Encoded length for legacy receipt should match the actual encoded data length"
677 );
678 }
679
680 #[test]
681 fn seismic_seismic_receipt_roundtrip() {
683 let receipt: ReceiptWithBloom<SeismicReceipt> = ReceiptWithBloom {
684 receipt: SeismicReceipt::Legacy(Receipt {
685 status: Eip658Value::Eip658(false),
686 cumulative_gas_used: 0x1,
687 logs: vec![Log::new_unchecked(
688 address!("0x0000000000000000000000000000000000000011"),
689 vec![
690 b256!("0x000000000000000000000000000000000000000000000000000000000000dead"),
691 b256!("0x000000000000000000000000000000000000000000000000000000000000beef"),
692 ],
693 bytes!("0100ff"),
694 )],
695 }),
696 logs_bloom: [0; 256].into(),
697 };
698
699 let mut data = Vec::with_capacity(receipt.encode_2718_len());
700 receipt.encode(&mut data);
701 let decoded: ReceiptWithBloom<SeismicReceipt> =
702 ReceiptWithBloom::decode(&mut &data[..]).unwrap();
703 assert_eq!(receipt, decoded);
704 }
705}