mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
refactor(trie): hashed state (#6244)
This commit is contained in:
@ -25,7 +25,7 @@ use reth_provider::{
|
||||
StorageReader,
|
||||
};
|
||||
use reth_tasks::TaskExecutor;
|
||||
use reth_trie::{hashed_cursor::HashedPostStateCursorFactory, updates::TrieKey, StateRoot};
|
||||
use reth_trie::{updates::TrieKey, StateRoot};
|
||||
use std::{
|
||||
net::{SocketAddr, SocketAddrV4},
|
||||
path::PathBuf,
|
||||
@ -181,15 +181,8 @@ impl Command {
|
||||
let block_state = executor.take_output_state();
|
||||
|
||||
// Unpacked `BundleState::state_root_slow` function
|
||||
let hashed_post_state = block_state.hash_state_slow().sorted();
|
||||
let (account_prefix_set, storage_prefix_set) = hashed_post_state.construct_prefix_sets();
|
||||
let tx = provider.tx_ref();
|
||||
let hashed_cursor_factory = HashedPostStateCursorFactory::new(tx, &hashed_post_state);
|
||||
let (in_memory_state_root, in_memory_updates) = StateRoot::from_tx(tx)
|
||||
.with_hashed_cursor_factory(hashed_cursor_factory)
|
||||
.with_changed_account_prefixes(account_prefix_set)
|
||||
.with_changed_storage_prefixes(storage_prefix_set)
|
||||
.root_with_updates()?;
|
||||
let (in_memory_state_root, in_memory_updates) =
|
||||
block_state.hash_state_slow().state_root_with_updates(provider.tx_ref())?;
|
||||
|
||||
if in_memory_state_root == block.state_root {
|
||||
info!(target: "reth::cli", state_root = ?in_memory_state_root, "Computed in-memory state root matches");
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
use itertools::Itertools;
|
||||
use reth_db::{
|
||||
cursor::{DbCursorRO, DbCursorRW, DbDupCursorRO, DbDupCursorRW},
|
||||
tables,
|
||||
transaction::{DbTx, DbTxMut},
|
||||
DatabaseError,
|
||||
};
|
||||
use reth_primitives::{Account, StorageEntry, B256, U256};
|
||||
use reth_primitives::{StorageEntry, U256};
|
||||
use reth_trie::HashedPostState;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
/// Changes to the hashed state.
|
||||
#[derive(Debug, Default)]
|
||||
@ -15,15 +15,10 @@ pub struct HashedStateChanges(pub HashedPostState);
|
||||
impl HashedStateChanges {
|
||||
/// Write the bundle state to the database.
|
||||
pub fn write_to_db<TX: DbTxMut + DbTx>(self, tx: &TX) -> Result<(), DatabaseError> {
|
||||
// Collect hashed account changes.
|
||||
let mut hashed_accounts = BTreeMap::<B256, Option<Account>>::default();
|
||||
for (hashed_address, account) in self.0.accounts() {
|
||||
hashed_accounts.insert(hashed_address, account);
|
||||
}
|
||||
|
||||
// Write hashed account updates.
|
||||
let sorted_accounts = self.0.accounts.into_iter().sorted_unstable_by_key(|(key, _)| *key);
|
||||
let mut hashed_accounts_cursor = tx.cursor_write::<tables::HashedAccount>()?;
|
||||
for (hashed_address, account) in hashed_accounts {
|
||||
for (hashed_address, account) in sorted_accounts {
|
||||
if let Some(account) = account {
|
||||
hashed_accounts_cursor.upsert(hashed_address, account)?;
|
||||
} else if hashed_accounts_cursor.seek_exact(hashed_address)?.is_some() {
|
||||
@ -31,24 +26,16 @@ impl HashedStateChanges {
|
||||
}
|
||||
}
|
||||
|
||||
// Collect hashed storage changes.
|
||||
let mut hashed_storages = BTreeMap::<B256, (bool, BTreeMap<B256, U256>)>::default();
|
||||
for (hashed_address, storage) in self.0.storages() {
|
||||
let entry = hashed_storages.entry(*hashed_address).or_default();
|
||||
entry.0 |= storage.wiped();
|
||||
for (hashed_slot, value) in storage.storage_slots() {
|
||||
entry.1.insert(hashed_slot, value);
|
||||
}
|
||||
}
|
||||
|
||||
// Write hashed storage changes.
|
||||
let sorted_storages = self.0.storages.into_iter().sorted_by_key(|(key, _)| *key);
|
||||
let mut hashed_storage_cursor = tx.cursor_dup_write::<tables::HashedStorage>()?;
|
||||
for (hashed_address, (wiped, storage)) in hashed_storages {
|
||||
if wiped && hashed_storage_cursor.seek_exact(hashed_address)?.is_some() {
|
||||
for (hashed_address, storage) in sorted_storages {
|
||||
if storage.wiped && hashed_storage_cursor.seek_exact(hashed_address)?.is_some() {
|
||||
hashed_storage_cursor.delete_current_duplicates()?;
|
||||
}
|
||||
|
||||
for (hashed_slot, value) in storage {
|
||||
let sorted_storage = storage.storage.into_iter().sorted_by_key(|(key, _)| *key);
|
||||
for (hashed_slot, value) in sorted_storage {
|
||||
let entry = StorageEntry { key: hashed_slot, value };
|
||||
if let Some(db_entry) =
|
||||
hashed_storage_cursor.seek_by_key_subkey(hashed_address, entry.key)?
|
||||
@ -72,7 +59,7 @@ impl HashedStateChanges {
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::test_utils::create_test_provider_factory;
|
||||
use reth_primitives::{keccak256, Address};
|
||||
use reth_primitives::{keccak256, Account, Address, B256};
|
||||
use reth_trie::HashedStorage;
|
||||
|
||||
#[test]
|
||||
@ -104,8 +91,8 @@ mod tests {
|
||||
}
|
||||
|
||||
let mut hashed_state = HashedPostState::default();
|
||||
hashed_state.insert_account(destroyed_address_hashed, None);
|
||||
hashed_state.insert_hashed_storage(destroyed_address_hashed, HashedStorage::new(true));
|
||||
hashed_state.accounts.insert(destroyed_address_hashed, None);
|
||||
hashed_state.storages.insert(destroyed_address_hashed, HashedStorage::new(true));
|
||||
|
||||
let provider_rw = provider_factory.provider_rw().unwrap();
|
||||
assert_eq!(HashedStateChanges(hashed_state).write_to_db(provider_rw.tx_ref()), Ok(()));
|
||||
|
||||
@ -228,7 +228,6 @@ impl<'b, TX: DbTx> StateRootProvider for HistoricalStateProviderRef<'b, TX> {
|
||||
fn state_root(&self, state: &BundleStateWithReceipts) -> ProviderResult<B256> {
|
||||
let mut revert_state = self.revert_state()?;
|
||||
revert_state.extend(state.hash_state_slow());
|
||||
revert_state.sort();
|
||||
revert_state.state_root(self.tx).map_err(|err| ProviderError::Database(err.into()))
|
||||
}
|
||||
|
||||
@ -238,7 +237,6 @@ impl<'b, TX: DbTx> StateRootProvider for HistoricalStateProviderRef<'b, TX> {
|
||||
) -> ProviderResult<(B256, TrieUpdates)> {
|
||||
let mut revert_state = self.revert_state()?;
|
||||
revert_state.extend(state.hash_state_slow());
|
||||
revert_state.sort();
|
||||
revert_state
|
||||
.state_root_with_updates(self.tx)
|
||||
.map_err(|err| ProviderError::Database(err.into()))
|
||||
|
||||
@ -1,17 +1,17 @@
|
||||
use super::{HashedAccountCursor, HashedCursorFactory, HashedStorageCursor};
|
||||
use crate::state::HashedPostState;
|
||||
use crate::state::HashedPostStateSorted;
|
||||
use reth_primitives::{Account, StorageEntry, B256, U256};
|
||||
|
||||
/// The hashed cursor factory for the post state.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct HashedPostStateCursorFactory<'a, CF> {
|
||||
cursor_factory: CF,
|
||||
post_state: &'a HashedPostState,
|
||||
post_state: &'a HashedPostStateSorted,
|
||||
}
|
||||
|
||||
impl<'a, CF> HashedPostStateCursorFactory<'a, CF> {
|
||||
/// Create a new factory.
|
||||
pub fn new(cursor_factory: CF, post_state: &'a HashedPostState) -> Self {
|
||||
pub fn new(cursor_factory: CF, post_state: &'a HashedPostStateSorted) -> Self {
|
||||
Self { cursor_factory, post_state }
|
||||
}
|
||||
}
|
||||
@ -37,8 +37,8 @@ impl<'a, CF: HashedCursorFactory> HashedCursorFactory for HashedPostStateCursorF
|
||||
pub struct HashedPostStateAccountCursor<'b, C> {
|
||||
/// The database cursor.
|
||||
cursor: C,
|
||||
/// The reference to the in-memory [HashedPostState].
|
||||
post_state: &'b HashedPostState,
|
||||
/// The reference to the in-memory [HashedPostStateSorted].
|
||||
post_state: &'b HashedPostStateSorted,
|
||||
/// The post state account index where the cursor is currently at.
|
||||
post_state_account_index: usize,
|
||||
/// The last hashed account that was returned by the cursor.
|
||||
@ -48,7 +48,7 @@ pub struct HashedPostStateAccountCursor<'b, C> {
|
||||
|
||||
impl<'b, C> HashedPostStateAccountCursor<'b, C> {
|
||||
/// Create new instance of [HashedPostStateAccountCursor].
|
||||
pub fn new(cursor: C, post_state: &'b HashedPostState) -> Self {
|
||||
pub fn new(cursor: C, post_state: &'b HashedPostStateSorted) -> Self {
|
||||
Self { cursor, post_state, last_account: None, post_state_account_index: 0 }
|
||||
}
|
||||
|
||||
@ -98,8 +98,6 @@ where
|
||||
/// The returned account key is memoized and the cursor remains positioned at that key until
|
||||
/// [HashedAccountCursor::seek] or [HashedAccountCursor::next] are called.
|
||||
fn seek(&mut self, key: B256) -> Result<Option<(B256, Account)>, reth_db::DatabaseError> {
|
||||
debug_assert!(self.post_state.sorted, "`HashedPostState` must be pre-sorted");
|
||||
|
||||
self.last_account = None;
|
||||
|
||||
// Take the next account from the post state with the key greater than or equal to the
|
||||
@ -144,8 +142,6 @@ where
|
||||
/// NOTE: This function will not return any entry unless [HashedAccountCursor::seek] has been
|
||||
/// called.
|
||||
fn next(&mut self) -> Result<Option<(B256, Account)>, reth_db::DatabaseError> {
|
||||
debug_assert!(self.post_state.sorted, "`HashedPostState` must be pre-sorted");
|
||||
|
||||
let last_account = match self.last_account.as_ref() {
|
||||
Some(account) => account,
|
||||
None => return Ok(None), // no previous entry was found
|
||||
@ -182,7 +178,7 @@ pub struct HashedPostStateStorageCursor<'b, C> {
|
||||
/// The database cursor.
|
||||
cursor: C,
|
||||
/// The reference to the post state.
|
||||
post_state: &'b HashedPostState,
|
||||
post_state: &'b HashedPostStateSorted,
|
||||
/// The post state index where the cursor is currently at.
|
||||
post_state_storage_index: usize,
|
||||
/// The current hashed account key.
|
||||
@ -194,7 +190,7 @@ pub struct HashedPostStateStorageCursor<'b, C> {
|
||||
|
||||
impl<'b, C> HashedPostStateStorageCursor<'b, C> {
|
||||
/// Create new instance of [HashedPostStateStorageCursor].
|
||||
pub fn new(cursor: C, post_state: &'b HashedPostState) -> Self {
|
||||
pub fn new(cursor: C, post_state: &'b HashedPostStateSorted) -> Self {
|
||||
Self { cursor, post_state, account: None, last_slot: None, post_state_storage_index: 0 }
|
||||
}
|
||||
|
||||
@ -279,8 +275,6 @@ where
|
||||
// Attempt to find the account's storage in post state.
|
||||
let mut post_state_entry = None;
|
||||
if let Some(storage) = self.post_state.storages.get(&account) {
|
||||
debug_assert!(storage.sorted, "`HashedStorage` must be pre-sorted");
|
||||
|
||||
post_state_entry = storage.non_zero_valued_slots.get(self.post_state_storage_index);
|
||||
|
||||
while post_state_entry.map(|(slot, _)| slot < &subkey).unwrap_or_default() {
|
||||
@ -358,8 +352,6 @@ where
|
||||
// Attempt to find the account's storage in post state.
|
||||
let mut post_state_entry = None;
|
||||
if let Some(storage) = self.post_state.storages.get(&account) {
|
||||
debug_assert!(storage.sorted, "`HashedStorage` must be pre-sorted");
|
||||
|
||||
post_state_entry = storage.non_zero_valued_slots.get(self.post_state_storage_index);
|
||||
while post_state_entry.map(|(slot, _)| slot <= last_slot).unwrap_or_default() {
|
||||
self.post_state_storage_index += 1;
|
||||
@ -376,9 +368,8 @@ where
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::HashedStorage;
|
||||
|
||||
use super::*;
|
||||
use crate::{HashedPostState, HashedStorage};
|
||||
use proptest::prelude::*;
|
||||
use reth_db::{
|
||||
database::Database, tables, test_utils::create_test_rw_db, transaction::DbTxMut,
|
||||
@ -430,14 +421,14 @@ mod tests {
|
||||
|
||||
let mut hashed_post_state = HashedPostState::default();
|
||||
for (hashed_address, account) in &accounts {
|
||||
hashed_post_state.insert_account(*hashed_address, Some(*account));
|
||||
hashed_post_state.accounts.insert(*hashed_address, Some(*account));
|
||||
}
|
||||
hashed_post_state.sort();
|
||||
|
||||
let db = create_test_rw_db();
|
||||
let tx = db.tx().unwrap();
|
||||
|
||||
let factory = HashedPostStateCursorFactory::new(&tx, &hashed_post_state);
|
||||
let sorted = hashed_post_state.into_sorted();
|
||||
let tx = db.tx().unwrap();
|
||||
let factory = HashedPostStateCursorFactory::new(&tx, &sorted);
|
||||
assert_account_cursor_order(&factory, accounts.into_iter());
|
||||
}
|
||||
|
||||
@ -454,9 +445,9 @@ mod tests {
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
let sorted_post_state = HashedPostState::default().into_sorted();
|
||||
let tx = db.tx().unwrap();
|
||||
let post_state = HashedPostState::default();
|
||||
let factory = HashedPostStateCursorFactory::new(&tx, &post_state);
|
||||
let factory = HashedPostStateCursorFactory::new(&tx, &sorted_post_state);
|
||||
assert_account_cursor_order(&factory, accounts.into_iter());
|
||||
}
|
||||
|
||||
@ -476,12 +467,12 @@ mod tests {
|
||||
|
||||
let mut hashed_post_state = HashedPostState::default();
|
||||
for (hashed_address, account) in accounts.iter().filter(|x| x.0[31] % 2 != 0) {
|
||||
hashed_post_state.insert_account(*hashed_address, Some(*account));
|
||||
hashed_post_state.accounts.insert(*hashed_address, Some(*account));
|
||||
}
|
||||
hashed_post_state.sort();
|
||||
|
||||
let sorted = hashed_post_state.into_sorted();
|
||||
let tx = db.tx().unwrap();
|
||||
let factory = HashedPostStateCursorFactory::new(&tx, &hashed_post_state);
|
||||
let factory = HashedPostStateCursorFactory::new(&tx, &sorted);
|
||||
assert_account_cursor_order(&factory, accounts.into_iter());
|
||||
}
|
||||
|
||||
@ -503,14 +494,15 @@ mod tests {
|
||||
|
||||
let mut hashed_post_state = HashedPostState::default();
|
||||
for (hashed_address, account) in accounts.iter().filter(|x| x.0[31] % 2 != 0) {
|
||||
let account_info =
|
||||
if removed_keys.contains(hashed_address) { None } else { Some(*account) };
|
||||
hashed_post_state.insert_account(*hashed_address, account_info)
|
||||
hashed_post_state.accounts.insert(
|
||||
*hashed_address,
|
||||
if removed_keys.contains(hashed_address) { None } else { Some(*account) },
|
||||
);
|
||||
}
|
||||
hashed_post_state.sort();
|
||||
|
||||
let sorted = hashed_post_state.into_sorted();
|
||||
let tx = db.tx().unwrap();
|
||||
let factory = HashedPostStateCursorFactory::new(&tx, &hashed_post_state);
|
||||
let factory = HashedPostStateCursorFactory::new(&tx, &sorted);
|
||||
let expected = accounts.into_iter().filter(|x| !removed_keys.contains(&x.0));
|
||||
assert_account_cursor_order(&factory, expected);
|
||||
}
|
||||
@ -532,12 +524,12 @@ mod tests {
|
||||
|
||||
let mut hashed_post_state = HashedPostState::default();
|
||||
for (hashed_address, account) in &accounts {
|
||||
hashed_post_state.insert_account(*hashed_address, Some(*account));
|
||||
hashed_post_state.accounts.insert(*hashed_address, Some(*account));
|
||||
}
|
||||
hashed_post_state.sort();
|
||||
|
||||
let sorted = hashed_post_state.into_sorted();
|
||||
let tx = db.tx().unwrap();
|
||||
let factory = HashedPostStateCursorFactory::new(&tx, &hashed_post_state);
|
||||
let factory = HashedPostStateCursorFactory::new(&tx, &sorted);
|
||||
assert_account_cursor_order(&factory, accounts.into_iter());
|
||||
}
|
||||
|
||||
@ -554,9 +546,8 @@ mod tests {
|
||||
|
||||
let mut hashed_post_state = HashedPostState::default();
|
||||
for (hashed_address, account) in &post_state_accounts {
|
||||
hashed_post_state.insert_account(*hashed_address, *account);
|
||||
hashed_post_state.accounts.insert(*hashed_address, *account);
|
||||
}
|
||||
hashed_post_state.sort();
|
||||
|
||||
let mut expected = db_accounts;
|
||||
// overwrite or remove accounts from the expected result
|
||||
@ -568,8 +559,9 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
let sorted = hashed_post_state.into_sorted();
|
||||
let tx = db.tx().unwrap();
|
||||
let factory = HashedPostStateCursorFactory::new(&tx, &hashed_post_state);
|
||||
let factory = HashedPostStateCursorFactory::new(&tx, &sorted);
|
||||
assert_account_cursor_order(&factory, expected.into_iter());
|
||||
}
|
||||
);
|
||||
@ -582,9 +574,9 @@ mod tests {
|
||||
|
||||
// empty from the get go
|
||||
{
|
||||
let post_state = HashedPostState::default();
|
||||
let sorted = HashedPostState::default().into_sorted();
|
||||
let tx = db.tx().unwrap();
|
||||
let factory = HashedPostStateCursorFactory::new(&tx, &post_state);
|
||||
let factory = HashedPostStateCursorFactory::new(&tx, &sorted);
|
||||
let mut cursor = factory.hashed_storage_cursor().unwrap();
|
||||
assert!(cursor.is_storage_empty(address).unwrap());
|
||||
}
|
||||
@ -605,9 +597,9 @@ mod tests {
|
||||
|
||||
// not empty
|
||||
{
|
||||
let post_state = HashedPostState::default();
|
||||
let sorted = HashedPostState::default().into_sorted();
|
||||
let tx = db.tx().unwrap();
|
||||
let factory = HashedPostStateCursorFactory::new(&tx, &post_state);
|
||||
let factory = HashedPostStateCursorFactory::new(&tx, &sorted);
|
||||
let mut cursor = factory.hashed_storage_cursor().unwrap();
|
||||
assert!(!cursor.is_storage_empty(address).unwrap());
|
||||
}
|
||||
@ -618,10 +610,11 @@ mod tests {
|
||||
let hashed_storage = HashedStorage::new(wiped);
|
||||
|
||||
let mut hashed_post_state = HashedPostState::default();
|
||||
hashed_post_state.insert_hashed_storage(address, hashed_storage);
|
||||
hashed_post_state.storages.insert(address, hashed_storage);
|
||||
|
||||
let sorted = hashed_post_state.into_sorted();
|
||||
let tx = db.tx().unwrap();
|
||||
let factory = HashedPostStateCursorFactory::new(&tx, &hashed_post_state);
|
||||
let factory = HashedPostStateCursorFactory::new(&tx, &sorted);
|
||||
let mut cursor = factory.hashed_storage_cursor().unwrap();
|
||||
assert!(cursor.is_storage_empty(address).unwrap());
|
||||
}
|
||||
@ -630,13 +623,14 @@ mod tests {
|
||||
{
|
||||
let wiped = true;
|
||||
let mut hashed_storage = HashedStorage::new(wiped);
|
||||
hashed_storage.insert_slot(B256::random(), U256::ZERO);
|
||||
hashed_storage.storage.insert(B256::random(), U256::ZERO);
|
||||
|
||||
let mut hashed_post_state = HashedPostState::default();
|
||||
hashed_post_state.insert_hashed_storage(address, hashed_storage);
|
||||
hashed_post_state.storages.insert(address, hashed_storage);
|
||||
|
||||
let sorted = hashed_post_state.into_sorted();
|
||||
let tx = db.tx().unwrap();
|
||||
let factory = HashedPostStateCursorFactory::new(&tx, &hashed_post_state);
|
||||
let factory = HashedPostStateCursorFactory::new(&tx, &sorted);
|
||||
let mut cursor = factory.hashed_storage_cursor().unwrap();
|
||||
assert!(cursor.is_storage_empty(address).unwrap());
|
||||
}
|
||||
@ -645,13 +639,14 @@ mod tests {
|
||||
{
|
||||
let wiped = true;
|
||||
let mut hashed_storage = HashedStorage::new(wiped);
|
||||
hashed_storage.insert_slot(B256::random(), U256::from(1));
|
||||
hashed_storage.storage.insert(B256::random(), U256::from(1));
|
||||
|
||||
let mut hashed_post_state = HashedPostState::default();
|
||||
hashed_post_state.insert_hashed_storage(address, hashed_storage);
|
||||
hashed_post_state.storages.insert(address, hashed_storage);
|
||||
|
||||
let sorted = hashed_post_state.into_sorted();
|
||||
let tx = db.tx().unwrap();
|
||||
let factory = HashedPostStateCursorFactory::new(&tx, &hashed_post_state);
|
||||
let factory = HashedPostStateCursorFactory::new(&tx, &sorted);
|
||||
let mut cursor = factory.hashed_storage_cursor().unwrap();
|
||||
assert!(!cursor.is_storage_empty(address).unwrap());
|
||||
}
|
||||
@ -681,15 +676,15 @@ mod tests {
|
||||
let wiped = false;
|
||||
let mut hashed_storage = HashedStorage::new(wiped);
|
||||
for (slot, value) in post_state_storage.iter() {
|
||||
hashed_storage.insert_slot(*slot, *value);
|
||||
hashed_storage.storage.insert(*slot, *value);
|
||||
}
|
||||
|
||||
let mut hashed_post_state = HashedPostState::default();
|
||||
hashed_post_state.insert_hashed_storage(address, hashed_storage);
|
||||
hashed_post_state.sort();
|
||||
hashed_post_state.storages.insert(address, hashed_storage);
|
||||
|
||||
let sorted = hashed_post_state.into_sorted();
|
||||
let tx = db.tx().unwrap();
|
||||
let factory = HashedPostStateCursorFactory::new(&tx, &hashed_post_state);
|
||||
let factory = HashedPostStateCursorFactory::new(&tx, &sorted);
|
||||
let expected =
|
||||
[(address, db_storage.into_iter().chain(post_state_storage).collect())].into_iter();
|
||||
assert_storage_cursor_order(&factory, expected);
|
||||
@ -717,15 +712,15 @@ mod tests {
|
||||
let wiped = false;
|
||||
let mut hashed_storage = HashedStorage::new(wiped);
|
||||
for (slot, value) in post_state_storage.iter() {
|
||||
hashed_storage.insert_slot(*slot, *value);
|
||||
hashed_storage.storage.insert(*slot, *value);
|
||||
}
|
||||
|
||||
let mut hashed_post_state = HashedPostState::default();
|
||||
hashed_post_state.insert_hashed_storage(address, hashed_storage);
|
||||
hashed_post_state.sort();
|
||||
hashed_post_state.storages.insert(address, hashed_storage);
|
||||
|
||||
let sorted = hashed_post_state.into_sorted();
|
||||
let tx = db.tx().unwrap();
|
||||
let factory = HashedPostStateCursorFactory::new(&tx, &hashed_post_state);
|
||||
let factory = HashedPostStateCursorFactory::new(&tx, &sorted);
|
||||
let expected = [(
|
||||
address,
|
||||
post_state_storage.into_iter().filter(|(_, value)| *value > U256::ZERO).collect(),
|
||||
@ -755,15 +750,15 @@ mod tests {
|
||||
let wiped = true;
|
||||
let mut hashed_storage = HashedStorage::new(wiped);
|
||||
for (slot, value) in post_state_storage.iter() {
|
||||
hashed_storage.insert_slot(*slot, *value);
|
||||
hashed_storage.storage.insert(*slot, *value);
|
||||
}
|
||||
|
||||
let mut hashed_post_state = HashedPostState::default();
|
||||
hashed_post_state.insert_hashed_storage(address, hashed_storage);
|
||||
hashed_post_state.sort();
|
||||
hashed_post_state.storages.insert(address, hashed_storage);
|
||||
|
||||
let sorted = hashed_post_state.into_sorted();
|
||||
let tx = db.tx().unwrap();
|
||||
let factory = HashedPostStateCursorFactory::new(&tx, &hashed_post_state);
|
||||
let factory = HashedPostStateCursorFactory::new(&tx, &sorted);
|
||||
let expected = [(address, post_state_storage)].into_iter();
|
||||
assert_storage_cursor_order(&factory, expected);
|
||||
}
|
||||
@ -790,15 +785,15 @@ mod tests {
|
||||
let wiped = false;
|
||||
let mut hashed_storage = HashedStorage::new(wiped);
|
||||
for (slot, value) in storage.iter() {
|
||||
hashed_storage.insert_slot(*slot, *value);
|
||||
hashed_storage.storage.insert(*slot, *value);
|
||||
}
|
||||
|
||||
let mut hashed_post_state = HashedPostState::default();
|
||||
hashed_post_state.insert_hashed_storage(address, hashed_storage);
|
||||
hashed_post_state.sort();
|
||||
hashed_post_state.storages.insert(address, hashed_storage);
|
||||
|
||||
let sorted = hashed_post_state.into_sorted();
|
||||
let tx = db.tx().unwrap();
|
||||
let factory = HashedPostStateCursorFactory::new(&tx, &hashed_post_state);
|
||||
let factory = HashedPostStateCursorFactory::new(&tx, &sorted);
|
||||
let expected = [(address, storage)].into_iter();
|
||||
assert_storage_cursor_order(&factory, expected);
|
||||
}
|
||||
@ -827,12 +822,11 @@ mod tests {
|
||||
for (address, (wiped, storage)) in &post_state_storages {
|
||||
let mut hashed_storage = HashedStorage::new(*wiped);
|
||||
for (slot, value) in storage {
|
||||
hashed_storage.insert_slot(*slot, *value);
|
||||
hashed_storage.storage.insert(*slot, *value);
|
||||
}
|
||||
hashed_post_state.insert_hashed_storage(*address, hashed_storage);
|
||||
hashed_post_state.storages.insert(*address, hashed_storage);
|
||||
}
|
||||
|
||||
hashed_post_state.sort();
|
||||
|
||||
let mut expected = db_storages;
|
||||
// overwrite or remove accounts from the expected result
|
||||
@ -844,8 +838,9 @@ mod tests {
|
||||
entry.extend(storage);
|
||||
}
|
||||
|
||||
let sorted = hashed_post_state.into_sorted();
|
||||
let tx = db.tx().unwrap();
|
||||
let factory = HashedPostStateCursorFactory::new(&tx, &hashed_post_state);
|
||||
let factory = HashedPostStateCursorFactory::new(&tx, &sorted);
|
||||
assert_storage_cursor_order(&factory, expected.into_iter());
|
||||
});
|
||||
}
|
||||
|
||||
@ -34,7 +34,7 @@ pub(crate) mod node_iter;
|
||||
|
||||
/// In-memory hashed state.
|
||||
mod state;
|
||||
pub use state::{HashedPostState, HashedStorage};
|
||||
pub use state::*;
|
||||
|
||||
/// Merkle proof generation.
|
||||
pub mod proof;
|
||||
|
||||
@ -22,28 +22,13 @@ use std::{
|
||||
ops::RangeInclusive,
|
||||
};
|
||||
|
||||
/// The post state with hashed addresses as keys.
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
/// Representation of in-memory hashed state.
|
||||
#[derive(PartialEq, Eq, Clone, Default, Debug)]
|
||||
pub struct HashedPostState {
|
||||
/// Collection of hashed addresses and their account info.
|
||||
pub(crate) accounts: Vec<(B256, Account)>,
|
||||
/// Set of destroyed account keys.
|
||||
pub(crate) destroyed_accounts: AHashSet<B256>,
|
||||
/// Map of hashed addresses to hashed storage.
|
||||
pub(crate) storages: AHashMap<B256, HashedStorage>,
|
||||
/// Flag indicating whether the account and storage entries were sorted.
|
||||
pub(crate) sorted: bool,
|
||||
}
|
||||
|
||||
impl Default for HashedPostState {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
accounts: Vec::new(),
|
||||
destroyed_accounts: AHashSet::new(),
|
||||
storages: AHashMap::new(),
|
||||
sorted: true, // empty is sorted
|
||||
}
|
||||
}
|
||||
/// Mapping of hashed address to account info, `None` if destroyed.
|
||||
pub accounts: AHashMap<B256, Option<Account>>,
|
||||
/// Mapping of hashed address to hashed storage.
|
||||
pub storages: AHashMap<B256, HashedStorage>,
|
||||
}
|
||||
|
||||
impl HashedPostState {
|
||||
@ -54,21 +39,19 @@ impl HashedPostState {
|
||||
state: impl IntoIterator<Item = (&'a Address, &'a BundleAccount)>,
|
||||
) -> Self {
|
||||
let mut this = Self::default();
|
||||
|
||||
for (address, account) in state {
|
||||
let hashed_address = keccak256(address);
|
||||
this.insert_account(hashed_address, account.info.clone().map(into_reth_acc));
|
||||
this.accounts.insert(hashed_address, account.info.clone().map(into_reth_acc));
|
||||
|
||||
// insert storage.
|
||||
let mut hashed_storage = HashedStorage::new(account.status.was_destroyed());
|
||||
|
||||
for (key, value) in account.storage.iter() {
|
||||
let hashed_key = keccak256(B256::new(key.to_be_bytes()));
|
||||
hashed_storage.insert_slot(hashed_key, value.present_value);
|
||||
}
|
||||
this.insert_hashed_storage(hashed_address, hashed_storage)
|
||||
let hashed_storage = HashedStorage::from_iter(
|
||||
account.status.was_destroyed(),
|
||||
account.storage.iter().map(|(key, value)| {
|
||||
(keccak256(B256::new(key.to_be_bytes())), value.present_value)
|
||||
}),
|
||||
);
|
||||
this.storages.insert(hashed_address, hashed_storage);
|
||||
}
|
||||
this.sorted()
|
||||
this
|
||||
}
|
||||
|
||||
/// Initialize [HashedPostState] from revert range.
|
||||
@ -81,77 +64,48 @@ impl HashedPostState {
|
||||
tx: &TX,
|
||||
range: RangeInclusive<BlockNumber>,
|
||||
) -> Result<Self, DatabaseError> {
|
||||
// A single map for aggregating state changes where each map value is a tuple
|
||||
// `(maybe_account_change, storage_changes)`.
|
||||
// If `maybe_account_change` is `None`, no account info change had occurred.
|
||||
// If `maybe_account_change` is `Some(None)`, the account had previously been destroyed
|
||||
// or non-existent.
|
||||
// If `maybe_account_change` is `Some(Some(info))`, the contained value is the previous
|
||||
// account state.
|
||||
let mut state =
|
||||
HashMap::<Address, (Option<Option<Account>>, HashMap<B256, U256>)>::default();
|
||||
let mut this = Self::default();
|
||||
|
||||
// Iterate over account changesets in reverse.
|
||||
// Iterate over account changesets and record value before first occurring account change.
|
||||
let mut account_changesets_cursor = tx.cursor_read::<tables::AccountChangeSet>()?;
|
||||
for entry in account_changesets_cursor.walk_range(range.clone())? {
|
||||
let (_, AccountBeforeTx { address, info }) = entry?;
|
||||
let account_entry = state.entry(address).or_default();
|
||||
if account_entry.0.is_none() {
|
||||
account_entry.0 = Some(info);
|
||||
let hashed_address = keccak256(address); // TODO: cache hashes?
|
||||
if let hash_map::Entry::Vacant(entry) = this.accounts.entry(hashed_address) {
|
||||
entry.insert(info);
|
||||
}
|
||||
}
|
||||
|
||||
// Iterate over storage changesets in reverse.
|
||||
// Iterate over storage changesets and record value before first occurring storage change.
|
||||
let mut storages = AHashMap::<Address, HashMap<B256, U256>>::default();
|
||||
let mut storage_changesets_cursor = tx.cursor_read::<tables::StorageChangeSet>()?;
|
||||
for entry in storage_changesets_cursor.walk_range(BlockNumberAddress::range(range))? {
|
||||
let (BlockNumberAddress((_, address)), storage) = entry?;
|
||||
let account_entry = state.entry(address).or_default();
|
||||
if let hash_map::Entry::Vacant(entry) = account_entry.1.entry(storage.key) {
|
||||
let account_storage = storages.entry(address).or_default();
|
||||
if let hash_map::Entry::Vacant(entry) = account_storage.entry(storage.key) {
|
||||
entry.insert(storage.value);
|
||||
}
|
||||
}
|
||||
|
||||
let mut this = Self::default();
|
||||
for (address, (maybe_account_change, storage)) in state {
|
||||
let hashed_address = keccak256(address);
|
||||
|
||||
if let Some(account_change) = maybe_account_change {
|
||||
this.insert_account(hashed_address, account_change);
|
||||
}
|
||||
|
||||
// The `wiped` flag indicates only whether previous storage entries should be looked
|
||||
for (address, storage) in storages {
|
||||
// The `wiped` flag indicates only whether previous storage entries should be looked
|
||||
// up in db or not. For reverts it's a noop since all wiped changes had been written as
|
||||
// storage reverts.
|
||||
let mut hashed_storage = HashedStorage::new(false);
|
||||
for (slot, value) in storage {
|
||||
hashed_storage.insert_slot(keccak256(slot), value);
|
||||
}
|
||||
this.insert_hashed_storage(hashed_address, hashed_storage);
|
||||
let hashed_storage = HashedStorage::from_iter(
|
||||
false,
|
||||
storage.into_iter().map(|(slot, value)| (keccak256(slot), value)),
|
||||
);
|
||||
this.storages.insert(keccak256(address), hashed_storage);
|
||||
}
|
||||
|
||||
Ok(this.sorted())
|
||||
Ok(this)
|
||||
}
|
||||
|
||||
/// Extend this hashed post state with contents of another.
|
||||
/// Entries in the second hashed post state take precedence.
|
||||
pub fn extend(&mut self, other: Self) {
|
||||
// Merge accounts and insert them into extended state.
|
||||
let mut accounts: HashMap<B256, Option<Account>> = HashMap::from_iter(
|
||||
self.accounts
|
||||
.drain(..)
|
||||
.map(|(hashed_address, account)| (hashed_address, Some(account)))
|
||||
.chain(
|
||||
self.destroyed_accounts.drain().map(|hashed_address| (hashed_address, None)),
|
||||
),
|
||||
);
|
||||
for (hashed_address, account) in other.accounts {
|
||||
accounts.insert(hashed_address, Some(account));
|
||||
}
|
||||
for hashed_address in other.destroyed_accounts {
|
||||
accounts.insert(hashed_address, None);
|
||||
}
|
||||
for (hashed_address, account) in accounts {
|
||||
self.insert_account(hashed_address, account);
|
||||
self.accounts.insert(hashed_address, account);
|
||||
}
|
||||
|
||||
for (hashed_address, storage) in other.storages {
|
||||
@ -166,55 +120,26 @@ impl HashedPostState {
|
||||
}
|
||||
}
|
||||
|
||||
/// Sort and return self.
|
||||
pub fn sorted(mut self) -> Self {
|
||||
self.sort();
|
||||
self
|
||||
}
|
||||
|
||||
/// Returns all accounts with their state.
|
||||
pub fn accounts(&self) -> impl Iterator<Item = (B256, Option<Account>)> + '_ {
|
||||
self.destroyed_accounts.iter().map(|hashed_address| (*hashed_address, None)).chain(
|
||||
self.accounts.iter().map(|(hashed_address, account)| (*hashed_address, Some(*account))),
|
||||
)
|
||||
}
|
||||
|
||||
/// Returns all account storages.
|
||||
pub fn storages(&self) -> impl Iterator<Item = (&B256, &HashedStorage)> {
|
||||
self.storages.iter()
|
||||
}
|
||||
|
||||
/// Sort account and storage entries.
|
||||
pub fn sort(&mut self) {
|
||||
if !self.sorted {
|
||||
for (_, storage) in self.storages.iter_mut() {
|
||||
storage.sort_storage();
|
||||
/// Converts hashed post state into [HashedPostStateSorted].
|
||||
pub fn into_sorted(self) -> HashedPostStateSorted {
|
||||
let mut accounts = Vec::new();
|
||||
let mut destroyed_accounts = AHashSet::default();
|
||||
for (hashed_address, info) in self.accounts {
|
||||
if let Some(info) = info {
|
||||
accounts.push((hashed_address, info));
|
||||
} else {
|
||||
destroyed_accounts.insert(hashed_address);
|
||||
}
|
||||
|
||||
self.accounts.sort_unstable_by_key(|(address, _)| *address);
|
||||
self.sorted = true;
|
||||
}
|
||||
}
|
||||
accounts.sort_unstable_by_key(|(address, _)| *address);
|
||||
|
||||
/// Insert account. If `account` is `None`, the account had previously been destroyed.
|
||||
pub fn insert_account(&mut self, hashed_address: B256, account: Option<Account>) {
|
||||
if let Some(account) = account {
|
||||
self.accounts.push((hashed_address, account));
|
||||
self.sorted = false;
|
||||
} else {
|
||||
self.destroyed_accounts.insert(hashed_address);
|
||||
}
|
||||
}
|
||||
let storages = self
|
||||
.storages
|
||||
.into_iter()
|
||||
.map(|(hashed_address, storage)| (hashed_address, storage.into_sorted()))
|
||||
.collect();
|
||||
|
||||
/// Insert hashed storage entry.
|
||||
pub fn insert_hashed_storage(&mut self, hashed_address: B256, hashed_storage: HashedStorage) {
|
||||
self.sorted &= hashed_storage.sorted;
|
||||
self.storages.insert(hashed_address, hashed_storage);
|
||||
}
|
||||
|
||||
/// Returns all destroyed accounts.
|
||||
pub fn destroyed_accounts(&self) -> AHashSet<B256> {
|
||||
self.destroyed_accounts.clone()
|
||||
HashedPostStateSorted { accounts, destroyed_accounts, storages }
|
||||
}
|
||||
|
||||
/// Construct [PrefixSet] from hashed post state.
|
||||
@ -229,19 +154,13 @@ impl HashedPostState {
|
||||
for (hashed_address, _) in &self.accounts {
|
||||
account_prefix_set.insert(Nibbles::unpack(hashed_address));
|
||||
}
|
||||
for hashed_address in &self.destroyed_accounts {
|
||||
account_prefix_set.insert(Nibbles::unpack(hashed_address));
|
||||
}
|
||||
|
||||
// Populate storage prefix sets.
|
||||
for (hashed_address, hashed_storage) in self.storages.iter() {
|
||||
account_prefix_set.insert(Nibbles::unpack(hashed_address));
|
||||
|
||||
let storage_prefix_set_entry = storage_prefix_set.entry(*hashed_address).or_default();
|
||||
for (hashed_slot, _) in &hashed_storage.non_zero_valued_slots {
|
||||
storage_prefix_set_entry.insert(Nibbles::unpack(hashed_slot));
|
||||
}
|
||||
for hashed_slot in &hashed_storage.zero_valued_slots {
|
||||
for (hashed_slot, _) in &hashed_storage.storage {
|
||||
storage_prefix_set_entry.insert(Nibbles::unpack(hashed_slot));
|
||||
}
|
||||
}
|
||||
@ -252,21 +171,6 @@ impl HashedPostState {
|
||||
)
|
||||
}
|
||||
|
||||
/// Returns [StateRoot] calculator based on database and in-memory state.
|
||||
fn state_root_calculator<'a, TX: DbTx>(
|
||||
&self,
|
||||
tx: &'a TX,
|
||||
) -> StateRoot<&'a TX, HashedPostStateCursorFactory<'_, &'a TX>> {
|
||||
assert!(self.sorted, "Hashed post state must be sorted for state root calculation");
|
||||
let (account_prefix_set, storage_prefix_set) = self.construct_prefix_sets();
|
||||
let hashed_cursor_factory = HashedPostStateCursorFactory::new(tx, self);
|
||||
StateRoot::from_tx(tx)
|
||||
.with_hashed_cursor_factory(hashed_cursor_factory)
|
||||
.with_changed_account_prefixes(account_prefix_set)
|
||||
.with_changed_storage_prefixes(storage_prefix_set)
|
||||
.with_destroyed_accounts(self.destroyed_accounts())
|
||||
}
|
||||
|
||||
/// Calculate the state root for this [HashedPostState].
|
||||
/// Internally, this method retrieves prefixsets and uses them
|
||||
/// to calculate incremental state root.
|
||||
@ -283,11 +187,10 @@ impl HashedPostState {
|
||||
///
|
||||
/// // Initialize hashed post state
|
||||
/// let mut hashed_state = HashedPostState::default();
|
||||
/// hashed_state.insert_account(
|
||||
/// hashed_state.accounts.insert(
|
||||
/// [0x11; 32].into(),
|
||||
/// Some(Account { nonce: 1, balance: U256::from(10), bytecode_hash: None }),
|
||||
/// );
|
||||
/// hashed_state.sort();
|
||||
///
|
||||
/// // Calculate the state root
|
||||
/// let tx = db.tx().expect("failed to create transaction");
|
||||
@ -298,7 +201,13 @@ impl HashedPostState {
|
||||
///
|
||||
/// The state root for this [HashedPostState].
|
||||
pub fn state_root<TX: DbTx>(&self, tx: &TX) -> Result<B256, StateRootError> {
|
||||
self.state_root_calculator(tx).root()
|
||||
let sorted = self.clone().into_sorted();
|
||||
let (account_prefix_set, storage_prefix_set) = self.construct_prefix_sets();
|
||||
sorted
|
||||
.state_root_calculator(tx)
|
||||
.with_changed_account_prefixes(account_prefix_set)
|
||||
.with_changed_storage_prefixes(storage_prefix_set)
|
||||
.root()
|
||||
}
|
||||
|
||||
/// Calculates the state root for this [HashedPostState] and returns it alongside trie updates.
|
||||
@ -307,82 +216,98 @@ impl HashedPostState {
|
||||
&self,
|
||||
tx: &TX,
|
||||
) -> Result<(B256, TrieUpdates), StateRootError> {
|
||||
self.state_root_calculator(tx).root_with_updates()
|
||||
let sorted = self.clone().into_sorted();
|
||||
let (account_prefix_set, storage_prefix_set) = self.construct_prefix_sets();
|
||||
sorted
|
||||
.state_root_calculator(tx)
|
||||
.with_changed_account_prefixes(account_prefix_set)
|
||||
.with_changed_storage_prefixes(storage_prefix_set)
|
||||
.root_with_updates()
|
||||
}
|
||||
}
|
||||
|
||||
/// The post state account storage with hashed slots.
|
||||
#[derive(Clone, Eq, PartialEq, Debug)]
|
||||
/// Representation of in-memory hashed storage.
|
||||
#[derive(PartialEq, Eq, Clone, Debug)]
|
||||
pub struct HashedStorage {
|
||||
/// Hashed storage slots with non-zero.
|
||||
pub(crate) non_zero_valued_slots: Vec<(B256, U256)>,
|
||||
/// Slots that have been zero valued.
|
||||
pub(crate) zero_valued_slots: AHashSet<B256>,
|
||||
/// Whether the storage was wiped or not.
|
||||
pub(crate) wiped: bool,
|
||||
/// Whether the storage entries were sorted or not.
|
||||
pub(crate) sorted: bool,
|
||||
/// Flag indicating whether the storage was wiped or not.
|
||||
pub wiped: bool,
|
||||
/// Mapping of hashed storage slot to storage value.
|
||||
pub storage: AHashMap<B256, U256>,
|
||||
}
|
||||
|
||||
impl HashedStorage {
|
||||
/// Create new instance of [HashedStorage].
|
||||
pub fn new(wiped: bool) -> Self {
|
||||
Self {
|
||||
non_zero_valued_slots: Vec::new(),
|
||||
zero_valued_slots: AHashSet::new(),
|
||||
wiped,
|
||||
sorted: true, // empty is sorted
|
||||
}
|
||||
Self { wiped, storage: AHashMap::default() }
|
||||
}
|
||||
|
||||
/// Create new hashed storage from iterator.
|
||||
pub fn from_iter(wiped: bool, iter: impl IntoIterator<Item = (B256, U256)>) -> Self {
|
||||
Self { wiped, storage: AHashMap::from_iter(iter) }
|
||||
}
|
||||
|
||||
/// Extend hashed storage with contents of other.
|
||||
/// The entries in second hashed storage take precedence.
|
||||
pub fn extend(&mut self, other: Self) {
|
||||
let mut entries: HashMap<B256, U256> =
|
||||
HashMap::from_iter(self.non_zero_valued_slots.drain(..).chain(
|
||||
self.zero_valued_slots.drain().map(|hashed_slot| (hashed_slot, U256::ZERO)),
|
||||
));
|
||||
for (hashed_slot, value) in other.non_zero_valued_slots {
|
||||
entries.insert(hashed_slot, value);
|
||||
}
|
||||
for hashed_slot in other.zero_valued_slots {
|
||||
entries.insert(hashed_slot, U256::ZERO);
|
||||
}
|
||||
for (hashed_slot, value) in entries {
|
||||
self.insert_slot(hashed_slot, value);
|
||||
for (hashed_slot, value) in other.storage {
|
||||
self.storage.insert(hashed_slot, value);
|
||||
}
|
||||
self.wiped |= other.wiped;
|
||||
}
|
||||
|
||||
/// Returns `true` if the storage was wiped.
|
||||
pub fn wiped(&self) -> bool {
|
||||
self.wiped
|
||||
}
|
||||
|
||||
/// Returns all storage slots.
|
||||
pub fn storage_slots(&self) -> impl Iterator<Item = (B256, U256)> + '_ {
|
||||
self.zero_valued_slots
|
||||
.iter()
|
||||
.map(|slot| (*slot, U256::ZERO))
|
||||
.chain(self.non_zero_valued_slots.iter().cloned())
|
||||
}
|
||||
|
||||
/// Sorts the non zero value storage entries.
|
||||
pub fn sort_storage(&mut self) {
|
||||
if !self.sorted {
|
||||
self.non_zero_valued_slots.sort_unstable_by_key(|(slot, _)| *slot);
|
||||
self.sorted = true;
|
||||
/// Converts hashed storage into [HashedStorageSorted].
|
||||
pub fn into_sorted(self) -> HashedStorageSorted {
|
||||
let mut non_zero_valued_slots = Vec::new();
|
||||
let mut zero_valued_slots = AHashSet::default();
|
||||
for (hashed_slot, value) in self.storage {
|
||||
if value == U256::ZERO {
|
||||
zero_valued_slots.insert(hashed_slot);
|
||||
} else {
|
||||
non_zero_valued_slots.push((hashed_slot, value));
|
||||
}
|
||||
}
|
||||
}
|
||||
non_zero_valued_slots.sort_unstable_by_key(|(key, _)| *key);
|
||||
|
||||
/// Insert storage entry.
|
||||
#[inline]
|
||||
pub fn insert_slot(&mut self, slot: B256, value: U256) {
|
||||
if value.is_zero() {
|
||||
self.zero_valued_slots.insert(slot);
|
||||
} else {
|
||||
self.non_zero_valued_slots.push((slot, value));
|
||||
self.sorted = false;
|
||||
}
|
||||
HashedStorageSorted { non_zero_valued_slots, zero_valued_slots, wiped: self.wiped }
|
||||
}
|
||||
}
|
||||
|
||||
/// Sorted hashed post state optimized for iterating during state trie calculation.
|
||||
#[derive(PartialEq, Eq, Clone, Debug)]
|
||||
pub struct HashedPostStateSorted {
|
||||
/// Sorted collection of hashed addresses and their account info.
|
||||
pub(crate) accounts: Vec<(B256, Account)>,
|
||||
/// Set of destroyed account keys.
|
||||
pub(crate) destroyed_accounts: AHashSet<B256>,
|
||||
/// Map of hashed addresses to hashed storage.
|
||||
pub(crate) storages: AHashMap<B256, HashedStorageSorted>,
|
||||
}
|
||||
|
||||
impl HashedPostStateSorted {
|
||||
/// Returns all destroyed accounts.
|
||||
pub fn destroyed_accounts(&self) -> AHashSet<B256> {
|
||||
self.destroyed_accounts.clone()
|
||||
}
|
||||
|
||||
/// Returns [StateRoot] calculator based on database and in-memory state.
|
||||
fn state_root_calculator<'a, TX: DbTx>(
|
||||
&self,
|
||||
tx: &'a TX,
|
||||
) -> StateRoot<&'a TX, HashedPostStateCursorFactory<'_, &'a TX>> {
|
||||
let hashed_cursor_factory = HashedPostStateCursorFactory::new(tx, self);
|
||||
StateRoot::from_tx(tx)
|
||||
.with_hashed_cursor_factory(hashed_cursor_factory)
|
||||
.with_destroyed_accounts(self.destroyed_accounts())
|
||||
}
|
||||
}
|
||||
|
||||
/// Sorted hashed storage optimized for iterating during state trie calculation.
|
||||
#[derive(Clone, Eq, PartialEq, Debug)]
|
||||
pub struct HashedStorageSorted {
|
||||
/// Sorted hashed storage slots with non-zero value.
|
||||
pub(crate) non_zero_valued_slots: Vec<(B256, U256)>,
|
||||
/// Slots that have been zero valued.
|
||||
pub(crate) zero_valued_slots: AHashSet<B256>,
|
||||
/// Flag indicating hether the storage was wiped or not.
|
||||
pub(crate) wiped: bool,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user