1use crate::stages::MERKLE_STAGE_DEFAULT_INCREMENTAL_THRESHOLD;
2use alloy_consensus::BlockHeader;
3use alloy_primitives::BlockNumber;
4use num_traits::Zero;
5use reth_config::config::ExecutionConfig;
6use reth_consensus::{ConsensusError, FullConsensus};
7use reth_db::{static_file::HeaderMask, tables};
8use reth_evm::{execute::Executor, metrics::ExecutorMetrics, ConfigureEvm};
9use reth_execution_types::Chain;
10use reth_exex::{ExExManagerHandle, ExExNotification, ExExNotificationSource};
11use reth_primitives_traits::{format_gas_throughput, BlockBody, NodePrimitives};
12use reth_provider::{
13 providers::{StaticFileProvider, StaticFileWriter},
14 BlockHashReader, BlockReader, DBProvider, ExecutionOutcome, HeaderProvider,
15 LatestStateProviderRef, OriginalValuesKnown, ProviderError, StateWriter,
16 StaticFileProviderFactory, StatsReader, TransactionVariant,
17};
18use reth_revm::database::StateProviderDatabase;
19use reth_stages_api::{
20 BlockErrorKind, CheckpointBlockRange, EntitiesCheckpoint, ExecInput, ExecOutput,
21 ExecutionCheckpoint, ExecutionStageThresholds, Stage, StageCheckpoint, StageError, StageId,
22 UnwindInput, UnwindOutput,
23};
24use reth_static_file_types::StaticFileSegment;
25use std::{
26 cmp::Ordering,
27 ops::RangeInclusive,
28 sync::Arc,
29 task::{ready, Context, Poll},
30 time::{Duration, Instant},
31};
32use tracing::*;
33
34use super::missing_static_data_error;
35
36#[derive(Debug)]
65pub struct ExecutionStage<E>
66where
67 E: ConfigureEvm,
68{
69 evm_config: E,
71 consensus: Arc<dyn FullConsensus<E::Primitives, Error = ConsensusError>>,
73 thresholds: ExecutionStageThresholds,
75 external_clean_threshold: u64,
80 post_execute_commit_input: Option<Chain<E::Primitives>>,
84 post_unwind_commit_input: Option<Chain<E::Primitives>>,
88 exex_manager_handle: ExExManagerHandle<E::Primitives>,
90 metrics: ExecutorMetrics,
92}
93
94impl<E> ExecutionStage<E>
95where
96 E: ConfigureEvm,
97{
98 pub fn new(
100 evm_config: E,
101 consensus: Arc<dyn FullConsensus<E::Primitives, Error = ConsensusError>>,
102 thresholds: ExecutionStageThresholds,
103 external_clean_threshold: u64,
104 exex_manager_handle: ExExManagerHandle<E::Primitives>,
105 ) -> Self {
106 Self {
107 external_clean_threshold,
108 evm_config,
109 consensus,
110 thresholds,
111 post_execute_commit_input: None,
112 post_unwind_commit_input: None,
113 exex_manager_handle,
114 metrics: ExecutorMetrics::default(),
115 }
116 }
117
118 pub fn new_with_executor(
122 evm_config: E,
123 consensus: Arc<dyn FullConsensus<E::Primitives, Error = ConsensusError>>,
124 ) -> Self {
125 Self::new(
126 evm_config,
127 consensus,
128 ExecutionStageThresholds::default(),
129 MERKLE_STAGE_DEFAULT_INCREMENTAL_THRESHOLD,
130 ExExManagerHandle::empty(),
131 )
132 }
133
134 pub fn from_config(
136 evm_config: E,
137 consensus: Arc<dyn FullConsensus<E::Primitives, Error = ConsensusError>>,
138 config: ExecutionConfig,
139 external_clean_threshold: u64,
140 ) -> Self {
141 Self::new(
142 evm_config,
143 consensus,
144 config.into(),
145 external_clean_threshold,
146 ExExManagerHandle::empty(),
147 )
148 }
149
150 fn can_prune_changesets(
162 &self,
163 provider: impl StatsReader,
164 start_block: u64,
165 max_block: u64,
166 ) -> Result<bool, StageError> {
167 Ok(max_block - start_block > self.external_clean_threshold ||
170 provider.count_entries::<tables::AccountsTrie>()?.is_zero())
171 }
172
173 fn ensure_consistency<Provider>(
182 &self,
183 provider: &Provider,
184 checkpoint: u64,
185 unwind_to: Option<u64>,
186 ) -> Result<(), StageError>
187 where
188 Provider: StaticFileProviderFactory + DBProvider + BlockReader + HeaderProvider,
189 {
190 if provider.prune_modes_ref().has_receipts_pruning() {
193 return Ok(())
194 }
195
196 let next_receipt_num =
198 provider.block_body_indices(checkpoint)?.map(|b| b.next_tx_num()).unwrap_or(0);
199
200 let static_file_provider = provider.static_file_provider();
201
202 let next_static_file_receipt_num = static_file_provider
204 .get_highest_static_file_tx(StaticFileSegment::Receipts)
205 .map(|num| num + 1)
206 .unwrap_or(0);
207
208 match next_static_file_receipt_num.cmp(&next_receipt_num) {
211 Ordering::Greater | Ordering::Equal => {
214 let mut static_file_producer =
215 static_file_provider.latest_writer(StaticFileSegment::Receipts)?;
216 static_file_producer
217 .prune_receipts(next_static_file_receipt_num - next_receipt_num, checkpoint)?;
218 static_file_producer.commit()?;
221 }
222 Ordering::Less => {
223 if let Some(unwind_to) = unwind_to {
226 let next_receipt_num_after_unwind = provider
227 .block_body_indices(unwind_to)?
228 .map(|b| b.next_tx_num())
229 .ok_or(ProviderError::BlockBodyIndicesNotFound(unwind_to))?;
230
231 if next_receipt_num_after_unwind > next_static_file_receipt_num {
232 } else {
234 return Ok(())
235 }
236 }
237
238 return Err(missing_static_data_error(
239 next_static_file_receipt_num.saturating_sub(1),
240 &static_file_provider,
241 provider,
242 StaticFileSegment::Receipts,
243 )?)
244 }
245 }
246
247 Ok(())
248 }
249}
250
251impl<E, Provider> Stage<Provider> for ExecutionStage<E>
252where
253 E: ConfigureEvm,
254 Provider: DBProvider
255 + BlockReader<
256 Block = <E::Primitives as NodePrimitives>::Block,
257 Header = <E::Primitives as NodePrimitives>::BlockHeader,
258 > + StaticFileProviderFactory<
259 Primitives: NodePrimitives<BlockHeader: reth_db_api::table::Value>,
260 > + StatsReader
261 + BlockHashReader
262 + StateWriter<Receipt = <E::Primitives as NodePrimitives>::Receipt>,
263{
264 fn id(&self) -> StageId {
266 StageId::Execution
267 }
268
269 fn poll_execute_ready(
270 &mut self,
271 cx: &mut Context<'_>,
272 _: ExecInput,
273 ) -> Poll<Result<(), StageError>> {
274 ready!(self.exex_manager_handle.poll_ready(cx));
275
276 Poll::Ready(Ok(()))
277 }
278
279 fn execute(&mut self, provider: &Provider, input: ExecInput) -> Result<ExecOutput, StageError> {
281 if input.target_reached() {
282 return Ok(ExecOutput::done(input.checkpoint()))
283 }
284
285 let start_block = input.next_block();
286 let max_block = input.target();
287 let static_file_provider = provider.static_file_provider();
288
289 self.ensure_consistency(provider, input.checkpoint().block_number, None)?;
290
291 let db = StateProviderDatabase(LatestStateProviderRef::new(provider));
292 let mut executor = self.evm_config.batch_executor(db);
293
294 let mut stage_progress = start_block;
296 let mut stage_checkpoint = execution_checkpoint(
297 &static_file_provider,
298 start_block,
299 max_block,
300 input.checkpoint(),
301 )?;
302
303 let mut fetch_block_duration = Duration::default();
304 let mut execution_duration = Duration::default();
305
306 let mut last_block = start_block;
307 let mut last_execution_duration = Duration::default();
308 let mut last_cumulative_gas = 0;
309 let mut last_log_instant = Instant::now();
310 let log_duration = Duration::from_secs(10);
311
312 debug!(target: "sync::stages::execution", start = start_block, end = max_block, "Executing range");
313
314 let mut cumulative_gas = 0;
316 let batch_start = Instant::now();
317
318 let mut blocks = Vec::new();
319 let mut results = Vec::new();
320 for block_number in start_block..=max_block {
321 let fetch_block_start = Instant::now();
323
324 let block = provider
326 .recovered_block(block_number.into(), TransactionVariant::NoHash)?
327 .ok_or_else(|| ProviderError::HeaderNotFound(block_number.into()))?;
328
329 fetch_block_duration += fetch_block_start.elapsed();
330
331 cumulative_gas += block.header().gas_used();
332
333 trace!(target: "sync::stages::execution", number = block_number, txs = block.body().transactions().len(), "Executing block");
335
336 let execute_start = Instant::now();
338
339 let result = self.metrics.metered_one(&block, |input| {
340 executor.execute_one(input).map_err(|error| StageError::Block {
341 block: Box::new(block.block_with_parent()),
342 error: BlockErrorKind::Execution(error),
343 })
344 })?;
345
346 if let Err(err) = self.consensus.validate_block_post_execution(&block, &result) {
347 return Err(StageError::Block {
348 block: Box::new(block.block_with_parent()),
349 error: BlockErrorKind::Validation(err),
350 })
351 }
352 results.push(result);
353
354 execution_duration += execute_start.elapsed();
355
356 if last_log_instant.elapsed() >= log_duration {
358 info!(
359 target: "sync::stages::execution",
360 start = last_block,
361 end = block_number,
362 throughput = format_gas_throughput(cumulative_gas - last_cumulative_gas, execution_duration - last_execution_duration),
363 "Executed block range"
364 );
365
366 last_block = block_number + 1;
367 last_execution_duration = execution_duration;
368 last_cumulative_gas = cumulative_gas;
369 last_log_instant = Instant::now();
370 }
371
372 stage_progress = block_number;
373 stage_checkpoint.progress.processed += block.header().gas_used();
374
375 if self.exex_manager_handle.has_exexs() {
377 blocks.push(block);
378 }
379
380 if self.thresholds.is_end_of_batch(
382 block_number - start_block,
383 executor.size_hint() as u64,
384 cumulative_gas,
385 batch_start.elapsed(),
386 ) {
387 break
388 }
389 }
390
391 let time = Instant::now();
393 let mut state = ExecutionOutcome::from_blocks(
394 start_block,
395 executor.into_state().take_bundle(),
396 results,
397 );
398 let write_preparation_duration = time.elapsed();
399
400 debug!(
402 target: "sync::stages::execution",
403 start = start_block,
404 end = stage_progress,
405 throughput = format_gas_throughput(cumulative_gas, execution_duration),
406 "Finished executing block range"
407 );
408
409 if !blocks.is_empty() {
414 let previous_input =
415 self.post_execute_commit_input.replace(Chain::new(blocks, state.clone(), None));
416
417 if previous_input.is_some() {
418 return Err(StageError::PostExecuteCommit(
421 "Previous post execute commit input wasn't processed",
422 ))
423 }
424 }
425
426 let time = Instant::now();
427
428 if self.can_prune_changesets(provider, start_block, max_block)? {
429 let prune_modes = provider.prune_modes_ref();
430
431 for block_number in start_block..=max_block {
433 let Some(reverts) =
434 state.bundle.reverts.get_mut((block_number - start_block) as usize)
435 else {
436 break
437 };
438
439 if prune_modes
442 .account_history
443 .is_some_and(|m| m.should_prune(block_number, max_block)) &&
444 prune_modes
445 .storage_history
446 .is_some_and(|m| m.should_prune(block_number, max_block))
447 {
448 reverts.clear();
449 }
450 }
451 }
452
453 provider.write_state(&state, OriginalValuesKnown::Yes)?;
455
456 let db_write_duration = time.elapsed();
457 debug!(
458 target: "sync::stages::execution",
459 block_fetch = ?fetch_block_duration,
460 execution = ?execution_duration,
461 write_preparation = ?write_preparation_duration,
462 write = ?db_write_duration,
463 "Execution time"
464 );
465
466 let done = stage_progress == max_block;
467 Ok(ExecOutput {
468 checkpoint: StageCheckpoint::new(stage_progress)
469 .with_execution_stage_checkpoint(stage_checkpoint),
470 done,
471 })
472 }
473
474 fn post_execute_commit(&mut self) -> Result<(), StageError> {
475 let Some(chain) = self.post_execute_commit_input.take() else { return Ok(()) };
476
477 let _ = self.exex_manager_handle.send(
480 ExExNotificationSource::Pipeline,
481 ExExNotification::ChainCommitted { new: Arc::new(chain) },
482 );
483
484 Ok(())
485 }
486
487 fn unwind(
489 &mut self,
490 provider: &Provider,
491 input: UnwindInput,
492 ) -> Result<UnwindOutput, StageError> {
493 let (range, unwind_to, _) =
494 input.unwind_block_range_with_threshold(self.thresholds.max_blocks.unwrap_or(u64::MAX));
495 if range.is_empty() {
496 return Ok(UnwindOutput {
497 checkpoint: input.checkpoint.with_block_number(input.unwind_to),
498 })
499 }
500
501 self.ensure_consistency(provider, input.checkpoint.block_number, Some(unwind_to))?;
502
503 let bundle_state_with_receipts = provider.take_state_above(unwind_to)?;
507
508 if self.exex_manager_handle.has_exexs() {
510 let blocks = provider.recovered_block_range(range.clone())?;
512 let previous_input = self.post_unwind_commit_input.replace(Chain::new(
513 blocks,
514 bundle_state_with_receipts,
515 None,
516 ));
517
518 debug_assert!(
519 previous_input.is_none(),
520 "Previous post unwind commit input wasn't processed"
521 );
522 if let Some(previous_input) = previous_input {
523 tracing::debug!(target: "sync::stages::execution", ?previous_input, "Previous post unwind commit input wasn't processed");
524 }
525 }
526
527 let mut stage_checkpoint = input.checkpoint.execution_stage_checkpoint();
529 if let Some(stage_checkpoint) = stage_checkpoint.as_mut() {
530 for block_number in range {
531 stage_checkpoint.progress.processed -= provider
532 .header_by_number(block_number)?
533 .ok_or_else(|| ProviderError::HeaderNotFound(block_number.into()))?
534 .gas_used();
535 }
536 }
537 let checkpoint = if let Some(stage_checkpoint) = stage_checkpoint {
538 StageCheckpoint::new(unwind_to).with_execution_stage_checkpoint(stage_checkpoint)
539 } else {
540 StageCheckpoint::new(unwind_to)
541 };
542
543 Ok(UnwindOutput { checkpoint })
544 }
545
546 fn post_unwind_commit(&mut self) -> Result<(), StageError> {
547 let Some(chain) = self.post_unwind_commit_input.take() else { return Ok(()) };
548
549 let _ = self.exex_manager_handle.send(
552 ExExNotificationSource::Pipeline,
553 ExExNotification::ChainReverted { old: Arc::new(chain) },
554 );
555
556 Ok(())
557 }
558}
559
560fn execution_checkpoint<N>(
561 provider: &StaticFileProvider<N>,
562 start_block: BlockNumber,
563 max_block: BlockNumber,
564 checkpoint: StageCheckpoint,
565) -> Result<ExecutionCheckpoint, ProviderError>
566where
567 N: NodePrimitives<BlockHeader: reth_db_api::table::Value>,
568{
569 Ok(match checkpoint.execution_stage_checkpoint() {
570 Some(stage_checkpoint @ ExecutionCheckpoint { block_range, .. })
573 if block_range == CheckpointBlockRange::from(start_block..=max_block) =>
574 {
575 stage_checkpoint
576 }
577 Some(ExecutionCheckpoint {
580 block_range: CheckpointBlockRange { to, .. },
581 progress: EntitiesCheckpoint { processed, total },
582 }) if to == start_block - 1 => ExecutionCheckpoint {
583 block_range: CheckpointBlockRange { from: start_block, to: max_block },
584 progress: EntitiesCheckpoint {
585 processed,
586 total: total + calculate_gas_used_from_headers(provider, start_block..=max_block)?,
587 },
588 },
589 Some(ExecutionCheckpoint { block_range: CheckpointBlockRange { to, .. }, progress })
592 if to == max_block =>
593 {
594 ExecutionCheckpoint {
595 block_range: CheckpointBlockRange { from: start_block, to: max_block },
596 progress,
597 }
598 }
599 Some(ExecutionCheckpoint { progress: EntitiesCheckpoint { processed, .. }, .. }) => {
602 let after_checkpoint_block_number =
603 calculate_gas_used_from_headers(provider, checkpoint.block_number + 1..=max_block)?;
604
605 ExecutionCheckpoint {
606 block_range: CheckpointBlockRange { from: start_block, to: max_block },
607 progress: EntitiesCheckpoint {
608 processed,
609 total: processed + after_checkpoint_block_number,
610 },
611 }
612 }
613 _ => {
616 let processed = calculate_gas_used_from_headers(provider, 0..=start_block - 1)?;
617
618 ExecutionCheckpoint {
619 block_range: CheckpointBlockRange { from: start_block, to: max_block },
620 progress: EntitiesCheckpoint {
621 processed,
622 total: processed +
623 calculate_gas_used_from_headers(provider, start_block..=max_block)?,
624 },
625 }
626 }
627 })
628}
629
630pub fn calculate_gas_used_from_headers<N>(
632 provider: &StaticFileProvider<N>,
633 range: RangeInclusive<BlockNumber>,
634) -> Result<u64, ProviderError>
635where
636 N: NodePrimitives<BlockHeader: reth_db_api::table::Value>,
637{
638 debug!(target: "sync::stages::execution", ?range, "Calculating gas used from headers");
639
640 let mut gas_total = 0;
641
642 let start = Instant::now();
643
644 for entry in provider.fetch_range_iter(
645 StaticFileSegment::Headers,
646 *range.start()..*range.end() + 1,
647 |cursor, number| cursor.get_one::<HeaderMask<N::BlockHeader>>(number.into()),
648 )? {
649 let entry = entry?;
650 gas_total += entry.gas_used();
651 }
652
653 let duration = start.elapsed();
654 debug!(target: "sync::stages::execution", ?range, ?duration, "Finished calculating gas used from headers");
655
656 Ok(gas_total)
657}
658
659#[cfg(test)]
660mod tests {
661 use super::*;
662 use crate::{stages::MERKLE_STAGE_DEFAULT_REBUILD_THRESHOLD, test_utils::TestStageDB};
663 use alloy_primitives::{address, hex_literal::hex, keccak256, B256, U256};
664 use alloy_rlp::Decodable;
665 use assert_matches::assert_matches;
666 use reth_chainspec::ChainSpecBuilder;
667 use reth_db_api::{
668 models::AccountBeforeTx,
669 transaction::{DbTx, DbTxMut},
670 };
671 use reth_ethereum_consensus::EthBeaconConsensus;
672 use reth_ethereum_primitives::Block;
673 use reth_evm_ethereum::EthEvmConfig;
674 use reth_primitives_traits::{Account, Bytecode, SealedBlock, StorageEntry};
675 use reth_provider::{
676 test_utils::create_test_provider_factory, AccountReader, BlockWriter,
677 DatabaseProviderFactory, ReceiptProvider, StaticFileProviderFactory,
678 };
679 use reth_prune::PruneModes;
680 use reth_stages_api::StageUnitCheckpoint;
681
682 fn stage() -> ExecutionStage<EthEvmConfig> {
683 let evm_config =
684 EthEvmConfig::new(Arc::new(ChainSpecBuilder::mainnet().berlin_activated().build()));
685 let consensus = Arc::new(EthBeaconConsensus::new(Arc::new(
686 ChainSpecBuilder::mainnet().berlin_activated().build(),
687 )));
688 ExecutionStage::new(
689 evm_config,
690 consensus,
691 ExecutionStageThresholds {
692 max_blocks: Some(100),
693 max_changes: None,
694 max_cumulative_gas: None,
695 max_duration: None,
696 },
697 MERKLE_STAGE_DEFAULT_REBUILD_THRESHOLD,
698 ExExManagerHandle::empty(),
699 )
700 }
701
702 #[test]
703 fn execution_checkpoint_matches() {
704 let factory = create_test_provider_factory();
705
706 let previous_stage_checkpoint = ExecutionCheckpoint {
707 block_range: CheckpointBlockRange { from: 0, to: 0 },
708 progress: EntitiesCheckpoint { processed: 1, total: 2 },
709 };
710 let previous_checkpoint = StageCheckpoint {
711 block_number: 0,
712 stage_checkpoint: Some(StageUnitCheckpoint::Execution(previous_stage_checkpoint)),
713 };
714
715 let stage_checkpoint = execution_checkpoint(
716 &factory.static_file_provider(),
717 previous_stage_checkpoint.block_range.from,
718 previous_stage_checkpoint.block_range.to,
719 previous_checkpoint,
720 );
721
722 assert!(
723 matches!(stage_checkpoint, Ok(checkpoint) if checkpoint == previous_stage_checkpoint)
724 );
725 }
726
727 #[test]
728 fn execution_checkpoint_precedes() {
729 let factory = create_test_provider_factory();
730 let provider = factory.provider_rw().unwrap();
731
732 let mut genesis_rlp = hex!("f901faf901f5a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347942adc25665018aa1fe0e6bc666dac8fc2697ff9baa045571b40ae66ca7480791bbb2887286e4e4c4b1b298b191c889d6959023a32eda056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000083020000808502540be400808000a00000000000000000000000000000000000000000000000000000000000000000880000000000000000c0c0").as_slice();
733 let genesis = SealedBlock::<Block>::decode(&mut genesis_rlp).unwrap();
734 let mut block_rlp = hex!("f90262f901f9a075c371ba45999d87f4542326910a11af515897aebce5265d3f6acd1f1161f82fa01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347942adc25665018aa1fe0e6bc666dac8fc2697ff9baa098f2dcd87c8ae4083e7017a05456c14eea4b1db2032126e27b3b1563d57d7cc0a08151d548273f6683169524b66ca9fe338b9ce42bc3540046c828fd939ae23bcba03f4e5c2ec5b2170b711d97ee755c160457bb58d8daa338e835ec02ae6860bbabb901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000083020000018502540be40082a8798203e800a00000000000000000000000000000000000000000000000000000000000000000880000000000000000f863f861800a8405f5e10094100000000000000000000000000000000000000080801ba07e09e26678ed4fac08a249ebe8ed680bf9051a5e14ad223e4b2b9d26e0208f37a05f6e3f188e3e6eab7d7d3b6568f5eac7d687b08d307d3154ccd8c87b4630509bc0").as_slice();
735 let block = SealedBlock::<Block>::decode(&mut block_rlp).unwrap();
736 provider.insert_block(genesis.try_recover().unwrap()).unwrap();
737 provider.insert_block(block.clone().try_recover().unwrap()).unwrap();
738 provider
739 .static_file_provider()
740 .latest_writer(StaticFileSegment::Headers)
741 .unwrap()
742 .commit()
743 .unwrap();
744 provider.commit().unwrap();
745
746 let previous_stage_checkpoint = ExecutionCheckpoint {
747 block_range: CheckpointBlockRange { from: 0, to: 0 },
748 progress: EntitiesCheckpoint { processed: 1, total: 1 },
749 };
750 let previous_checkpoint = StageCheckpoint {
751 block_number: 1,
752 stage_checkpoint: Some(StageUnitCheckpoint::Execution(previous_stage_checkpoint)),
753 };
754
755 let stage_checkpoint =
756 execution_checkpoint(&factory.static_file_provider(), 1, 1, previous_checkpoint);
757
758 assert_matches!(stage_checkpoint, Ok(ExecutionCheckpoint {
759 block_range: CheckpointBlockRange { from: 1, to: 1 },
760 progress: EntitiesCheckpoint {
761 processed,
762 total
763 }
764 }) if processed == previous_stage_checkpoint.progress.processed &&
765 total == previous_stage_checkpoint.progress.total + block.gas_used);
766 }
767
768 #[test]
769 fn execution_checkpoint_recalculate_full_previous_some() {
770 let factory = create_test_provider_factory();
771 let provider = factory.provider_rw().unwrap();
772
773 let mut genesis_rlp = hex!("f901faf901f5a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347942adc25665018aa1fe0e6bc666dac8fc2697ff9baa045571b40ae66ca7480791bbb2887286e4e4c4b1b298b191c889d6959023a32eda056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000083020000808502540be400808000a00000000000000000000000000000000000000000000000000000000000000000880000000000000000c0c0").as_slice();
774 let genesis = SealedBlock::<Block>::decode(&mut genesis_rlp).unwrap();
775 let mut block_rlp = hex!("f90262f901f9a075c371ba45999d87f4542326910a11af515897aebce5265d3f6acd1f1161f82fa01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347942adc25665018aa1fe0e6bc666dac8fc2697ff9baa098f2dcd87c8ae4083e7017a05456c14eea4b1db2032126e27b3b1563d57d7cc0a08151d548273f6683169524b66ca9fe338b9ce42bc3540046c828fd939ae23bcba03f4e5c2ec5b2170b711d97ee755c160457bb58d8daa338e835ec02ae6860bbabb901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000083020000018502540be40082a8798203e800a00000000000000000000000000000000000000000000000000000000000000000880000000000000000f863f861800a8405f5e10094100000000000000000000000000000000000000080801ba07e09e26678ed4fac08a249ebe8ed680bf9051a5e14ad223e4b2b9d26e0208f37a05f6e3f188e3e6eab7d7d3b6568f5eac7d687b08d307d3154ccd8c87b4630509bc0").as_slice();
776 let block = SealedBlock::<Block>::decode(&mut block_rlp).unwrap();
777 provider.insert_block(genesis.try_recover().unwrap()).unwrap();
778 provider.insert_block(block.clone().try_recover().unwrap()).unwrap();
779 provider
780 .static_file_provider()
781 .latest_writer(StaticFileSegment::Headers)
782 .unwrap()
783 .commit()
784 .unwrap();
785 provider.commit().unwrap();
786
787 let previous_stage_checkpoint = ExecutionCheckpoint {
788 block_range: CheckpointBlockRange { from: 0, to: 0 },
789 progress: EntitiesCheckpoint { processed: 1, total: 1 },
790 };
791 let previous_checkpoint = StageCheckpoint {
792 block_number: 1,
793 stage_checkpoint: Some(StageUnitCheckpoint::Execution(previous_stage_checkpoint)),
794 };
795
796 let stage_checkpoint =
797 execution_checkpoint(&factory.static_file_provider(), 1, 1, previous_checkpoint);
798
799 assert_matches!(stage_checkpoint, Ok(ExecutionCheckpoint {
800 block_range: CheckpointBlockRange { from: 1, to: 1 },
801 progress: EntitiesCheckpoint {
802 processed,
803 total
804 }
805 }) if processed == previous_stage_checkpoint.progress.processed &&
806 total == previous_stage_checkpoint.progress.total + block.gas_used());
807 }
808
809 #[test]
810 fn execution_checkpoint_recalculate_full_previous_none() {
811 let factory = create_test_provider_factory();
812 let provider = factory.provider_rw().unwrap();
813
814 let mut genesis_rlp = hex!("f901faf901f5a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347942adc25665018aa1fe0e6bc666dac8fc2697ff9baa045571b40ae66ca7480791bbb2887286e4e4c4b1b298b191c889d6959023a32eda056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000083020000808502540be400808000a00000000000000000000000000000000000000000000000000000000000000000880000000000000000c0c0").as_slice();
815 let genesis = SealedBlock::<Block>::decode(&mut genesis_rlp).unwrap();
816 let mut block_rlp = hex!("f90262f901f9a075c371ba45999d87f4542326910a11af515897aebce5265d3f6acd1f1161f82fa01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347942adc25665018aa1fe0e6bc666dac8fc2697ff9baa098f2dcd87c8ae4083e7017a05456c14eea4b1db2032126e27b3b1563d57d7cc0a08151d548273f6683169524b66ca9fe338b9ce42bc3540046c828fd939ae23bcba03f4e5c2ec5b2170b711d97ee755c160457bb58d8daa338e835ec02ae6860bbabb901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000083020000018502540be40082a8798203e800a00000000000000000000000000000000000000000000000000000000000000000880000000000000000f863f861800a8405f5e10094100000000000000000000000000000000000000080801ba07e09e26678ed4fac08a249ebe8ed680bf9051a5e14ad223e4b2b9d26e0208f37a05f6e3f188e3e6eab7d7d3b6568f5eac7d687b08d307d3154ccd8c87b4630509bc0").as_slice();
817 let block = SealedBlock::<Block>::decode(&mut block_rlp).unwrap();
818 provider.insert_block(genesis.try_recover().unwrap()).unwrap();
819 provider.insert_block(block.clone().try_recover().unwrap()).unwrap();
820 provider
821 .static_file_provider()
822 .latest_writer(StaticFileSegment::Headers)
823 .unwrap()
824 .commit()
825 .unwrap();
826 provider.commit().unwrap();
827
828 let previous_checkpoint = StageCheckpoint { block_number: 1, stage_checkpoint: None };
829
830 let stage_checkpoint =
831 execution_checkpoint(&factory.static_file_provider(), 1, 1, previous_checkpoint);
832
833 assert_matches!(stage_checkpoint, Ok(ExecutionCheckpoint {
834 block_range: CheckpointBlockRange { from: 1, to: 1 },
835 progress: EntitiesCheckpoint {
836 processed: 0,
837 total
838 }
839 }) if total == block.gas_used);
840 }
841
842 #[tokio::test]
843 async fn sanity_execution_of_block() {
844 let factory = create_test_provider_factory();
845 let provider = factory.provider_rw().unwrap();
846 let input = ExecInput { target: Some(1), checkpoint: None };
847 let mut genesis_rlp = hex!("f901faf901f5a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347942adc25665018aa1fe0e6bc666dac8fc2697ff9baa045571b40ae66ca7480791bbb2887286e4e4c4b1b298b191c889d6959023a32eda056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000083020000808502540be400808000a00000000000000000000000000000000000000000000000000000000000000000880000000000000000c0c0").as_slice();
848 let genesis = SealedBlock::<Block>::decode(&mut genesis_rlp).unwrap();
849 let mut block_rlp = hex!("f90262f901f9a075c371ba45999d87f4542326910a11af515897aebce5265d3f6acd1f1161f82fa01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347942adc25665018aa1fe0e6bc666dac8fc2697ff9baa098f2dcd87c8ae4083e7017a05456c14eea4b1db2032126e27b3b1563d57d7cc0a08151d548273f6683169524b66ca9fe338b9ce42bc3540046c828fd939ae23bcba03f4e5c2ec5b2170b711d97ee755c160457bb58d8daa338e835ec02ae6860bbabb901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000083020000018502540be40082a8798203e800a00000000000000000000000000000000000000000000000000000000000000000880000000000000000f863f861800a8405f5e10094100000000000000000000000000000000000000080801ba07e09e26678ed4fac08a249ebe8ed680bf9051a5e14ad223e4b2b9d26e0208f37a05f6e3f188e3e6eab7d7d3b6568f5eac7d687b08d307d3154ccd8c87b4630509bc0").as_slice();
850 let block = SealedBlock::<Block>::decode(&mut block_rlp).unwrap();
851 provider.insert_block(genesis.try_recover().unwrap()).unwrap();
852 provider.insert_block(block.clone().try_recover().unwrap()).unwrap();
853 provider
854 .static_file_provider()
855 .latest_writer(StaticFileSegment::Headers)
856 .unwrap()
857 .commit()
858 .unwrap();
859 {
860 let static_file_provider = provider.static_file_provider();
861 let mut receipts_writer =
862 static_file_provider.latest_writer(StaticFileSegment::Receipts).unwrap();
863 receipts_writer.increment_block(0).unwrap();
864 receipts_writer.commit().unwrap();
865 }
866 provider.commit().unwrap();
867
868 let provider = factory.provider_rw().unwrap();
870
871 let db_tx = provider.tx_ref();
872 let acc1 = address!("0x1000000000000000000000000000000000000000");
873 let acc2 = address!("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b");
874 let code = hex!("5a465a905090036002900360015500");
875 let balance = U256::from(0x3635c9adc5dea00000u128);
876 let code_hash = keccak256(code);
877 db_tx
878 .put::<tables::PlainAccountState>(
879 acc1,
880 Account { nonce: 0, balance: U256::ZERO, bytecode_hash: Some(code_hash) },
881 )
882 .unwrap();
883 db_tx
884 .put::<tables::PlainAccountState>(
885 acc2,
886 Account { nonce: 0, balance, bytecode_hash: None },
887 )
888 .unwrap();
889 db_tx.put::<tables::Bytecodes>(code_hash, Bytecode::new_raw(code.to_vec().into())).unwrap();
890 provider.commit().unwrap();
891
892 let modes = [None, Some(PruneModes::default())];
897
898 for mode in modes {
900 let mut provider = factory.database_provider_rw().unwrap();
901
902 let mut execution_stage = stage();
903 provider.set_prune_modes(mode.clone().unwrap_or_default());
904
905 let output = execution_stage.execute(&provider, input).unwrap();
906 provider.commit().unwrap();
907
908 assert_matches!(output, ExecOutput {
909 checkpoint: StageCheckpoint {
910 block_number: 1,
911 stage_checkpoint: Some(StageUnitCheckpoint::Execution(ExecutionCheckpoint {
912 block_range: CheckpointBlockRange {
913 from: 1,
914 to: 1,
915 },
916 progress: EntitiesCheckpoint {
917 processed,
918 total
919 }
920 }))
921 },
922 done: true
923 } if processed == total && total == block.gas_used);
924
925 let provider = factory.provider().unwrap();
926
927 let account1 = address!("0x1000000000000000000000000000000000000000");
929 let account1_info =
930 Account { balance: U256::ZERO, nonce: 0x00, bytecode_hash: Some(code_hash) };
931 let account2 = address!("0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba");
932 let account2_info = Account {
933 balance: U256::from(0x1bc16d674ece94bau128),
934 nonce: 0x00,
935 bytecode_hash: None,
936 };
937 let account3 = address!("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b");
938 let account3_info = Account {
939 balance: U256::from(0x3635c9adc5de996b46u128),
940 nonce: 0x01,
941 bytecode_hash: None,
942 };
943
944 assert!(
946 matches!(provider.basic_account(&account1), Ok(Some(acc)) if acc == account1_info)
947 );
948 assert!(
949 matches!(provider.basic_account(&account2), Ok(Some(acc)) if acc == account2_info)
950 );
951 assert!(
952 matches!(provider.basic_account(&account3), Ok(Some(acc)) if acc == account3_info)
953 );
954 assert!(matches!(
957 provider.tx_ref().get::<tables::PlainStorageState>(account1),
958 Ok(Some(entry)) if entry.key == B256::with_last_byte(1) && entry.value == U256::from(2)
959 ));
960
961 let mut provider = factory.database_provider_rw().unwrap();
962 let mut stage = stage();
963 provider.set_prune_modes(mode.unwrap_or_default());
964
965 let _result = stage
966 .unwind(
967 &provider,
968 UnwindInput { checkpoint: output.checkpoint, unwind_to: 0, bad_block: None },
969 )
970 .unwrap();
971 provider.commit().unwrap();
972 }
973 }
974
975 #[tokio::test]
976 async fn sanity_execute_unwind() {
977 let factory = create_test_provider_factory();
978 let provider = factory.provider_rw().unwrap();
979 let input = ExecInput { target: Some(1), checkpoint: None };
980 let mut genesis_rlp = hex!("f901faf901f5a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347942adc25665018aa1fe0e6bc666dac8fc2697ff9baa045571b40ae66ca7480791bbb2887286e4e4c4b1b298b191c889d6959023a32eda056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000083020000808502540be400808000a00000000000000000000000000000000000000000000000000000000000000000880000000000000000c0c0").as_slice();
981 let genesis = SealedBlock::<Block>::decode(&mut genesis_rlp).unwrap();
982 let mut block_rlp = hex!("f90262f901f9a075c371ba45999d87f4542326910a11af515897aebce5265d3f6acd1f1161f82fa01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347942adc25665018aa1fe0e6bc666dac8fc2697ff9baa098f2dcd87c8ae4083e7017a05456c14eea4b1db2032126e27b3b1563d57d7cc0a08151d548273f6683169524b66ca9fe338b9ce42bc3540046c828fd939ae23bcba03f4e5c2ec5b2170b711d97ee755c160457bb58d8daa338e835ec02ae6860bbabb901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000083020000018502540be40082a8798203e800a00000000000000000000000000000000000000000000000000000000000000000880000000000000000f863f861800a8405f5e10094100000000000000000000000000000000000000080801ba07e09e26678ed4fac08a249ebe8ed680bf9051a5e14ad223e4b2b9d26e0208f37a05f6e3f188e3e6eab7d7d3b6568f5eac7d687b08d307d3154ccd8c87b4630509bc0").as_slice();
983 let block = SealedBlock::<Block>::decode(&mut block_rlp).unwrap();
984 provider.insert_block(genesis.try_recover().unwrap()).unwrap();
985 provider.insert_block(block.clone().try_recover().unwrap()).unwrap();
986 provider
987 .static_file_provider()
988 .latest_writer(StaticFileSegment::Headers)
989 .unwrap()
990 .commit()
991 .unwrap();
992 {
993 let static_file_provider = provider.static_file_provider();
994 let mut receipts_writer =
995 static_file_provider.latest_writer(StaticFileSegment::Receipts).unwrap();
996 receipts_writer.increment_block(0).unwrap();
997 receipts_writer.commit().unwrap();
998 }
999 provider.commit().unwrap();
1000
1001 let code = hex!("5a465a905090036002900360015500");
1003 let balance = U256::from(0x3635c9adc5dea00000u128);
1004 let code_hash = keccak256(code);
1005 let provider = factory.provider_rw().unwrap();
1007
1008 let db_tx = provider.tx_ref();
1009 let acc1 = address!("0x1000000000000000000000000000000000000000");
1010 let acc1_info = Account { nonce: 0, balance: U256::ZERO, bytecode_hash: Some(code_hash) };
1011 let acc2 = address!("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b");
1012 let acc2_info = Account { nonce: 0, balance, bytecode_hash: None };
1013
1014 db_tx.put::<tables::PlainAccountState>(acc1, acc1_info).unwrap();
1015 db_tx.put::<tables::PlainAccountState>(acc2, acc2_info).unwrap();
1016 db_tx.put::<tables::Bytecodes>(code_hash, Bytecode::new_raw(code.to_vec().into())).unwrap();
1017 provider.commit().unwrap();
1018
1019 let mut provider = factory.database_provider_rw().unwrap();
1021
1022 let modes = [None, Some(PruneModes::default())];
1025
1026 for mode in modes {
1028 let mut execution_stage = stage();
1030 provider.set_prune_modes(mode.clone().unwrap_or_default());
1031
1032 let result = execution_stage.execute(&provider, input).unwrap();
1033 provider.commit().unwrap();
1034
1035 provider = factory.database_provider_rw().unwrap();
1037 let mut stage = stage();
1038 provider.set_prune_modes(mode.clone().unwrap_or_default());
1039
1040 let result = stage
1041 .unwind(
1042 &provider,
1043 UnwindInput { checkpoint: result.checkpoint, unwind_to: 0, bad_block: None },
1044 )
1045 .unwrap();
1046
1047 provider.static_file_provider().commit().unwrap();
1048
1049 assert_matches!(result, UnwindOutput {
1050 checkpoint: StageCheckpoint {
1051 block_number: 0,
1052 stage_checkpoint: Some(StageUnitCheckpoint::Execution(ExecutionCheckpoint {
1053 block_range: CheckpointBlockRange {
1054 from: 1,
1055 to: 1,
1056 },
1057 progress: EntitiesCheckpoint {
1058 processed: 0,
1059 total
1060 }
1061 }))
1062 }
1063 } if total == block.gas_used);
1064
1065 assert!(matches!(provider.basic_account(&acc1), Ok(Some(acc)) if acc == acc1_info));
1067 assert!(matches!(provider.basic_account(&acc2), Ok(Some(acc)) if acc == acc2_info));
1068
1069 let miner_acc = address!("0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba");
1070 assert!(matches!(provider.basic_account(&miner_acc), Ok(None)));
1071
1072 assert!(matches!(provider.receipt(0), Ok(None)));
1073 }
1074 }
1075
1076 #[tokio::test]
1077 async fn test_selfdestruct() {
1078 let test_db = TestStageDB::default();
1079 let provider = test_db.factory.database_provider_rw().unwrap();
1080 let input = ExecInput { target: Some(1), checkpoint: None };
1081 let mut genesis_rlp = hex!("f901f8f901f3a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347942adc25665018aa1fe0e6bc666dac8fc2697ff9baa0c9ceb8372c88cb461724d8d3d87e8b933f6fc5f679d4841800e662f4428ffd0da056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000080830f4240808000a00000000000000000000000000000000000000000000000000000000000000000880000000000000000c0c0").as_slice();
1082 let genesis = SealedBlock::<Block>::decode(&mut genesis_rlp).unwrap();
1083 let mut block_rlp = hex!("f9025ff901f7a0c86e8cc0310ae7c531c758678ddbfd16fc51c8cef8cec650b032de9869e8b94fa01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347942adc25665018aa1fe0e6bc666dac8fc2697ff9baa050554882fbbda2c2fd93fdc466db9946ea262a67f7a76cc169e714f105ab583da00967f09ef1dfed20c0eacfaa94d5cd4002eda3242ac47eae68972d07b106d192a0e3c8b47fbfc94667ef4cceb17e5cc21e3b1eebd442cebb27f07562b33836290db90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000001830f42408238108203e800a00000000000000000000000000000000000000000000000000000000000000000880000000000000000f862f860800a83061a8094095e7baea6a6c7c4c2dfeb977efac326af552d8780801ba072ed817487b84ba367d15d2f039b5fc5f087d0a8882fbdf73e8cb49357e1ce30a0403d800545b8fc544f92ce8124e2255f8c3c6af93f28243a120585d4c4c6a2a3c0").as_slice();
1084 let block = SealedBlock::<Block>::decode(&mut block_rlp).unwrap();
1085 provider.insert_block(genesis.try_recover().unwrap()).unwrap();
1086 provider.insert_block(block.clone().try_recover().unwrap()).unwrap();
1087 provider
1088 .static_file_provider()
1089 .latest_writer(StaticFileSegment::Headers)
1090 .unwrap()
1091 .commit()
1092 .unwrap();
1093 {
1094 let static_file_provider = provider.static_file_provider();
1095 let mut receipts_writer =
1096 static_file_provider.latest_writer(StaticFileSegment::Receipts).unwrap();
1097 receipts_writer.increment_block(0).unwrap();
1098 receipts_writer.commit().unwrap();
1099 }
1100 provider.commit().unwrap();
1101
1102 let caller_address = address!("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b");
1104 let destroyed_address = address!("0x095e7baea6a6c7c4c2dfeb977efac326af552d87");
1105 let beneficiary_address = address!("0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba");
1106
1107 let code = hex!("73095e7baea6a6c7c4c2dfeb977efac326af552d8731ff00");
1108 let balance = U256::from(0x0de0b6b3a7640000u64);
1109 let code_hash = keccak256(code);
1110
1111 let caller_info = Account { nonce: 0, balance, bytecode_hash: None };
1113 let destroyed_info =
1114 Account { nonce: 0, balance: U256::ZERO, bytecode_hash: Some(code_hash) };
1115
1116 let provider = test_db.factory.provider_rw().unwrap();
1118 provider.tx_ref().put::<tables::PlainAccountState>(caller_address, caller_info).unwrap();
1119 provider
1120 .tx_ref()
1121 .put::<tables::PlainAccountState>(destroyed_address, destroyed_info)
1122 .unwrap();
1123 provider
1124 .tx_ref()
1125 .put::<tables::Bytecodes>(code_hash, Bytecode::new_raw(code.to_vec().into()))
1126 .unwrap();
1127 provider
1129 .tx_ref()
1130 .put::<tables::PlainStorageState>(
1131 destroyed_address,
1132 StorageEntry { key: B256::ZERO, value: U256::ZERO },
1133 )
1134 .unwrap();
1135 provider
1136 .tx_ref()
1137 .put::<tables::PlainStorageState>(
1138 destroyed_address,
1139 StorageEntry { key: B256::with_last_byte(1), value: U256::from(1u64) },
1140 )
1141 .unwrap();
1142
1143 provider.commit().unwrap();
1144
1145 let provider = test_db.factory.database_provider_rw().unwrap();
1147 let mut execution_stage = stage();
1148 let _ = execution_stage.execute(&provider, input).unwrap();
1149 provider.commit().unwrap();
1150
1151 let provider = test_db.factory.database_provider_rw().unwrap();
1153 assert!(matches!(provider.basic_account(&destroyed_address), Ok(None)));
1154
1155 assert!(matches!(
1156 provider.tx_ref().get::<tables::PlainStorageState>(destroyed_address),
1157 Ok(None)
1158 ));
1159 drop(provider);
1161 let plain_accounts = test_db.table::<tables::PlainAccountState>().unwrap();
1162 let plain_storage = test_db.table::<tables::PlainStorageState>().unwrap();
1163
1164 assert_eq!(
1165 plain_accounts,
1166 vec![
1167 (
1168 beneficiary_address,
1169 Account {
1170 nonce: 0,
1171 balance: U256::from(0x1bc16d674eca30a0u64),
1172 bytecode_hash: None
1173 }
1174 ),
1175 (
1176 caller_address,
1177 Account {
1178 nonce: 1,
1179 balance: U256::from(0xde0b6b3a761cf60u64),
1180 bytecode_hash: None
1181 }
1182 )
1183 ]
1184 );
1185 assert!(plain_storage.is_empty());
1186
1187 let account_changesets = test_db.table::<tables::AccountChangeSets>().unwrap();
1188 let storage_changesets = test_db.table::<tables::StorageChangeSets>().unwrap();
1189
1190 assert_eq!(
1191 account_changesets,
1192 vec![
1193 (
1194 block.number,
1195 AccountBeforeTx { address: destroyed_address, info: Some(destroyed_info) },
1196 ),
1197 (block.number, AccountBeforeTx { address: beneficiary_address, info: None }),
1198 (
1199 block.number,
1200 AccountBeforeTx { address: caller_address, info: Some(caller_info) }
1201 ),
1202 ]
1203 );
1204
1205 assert_eq!(
1206 storage_changesets,
1207 vec![
1208 (
1209 (block.number, destroyed_address).into(),
1210 StorageEntry { key: B256::ZERO, value: U256::ZERO }
1211 ),
1212 (
1213 (block.number, destroyed_address).into(),
1214 StorageEntry { key: B256::with_last_byte(1), value: U256::from(1u64) }
1215 )
1216 ]
1217 );
1218 }
1219}