diff --git a/besu/src/main/java/org/hyperledger/besu/chainimport/JsonBlockImporter.java b/besu/src/main/java/org/hyperledger/besu/chainimport/JsonBlockImporter.java index 65a399aaf2..2e9e7fc7d6 100644 --- a/besu/src/main/java/org/hyperledger/besu/chainimport/JsonBlockImporter.java +++ b/besu/src/main/java/org/hyperledger/besu/chainimport/JsonBlockImporter.java @@ -84,7 +84,7 @@ public class JsonBlockImporter { controller .getProtocolContext() .getWorldStateArchive() - .get(parentHeader.getStateRoot()) + .get(parentHeader.getStateRoot(), parentHeader.getHash()) .get(); final List transactions = blockData.streamTransactions(worldState).collect(Collectors.toList()); diff --git a/besu/src/test/java/org/hyperledger/besu/services/BesuEventsImplTest.java b/besu/src/test/java/org/hyperledger/besu/services/BesuEventsImplTest.java index 4a06d63e66..5f704b18c3 100644 --- a/besu/src/test/java/org/hyperledger/besu/services/BesuEventsImplTest.java +++ b/besu/src/test/java/org/hyperledger/besu/services/BesuEventsImplTest.java @@ -125,7 +125,7 @@ public class BesuEventsImplTest { .thenReturn(ValidationResult.valid()); when(mockTransactionValidator.validateForSender(any(), any(), any())) .thenReturn(ValidationResult.valid()); - when(mockWorldStateArchive.get(any())).thenReturn(Optional.of(mockWorldState)); + when(mockWorldStateArchive.get(any(), any())).thenReturn(Optional.of(mockWorldState)); blockBroadcaster = new BlockBroadcaster(mockEthContext); syncState = new SyncState(blockchain, mockEthPeers); diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthEstimateGas.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthEstimateGas.java index 6d05b9159a..fee3dec23c 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthEstimateGas.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthEstimateGas.java @@ -68,7 +68,7 @@ public class EthEstimateGas implements JsonRpcMethod { } if (!blockchainQueries .getWorldStateArchive() - .isWorldStateAvailable(blockHeader.getStateRoot())) { + .isWorldStateAvailable(blockHeader.getStateRoot(), blockHeader.getHash())) { return errorResponse(requestContext, JsonRpcError.WORLD_STATE_UNAVAILABLE); } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/processor/BlockReplay.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/processor/BlockReplay.java index c2025488d3..ae8278d3a7 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/processor/BlockReplay.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/processor/BlockReplay.java @@ -146,7 +146,7 @@ public class BlockReplay { return Optional.empty(); } final MutableWorldState mutableWorldState = - worldStateArchive.getMutable(previous.getStateRoot()).orElse(null); + worldStateArchive.getMutable(previous.getStateRoot(), previous.getHash()).orElse(null); if (mutableWorldState == null) { return Optional.empty(); } 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 a69bbed193..320e526ce2 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 @@ -730,7 +730,9 @@ public class BlockchainQueries { */ public Optional getWorldState(final long blockNumber) { final Optional header = blockchain.getBlockHeader(blockNumber); - return header.map(BlockHeader::getStateRoot).flatMap(worldStateArchive::getMutable); + return header.flatMap( + blockHeader -> + worldStateArchive.getMutable(blockHeader.getStateRoot(), blockHeader.getHash())); } public Optional gasPrice() { diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthEstimateGasTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthEstimateGasTest.java index a05541bbe6..d19b5d08c0 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthEstimateGasTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthEstimateGasTest.java @@ -76,7 +76,7 @@ public class EthEstimateGasTest { when(blockchain.getBlockHeader(eq(1L))).thenReturn(Optional.of(blockHeader)); when(blockHeader.getGasLimit()).thenReturn(Long.MAX_VALUE); when(blockHeader.getNumber()).thenReturn(1L); - when(worldStateArchive.isWorldStateAvailable(any())).thenReturn(true); + when(worldStateArchive.isWorldStateAvailable(any(), any())).thenReturn(true); method = new EthEstimateGas(blockchainQueries, transactionSimulator); } @@ -223,7 +223,7 @@ public class EthEstimateGasTest { @Test public void shouldReturnErrorWhenWorldStateIsNotAvailable() { - when(worldStateArchive.isWorldStateAvailable(any())).thenReturn(false); + when(worldStateArchive.isWorldStateAvailable(any(), any())).thenReturn(false); final JsonRpcRequestContext request = ethEstimateGasRequest(defaultLegacyTransactionCallParameter(Wei.ZERO)); mockTransientProcessorResultGasEstimate(1L, false, false); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/processor/TransactionTracerTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/processor/TransactionTracerTest.java index 9d5bb1a2ef..67f50e9fcf 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/processor/TransactionTracerTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/processor/TransactionTracerTest.java @@ -110,7 +110,7 @@ public class TransactionTracerTest { when(blockHeader.getHash()).thenReturn(blockHash); when(blockHeader.getParentHash()).thenReturn(previousBlockHash); when(previousBlockHeader.getStateRoot()).thenReturn(Hash.ZERO); - when(worldStateArchive.getMutable(Hash.ZERO)).thenReturn(Optional.of(mutableWorldState)); + when(worldStateArchive.getMutable(Hash.ZERO, null)).thenReturn(Optional.of(mutableWorldState)); when(protocolSchedule.getByBlockNumber(12)).thenReturn(protocolSpec); when(protocolSpec.getTransactionProcessor()).thenReturn(transactionProcessor); when(protocolSpec.getMiningBeneficiaryCalculator()).thenReturn(BlockHeader::getCoinbase); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueriesTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueriesTest.java index 0aad8d5af3..4983201213 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueriesTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueriesTest.java @@ -204,8 +204,10 @@ public class BlockchainQueriesTest { final BlockchainWithData data = setupBlockchain(3, addresses, storageKeys); final BlockchainQueries queries = data.blockchainQueries; - final Hash latestStateRoot0 = data.blockData.get(2).block.getHeader().getStateRoot(); - final WorldState worldState0 = data.worldStateArchive.get(latestStateRoot0).get(); + final BlockHeader blockHeader0 = data.blockData.get(2).block.getHeader(); + final Hash latestStateRoot0 = blockHeader0.getStateRoot(); + final WorldState worldState0 = + data.worldStateArchive.get(latestStateRoot0, blockHeader0.getHash()).get(); addresses.forEach( address -> storageKeys.forEach( @@ -215,8 +217,10 @@ public class BlockchainQueriesTest { assertThat(result).contains(actualAccount0.getStorageValue(storageKey)); })); - final Hash latestStateRoot1 = data.blockData.get(1).block.getHeader().getStateRoot(); - final WorldState worldState1 = data.worldStateArchive.get(latestStateRoot1).get(); + final BlockHeader header1 = data.blockData.get(1).block.getHeader(); + final Hash latestStateRoot1 = header1.getStateRoot(); + final WorldState worldState1 = + data.worldStateArchive.get(latestStateRoot1, header1.getHash()).get(); addresses.forEach( address -> storageKeys.forEach( @@ -236,8 +240,9 @@ public class BlockchainQueriesTest { for (int i = 0; i < blockCount; i++) { final long curBlockNumber = i; - final Hash stateRoot = data.blockData.get(i).block.getHeader().getStateRoot(); - final WorldState worldState = data.worldStateArchive.get(stateRoot).get(); + final BlockHeader header = data.blockData.get(i).block.getHeader(); + final Hash stateRoot = header.getStateRoot(); + final WorldState worldState = data.worldStateArchive.get(stateRoot, header.getHash()).get(); assertThat(addresses).isNotEmpty(); addresses.forEach( diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreator.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreator.java index be74a6b1e1..5bacd20008 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreator.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreator.java @@ -240,7 +240,7 @@ public abstract class AbstractBlockCreator implements AsyncBlockCreator { final MutableWorldState worldState = protocolContext .getWorldStateArchive() - .getMutable(parentStateRoot) + .getMutable(parentStateRoot, parentHeader.getHash()) .orElseThrow( () -> { LOG.info("Unable to create block because world state is not available"); diff --git a/ethereum/core/src/integration-test/java/org/hyperledger/besu/ethereum/mainnet/precompiles/privacy/PrivacyPrecompiledContractIntegrationTest.java b/ethereum/core/src/integration-test/java/org/hyperledger/besu/ethereum/mainnet/precompiles/privacy/PrivacyPrecompiledContractIntegrationTest.java index 9f86a6d18a..bb5cf2d52e 100644 --- a/ethereum/core/src/integration-test/java/org/hyperledger/besu/ethereum/mainnet/precompiles/privacy/PrivacyPrecompiledContractIntegrationTest.java +++ b/ethereum/core/src/integration-test/java/org/hyperledger/besu/ethereum/mainnet/precompiles/privacy/PrivacyPrecompiledContractIntegrationTest.java @@ -147,7 +147,7 @@ public class PrivacyPrecompiledContractIntegrationTest { final MutableWorldState mutableWorldState = mock(MutableWorldState.class); when(mutableWorldState.updater()).thenReturn(mock(WorldUpdater.class)); when(worldStateArchive.getMutable()).thenReturn(mutableWorldState); - when(worldStateArchive.getMutable(any())).thenReturn(Optional.of(mutableWorldState)); + when(worldStateArchive.getMutable(any(), any())).thenReturn(Optional.of(mutableWorldState)); privateStateStorage = mock(PrivateStateStorage.class); final PrivateStateStorage.Updater storageUpdater = mock(PrivateStateStorage.Updater.class); diff --git a/ethereum/core/src/integration-test/java/org/hyperledger/besu/ethereum/vm/TraceTransactionIntegrationTest.java b/ethereum/core/src/integration-test/java/org/hyperledger/besu/ethereum/vm/TraceTransactionIntegrationTest.java index a0eda0b729..8cdd710cd9 100644 --- a/ethereum/core/src/integration-test/java/org/hyperledger/besu/ethereum/vm/TraceTransactionIntegrationTest.java +++ b/ethereum/core/src/integration-test/java/org/hyperledger/besu/ethereum/vm/TraceTransactionIntegrationTest.java @@ -21,6 +21,7 @@ import org.hyperledger.besu.crypto.SECP256K1.KeyPair; import org.hyperledger.besu.ethereum.chain.MutableBlockchain; import org.hyperledger.besu.ethereum.core.Account; import org.hyperledger.besu.ethereum.core.Block; +import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.ExecutionContextTestFixture; import org.hyperledger.besu.ethereum.core.Gas; import org.hyperledger.besu.ethereum.core.MutableWorldState; @@ -86,16 +87,19 @@ public class TraceTransactionIntegrationTest { .value(Wei.ZERO) .signAndBuild(keyPair); + final BlockHeader genesisBlockHeader = genesisBlock.getHeader(); final MutableWorldState worldState = - worldStateArchive.getMutable(genesisBlock.getHeader().getStateRoot()).get(); + worldStateArchive + .getMutable(genesisBlockHeader.getStateRoot(), genesisBlockHeader.getHash()) + .get(); final WorldUpdater createTransactionUpdater = worldState.updater(); TransactionProcessingResult result = transactionProcessor.processTransaction( blockchain, createTransactionUpdater, - genesisBlock.getHeader(), + genesisBlockHeader, createTransaction, - genesisBlock.getHeader().getCoinbase(), + genesisBlockHeader.getCoinbase(), blockHashLookup, false, TransactionValidationParams.blockReplay()); @@ -125,9 +129,9 @@ public class TraceTransactionIntegrationTest { transactionProcessor.processTransaction( blockchain, storeUpdater, - genesisBlock.getHeader(), + genesisBlockHeader, executeTransaction, - genesisBlock.getHeader().getCoinbase(), + genesisBlockHeader.getCoinbase(), tracer, blockHashLookup, false); @@ -159,14 +163,18 @@ public class TraceTransactionIntegrationTest { final Transaction transaction = Transaction.readFrom( new BytesValueRLPInput(Bytes.fromHexString(CONTRACT_CREATION_TX), false)); + BlockHeader genesisBlockHeader = genesisBlock.getHeader(); transactionProcessor.processTransaction( blockchain, - worldStateArchive.getMutable(genesisBlock.getHeader().getStateRoot()).get().updater(), - genesisBlock.getHeader(), + worldStateArchive + .getMutable(genesisBlockHeader.getStateRoot(), genesisBlockHeader.getHash()) + .get() + .updater(), + genesisBlockHeader, transaction, - genesisBlock.getHeader().getCoinbase(), + genesisBlockHeader.getCoinbase(), tracer, - new BlockHashLookup(genesisBlock.getHeader(), blockchain), + new BlockHashLookup(genesisBlockHeader, blockchain), false); final int expectedDepth = 0; // Reference impl returned 1. Why the difference? diff --git a/ethereum/core/src/integration-test/java/org/hyperledger/besu/ethereum/worldstate/PrunerIntegrationTest.java b/ethereum/core/src/integration-test/java/org/hyperledger/besu/ethereum/worldstate/PrunerIntegrationTest.java index aa0f9bc0cf..f2021c134c 100644 --- a/ethereum/core/src/integration-test/java/org/hyperledger/besu/ethereum/worldstate/PrunerIntegrationTest.java +++ b/ethereum/core/src/integration-test/java/org/hyperledger/besu/ethereum/worldstate/PrunerIntegrationTest.java @@ -137,9 +137,11 @@ public class PrunerIntegrationTest { // Assert that blocks from mark point onward are still accessible for (int i = fullyMarkedBlockNum; i <= blockchain.getChainHeadBlockNumber(); i++) { - final Hash stateRoot = blockchain.getBlockHeader(i).get().getStateRoot(); - assertThat(worldStateArchive.get(stateRoot)).isPresent(); - final WorldState markedState = worldStateArchive.get(stateRoot).get(); + final BlockHeader blockHeader = blockchain.getBlockHeader(i).get(); + final Hash stateRoot = blockHeader.getStateRoot(); + assertThat(worldStateArchive.get(stateRoot, blockHeader.getHash())).isPresent(); + final WorldState markedState = + worldStateArchive.get(stateRoot, blockHeader.getHash()).get(); // Traverse accounts and make sure all are accessible final int expectedAccounts = accountsPerBlock * i; final long accounts = @@ -155,7 +157,8 @@ public class PrunerIntegrationTest { for (int i = 0; i < fullyMarkedBlockNum; i++) { final BlockHeader curHeader = blockchain.getBlockHeader(i).get(); if (!curHeader.getStateRoot().equals(Hash.EMPTY_TRIE_HASH)) { - assertThat(worldStateArchive.get(curHeader.getStateRoot())).isEmpty(); + assertThat(worldStateArchive.get(curHeader.getStateRoot(), curHeader.getHash())) + .isEmpty(); } } @@ -172,8 +175,10 @@ public class PrunerIntegrationTest { private void generateBlockchainData(final int numBlocks, final int numAccounts) { Block parentBlock = blockchain.getChainHeadBlock(); for (int i = 0; i < numBlocks; i++) { + final BlockHeader parentHeader = parentBlock.getHeader(); + final Hash parentHash = parentBlock.getHash(); final MutableWorldState worldState = - worldStateArchive.getMutable(parentBlock.getHeader().getStateRoot()).get(); + worldStateArchive.getMutable(parentHeader.getStateRoot(), parentHash).get(); gen.createRandomContractAccountsWithNonEmptyStorage(worldState, numAccounts); final Hash stateRoot = worldState.rootHash(); @@ -181,8 +186,8 @@ public class PrunerIntegrationTest { gen.block( BlockOptions.create() .setStateRoot(stateRoot) - .setBlockNumber(parentBlock.getHeader().getNumber() + 1L) - .setParentHash(parentBlock.getHash())); + .setBlockNumber(parentHeader.getNumber() + 1L) + .setParentHash(parentHash)); final List receipts = gen.receipts(block); blockchain.appendBlock(block, receipts); parentBlock = block; diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/MainnetBlockValidator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/MainnetBlockValidator.java index d047429df1..188fa1f4ca 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/MainnetBlockValidator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/MainnetBlockValidator.java @@ -83,7 +83,9 @@ public class MainnetBlockValidator implements BlockValidator { final MutableBlockchain blockchain = context.getBlockchain(); final Optional maybeWorldState = - context.getWorldStateArchive().getMutable(parentHeader.getStateRoot()); + context + .getWorldStateArchive() + .getMutable(parentHeader.getStateRoot(), parentHeader.getHash()); if (!maybeWorldState.isPresent()) { LOG.debug( "Unable to process block {} because parent world state {} is not available", diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/BonsaiWorldStateArchive.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/BonsaiWorldStateArchive.java index 9f268ff379..00cbe0f0e5 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/BonsaiWorldStateArchive.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/BonsaiWorldStateArchive.java @@ -53,7 +53,7 @@ public class BonsaiWorldStateArchive implements WorldStateArchive { } @Override - public Optional get(final Hash rootHash) { + public Optional get(final Hash rootHash, final Hash blockHash) { if (layeredWorldStates.containsKey(rootHash)) { return Optional.of(layeredWorldStates.get(rootHash)); } else if (rootHash.equals(persistedState.rootHash())) { @@ -68,13 +68,13 @@ public class BonsaiWorldStateArchive implements WorldStateArchive { } @Override - public boolean isWorldStateAvailable(final Hash rootHash) { + public boolean isWorldStateAvailable(final Hash rootHash, final Hash blockHash) { return layeredWorldStates.containsKey(rootHash) || persistedState.rootHash().equals(rootHash) /* || check disk storage */; } @Override - public Optional getMutable(final Hash rootHash) { + public Optional getMutable(final Hash rootHash, final Hash blockHash) { if (rootHash.equals(persistedState.rootHash())) { return Optional.of(persistedState); } else { diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/precompiles/privacy/OnChainPrivacyPrecompiledContract.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/precompiles/privacy/OnChainPrivacyPrecompiledContract.java index ac5960d559..c0753c4b3e 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/precompiles/privacy/OnChainPrivacyPrecompiledContract.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/precompiles/privacy/OnChainPrivacyPrecompiledContract.java @@ -147,7 +147,7 @@ public class OnChainPrivacyPrecompiledContract extends PrivacyPrecompiledContrac privateStateRootResolver.resolveLastStateRoot(privacyGroupId, privateMetadataUpdater); final MutableWorldState disposablePrivateState = - privateWorldStateArchive.getMutable(lastRootHash).get(); + privateWorldStateArchive.getMutable(lastRootHash, null).get(); final WorldUpdater privateWorldStateUpdater = disposablePrivateState.updater(); @@ -398,7 +398,7 @@ public class OnChainPrivacyPrecompiledContract extends PrivacyPrecompiledContrac // privateTransactionProcessor.processTransaction(...) commits the state if the process was // successful before it returns final MutableWorldState localMutableState = - privateWorldStateArchive.getMutable(disposablePrivateState.rootHash()).get(); + privateWorldStateArchive.getMutable(disposablePrivateState.rootHash(), null).get(); final WorldUpdater updater = localMutableState.updater(); return privateTransactionProcessor.processTransaction( diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/precompiles/privacy/PrivacyPrecompiledContract.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/precompiles/privacy/PrivacyPrecompiledContract.java index 9b40048a2f..75b3677a7f 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/precompiles/privacy/PrivacyPrecompiledContract.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/precompiles/privacy/PrivacyPrecompiledContract.java @@ -158,7 +158,7 @@ public class PrivacyPrecompiledContract extends AbstractPrecompiledContract { privateStateRootResolver.resolveLastStateRoot(privacyGroupId, privateMetadataUpdater); final MutableWorldState disposablePrivateState = - privateWorldStateArchive.getMutable(lastRootHash).get(); + privateWorldStateArchive.getMutable(lastRootHash, null).get(); final WorldUpdater privateWorldStateUpdater = disposablePrivateState.updater(); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/ChainHeadPrivateNonceProvider.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/ChainHeadPrivateNonceProvider.java index 8d10f565a8..3d879d8e2b 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/ChainHeadPrivateNonceProvider.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/ChainHeadPrivateNonceProvider.java @@ -40,10 +40,11 @@ public class ChainHeadPrivateNonceProvider implements PrivateNonceProvider { @Override public long getNonce(final Address sender, final Bytes32 privacyGroupId) { final BlockHeader chainHeadHeader = blockchain.getChainHeadHeader(); + Hash chainHeadHash = chainHeadHeader.getHash(); final Hash stateRoot = - privateStateRootResolver.resolveLastStateRoot(privacyGroupId, chainHeadHeader.getHash()); + privateStateRootResolver.resolveLastStateRoot(privacyGroupId, chainHeadHash); return privateWorldStateArchive - .get(stateRoot) + .get(stateRoot, chainHeadHash) .map( privateWorldState -> { final Account account = privateWorldState.get(sender); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/PrivateGroupRehydrationBlockProcessor.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/PrivateGroupRehydrationBlockProcessor.java index 480fda83eb..47d65f937c 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/PrivateGroupRehydrationBlockProcessor.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/PrivateGroupRehydrationBlockProcessor.java @@ -121,7 +121,7 @@ public class PrivateGroupRehydrationBlockProcessor { privateStateRootResolver.resolveLastStateRoot(privacyGroupId, metadataUpdater); final MutableWorldState disposablePrivateState = - privateWorldStateArchive.getMutable(lastRootHash).get(); + privateWorldStateArchive.getMutable(lastRootHash, null).get(); final WorldUpdater privateStateUpdater = disposablePrivateState.updater(); maybeInjectDefaultManagementAndProxy( lastRootHash, disposablePrivateState, privateStateUpdater); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/PrivateStateRehydration.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/PrivateStateRehydration.java index d6fe7844a5..cdbde34506 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/PrivateStateRehydration.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/PrivateStateRehydration.java @@ -150,8 +150,9 @@ public class PrivateStateRehydration { final MutableWorldState publicWorldState = blockchain .getBlockHeader(blockHeader.getParentHash()) - .map(BlockHeader::getStateRoot) - .flatMap(publicWorldStateArchive::getMutable) + .flatMap( + header -> + publicWorldStateArchive.getMutable(header.getStateRoot(), header.getHash())) .orElseThrow(RuntimeException::new); privateGroupRehydrationBlockProcessor.processBlock( diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/PrivateTransactionSimulator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/PrivateTransactionSimulator.java index 2b89276832..0515d54033 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/PrivateTransactionSimulator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/PrivateTransactionSimulator.java @@ -94,7 +94,7 @@ public class PrivateTransactionSimulator { } final MutableWorldState publicWorldState = - worldStateArchive.getMutable(header.getStateRoot()).orElse(null); + worldStateArchive.getMutable(header.getStateRoot(), header.getHash()).orElse(null); if (publicWorldState == null) { return Optional.empty(); } @@ -105,7 +105,10 @@ public class PrivateTransactionSimulator { privateStateRootResolver.resolveLastStateRoot(privacyGroupId, header.getHash()); final MutableWorldState disposablePrivateState = - privacyParameters.getPrivateWorldStateArchive().getMutable(lastRootHash).get(); + privacyParameters + .getPrivateWorldStateArchive() + .getMutable(lastRootHash, header.getHash()) + .get(); final PrivateTransaction transaction = getPrivateTransaction(callParams, header, privacyGroupId, disposablePrivateState); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/PrivateWorldStateReader.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/PrivateWorldStateReader.java index 5386ec089a..0823e50031 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/PrivateWorldStateReader.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/PrivateWorldStateReader.java @@ -50,7 +50,7 @@ public class PrivateWorldStateReader { Bytes32.wrap(Bytes.fromBase64String(privacyGroupId)), blockHash); return privateWorldStateArchive - .get(latestStateRoot) + .get(latestStateRoot, blockHash) .flatMap(worldState -> Optional.ofNullable(worldState.get(contractAddress))) .flatMap(account -> Optional.ofNullable(account.getCode())); } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/storage/migration/PrivateStorageMigration.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/storage/migration/PrivateStorageMigration.java index 5b795c9fe6..d0d5b9afb1 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/storage/migration/PrivateStorageMigration.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/storage/migration/PrivateStorageMigration.java @@ -100,8 +100,9 @@ public class PrivateStorageMigration { final MutableWorldState publicWorldState = blockchain .getBlockHeader(blockHeader.getParentHash()) - .map(BlockHeader::getStateRoot) - .flatMap(publicWorldStateArchive::getMutable) + .flatMap( + header -> + publicWorldStateArchive.getMutable(header.getStateRoot(), header.getHash())) .orElseThrow(PrivateStorageMigrationException::new); final List transactionsToProcess = diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulator.java index 6d5348e227..bb5f17ab76 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulator.java @@ -113,7 +113,7 @@ public class TransactionSimulator { return Optional.empty(); } final MutableWorldState worldState = - worldStateArchive.getMutable(header.getStateRoot()).orElse(null); + worldStateArchive.getMutable(header.getStateRoot(), header.getHash()).orElse(null); if (worldState == null) { return Optional.empty(); } @@ -179,7 +179,7 @@ public class TransactionSimulator { } final MutableWorldState worldState = - worldStateArchive.getMutable(header.getStateRoot()).orElse(null); + worldStateArchive.getMutable(header.getStateRoot(), header.getHash()).orElse(null); if (worldState == null) { return Optional.empty(); } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/worldstate/DefaultWorldStateArchive.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/worldstate/DefaultWorldStateArchive.java index 7bbb25efda..52a95434f4 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/worldstate/DefaultWorldStateArchive.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/worldstate/DefaultWorldStateArchive.java @@ -44,17 +44,17 @@ public class DefaultWorldStateArchive implements WorldStateArchive { } @Override - public Optional get(final Hash rootHash) { - return getMutable(rootHash).map(state -> state); + public Optional get(final Hash rootHash, final Hash blockHash) { + return getMutable(rootHash, blockHash).map(state -> state); } @Override - public boolean isWorldStateAvailable(final Hash rootHash) { + public boolean isWorldStateAvailable(final Hash rootHash, final Hash blockHash) { return worldStateStorage.isWorldStateAvailable(rootHash); } @Override - public Optional getMutable(final Hash rootHash) { + public Optional getMutable(final Hash rootHash, final Hash blockHash) { if (!worldStateStorage.isWorldStateAvailable(rootHash)) { return Optional.empty(); } @@ -63,7 +63,7 @@ public class DefaultWorldStateArchive implements WorldStateArchive { @Override public MutableWorldState getMutable() { - return getMutable(EMPTY_ROOT_HASH).get(); + return getMutable(EMPTY_ROOT_HASH, null).get(); } @Override diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/worldstate/WorldStateArchive.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/worldstate/WorldStateArchive.java index 1e28a9c08f..4ff166d201 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/worldstate/WorldStateArchive.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/worldstate/WorldStateArchive.java @@ -30,18 +30,16 @@ import org.apache.tuweni.units.bigints.UInt256; public interface WorldStateArchive { Hash EMPTY_ROOT_HASH = Hash.wrap(MerklePatriciaTrie.EMPTY_TRIE_NODE_HASH); - Optional get(final Hash rootHash); + Optional get(Hash rootHash, Hash blockHash); - boolean isWorldStateAvailable(final Hash rootHash); + boolean isWorldStateAvailable(Hash rootHash, Hash blockHash); - Optional getMutable(final Hash rootHash); + Optional getMutable(Hash rootHash, Hash blockHash); MutableWorldState getMutable(); - Optional getNodeData(final Hash hash); + Optional getNodeData(Hash hash); Optional getAccountProof( - final Hash worldStateRoot, - final Address accountAddress, - final List accountStorageKeys); + Hash worldStateRoot, Address accountAddress, List accountStorageKeys); } diff --git a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/TestCodeExecutor.java b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/TestCodeExecutor.java index 501629f246..d791ac02ae 100644 --- a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/TestCodeExecutor.java +++ b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/TestCodeExecutor.java @@ -101,6 +101,6 @@ public class TestCodeExecutor { accountSetup.accept(senderAccount); worldState.commit(); initialWorldState.persist(null); - return stateArchive.getMutable(initialWorldState.rootHash()).get().updater(); + return stateArchive.getMutable(initialWorldState.rootHash(), null).get().updater(); } } diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/MainnetBlockValidatorTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/MainnetBlockValidatorTest.java index ca5be707d2..bc57b8a25b 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/MainnetBlockValidatorTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/MainnetBlockValidatorTest.java @@ -115,7 +115,8 @@ public class MainnetBlockValidatorTest { eq(protocolContext), eq(HeaderValidationMode.DETACHED_ONLY))) .thenReturn(true); - when(worldStateArchive.getMutable(any(Hash.class))).thenReturn(Optional.empty()); + when(worldStateArchive.getMutable(any(Hash.class), any(Hash.class))) + .thenReturn(Optional.empty()); assertThat(badBlockManager.getBadBlocks().size()).isEqualTo(0); mainnetBlockValidator.validateAndProcessBlock( @@ -136,7 +137,7 @@ public class MainnetBlockValidatorTest { eq(protocolContext), eq(HeaderValidationMode.DETACHED_ONLY))) .thenReturn(true); - when(worldStateArchive.getMutable(any(Hash.class))) + when(worldStateArchive.getMutable(any(Hash.class), any(Hash.class))) .thenReturn(Optional.of(mock(MutableWorldState.class))); when(blockProcessor.processBlock(eq(blockchain), any(MutableWorldState.class), eq(badBlock))) .thenReturn( @@ -171,7 +172,7 @@ public class MainnetBlockValidatorTest { eq(protocolContext), eq(HeaderValidationMode.DETACHED_ONLY))) .thenReturn(true); - when(worldStateArchive.getMutable(any(Hash.class))) + when(worldStateArchive.getMutable(any(Hash.class), any(Hash.class))) .thenReturn(Optional.of(mock(MutableWorldState.class))); when(blockProcessor.processBlock(eq(blockchain), any(MutableWorldState.class), eq(badBlock))) .thenReturn( @@ -206,7 +207,7 @@ public class MainnetBlockValidatorTest { eq(protocolContext), eq(HeaderValidationMode.DETACHED_ONLY))) .thenReturn(true); - when(worldStateArchive.getMutable(any(Hash.class))) + when(worldStateArchive.getMutable(any(Hash.class), any(Hash.class))) .thenReturn(Optional.of(mock(MutableWorldState.class))); when(blockProcessor.processBlock(eq(blockchain), any(MutableWorldState.class), eq(badBlock))) .thenReturn( diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/PrivacyBlockProcessorTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/PrivacyBlockProcessorTest.java index c7dcf10576..d1179e2ff1 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/PrivacyBlockProcessorTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/PrivacyBlockProcessorTest.java @@ -150,9 +150,10 @@ public class PrivacyBlockProcessorTest { when(blockchain.getBlockHeader(any())).thenReturn(Optional.of(firstBlock.getHeader())); final ProtocolSpec protocolSpec = mockProtocolSpec(); when(protocolSchedule.getByBlockNumber(anyLong())).thenReturn(protocolSpec); - when(publicWorldStateArchive.getMutable(any())).thenReturn(Optional.of(mutableWorldState)); + when(publicWorldStateArchive.getMutable(any(), any())) + .thenReturn(Optional.of(mutableWorldState)); final MutableWorldState mockPrivateStateArchive = mockPrivateStateArchive(); - when(privateWorldStateArchive.getMutable(any())) + when(privateWorldStateArchive.getMutable(any(), any())) .thenReturn(Optional.of(mockPrivateStateArchive)); final PrivacyGroupHeadBlockMap expected = diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/precompiles/privacy/OnChainPrivacyPrecompiledContractTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/precompiles/privacy/OnChainPrivacyPrecompiledContractTest.java index e0cfa83d7e..074df99fff 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/precompiles/privacy/OnChainPrivacyPrecompiledContractTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/precompiles/privacy/OnChainPrivacyPrecompiledContractTest.java @@ -107,7 +107,7 @@ public class OnChainPrivacyPrecompiledContractTest { final MutableWorldState mutableWorldState = mock(MutableWorldState.class); when(mutableWorldState.updater()).thenReturn(mock(WorldUpdater.class)); when(worldStateArchive.getMutable()).thenReturn(mutableWorldState); - when(worldStateArchive.getMutable(any())).thenReturn(Optional.of(mutableWorldState)); + when(worldStateArchive.getMutable(any(), any())).thenReturn(Optional.of(mutableWorldState)); final PrivateStateStorage.Updater storageUpdater = mock(PrivateStateStorage.Updater.class); when(privateStateStorage.getPrivacyGroupHeadBlockMap(any())) diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/precompiles/privacy/PrivacyPrecompiledContractTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/precompiles/privacy/PrivacyPrecompiledContractTest.java index 4c44fe3679..1182e0f6be 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/precompiles/privacy/PrivacyPrecompiledContractTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/precompiles/privacy/PrivacyPrecompiledContractTest.java @@ -110,7 +110,7 @@ public class PrivacyPrecompiledContractTest { final MutableWorldState mutableWorldState = mock(MutableWorldState.class); when(mutableWorldState.updater()).thenReturn(mock(WorldUpdater.class)); when(worldStateArchive.getMutable()).thenReturn(mutableWorldState); - when(worldStateArchive.getMutable(any())).thenReturn(Optional.of(mutableWorldState)); + when(worldStateArchive.getMutable(any(), any())).thenReturn(Optional.of(mutableWorldState)); when(privateMetadataUpdater.getPrivacyGroupHeadBlockMap()) .thenReturn(PrivacyGroupHeadBlockMap.empty()); diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/ChainHeadPrivateNonceProviderTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/ChainHeadPrivateNonceProviderTest.java index fb578cb5ea..f4f1974fbb 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/ChainHeadPrivateNonceProviderTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/ChainHeadPrivateNonceProviderTest.java @@ -67,7 +67,8 @@ public class ChainHeadPrivateNonceProviderTest { public void determineNonceForPrivacyGroupRequestWhenPrivateStateDoesNotExist() { when(privateStateRootResolver.resolveLastStateRoot(any(Bytes32.class), any(Hash.class))) .thenReturn(Hash.ZERO); - when(privateWorldStateArchive.get(any(Hash.class))).thenReturn(Optional.empty()); + when(privateWorldStateArchive.get(any(Hash.class), any(Hash.class))) + .thenReturn(Optional.empty()); final long nonce = privateNonceProvider.getNonce(ADDRESS, PRIVACY_GROUP_ID); @@ -80,7 +81,8 @@ public class ChainHeadPrivateNonceProviderTest { when(worldState.get(any(Address.class))).thenReturn(account); when(privateStateRootResolver.resolveLastStateRoot(any(Bytes32.class), any(Hash.class))) .thenReturn(Hash.ZERO); - when(privateWorldStateArchive.get(any(Hash.class))).thenReturn(Optional.of(worldState)); + when(privateWorldStateArchive.get(any(Hash.class), any(Hash.class))) + .thenReturn(Optional.of(worldState)); final long nonce = privateNonceProvider.getNonce(ADDRESS, PRIVACY_GROUP_ID); @@ -91,7 +93,8 @@ public class ChainHeadPrivateNonceProviderTest { public void determineNonceForPrivacyGroupRequestWhenAccountDoesNotExist() { when(privateStateRootResolver.resolveLastStateRoot(any(Bytes32.class), any(Hash.class))) .thenReturn(Hash.ZERO); - when(privateWorldStateArchive.get(any(Hash.class))).thenReturn(Optional.of(worldState)); + when(privateWorldStateArchive.get(any(Hash.class), any(Hash.class))) + .thenReturn(Optional.of(worldState)); when(account.getNonce()).thenReturn(4L); final long nonce = privateNonceProvider.getNonce(ADDRESS, PRIVACY_GROUP_ID); diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/PrivateWorldStateReaderTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/PrivateWorldStateReaderTest.java index a476b44138..44e557dac2 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/PrivateWorldStateReaderTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/PrivateWorldStateReaderTest.java @@ -17,6 +17,7 @@ package org.hyperledger.besu.ethereum.privacy; import static org.assertj.core.api.Assertions.assertThat; import static org.hyperledger.besu.ethereum.core.PrivateTransactionDataFixture.generatePrivateBlockMetadata; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.when; @@ -81,7 +82,7 @@ public class PrivateWorldStateReaderTest { when(privateStateRootResolver.resolveLastStateRoot(eq(privacyGroupBytes), eq(blockHash))) .thenReturn(stateRootHash); - when(privateWorldStateArchive.get(eq(stateRootHash))).thenReturn(Optional.empty()); + when(privateWorldStateArchive.get(eq(stateRootHash), any())).thenReturn(Optional.empty()); final Optional maybecontractCode = privateWorldStateReader.getContractCode(PRIVACY_GROUP_ID, blockHash, contractAddress); @@ -96,7 +97,7 @@ public class PrivateWorldStateReaderTest { when(privateStateRootResolver.resolveLastStateRoot(eq(privacyGroupBytes), eq(blockHash))) .thenReturn(stateRootHash); - when(privateWorldStateArchive.get(eq(stateRootHash))) + when(privateWorldStateArchive.get(eq(stateRootHash), any())) .thenReturn(Optional.of(privateWorldState)); when(privateWorldState.get(eq(contractAddress))).thenReturn(null); @@ -113,7 +114,7 @@ public class PrivateWorldStateReaderTest { when(privateStateRootResolver.resolveLastStateRoot(eq(privacyGroupBytes), eq(blockHash))) .thenReturn(stateRootHash); - when(privateWorldStateArchive.get(eq(stateRootHash))) + when(privateWorldStateArchive.get(eq(stateRootHash), any())) .thenReturn(Optional.of(privateWorldState)); when(privateWorldState.get(eq(contractAddress))).thenReturn(contractAccount); when(contractAccount.getCode()).thenReturn(null); @@ -128,7 +129,7 @@ public class PrivateWorldStateReaderTest { public void existingAccountWithCodeReturnsExpectedBytes() { when(privateStateRootResolver.resolveLastStateRoot(eq(PRIVACY_GROUP_ID_BYTES), eq(blockHash))) .thenReturn(stateRootHash); - when(privateWorldStateArchive.get(eq(stateRootHash))) + when(privateWorldStateArchive.get(eq(stateRootHash), any())) .thenReturn(Optional.of(privateWorldState)); when(privateWorldState.get(eq(contractAddress))).thenReturn(contractAccount); when(contractAccount.getCode()).thenReturn(contractCode); diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/storage/migration/PrivateStorageMigrationTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/storage/migration/PrivateStorageMigrationTest.java index c3f0b31bcd..179955e5d2 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/storage/migration/PrivateStorageMigrationTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/storage/migration/PrivateStorageMigrationTest.java @@ -33,6 +33,7 @@ import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.core.Address; import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.BlockDataGenerator; +import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.Hash; import org.hyperledger.besu.ethereum.core.MutableWorldState; import org.hyperledger.besu.ethereum.core.Transaction; @@ -297,11 +298,13 @@ public class PrivateStorageMigrationTest { } private void mockBlockInBlockchain(final Block block) { - when(blockchain.getBlockByNumber(block.getHeader().getNumber())).thenReturn(Optional.of(block)); - when(blockchain.getBlockHeader(block.getHash())).thenReturn(Optional.of(block.getHeader())); - when(blockchain.getBlockBody(block.getHash())).thenReturn(Optional.of(block.getBody())); + final BlockHeader blockHeader = block.getHeader(); + final Hash blockHash = block.getHash(); + when(blockchain.getBlockByNumber(blockHeader.getNumber())).thenReturn(Optional.of(block)); + when(blockchain.getBlockHeader(blockHash)).thenReturn(Optional.of(blockHeader)); + when(blockchain.getBlockBody(blockHash)).thenReturn(Optional.of(block.getBody())); - when(publicWorldStateArchive.getMutable(block.getHeader().getStateRoot())) + when(publicWorldStateArchive.getMutable(blockHeader.getStateRoot(), blockHash)) .thenReturn(Optional.of(publicMutableWorldState)); } diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulatorTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulatorTest.java index 9ebd9fc3f9..650ff6a38b 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulatorTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulatorTest.java @@ -409,19 +409,19 @@ public class TransactionSimulatorTest { final Hash stateRoot, final Address address, final long nonce) { final Account account = mock(Account.class); when(account.getNonce()).thenReturn(nonce); - when(worldStateArchive.getMutable(eq(stateRoot))).thenReturn(Optional.of(worldState)); + when(worldStateArchive.getMutable(eq(stateRoot), any())).thenReturn(Optional.of(worldState)); when(worldState.get(eq(address))).thenReturn(account); } private void mockWorldStateForAbsentAccount(final Hash stateRoot) { - when(worldStateArchive.getMutable(eq(stateRoot))).thenReturn(Optional.of(worldState)); + when(worldStateArchive.getMutable(eq(stateRoot), any())).thenReturn(Optional.of(worldState)); when(worldState.get(any())).thenReturn(null); } private MutableAccount mockWorldUpdaterForAccount(final Hash stateRoot, final Address address) { final EvmAccount account = mock(EvmAccount.class); final MutableAccount mutableAccount = mock(MutableAccount.class); - when(worldStateArchive.getMutable(eq(stateRoot))).thenReturn(Optional.of(worldState)); + when(worldStateArchive.getMutable(eq(stateRoot), any())).thenReturn(Optional.of(worldState)); when(worldState.updater()).thenReturn(worldUpdater); when(worldUpdater.getOrCreate(eq(address))).thenReturn(account); when(account.getMutable()).thenReturn(mutableAccount); diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/vm/BlockchainReferenceTestTools.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/vm/BlockchainReferenceTestTools.java index f97ff01898..3114097139 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/vm/BlockchainReferenceTestTools.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/vm/BlockchainReferenceTestTools.java @@ -90,9 +90,11 @@ public class BlockchainReferenceTestTools { } public static void executeTest(final BlockchainReferenceTestCaseSpec spec) { - final MutableWorldState worldState = - spec.getWorldStateArchive().getMutable(spec.getGenesisBlockHeader().getStateRoot()).get(); final BlockHeader genesisBlockHeader = spec.getGenesisBlockHeader(); + final MutableWorldState worldState = + spec.getWorldStateArchive() + .getMutable(genesisBlockHeader.getStateRoot(), genesisBlockHeader.getHash()) + .get(); assertThat(worldState.rootHash()).isEqualTo(genesisBlockHeader.getStateRoot()); final ProtocolSchedule schedule = diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/worldstate/MarkSweepPrunerTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/worldstate/MarkSweepPrunerTest.java index e975734b8c..518dd2ce92 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/worldstate/MarkSweepPrunerTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/worldstate/MarkSweepPrunerTest.java @@ -87,8 +87,9 @@ public class MarkSweepPrunerTest { pruner.sweepBefore(markBlock.getNumber()); // Assert that the block we marked is still present and all accounts are accessible - assertThat(worldStateArchive.get(markBlock.getStateRoot())).isPresent(); - final WorldState markedState = worldStateArchive.get(markBlock.getStateRoot()).get(); + assertThat(worldStateArchive.get(markBlock.getStateRoot(), markBlock.getHash())).isPresent(); + final WorldState markedState = + worldStateArchive.get(markBlock.getStateRoot(), markBlock.getHash()).get(); // Traverse accounts and make sure all are accessible final int expectedAccounts = numAccounts * markBlockNumber; final long accounts = markedState.streamAccounts(Bytes32.ZERO, expectedAccounts * 2).count(); @@ -104,7 +105,7 @@ public class MarkSweepPrunerTest { if (curHeader.getNumber() == markBlock.getNumber()) { continue; } - assertThat(worldStateArchive.get(curHeader.getStateRoot())).isEmpty(); + assertThat(worldStateArchive.get(curHeader.getStateRoot(), curHeader.getHash())).isEmpty(); } // Check that storage contains only the values we expect @@ -189,8 +190,9 @@ public class MarkSweepPrunerTest { private void generateBlockchainData(final int numBlocks, final int numAccounts) { Block parentBlock = blockchain.getChainHeadBlock(); for (int i = 0; i < numBlocks; i++) { + final BlockHeader parentHeader = parentBlock.getHeader(); final MutableWorldState worldState = - worldStateArchive.getMutable(parentBlock.getHeader().getStateRoot()).get(); + worldStateArchive.getMutable(parentHeader.getStateRoot(), parentHeader.getHash()).get(); gen.createRandomContractAccountsWithNonEmptyStorage(worldState, numAccounts); final Hash stateRoot = worldState.rootHash(); @@ -198,7 +200,7 @@ public class MarkSweepPrunerTest { gen.block( BlockOptions.create() .setStateRoot(stateRoot) - .setBlockNumber(parentBlock.getHeader().getNumber() + 1L) + .setBlockNumber(parentHeader.getNumber() + 1L) .setParentHash(parentBlock.getHash())); final List receipts = gen.receipts(block); blockchain.appendBlock(block, receipts); diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncTargetManager.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncTargetManager.java index 400957b0fb..76f984f917 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncTargetManager.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncTargetManager.java @@ -56,7 +56,7 @@ class FullSyncTargetManager extends SyncTargetManager { final BlockHeader commonAncestor = syncTarget.commonAncestor(); if (protocolContext .getWorldStateArchive() - .isWorldStateAvailable(commonAncestor.getStateRoot())) { + .isWorldStateAvailable(commonAncestor.getStateRoot(), commonAncestor.getHash())) { return Optional.of(syncTarget); } else { LOG.warn( diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPool.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPool.java index 8ae3802859..ac4986fe63 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPool.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPool.java @@ -251,7 +251,7 @@ public class TransactionPool implements BlockAddedObserver { return protocolContext .getWorldStateArchive() - .get(chainHeadBlockHeader.getStateRoot()) + .get(chainHeadBlockHeader.getStateRoot(), chainHeadBlockHeader.getHash()) .map( worldState -> { final Account senderAccount = worldState.get(transaction.getSender()); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncTargetManagerTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncTargetManagerTest.java index a45aaea5dd..e268705fa8 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncTargetManagerTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncTargetManagerTest.java @@ -21,6 +21,7 @@ import static org.mockito.Mockito.when; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.chain.MutableBlockchain; +import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockchainSetupUtil; import org.hyperledger.besu.ethereum.core.Difficulty; import org.hyperledger.besu.ethereum.core.ProtocolScheduleFixture; @@ -90,7 +91,9 @@ public class FullSyncTargetManagerTest { @Test public void findSyncTarget_withHeightEstimates() { - when(localWorldState.isWorldStateAvailable(localBlockchain.getChainHeadHeader().getStateRoot())) + final BlockHeader chainHeadHeader = localBlockchain.getChainHeadHeader(); + when(localWorldState.isWorldStateAvailable( + chainHeadHeader.getStateRoot(), chainHeadHeader.getHash())) .thenReturn(true); final RespondingEthPeer bestPeer = EthProtocolManagerTestUtil.createPeer(ethProtocolManager, Difficulty.MAX_VALUE, 4); @@ -105,7 +108,9 @@ public class FullSyncTargetManagerTest { @Test public void findSyncTarget_noHeightEstimates() { - when(localWorldState.isWorldStateAvailable(localBlockchain.getChainHeadHeader().getStateRoot())) + final BlockHeader chainHeadHeader = localBlockchain.getChainHeadHeader(); + when(localWorldState.isWorldStateAvailable( + chainHeadHeader.getStateRoot(), chainHeadHeader.getHash())) .thenReturn(true); final RespondingEthPeer bestPeer = EthProtocolManagerTestUtil.createPeer(ethProtocolManager, Difficulty.MAX_VALUE, 0); @@ -118,7 +123,9 @@ public class FullSyncTargetManagerTest { @Test public void shouldDisconnectPeerIfWorldStateIsUnavailableForCommonAncestor() { - when(localWorldState.isWorldStateAvailable(localBlockchain.getChainHeadHeader().getStateRoot())) + final BlockHeader chainHeadHeader = localBlockchain.getChainHeadHeader(); + when(localWorldState.isWorldStateAvailable( + chainHeadHeader.getStateRoot(), chainHeadHeader.getHash())) .thenReturn(false); final RespondingEthPeer bestPeer = EthProtocolManagerTestUtil.createPeer(ethProtocolManager, 20); @@ -133,7 +140,9 @@ public class FullSyncTargetManagerTest { @Test public void shouldAllowSyncTargetWhenIfWorldStateIsAvailableForCommonAncestor() { - when(localWorldState.isWorldStateAvailable(localBlockchain.getChainHeadHeader().getStateRoot())) + final BlockHeader chainHeadHeader = localBlockchain.getChainHeadHeader(); + when(localWorldState.isWorldStateAvailable( + chainHeadHeader.getStateRoot(), chainHeadHeader.getHash())) .thenReturn(true); final RespondingEthPeer bestPeer = EthProtocolManagerTestUtil.createPeer(ethProtocolManager, 20); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/worldstate/WorldStateDownloaderTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/worldstate/WorldStateDownloaderTest.java index 0bf4f51525..9436c664d2 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/worldstate/WorldStateDownloaderTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/worldstate/WorldStateDownloaderTest.java @@ -266,7 +266,7 @@ public class WorldStateDownloaderTest { // Check that all expected account data was downloaded final WorldStateArchive localWorldStateArchive = new DefaultWorldStateArchive(localStorage, createPreimageStorage()); - final WorldState localWorldState = localWorldStateArchive.get(stateRoot).get(); + final WorldState localWorldState = localWorldStateArchive.get(stateRoot, null).get(); assertThat(result).isDone(); assertAccountsMatch(localWorldState, accounts); } @@ -335,7 +335,7 @@ public class WorldStateDownloaderTest { // Check that all expected account data was downloaded final WorldStateArchive localWorldStateArchive = new DefaultWorldStateArchive(localStorage, createPreimageStorage()); - final WorldState localWorldState = localWorldStateArchive.get(stateRoot).get(); + final WorldState localWorldState = localWorldStateArchive.get(stateRoot, null).get(); assertThat(result).isDone(); assertAccountsMatch(localWorldState, accounts); } @@ -501,7 +501,7 @@ public class WorldStateDownloaderTest { // Check that all expected account data was downloaded final WorldStateArchive localWorldStateArchive = new DefaultWorldStateArchive(localStorage, createPreimageStorage()); - final WorldState localWorldState = localWorldStateArchive.get(stateRoot).get(); + final WorldState localWorldState = localWorldStateArchive.get(stateRoot, null).get(); assertThat(result).isDone(); assertAccountsMatch(localWorldState, accounts); } @@ -600,7 +600,7 @@ public class WorldStateDownloaderTest { // Check that all expected account data was downloaded final WorldStateArchive localWorldStateArchive = new DefaultWorldStateArchive(localStorage, createPreimageStorage()); - final WorldState localWorldState = localWorldStateArchive.get(stateRoot).get(); + final WorldState localWorldState = localWorldStateArchive.get(stateRoot, null).get(); assertThat(result).isDone(); assertAccountsMatch(localWorldState, accounts); } @@ -732,7 +732,7 @@ public class WorldStateDownloaderTest { assertThat(result).isDone(); final WorldStateArchive localWorldStateArchive = new DefaultWorldStateArchive(localStorage, createPreimageStorage()); - final WorldState localWorldState = localWorldStateArchive.get(stateRoot).get(); + final WorldState localWorldState = localWorldStateArchive.get(stateRoot, null).get(); assertAccountsMatch(localWorldState, accounts); } @@ -875,7 +875,7 @@ public class WorldStateDownloaderTest { } // Check that all expected account data was downloaded - final WorldState localWorldState = localWorldStateArchive.get(stateRoot).get(); + final WorldState localWorldState = localWorldStateArchive.get(stateRoot, null).get(); assertThat(result).isDone(); assertAccountsMatch(localWorldState, accounts); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolFactoryTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolFactoryTest.java index cb7948c076..1e5db3362f 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolFactoryTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolFactoryTest.java @@ -166,7 +166,7 @@ public class TransactionPoolFactoryTest { .thenReturn(ValidationResult.valid()); when(transactionValidator.validateForSender(any(), any(), any())) .thenReturn(ValidationResult.valid()); - when(worldStateArchive.get(any())).thenReturn(Optional.of(worldState)); + when(worldStateArchive.get(any(), any())).thenReturn(Optional.of(worldState)); final TransactionPool pool = TransactionPoolFactory.createTransactionPool(