reth_stages/stages/
finish.rs

1use reth_stages_api::{
2    ExecInput, ExecOutput, Stage, StageCheckpoint, StageError, StageId, UnwindInput, UnwindOutput,
3};
4
5/// The finish stage.
6///
7/// This stage does not write anything; it's checkpoint is used to denote the highest fully synced
8/// block.
9#[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            // use previous progress as seed size
78            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}