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