chore(sdk): make reth-chain-state types generic over receipt (#12667)

This commit is contained in:
Emilia Hane
2024-11-19 21:16:45 +01:00
committed by GitHub
parent fcb5050f87
commit aa34a2795b
10 changed files with 144 additions and 127 deletions

1
Cargo.lock generated
View File

@@ -7644,6 +7644,7 @@ dependencies = [
"reth-chain-state",
"reth-execution-types",
"reth-primitives",
"reth-primitives-traits",
"serde",
"serde_with",
]

View File

@@ -13,8 +13,8 @@ use reth_evm::execute::BlockExecutorProvider;
use reth_node_types::NodeTypesWithDB;
use reth_primitives::{Receipt, SealedBlock, SealedBlockWithSenders, SealedHeader};
use reth_provider::{
providers::ProviderNodeTypes, BlockchainTreePendingStateProvider, CanonStateSubscriptions,
FullExecutionDataProvider, ProviderError,
providers::ProviderNodeTypes, BlockchainTreePendingStateProvider, CanonStateNotifications,
CanonStateSubscriptions, FullExecutionDataProvider, ProviderError,
};
use reth_storage_errors::provider::ProviderResult;
use std::{collections::BTreeMap, sync::Arc};
@@ -188,7 +188,7 @@ where
N: ProviderNodeTypes,
E: Send + Sync,
{
fn subscribe_to_canonical_state(&self) -> reth_provider::CanonStateNotifications {
fn subscribe_to_canonical_state(&self) -> CanonStateNotifications {
trace!(target: "blockchain_tree", "Registered subscriber for canonical state");
self.tree.read().subscribe_canon_state()
}

View File

@@ -12,7 +12,7 @@ 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,
BlockWithSenders, NodePrimitives, Receipts, SealedBlock, SealedBlockWithSenders, SealedHeader,
TransactionMeta, TransactionSigned,
};
use reth_storage_api::StateProviderBox;
@@ -50,22 +50,22 @@ pub(crate) struct InMemoryStateMetrics {
/// This holds, because only lookup by number functions need to acquire the numbers lock first to
/// get the block hash.
#[derive(Debug, Default)]
pub(crate) struct InMemoryState {
pub(crate) struct InMemoryState<N: NodePrimitives = reth_primitives::EthPrimitives> {
/// All canonical blocks that are not on disk yet.
blocks: RwLock<HashMap<B256, Arc<BlockState>>>,
blocks: RwLock<HashMap<B256, Arc<BlockState<N>>>>,
/// Mapping of block numbers to block hashes.
numbers: RwLock<BTreeMap<u64, B256>>,
/// The pending block that has not yet been made canonical.
pending: watch::Sender<Option<BlockState>>,
pending: watch::Sender<Option<BlockState<N>>>,
/// Metrics for the in-memory state.
metrics: InMemoryStateMetrics,
}
impl InMemoryState {
impl<N: NodePrimitives> InMemoryState<N> {
pub(crate) fn new(
blocks: HashMap<B256, Arc<BlockState>>,
blocks: HashMap<B256, Arc<BlockState<N>>>,
numbers: BTreeMap<u64, B256>,
pending: Option<BlockState>,
pending: Option<BlockState<N>>,
) -> Self {
let (pending, _) = watch::channel(pending);
let this = Self {
@@ -95,12 +95,12 @@ impl InMemoryState {
}
/// Returns the state for a given block hash.
pub(crate) fn state_by_hash(&self, hash: B256) -> Option<Arc<BlockState>> {
pub(crate) fn state_by_hash(&self, hash: B256) -> Option<Arc<BlockState<N>>> {
self.blocks.read().get(&hash).cloned()
}
/// Returns the state for a given block number.
pub(crate) fn state_by_number(&self, number: u64) -> Option<Arc<BlockState>> {
pub(crate) fn state_by_number(&self, number: u64) -> Option<Arc<BlockState<N>>> {
let hash = self.hash_by_number(number)?;
self.state_by_hash(hash)
}
@@ -111,14 +111,14 @@ impl InMemoryState {
}
/// Returns the current chain head state.
pub(crate) fn head_state(&self) -> Option<Arc<BlockState>> {
pub(crate) fn head_state(&self) -> Option<Arc<BlockState<N>>> {
let hash = *self.numbers.read().last_key_value()?.1;
self.state_by_hash(hash)
}
/// Returns the pending state corresponding to the current head plus one,
/// from the payload received in newPayload that does not have a FCU yet.
pub(crate) fn pending_state(&self) -> Option<BlockState> {
pub(crate) fn pending_state(&self) -> Option<BlockState<N>> {
self.pending.borrow().clone()
}
@@ -131,17 +131,17 @@ impl InMemoryState {
/// Inner type to provide in memory state. It includes a chain tracker to be
/// advanced internally by the tree.
#[derive(Debug)]
pub(crate) struct CanonicalInMemoryStateInner {
pub(crate) struct CanonicalInMemoryStateInner<N: NodePrimitives> {
/// Tracks certain chain information, such as the canonical head, safe head, and finalized
/// head.
pub(crate) chain_info_tracker: ChainInfoTracker,
/// Tracks blocks at the tip of the chain that have not been persisted to disk yet.
pub(crate) in_memory_state: InMemoryState,
pub(crate) in_memory_state: InMemoryState<N>,
/// A broadcast stream that emits events when the canonical chain is updated.
pub(crate) canon_state_notification_sender: CanonStateNotificationSender,
pub(crate) canon_state_notification_sender: CanonStateNotificationSender<N>,
}
impl CanonicalInMemoryStateInner {
impl<N: NodePrimitives> CanonicalInMemoryStateInner<N> {
/// Clears all entries in the in memory state.
fn clear(&self) {
{
@@ -162,17 +162,17 @@ impl CanonicalInMemoryStateInner {
/// all canonical blocks not on disk yet and keeps track of the block range that
/// is in memory.
#[derive(Debug, Clone)]
pub struct CanonicalInMemoryState {
pub(crate) inner: Arc<CanonicalInMemoryStateInner>,
pub struct CanonicalInMemoryState<N: NodePrimitives = reth_primitives::EthPrimitives> {
pub(crate) inner: Arc<CanonicalInMemoryStateInner<N>>,
}
impl CanonicalInMemoryState {
impl<N: NodePrimitives> CanonicalInMemoryState<N> {
/// Create a new in-memory state with the given blocks, numbers, pending state, and optional
/// finalized header.
pub fn new(
blocks: HashMap<B256, Arc<BlockState>>,
blocks: HashMap<B256, Arc<BlockState<N>>>,
numbers: BTreeMap<u64, B256>,
pending: Option<BlockState>,
pending: Option<BlockState<N>>,
finalized: Option<SealedHeader>,
safe: Option<SealedHeader>,
) -> Self {
@@ -236,7 +236,7 @@ impl CanonicalInMemoryState {
/// Updates the pending block with the given block.
///
/// Note: This assumes that the parent block of the pending block is canonical.
pub fn set_pending_block(&self, pending: ExecutedBlock) {
pub fn set_pending_block(&self, pending: ExecutedBlock<N>) {
// fetch the state of the pending block's parent block
let parent = self.state_by_hash(pending.block().parent_hash);
let pending = BlockState::with_parent(pending, parent);
@@ -252,7 +252,7 @@ impl CanonicalInMemoryState {
/// them to their parent blocks.
fn update_blocks<I>(&self, new_blocks: I, reorged: I)
where
I: IntoIterator<Item = ExecutedBlock>,
I: IntoIterator<Item = ExecutedBlock<N>>,
{
{
// acquire locks, starting with the numbers lock
@@ -288,7 +288,7 @@ impl CanonicalInMemoryState {
}
/// Update the in memory state with the given chain update.
pub fn update_chain(&self, new_chain: NewCanonicalChain) {
pub fn update_chain(&self, new_chain: NewCanonicalChain<N>) {
match new_chain {
NewCanonicalChain::Commit { new } => {
self.update_blocks(new, vec![]);
@@ -359,22 +359,22 @@ impl CanonicalInMemoryState {
}
/// Returns in memory state corresponding the given hash.
pub fn state_by_hash(&self, hash: B256) -> Option<Arc<BlockState>> {
pub fn state_by_hash(&self, hash: B256) -> Option<Arc<BlockState<N>>> {
self.inner.in_memory_state.state_by_hash(hash)
}
/// Returns in memory state corresponding the block number.
pub fn state_by_number(&self, number: u64) -> Option<Arc<BlockState>> {
pub fn state_by_number(&self, number: u64) -> Option<Arc<BlockState<N>>> {
self.inner.in_memory_state.state_by_number(number)
}
/// Returns the in memory head state.
pub fn head_state(&self) -> Option<Arc<BlockState>> {
pub fn head_state(&self) -> Option<Arc<BlockState<N>>> {
self.inner.in_memory_state.head_state()
}
/// Returns the in memory pending state.
pub fn pending_state(&self) -> Option<BlockState> {
pub fn pending_state(&self) -> Option<BlockState<N>> {
self.inner.in_memory_state.pending_state()
}
@@ -479,14 +479,14 @@ impl CanonicalInMemoryState {
/// Returns a tuple with the `SealedBlock` corresponding to the pending
/// state and a vector of its `Receipt`s.
pub fn pending_block_and_receipts(&self) -> Option<(SealedBlock, Vec<Receipt>)> {
pub fn pending_block_and_receipts(&self) -> Option<(SealedBlock, Vec<N::Receipt>)> {
self.pending_state().map(|block_state| {
(block_state.block_ref().block().clone(), block_state.executed_block_receipts())
})
}
/// Subscribe to new blocks events.
pub fn subscribe_canon_state(&self) -> CanonStateNotifications {
pub fn subscribe_canon_state(&self) -> CanonStateNotifications<N> {
self.inner.canon_state_notification_sender.subscribe()
}
@@ -501,7 +501,7 @@ impl CanonicalInMemoryState {
}
/// Attempts to send a new [`CanonStateNotification`] to all active Receiver handles.
pub fn notify_canon_state(&self, event: CanonStateNotification) {
pub fn notify_canon_state(&self, event: CanonStateNotification<N>) {
self.inner.canon_state_notification_sender.send(event).ok();
}
@@ -513,7 +513,7 @@ impl CanonicalInMemoryState {
&self,
hash: B256,
historical: StateProviderBox,
) -> MemoryOverlayStateProvider {
) -> MemoryOverlayStateProvider<N> {
let in_memory = if let Some(state) = self.state_by_hash(hash) {
state.chain().map(|block_state| block_state.block()).collect()
} else {
@@ -527,7 +527,7 @@ impl CanonicalInMemoryState {
/// oldest (highest to lowest).
///
/// This iterator contains a snapshot of the in-memory state at the time of the call.
pub fn canonical_chain(&self) -> impl Iterator<Item = Arc<BlockState>> {
pub fn canonical_chain(&self) -> impl Iterator<Item = Arc<BlockState<N>>> {
self.inner.in_memory_state.head_state().into_iter().flat_map(|head| head.iter())
}
@@ -577,22 +577,22 @@ impl CanonicalInMemoryState {
/// State after applying the given block, this block is part of the canonical chain that partially
/// stored in memory and can be traced back to a canonical block on disk.
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct BlockState {
pub struct BlockState<N: NodePrimitives = reth_primitives::EthPrimitives> {
/// The executed block that determines the state after this block has been executed.
block: ExecutedBlock,
block: ExecutedBlock<N>,
/// The block's parent block if it exists.
parent: Option<Arc<BlockState>>,
parent: Option<Arc<BlockState<N>>>,
}
#[allow(dead_code)]
impl BlockState {
impl<N: NodePrimitives> BlockState<N> {
/// [`BlockState`] constructor.
pub const fn new(block: ExecutedBlock) -> Self {
pub const fn new(block: ExecutedBlock<N>) -> Self {
Self { block, parent: None }
}
/// [`BlockState`] constructor with parent.
pub const fn with_parent(block: ExecutedBlock, parent: Option<Arc<Self>>) -> Self {
pub const fn with_parent(block: ExecutedBlock<N>, parent: Option<Arc<Self>>) -> Self {
Self { block, parent }
}
@@ -606,12 +606,12 @@ impl BlockState {
}
/// Returns the executed block that determines the state.
pub fn block(&self) -> ExecutedBlock {
pub fn block(&self) -> ExecutedBlock<N> {
self.block.clone()
}
/// Returns a reference to the executed block that determines the state.
pub const fn block_ref(&self) -> &ExecutedBlock {
pub const fn block_ref(&self) -> &ExecutedBlock<N> {
&self.block
}
@@ -646,7 +646,7 @@ impl BlockState {
}
/// Returns the `Receipts` of executed block that determines the state.
pub fn receipts(&self) -> &Receipts {
pub fn receipts(&self) -> &Receipts<N::Receipt> {
&self.block.execution_outcome().receipts
}
@@ -654,7 +654,7 @@ impl BlockState {
/// We assume that the `Receipts` in the executed block `ExecutionOutcome`
/// has only one element corresponding to the executed block associated to
/// the state.
pub fn executed_block_receipts(&self) -> Vec<Receipt> {
pub fn executed_block_receipts(&self) -> Vec<N::Receipt> {
let receipts = self.receipts();
debug_assert!(
@@ -713,7 +713,7 @@ impl BlockState {
///
/// This merges the state of all blocks that are part of the chain that the this block is
/// the head of. This includes all blocks that connect back to the canonical block on disk.
pub fn state_provider(&self, historical: StateProviderBox) -> MemoryOverlayStateProvider {
pub fn state_provider(&self, historical: StateProviderBox) -> MemoryOverlayStateProvider<N> {
let in_memory = self.chain().map(|block_state| block_state.block()).collect();
MemoryOverlayStateProvider::new(historical, in_memory)
@@ -771,25 +771,25 @@ impl BlockState {
/// Represents an executed block stored in-memory.
#[derive(Clone, Debug, PartialEq, Eq, Default)]
pub struct ExecutedBlock {
pub struct ExecutedBlock<N: NodePrimitives = reth_primitives::EthPrimitives> {
/// Sealed block the rest of fields refer to.
pub block: Arc<SealedBlock>,
/// Block's senders.
pub senders: Arc<Vec<Address>>,
/// Block's execution outcome.
pub execution_output: Arc<ExecutionOutcome>,
pub execution_output: Arc<ExecutionOutcome<N::Receipt>>,
/// Block's hashed state.
pub hashed_state: Arc<HashedPostState>,
/// Trie updates that result of applying the block.
pub trie: Arc<TrieUpdates>,
}
impl ExecutedBlock {
impl<N: NodePrimitives> ExecutedBlock<N> {
/// [`ExecutedBlock`] constructor.
pub const fn new(
block: Arc<SealedBlock>,
senders: Arc<Vec<Address>>,
execution_output: Arc<ExecutionOutcome>,
execution_output: Arc<ExecutionOutcome<N::Receipt>>,
hashed_state: Arc<HashedPostState>,
trie: Arc<TrieUpdates>,
) -> Self {
@@ -814,7 +814,7 @@ impl ExecutedBlock {
}
/// Returns a reference to the block's execution outcome
pub fn execution_outcome(&self) -> &ExecutionOutcome {
pub fn execution_outcome(&self) -> &ExecutionOutcome<N::Receipt> {
&self.execution_output
}
@@ -831,23 +831,23 @@ impl ExecutedBlock {
/// Non-empty chain of blocks.
#[derive(Debug)]
pub enum NewCanonicalChain {
pub enum NewCanonicalChain<N: NodePrimitives = reth_primitives::EthPrimitives> {
/// A simple append to the current canonical head
Commit {
/// all blocks that lead back to the canonical head
new: Vec<ExecutedBlock>,
new: Vec<ExecutedBlock<N>>,
},
/// A reorged chain consists of two chains that trace back to a shared ancestor block at which
/// point they diverge.
Reorg {
/// All blocks of the _new_ chain
new: Vec<ExecutedBlock>,
new: Vec<ExecutedBlock<N>>,
/// All blocks of the _old_ chain
old: Vec<ExecutedBlock>,
old: Vec<ExecutedBlock<N>>,
},
}
impl NewCanonicalChain {
impl<N: NodePrimitives> NewCanonicalChain<N> {
/// Returns the length of the new chain.
pub fn new_block_count(&self) -> usize {
match self {
@@ -864,7 +864,7 @@ impl NewCanonicalChain {
}
/// Converts the new chain into a notification that will be emitted to listeners
pub fn to_chain_notification(&self) -> CanonStateNotification {
pub fn to_chain_notification(&self) -> CanonStateNotification<N> {
match self {
Self::Commit { new } => {
let new = Arc::new(new.iter().fold(Chain::default(), |mut chain, exec| {
@@ -917,7 +917,7 @@ mod tests {
use alloy_primitives::{map::HashSet, BlockNumber, Bytes, StorageKey, StorageValue};
use rand::Rng;
use reth_errors::ProviderResult;
use reth_primitives::{Account, Bytecode, Receipt};
use reth_primitives::{Account, Bytecode, EthPrimitives, Receipt};
use reth_storage_api::{
AccountReader, BlockHashReader, StateProofProvider, StateProvider, StateRootProvider,
StorageRootProvider,
@@ -925,7 +925,7 @@ mod tests {
use reth_trie::{AccountProof, HashedStorage, MultiProof, StorageProof, TrieInput};
fn create_mock_state(
test_block_builder: &mut TestBlockBuilder,
test_block_builder: &mut TestBlockBuilder<EthPrimitives>,
block_number: u64,
parent_hash: B256,
) -> BlockState {
@@ -935,7 +935,7 @@ mod tests {
}
fn create_mock_state_chain(
test_block_builder: &mut TestBlockBuilder,
test_block_builder: &mut TestBlockBuilder<EthPrimitives>,
num_blocks: u64,
) -> Vec<BlockState> {
let mut chain = Vec::with_capacity(num_blocks as usize);
@@ -1065,7 +1065,7 @@ mod tests {
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 mut test_block_builder: TestBlockBuilder = TestBlockBuilder::default();
let state = Arc::new(create_mock_state(&mut test_block_builder, number, B256::random()));
state_by_hash.insert(state.hash(), state.clone());
@@ -1081,7 +1081,7 @@ mod tests {
let mut hash_by_number = BTreeMap::new();
let number = rand::thread_rng().gen::<u64>();
let mut test_block_builder = TestBlockBuilder::default();
let mut test_block_builder: TestBlockBuilder = TestBlockBuilder::default();
let state = Arc::new(create_mock_state(&mut test_block_builder, number, B256::random()));
let hash = state.hash();
@@ -1098,7 +1098,7 @@ mod tests {
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 mut test_block_builder: TestBlockBuilder = 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));
@@ -1118,7 +1118,7 @@ mod tests {
#[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 mut test_block_builder: TestBlockBuilder = TestBlockBuilder::default();
let pending_state =
create_mock_state(&mut test_block_builder, pending_number, B256::random());
let pending_hash = pending_state.hash();
@@ -1135,7 +1135,8 @@ mod tests {
#[test]
fn test_in_memory_state_impl_no_pending_state() {
let in_memory_state = InMemoryState::new(HashMap::default(), BTreeMap::new(), None);
let in_memory_state: InMemoryState =
InMemoryState::new(HashMap::default(), BTreeMap::new(), None);
assert_eq!(in_memory_state.pending_state(), None);
}
@@ -1143,7 +1144,7 @@ mod tests {
#[test]
fn test_state_new() {
let number = rand::thread_rng().gen::<u64>();
let mut test_block_builder = TestBlockBuilder::default();
let mut test_block_builder: TestBlockBuilder = TestBlockBuilder::default();
let block = test_block_builder.get_executed_block_with_number(number, B256::random());
let state = BlockState::new(block.clone());
@@ -1154,7 +1155,7 @@ mod tests {
#[test]
fn test_state_block() {
let number = rand::thread_rng().gen::<u64>();
let mut test_block_builder = TestBlockBuilder::default();
let mut test_block_builder: TestBlockBuilder = TestBlockBuilder::default();
let block = test_block_builder.get_executed_block_with_number(number, B256::random());
let state = BlockState::new(block.clone());
@@ -1165,7 +1166,7 @@ mod tests {
#[test]
fn test_state_hash() {
let number = rand::thread_rng().gen::<u64>();
let mut test_block_builder = TestBlockBuilder::default();
let mut test_block_builder: TestBlockBuilder = TestBlockBuilder::default();
let block = test_block_builder.get_executed_block_with_number(number, B256::random());
let state = BlockState::new(block.clone());
@@ -1176,7 +1177,7 @@ mod tests {
#[test]
fn test_state_number() {
let number = rand::thread_rng().gen::<u64>();
let mut test_block_builder = TestBlockBuilder::default();
let mut test_block_builder: TestBlockBuilder = TestBlockBuilder::default();
let block = test_block_builder.get_executed_block_with_number(number, B256::random());
let state = BlockState::new(block);
@@ -1187,7 +1188,7 @@ mod tests {
#[test]
fn test_state_state_root() {
let number = rand::thread_rng().gen::<u64>();
let mut test_block_builder = TestBlockBuilder::default();
let mut test_block_builder: TestBlockBuilder = TestBlockBuilder::default();
let block = test_block_builder.get_executed_block_with_number(number, B256::random());
let state = BlockState::new(block.clone());
@@ -1198,7 +1199,7 @@ mod tests {
#[test]
fn test_state_receipts() {
let receipts = Receipts { receipt_vec: vec![vec![Some(Receipt::default())]] };
let mut test_block_builder = TestBlockBuilder::default();
let mut test_block_builder: TestBlockBuilder = TestBlockBuilder::default();
let block =
test_block_builder.get_executed_block_with_receipts(receipts.clone(), B256::random());
@@ -1209,8 +1210,8 @@ mod tests {
#[test]
fn test_in_memory_state_chain_update() {
let state = CanonicalInMemoryState::empty();
let mut test_block_builder = TestBlockBuilder::default();
let state: CanonicalInMemoryState = CanonicalInMemoryState::empty();
let mut test_block_builder: TestBlockBuilder = 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()] };
@@ -1234,8 +1235,8 @@ mod tests {
#[test]
fn test_in_memory_state_set_pending_block() {
let state = CanonicalInMemoryState::empty();
let mut test_block_builder = TestBlockBuilder::default();
let state: CanonicalInMemoryState = CanonicalInMemoryState::empty();
let mut test_block_builder: TestBlockBuilder = TestBlockBuilder::default();
// First random block
let block1 = test_block_builder.get_executed_block_with_number(0, B256::random());
@@ -1286,7 +1287,7 @@ mod tests {
#[test]
fn test_canonical_in_memory_state_state_provider() {
let mut test_block_builder = TestBlockBuilder::default();
let mut test_block_builder: TestBlockBuilder = 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());
@@ -1333,14 +1334,15 @@ mod tests {
#[test]
fn test_canonical_in_memory_state_canonical_chain_empty() {
let state = CanonicalInMemoryState::empty();
let state: CanonicalInMemoryState = 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 block = TestBlockBuilder::<EthPrimitives>::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)));
@@ -1359,7 +1361,7 @@ mod tests {
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();
let state: CanonicalInMemoryState = CanonicalInMemoryState::empty();
for i in 1..=3 {
let block = block_builder.get_executed_block_with_number(i, parent_hash);
@@ -1381,7 +1383,7 @@ mod tests {
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();
let state: CanonicalInMemoryState = CanonicalInMemoryState::empty();
for i in 1..=2 {
let block = block_builder.get_executed_block_with_number(i, parent_hash);
@@ -1401,7 +1403,7 @@ mod tests {
#[test]
fn test_block_state_parent_blocks() {
let mut test_block_builder = TestBlockBuilder::default();
let mut test_block_builder: TestBlockBuilder = TestBlockBuilder::default();
let chain = create_mock_state_chain(&mut test_block_builder, 4);
let parents = chain[3].parent_state_chain();
@@ -1422,7 +1424,7 @@ mod tests {
#[test]
fn test_block_state_single_block_state_chain() {
let single_block_number = 1;
let mut test_block_builder = TestBlockBuilder::default();
let mut test_block_builder: TestBlockBuilder = 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();
@@ -1438,7 +1440,7 @@ mod tests {
#[test]
fn test_block_state_chain() {
let mut test_block_builder = TestBlockBuilder::default();
let mut test_block_builder: TestBlockBuilder = TestBlockBuilder::default();
let chain = create_mock_state_chain(&mut test_block_builder, 3);
let block_state_chain = chain[2].chain().collect::<Vec<_>>();
@@ -1460,7 +1462,7 @@ mod tests {
#[test]
fn test_to_chain_notification() {
// Generate 4 blocks
let mut test_block_builder = TestBlockBuilder::default();
let mut test_block_builder: TestBlockBuilder = 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());

View File

@@ -27,3 +27,6 @@ pub use memory_overlay::{MemoryOverlayStateProvider, MemoryOverlayStateProviderR
#[cfg(any(test, feature = "test-utils"))]
/// Common test helpers
pub mod test_utils;
// todo: remove when generic data prim integration complete
pub use reth_primitives::EthPrimitives;

View File

@@ -5,7 +5,7 @@ use alloy_primitives::{
Address, BlockNumber, Bytes, StorageKey, StorageValue, B256,
};
use reth_errors::ProviderResult;
use reth_primitives::{Account, Bytecode};
use reth_primitives::{Account, Bytecode, NodePrimitives};
use reth_storage_api::{
AccountReader, BlockHashReader, StateProofProvider, StateProvider, StateRootProvider,
StorageRootProvider,
@@ -18,11 +18,11 @@ use std::sync::OnceLock;
/// A state provider that stores references to in-memory blocks along with their state as well as a
/// reference of the historical state provider for fallback lookups.
#[allow(missing_debug_implementations)]
pub struct MemoryOverlayStateProviderRef<'a> {
pub struct MemoryOverlayStateProviderRef<'a, N: NodePrimitives = reth_primitives::EthPrimitives> {
/// Historical state provider for state lookups that are not found in in-memory blocks.
pub(crate) historical: Box<dyn StateProvider + 'a>,
/// The collection of executed parent blocks. Expected order is newest to oldest.
pub(crate) in_memory: Vec<ExecutedBlock>,
pub(crate) in_memory: Vec<ExecutedBlock<N>>,
/// Lazy-loaded in-memory trie data.
pub(crate) trie_state: OnceLock<MemoryOverlayTrieState>,
}
@@ -30,11 +30,11 @@ pub struct MemoryOverlayStateProviderRef<'a> {
/// A state provider that stores references to in-memory blocks along with their state as well as
/// the historical state provider for fallback lookups.
#[allow(missing_debug_implementations)]
pub struct MemoryOverlayStateProvider {
pub struct MemoryOverlayStateProvider<N: NodePrimitives = reth_primitives::EthPrimitives> {
/// Historical state provider for state lookups that are not found in in-memory blocks.
pub(crate) historical: Box<dyn StateProvider>,
/// The collection of executed parent blocks. Expected order is newest to oldest.
pub(crate) in_memory: Vec<ExecutedBlock>,
pub(crate) in_memory: Vec<ExecutedBlock<N>>,
/// Lazy-loaded in-memory trie data.
pub(crate) trie_state: OnceLock<MemoryOverlayTrieState>,
}
@@ -49,7 +49,7 @@ macro_rules! impl_state_provider {
/// - `in_memory` - the collection of executed ancestor blocks in reverse.
/// - `historical` - a historical state provider for the latest ancestor block stored in the
/// database.
pub fn new(historical: $historical_type, in_memory: Vec<ExecutedBlock>) -> Self {
pub fn new(historical: $historical_type, in_memory: Vec<ExecutedBlock<N>>) -> Self {
Self { historical, in_memory, trie_state: OnceLock::new() }
}
@@ -230,8 +230,8 @@ macro_rules! impl_state_provider {
};
}
impl_state_provider!([], MemoryOverlayStateProvider, Box<dyn StateProvider>);
impl_state_provider!([<'a>], MemoryOverlayStateProviderRef<'a>, Box<dyn StateProvider + 'a>);
impl_state_provider!([<N: NodePrimitives>], MemoryOverlayStateProvider<N>, Box<dyn StateProvider>);
impl_state_provider!([<'a, N: NodePrimitives>], MemoryOverlayStateProviderRef<'a, N>, Box<dyn StateProvider + 'a>);
/// The collection of data necessary for trie-related operations for [`MemoryOverlayStateProvider`].
#[derive(Clone, Default, Debug)]

View File

@@ -3,7 +3,7 @@
use auto_impl::auto_impl;
use derive_more::{Deref, DerefMut};
use reth_execution_types::{BlockReceipts, Chain};
use reth_primitives::{SealedBlockWithSenders, SealedHeader};
use reth_primitives::{NodePrimitives, SealedBlockWithSenders, SealedHeader};
use std::{
pin::Pin,
sync::Arc,
@@ -17,10 +17,12 @@ use tokio_stream::{
use tracing::debug;
/// Type alias for a receiver that receives [`CanonStateNotification`]
pub type CanonStateNotifications = broadcast::Receiver<CanonStateNotification>;
pub type CanonStateNotifications<N = reth_primitives::EthPrimitives> =
broadcast::Receiver<CanonStateNotification<N>>;
/// Type alias for a sender that sends [`CanonStateNotification`]
pub type CanonStateNotificationSender = broadcast::Sender<CanonStateNotification>;
pub type CanonStateNotificationSender<N = reth_primitives::EthPrimitives> =
broadcast::Sender<CanonStateNotification<N>>;
/// A type that allows to register chain related event subscriptions.
#[auto_impl(&, Arc)]
@@ -41,13 +43,13 @@ pub trait CanonStateSubscriptions: Send + Sync {
/// A Stream of [`CanonStateNotification`].
#[derive(Debug)]
#[pin_project::pin_project]
pub struct CanonStateNotificationStream {
pub struct CanonStateNotificationStream<N: NodePrimitives = reth_primitives::EthPrimitives> {
#[pin]
st: BroadcastStream<CanonStateNotification>,
st: BroadcastStream<CanonStateNotification<N>>,
}
impl Stream for CanonStateNotificationStream {
type Item = CanonStateNotification;
impl<N: NodePrimitives> Stream for CanonStateNotificationStream<N> {
type Item = CanonStateNotification<N>;
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
loop {
@@ -68,11 +70,11 @@ impl Stream for CanonStateNotificationStream {
/// The notification contains at least one [`Chain`] with the imported segment. If some blocks were
/// reverted (e.g. during a reorg), the old chain is also returned.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum CanonStateNotification {
pub enum CanonStateNotification<N: NodePrimitives = reth_primitives::EthPrimitives> {
/// The canonical chain was extended.
Commit {
/// The newly added chain segment.
new: Arc<Chain>,
new: Arc<Chain<N>>,
},
/// A chain segment was reverted or reorged.
///
@@ -82,18 +84,18 @@ pub enum CanonStateNotification {
/// chain segment.
Reorg {
/// The chain segment that was reverted.
old: Arc<Chain>,
old: Arc<Chain<N>>,
/// The chain segment that was added on top of the canonical chain, minus the reverted
/// blocks.
///
/// In the case of a revert, not a reorg, this chain segment is empty.
new: Arc<Chain>,
new: Arc<Chain<N>>,
},
}
impl CanonStateNotification {
impl<N: NodePrimitives> CanonStateNotification<N> {
/// Get the chain segment that was reverted, if any.
pub fn reverted(&self) -> Option<Arc<Chain>> {
pub fn reverted(&self) -> Option<Arc<Chain<N>>> {
match self {
Self::Commit { .. } => None,
Self::Reorg { old, .. } => Some(old.clone()),
@@ -101,7 +103,7 @@ impl CanonStateNotification {
}
/// Get the newly imported chain segment, if any.
pub fn committed(&self) -> Arc<Chain> {
pub fn committed(&self) -> Arc<Chain<N>> {
match self {
Self::Commit { new } | Self::Reorg { new, .. } => new.clone(),
}
@@ -122,7 +124,7 @@ impl CanonStateNotification {
///
/// The boolean in the tuple (2nd element) denotes whether the receipt was from the reverted
/// chain segment.
pub fn block_receipts(&self) -> Vec<(BlockReceipts, bool)> {
pub fn block_receipts(&self) -> Vec<(BlockReceipts<N::Receipt>, bool)> {
let mut receipts = Vec::new();
// get old receipts
@@ -212,7 +214,7 @@ mod tests {
block2.set_block_number(2);
block2.set_hash(block2_hash);
let chain = Arc::new(Chain::new(
let chain: Arc<Chain> = Arc::new(Chain::new(
vec![block1.clone(), block2.clone()],
ExecutionOutcome::default(),
None,
@@ -250,7 +252,7 @@ mod tests {
block3.set_block_number(3);
block3.set_hash(block3_hash);
let old_chain =
let old_chain: Arc<Chain> =
Arc::new(Chain::new(vec![block1.clone()], ExecutionOutcome::default(), None));
let new_chain = Arc::new(Chain::new(
vec![block2.clone(), block3.clone()],
@@ -313,7 +315,7 @@ mod tests {
let execution_outcome = ExecutionOutcome { receipts, ..Default::default() };
// Create a new chain segment with `block1` and `block2` and the execution outcome.
let new_chain =
let new_chain: Arc<Chain> =
Arc::new(Chain::new(vec![block1.clone(), block2.clone()], execution_outcome, None));
// Create a commit notification containing the new chain segment.
@@ -361,7 +363,8 @@ mod tests {
ExecutionOutcome { receipts: old_receipts, ..Default::default() };
// Create an old chain segment to be reverted, containing `old_block1`.
let old_chain = Arc::new(Chain::new(vec![old_block1.clone()], old_execution_outcome, None));
let old_chain: Arc<Chain> =
Arc::new(Chain::new(vec![old_block1.clone()], old_execution_outcome, None));
// Define block2 for the new chain segment, which will be committed.
let mut new_block1 = SealedBlockWithSenders::default();

View File

@@ -1,3 +1,5 @@
use core::marker::PhantomData;
use crate::{
in_memory::ExecutedBlock, CanonStateNotification, CanonStateNotifications,
CanonStateSubscriptions,
@@ -12,8 +14,8 @@ use reth_chainspec::{ChainSpec, EthereumHardfork, MIN_TRANSACTION_GAS};
use reth_execution_types::{Chain, ExecutionOutcome};
use reth_primitives::{
proofs::{calculate_receipt_root, calculate_transaction_root, calculate_withdrawals_root},
BlockBody, Receipt, Receipts, SealedBlock, SealedBlockWithSenders, SealedHeader, Transaction,
TransactionSigned, TransactionSignedEcRecovered,
BlockBody, NodePrimitives, Receipt, Receipts, SealedBlock, SealedBlockWithSenders,
SealedHeader, Transaction, TransactionSigned, TransactionSignedEcRecovered,
};
use reth_trie::{root::state_root_unhashed, updates::TrieUpdates, HashedPostState};
use revm::{db::BundleState, primitives::AccountInfo};
@@ -27,7 +29,7 @@ use tokio::sync::broadcast::{self, Sender};
/// Functionality to build blocks for tests and help with assertions about
/// their execution.
#[derive(Debug)]
pub struct TestBlockBuilder {
pub struct TestBlockBuilder<N: NodePrimitives = reth_primitives::EthPrimitives> {
/// The account that signs all the block's transactions.
pub signer: Address,
/// Private key for signing.
@@ -40,9 +42,10 @@ pub struct TestBlockBuilder {
pub signer_build_account_info: AccountInfo,
/// Chain spec of the blocks generated by this builder
pub chain_spec: ChainSpec,
_prims: PhantomData<N>,
}
impl Default for TestBlockBuilder {
impl<N: NodePrimitives> Default for TestBlockBuilder<N> {
fn default() -> Self {
let initial_account_info = AccountInfo::from_balance(U256::from(10).pow(U256::from(18)));
let signer_pk = PrivateKeySigner::random();
@@ -53,6 +56,7 @@ impl Default for TestBlockBuilder {
signer_pk,
signer_execute_account_info: initial_account_info.clone(),
signer_build_account_info: initial_account_info,
_prims: PhantomData,
}
}
}
@@ -289,8 +293,8 @@ impl TestBlockBuilder {
}
/// A test `ChainEventSubscriptions`
#[derive(Clone, Debug, Default)]
pub struct TestCanonStateSubscriptions {
canon_notif_tx: Arc<Mutex<Vec<Sender<CanonStateNotification>>>>,
pub struct TestCanonStateSubscriptions<N: NodePrimitives = reth_primitives::EthPrimitives> {
canon_notif_tx: Arc<Mutex<Vec<Sender<CanonStateNotification<N>>>>>,
}
impl TestCanonStateSubscriptions {

View File

@@ -15,6 +15,7 @@ workspace = true
# reth
reth-chain-state.workspace = true
reth-execution-types.workspace = true
reth-primitives-traits.workspace = true
# reth
alloy-primitives.workspace = true
@@ -38,11 +39,13 @@ serde = [
"reth-execution-types/serde",
"alloy-eips/serde",
"alloy-primitives/serde",
"rand/serde"
"rand/serde",
"reth-primitives-traits/serde",
]
serde-bincode-compat = [
"reth-execution-types/serde-bincode-compat",
"serde_with",
"reth-primitives/serde-bincode-compat",
"alloy-eips/serde-bincode-compat"
"alloy-eips/serde-bincode-compat",
"reth-primitives-traits/serde-bincode-compat",
]

View File

@@ -2,27 +2,28 @@ use std::sync::Arc;
use reth_chain_state::CanonStateNotification;
use reth_execution_types::Chain;
use reth_primitives_traits::NodePrimitives;
/// Notifications sent to an `ExEx`.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum ExExNotification {
pub enum ExExNotification<P: NodePrimitives = reth_chain_state::EthPrimitives> {
/// Chain got committed without a reorg, and only the new chain is returned.
ChainCommitted {
/// The new chain after commit.
new: Arc<Chain>,
new: Arc<Chain<P>>,
},
/// Chain got reorged, and both the old and the new chains are returned.
ChainReorged {
/// The old chain before reorg.
old: Arc<Chain>,
old: Arc<Chain<P>>,
/// The new chain after reorg.
new: Arc<Chain>,
new: Arc<Chain<P>>,
},
/// Chain got reverted, and only the old chain is returned.
ChainReverted {
/// The old chain before reversion.
old: Arc<Chain>,
old: Arc<Chain<P>>,
},
}
@@ -60,8 +61,8 @@ impl ExExNotification {
}
}
impl From<CanonStateNotification> for ExExNotification {
fn from(notification: CanonStateNotification) -> Self {
impl<P: NodePrimitives> From<CanonStateNotification<P>> for ExExNotification<P> {
fn from(notification: CanonStateNotification<P>) -> Self {
match notification {
CanonStateNotification::Commit { new } => Self::ChainCommitted { new },
CanonStateNotification::Reorg { old, new } => Self::ChainReorged { old, new },

View File

@@ -76,7 +76,7 @@ pub mod serde_bincode_compat {
}
/// Temp helper struct for integrating [`NodePrimitives`].
#[derive(Debug, Clone, Default, PartialEq, Eq)]
#[derive(Debug, Clone, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub struct EthPrimitives;
#[cfg(feature = "reth-codec")]