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