1use crate::{DBProvider, DatabaseProviderRW, ExecutionOutcome};
3use alloy_consensus::{TxLegacy, EMPTY_OMMER_ROOT_HASH};
4use alloy_primitives::{
5 b256, hex_literal::hex, map::HashMap, Address, BlockNumber, Bytes, Log, TxKind, B256, U256,
6};
7
8use alloy_consensus::Header;
9use alloy_eips::eip4895::{Withdrawal, Withdrawals};
10use alloy_primitives::Signature;
11use reth_db_api::{database::Database, models::StoredBlockBodyIndices, tables};
12use reth_ethereum_primitives::{BlockBody, Receipt, Transaction, TransactionSigned, TxType};
13use reth_node_types::NodeTypes;
14use reth_primitives_traits::{Account, RecoveredBlock, SealedBlock, SealedHeader};
15use reth_trie::root::{state_root_unhashed, storage_root_unhashed};
16use revm_database::BundleState;
17use revm_state::AccountInfo;
18use std::{str::FromStr, sync::LazyLock};
19
20pub fn assert_genesis_block<DB: Database, N: NodeTypes>(
22 provider: &DatabaseProviderRW<DB, N>,
23 g: SealedBlock<reth_ethereum_primitives::Block>,
24) {
25 let n = g.number;
26 let h = B256::ZERO;
27 let tx = provider;
28
29 assert_eq!(tx.table::<tables::Headers>().unwrap(), vec![(g.number, g.header().clone())]);
31
32 assert_eq!(tx.table::<tables::HeaderNumbers>().unwrap(), vec![(h, n)]);
33 assert_eq!(tx.table::<tables::CanonicalHeaders>().unwrap(), vec![(n, h)]);
34 assert_eq!(
35 tx.table::<tables::BlockBodyIndices>().unwrap(),
36 vec![(0, StoredBlockBodyIndices::default())]
37 );
38 assert_eq!(tx.table::<tables::BlockOmmers>().unwrap(), vec![]);
39 assert_eq!(tx.table::<tables::BlockWithdrawals>().unwrap(), vec![]);
40 assert_eq!(tx.table::<tables::Transactions>().unwrap(), vec![]);
41 assert_eq!(tx.table::<tables::TransactionBlocks>().unwrap(), vec![]);
42 assert_eq!(tx.table::<tables::TransactionHashNumbers>().unwrap(), vec![]);
43 assert_eq!(tx.table::<tables::Receipts>().unwrap(), vec![]);
44 assert_eq!(tx.table::<tables::PlainAccountState>().unwrap(), vec![]);
45 assert_eq!(tx.table::<tables::PlainStorageState>().unwrap(), vec![]);
46 assert_eq!(tx.table::<tables::AccountsHistory>().unwrap(), vec![]);
47 assert_eq!(tx.table::<tables::StoragesHistory>().unwrap(), vec![]);
48 assert_eq!(tx.table::<tables::AccountChangeSets>().unwrap(), vec![]);
51 assert_eq!(tx.table::<tables::StorageChangeSets>().unwrap(), vec![]);
52 assert_eq!(tx.table::<tables::HashedAccounts>().unwrap(), vec![]);
53 assert_eq!(tx.table::<tables::HashedStorages>().unwrap(), vec![]);
54 assert_eq!(tx.table::<tables::AccountsTrie>().unwrap(), vec![]);
55 assert_eq!(tx.table::<tables::StoragesTrie>().unwrap(), vec![]);
56 assert_eq!(tx.table::<tables::TransactionSenders>().unwrap(), vec![]);
57 }
59
60pub(crate) static TEST_BLOCK: LazyLock<SealedBlock<reth_ethereum_primitives::Block>> =
61 LazyLock::new(|| {
62 SealedBlock::from_sealed_parts(
63 SealedHeader::new(
64 Header {
65 parent_hash: hex!(
66 "c86e8cc0310ae7c531c758678ddbfd16fc51c8cef8cec650b032de9869e8b94f"
67 )
68 .into(),
69 ommers_hash: EMPTY_OMMER_ROOT_HASH,
70 beneficiary: hex!("2adc25665018aa1fe0e6bc666dac8fc2697ff9ba").into(),
71 state_root: hex!(
72 "50554882fbbda2c2fd93fdc466db9946ea262a67f7a76cc169e714f105ab583d"
73 )
74 .into(),
75 transactions_root: hex!(
76 "0967f09ef1dfed20c0eacfaa94d5cd4002eda3242ac47eae68972d07b106d192"
77 )
78 .into(),
79 receipts_root: hex!(
80 "e3c8b47fbfc94667ef4cceb17e5cc21e3b1eebd442cebb27f07562b33836290d"
81 )
82 .into(),
83 difficulty: U256::from(131_072),
84 number: 0,
85 gas_limit: 1_000_000,
86 gas_used: 14_352,
87 timestamp: 1_000,
88 ..Default::default()
89 },
90 hex!("cf7b274520720b50e6a4c3e5c4d553101f44945396827705518ce17cb7219a42").into(),
91 ),
92 BlockBody {
93 transactions: vec![TransactionSigned::new_unhashed(
94 Transaction::Legacy(TxLegacy {
95 gas_price: 10,
96 gas_limit: 400_000,
97 to: TxKind::Call(hex!("095e7baea6a6c7c4c2dfeb977efac326af552d87").into()),
98 ..Default::default()
99 }),
100 Signature::new(
101 U256::from_str(
102 "51983300959770368863831494747186777928121405155922056726144551509338672451120",
103 )
104 .unwrap(),
105 U256::from_str(
106 "29056683545955299640297374067888344259176096769870751649153779895496107008675",
107 )
108 .unwrap(),
109 false,
110 )
111 )],
112 ..Default::default()
113 },
114 )
115 });
116
117#[derive(Debug)]
120pub struct BlockchainTestData {
121 pub genesis: SealedBlock<reth_ethereum_primitives::Block>,
123 pub blocks: Vec<(RecoveredBlock<reth_ethereum_primitives::Block>, ExecutionOutcome)>,
125}
126
127impl BlockchainTestData {
128 pub fn default_from_number(first: BlockNumber) -> Self {
130 let one = block1(first);
131 let mut extended_execution_outcome = one.1.clone();
132 let two = block2(first + 1, one.0.hash(), &extended_execution_outcome);
133 extended_execution_outcome.extend(two.1.clone());
134 let three = block3(first + 2, two.0.hash(), &extended_execution_outcome);
135 extended_execution_outcome.extend(three.1.clone());
136 let four = block4(first + 3, three.0.hash(), &extended_execution_outcome);
137 extended_execution_outcome.extend(four.1.clone());
138 let five = block5(first + 4, four.0.hash(), &extended_execution_outcome);
139 Self { genesis: genesis(), blocks: vec![one, two, three, four, five] }
140 }
141}
142
143impl Default for BlockchainTestData {
144 fn default() -> Self {
145 let one = block1(1);
146 let mut extended_execution_outcome = one.1.clone();
147 let two = block2(2, one.0.hash(), &extended_execution_outcome);
148 extended_execution_outcome.extend(two.1.clone());
149 let three = block3(3, two.0.hash(), &extended_execution_outcome);
150 extended_execution_outcome.extend(three.1.clone());
151 let four = block4(4, three.0.hash(), &extended_execution_outcome);
152 extended_execution_outcome.extend(four.1.clone());
153 let five = block5(5, four.0.hash(), &extended_execution_outcome);
154 Self { genesis: genesis(), blocks: vec![one, two, three, four, five] }
155 }
156}
157
158pub fn genesis() -> SealedBlock<reth_ethereum_primitives::Block> {
160 SealedBlock::from_sealed_parts(
161 SealedHeader::new(
162 Header { number: 0, difficulty: U256::from(1), ..Default::default() },
163 B256::ZERO,
164 ),
165 Default::default(),
166 )
167}
168
169fn bundle_state_root(execution_outcome: &ExecutionOutcome) -> B256 {
170 state_root_unhashed(execution_outcome.bundle_accounts_iter().filter_map(
171 |(address, account)| {
172 account.info.as_ref().map(|info| {
173 (
174 address,
175 Account::from(info).into_trie_account(storage_root_unhashed(
176 account
177 .storage
178 .iter()
179 .filter(|(_, value)| !value.present_value.is_zero())
180 .map(|(slot, value)| ((*slot).into(), value.present_value)),
181 )),
182 )
183 })
184 },
185 ))
186}
187
188fn block1(
190 number: BlockNumber,
191) -> (RecoveredBlock<reth_ethereum_primitives::Block>, ExecutionOutcome) {
192 let account1: Address = [0x60; 20].into();
194 let account2: Address = [0x61; 20].into();
195 let slot = U256::from(5);
196 let info = AccountInfo { nonce: 1, balance: U256::from(10), ..Default::default() };
197
198 let execution_outcome = ExecutionOutcome::new(
199 BundleState::builder(number..=number)
200 .state_present_account_info(account1, info.clone())
201 .revert_account_info(number, account1, Some(None))
202 .state_present_account_info(account2, info)
203 .revert_account_info(number, account2, Some(None))
204 .state_storage(account1, HashMap::from_iter([(slot, (U256::ZERO, U256::from(10)))]))
205 .build(),
206 vec![vec![Receipt {
207 tx_type: TxType::Eip2930,
208 success: true,
209 cumulative_gas_used: 300,
210 logs: vec![Log::new_unchecked(
211 Address::new([0x60; 20]),
212 vec![B256::with_last_byte(1), B256::with_last_byte(2)],
213 Bytes::default(),
214 )],
215 }]],
216 number,
217 Vec::new(),
218 );
219
220 let state_root = bundle_state_root(&execution_outcome);
221 assert_eq!(
222 state_root,
223 b256!("0x5d035ccb3e75a9057452ff060b773b213ec1fc353426174068edfc3971a0b6bd")
224 );
225
226 let (mut header, mut body) = TEST_BLOCK.clone().split_header_body();
227 body.withdrawals = Some(Withdrawals::new(vec![Withdrawal::default()]));
228 header.number = number;
229 header.state_root = state_root;
230 header.parent_hash = B256::ZERO;
231 let block = SealedBlock::seal_parts(header, body);
232
233 (RecoveredBlock::new_sealed(block, vec![Address::new([0x30; 20])]), execution_outcome)
234}
235
236fn block2(
238 number: BlockNumber,
239 parent_hash: B256,
240 prev_execution_outcome: &ExecutionOutcome,
241) -> (RecoveredBlock<reth_ethereum_primitives::Block>, ExecutionOutcome) {
242 let account: Address = [0x60; 20].into();
244 let slot = U256::from(5);
245
246 let execution_outcome = ExecutionOutcome::new(
247 BundleState::builder(number..=number)
248 .state_present_account_info(
249 account,
250 AccountInfo { nonce: 3, balance: U256::from(20), ..Default::default() },
251 )
252 .state_storage(account, HashMap::from_iter([(slot, (U256::ZERO, U256::from(15)))]))
253 .revert_account_info(
254 number,
255 account,
256 Some(Some(AccountInfo { nonce: 1, balance: U256::from(10), ..Default::default() })),
257 )
258 .revert_storage(number, account, Vec::from([(slot, U256::from(10))]))
259 .build(),
260 vec![vec![Receipt {
261 tx_type: TxType::Eip1559,
262 success: false,
263 cumulative_gas_used: 400,
264 logs: vec![Log::new_unchecked(
265 Address::new([0x61; 20]),
266 vec![B256::with_last_byte(3), B256::with_last_byte(4)],
267 Bytes::default(),
268 )],
269 }]],
270 number,
271 Vec::new(),
272 );
273
274 let mut extended = prev_execution_outcome.clone();
275 extended.extend(execution_outcome.clone());
276 let state_root = bundle_state_root(&extended);
277 assert_eq!(
278 state_root,
279 b256!("0x90101a13dd059fa5cca99ed93d1dc23657f63626c5b8f993a2ccbdf7446b64f8")
280 );
281
282 let (mut header, mut body) = TEST_BLOCK.clone().split_header_body();
283
284 body.withdrawals = Some(Withdrawals::new(vec![Withdrawal::default()]));
285 header.number = number;
286 header.state_root = state_root;
287 header.parent_hash = parent_hash;
289 let block = SealedBlock::seal_parts(header, body);
290
291 (RecoveredBlock::new_sealed(block, vec![Address::new([0x31; 20])]), execution_outcome)
292}
293
294fn block3(
296 number: BlockNumber,
297 parent_hash: B256,
298 prev_execution_outcome: &ExecutionOutcome,
299) -> (RecoveredBlock<reth_ethereum_primitives::Block>, ExecutionOutcome) {
300 let address_range = 1..=20;
301 let slot_range = 1..=100;
302
303 let mut bundle_state_builder = BundleState::builder(number..=number);
304 for idx in address_range {
305 let address = Address::with_last_byte(idx);
306 bundle_state_builder = bundle_state_builder
307 .state_present_account_info(
308 address,
309 AccountInfo { nonce: 1, balance: U256::from(idx), ..Default::default() },
310 )
311 .state_storage(
312 address,
313 slot_range
314 .clone()
315 .map(|slot| (U256::from(slot), (U256::ZERO, U256::from(slot))))
316 .collect(),
317 )
318 .revert_account_info(number, address, Some(None))
319 .revert_storage(number, address, Vec::new());
320 }
321 let execution_outcome = ExecutionOutcome::new(
322 bundle_state_builder.build(),
323 vec![vec![Receipt {
324 tx_type: TxType::Eip1559,
325 success: true,
326 cumulative_gas_used: 400,
327 logs: vec![Log::new_unchecked(
328 Address::new([0x61; 20]),
329 vec![B256::with_last_byte(3), B256::with_last_byte(4)],
330 Bytes::default(),
331 )],
332 }]],
333 number,
334 Vec::new(),
335 );
336
337 let mut extended = prev_execution_outcome.clone();
338 extended.extend(execution_outcome.clone());
339 let state_root = bundle_state_root(&extended);
340
341 let (mut header, mut body) = TEST_BLOCK.clone().split_header_body();
342 body.withdrawals = Some(Withdrawals::new(vec![Withdrawal::default()]));
343 header.number = number;
344 header.state_root = state_root;
345 header.parent_hash = parent_hash;
347 let block = SealedBlock::seal_parts(header, body);
348
349 (RecoveredBlock::new_sealed(block, vec![Address::new([0x31; 20])]), execution_outcome)
350}
351
352fn block4(
354 number: BlockNumber,
355 parent_hash: B256,
356 prev_execution_outcome: &ExecutionOutcome,
357) -> (RecoveredBlock<reth_ethereum_primitives::Block>, ExecutionOutcome) {
358 let address_range = 1..=20;
359 let slot_range = 1..=100;
360
361 let mut bundle_state_builder = BundleState::builder(number..=number);
362 for idx in address_range {
363 let address = Address::with_last_byte(idx);
364 bundle_state_builder = if idx.is_multiple_of(2) {
366 bundle_state_builder
367 .state_present_account_info(
368 address,
369 AccountInfo { nonce: 1, balance: U256::from(idx * 2), ..Default::default() },
370 )
371 .state_storage(
372 address,
373 slot_range
374 .clone()
375 .map(|slot| (U256::from(slot), (U256::from(slot), U256::from(slot * 2))))
376 .collect(),
377 )
378 } else {
379 bundle_state_builder.state_address(address).state_storage(
380 address,
381 slot_range
382 .clone()
383 .map(|slot| (U256::from(slot), (U256::from(slot), U256::ZERO)))
384 .collect(),
385 )
386 };
387 bundle_state_builder = bundle_state_builder
389 .revert_account_info(
390 number,
391 address,
392 Some(Some(AccountInfo {
393 nonce: 1,
394 balance: U256::from(idx),
395 ..Default::default()
396 })),
397 )
398 .revert_storage(
399 number,
400 address,
401 slot_range.clone().map(|slot| (U256::from(slot), U256::from(slot))).collect(),
402 );
403 }
404 let execution_outcome = ExecutionOutcome::new(
405 bundle_state_builder.build(),
406 vec![vec![Receipt {
407 tx_type: TxType::Eip1559,
408 success: true,
409 cumulative_gas_used: 400,
410 logs: vec![Log::new_unchecked(
411 Address::new([0x61; 20]),
412 vec![B256::with_last_byte(3), B256::with_last_byte(4)],
413 Bytes::default(),
414 )],
415 }]],
416 number,
417 Vec::new(),
418 );
419
420 let mut extended = prev_execution_outcome.clone();
421 extended.extend(execution_outcome.clone());
422 let state_root = bundle_state_root(&extended);
423
424 let (mut header, mut body) = TEST_BLOCK.clone().split_header_body();
425 body.withdrawals = Some(Withdrawals::new(vec![Withdrawal::default()]));
426 header.number = number;
427 header.state_root = state_root;
428 header.parent_hash = parent_hash;
430 let block = SealedBlock::seal_parts(header, body);
431
432 (RecoveredBlock::new_sealed(block, vec![Address::new([0x31; 20])]), execution_outcome)
433}
434
435fn block5(
437 number: BlockNumber,
438 parent_hash: B256,
439 prev_execution_outcome: &ExecutionOutcome,
440) -> (RecoveredBlock<reth_ethereum_primitives::Block>, ExecutionOutcome) {
441 let address_range = 1..=20;
442 let slot_range = 1..=100;
443
444 let mut bundle_state_builder = BundleState::builder(number..=number);
445 for idx in address_range {
446 let address = Address::with_last_byte(idx);
447 bundle_state_builder = bundle_state_builder
449 .state_present_account_info(
450 address,
451 AccountInfo { nonce: 1, balance: U256::from(idx * 2), ..Default::default() },
452 )
453 .state_storage(
454 address,
455 slot_range
456 .clone()
457 .take(50)
458 .map(|slot| (U256::from(slot), (U256::from(slot), U256::from(slot * 4))))
459 .collect(),
460 );
461 bundle_state_builder = if idx.is_multiple_of(2) {
462 bundle_state_builder
463 .revert_account_info(
464 number,
465 address,
466 Some(Some(AccountInfo {
467 nonce: 1,
468 balance: U256::from(idx * 2),
469 ..Default::default()
470 })),
471 )
472 .revert_storage(
473 number,
474 address,
475 slot_range
476 .clone()
477 .map(|slot| (U256::from(slot), U256::from(slot * 2)))
478 .collect(),
479 )
480 } else {
481 bundle_state_builder.revert_address(number, address)
482 };
483 }
484 let execution_outcome = ExecutionOutcome::new(
485 bundle_state_builder.build(),
486 vec![vec![Receipt {
487 tx_type: TxType::Eip1559,
488 success: true,
489 cumulative_gas_used: 400,
490 logs: vec![Log::new_unchecked(
491 Address::new([0x61; 20]),
492 vec![B256::with_last_byte(3), B256::with_last_byte(4)],
493 Bytes::default(),
494 )],
495 }]],
496 number,
497 Vec::new(),
498 );
499
500 let mut extended = prev_execution_outcome.clone();
501 extended.extend(execution_outcome.clone());
502 let state_root = bundle_state_root(&extended);
503
504 let (mut header, mut body) = TEST_BLOCK.clone().split_header_body();
505 body.withdrawals = Some(Withdrawals::new(vec![Withdrawal::default()]));
506 header.number = number;
507 header.state_root = state_root;
508 header.parent_hash = parent_hash;
510 let block = SealedBlock::seal_parts(header, body);
511
512 (RecoveredBlock::new_sealed(block, vec![Address::new([0x31; 20])]), execution_outcome)
513}