Skip to main content

reth_storage_api/
state_writer.rs

1use alloc::vec::Vec;
2use alloy_consensus::transaction::Either;
3use alloy_primitives::BlockNumber;
4use reth_execution_types::{BlockExecutionOutput, ExecutionOutcome};
5use reth_storage_errors::provider::ProviderResult;
6use reth_trie_common::{
7    bundle_state::{BundleState, OriginalValuesKnown, PlainStateReverts, StateChangeset},
8    HashedPostStateSorted,
9};
10
11/// A helper type used as input to [`StateWriter`] for writing execution outcome for one or many
12/// blocks.
13#[derive(Debug)]
14pub enum WriteStateInput<'a, R> {
15    /// A single block execution outcome.
16    Single {
17        /// The execution outcome.
18        outcome: &'a BlockExecutionOutput<R>,
19        /// Block number
20        block: BlockNumber,
21    },
22    /// Multiple block execution outcomes.
23    Multiple(&'a ExecutionOutcome<R>),
24}
25
26impl<'a, R> WriteStateInput<'a, R> {
27    /// Number of blocks in the execution outcome.
28    pub const fn len(&self) -> usize {
29        match self {
30            Self::Single { .. } => 1,
31            Self::Multiple(outcome) => outcome.len(),
32        }
33    }
34
35    /// Returns true if the execution outcome is empty.
36    pub const fn is_empty(&self) -> bool {
37        match self {
38            Self::Single { outcome, .. } => outcome.result.receipts.is_empty(),
39            Self::Multiple(outcome) => outcome.is_empty(),
40        }
41    }
42
43    /// Number of the first block.
44    pub const fn first_block(&self) -> BlockNumber {
45        match self {
46            Self::Single { block, .. } => *block,
47            Self::Multiple(outcome) => outcome.first_block(),
48        }
49    }
50
51    /// Number of the last block.
52    pub const fn last_block(&self) -> BlockNumber {
53        match self {
54            Self::Single { block, .. } => *block,
55            Self::Multiple(outcome) => outcome.last_block(),
56        }
57    }
58
59    /// Returns a reference to the [`BundleState`].
60    pub const fn state(&self) -> &BundleState {
61        match self {
62            Self::Single { outcome, .. } => &outcome.state,
63            Self::Multiple(outcome) => &outcome.bundle,
64        }
65    }
66
67    /// Returns an iterator over receipt sets for each block.
68    pub fn receipts(&self) -> impl Iterator<Item = &Vec<R>> {
69        match self {
70            Self::Single { outcome, .. } => {
71                Either::Left(core::iter::once(&outcome.result.receipts))
72            }
73            Self::Multiple(outcome) => Either::Right(outcome.receipts.iter()),
74        }
75    }
76}
77
78impl<'a, R> From<&'a ExecutionOutcome<R>> for WriteStateInput<'a, R> {
79    fn from(outcome: &'a ExecutionOutcome<R>) -> Self {
80        Self::Multiple(outcome)
81    }
82}
83
84/// A trait specifically for writing state changes or reverts
85pub trait StateWriter {
86    /// Receipt type included into [`ExecutionOutcome`].
87    type Receipt: 'static;
88
89    /// Write the state and optionally receipts to the database.
90    ///
91    /// Use `config` to skip writing certain data types when they are written elsewhere.
92    fn write_state<'a>(
93        &self,
94        execution_outcome: impl Into<WriteStateInput<'a, Self::Receipt>>,
95        is_value_known: OriginalValuesKnown,
96        config: StateWriteConfig,
97    ) -> ProviderResult<()>;
98
99    /// Write state reverts to the database.
100    ///
101    /// NOTE: Reverts will delete all wiped storage from plain state.
102    ///
103    /// Use `config` to skip writing certain data types when they are written elsewhere.
104    fn write_state_reverts(
105        &self,
106        reverts: PlainStateReverts,
107        first_block: BlockNumber,
108        config: StateWriteConfig,
109    ) -> ProviderResult<()>;
110
111    /// Write state changes to the database.
112    fn write_state_changes(&self, changes: StateChangeset) -> ProviderResult<()>;
113
114    /// Writes the hashed state changes to the database
115    fn write_hashed_state(&self, hashed_state: &HashedPostStateSorted) -> ProviderResult<()>;
116
117    /// Remove the block range of state above the given block. The state of the passed block is not
118    /// removed.
119    fn remove_state_above(&self, block: BlockNumber) -> ProviderResult<()>;
120
121    /// Take the block range of state, recreating the [`ExecutionOutcome`]. The state of the passed
122    /// block is not removed.
123    fn take_state_above(
124        &self,
125        block: BlockNumber,
126    ) -> ProviderResult<ExecutionOutcome<Self::Receipt>>;
127}
128
129/// Configuration for what to write to the database (MDBX) when calling
130/// [`StateWriter::write_state`].
131///
132/// Some types (receipts, changesets) may be written directly to
133/// static files instead of the database depending on the storage settings. This config allows
134/// skipping those types in the database write to avoid duplication.
135#[derive(Debug, Clone, Copy)]
136pub struct StateWriteConfig {
137    /// Whether to write receipts to the database.
138    ///
139    /// Set to `false` when receipts are being written to static files instead.
140    pub write_receipts: bool,
141    /// Whether to write account changesets to the database.
142    ///
143    /// Set to `false` when account changesets are being written to static files instead.
144    pub write_account_changesets: bool,
145    /// Whether to write storage changesets to the database.
146    ///
147    /// Set to `false` when storage changesets are being written to static files instead.
148    pub write_storage_changesets: bool,
149}
150
151impl Default for StateWriteConfig {
152    fn default() -> Self {
153        Self {
154            write_receipts: true,
155            write_account_changesets: true,
156            write_storage_changesets: true,
157        }
158    }
159}