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