mirror of
https://github.com/paradigmxyz/reth.git
synced 2026-04-08 03:01:12 -04:00
perf: put all prefix sets in Rc (#3582)
This commit is contained in:
@@ -7,21 +7,23 @@ use proptest::{
|
||||
test_runner::{basic_result_cache, TestRunner},
|
||||
};
|
||||
use reth_primitives::trie::Nibbles;
|
||||
use reth_trie::prefix_set::PrefixSet;
|
||||
use reth_trie::prefix_set::PrefixSetMut;
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
/// Abstractions used for benching
|
||||
pub trait PrefixSetAbstraction: Default {
|
||||
fn insert(&mut self, key: Nibbles);
|
||||
fn contains(&mut self, key: Nibbles) -> bool;
|
||||
}
|
||||
|
||||
impl PrefixSetAbstraction for PrefixSet {
|
||||
/// Abstractions used for benching
|
||||
impl PrefixSetAbstraction for PrefixSetMut {
|
||||
fn insert(&mut self, key: Nibbles) {
|
||||
self.insert(key)
|
||||
}
|
||||
|
||||
fn contains(&mut self, key: Nibbles) -> bool {
|
||||
PrefixSet::contains(self, key)
|
||||
PrefixSetMut::contains(self, key)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use super::{HashedAccountCursor, HashedCursorFactory, HashedStorageCursor};
|
||||
use crate::prefix_set::PrefixSet;
|
||||
use crate::prefix_set::{PrefixSet, PrefixSetMut};
|
||||
use reth_db::{
|
||||
cursor::{DbCursorRO, DbDupCursorRO},
|
||||
tables,
|
||||
@@ -27,13 +27,13 @@ pub struct HashedPostState {
|
||||
}
|
||||
|
||||
impl HashedPostState {
|
||||
/// Construct (PrefixSets)[PrefixSet] from hashed post state.
|
||||
/// Construct (PrefixSet)[PrefixSet] from hashed post state.
|
||||
/// The prefix sets contain the hashed account and storage keys that have been changed in the
|
||||
/// post state.
|
||||
pub fn construct_prefix_sets(&self) -> (PrefixSet, HashMap<H256, PrefixSet>) {
|
||||
// Initialize prefix sets.
|
||||
let mut account_prefix_set = PrefixSet::default();
|
||||
let mut storage_prefix_set: HashMap<H256, PrefixSet> = HashMap::default();
|
||||
let mut account_prefix_set = PrefixSetMut::default();
|
||||
let mut storage_prefix_set: HashMap<H256, PrefixSetMut> = HashMap::default();
|
||||
|
||||
for hashed_address in self.accounts.keys() {
|
||||
account_prefix_set.insert(Nibbles::unpack(hashed_address));
|
||||
@@ -49,7 +49,10 @@ impl HashedPostState {
|
||||
}
|
||||
}
|
||||
|
||||
(account_prefix_set, storage_prefix_set)
|
||||
(
|
||||
account_prefix_set.freeze(),
|
||||
storage_prefix_set.into_iter().map(|(k, v)| (k, v.freeze())).collect(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use super::PrefixSet;
|
||||
use super::PrefixSetMut;
|
||||
use derive_more::Deref;
|
||||
use reth_db::{
|
||||
cursor::DbCursorRO,
|
||||
@@ -29,10 +29,10 @@ where
|
||||
pub fn load(
|
||||
self,
|
||||
range: RangeInclusive<BlockNumber>,
|
||||
) -> Result<(PrefixSet, HashMap<H256, PrefixSet>), DatabaseError> {
|
||||
) -> Result<(PrefixSetMut, HashMap<H256, PrefixSetMut>), DatabaseError> {
|
||||
// Initialize prefix sets.
|
||||
let mut account_prefix_set = PrefixSet::default();
|
||||
let mut storage_prefix_set: HashMap<H256, PrefixSet> = HashMap::default();
|
||||
let mut account_prefix_set = PrefixSetMut::default();
|
||||
let mut storage_prefix_set: HashMap<H256, PrefixSetMut> = HashMap::default();
|
||||
|
||||
// Walk account changeset and insert account prefixes.
|
||||
let mut account_cursor = self.cursor_read::<tables::AccountChangeSet>()?;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use reth_primitives::trie::Nibbles;
|
||||
use std::rc::Rc;
|
||||
|
||||
mod loader;
|
||||
pub use loader::PrefixSetLoader;
|
||||
@@ -14,22 +15,22 @@ pub use loader::PrefixSetLoader;
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use reth_trie::prefix_set::PrefixSet;
|
||||
/// use reth_trie::prefix_set::PrefixSetMut;
|
||||
///
|
||||
/// let mut prefix_set = PrefixSet::default();
|
||||
/// let mut prefix_set = PrefixSetMut::default();
|
||||
/// prefix_set.insert(b"key1");
|
||||
/// prefix_set.insert(b"key2");
|
||||
///
|
||||
/// assert_eq!(prefix_set.contains(b"key"), true);
|
||||
/// ```
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct PrefixSet {
|
||||
pub struct PrefixSetMut {
|
||||
keys: Vec<Nibbles>,
|
||||
sorted: bool,
|
||||
index: usize,
|
||||
}
|
||||
|
||||
impl PrefixSet {
|
||||
impl PrefixSetMut {
|
||||
/// Returns `true` if any of the keys in the set has the given prefix or
|
||||
/// if the given prefix is a prefix of any key in the set.
|
||||
pub fn contains<T: Into<Nibbles>>(&mut self, prefix: T) -> bool {
|
||||
@@ -75,6 +76,64 @@ impl PrefixSet {
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.keys.is_empty()
|
||||
}
|
||||
|
||||
/// Returns a `PrefixSet` with the same elements as this set.
|
||||
///
|
||||
/// If not yet sorted, the elements will be sorted and deduplicated.
|
||||
pub fn freeze(mut self) -> PrefixSet {
|
||||
if !self.sorted {
|
||||
self.keys.sort();
|
||||
self.keys.dedup();
|
||||
}
|
||||
|
||||
PrefixSet { keys: Rc::new(self.keys), index: self.index }
|
||||
}
|
||||
}
|
||||
|
||||
/// A sorted prefix set that has an immutable _sorted_ list of unique keys.
|
||||
///
|
||||
/// See also [PrefixSetMut::freeze].
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct PrefixSet {
|
||||
keys: Rc<Vec<Nibbles>>,
|
||||
index: usize,
|
||||
}
|
||||
|
||||
impl PrefixSet {
|
||||
/// Returns `true` if any of the keys in the set has the given prefix or
|
||||
/// if the given prefix is a prefix of any key in the set.
|
||||
#[inline]
|
||||
pub fn contains<T: Into<Nibbles>>(&mut self, prefix: T) -> bool {
|
||||
let prefix = prefix.into();
|
||||
|
||||
while self.index > 0 && self.keys[self.index] > prefix {
|
||||
self.index -= 1;
|
||||
}
|
||||
|
||||
for (idx, key) in self.keys[self.index..].iter().enumerate() {
|
||||
if key.has_prefix(&prefix) {
|
||||
self.index += idx;
|
||||
return true
|
||||
}
|
||||
|
||||
if key > &prefix {
|
||||
self.index += idx;
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
/// Returns the number of elements in the set.
|
||||
pub fn len(&self) -> usize {
|
||||
self.keys.len()
|
||||
}
|
||||
|
||||
/// Returns `true` if the set is empty.
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.keys.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -83,7 +142,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_contains_with_multiple_inserts_and_duplicates() {
|
||||
let mut prefix_set = PrefixSet::default();
|
||||
let mut prefix_set = PrefixSetMut::default();
|
||||
prefix_set.insert(b"123");
|
||||
prefix_set.insert(b"124");
|
||||
prefix_set.insert(b"456");
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use crate::{
|
||||
account::EthAccount,
|
||||
hashed_cursor::{HashedAccountCursor, HashedCursorFactory, HashedStorageCursor},
|
||||
prefix_set::{PrefixSet, PrefixSetLoader},
|
||||
prefix_set::{PrefixSet, PrefixSetLoader, PrefixSetMut},
|
||||
progress::{IntermediateStateRootState, StateRootProgress},
|
||||
trie_cursor::{AccountTrieCursor, StorageTrieCursor},
|
||||
updates::{TrieKey, TrieOp, TrieUpdates},
|
||||
@@ -90,7 +90,7 @@ where
|
||||
pub fn new(tx: &'a TX) -> Self {
|
||||
Self {
|
||||
tx,
|
||||
changed_account_prefixes: PrefixSet::default(),
|
||||
changed_account_prefixes: PrefixSetMut::default().freeze(),
|
||||
changed_storage_prefixes: HashMap::default(),
|
||||
previous_state: None,
|
||||
threshold: 100_000,
|
||||
@@ -110,8 +110,10 @@ where
|
||||
) -> Result<Self, StateRootError> {
|
||||
let (account_prefixes, storage_prefixes) = PrefixSetLoader::new(tx).load(range)?;
|
||||
Ok(Self::new(tx)
|
||||
.with_changed_account_prefixes(account_prefixes)
|
||||
.with_changed_storage_prefixes(storage_prefixes))
|
||||
.with_changed_account_prefixes(account_prefixes.freeze())
|
||||
.with_changed_storage_prefixes(
|
||||
storage_prefixes.into_iter().map(|(k, v)| (k, v.freeze())).collect(),
|
||||
))
|
||||
}
|
||||
|
||||
/// Computes the state root of the trie with the changed account and storage prefixes and
|
||||
@@ -371,7 +373,7 @@ where
|
||||
Self {
|
||||
tx,
|
||||
hashed_address,
|
||||
changed_prefixes: PrefixSet::default(),
|
||||
changed_prefixes: PrefixSetMut::default().freeze(),
|
||||
hashed_cursor_factory: tx,
|
||||
}
|
||||
}
|
||||
@@ -389,7 +391,12 @@ impl<'a, 'b, TX, H> StorageRoot<'a, 'b, TX, H> {
|
||||
hashed_cursor_factory: &'b H,
|
||||
hashed_address: H256,
|
||||
) -> Self {
|
||||
Self { tx, hashed_address, changed_prefixes: PrefixSet::default(), hashed_cursor_factory }
|
||||
Self {
|
||||
tx,
|
||||
hashed_address,
|
||||
changed_prefixes: PrefixSetMut::default().freeze(),
|
||||
hashed_cursor_factory,
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the changed prefixes.
|
||||
@@ -591,10 +598,10 @@ mod tests {
|
||||
trie_updates.flush(tx.tx_ref()).unwrap();
|
||||
|
||||
// 3. Calculate the incremental root
|
||||
let mut storage_changes = PrefixSet::default();
|
||||
let mut storage_changes = PrefixSetMut::default();
|
||||
storage_changes.insert(Nibbles::unpack(modified_key));
|
||||
let loader = StorageRoot::new_hashed(tx.tx_ref(), hashed_address)
|
||||
.with_changed_prefixes(storage_changes);
|
||||
.with_changed_prefixes(storage_changes.freeze());
|
||||
let incremental_root = loader.root().unwrap();
|
||||
|
||||
assert_eq!(modified_root, incremental_root);
|
||||
@@ -1014,7 +1021,7 @@ mod tests {
|
||||
Account { nonce: 0, balance: U256::from(5).mul(ether), bytecode_hash: None };
|
||||
hashed_account_cursor.upsert(key4b, account4b).unwrap();
|
||||
|
||||
let mut prefix_set = PrefixSet::default();
|
||||
let mut prefix_set = PrefixSetMut::default();
|
||||
prefix_set.insert(Nibbles::unpack(key4b));
|
||||
|
||||
let expected_state_root =
|
||||
@@ -1022,7 +1029,7 @@ mod tests {
|
||||
.unwrap();
|
||||
|
||||
let (root, trie_updates) = StateRoot::new(tx.tx_ref())
|
||||
.with_changed_account_prefixes(prefix_set)
|
||||
.with_changed_account_prefixes(prefix_set.freeze())
|
||||
.root_with_updates()
|
||||
.unwrap();
|
||||
assert_eq!(root, expected_state_root);
|
||||
@@ -1060,7 +1067,7 @@ mod tests {
|
||||
let account = hashed_account_cursor.seek_exact(key2).unwrap().unwrap();
|
||||
hashed_account_cursor.delete_current().unwrap();
|
||||
|
||||
let mut account_prefix_set = PrefixSet::default();
|
||||
let mut account_prefix_set = PrefixSetMut::default();
|
||||
account_prefix_set.insert(Nibbles::unpack(account.0));
|
||||
|
||||
let computed_expected_root: H256 = triehash::trie_root::<KeccakHasher, _, _, _>([
|
||||
@@ -1074,7 +1081,7 @@ mod tests {
|
||||
]);
|
||||
|
||||
let (root, trie_updates) = StateRoot::new(tx.tx_ref())
|
||||
.with_changed_account_prefixes(account_prefix_set)
|
||||
.with_changed_account_prefixes(account_prefix_set.freeze())
|
||||
.root_with_updates()
|
||||
.unwrap();
|
||||
assert_eq!(root, computed_expected_root);
|
||||
@@ -1116,7 +1123,7 @@ mod tests {
|
||||
let account3 = hashed_account_cursor.seek_exact(key3).unwrap().unwrap();
|
||||
hashed_account_cursor.delete_current().unwrap();
|
||||
|
||||
let mut account_prefix_set = PrefixSet::default();
|
||||
let mut account_prefix_set = PrefixSetMut::default();
|
||||
account_prefix_set.insert(Nibbles::unpack(account2.0));
|
||||
account_prefix_set.insert(Nibbles::unpack(account3.0));
|
||||
|
||||
@@ -1131,7 +1138,7 @@ mod tests {
|
||||
]);
|
||||
|
||||
let (root, trie_updates) = StateRoot::new(tx.tx_ref())
|
||||
.with_changed_account_prefixes(account_prefix_set)
|
||||
.with_changed_account_prefixes(account_prefix_set.freeze())
|
||||
.root_with_updates()
|
||||
.unwrap();
|
||||
assert_eq!(root, computed_expected_root);
|
||||
@@ -1227,7 +1234,7 @@ mod tests {
|
||||
let mut state = BTreeMap::default();
|
||||
for accounts in account_changes {
|
||||
let should_generate_changeset = !state.is_empty();
|
||||
let mut changes = PrefixSet::default();
|
||||
let mut changes = PrefixSetMut::default();
|
||||
for (hashed_address, balance) in accounts.clone() {
|
||||
hashed_account_cursor.upsert(hashed_address, Account { balance,..Default::default() }).unwrap();
|
||||
if should_generate_changeset {
|
||||
@@ -1236,7 +1243,7 @@ mod tests {
|
||||
}
|
||||
|
||||
let (state_root, trie_updates) = StateRoot::new(tx.tx_ref())
|
||||
.with_changed_account_prefixes(changes)
|
||||
.with_changed_account_prefixes(changes.freeze())
|
||||
.root_with_updates()
|
||||
.unwrap();
|
||||
|
||||
|
||||
@@ -256,7 +256,10 @@ impl<'a, K: Key + From<Vec<u8>>, C: TrieCursor<K>> TrieWalker<'a, K, C> {
|
||||
mod tests {
|
||||
|
||||
use super::*;
|
||||
use crate::trie_cursor::{AccountTrieCursor, StorageTrieCursor};
|
||||
use crate::{
|
||||
prefix_set::PrefixSetMut,
|
||||
trie_cursor::{AccountTrieCursor, StorageTrieCursor},
|
||||
};
|
||||
use reth_db::{
|
||||
cursor::DbCursorRW, tables, test_utils::create_test_rw_db, transaction::DbTxMut,
|
||||
};
|
||||
@@ -378,9 +381,9 @@ mod tests {
|
||||
assert_eq!(cursor.key(), None);
|
||||
|
||||
// We insert something that's not part of the existing trie/prefix.
|
||||
let mut changed = PrefixSet::default();
|
||||
let mut changed = PrefixSetMut::default();
|
||||
changed.insert(&[0xF, 0x1]);
|
||||
let mut cursor = TrieWalker::new(&mut trie, changed);
|
||||
let mut cursor = TrieWalker::new(&mut trie, changed.freeze());
|
||||
|
||||
// Root node
|
||||
assert_eq!(cursor.key(), Some(Nibbles::from_hex(vec![])));
|
||||
|
||||
Reference in New Issue
Block a user