Skip to content

Commit

Permalink
add bsc-specific EvmProcessor
Browse files Browse the repository at this point in the history
  • Loading branch information
pythonberg1997 committed May 8, 2024
1 parent e1e1b33 commit 97f997f
Show file tree
Hide file tree
Showing 14 changed files with 706 additions and 318 deletions.
11 changes: 7 additions & 4 deletions bin/reth/src/commands/db/diff.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ use reth_db::{
cursor::DbCursorRO, database::Database, open_db_read_only, table::Table, transaction::DbTx,
AccountChangeSets, AccountsHistory, AccountsTrie, BlockBodyIndices, BlockOmmers,
BlockWithdrawals, Bytecodes, CanonicalHeaders, DatabaseEnv, HashedAccounts, HashedStorages,
HeaderNumbers, HeaderTerminalDifficulties, Headers, PlainAccountState, PlainStorageState,
PruneCheckpoints, Receipts, StageCheckpointProgresses, StageCheckpoints, StorageChangeSets,
StoragesHistory, StoragesTrie, Tables, TransactionBlocks, TransactionHashNumbers,
TransactionSenders, Transactions, VersionHistory,
HeaderNumbers, HeaderTerminalDifficulties, Headers, ParliaSnapshot, PlainAccountState,
PlainStorageState, PruneCheckpoints, Receipts, StageCheckpointProgresses, StageCheckpoints,
StorageChangeSets, StoragesHistory, StoragesTrie, Tables, TransactionBlocks,
TransactionHashNumbers, TransactionSenders, Transactions, VersionHistory,
};
use std::{
collections::HashMap,
Expand Down Expand Up @@ -154,6 +154,9 @@ impl Command {
Tables::VersionHistory => {
find_diffs::<VersionHistory>(primary_tx, secondary_tx, output_dir)?
}
Tables::ParliaSnapshot => {
find_diffs::<ParliaSnapshot>(primary_tx, secondary_tx, output_dir)?
}
};
}

Expand Down
3 changes: 2 additions & 1 deletion bin/reth/src/commands/db/stats.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use reth_db::{
database::Database, mdbx, static_file::iter_static_files, AccountChangeSets, AccountsHistory,
AccountsTrie, BlockBodyIndices, BlockOmmers, BlockWithdrawals, Bytecodes, CanonicalHeaders,
DatabaseEnv, HashedAccounts, HashedStorages, HeaderNumbers, HeaderTerminalDifficulties,
Headers, PlainAccountState, PlainStorageState, PruneCheckpoints, Receipts,
Headers, ParliaSnapshot, PlainAccountState, PlainStorageState, PruneCheckpoints, Receipts,
StageCheckpointProgresses, StageCheckpoints, StorageChangeSets, StoragesHistory, StoragesTrie,
Tables, TransactionBlocks, TransactionHashNumbers, TransactionSenders, Transactions,
VersionHistory,
Expand Down Expand Up @@ -359,6 +359,7 @@ impl Command {
Tables::TransactionSenders => viewer.get_checksum::<TransactionSenders>().unwrap(),
Tables::Transactions => viewer.get_checksum::<Transactions>().unwrap(),
Tables::VersionHistory => viewer.get_checksum::<VersionHistory>().unwrap(),
Tables::ParliaSnapshot => viewer.get_checksum::<ParliaSnapshot>().unwrap(),
};

// increment duration for final report
Expand Down
4 changes: 2 additions & 2 deletions crates/consensus/auto-seal/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -337,10 +337,10 @@ impl StorageInner {
/// 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<EvmConfig, P>(
pub(crate) fn execute<EvmConfig>(
&mut self,
block: &BlockWithSenders,
executor: &mut EVMProcessor<'_, EvmConfig, P>,
executor: &mut EVMProcessor<'_, EvmConfig>,
) -> Result<(BundleStateWithReceipts, u64), BlockExecutionError>
where
EvmConfig: ConfigureEvm,
Expand Down
2 changes: 1 addition & 1 deletion crates/consensus/parlia/src/feynman_fork.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use reth_primitives::{Address, U256};
use std::{cmp::Ordering, collections::BinaryHeap};

#[derive(Eq, PartialEq)]
#[derive(Debug, Eq, PartialEq)]
pub struct ValidatorItem {
pub address: Address,
pub voting_power: U256,
Expand Down
2 changes: 2 additions & 0 deletions crates/revm/src/bsc/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/// Bsc-specific processor implementation for the `EVMProcessor`
pub mod processor;
251 changes: 251 additions & 0 deletions crates/revm/src/bsc/processor.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,251 @@
use reth_evm::ConfigureEvm;
use reth_interfaces::executor::{BlockExecutionError, BlockValidationError};
use reth_primitives::{
revm::env::fill_tx_env, Address, Block, BlockNumber, BlockWithSenders, Bloom, ChainSpec,
GotExpected, Hardfork, Header, PruneModes, Receipt, ReceiptWithBloom, Receipts,
TransactionSigned, Withdrawals, B256, U256,
};
use reth_provider::{
BlockExecutor, BundleStateWithReceipts, ProviderError, PrunableBlockExecutor, StateProvider,
};
use revm::{
db::StateDBBox,
inspector_handle_register,
interpreter::Host,
primitives::{CfgEnvWithHandlerCfg, ResultAndState},
DatabaseCommit, Evm, State,
};
use std::{marker::PhantomData, sync::Arc, time::Instant};
use tracing::{debug, trace};

use crate::Database;
use reth_db::{database, models::parlia::VoteAddress};
use reth_interfaces::executor::BscBlockExecutionError;
use reth_parlia_consensus::{
get_top_validators_by_voting_power, is_breathe_block, is_system_transaction, Parlia,
DIFF_INTURN, MAX_SYSTEM_REWARD, SYSTEM_REWARD_CONTRACT, SYSTEM_REWARD_PERCENT,
};
use reth_primitives::{constants::SYSTEM_ADDRESS, Bytes, SealedHeader, Transaction};
use reth_provider::DatabaseProviderRW;
use revm::primitives::{Env, TransactTo, TxEnv};
use std::collections::HashMap;

use crate::{
batch::{BlockBatchRecord, BlockExecutorStats},
database::StateProviderDatabase,
eth_dao_fork::{DAO_HARDFORK_BENEFICIARY, DAO_HARDKFORK_ACCOUNTS},
processor::{verify_receipt, EVMProcessor},
stack::{InspectorStack, InspectorStackConfig},
state_change::{apply_beacon_root_contract_call, post_block_balance_increments},
};

/// Bsc Ethereum implementation of the [BlockExecutor] trait for the [EVMProcessor].
impl<'a, EvmConfig, P> BlockExecutor for EVMProcessor<'a, EvmConfig, P>
where
EvmConfig: ConfigureEvm,
{
type Error = BlockExecutionError;

fn execute_and_verify_receipt(
&mut self,
block: &BlockWithSenders,
total_difficulty: U256,
) -> Result<(), BlockExecutionError> {
// execute block
let receipts = self.execute_inner(block, total_difficulty)?;

// TODO Before Byzantium, receipts contained state root that would mean that expensive
// operation as hashing that is needed for state root got calculated in every
// transaction This was replaced with is_success flag.
// See more about EIP here: https://eips.ethereum.org/EIPS/eip-658
if self.chain_spec.fork(Hardfork::Byzantium).active_at_block(block.header.number) {
let time = Instant::now();
if let Err(error) =
verify_receipt(block.header.receipts_root, block.header.logs_bloom, receipts.iter())
{
debug!(target: "evm", %error, ?receipts, "receipts verification failed");
return Err(error)
};
self.stats.receipt_root_duration += time.elapsed();
}

self.batch_record.save_receipts(receipts)?;
Ok(())
}

fn execute_transactions(
&mut self,
block: &BlockWithSenders,
total_difficulty: U256,
) -> Result<(Vec<Receipt>, u64), BlockExecutionError> {
self.init_env(&block.header, total_difficulty);

// perf: do not execute empty blocks
if block.body.is_empty() {
return Ok((Vec::new(), 0))
}

let mut cumulative_gas_used = 0;
let mut receipts = Vec::with_capacity(block.body.len());
for (sender, transaction) in block.transactions_with_sender() {
let time = Instant::now();
// The sum of the transaction’s gas limit, Tg, and the gas utilized in this block prior,
// must be no greater than the block’s gasLimit.
let block_available_gas = block.header.gas_limit - cumulative_gas_used;
if transaction.gas_limit() > block_available_gas {
return Err(BlockValidationError::TransactionGasLimitMoreThanAvailableBlockGas {
transaction_gas_limit: transaction.gas_limit(),
block_available_gas,
}
.into())
}
// Execute transaction.
let ResultAndState { result, state } = self.transact(transaction, *sender)?;
trace!(
target: "evm",
?transaction, ?result, ?state,
"Executed transaction"
);
self.stats.execution_duration += time.elapsed();
let time = Instant::now();

self.db_mut().commit(state);

self.stats.apply_state_duration += time.elapsed();

// append gas used
cumulative_gas_used += result.gas_used();

// Push transaction changeset and calculate header bloom filter for receipt.
receipts.push(Receipt {
tx_type: transaction.tx_type(),
// Success flag was added in `EIP-658: Embedding transaction status code in
// receipts`.
success: result.is_success(),
cumulative_gas_used,
// convert to reth log
logs: result.into_logs().into_iter().map(Into::into).collect(),
});
}

Ok((receipts, cumulative_gas_used))
}

fn execute_transactions_and_get_system_txs(
&mut self,
block: &BlockWithSenders,
total_difficulty: U256,
) -> Result<(Vec<&TransactionSigned>, Vec<Receipt>, u64), BlockExecutionError> {
self.init_env(&block.header, total_difficulty);

if !self
.parlia_consensus
.chain_spec()
.fork(Hardfork::Feynman)
.active_at_timestamp(block.timestamp)
{
let _parent =
self.parlia_consensus.get_header_by_hash(block.number - 1, block.parent_hash)?;
// apply system contract upgrade
todo!()
}

// perf: do not execute empty blocks
if block.body.is_empty() {
return Ok((Vec::new(), Vec::new(), 0))
}

let mut cumulative_gas_used = 0;
let mut system_txs = Vec::with_capacity(2);
let mut receipts = Vec::with_capacity(block.body.len());
for (sender, transaction) in block.transactions_with_sender() {
if is_system_transaction(transaction, &block.header) {
system_txs.push(transaction);
continue
}
// systemTxs should be always at the end of block.
if self.parlia_consensus.chain_spec().is_cancun_active_at_timestamp(block.timestamp) {
if system_txs.len() > 0 {
return Err(BlockExecutionError::Validation(
BscBlockExecutionError::UnexpectedNormalTx.into(),
))
}
}

let time = Instant::now();
// The sum of the transaction’s gas limit, Tg, and the gas utilized in this block prior,
// must be no greater than the block’s gasLimit.
let block_available_gas = block.header.gas_limit - cumulative_gas_used;
if transaction.gas_limit() > block_available_gas {
return Err(BlockValidationError::TransactionGasLimitMoreThanAvailableBlockGas {
transaction_gas_limit: transaction.gas_limit(),
block_available_gas,
}
.into())
}
// Execute transaction.
let ResultAndState { result, state } = self.transact(transaction, *sender)?;
trace!(
target: "evm",
?transaction, ?result, ?state,
"Executed transaction"
);
self.stats.execution_duration += time.elapsed();
let time = Instant::now();

self.db_mut().commit(state);

self.stats.apply_state_duration += time.elapsed();

// append gas used
cumulative_gas_used += result.gas_used();

// Push transaction changeset and calculate header bloom filter for receipt.
receipts.push(Receipt {
tx_type: transaction.tx_type(),
// Success flag was added in `EIP-658: Embedding transaction status code in
// receipts`.
success: result.is_success(),
cumulative_gas_used,
// convert to reth log
logs: result.into_logs().into_iter().map(Into::into).collect(),
});
}

Ok((system_txs, receipts, cumulative_gas_used))
}

fn take_output_state(&mut self) -> BundleStateWithReceipts {
self.stats.log_debug();
BundleStateWithReceipts::new(
self.evm.context.evm.db.take_bundle(),
self.batch_record.take_receipts(),
self.batch_record.first_block().unwrap_or_default(),
)
}

fn size_hint(&self) -> Option<usize> {
Some(self.evm.context.evm.db.bundle_size_hint())
}
}

impl<'a, EvmConfig, P> PrunableBlockExecutor for EVMProcessor<'a, EvmConfig, P>
where
EvmConfig: ConfigureEvm,
{
fn set_tip(&mut self, tip: BlockNumber) {
self.batch_record.set_tip(tip);
}

fn set_prune_modes(&mut self, prune_modes: PruneModes) {
self.batch_record.set_prune_modes(prune_modes);
}

#[cfg(feature = "bsc")]
fn set_provider_for_parlia<DB: database::Database>(
&mut self,
provider: &DatabaseProviderRW<DB>,
) {
self.parlia_consensus.set_provider(provider);
}
}
34 changes: 27 additions & 7 deletions crates/revm/src/factory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,30 +9,28 @@ use reth_interfaces::executor::BlockExecutionError;
use reth_parlia_consensus::{Parlia, ParliaConfig};
use reth_primitives::ChainSpec;
use reth_provider::{ExecutorFactory, PrunableBlockExecutor, StateProvider};
use std::{fmt::Debug, marker::PhantomData, sync::Arc};
use std::{fmt::Debug, sync::Arc};

/// Factory for creating [EVMProcessor].
#[derive(Clone, Debug)]
pub struct EvmProcessorFactory<EvmConfig, P> {
pub struct EvmProcessorFactory<EvmConfig> {
chain_spec: Arc<ChainSpec>,
stack: Option<InspectorStack>,
/// Type that defines how the produced EVM should be configured.
evm_config: EvmConfig,

_phantom: PhantomData<P>,
/// Parlia consensus config
#[cfg(feature = "bsc")]
parlia_cfg: Option<ParliaConfig>,
}

impl<EvmConfig, P> EvmProcessorFactory<EvmConfig, P> {
impl<EvmConfig> EvmProcessorFactory<EvmConfig> {
/// Create new factory
pub fn new(chain_spec: Arc<ChainSpec>, evm_config: EvmConfig) -> Self {
Self {
chain_spec,
stack: None,
evm_config,
_phantom: PhantomData::default(),
#[cfg(feature = "bsc")]
parlia_cfg: None,
}
Expand All @@ -57,7 +55,30 @@ impl<EvmConfig, P> EvmProcessorFactory<EvmConfig, P> {
}
}

impl<EvmConfig, P> ExecutorFactory for EvmProcessorFactory<EvmConfig, P>
#[cfg(not(feature = "bsc"))]
impl<EvmConfig> ExecutorFactory for EvmProcessorFactory<EvmConfig>
where
EvmConfig: ConfigureEvm + Send + Sync + Clone + 'static,
{
fn with_state<'a, SP: StateProvider + 'a>(
&'a self,
sp: SP,
) -> Box<dyn PrunableBlockExecutor<Error = BlockExecutionError> + 'a> {
let database_state = StateProviderDatabase::new(sp);
let mut evm = EVMProcessor::new_with_db(
self.chain_spec.clone(),
database_state,
self.evm_config.clone(),
);
if let Some(stack) = &self.stack {
evm.set_stack(stack.clone());
}
Box::new(evm)
}
}

#[cfg(feature = "bsc")]
impl<EvmConfig, P> ExecutorFactory for EvmProcessorFactory<EvmConfig>
where
EvmConfig: ConfigureEvm + Send + Sync + Clone + 'static,
P: Debug + Send + Sync + 'static,
Expand All @@ -75,7 +96,6 @@ where
if let Some(stack) = &self.stack {
evm.set_stack(stack.clone());
}
#[cfg(feature = "bsc")]
if let Some(parlia_cfg) = &self.parlia_cfg {
evm.set_parlia(Arc::new(Parlia::new(self.chain_spec.clone(), parlia_cfg.clone())));
}
Expand Down
Loading

0 comments on commit 97f997f

Please sign in to comment.