1use super::Transaction;
2use cfx_rpc_primitives::Bytes;
3use cfx_types::{Address, Bloom, H256, U256, U64};
4use serde::Deserialize;
5
6#[derive(Debug, PartialEq, Eq, Deserialize)]
7#[serde(rename_all = "camelCase")]
8pub struct BlockHeader {
9 pub parent_hash: H256,
10 pub uncle_hash: H256,
11 pub coinbase: Address,
12 pub state_root: H256,
13 pub transactions_trie: H256,
14 pub receipt_trie: H256,
15 pub bloom: Bloom,
16 pub difficulty: U256,
17 pub number: U256,
18 pub gas_limit: U256,
19 pub gas_used: U256,
20 pub timestamp: U256,
21 pub extra_data: Bytes,
22 pub mix_hash: H256,
23 pub nonce: U64, pub base_fee_per_gas: Option<U256>,
25 pub withdrawals_root: Option<H256>,
26 pub blob_gas_used: Option<U256>,
27 pub excess_blob_gas: Option<U256>,
28 pub parent_beacon_block_root: Option<H256>,
29 pub requests_hash: Option<H256>,
30 pub hash: H256,
31}
32
33#[derive(Debug, PartialEq, Eq, Deserialize)]
34#[serde(rename_all = "camelCase")]
35pub struct Block {
36 pub block_header: BlockHeader,
37 pub transactions: Vec<Transaction>,
38 pub uncle_headers: Vec<BlockHeader>,
39 pub withdrawals: Option<Vec<Withdrawal>>,
40 pub rlp: Bytes,
41 pub blocknumber: Option<String>, }
43
44#[derive(Debug, PartialEq, Eq, Deserialize)]
45#[serde(rename_all = "camelCase")]
46pub struct Withdrawal {
47 index: U256,
48 validator_index: U256,
49 address: Address,
50 amount: U256,
51}
52
53#[derive(Debug, PartialEq, Eq, Deserialize)]
54#[serde(rename_all = "camelCase")]
55pub struct InvalidBlock {
56 pub rlp: Bytes,
57 pub expect_exception: String,
58 pub rlp_decoded: Option<Block>,
59}
60
61#[cfg(test)]
62mod tests {
63 use super::*;
64
65 #[test]
66 fn recover_withdrawal() {
67 let json_str = r#"{
68 "index": "0x00",
69 "validatorIndex": "0x00",
70 "address": "0x0000000000000000000000000000000000000002",
71 "amount": "0x01"
72 }"#;
73
74 let data: Withdrawal = serde_json::from_str(json_str).unwrap();
75 assert_eq!(data.amount, U256::from(1));
76 }
77
78 #[test]
79 fn recover_block_header() {
80 let json_str = r#"{
81 "parentHash": "0x75f987ffc84f12861a575922ee8620845a804f7c79f2dfeef0ca352d0fe1c46a",
82 "uncleHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
83 "coinbase": "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
84 "stateRoot": "0xc2a77e1e008094eb69970a5ca782d3db246a13f27d8eb9f9dbda741f594c4f32",
85 "transactionsTrie": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
86 "receiptTrie": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
87 "bloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
88 "difficulty": "0x00",
89 "number": "0x01",
90 "gasLimit": "0x016345785d8a0000",
91 "gasUsed": "0x00",
92 "timestamp": "0x0c",
93 "extraData": "0x",
94 "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
95 "nonce": "0x0000000000000000",
96 "baseFeePerGas": "0x07",
97 "withdrawalsRoot": "0xe69c7b5847f8c1bb8052999046c12ba942ad4d05e5627b0d339ec7772574e544",
98 "blobGasUsed": "0x00",
99 "excessBlobGas": "0x00",
100 "parentBeaconBlockRoot": "0x0000000000000000000000000000000000000000000000000000000000000000",
101 "hash": "0xe6f643b08c3757450d93d5bfa27168a2af5a861ac3bd2793ca57650f9d77a50c"
102 }"#;
103
104 let data: BlockHeader = serde_json::from_str(json_str).unwrap();
105 assert_eq!(data.number, U256::from(1));
106 }
107
108 #[test]
109 fn recover_block_basic() {
110 let json_str = r#"{
111 "blockHeader": {
112 "parentHash": "0x75f987ffc84f12861a575922ee8620845a804f7c79f2dfeef0ca352d0fe1c46a",
113 "uncleHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
114 "coinbase": "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
115 "stateRoot": "0xc2a77e1e008094eb69970a5ca782d3db246a13f27d8eb9f9dbda741f594c4f32",
116 "transactionsTrie": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
117 "receiptTrie": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
118 "bloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
119 "difficulty": "0x00",
120 "number": "0x01",
121 "gasLimit": "0x016345785d8a0000",
122 "gasUsed": "0x00",
123 "timestamp": "0x0c",
124 "extraData": "0x",
125 "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
126 "nonce": "0x0000000000000000",
127 "baseFeePerGas": "0x07",
128 "withdrawalsRoot": "0xe69c7b5847f8c1bb8052999046c12ba942ad4d05e5627b0d339ec7772574e544",
129 "blobGasUsed": "0x00",
130 "excessBlobGas": "0x00",
131 "parentBeaconBlockRoot": "0x0000000000000000000000000000000000000000000000000000000000000000",
132 "hash": "0xe6f643b08c3757450d93d5bfa27168a2af5a861ac3bd2793ca57650f9d77a50c"
133 },
134 "transactions": [
135 {
136 "type": "0x00",
137 "chainId": "0x01",
138 "nonce": "0x00",
139 "gasPrice": "0x0a",
140 "gasLimit": "0x07a120",
141 "to": "0x0000000000000000000000000000000000001000",
142 "value": "0x00",
143 "data": "0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002003fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2efffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f",
144 "v": "0x26",
145 "r": "0xb71d8dd5ac327ec1b822930c066a9d0931a26f8529cbd0dca51a6a1f3fc508c9",
146 "s": "0x63698823fb964779539d8fd4d016e7326cbd9dab987233458980d422776167b5",
147 "sender": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b"
148 }
149 ],
150 "uncleHeaders": [],
151 "withdrawals": [
152 {
153 "index": "0x00",
154 "validatorIndex": "0x00",
155 "address": "0x0000000000000000000000000000000000000002",
156 "amount": "0x01"
157 }
158 ],
159 "rlp": "0xf90259f9023aa075f987ffc84f12861a575922ee8620845a804f7c79f2dfeef0ca352d0fe1c46aa01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347942adc25665018aa1fe0e6bc666dac8fc2697ff9baa0c2a77e1e008094eb69970a5ca782d3db246a13f27d8eb9f9dbda741f594c4f32a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800188016345785d8a0000800c80a0000000000000000000000000000000000000000000000000000000000000000088000000000000000007a0e69c7b5847f8c1bb8052999046c12ba942ad4d05e5627b0d339ec7772574e5448080a00000000000000000000000000000000000000000000000000000000000000000c0c0d9d8808094000000000000000000000000000000000000000201",
160 "blocknumber": "1"
161 }"#;
162
163 let data: Block = serde_json::from_str(json_str).unwrap();
164 assert_eq!(data.blocknumber.is_some(), true);
165 assert_eq!(data.blocknumber.unwrap().parse(), Ok(1));
166 }
167
168 #[test]
169 fn recover_invalid_block() {
170 let json_str = r#"{
171 "rlp": "0xf9035ef90242a0d9afd2e454bd4dbaba688c0f8a0463689e50da4fe4bd675a9fb59434bedc2d55a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347942adc25665018aa1fe0e6bc666dac8fc2697ff9baa00db85f0bc22f84493da39f9c08113aea13559eb14f9cac67e5db5007d01c5df4a01cbe160c60be9946c1477734baf89a03a0d6d75b8d64b3bed9d3954a1976c656a0eaa8c40899a61ae59615cf9985f5e2194f8fd2b57d273be63bde6733e89b12abb9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800188016345785d8a00008252080c80a0000000000000000000000000000000000000000000000000000000000000000088000000000000000007a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b42183040000830e0000a00000000000000000000000000000000000000000000000000000000000000000f90114b88803f88501808007825208948a0a19589531694250d570040a0c4b74576919b80180c001e1a0010000000000000000000000000000000000000000000000000000000000000001a06c120e55aeb31122c5caad29e69d28ec90abb71e089e0cdf4aebbf51bbc46a89a067983552dabf029ffb7ac58209a620d4a98eeeaf3df55bc9eb8e7684051ac70ab88803f88501018007825208948a0a19589531694250d570040a0c4b74576919b80180c001e1a0010000000000000000000000000000000000000000000000000000000000000080a04fc1b52cdbb48421d17e7ccfc33496c95bae6ecfd8f29816699f151d92e4ed9ca074271236ba3a66db6ea60f4482287b8f52de28a6a525626c55e741c54296309bc0c0",
172 "expectException": "TransactionException.INSUFFICIENT_ACCOUNT_FUNDS",
173 "rlp_decoded": {
174 "blockHeader": {
175 "parentHash": "0xd9afd2e454bd4dbaba688c0f8a0463689e50da4fe4bd675a9fb59434bedc2d55",
176 "uncleHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
177 "coinbase": "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
178 "stateRoot": "0x0db85f0bc22f84493da39f9c08113aea13559eb14f9cac67e5db5007d01c5df4",
179 "transactionsTrie": "0x1cbe160c60be9946c1477734baf89a03a0d6d75b8d64b3bed9d3954a1976c656",
180 "receiptTrie": "0xeaa8c40899a61ae59615cf9985f5e2194f8fd2b57d273be63bde6733e89b12ab",
181 "bloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
182 "difficulty": "0x00",
183 "number": "0x01",
184 "gasLimit": "0x016345785d8a0000",
185 "gasUsed": "0x5208",
186 "timestamp": "0x0c",
187 "extraData": "0x",
188 "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
189 "nonce": "0x0000000000000000",
190 "baseFeePerGas": "0x07",
191 "withdrawalsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
192 "blobGasUsed": "0x040000",
193 "excessBlobGas": "0x0e0000",
194 "parentBeaconBlockRoot": "0x0000000000000000000000000000000000000000000000000000000000000000",
195 "hash": "0x4ff059d45cd9c3aaee26292786a7ea8bf6d00ec330bd50e00d2a6b1c9b6ed06e"
196 },
197 "transactions": [
198 {
199 "type": "0x03",
200 "chainId": "0x01",
201 "nonce": "0x00",
202 "maxPriorityFeePerGas": "0x00",
203 "maxFeePerGas": "0x07",
204 "gasLimit": "0x5208",
205 "to": "0x8a0a19589531694250d570040a0c4b74576919b8",
206 "value": "0x01",
207 "data": "0x",
208 "accessList": [],
209 "maxFeePerBlobGas": "0x01",
210 "blobVersionedHashes": [
211 "0x0100000000000000000000000000000000000000000000000000000000000000"
212 ],
213 "v": "0x01",
214 "r": "0x6c120e55aeb31122c5caad29e69d28ec90abb71e089e0cdf4aebbf51bbc46a89",
215 "s": "0x67983552dabf029ffb7ac58209a620d4a98eeeaf3df55bc9eb8e7684051ac70a",
216 "sender": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b"
217 },
218 {
219 "type": "0x03",
220 "chainId": "0x01",
221 "nonce": "0x01",
222 "maxPriorityFeePerGas": "0x00",
223 "maxFeePerGas": "0x07",
224 "gasLimit": "0x5208",
225 "to": "0x8a0a19589531694250d570040a0c4b74576919b8",
226 "value": "0x01",
227 "data": "0x",
228 "accessList": [],
229 "maxFeePerBlobGas": "0x01",
230 "blobVersionedHashes": [
231 "0x0100000000000000000000000000000000000000000000000000000000000000"
232 ],
233 "v": "0x00",
234 "r": "0x4fc1b52cdbb48421d17e7ccfc33496c95bae6ecfd8f29816699f151d92e4ed9c",
235 "s": "0x74271236ba3a66db6ea60f4482287b8f52de28a6a525626c55e741c54296309b",
236 "sender": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b"
237 }
238 ],
239 "uncleHeaders": [],
240 "withdrawals": [],
241 "blocknumber": "1"
242 }
243 }"#;
244
245 let data: InvalidBlock = serde_json::from_str(json_str).unwrap();
246 assert_eq!(
247 data.expect_exception,
248 "TransactionException.INSUFFICIENT_ACCOUNT_FUNDS"
249 );
250 }
251}