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 when calling [`StateWriter::write_state`].
131///
132/// Used to skip writing certain data types, when they are being written separately.
133#[derive(Debug, Clone, Copy)]
134pub struct StateWriteConfig {
135    /// Whether to write receipts.
136    pub write_receipts: bool,
137    /// Whether to write account changesets.
138    pub write_account_changesets: bool,
139    /// Whether to write storage changesets.
140    pub write_storage_changesets: bool,
141}
142
143impl Default for StateWriteConfig {
144    fn default() -> Self {
145        Self {
146            write_receipts: true,
147            write_account_changesets: true,
148            write_storage_changesets: true,
149        }
150    }
151}