referrerpolicy=no-referrer-when-downgrade

snowbridge_ethereum/
receipt.rs

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: 2023 Snowfork <hello@snowfork.com>
3use crate::{Bloom, Log};
4use codec::{Decode, Encode};
5use sp_runtime::RuntimeDebug;
6use sp_std::prelude::*;
7
8#[derive(Clone, Default, Encode, Decode, PartialEq, RuntimeDebug)]
9pub struct Receipt {
10	pub post_state_or_status: Vec<u8>,
11	pub cumulative_gas_used: u64,
12	pub bloom: Bloom,
13	pub logs: Vec<Log>,
14}
15
16impl Receipt {
17	pub fn contains_log(&self, log: &Log) -> bool {
18		self.logs.iter().any(|l| l == log)
19	}
20
21	fn decode_list(rlp: &rlp::Rlp) -> Result<Self, rlp::DecoderError> {
22		let mut iter = rlp.iter();
23
24		let post_state_or_status: Vec<u8> = match iter.next() {
25			Some(data) => data.as_val()?,
26			None => return Err(rlp::DecoderError::Custom("Expected receipt post state or status")),
27		};
28
29		let cumulative_gas_used: u64 = match iter.next() {
30			Some(data) => data.as_val()?,
31			None => return Err(rlp::DecoderError::Custom("Expected receipt cumulative gas used")),
32		};
33
34		let bloom: Bloom = match iter.next() {
35			Some(data) => data.as_val()?,
36			None => return Err(rlp::DecoderError::Custom("Expected receipt bloom")),
37		};
38
39		let logs: Vec<Log> = match iter.next() {
40			Some(data) => data.as_list()?,
41			None => return Err(rlp::DecoderError::Custom("Expected receipt logs")),
42		};
43
44		Ok(Self { post_state_or_status, cumulative_gas_used, bloom, logs })
45	}
46}
47
48impl rlp::Decodable for Receipt {
49	fn decode(rlp: &rlp::Rlp) -> Result<Self, rlp::DecoderError> {
50		if rlp.is_data() {
51			// Typed receipt
52			let data = rlp.as_raw();
53			match data[0] {
54				// 1 = EIP-2930, 2 = EIP-1559
55				1 | 2 => {
56					let receipt_rlp = &rlp::Rlp::new(&data[1..]);
57					if !receipt_rlp.is_list() {
58						return Err(rlp::DecoderError::RlpExpectedToBeList)
59					}
60					Self::decode_list(&rlp::Rlp::new(&data[1..]))
61				},
62				_ => Err(rlp::DecoderError::Custom("Unsupported receipt type")),
63			}
64		} else if rlp.is_list() {
65			// Legacy receipt
66			Self::decode_list(rlp)
67		} else {
68			Err(rlp::DecoderError::RlpExpectedToBeList)
69		}
70	}
71}
72
73#[cfg(test)]
74mod tests {
75
76	use super::Receipt;
77	use hex_literal::hex;
78
79	const RAW_RECEIPT: [u8; 1242] = hex!(
80		"
81		f904d701830652f0b901000420000000000000000000008002000000000001000000000001000000
82		00000000000000000000000000000000000000020000000800000000000000002000000000000000
83		00000000000008000000220000000000400010000000000000000000000000000000000000000000
84		00000000000000000004000000001000010000000000080000000000400000000000000000000000
85		00000800000040000000000200000000000200000000000000000000000000000000000000000000
86		04000000000002000000000100000000000000000000000000001000000002000020000010200000
87		000000010000000000000000000000000000000000000010000000f903ccf89b9421130f34829b4c
88		343142047a28ce96ec07814b15f863a0ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a116
89		28f55a4df523b3efa00000000000000000000000007d843005c7433c16b27ff939cb37471541561e
90		bda0000000000000000000000000e9c1281aae66801fa35ec404d5f2aea393ff6988a00000000000
91		0000000000000000000000000000000000000000000005d09b7380f89b9421130f34829b4c343142
92		047a28ce96ec07814b15f863a08c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200a
93		c8c7c3b925a00000000000000000000000007d843005c7433c16b27ff939cb37471541561ebda000
94		00000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488da0ffffffffffffffff
95		ffffffffffffffffffffffffffffffffffffffcc840c6920f89b94c02aaa39b223fe8d0a0e5c4f27
96		ead9083c756cc2f863a0ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523
97		b3efa0000000000000000000000000e9c1281aae66801fa35ec404d5f2aea393ff6988a000000000
98		00000000000000007a250d5630b4cf539739df2c5dacb4c659f2488da00000000000000000000000
99		0000000000000000000000000003e973b5a5d1078ef87994e9c1281aae66801fa35ec404d5f2aea3
100		93ff6988e1a01c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1b840
101		000000000000000000000000000000000000000000000000000001f1420ad1d40000000000000000
102		000000000000000000000000000000014ad400879d159a38f8fc94e9c1281aae66801fa35ec404d5
103		f2aea393ff6988f863a0d78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159
104		d822a00000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488da000000000
105		00000000000000007a250d5630b4cf539739df2c5dacb4c659f2488db88000000000000000000000
106		000000000000000000000000000000000005d415f332000000000000000000000000000000000000
107		00000000000000000000000000000000000000000000000000000000000000000000000000000000
108		00000000000000000000000000000000000000000000000000000000000003e973b5a5d1078ef87a
109		94c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2f842a07fcf532c15f0a6db0bd6d0e038bea71d
110		30d808c7d98cb3bf7268a95bf5081b65a00000000000000000000000007a250d5630b4cf539739df
111		2c5dacb4c659f2488da000000000000000000000000000000000000000000000000003e973b5a5d1
112		078e
113	"
114	);
115
116	#[test]
117	fn decode_legacy_receipt() {
118		let receipt: Receipt = rlp::decode(&RAW_RECEIPT).unwrap();
119		assert_eq!(receipt.post_state_or_status, vec!(1));
120		assert_eq!(receipt.cumulative_gas_used, 414448);
121		assert_eq!(
122			receipt.bloom,
123			(&hex!(
124				"
125				042000000000000000000000800200000000000100000000000100000000000000000000
126				000000000000000000000000020000000800000000000000002000000000000000000000
127				000000080000002200000000004000100000000000000000000000000000000000000000
128				000000000000000000000400000000100001000000000008000000000040000000000000
129				000000000000000800000040000000000200000000000200000000000000000000000000
130				000000000000000000040000000000020000000001000000000000000000000000000010
131				000000020000200000102000000000000100000000000000000000000000000000000000
132				10000000
133			"
134			))
135				.into(),
136		);
137		assert_eq!(receipt.logs.len(), 6);
138	}
139}