diff --git a/CHANGELOG.md b/CHANGELOG.md index 59742499f47..c1d93eaeebd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,7 +25,7 @@ #### Dependencies - Replace tuweni libs with https://github.com/Consensys/tuweni [#8330](https://github.com/hyperledger/besu/pull/8330), [#8461](https://github.com/hyperledger/besu/pull/8461) -- Performance: Consensys/tuweni 2.7.0 reduces boxing/unboxing overhead on some EVM opcodes, like PushX and Caller [#8330](https://github.com/hyperledger/besu/pull/8330) +- Performance: Consensys/tuweni 2.7.0 reduces boxing/unboxing overhead on some EVM opcodes, like PushX and Caller [#8330](https://github.com/hyperledger/besu/pull/8330), [#8461](https://github.com/hyperledger/besu/pull/8461) ### Bug fixes - Fix QBFT and IBFT transitions that change the mining beneficiary [#8387](https://github.com/hyperledger/besu/issues/8387) @@ -88,6 +88,7 @@ have support in besu-native can run mainnet ethereum configurations. Windows su - Add missing RPC method `debug_accountRange` to `RpcMethod.java` so this method can be used with `--rpc-http-api-method-no-auth` [#8153](https://github.com/hyperledger/besu/issues/8153) - Add a fallback pivot strategy when the safe block does not change for a long time, to make possible to complete the initial sync in case the chain is not finalizing [#8395](https://github.com/hyperledger/besu/pull/8395) - Fix issue with new QBFT/IBFT blocks being produced under certain circumstances. [#8308](https://github.com/hyperledger/besu/issues/8308) +- Bonsai - check if storage is present before saving world state [#8434](https://github.com/hyperledger/besu/pull/8434) ## 25.2.2 hotfix - Pectra - Sepolia: Fix for deposit contract log decoding [#8383](https://github.com/hyperledger/besu/pull/8383) diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/pathbased/bonsai/worldview/BonsaiWorldState.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/pathbased/bonsai/worldview/BonsaiWorldState.java index 0a0fee7f801..bcb8dc45459 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/pathbased/bonsai/worldview/BonsaiWorldState.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/pathbased/bonsai/worldview/BonsaiWorldState.java @@ -48,6 +48,7 @@ import java.util.Map; import java.util.Objects; import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; import java.util.function.Supplier; import java.util.stream.Stream; @@ -320,24 +321,34 @@ private void clearStorage( (location, key) -> getStorageTrieNode(addressHash, location, key), oldAccount.getStorageRoot()); try { - final StorageConsumingMap> storageToDelete = - worldStateUpdater.getStorageToUpdate().get(address); + StorageConsumingMap> storageToDelete = null; Map entriesToDelete = storageTrie.entriesFrom(Bytes32.ZERO, 256); while (!entriesToDelete.isEmpty()) { - entriesToDelete.forEach( - (k, v) -> { - final StorageSlotKey storageSlotKey = - new StorageSlotKey(Hash.wrap(k), Optional.empty()); - final UInt256 slotValue = UInt256.fromBytes(Bytes32.leftPad(RLP.decodeValue(v))); - maybeStateUpdater.ifPresent( - bonsaiUpdater -> - bonsaiUpdater.removeStorageValueBySlotHash( - address.addressHash(), storageSlotKey.getSlotHash())); - storageToDelete + if (storageToDelete == null) { + storageToDelete = + worldStateUpdater + .getStorageToUpdate() .computeIfAbsent( - storageSlotKey, key -> new PathBasedValue<>(slotValue, null, true)) - .setPrior(slotValue); - }); + address, + add -> + new StorageConsumingMap<>( + address, + new ConcurrentHashMap<>(), + worldStateUpdater.getStoragePreloader())); + } + for (Map.Entry slot : entriesToDelete.entrySet()) { + final StorageSlotKey storageSlotKey = + new StorageSlotKey(Hash.wrap(slot.getKey()), Optional.empty()); + final UInt256 slotValue = + UInt256.fromBytes(Bytes32.leftPad(RLP.decodeValue(slot.getValue()))); + maybeStateUpdater.ifPresent( + bonsaiUpdater -> + bonsaiUpdater.removeStorageValueBySlotHash( + address.addressHash(), storageSlotKey.getSlotHash())); + storageToDelete + .computeIfAbsent(storageSlotKey, key -> new PathBasedValue<>(slotValue, null, true)) + .setPrior(slotValue); + } entriesToDelete.keySet().forEach(storageTrie::remove); if (entriesToDelete.size() == 256) { entriesToDelete = storageTrie.entriesFrom(Bytes32.ZERO, 256); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/pathbased/common/worldview/accumulator/PathBasedWorldStateUpdateAccumulator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/pathbased/common/worldview/accumulator/PathBasedWorldStateUpdateAccumulator.java index 8c31337315a..3a261be8334 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/pathbased/common/worldview/accumulator/PathBasedWorldStateUpdateAccumulator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/pathbased/common/worldview/accumulator/PathBasedWorldStateUpdateAccumulator.java @@ -227,7 +227,7 @@ protected Consumer> getAccountPreloader() { return accountPreloader; } - protected Consumer getStoragePreloader() { + public Consumer getStoragePreloader() { return storagePreloader; }