From d23a1879455f78763502593fa7f70a44b7394595 Mon Sep 17 00:00:00 2001 From: ahamlat Date: Wed, 11 Jan 2023 23:14:27 +0100 Subject: [PATCH] Cache empty slots (#4874) * Cache empty slots. Signed-off-by: Ameziane H * clear after each block and copy during clone Signed-off-by: Karim TAAM * add changelog Signed-off-by: Ameziane H * Avoid triggering a calculate root hash when empty slot cache is not empty. Signed-off-by: Ameziane H Signed-off-by: Ameziane H Signed-off-by: Karim TAAM Signed-off-by: ahamlat Co-authored-by: Karim TAAM --- CHANGELOG.md | 2 ++ .../bonsai/BonsaiWorldStateUpdater.java | 35 ++++++++++++------- 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 92532d854be..90321de0db9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ - Default configurations for the deprecated Ropsten, Kiln, Shandong, and Astor networks have been removed from the CLI network list. These networks can currently be accessed but will require a user-provided genesis configuration. [#4869](https://github.com/hyperledger/besu/pull/4869) ### Additions and Improvements + +- Improve SLOAD and SSTORE performance by caching empty slots [#4874](https://github.com/hyperledger/besu/pull/4874) - RPC methods that lookup block by hash will now return an error response if no block found [#4582](https://github.com/hyperledger/besu/pull/4582) ### Bug Fixes diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/BonsaiWorldStateUpdater.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/BonsaiWorldStateUpdater.java index 1eb307adb7e..fd71e6a856e 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/BonsaiWorldStateUpdater.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/BonsaiWorldStateUpdater.java @@ -52,6 +52,7 @@ public class BonsaiWorldStateUpdater extends AbstractWorldUpdater storagePreloader; private final Map> codeToUpdate = new ConcurrentHashMap<>(); private final Set
storageToClear = Collections.synchronizedSet(new HashSet<>()); + private final Set emptySlot = Collections.synchronizedSet(new HashSet<>()); // storage sub mapped by _hashed_ key. This is because in self_destruct calls we need to // enumerate the old storage and delete it. Those are trie stored by hashed key by spec and the @@ -87,6 +88,7 @@ void cloneFromUpdater(final BonsaiWorldStateUpdater source) { storageToUpdate.putAll(source.storageToUpdate); updatedAccounts.putAll(source.updatedAccounts); deletedAccounts.addAll(source.deletedAccounts); + emptySlot.addAll(source.emptySlot); } @Override @@ -349,18 +351,26 @@ public Optional getStorageValueBySlotHash(final Address address, final return Optional.ofNullable(value.getUpdated()); } } - final Optional valueUInt = - wrappedWorldView().getStorageValueBySlotHash(address, slotHash); - valueUInt.ifPresent( - v -> - storageToUpdate - .computeIfAbsent( - address, - key -> - new StorageConsumingMap<>( - address, new ConcurrentHashMap<>(), storagePreloader)) - .put(slotHash, new BonsaiValue<>(v, v))); - return valueUInt; + final Bytes slot = Bytes.concatenate(Hash.hash(address), slotHash); + if (emptySlot.contains(slot)) { + return Optional.empty(); + } else { + final Optional valueUInt = + wrappedWorldView().getStorageValueBySlotHash(address, slotHash); + valueUInt.ifPresentOrElse( + v -> + storageToUpdate + .computeIfAbsent( + address, + key -> + new StorageConsumingMap<>( + address, new ConcurrentHashMap<>(), storagePreloader)) + .put(slotHash, new BonsaiValue<>(v, v)), + () -> { + emptySlot.add(Bytes.concatenate(Hash.hash(address), slotHash)); + }); + return valueUInt; + } } @Override @@ -705,6 +715,7 @@ public void reset() { storageToUpdate.clear(); codeToUpdate.clear(); accountsToUpdate.clear(); + emptySlot.clear(); super.reset(); }