reth_e2e_test_utils/
trie.rs1use alloy_consensus::BlockHeader;
4use eyre::{ensure, eyre, Result};
5use reth_provider::{
6 BlockNumReader, DBProvider, DatabaseProviderFactory, HeaderProvider, StorageSettingsCache,
7};
8use reth_trie::{
9 prefix_set::{PrefixSetMut, TriePrefixSets},
10 verify::{Output, Verifier},
11 StateRoot,
12};
13use reth_trie_db::{DatabaseHashedCursorFactory, DatabaseTrieCursorFactory};
14use std::time::{Duration, Instant};
15
16pub async fn wait_for_persisted_block<F>(factory: &F, number: u64, timeout: Duration) -> Result<()>
23where
24 F: DatabaseProviderFactory<Provider: BlockNumReader>,
25{
26 let start = Instant::now();
27 loop {
28 if factory.database_provider_ro()?.best_block_number()? >= number {
30 return Ok(())
31 }
32 ensure!(start.elapsed() < timeout, "timed out waiting for block {number} to be persisted");
33 tokio::time::sleep(Duration::from_millis(50)).await;
34 }
35}
36
37pub fn assert_trie_consistency<F>(factory: &F) -> Result<()>
49where
50 F: DatabaseProviderFactory<
51 Provider: DBProvider + StorageSettingsCache + BlockNumReader + HeaderProvider,
52 >,
53{
54 let provider = factory.database_provider_ro()?;
55 let tip = provider.best_block_number()?;
56 let header = provider
57 .header_by_number(tip)?
58 .ok_or_else(|| eyre!("missing persisted header for block {tip}"))?;
59 let tx = provider.tx_ref();
60
61 reth_trie_db::with_adapter!(provider, |A| {
62 let recomputed = StateRoot::new(
66 DatabaseTrieCursorFactory::<_, A>::new(tx),
67 DatabaseHashedCursorFactory::new(tx),
68 )
69 .with_prefix_sets(TriePrefixSets {
70 account_prefix_set: PrefixSetMut::all().freeze(),
71 ..Default::default()
72 })
73 .root()?;
74 ensure!(
75 recomputed == header.state_root(),
76 "state root {recomputed} recomputed from the persisted state does not match the state root of persisted block {tip}: {}",
77 header.state_root()
78 );
79
80 let trie_cursor_factory = DatabaseTrieCursorFactory::<_, A>::new(tx);
81 let verifier = Verifier::new(&trie_cursor_factory, DatabaseHashedCursorFactory::new(tx))?;
82 let mut inconsistencies = Vec::new();
83 for output in verifier {
84 match output? {
85 Output::Progress(_) => {}
86 inconsistency => inconsistencies.push(inconsistency),
87 }
88 }
89 ensure!(
90 inconsistencies.is_empty(),
91 "persisted trie is inconsistent with the persisted hashed state: {inconsistencies:?}"
92 );
93
94 Ok(())
95 })
96}