use crate::{
CanonStateNotification, CanonStateNotificationSender, CanonStateNotifications,
ChainInfoTracker, MemoryOverlayStateProvider,
};
use alloy_consensus::Header;
use alloy_eips::{BlockHashOrNumber, BlockNumHash};
use alloy_primitives::{map::HashMap, Address, TxHash, B256};
use parking_lot::RwLock;
use reth_chainspec::ChainInfo;
use reth_execution_types::{Chain, ExecutionOutcome};
use reth_metrics::{metrics::Gauge, Metrics};
use reth_primitives::{
BlockWithSenders, Receipt, Receipts, SealedBlock, SealedBlockWithSenders, SealedHeader,
TransactionMeta, TransactionSigned,
};
use reth_storage_api::StateProviderBox;
use reth_trie::{updates::TrieUpdates, HashedPostState};
use std::{collections::BTreeMap, sync::Arc, time::Instant};
use tokio::sync::{broadcast, watch};
const CANON_STATE_NOTIFICATION_CHANNEL_SIZE: usize = 256;
#[derive(Metrics)]
#[metrics(scope = "blockchain_tree.in_mem_state")]
pub(crate) struct InMemoryStateMetrics {
pub(crate) earliest_block: Gauge,
pub(crate) latest_block: Gauge,
pub(crate) num_blocks: Gauge,
}
#[derive(Debug, Default)]
pub(crate) struct InMemoryState {
blocks: RwLock<HashMap<B256, Arc<BlockState>>>,
numbers: RwLock<BTreeMap<u64, B256>>,
pending: watch::Sender<Option<BlockState>>,
metrics: InMemoryStateMetrics,
}
impl InMemoryState {
pub(crate) fn new(
blocks: HashMap<B256, Arc<BlockState>>,
numbers: BTreeMap<u64, B256>,
pending: Option<BlockState>,
) -> Self {
let (pending, _) = watch::channel(pending);
let this = Self {
blocks: RwLock::new(blocks),
numbers: RwLock::new(numbers),
pending,
metrics: Default::default(),
};
this.update_metrics();
this
}
pub(crate) fn update_metrics(&self) {
let numbers = self.numbers.read();
if let Some((earliest_block_number, _)) = numbers.first_key_value() {
self.metrics.earliest_block.set(*earliest_block_number as f64);
}
if let Some((latest_block_number, _)) = numbers.last_key_value() {
self.metrics.latest_block.set(*latest_block_number as f64);
}
self.metrics.num_blocks.set(numbers.len() as f64);
}
pub(crate) fn state_by_hash(&self, hash: B256) -> Option<Arc<BlockState>> {
self.blocks.read().get(&hash).cloned()
}
pub(crate) fn state_by_number(&self, number: u64) -> Option<Arc<BlockState>> {
let hash = self.hash_by_number(number)?;
self.state_by_hash(hash)
}
pub(crate) fn hash_by_number(&self, number: u64) -> Option<B256> {
self.numbers.read().get(&number).copied()
}
pub(crate) fn head_state(&self) -> Option<Arc<BlockState>> {
let hash = *self.numbers.read().last_key_value()?.1;
self.state_by_hash(hash)
}
pub(crate) fn pending_state(&self) -> Option<BlockState> {
self.pending.borrow().clone()
}
#[cfg(test)]
fn block_count(&self) -> usize {
self.blocks.read().len()
}
}
#[derive(Debug)]
pub(crate) struct CanonicalInMemoryStateInner {
pub(crate) chain_info_tracker: ChainInfoTracker,
pub(crate) in_memory_state: InMemoryState,
pub(crate) canon_state_notification_sender: CanonStateNotificationSender,
}
impl CanonicalInMemoryStateInner {
fn clear(&self) {
{
let mut numbers = self.in_memory_state.numbers.write();
let mut blocks = self.in_memory_state.blocks.write();
numbers.clear();
blocks.clear();
self.in_memory_state.pending.send_modify(|p| {
p.take();
});
}
self.in_memory_state.update_metrics();
}
}
#[derive(Debug, Clone)]
pub struct CanonicalInMemoryState {
pub(crate) inner: Arc<CanonicalInMemoryStateInner>,
}
impl CanonicalInMemoryState {
pub fn new(
blocks: HashMap<B256, Arc<BlockState>>,
numbers: BTreeMap<u64, B256>,
pending: Option<BlockState>,
finalized: Option<SealedHeader>,
safe: Option<SealedHeader>,
) -> Self {
let in_memory_state = InMemoryState::new(blocks, numbers, pending);
let header = in_memory_state
.head_state()
.map_or_else(SealedHeader::default, |state| state.block_ref().block().header.clone());
let chain_info_tracker = ChainInfoTracker::new(header, finalized, safe);
let (canon_state_notification_sender, _) =
broadcast::channel(CANON_STATE_NOTIFICATION_CHANNEL_SIZE);
Self {
inner: Arc::new(CanonicalInMemoryStateInner {
chain_info_tracker,
in_memory_state,
canon_state_notification_sender,
}),
}
}
pub fn empty() -> Self {
Self::new(HashMap::default(), BTreeMap::new(), None, None, None)
}
pub fn with_head(
head: SealedHeader,
finalized: Option<SealedHeader>,
safe: Option<SealedHeader>,
) -> Self {
let chain_info_tracker = ChainInfoTracker::new(head, finalized, safe);
let in_memory_state = InMemoryState::default();
let (canon_state_notification_sender, _) =
broadcast::channel(CANON_STATE_NOTIFICATION_CHANNEL_SIZE);
let inner = CanonicalInMemoryStateInner {
chain_info_tracker,
in_memory_state,
canon_state_notification_sender,
};
Self { inner: Arc::new(inner) }
}
pub fn hash_by_number(&self, number: u64) -> Option<B256> {
self.inner.in_memory_state.hash_by_number(number)
}
pub fn header_by_hash(&self, hash: B256) -> Option<SealedHeader> {
self.state_by_hash(hash).map(|block| block.block_ref().block.header.clone())
}
pub fn clear_state(&self) {
self.inner.clear()
}
pub fn set_pending_block(&self, pending: ExecutedBlock) {
let parent = self.state_by_hash(pending.block().parent_hash);
let pending = BlockState::with_parent(pending, parent);
self.inner.in_memory_state.pending.send_modify(|p| {
p.replace(pending);
});
self.inner.in_memory_state.update_metrics();
}
fn update_blocks<I>(&self, new_blocks: I, reorged: I)
where
I: IntoIterator<Item = ExecutedBlock>,
{
{
let mut numbers = self.inner.in_memory_state.numbers.write();
let mut blocks = self.inner.in_memory_state.blocks.write();
for block in reorged {
let hash = block.block().hash();
let number = block.block().number;
blocks.remove(&hash);
numbers.remove(&number);
}
for block in new_blocks {
let parent = blocks.get(&block.block().parent_hash).cloned();
let block_state = BlockState::with_parent(block, parent);
let hash = block_state.hash();
let number = block_state.number();
blocks.insert(hash, Arc::new(block_state));
numbers.insert(number, hash);
}
self.inner.in_memory_state.pending.send_modify(|p| {
p.take();
});
}
self.inner.in_memory_state.update_metrics();
}
pub fn update_chain(&self, new_chain: NewCanonicalChain) {
match new_chain {
NewCanonicalChain::Commit { new } => {
self.update_blocks(new, vec![]);
}
NewCanonicalChain::Reorg { new, old } => {
self.update_blocks(new, old);
}
}
}
pub fn remove_persisted_blocks(&self, persisted_num_hash: BlockNumHash) {
{
if self.inner.in_memory_state.blocks.read().get(&persisted_num_hash.hash).is_none() {
return
}
}
{
let mut numbers = self.inner.in_memory_state.numbers.write();
let mut blocks = self.inner.in_memory_state.blocks.write();
let BlockNumHash { number: persisted_height, hash: _ } = persisted_num_hash;
numbers.clear();
let mut old_blocks = blocks
.drain()
.filter(|(_, b)| b.block_ref().block().number > persisted_height)
.map(|(_, b)| b.block.clone())
.collect::<Vec<_>>();
old_blocks.sort_unstable_by_key(|block| block.block().number);
for block in old_blocks {
let parent = blocks.get(&block.block().parent_hash).cloned();
let block_state = BlockState::with_parent(block, parent);
let hash = block_state.hash();
let number = block_state.number();
blocks.insert(hash, Arc::new(block_state));
numbers.insert(number, hash);
}
self.inner.in_memory_state.pending.send_modify(|p| {
if let Some(p) = p.as_mut() {
p.parent = blocks.get(&p.block_ref().block.parent_hash).cloned();
}
});
}
self.inner.in_memory_state.update_metrics();
}
pub fn state_by_hash(&self, hash: B256) -> Option<Arc<BlockState>> {
self.inner.in_memory_state.state_by_hash(hash)
}
pub fn state_by_number(&self, number: u64) -> Option<Arc<BlockState>> {
self.inner.in_memory_state.state_by_number(number)
}
pub fn head_state(&self) -> Option<Arc<BlockState>> {
self.inner.in_memory_state.head_state()
}
pub fn pending_state(&self) -> Option<BlockState> {
self.inner.in_memory_state.pending_state()
}
pub fn pending_block_num_hash(&self) -> Option<BlockNumHash> {
self.inner
.in_memory_state
.pending_state()
.map(|state| BlockNumHash { number: state.number(), hash: state.hash() })
}
pub fn chain_info(&self) -> ChainInfo {
self.inner.chain_info_tracker.chain_info()
}
pub fn get_canonical_block_number(&self) -> u64 {
self.inner.chain_info_tracker.get_canonical_block_number()
}
pub fn get_safe_num_hash(&self) -> Option<BlockNumHash> {
self.inner.chain_info_tracker.get_safe_num_hash()
}
pub fn get_finalized_num_hash(&self) -> Option<BlockNumHash> {
self.inner.chain_info_tracker.get_finalized_num_hash()
}
pub fn on_forkchoice_update_received(&self) {
self.inner.chain_info_tracker.on_forkchoice_update_received();
}
pub fn last_received_update_timestamp(&self) -> Option<Instant> {
self.inner.chain_info_tracker.last_forkchoice_update_received_at()
}
pub fn on_transition_configuration_exchanged(&self) {
self.inner.chain_info_tracker.on_transition_configuration_exchanged();
}
pub fn last_exchanged_transition_configuration_timestamp(&self) -> Option<Instant> {
self.inner.chain_info_tracker.last_transition_configuration_exchanged_at()
}
pub fn set_canonical_head(&self, header: SealedHeader) {
self.inner.chain_info_tracker.set_canonical_head(header);
}
pub fn set_safe(&self, header: SealedHeader) {
self.inner.chain_info_tracker.set_safe(header);
}
pub fn set_finalized(&self, header: SealedHeader) {
self.inner.chain_info_tracker.set_finalized(header);
}
pub fn get_canonical_head(&self) -> SealedHeader {
self.inner.chain_info_tracker.get_canonical_head()
}
pub fn get_finalized_header(&self) -> Option<SealedHeader> {
self.inner.chain_info_tracker.get_finalized_header()
}
pub fn get_safe_header(&self) -> Option<SealedHeader> {
self.inner.chain_info_tracker.get_safe_header()
}
pub fn pending_sealed_header(&self) -> Option<SealedHeader> {
self.pending_state().map(|h| h.block_ref().block().header.clone())
}
pub fn pending_header(&self) -> Option<Header> {
self.pending_sealed_header().map(|sealed_header| sealed_header.unseal())
}
pub fn pending_block(&self) -> Option<SealedBlock> {
self.pending_state().map(|block_state| block_state.block_ref().block().clone())
}
pub fn pending_block_with_senders(&self) -> Option<SealedBlockWithSenders> {
self.pending_state()
.and_then(|block_state| block_state.block_ref().block().clone().seal_with_senders())
}
pub fn pending_block_and_receipts(&self) -> Option<(SealedBlock, Vec<Receipt>)> {
self.pending_state().map(|block_state| {
(block_state.block_ref().block().clone(), block_state.executed_block_receipts())
})
}
pub fn subscribe_canon_state(&self) -> CanonStateNotifications {
self.inner.canon_state_notification_sender.subscribe()
}
pub fn subscribe_safe_block(&self) -> watch::Receiver<Option<SealedHeader>> {
self.inner.chain_info_tracker.subscribe_safe_block()
}
pub fn subscribe_finalized_block(&self) -> watch::Receiver<Option<SealedHeader>> {
self.inner.chain_info_tracker.subscribe_finalized_block()
}
pub fn notify_canon_state(&self, event: CanonStateNotification) {
self.inner.canon_state_notification_sender.send(event).ok();
}
pub fn state_provider(
&self,
hash: B256,
historical: StateProviderBox,
) -> MemoryOverlayStateProvider {
let in_memory = if let Some(state) = self.state_by_hash(hash) {
state.chain().map(|block_state| block_state.block()).collect()
} else {
Vec::new()
};
MemoryOverlayStateProvider::new(historical, in_memory)
}
pub fn canonical_chain(&self) -> impl Iterator<Item = Arc<BlockState>> {
self.inner.in_memory_state.head_state().into_iter().flat_map(|head| head.iter())
}
pub fn transaction_by_hash(&self, hash: TxHash) -> Option<TransactionSigned> {
for block_state in self.canonical_chain() {
if let Some(tx) =
block_state.block_ref().block().body.transactions().find(|tx| tx.hash() == hash)
{
return Some(tx.clone())
}
}
None
}
pub fn transaction_by_hash_with_meta(
&self,
tx_hash: TxHash,
) -> Option<(TransactionSigned, TransactionMeta)> {
for block_state in self.canonical_chain() {
if let Some((index, tx)) = block_state
.block_ref()
.block()
.body
.transactions()
.enumerate()
.find(|(_, tx)| tx.hash() == tx_hash)
{
let meta = TransactionMeta {
tx_hash,
index: index as u64,
block_hash: block_state.hash(),
block_number: block_state.block_ref().block.number,
base_fee: block_state.block_ref().block.header.base_fee_per_gas,
timestamp: block_state.block_ref().block.timestamp,
excess_blob_gas: block_state.block_ref().block.excess_blob_gas,
};
return Some((tx.clone(), meta))
}
}
None
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct BlockState {
block: ExecutedBlock,
parent: Option<Arc<BlockState>>,
}
#[allow(dead_code)]
impl BlockState {
pub const fn new(block: ExecutedBlock) -> Self {
Self { block, parent: None }
}
pub const fn with_parent(block: ExecutedBlock, parent: Option<Arc<Self>>) -> Self {
Self { block, parent }
}
pub fn anchor(&self) -> BlockNumHash {
if let Some(parent) = &self.parent {
parent.anchor()
} else {
self.block.block().parent_num_hash()
}
}
pub fn block(&self) -> ExecutedBlock {
self.block.clone()
}
pub const fn block_ref(&self) -> &ExecutedBlock {
&self.block
}
pub fn block_with_senders(&self) -> BlockWithSenders {
let block = self.block.block().clone();
let senders = self.block.senders().clone();
BlockWithSenders { block: block.unseal(), senders }
}
pub fn sealed_block_with_senders(&self) -> SealedBlockWithSenders {
let block = self.block.block().clone();
let senders = self.block.senders().clone();
SealedBlockWithSenders { block, senders }
}
pub fn hash(&self) -> B256 {
self.block.block().hash()
}
pub fn number(&self) -> u64 {
self.block.block().number
}
pub fn state_root(&self) -> B256 {
self.block.block().header.state_root
}
pub fn receipts(&self) -> &Receipts {
&self.block.execution_outcome().receipts
}
pub fn executed_block_receipts(&self) -> Vec<Receipt> {
let receipts = self.receipts();
debug_assert!(
receipts.receipt_vec.len() <= 1,
"Expected at most one block's worth of receipts, found {}",
receipts.receipt_vec.len()
);
receipts
.receipt_vec
.first()
.map(|block_receipts| {
block_receipts.iter().filter_map(|opt_receipt| opt_receipt.clone()).collect()
})
.unwrap_or_default()
}
pub fn parent_state_chain(&self) -> Vec<&Self> {
let mut parents = Vec::new();
let mut current = self.parent.as_deref();
while let Some(parent) = current {
parents.push(parent);
current = parent.parent.as_deref();
}
parents
}
pub fn chain(&self) -> impl Iterator<Item = &Self> {
std::iter::successors(Some(self), |state| state.parent.as_deref())
}
pub fn append_parent_chain<'a>(&'a self, chain: &mut Vec<&'a Self>) {
chain.extend(self.parent_state_chain());
}
pub fn iter(self: Arc<Self>) -> impl Iterator<Item = Arc<Self>> {
std::iter::successors(Some(self), |state| state.parent.clone())
}
pub fn state_provider(&self, historical: StateProviderBox) -> MemoryOverlayStateProvider {
let in_memory = self.chain().map(|block_state| block_state.block()).collect();
MemoryOverlayStateProvider::new(historical, in_memory)
}
pub fn block_on_chain(&self, hash_or_num: BlockHashOrNumber) -> Option<&Self> {
self.chain().find(|block| match hash_or_num {
BlockHashOrNumber::Hash(hash) => block.hash() == hash,
BlockHashOrNumber::Number(number) => block.number() == number,
})
}
pub fn transaction_on_chain(&self, hash: TxHash) -> Option<TransactionSigned> {
self.chain().find_map(|block_state| {
block_state
.block_ref()
.block()
.body
.transactions()
.find(|tx| tx.hash() == hash)
.cloned()
})
}
pub fn transaction_meta_on_chain(
&self,
tx_hash: TxHash,
) -> Option<(TransactionSigned, TransactionMeta)> {
self.chain().find_map(|block_state| {
block_state
.block_ref()
.block()
.body
.transactions()
.enumerate()
.find(|(_, tx)| tx.hash() == tx_hash)
.map(|(index, tx)| {
let meta = TransactionMeta {
tx_hash,
index: index as u64,
block_hash: block_state.hash(),
block_number: block_state.block_ref().block.number,
base_fee: block_state.block_ref().block.header.base_fee_per_gas,
timestamp: block_state.block_ref().block.timestamp,
excess_blob_gas: block_state.block_ref().block.excess_blob_gas,
};
(tx.clone(), meta)
})
})
}
}
#[derive(Clone, Debug, PartialEq, Eq, Default)]
pub struct ExecutedBlock {
pub block: Arc<SealedBlock>,
pub senders: Arc<Vec<Address>>,
pub execution_output: Arc<ExecutionOutcome>,
pub hashed_state: Arc<HashedPostState>,
pub trie: Arc<TrieUpdates>,
}
impl ExecutedBlock {
pub const fn new(
block: Arc<SealedBlock>,
senders: Arc<Vec<Address>>,
execution_output: Arc<ExecutionOutcome>,
hashed_state: Arc<HashedPostState>,
trie: Arc<TrieUpdates>,
) -> Self {
Self { block, senders, execution_output, hashed_state, trie }
}
pub fn block(&self) -> &SealedBlock {
&self.block
}
pub fn senders(&self) -> &Vec<Address> {
&self.senders
}
pub fn sealed_block_with_senders(&self) -> SealedBlockWithSenders {
SealedBlockWithSenders { block: (*self.block).clone(), senders: (*self.senders).clone() }
}
pub fn execution_outcome(&self) -> &ExecutionOutcome {
&self.execution_output
}
pub fn hashed_state(&self) -> &HashedPostState {
&self.hashed_state
}
pub fn trie_updates(&self) -> &TrieUpdates {
&self.trie
}
}
#[derive(Debug)]
pub enum NewCanonicalChain {
Commit {
new: Vec<ExecutedBlock>,
},
Reorg {
new: Vec<ExecutedBlock>,
old: Vec<ExecutedBlock>,
},
}
impl NewCanonicalChain {
pub fn new_block_count(&self) -> usize {
match self {
Self::Commit { new } | Self::Reorg { new, .. } => new.len(),
}
}
pub fn reorged_block_count(&self) -> usize {
match self {
Self::Commit { .. } => 0,
Self::Reorg { old, .. } => old.len(),
}
}
pub fn to_chain_notification(&self) -> CanonStateNotification {
match self {
Self::Commit { new } => {
let new = Arc::new(new.iter().fold(Chain::default(), |mut chain, exec| {
chain.append_block(
exec.sealed_block_with_senders(),
exec.execution_outcome().clone(),
);
chain
}));
CanonStateNotification::Commit { new }
}
Self::Reorg { new, old } => {
let new = Arc::new(new.iter().fold(Chain::default(), |mut chain, exec| {
chain.append_block(
exec.sealed_block_with_senders(),
exec.execution_outcome().clone(),
);
chain
}));
let old = Arc::new(old.iter().fold(Chain::default(), |mut chain, exec| {
chain.append_block(
exec.sealed_block_with_senders(),
exec.execution_outcome().clone(),
);
chain
}));
CanonStateNotification::Reorg { new, old }
}
}
}
pub fn tip(&self) -> &SealedBlock {
match self {
Self::Commit { new } | Self::Reorg { new, .. } => {
new.last().expect("non empty blocks").block()
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::test_utils::TestBlockBuilder;
use alloy_eips::eip7685::Requests;
use alloy_primitives::{map::HashSet, BlockNumber, Bytes, StorageKey, StorageValue};
use rand::Rng;
use reth_errors::ProviderResult;
use reth_primitives::{Account, Bytecode, Receipt};
use reth_storage_api::{
AccountReader, BlockHashReader, StateProofProvider, StateProvider, StateRootProvider,
StorageRootProvider,
};
use reth_trie::{AccountProof, HashedStorage, MultiProof, StorageProof, TrieInput};
fn create_mock_state(
test_block_builder: &mut TestBlockBuilder,
block_number: u64,
parent_hash: B256,
) -> BlockState {
BlockState::new(
test_block_builder.get_executed_block_with_number(block_number, parent_hash),
)
}
fn create_mock_state_chain(
test_block_builder: &mut TestBlockBuilder,
num_blocks: u64,
) -> Vec<BlockState> {
let mut chain = Vec::with_capacity(num_blocks as usize);
let mut parent_hash = B256::random();
let mut parent_state: Option<BlockState> = None;
for i in 1..=num_blocks {
let mut state = create_mock_state(test_block_builder, i, parent_hash);
if let Some(parent) = parent_state {
state.parent = Some(Arc::new(parent));
}
parent_hash = state.hash();
parent_state = Some(state.clone());
chain.push(state);
}
chain
}
struct MockStateProvider;
impl StateProvider for MockStateProvider {
fn storage(
&self,
_address: Address,
_storage_key: StorageKey,
) -> ProviderResult<Option<StorageValue>> {
Ok(None)
}
fn bytecode_by_hash(&self, _code_hash: B256) -> ProviderResult<Option<Bytecode>> {
Ok(None)
}
}
impl BlockHashReader for MockStateProvider {
fn block_hash(&self, _number: BlockNumber) -> ProviderResult<Option<B256>> {
Ok(None)
}
fn canonical_hashes_range(
&self,
_start: BlockNumber,
_end: BlockNumber,
) -> ProviderResult<Vec<B256>> {
Ok(vec![])
}
}
impl AccountReader for MockStateProvider {
fn basic_account(&self, _address: Address) -> ProviderResult<Option<Account>> {
Ok(None)
}
}
impl StateRootProvider for MockStateProvider {
fn state_root(&self, _hashed_state: HashedPostState) -> ProviderResult<B256> {
Ok(B256::random())
}
fn state_root_from_nodes(&self, _input: TrieInput) -> ProviderResult<B256> {
Ok(B256::random())
}
fn state_root_with_updates(
&self,
_hashed_state: HashedPostState,
) -> ProviderResult<(B256, TrieUpdates)> {
Ok((B256::random(), TrieUpdates::default()))
}
fn state_root_from_nodes_with_updates(
&self,
_input: TrieInput,
) -> ProviderResult<(B256, TrieUpdates)> {
Ok((B256::random(), TrieUpdates::default()))
}
}
impl StorageRootProvider for MockStateProvider {
fn storage_root(
&self,
_address: Address,
_hashed_storage: HashedStorage,
) -> ProviderResult<B256> {
Ok(B256::random())
}
fn storage_proof(
&self,
_address: Address,
slot: B256,
_hashed_storage: HashedStorage,
) -> ProviderResult<StorageProof> {
Ok(StorageProof::new(slot))
}
}
impl StateProofProvider for MockStateProvider {
fn proof(
&self,
_input: TrieInput,
_address: Address,
_slots: &[B256],
) -> ProviderResult<AccountProof> {
Ok(AccountProof::new(Address::random()))
}
fn multiproof(
&self,
_input: TrieInput,
_targets: HashMap<B256, HashSet<B256>>,
) -> ProviderResult<MultiProof> {
Ok(MultiProof::default())
}
fn witness(
&self,
_input: TrieInput,
_target: HashedPostState,
) -> ProviderResult<HashMap<B256, Bytes>> {
Ok(HashMap::default())
}
}
#[test]
fn test_in_memory_state_impl_state_by_hash() {
let mut state_by_hash = HashMap::default();
let number = rand::thread_rng().gen::<u64>();
let mut test_block_builder = TestBlockBuilder::default();
let state = Arc::new(create_mock_state(&mut test_block_builder, number, B256::random()));
state_by_hash.insert(state.hash(), state.clone());
let in_memory_state = InMemoryState::new(state_by_hash, BTreeMap::new(), None);
assert_eq!(in_memory_state.state_by_hash(state.hash()), Some(state));
assert_eq!(in_memory_state.state_by_hash(B256::random()), None);
}
#[test]
fn test_in_memory_state_impl_state_by_number() {
let mut state_by_hash = HashMap::default();
let mut hash_by_number = BTreeMap::new();
let number = rand::thread_rng().gen::<u64>();
let mut test_block_builder = TestBlockBuilder::default();
let state = Arc::new(create_mock_state(&mut test_block_builder, number, B256::random()));
let hash = state.hash();
state_by_hash.insert(hash, state.clone());
hash_by_number.insert(number, hash);
let in_memory_state = InMemoryState::new(state_by_hash, hash_by_number, None);
assert_eq!(in_memory_state.state_by_number(number), Some(state));
assert_eq!(in_memory_state.state_by_number(number + 1), None);
}
#[test]
fn test_in_memory_state_impl_head_state() {
let mut state_by_hash = HashMap::default();
let mut hash_by_number = BTreeMap::new();
let mut test_block_builder = TestBlockBuilder::default();
let state1 = Arc::new(create_mock_state(&mut test_block_builder, 1, B256::random()));
let hash1 = state1.hash();
let state2 = Arc::new(create_mock_state(&mut test_block_builder, 2, hash1));
let hash2 = state2.hash();
hash_by_number.insert(1, hash1);
hash_by_number.insert(2, hash2);
state_by_hash.insert(hash1, state1);
state_by_hash.insert(hash2, state2);
let in_memory_state = InMemoryState::new(state_by_hash, hash_by_number, None);
let head_state = in_memory_state.head_state().unwrap();
assert_eq!(head_state.hash(), hash2);
assert_eq!(head_state.number(), 2);
}
#[test]
fn test_in_memory_state_impl_pending_state() {
let pending_number = rand::thread_rng().gen::<u64>();
let mut test_block_builder = TestBlockBuilder::default();
let pending_state =
create_mock_state(&mut test_block_builder, pending_number, B256::random());
let pending_hash = pending_state.hash();
let in_memory_state =
InMemoryState::new(HashMap::default(), BTreeMap::new(), Some(pending_state));
let result = in_memory_state.pending_state();
assert!(result.is_some());
let actual_pending_state = result.unwrap();
assert_eq!(actual_pending_state.block.block().hash(), pending_hash);
assert_eq!(actual_pending_state.block.block().number, pending_number);
}
#[test]
fn test_in_memory_state_impl_no_pending_state() {
let in_memory_state = InMemoryState::new(HashMap::default(), BTreeMap::new(), None);
assert_eq!(in_memory_state.pending_state(), None);
}
#[test]
fn test_state_new() {
let number = rand::thread_rng().gen::<u64>();
let mut test_block_builder = TestBlockBuilder::default();
let block = test_block_builder.get_executed_block_with_number(number, B256::random());
let state = BlockState::new(block.clone());
assert_eq!(state.block(), block);
}
#[test]
fn test_state_block() {
let number = rand::thread_rng().gen::<u64>();
let mut test_block_builder = TestBlockBuilder::default();
let block = test_block_builder.get_executed_block_with_number(number, B256::random());
let state = BlockState::new(block.clone());
assert_eq!(state.block(), block);
}
#[test]
fn test_state_hash() {
let number = rand::thread_rng().gen::<u64>();
let mut test_block_builder = TestBlockBuilder::default();
let block = test_block_builder.get_executed_block_with_number(number, B256::random());
let state = BlockState::new(block.clone());
assert_eq!(state.hash(), block.block.hash());
}
#[test]
fn test_state_number() {
let number = rand::thread_rng().gen::<u64>();
let mut test_block_builder = TestBlockBuilder::default();
let block = test_block_builder.get_executed_block_with_number(number, B256::random());
let state = BlockState::new(block);
assert_eq!(state.number(), number);
}
#[test]
fn test_state_state_root() {
let number = rand::thread_rng().gen::<u64>();
let mut test_block_builder = TestBlockBuilder::default();
let block = test_block_builder.get_executed_block_with_number(number, B256::random());
let state = BlockState::new(block.clone());
assert_eq!(state.state_root(), block.block().state_root);
}
#[test]
fn test_state_receipts() {
let receipts = Receipts { receipt_vec: vec![vec![Some(Receipt::default())]] };
let mut test_block_builder = TestBlockBuilder::default();
let block =
test_block_builder.get_executed_block_with_receipts(receipts.clone(), B256::random());
let state = BlockState::new(block);
assert_eq!(state.receipts(), &receipts);
}
#[test]
fn test_in_memory_state_chain_update() {
let state = CanonicalInMemoryState::empty();
let mut test_block_builder = TestBlockBuilder::default();
let block1 = test_block_builder.get_executed_block_with_number(0, B256::random());
let block2 = test_block_builder.get_executed_block_with_number(0, B256::random());
let chain = NewCanonicalChain::Commit { new: vec![block1.clone()] };
state.update_chain(chain);
assert_eq!(state.head_state().unwrap().block_ref().block().hash(), block1.block().hash());
assert_eq!(
state.state_by_number(0).unwrap().block_ref().block().hash(),
block1.block().hash()
);
let chain = NewCanonicalChain::Reorg { new: vec![block2.clone()], old: vec![block1] };
state.update_chain(chain);
assert_eq!(state.head_state().unwrap().block_ref().block().hash(), block2.block().hash());
assert_eq!(
state.state_by_number(0).unwrap().block_ref().block().hash(),
block2.block().hash()
);
assert_eq!(state.inner.in_memory_state.block_count(), 1);
}
#[test]
fn test_in_memory_state_set_pending_block() {
let state = CanonicalInMemoryState::empty();
let mut test_block_builder = TestBlockBuilder::default();
let block1 = test_block_builder.get_executed_block_with_number(0, B256::random());
let block2 = test_block_builder.get_executed_block_with_number(1, block1.block().hash());
let chain = NewCanonicalChain::Commit { new: vec![block1.clone(), block2.clone()] };
state.update_chain(chain);
assert!(state.pending_state().is_none());
state.set_pending_block(block2.clone());
assert_eq!(
state.pending_state().unwrap(),
BlockState::with_parent(block2.clone(), Some(Arc::new(BlockState::new(block1))))
);
assert_eq!(state.pending_block().unwrap(), block2.block().clone());
assert_eq!(
state.pending_block_num_hash().unwrap(),
BlockNumHash { number: 1, hash: block2.block().hash() }
);
assert_eq!(state.pending_header().unwrap(), block2.block().header.header().clone());
assert_eq!(state.pending_sealed_header().unwrap(), block2.block().header.clone());
assert_eq!(
state.pending_block_with_senders().unwrap(),
block2.block().clone().seal_with_senders().unwrap()
);
assert_eq!(state.pending_block_and_receipts().unwrap(), (block2.block().clone(), vec![]));
}
#[test]
fn test_canonical_in_memory_state_state_provider() {
let mut test_block_builder = TestBlockBuilder::default();
let block1 = test_block_builder.get_executed_block_with_number(1, B256::random());
let block2 = test_block_builder.get_executed_block_with_number(2, block1.block().hash());
let block3 = test_block_builder.get_executed_block_with_number(3, block2.block().hash());
let state1 = Arc::new(BlockState::new(block1.clone()));
let state2 = Arc::new(BlockState::with_parent(block2.clone(), Some(state1.clone())));
let state3 = Arc::new(BlockState::with_parent(block3.clone(), Some(state2.clone())));
let mut blocks = HashMap::default();
blocks.insert(block1.block().hash(), state1);
blocks.insert(block2.block().hash(), state2);
blocks.insert(block3.block().hash(), state3);
let mut numbers = BTreeMap::new();
numbers.insert(1, block1.block().hash());
numbers.insert(2, block2.block().hash());
numbers.insert(3, block3.block().hash());
let canonical_state = CanonicalInMemoryState::new(blocks, numbers, None, None, None);
let historical: StateProviderBox = Box::new(MockStateProvider);
let overlay_provider = canonical_state.state_provider(block3.block().hash(), historical);
assert_eq!(overlay_provider.in_memory.len(), 3);
assert_eq!(overlay_provider.in_memory[0].block().number, 3);
assert_eq!(overlay_provider.in_memory[1].block().number, 2);
assert_eq!(overlay_provider.in_memory[2].block().number, 1);
assert_eq!(
overlay_provider.in_memory[0].block().parent_hash,
overlay_provider.in_memory[1].block().hash()
);
assert_eq!(
overlay_provider.in_memory[1].block().parent_hash,
overlay_provider.in_memory[2].block().hash()
);
let unknown_hash = B256::random();
let empty_overlay_provider =
canonical_state.state_provider(unknown_hash, Box::new(MockStateProvider));
assert_eq!(empty_overlay_provider.in_memory.len(), 0);
}
#[test]
fn test_canonical_in_memory_state_canonical_chain_empty() {
let state = CanonicalInMemoryState::empty();
let chain: Vec<_> = state.canonical_chain().collect();
assert!(chain.is_empty());
}
#[test]
fn test_canonical_in_memory_state_canonical_chain_single_block() {
let block = TestBlockBuilder::default().get_executed_block_with_number(1, B256::random());
let hash = block.block().hash();
let mut blocks = HashMap::default();
blocks.insert(hash, Arc::new(BlockState::new(block)));
let mut numbers = BTreeMap::new();
numbers.insert(1, hash);
let state = CanonicalInMemoryState::new(blocks, numbers, None, None, None);
let chain: Vec<_> = state.canonical_chain().collect();
assert_eq!(chain.len(), 1);
assert_eq!(chain[0].number(), 1);
assert_eq!(chain[0].hash(), hash);
}
#[test]
fn test_canonical_in_memory_state_canonical_chain_multiple_blocks() {
let mut parent_hash = B256::random();
let mut block_builder = TestBlockBuilder::default();
let state = CanonicalInMemoryState::empty();
for i in 1..=3 {
let block = block_builder.get_executed_block_with_number(i, parent_hash);
let hash = block.block().hash();
state.update_blocks(Some(block), None);
parent_hash = hash;
}
let chain: Vec<_> = state.canonical_chain().collect();
assert_eq!(chain.len(), 3);
assert_eq!(chain[0].number(), 3);
assert_eq!(chain[1].number(), 2);
assert_eq!(chain[2].number(), 1);
}
#[test]
fn test_canonical_in_memory_state_canonical_chain_with_pending_block() {
let mut parent_hash = B256::random();
let mut block_builder = TestBlockBuilder::default();
let state = CanonicalInMemoryState::empty();
for i in 1..=2 {
let block = block_builder.get_executed_block_with_number(i, parent_hash);
let hash = block.block().hash();
state.update_blocks(Some(block), None);
parent_hash = hash;
}
let pending_block = block_builder.get_executed_block_with_number(3, parent_hash);
state.set_pending_block(pending_block);
let chain: Vec<_> = state.canonical_chain().collect();
assert_eq!(chain.len(), 2);
assert_eq!(chain[0].number(), 2);
assert_eq!(chain[1].number(), 1);
}
#[test]
fn test_block_state_parent_blocks() {
let mut test_block_builder = TestBlockBuilder::default();
let chain = create_mock_state_chain(&mut test_block_builder, 4);
let parents = chain[3].parent_state_chain();
assert_eq!(parents.len(), 3);
assert_eq!(parents[0].block().block.number, 3);
assert_eq!(parents[1].block().block.number, 2);
assert_eq!(parents[2].block().block.number, 1);
let parents = chain[2].parent_state_chain();
assert_eq!(parents.len(), 2);
assert_eq!(parents[0].block().block.number, 2);
assert_eq!(parents[1].block().block.number, 1);
let parents = chain[0].parent_state_chain();
assert_eq!(parents.len(), 0);
}
#[test]
fn test_block_state_single_block_state_chain() {
let single_block_number = 1;
let mut test_block_builder = TestBlockBuilder::default();
let single_block =
create_mock_state(&mut test_block_builder, single_block_number, B256::random());
let single_block_hash = single_block.block().block.hash();
let parents = single_block.parent_state_chain();
assert_eq!(parents.len(), 0);
let block_state_chain = single_block.chain().collect::<Vec<_>>();
assert_eq!(block_state_chain.len(), 1);
assert_eq!(block_state_chain[0].block().block.number, single_block_number);
assert_eq!(block_state_chain[0].block().block.hash(), single_block_hash);
}
#[test]
fn test_block_state_chain() {
let mut test_block_builder = TestBlockBuilder::default();
let chain = create_mock_state_chain(&mut test_block_builder, 3);
let block_state_chain = chain[2].chain().collect::<Vec<_>>();
assert_eq!(block_state_chain.len(), 3);
assert_eq!(block_state_chain[0].block().block.number, 3);
assert_eq!(block_state_chain[1].block().block.number, 2);
assert_eq!(block_state_chain[2].block().block.number, 1);
let block_state_chain = chain[1].chain().collect::<Vec<_>>();
assert_eq!(block_state_chain.len(), 2);
assert_eq!(block_state_chain[0].block().block.number, 2);
assert_eq!(block_state_chain[1].block().block.number, 1);
let block_state_chain = chain[0].chain().collect::<Vec<_>>();
assert_eq!(block_state_chain.len(), 1);
assert_eq!(block_state_chain[0].block().block.number, 1);
}
#[test]
fn test_to_chain_notification() {
let mut test_block_builder = TestBlockBuilder::default();
let block0 = test_block_builder.get_executed_block_with_number(0, B256::random());
let block1 = test_block_builder.get_executed_block_with_number(1, block0.block.hash());
let block1a = test_block_builder.get_executed_block_with_number(1, block0.block.hash());
let block2 = test_block_builder.get_executed_block_with_number(2, block1.block.hash());
let block2a = test_block_builder.get_executed_block_with_number(2, block1.block.hash());
let sample_execution_outcome = ExecutionOutcome {
receipts: Receipts::from_iter([vec![], vec![]]),
requests: vec![Requests::default(), Requests::default()],
..Default::default()
};
let chain_commit = NewCanonicalChain::Commit { new: vec![block0.clone(), block1.clone()] };
assert_eq!(
chain_commit.to_chain_notification(),
CanonStateNotification::Commit {
new: Arc::new(Chain::new(
vec![block0.sealed_block_with_senders(), block1.sealed_block_with_senders()],
sample_execution_outcome.clone(),
None
))
}
);
let chain_reorg = NewCanonicalChain::Reorg {
new: vec![block1a.clone(), block2a.clone()],
old: vec![block1.clone(), block2.clone()],
};
assert_eq!(
chain_reorg.to_chain_notification(),
CanonStateNotification::Reorg {
old: Arc::new(Chain::new(
vec![block1.sealed_block_with_senders(), block2.sealed_block_with_senders()],
sample_execution_outcome.clone(),
None
)),
new: Arc::new(Chain::new(
vec![block1a.sealed_block_with_senders(), block2a.sealed_block_with_senders()],
sample_execution_outcome,
None
))
}
);
}
}