From 6d77d58006b9c6fdda993803bb7f803aca00d33b Mon Sep 17 00:00:00 2001 From: Karim TAAM Date: Tue, 30 Jan 2024 21:03:39 +0100 Subject: [PATCH] Optimized Keccak Hashing for Account Storage Slots (#6452) * not recompute hash if not needed * Add memoize for the Supplier * Modify hashcode to only process keccak when slotkey is not defined * use single cache for keccak Signed-off-by: Karim Taam Signed-off-by: Ameziane H Signed-off-by: ahamlat Signed-off-by: garyschulte --- CHANGELOG.md | 1 + .../BonsaiWorldStateUpdateAccumulator.java | 27 +++++++++++++------ .../BonsaiReferenceTestUpdateAccumulator.java | 12 ++++++--- 3 files changed, 28 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ea8f5434714..2a650aa6d07 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ - Log blob count when importing a block via Engine API [#6466](https://github.com/hyperledger/besu/pull/6466) - Introduce `--Xbonsai-limit-trie-logs-enabled` experimental feature which by default will only retain the latest 512 trie logs, saving about 3GB per week in database growth [#5390](https://github.com/hyperledger/besu/issues/5390) - Introduce `besu storage x-trie-log prune` experimental offline subcommand which will prune all redundant trie logs except the latest 512 [#6303](https://github.com/hyperledger/besu/pull/6303) +- Introduce caching mechanism to optimize Keccak hash calculations for account storage slots during block processing [#6452](https://github.com/hyperledger/besu/pull/6452) - Added configuration options for `pragueTime` to genesis file for Prague fork development [#6473](https://github.com/hyperledger/besu/pull/6473) ### Bug fixes diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/bonsai/worldview/BonsaiWorldStateUpdateAccumulator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/bonsai/worldview/BonsaiWorldStateUpdateAccumulator.java index d73c272829b..7d8cfd03077 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/bonsai/worldview/BonsaiWorldStateUpdateAccumulator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/bonsai/worldview/BonsaiWorldStateUpdateAccumulator.java @@ -74,6 +74,7 @@ public class BonsaiWorldStateUpdateAccumulator private final Map>> storageToUpdate = new ConcurrentHashMap<>(); + private final Map storageKeyHashLookup = new ConcurrentHashMap<>(); protected boolean isAccumulatorStateChanged; public BonsaiWorldStateUpdateAccumulator( @@ -142,7 +143,7 @@ public MutableAccount createAccount(final Address address, final long nonce, fin new BonsaiAccount( this, address, - hashAndSavePreImage(address), + hashAndSaveAccountPreImage(address), nonce, balance, Hash.EMPTY_TRIE_HASH, @@ -364,11 +365,11 @@ public void commit() { entries.forEach( storageUpdate -> { final UInt256 keyUInt = storageUpdate.getKey(); - final Hash slotHash = hashAndSavePreImage(keyUInt); final StorageSlotKey slotKey = - new StorageSlotKey(slotHash, Optional.of(keyUInt)); + new StorageSlotKey(hashAndSaveSlotPreImage(keyUInt), Optional.of(keyUInt)); final UInt256 value = storageUpdate.getValue(); final BonsaiValue pendingValue = pendingStorageUpdates.get(slotKey); + if (pendingValue == null) { pendingStorageUpdates.put( slotKey, @@ -409,7 +410,7 @@ public Optional getCode(final Address address, final Hash codeHash) { @Override public UInt256 getStorageValue(final Address address, final UInt256 slotKey) { StorageSlotKey storageSlotKey = - new StorageSlotKey(hashAndSavePreImage(slotKey), Optional.of(slotKey)); + new StorageSlotKey(hashAndSaveSlotPreImage(slotKey), Optional.of(slotKey)); return getStorageValueByStorageSlotKey(address, storageSlotKey).orElse(UInt256.ZERO); } @@ -453,7 +454,7 @@ public Optional getStorageValueByStorageSlotKey( public UInt256 getPriorStorageValue(final Address address, final UInt256 storageKey) { // TODO maybe log the read into the trie layer? StorageSlotKey storageSlotKey = - new StorageSlotKey(hashAndSavePreImage(storageKey), Optional.of(storageKey)); + new StorageSlotKey(hashAndSaveSlotPreImage(storageKey), Optional.of(storageKey)); final Map> localAccountStorage = storageToUpdate.get(address); if (localAccountStorage != null) { @@ -765,6 +766,7 @@ public void reset() { resetAccumulatorStateChanged(); updatedAccounts.clear(); deletedAccounts.clear(); + storageKeyHashLookup.clear(); } public static class AccountConsumingMap extends ForwardingMap { @@ -828,8 +830,17 @@ public interface Consumer { void process(final Address address, T value); } - protected Hash hashAndSavePreImage(final Bytes bytes) { - // by default do not save hash preImages - return Hash.hash(bytes); + protected Hash hashAndSaveAccountPreImage(final Address address) { + // no need to save account preimage by default + return Hash.hash(address); + } + + protected Hash hashAndSaveSlotPreImage(final UInt256 slotKey) { + Hash hash = storageKeyHashLookup.get(slotKey); + if (hash == null) { + hash = Hash.hash(slotKey); + storageKeyHashLookup.put(slotKey, hash); + } + return hash; } } diff --git a/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/BonsaiReferenceTestUpdateAccumulator.java b/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/BonsaiReferenceTestUpdateAccumulator.java index 8c1bd515522..c64bbec90d8 100644 --- a/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/BonsaiReferenceTestUpdateAccumulator.java +++ b/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/BonsaiReferenceTestUpdateAccumulator.java @@ -14,6 +14,7 @@ */ package org.hyperledger.besu.ethereum.referencetests; +import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.StorageSlotKey; import org.hyperledger.besu.ethereum.trie.bonsai.BonsaiAccount; @@ -25,7 +26,6 @@ import java.util.concurrent.ConcurrentHashMap; -import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.units.bigints.UInt256; public class BonsaiReferenceTestUpdateAccumulator extends BonsaiWorldStateUpdateAccumulator { @@ -42,9 +42,13 @@ public BonsaiReferenceTestUpdateAccumulator( } @Override - protected Hash hashAndSavePreImage(final Bytes bytes) { - // by default do not save hash preImages - return preImageProxy.hashAndSavePreImage(bytes); + protected Hash hashAndSaveAccountPreImage(final Address address) { + return preImageProxy.hashAndSavePreImage(address); + } + + @Override + protected Hash hashAndSaveSlotPreImage(final UInt256 slotKey) { + return preImageProxy.hashAndSavePreImage(slotKey); } public BonsaiReferenceTestUpdateAccumulator createDetachedAccumulator() {