Skip to content

Commit dc7060b

Browse files
authored
perf(evm): improve commit hash calculations (#1274)
* use hash writer * improve sort * reuse already calculated commit hashes * update tests * fix importer with mocked bls keys * regenerate test configs * missing test
1 parent 38cd6cc commit dc7060b

20 files changed

Lines changed: 2156 additions & 2025 deletions

File tree

packages/configuration-generator/source/configuration-generator.ts

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -147,17 +147,20 @@ export class ConfigurationGenerator {
147147
)
148148
.generate();
149149

150-
this.app.get<Contracts.Crypto.Configuration>(Identifiers.Cryptography.Configuration).setConfig({
151-
genesisBlock: {
152-
// @ts-ignore
153-
block: {
154-
number: internalOptions.initialBlockNumber,
150+
this.app.get<Contracts.Crypto.Configuration>(Identifiers.Cryptography.Configuration).setConfig(
151+
{
152+
genesisBlock: {
153+
// @ts-ignore
154+
block: {
155+
number: internalOptions.initialBlockNumber,
156+
},
155157
},
158+
milestones,
159+
// @ts-ignore
160+
network: {},
156161
},
157-
milestones,
158-
// @ts-ignore
159-
network: {},
160-
});
162+
false,
163+
);
161164

162165
if (options.snapshot) {
163166
const importer = this.app.get<Contracts.Snapshot.LegacyImporter>(

packages/evm/core/src/db.rs

Lines changed: 61 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ use crate::{
3030
receipt::{TxReceipt, map_execution_result},
3131
state_changes,
3232
state_commit::StateCommit,
33-
state_root,
3433
};
3534

3635
#[derive(Debug)]
@@ -267,6 +266,14 @@ pub struct PendingCommit {
267266

268267
// Optimization to avoid unnecessary (deep) clones of commit data.
269268
pub built_commit: Option<StateCommit>,
269+
pub commit_hashes: Option<CommitHashes>,
270+
}
271+
272+
#[derive(Clone, Default, Debug, Serialize, Deserialize, PartialEq, Eq)]
273+
pub struct CommitHashes {
274+
pub accounts_hash: B256,
275+
pub contracts_hash: B256,
276+
pub storage_hash: B256,
270277
}
271278

272279
#[derive(Clone, Debug, Default, Serialize, PartialEq, Eq)]
@@ -801,14 +808,15 @@ impl PersistentDB {
801808
&self,
802809
state_commit: &mut StateCommit,
803810
commit_data: &Option<CommitData>,
811+
commit_hashes: &CommitHashes,
804812
) -> Result<(), Error> {
805813
let StateCommit {
806814
key,
807815
change_set,
808816
results,
809817
} = state_commit;
810818

811-
match self.commit_to_db(key, change_set, commit_data, results) {
819+
match self.commit_to_db(key, change_set, commit_data, commit_hashes, results) {
812820
Ok(_) => return Ok(()),
813821
Err(err) => match &err {
814822
Error::Heed(heed_err) => match heed_err {
@@ -828,6 +836,7 @@ impl PersistentDB {
828836
key: &CommitKey,
829837
change_set: &mut state_changes::StateChangeset,
830838
commit_data: &Option<CommitData>,
839+
commit_hashes: &CommitHashes,
831840
results: &BTreeMap<B256, (ExecutionResult, u64)>,
832841
) -> Result<(), Error> {
833842
assert!(!self.is_block_committed(key.0));
@@ -845,9 +854,9 @@ impl PersistentDB {
845854
merged_legacy_cold_wallets,
846855
} = change_set;
847856

848-
accounts.par_sort_by_key(|a| a.0);
849-
contracts.par_sort_by_key(|a| a.0);
850-
storage.par_sort_by_key(|a| a.address);
857+
accounts.par_sort_unstable_by_key(|a| a.0);
858+
contracts.par_sort_unstable_by_key(|a| a.0);
859+
storage.par_sort_unstable_by_key(|a| a.address);
851860

852861
// Update accounts
853862
for (address, account) in accounts.iter() {
@@ -1067,9 +1076,9 @@ impl PersistentDB {
10671076
rwtxn,
10681077
&key.0,
10691078
&CompressedBincode(&CommitReceipts {
1070-
accounts_hash: state_root::calculate_accounts_hash(&change_set)?,
1071-
contracts_hash: state_root::calculate_contracts_hash(&change_set)?,
1072-
storage_hash: state_root::calculate_storage_hash(&change_set)?,
1079+
accounts_hash: commit_hashes.accounts_hash,
1080+
contracts_hash: commit_hashes.contracts_hash,
1081+
storage_hash: commit_hashes.storage_hash,
10731082
tx_receipts,
10741083
}),
10751084
)?;
@@ -1113,20 +1122,17 @@ impl PersistentDB {
11131122
}
11141123
}
11151124

1116-
pub fn get_committed_hashes(
1117-
&self,
1118-
block_number: u64,
1119-
) -> Result<Option<(B256, B256, B256)>, Error> {
1125+
pub fn get_committed_hashes(&self, block_number: u64) -> Result<Option<CommitHashes>, Error> {
11201126
let env = self.env.clone();
11211127
let rtxn = env.read_txn().expect("read");
11221128
let inner = self.inner.borrow();
11231129

11241130
match inner.commits.get(&rtxn, &block_number)? {
1125-
Some(receipts) => Ok(Some((
1126-
receipts.accounts_hash,
1127-
receipts.contracts_hash,
1128-
receipts.storage_hash,
1129-
))),
1131+
Some(receipts) => Ok(Some(CommitHashes {
1132+
accounts_hash: receipts.accounts_hash,
1133+
contracts_hash: receipts.contracts_hash,
1134+
storage_hash: receipts.storage_hash,
1135+
})),
11301136
None => Ok(None),
11311137
}
11321138
}
@@ -1233,6 +1239,7 @@ impl PendingCommit {
12331239
legacy_cold_wallets: Default::default(),
12341240
merged_legacy_cold_wallets: Default::default(),
12351241
built_commit: Default::default(),
1242+
commit_hashes: Default::default(),
12361243
}
12371244
}
12381245

@@ -1276,17 +1283,18 @@ mod tests {
12761283
account::StoredAccountInfo,
12771284
compression::CompressedBincode,
12781285
db::{
1279-
AddressWrapper, BlockHeaderData, CommitData, CommitKey, CommitReceipts, HashWrapper,
1280-
LegacyAddressWrapper, MAP_SIZE_UNIT, PendingCommit, PersistentDB, PersistentDBOptions,
1281-
ProofData, StaticStringWrapper, StorageEntryWrapper, StringWrapper, TransactionData,
1282-
next_map_size,
1286+
AddressWrapper, BlockHeaderData, CommitData, CommitHashes, CommitKey, CommitReceipts,
1287+
HashWrapper, LegacyAddressWrapper, MAP_SIZE_UNIT, PendingCommit, PersistentDB,
1288+
PersistentDBOptions, ProofData, StaticStringWrapper, StorageEntryWrapper,
1289+
StringWrapper, TransactionData, next_map_size,
12831290
},
12841291
historical::HistoricalAccountData,
12851292
legacy::{LegacyAccountAttributes, LegacyAddress, LegacyColdWallet},
12861293
logger::Logger,
12871294
receipt::TxReceipt,
12881295
state_changes::{StateChangeset, StorageChangeset},
12891296
state_commit::{StateCommit, build_commit},
1297+
state_root,
12901298
};
12911299
use alloy_primitives::{Address, B256, Bytes, FixedBytes, U256, address, b256, hex};
12921300
use revm::{
@@ -1377,6 +1385,7 @@ mod tests {
13771385
PendingCommit {
13781386
key: CommitKey::default(),
13791387
transitions: TransitionState { transitions: state },
1388+
commit_hashes: Some(Default::default()),
13801389
..Default::default()
13811390
},
13821391
Default::default(),
@@ -1407,6 +1416,18 @@ mod tests {
14071416
let mut db = create_temp_database();
14081417
let mut pending_commit = PendingCommit::default();
14091418
pending_commit.built_commit = Some(build_commit(&mut pending_commit).unwrap());
1419+
pending_commit.commit_hashes = Some(CommitHashes::default());
1420+
1421+
crate::state_commit::commit_to_db(&mut db, pending_commit, Default::default()).unwrap();
1422+
}
1423+
1424+
#[test]
1425+
fn test_commit_built_without_precomputed_hashes() {
1426+
let mut db = create_temp_database();
1427+
let mut pending_commit = PendingCommit::default();
1428+
pending_commit.built_commit = Some(build_commit(&mut pending_commit).unwrap());
1429+
pending_commit.commit_hashes = None;
1430+
14101431
crate::state_commit::commit_to_db(&mut db, pending_commit, Default::default()).unwrap();
14111432
}
14121433

@@ -1460,6 +1481,7 @@ mod tests {
14601481
PendingCommit {
14611482
key: CommitKey::default(),
14621483
transitions: TransitionState { transitions: state },
1484+
commit_hashes: Some(CommitHashes::default()),
14631485
..Default::default()
14641486
},
14651487
Default::default(),
@@ -1515,6 +1537,7 @@ mod tests {
15151537
PendingCommit {
15161538
key: CommitKey::default(),
15171539
transitions: TransitionState { transitions: state },
1540+
commit_hashes: Some(Default::default()),
15181541
..Default::default()
15191542
},
15201543
Default::default(),
@@ -1552,6 +1575,7 @@ mod tests {
15521575
PendingCommit {
15531576
key: CommitKey(1, 0, B256::ZERO),
15541577
transitions: TransitionState { transitions: state },
1578+
commit_hashes: Some(Default::default()),
15551579
..Default::default()
15561580
},
15571581
Default::default(),
@@ -1614,6 +1638,7 @@ mod tests {
16141638
PendingCommit {
16151639
key: CommitKey(block_number, 0, B256::ZERO),
16161640
transitions: TransitionState { transitions: state },
1641+
commit_hashes: Some(Default::default()),
16171642
..Default::default()
16181643
}
16191644
};
@@ -2248,7 +2273,14 @@ mod tests {
22482273
}
22492274

22502275
let hashes = db.get_committed_hashes(1).unwrap();
2251-
assert_eq!(hashes, Some((accounts_hash, contracts_hash, storage_hash)));
2276+
assert_eq!(
2277+
hashes,
2278+
Some(CommitHashes {
2279+
accounts_hash,
2280+
contracts_hash,
2281+
storage_hash
2282+
})
2283+
);
22522284
}
22532285

22542286
#[test]
@@ -2655,7 +2687,13 @@ mod tests {
26552687
..Default::default()
26562688
};
26572689

2658-
db.commit(&mut state, &Some(data)).unwrap();
2690+
let commit_hashes = CommitHashes {
2691+
accounts_hash: state_root::calculate_accounts_hash(&state.change_set).unwrap(),
2692+
contracts_hash: state_root::calculate_contracts_hash(&state.change_set).unwrap(),
2693+
storage_hash: state_root::calculate_storage_hash(&state.change_set).unwrap(),
2694+
};
2695+
2696+
db.commit(&mut state, &Some(data), &commit_hashes).unwrap();
26592697
}
26602698

26612699
fn create_temp_database() -> PersistentDB {

packages/evm/core/src/state_commit.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use revm::{
1010
use crate::{
1111
db::{CommitData, CommitKey, Error, GenesisInfo, PendingCommit, PersistentDB},
1212
state_changes::{self, AccountMergeInfo, AccountUpdate},
13+
state_root::calculate_commit_hashes,
1314
};
1415

1516
#[derive(Clone, Debug, Default)]
@@ -86,13 +87,18 @@ pub fn commit_to_db(
8687
None => build_commit(&mut pending_commit)?,
8788
};
8889

89-
match db.commit(&mut commit, &commit_data) {
90+
let commit_hashes = match pending_commit.commit_hashes {
91+
Some(commit_hashes) => commit_hashes,
92+
None => calculate_commit_hashes(&mut commit)?,
93+
};
94+
95+
match db.commit(&mut commit, &commit_data, &commit_hashes) {
9096
Ok(_) => Ok(collect_dirty_accounts(commit, &genesis_info)),
9197
Err(err) => match &err {
9298
Error::DbFull => {
9399
// try to resize the db and attempt another commit on success
94100
db.resize().and_then(|_| {
95-
db.commit(&mut commit, &commit_data)
101+
db.commit(&mut commit, &commit_data, &commit_hashes)
96102
.and_then(|_| Ok(collect_dirty_accounts(commit, &genesis_info)))
97103
})
98104
}

0 commit comments

Comments
 (0)