mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
perf(engine): include selfdestructs in StateRootTask bench input (#13293)
Co-authored-by: Alexey Shekhirin <5773434+shekhirin@users.noreply.github.com>
This commit is contained in:
@ -10,7 +10,7 @@ use reth_primitives::{Account as RethAccount, StorageEntry};
|
||||
use reth_provider::{
|
||||
providers::ConsistentDbView,
|
||||
test_utils::{create_test_provider_factory, MockNodeTypesWithDB},
|
||||
HashingWriter, ProviderFactory,
|
||||
AccountReader, HashingWriter, ProviderFactory,
|
||||
};
|
||||
use reth_testing_utils::generators::{self, Rng};
|
||||
use reth_trie::{
|
||||
@ -28,38 +28,54 @@ struct BenchParams {
|
||||
num_accounts: usize,
|
||||
updates_per_account: usize,
|
||||
storage_slots_per_account: usize,
|
||||
selfdestructs_per_update: usize,
|
||||
}
|
||||
|
||||
/// Generates a series of random state updates with configurable accounts,
|
||||
/// storage, and self-destructs
|
||||
fn create_bench_state_updates(params: &BenchParams) -> Vec<EvmState> {
|
||||
let mut rng = generators::rng();
|
||||
let all_addresses: Vec<Address> = (0..params.num_accounts).map(|_| rng.gen()).collect();
|
||||
let mut updates = Vec::new();
|
||||
|
||||
for _ in 0..params.updates_per_account {
|
||||
let num_accounts_in_update = rng.gen_range(1..=params.num_accounts);
|
||||
let mut state_update = EvmState::default();
|
||||
let num_accounts_in_update = rng.gen_range(1..=params.num_accounts);
|
||||
|
||||
let selected_addresses = &all_addresses[0..num_accounts_in_update];
|
||||
// regular updates for randomly selected accounts
|
||||
for &address in &all_addresses[0..num_accounts_in_update] {
|
||||
// randomly choose to self-destruct with probability
|
||||
// (selfdestructs/accounts)
|
||||
let is_selfdestruct =
|
||||
rng.gen_bool(params.selfdestructs_per_update as f64 / params.num_accounts as f64);
|
||||
|
||||
for &address in selected_addresses {
|
||||
let mut storage = HashMap::default();
|
||||
for _ in 0..params.storage_slots_per_account {
|
||||
let slot = U256::from(rng.gen::<u64>());
|
||||
storage.insert(
|
||||
slot,
|
||||
EvmStorageSlot::new_changed(U256::ZERO, U256::from(rng.gen::<u64>())),
|
||||
);
|
||||
}
|
||||
|
||||
let account = RevmAccount {
|
||||
info: AccountInfo {
|
||||
balance: U256::from(rng.gen::<u64>()),
|
||||
nonce: rng.gen::<u64>(),
|
||||
code_hash: KECCAK_EMPTY,
|
||||
code: Some(Default::default()),
|
||||
},
|
||||
storage,
|
||||
status: AccountStatus::Touched,
|
||||
let account = if is_selfdestruct {
|
||||
RevmAccount {
|
||||
info: AccountInfo::default(),
|
||||
storage: HashMap::default(),
|
||||
status: AccountStatus::SelfDestructed,
|
||||
}
|
||||
} else {
|
||||
RevmAccount {
|
||||
info: AccountInfo {
|
||||
balance: U256::from(rng.gen::<u64>()),
|
||||
nonce: rng.gen::<u64>(),
|
||||
code_hash: KECCAK_EMPTY,
|
||||
code: Some(Default::default()),
|
||||
},
|
||||
storage: (0..rng.gen_range(0..=params.storage_slots_per_account))
|
||||
.map(|_| {
|
||||
(
|
||||
U256::from(rng.gen::<u64>()),
|
||||
EvmStorageSlot::new_changed(
|
||||
U256::ZERO,
|
||||
U256::from(rng.gen::<u64>()),
|
||||
),
|
||||
)
|
||||
})
|
||||
.collect(),
|
||||
status: AccountStatus::Touched,
|
||||
}
|
||||
};
|
||||
|
||||
state_update.insert(address, account);
|
||||
@ -71,50 +87,99 @@ fn create_bench_state_updates(params: &BenchParams) -> Vec<EvmState> {
|
||||
updates
|
||||
}
|
||||
|
||||
fn convert_revm_to_reth_account(revm_account: &RevmAccount) -> RethAccount {
|
||||
RethAccount {
|
||||
balance: revm_account.info.balance,
|
||||
nonce: revm_account.info.nonce,
|
||||
bytecode_hash: if revm_account.info.code_hash == KECCAK_EMPTY {
|
||||
None
|
||||
} else {
|
||||
Some(revm_account.info.code_hash)
|
||||
},
|
||||
fn convert_revm_to_reth_account(revm_account: &RevmAccount) -> Option<RethAccount> {
|
||||
match revm_account.status {
|
||||
AccountStatus::SelfDestructed => None,
|
||||
_ => Some(RethAccount {
|
||||
balance: revm_account.info.balance,
|
||||
nonce: revm_account.info.nonce,
|
||||
bytecode_hash: if revm_account.info.code_hash == KECCAK_EMPTY {
|
||||
None
|
||||
} else {
|
||||
Some(revm_account.info.code_hash)
|
||||
},
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
/// Applies state updates to the provider, ensuring self-destructs only affect
|
||||
/// existing accounts
|
||||
fn setup_provider(
|
||||
factory: &ProviderFactory<MockNodeTypesWithDB>,
|
||||
state_updates: &[EvmState],
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let provider_rw = factory.provider_rw()?;
|
||||
|
||||
for update in state_updates {
|
||||
let account_updates = update
|
||||
.iter()
|
||||
.map(|(address, account)| (*address, Some(convert_revm_to_reth_account(account))));
|
||||
provider_rw.insert_account_for_hashing(account_updates)?;
|
||||
let provider_rw = factory.provider_rw()?;
|
||||
|
||||
let storage_updates = update.iter().map(|(address, account)| {
|
||||
let storage_entries = account.storage.iter().map(|(slot, value)| StorageEntry {
|
||||
key: B256::from(*slot),
|
||||
value: value.present_value,
|
||||
});
|
||||
(*address, storage_entries)
|
||||
});
|
||||
provider_rw.insert_storage_for_hashing(storage_updates)?;
|
||||
let mut account_updates = Vec::new();
|
||||
|
||||
for (address, account) in update {
|
||||
// only process self-destructs if account exists, always process
|
||||
// other updates
|
||||
let should_process = match account.status {
|
||||
AccountStatus::SelfDestructed => {
|
||||
provider_rw.basic_account(*address).ok().flatten().is_some()
|
||||
}
|
||||
_ => true,
|
||||
};
|
||||
|
||||
if should_process {
|
||||
account_updates.push((
|
||||
*address,
|
||||
convert_revm_to_reth_account(account),
|
||||
(account.status == AccountStatus::Touched).then(|| {
|
||||
account
|
||||
.storage
|
||||
.iter()
|
||||
.map(|(slot, value)| StorageEntry {
|
||||
key: B256::from(*slot),
|
||||
value: value.present_value,
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
}),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// update in the provider account and its storage (if available)
|
||||
for (address, account, maybe_storage) in account_updates {
|
||||
provider_rw.insert_account_for_hashing(std::iter::once((address, account)))?;
|
||||
if let Some(storage) = maybe_storage {
|
||||
provider_rw
|
||||
.insert_storage_for_hashing(std::iter::once((address, storage.into_iter())))?;
|
||||
}
|
||||
}
|
||||
|
||||
provider_rw.commit()?;
|
||||
}
|
||||
|
||||
provider_rw.commit()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn bench_state_root(c: &mut Criterion) {
|
||||
reth_tracing::init_test_tracing();
|
||||
|
||||
let mut group = c.benchmark_group("state_root");
|
||||
|
||||
let scenarios = vec![
|
||||
BenchParams { num_accounts: 100, updates_per_account: 5, storage_slots_per_account: 10 },
|
||||
BenchParams { num_accounts: 1000, updates_per_account: 10, storage_slots_per_account: 20 },
|
||||
BenchParams {
|
||||
num_accounts: 100,
|
||||
updates_per_account: 5,
|
||||
storage_slots_per_account: 10,
|
||||
selfdestructs_per_update: 2,
|
||||
},
|
||||
BenchParams {
|
||||
num_accounts: 1000,
|
||||
updates_per_account: 10,
|
||||
storage_slots_per_account: 20,
|
||||
selfdestructs_per_update: 5,
|
||||
},
|
||||
BenchParams {
|
||||
num_accounts: 500,
|
||||
updates_per_account: 8,
|
||||
storage_slots_per_account: 15,
|
||||
selfdestructs_per_update: 20,
|
||||
},
|
||||
];
|
||||
|
||||
for params in scenarios {
|
||||
@ -122,10 +187,11 @@ fn bench_state_root(c: &mut Criterion) {
|
||||
BenchmarkId::new(
|
||||
"state_root_task",
|
||||
format!(
|
||||
"accounts_{}_updates_{}_slots_{}",
|
||||
"accounts_{}_updates_{}_slots_{}_selfdestructs_{}",
|
||||
params.num_accounts,
|
||||
params.updates_per_account,
|
||||
params.storage_slots_per_account
|
||||
params.storage_slots_per_account,
|
||||
params.selfdestructs_per_update
|
||||
),
|
||||
),
|
||||
¶ms,
|
||||
|
||||
Reference in New Issue
Block a user