feat(revm): Integrate State (#3512)

Co-authored-by: Roman Krasiuk <rokrassyuk@gmail.com>
Co-authored-by: Alexey Shekhirin <a.shekhirin@gmail.com>
Co-authored-by: Dan Cline <6798349+Rjected@users.noreply.github.com>
Co-authored-by: Bjerg <onbjerg@users.noreply.github.com>
This commit is contained in:
rakita
2023-09-16 13:00:22 +02:00
committed by GitHub
parent 62e7d98202
commit f153d8f4d4
93 changed files with 3436 additions and 4975 deletions

View File

@ -31,8 +31,14 @@ use reth_primitives::{
Header, ReceiptWithBloom, SealedBlock, SealedHeader, TransactionSigned, EMPTY_OMMER_ROOT, H256,
U256,
};
use reth_provider::{BlockReaderIdExt, CanonStateNotificationSender, PostState, StateProvider};
use reth_revm::executor::Executor;
use reth_provider::{
BlockExecutor, BlockReaderIdExt, BundleStateWithReceipts, CanonStateNotificationSender,
StateProviderFactory,
};
use reth_revm::{
database::StateProviderDatabase, db::states::bundle_state::BundleRetention,
processor::EVMProcessor, State,
};
use reth_transaction_pool::TransactionPool;
use std::{
collections::HashMap,
@ -289,41 +295,51 @@ impl StorageInner {
header
}
/// Executes the block with the given block and senders, on the provided [Executor].
/// Executes the block with the given block and senders, on the provided [EVMProcessor].
///
/// This returns the poststate from execution and post-block changes, as well as the gas used.
pub(crate) fn execute<DB: StateProvider>(
pub(crate) fn execute(
&mut self,
block: &Block,
executor: &mut Executor<DB>,
executor: &mut EVMProcessor<'_>,
senders: Vec<Address>,
) -> Result<(PostState, u64), BlockExecutionError> {
) -> Result<(BundleStateWithReceipts, u64), BlockExecutionError> {
trace!(target: "consensus::auto", transactions=?&block.body, "executing transactions");
let (post_state, gas_used) =
let (receipts, gas_used) =
executor.execute_transactions(block, U256::ZERO, Some(senders))?;
// apply post block changes
let post_state = executor.apply_post_block_changes(block, U256::ZERO, post_state)?;
// Save receipts.
executor.save_receipts(receipts)?;
Ok((post_state, gas_used))
// add post execution state change
// Withdrawals, rewards etc.
executor.apply_post_execution_state_change(block, U256::ZERO)?;
// merge transitions
executor.db_mut().merge_transitions(BundleRetention::Reverts);
// apply post block changes
Ok((executor.take_output_state(), gas_used))
}
/// Fills in the post-execution header fields based on the given PostState and gas used.
/// Fills in the post-execution header fields based on the given BundleState and gas used.
/// In doing this, the state root is calculated and the final header is returned.
pub(crate) fn complete_header<DB: StateProvider>(
pub(crate) fn complete_header<S: StateProviderFactory>(
&self,
mut header: Header,
post_state: &PostState,
executor: &mut Executor<DB>,
bundle_state: &BundleStateWithReceipts,
client: &S,
gas_used: u64,
) -> Header {
let receipts = post_state.receipts(header.number);
) -> Result<Header, BlockExecutionError> {
let receipts = bundle_state.receipts_by_block(header.number);
header.receipts_root = if receipts.is_empty() {
EMPTY_RECEIPTS
} else {
let receipts_with_bloom =
receipts.iter().map(|r| r.clone().into()).collect::<Vec<ReceiptWithBloom>>();
let receipts_with_bloom = receipts
.iter()
.map(|r| (*r).clone().expect("receipts have not been pruned").into())
.collect::<Vec<ReceiptWithBloom>>();
header.logs_bloom =
receipts_with_bloom.iter().fold(Bloom::zero(), |bloom, r| bloom | r.bloom);
proofs::calculate_receipt_root(&receipts_with_bloom)
@ -332,21 +348,25 @@ impl StorageInner {
header.gas_used = gas_used;
// calculate the state root
let state_root = executor.db().db.0.state_root(post_state.clone()).unwrap();
let state_root = client
.latest()
.map_err(|_| BlockExecutionError::ProviderError)?
.state_root(bundle_state.clone())
.unwrap();
header.state_root = state_root;
header
Ok(header)
}
/// Builds and executes a new block with the given transactions, on the provided [Executor].
/// Builds and executes a new block with the given transactions, on the provided [EVMProcessor].
///
/// This returns the header of the executed block, as well as the poststate from execution.
pub(crate) fn build_and_execute<DB: StateProvider>(
pub(crate) fn build_and_execute(
&mut self,
transactions: Vec<TransactionSigned>,
executor: &mut Executor<DB>,
client: &impl StateProviderFactory,
chain_spec: Arc<ChainSpec>,
) -> Result<(SealedHeader, PostState), BlockExecutionError> {
let header = self.build_header_template(&transactions, chain_spec);
) -> Result<(SealedHeader, BundleStateWithReceipts), BlockExecutionError> {
let header = self.build_header_template(&transactions, chain_spec.clone());
let block = Block { header, body: transactions, ommers: vec![], withdrawals: None };
@ -356,15 +376,21 @@ impl StorageInner {
trace!(target: "consensus::auto", transactions=?&block.body, "executing transactions");
// now execute the block
let (post_state, gas_used) = self.execute(&block, executor, senders)?;
let db = State::builder()
.with_database_boxed(Box::new(StateProviderDatabase::new(client.latest().unwrap())))
.with_bundle_update()
.build();
let mut executor = EVMProcessor::new_with_state(chain_spec, db);
let (bundle_state, gas_used) = self.execute(&block, &mut executor, senders)?;
let Block { header, body, .. } = block;
let body = BlockBody { transactions: body, ommers: vec![], withdrawals: None };
trace!(target: "consensus::auto", ?post_state, ?header, ?body, "executed block, calculating state root and completing header");
trace!(target: "consensus::auto", ?bundle_state, ?header, ?body, "executed block, calculating state root and completing header");
// fill in the rest of the fields
let header = self.complete_header(header, &post_state, executor, gas_used);
let header = self.complete_header(header, &bundle_state, client, gas_used)?;
trace!(target: "consensus::auto", root=?header.state_root, ?body, "calculated root");
@ -374,6 +400,6 @@ impl StorageInner {
// set new header with hash that should have been updated by insert_new_block
let new_header = header.seal(self.best_hash);
Ok((new_header, post_state))
Ok((new_header, bundle_state))
}
}

View File

@ -4,10 +4,6 @@ use reth_beacon_consensus::{BeaconEngineMessage, ForkchoiceStatus};
use reth_interfaces::consensus::ForkchoiceState;
use reth_primitives::{Block, ChainSpec, IntoRecoveredTransaction, SealedBlockWithSenders};
use reth_provider::{CanonChainTracker, CanonStateNotificationSender, Chain, StateProviderFactory};
use reth_revm::{
database::{State, SubState},
executor::Executor,
};
use reth_stages::PipelineEvent;
use reth_transaction_pool::{TransactionPool, ValidPoolTransaction};
use std::{
@ -127,13 +123,8 @@ where
})
.unzip();
// execute the new block
let substate = SubState::new(State::new(client.latest().unwrap()));
let mut executor = Executor::new(Arc::clone(&chain_spec), substate);
match storage.build_and_execute(transactions.clone(), &mut executor, chain_spec)
{
Ok((new_header, post_state)) => {
match storage.build_and_execute(transactions.clone(), &client, chain_spec) {
Ok((new_header, bundle_state)) => {
// clear all transactions from pool
pool.remove_transactions(
transactions.iter().map(|tx| tx.hash()).collect(),
@ -202,7 +193,7 @@ where
debug!(target: "consensus::auto", header=?sealed_block_with_senders.hash(), "sending block notification");
let chain =
Arc::new(Chain::new(vec![(sealed_block_with_senders, post_state)]));
Arc::new(Chain::new(vec![sealed_block_with_senders], bundle_state));
// send block notification
let _ = canon_state_notification