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