diff --git a/CHANGELOG.md b/CHANGELOG.md index 43857f46d420..6a67c0e2f7ab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,8 +28,7 @@ tests are updated to use EC private keys instead of RSA keys. ### Bug Fixes - Mitigation fix for stale bonsai code storage leading to log rolling issues on contract recreates [#4906](https://github.com/hyperledger/besu/pull/4906) -- Ensure latest cached layered worldstate is subscribed to storage, fix problem with RPC calls using 'latest' [#5039](https://github.com/hyperledger/besu/pull/5039) - +- Ensure latest cached layered worldstate is subscribed to storage, fix problem with RPC calls using 'latest' [#5076](https://github.com/hyperledger/besu/pull/5076) ## 23.1.0-RC1 diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueries.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueries.java index be0cb1ab51e2..776f5905397b 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueries.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueries.java @@ -855,12 +855,19 @@ public Optional getAndMapWorldState( .getBlockHeader(blockHash) .flatMap( blockHeader -> { - try (var ws = + try (final var worldState = worldStateArchive .getMutable(blockHeader.getStateRoot(), blockHeader.getHash(), false) + .map( + ws -> { + if (!ws.isPersistable()) { + return ws.copy(); + } + return ws; + }) .orElse(null)) { - if (ws != null) { - return Optional.ofNullable(mapper.apply(ws)); + if (worldState != null) { + return Optional.ofNullable(mapper.apply(worldState)); } } catch (Exception ex) { LOG.error("failed worldstate query for " + blockHash.toShortHexString(), ex); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/AbstractTrieLogManager.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/AbstractTrieLogManager.java index 7ac086bbaa1d..4aa07bcf936e 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/AbstractTrieLogManager.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/AbstractTrieLogManager.java @@ -97,16 +97,17 @@ protected abstract void addCachedLayer( @VisibleForTesting TrieLogLayer prepareTrieLog( - final BlockHeader blockHeader, - final Hash worldStateRootHash, + final BlockHeader forBlockHeader, + final Hash forWorldStateRootHash, final BonsaiWorldStateUpdater localUpdater, final BonsaiWorldStateArchive worldStateArchive, final BonsaiPersistedWorldState forWorldState) { - debugLambda(LOG, "Adding layered world state for {}", blockHeader::toLogString); - final TrieLogLayer trieLog = localUpdater.generateTrieLog(blockHeader.getBlockHash()); + debugLambda(LOG, "Adding layered world state for {}", forBlockHeader::toLogString); + final TrieLogLayer trieLog = localUpdater.generateTrieLog(forBlockHeader.getBlockHash()); trieLog.freeze(); - addCachedLayer(blockHeader, worldStateRootHash, trieLog, worldStateArchive, forWorldState); - scrubCachedLayers(blockHeader.getNumber()); + addCachedLayer( + forBlockHeader, forWorldStateRootHash, trieLog, worldStateArchive, forWorldState); + scrubCachedLayers(forBlockHeader.getNumber()); return trieLog; } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/BonsaiLayeredWorldState.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/BonsaiLayeredWorldState.java index e08394003782..4a45def378a7 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/BonsaiLayeredWorldState.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/BonsaiLayeredWorldState.java @@ -40,8 +40,13 @@ import org.apache.tuweni.units.bigints.UInt256; /** A World State backed first by trie log layer and then by another world state. */ -public class BonsaiLayeredWorldState implements MutableWorldState, BonsaiWorldView, WorldState { - private Optional nextWorldView; +public class BonsaiLayeredWorldState + implements MutableWorldState, + BonsaiWorldView, + WorldState, + BonsaiWorldStateKeyValueStorage.BonsaiStorageSubscriber { + private Optional nextWorldView = Optional.empty(); + private Optional newtWorldViewSubscribeId = Optional.empty(); protected final long height; protected final TrieLogLayer trieLog; private final Hash worldStateRootHash; @@ -58,7 +63,7 @@ public class BonsaiLayeredWorldState implements MutableWorldState, BonsaiWorldVi final TrieLogLayer trieLog) { this.blockchain = blockchain; this.archive = archive; - this.nextWorldView = nextWorldView; + this.setNextWorldView(nextWorldView); this.height = height; this.worldStateRootHash = worldStateRootHash; this.trieLog = trieLog; @@ -76,21 +81,28 @@ public Optional getNextWorldView() { } public void setNextWorldView(final Optional nextWorldView) { - maybeUnSubscribe(); + maybeUnSubscribe(); // unsubscribe the old view this.nextWorldView = nextWorldView; + maybeSubscribe(); // subscribe the next view + } + + private void maybeSubscribe() { + nextWorldView + .filter(BonsaiPersistedWorldState.class::isInstance) + .map(BonsaiPersistedWorldState.class::cast) + .ifPresent( + worldState -> { + newtWorldViewSubscribeId = Optional.of(worldState.worldStateStorage.subscribe(this)); + }); } private void maybeUnSubscribe() { nextWorldView - .filter(WorldState.class::isInstance) - .map(WorldState.class::cast) + .filter(BonsaiPersistedWorldState.class::isInstance) + .map(BonsaiPersistedWorldState.class::cast) .ifPresent( - ws -> { - try { - ws.close(); - } catch (final Exception e) { - // no-op - } + worldState -> { + newtWorldViewSubscribeId.ifPresent(worldState.worldStateStorage::unSubscribe); }); }