Skip to main content

reth_storage_overlay/
multiproof_calculator.rs

1//! Multiproof calculators over database trie tables with an immutable in-memory overlay.
2
3use alloy_primitives::{map::B256Map, B256};
4use reth_db_api::transaction::DbTx;
5use reth_errors::ProviderResult;
6use reth_trie::{
7    hashed_cursor::{HashedPostStateCursorFactory, InstrumentedHashedCursorFactory},
8    prefix_set::TriePrefixSets,
9    proof_v2::{MultiProofCalculator, ProofCursorMetrics},
10    trie_cursor::{InMemoryTrieCursorFactory, InstrumentedTrieCursorFactory},
11    updates::TrieUpdatesSorted,
12    DecodedMultiProofV2, HashedPostStateSorted, MultiProofTargetsV2, TrieInputSorted,
13};
14use reth_trie_db::{
15    DatabaseHashedCursorFactory, DatabaseTrieCursorFactory, LegacyKeyAdapter, PackedKeyAdapter,
16    TrieTableAdapter,
17};
18use std::sync::Arc;
19
20/// Multiproof calculator for the database's trie table layout.
21///
22/// The calculator borrows a transaction and overlay it does not own, so its owner must keep both
23/// alive and at stable addresses for as long as the calculator exists.
24pub(crate) enum OverlayMultiProofCalculator<TX: DbTx + 'static> {
25    /// Calculator over legacy trie tables.
26    Legacy(TableMultiProofCalculator<TX, LegacyKeyAdapter>),
27    /// Calculator over packed trie tables.
28    Packed(TableMultiProofCalculator<TX, PackedKeyAdapter>),
29}
30
31impl<TX: DbTx + 'static> OverlayMultiProofCalculator<TX> {
32    /// Creates a calculator over `tx` with `input` layered on top.
33    ///
34    /// `is_v2` selects the packed trie tables used by v2 storage settings.
35    ///
36    /// # Safety
37    ///
38    /// The transaction and the `Arc` allocations in `input` must stay alive and at stable addresses
39    /// until the calculator drops. Unless the transaction is `Sync`, the calculator must not be
40    /// sent to another thread separately from the transaction, and the transaction must not be
41    /// used from another thread while the calculator exists.
42    pub(crate) unsafe fn new(
43        tx: &TX,
44        input: &TrieInputSorted,
45        is_v2: bool,
46        metrics: ProofCursorMetrics,
47        known_storage_roots: Arc<B256Map<B256>>,
48    ) -> Self {
49        // SAFETY: The caller keeps these allocations alive and in place until the calculator drops.
50        let (tx, nodes, state) = unsafe {
51            (&*(tx as *const TX), &*Arc::as_ptr(&input.nodes), &*Arc::as_ptr(&input.state))
52        };
53        let prefix_sets = input.prefix_sets.clone().freeze();
54        if is_v2 {
55            Self::Packed(table_multiproof_calculator(
56                tx,
57                nodes,
58                state,
59                prefix_sets,
60                metrics,
61                known_storage_roots,
62            ))
63        } else {
64            Self::Legacy(table_multiproof_calculator(
65                tx,
66                nodes,
67                state,
68                prefix_sets,
69                metrics,
70                known_storage_roots,
71            ))
72        }
73    }
74
75    /// Generates account and storage proofs for `targets`.
76    pub(crate) fn multiproof(
77        &mut self,
78        targets: MultiProofTargetsV2,
79    ) -> ProviderResult<DecodedMultiProofV2> {
80        Ok(match self {
81            Self::Legacy(calculator) => calculator.multiproof(targets)?,
82            Self::Packed(calculator) => calculator.multiproof(targets)?,
83        })
84    }
85}
86
87// SAFETY: `new` requires the calculator to move between threads only together with its
88// transaction, or the transaction to be `Sync`, so the borrowed transaction is never shared across
89// threads without synchronization.
90unsafe impl<TX: DbTx + 'static> Send for OverlayMultiProofCalculator<TX> {}
91
92/// Multiproof calculator over trie table layout `A`, whose borrows of the transaction and overlay
93/// are extended to `'static` by [`OverlayMultiProofCalculator::new`].
94type TableMultiProofCalculator<TX, A> = MultiProofCalculator<
95    'static,
96    InstrumentedTrieCursorFactory<
97        InMemoryTrieCursorFactory<
98            DatabaseTrieCursorFactory<&'static TX, A>,
99            &'static TrieUpdatesSorted,
100        >,
101    >,
102    InstrumentedHashedCursorFactory<
103        HashedPostStateCursorFactory<
104            DatabaseHashedCursorFactory<&'static TX>,
105            &'static HashedPostStateSorted,
106        >,
107    >,
108>;
109
110/// Creates a calculator for trie table layout `A`.
111fn table_multiproof_calculator<TX: DbTx + 'static, A: TrieTableAdapter>(
112    tx: &'static TX,
113    nodes: &'static TrieUpdatesSorted,
114    state: &'static HashedPostStateSorted,
115    prefix_sets: TriePrefixSets,
116    metrics: ProofCursorMetrics,
117    known_storage_roots: Arc<B256Map<B256>>,
118) -> TableMultiProofCalculator<TX, A> {
119    MultiProofCalculator::new(
120        metrics.instrument_trie_factory(InMemoryTrieCursorFactory::new(
121            DatabaseTrieCursorFactory::new(tx),
122            nodes,
123        )),
124        metrics.instrument_hashed_factory(HashedPostStateCursorFactory::new(
125            DatabaseHashedCursorFactory::new(tx),
126            state,
127        )),
128        prefix_sets,
129        known_storage_roots,
130    )
131}