reth_stages/stages/
finish.rs
1use reth_stages_api::{
2 ExecInput, ExecOutput, Stage, StageCheckpoint, StageError, StageId, UnwindInput, UnwindOutput,
3};
4
5#[derive(Default, Debug, Clone)]
10#[non_exhaustive]
11pub struct FinishStage;
12
13impl<Provider> Stage<Provider> for FinishStage {
14 fn id(&self) -> StageId {
15 StageId::Finish
16 }
17
18 fn execute(
19 &mut self,
20 _provider: &Provider,
21 input: ExecInput,
22 ) -> Result<ExecOutput, StageError> {
23 Ok(ExecOutput { checkpoint: StageCheckpoint::new(input.target()), done: true })
24 }
25
26 fn unwind(
27 &mut self,
28 _provider: &Provider,
29 input: UnwindInput,
30 ) -> Result<UnwindOutput, StageError> {
31 Ok(UnwindOutput { checkpoint: StageCheckpoint::new(input.unwind_to) })
32 }
33}
34
35#[cfg(test)]
36mod tests {
37 use super::*;
38 use crate::test_utils::{
39 stage_test_suite_ext, ExecuteStageTestRunner, StageTestRunner, TestRunnerError,
40 TestStageDB, UnwindStageTestRunner,
41 };
42 use reth_primitives_traits::SealedHeader;
43 use reth_provider::providers::StaticFileWriter;
44 use reth_testing_utils::{
45 generators,
46 generators::{random_header, random_header_range},
47 };
48
49 stage_test_suite_ext!(FinishTestRunner, finish);
50
51 #[derive(Default)]
52 struct FinishTestRunner {
53 db: TestStageDB,
54 }
55
56 impl StageTestRunner for FinishTestRunner {
57 type S = FinishStage;
58
59 fn db(&self) -> &TestStageDB {
60 &self.db
61 }
62
63 fn stage(&self) -> Self::S {
64 FinishStage
65 }
66 }
67
68 impl ExecuteStageTestRunner for FinishTestRunner {
69 type Seed = Vec<SealedHeader>;
70
71 fn seed_execution(&mut self, input: ExecInput) -> Result<Self::Seed, TestRunnerError> {
72 let start = input.checkpoint().block_number;
73 let mut rng = generators::rng();
74 let head = random_header(&mut rng, start, None);
75 self.db.insert_headers_with_td(std::iter::once(&head))?;
76
77 let end = input.target.unwrap_or_default() + 1;
79
80 if start + 1 >= end {
81 return Ok(Vec::default())
82 }
83
84 let mut headers = random_header_range(&mut rng, start + 1..end, head.hash());
85 self.db.insert_headers_with_td(headers.iter())?;
86 headers.insert(0, head);
87 Ok(headers)
88 }
89
90 fn validate_execution(
91 &self,
92 input: ExecInput,
93 output: Option<ExecOutput>,
94 ) -> Result<(), TestRunnerError> {
95 if let Some(output) = output {
96 assert!(output.done, "stage should always be done");
97 assert_eq!(
98 output.checkpoint.block_number,
99 input.target(),
100 "stage progress should always match progress of previous stage"
101 );
102 }
103 Ok(())
104 }
105 }
106
107 impl UnwindStageTestRunner for FinishTestRunner {
108 fn validate_unwind(&self, _input: UnwindInput) -> Result<(), TestRunnerError> {
109 Ok(())
110 }
111 }
112}