Add BlockHash to WorldStateArchive query (#1732)

Bonsai tries will require storing state by block hash rather than by
state root.  To accommodate both forest mode and bonsai mode all state
queries will pass in both the block hash and state root.  This also
permits parallel forest/bonsai modes for private state with bonsai
public state.

Signed-off-by: Danno Ferrin <danno.ferrin@gmail.com>
pull/1753/head
Danno Ferrin 4 years ago committed by GitHub
parent ac82a075a2
commit fdc1c2d4bb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      besu/src/main/java/org/hyperledger/besu/chainimport/JsonBlockImporter.java
  2. 2
      besu/src/test/java/org/hyperledger/besu/services/BesuEventsImplTest.java
  3. 2
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthEstimateGas.java
  4. 2
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/processor/BlockReplay.java
  5. 4
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueries.java
  6. 4
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthEstimateGasTest.java
  7. 2
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/processor/TransactionTracerTest.java
  8. 17
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueriesTest.java
  9. 2
      ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreator.java
  10. 2
      ethereum/core/src/integration-test/java/org/hyperledger/besu/ethereum/mainnet/precompiles/privacy/PrivacyPrecompiledContractIntegrationTest.java
  11. 26
      ethereum/core/src/integration-test/java/org/hyperledger/besu/ethereum/vm/TraceTransactionIntegrationTest.java
  12. 19
      ethereum/core/src/integration-test/java/org/hyperledger/besu/ethereum/worldstate/PrunerIntegrationTest.java
  13. 4
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/MainnetBlockValidator.java
  14. 6
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/BonsaiWorldStateArchive.java
  15. 4
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/precompiles/privacy/OnChainPrivacyPrecompiledContract.java
  16. 2
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/precompiles/privacy/PrivacyPrecompiledContract.java
  17. 5
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/ChainHeadPrivateNonceProvider.java
  18. 2
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/PrivateGroupRehydrationBlockProcessor.java
  19. 5
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/PrivateStateRehydration.java
  20. 7
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/PrivateTransactionSimulator.java
  21. 2
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/PrivateWorldStateReader.java
  22. 5
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/storage/migration/PrivateStorageMigration.java
  23. 4
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulator.java
  24. 10
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/worldstate/DefaultWorldStateArchive.java
  25. 12
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/worldstate/WorldStateArchive.java
  26. 2
      ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/TestCodeExecutor.java
  27. 9
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/MainnetBlockValidatorTest.java
  28. 5
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/PrivacyBlockProcessorTest.java
  29. 2
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/precompiles/privacy/OnChainPrivacyPrecompiledContractTest.java
  30. 2
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/precompiles/privacy/PrivacyPrecompiledContractTest.java
  31. 9
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/ChainHeadPrivateNonceProviderTest.java
  32. 9
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/PrivateWorldStateReaderTest.java
  33. 11
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/storage/migration/PrivateStorageMigrationTest.java
  34. 6
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulatorTest.java
  35. 6
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/vm/BlockchainReferenceTestTools.java
  36. 12
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/worldstate/MarkSweepPrunerTest.java
  37. 2
      ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncTargetManager.java
  38. 2
      ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPool.java
  39. 17
      ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncTargetManagerTest.java
  40. 12
      ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/worldstate/WorldStateDownloaderTest.java
  41. 2
      ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolFactoryTest.java

@ -84,7 +84,7 @@ public class JsonBlockImporter {
controller controller
.getProtocolContext() .getProtocolContext()
.getWorldStateArchive() .getWorldStateArchive()
.get(parentHeader.getStateRoot()) .get(parentHeader.getStateRoot(), parentHeader.getHash())
.get(); .get();
final List<Transaction> transactions = final List<Transaction> transactions =
blockData.streamTransactions(worldState).collect(Collectors.toList()); blockData.streamTransactions(worldState).collect(Collectors.toList());

@ -125,7 +125,7 @@ public class BesuEventsImplTest {
.thenReturn(ValidationResult.valid()); .thenReturn(ValidationResult.valid());
when(mockTransactionValidator.validateForSender(any(), any(), any())) when(mockTransactionValidator.validateForSender(any(), any(), any()))
.thenReturn(ValidationResult.valid()); .thenReturn(ValidationResult.valid());
when(mockWorldStateArchive.get(any())).thenReturn(Optional.of(mockWorldState)); when(mockWorldStateArchive.get(any(), any())).thenReturn(Optional.of(mockWorldState));
blockBroadcaster = new BlockBroadcaster(mockEthContext); blockBroadcaster = new BlockBroadcaster(mockEthContext);
syncState = new SyncState(blockchain, mockEthPeers); syncState = new SyncState(blockchain, mockEthPeers);

@ -68,7 +68,7 @@ public class EthEstimateGas implements JsonRpcMethod {
} }
if (!blockchainQueries if (!blockchainQueries
.getWorldStateArchive() .getWorldStateArchive()
.isWorldStateAvailable(blockHeader.getStateRoot())) { .isWorldStateAvailable(blockHeader.getStateRoot(), blockHeader.getHash())) {
return errorResponse(requestContext, JsonRpcError.WORLD_STATE_UNAVAILABLE); return errorResponse(requestContext, JsonRpcError.WORLD_STATE_UNAVAILABLE);
} }

@ -146,7 +146,7 @@ public class BlockReplay {
return Optional.empty(); return Optional.empty();
} }
final MutableWorldState mutableWorldState = final MutableWorldState mutableWorldState =
worldStateArchive.getMutable(previous.getStateRoot()).orElse(null); worldStateArchive.getMutable(previous.getStateRoot(), previous.getHash()).orElse(null);
if (mutableWorldState == null) { if (mutableWorldState == null) {
return Optional.empty(); return Optional.empty();
} }

@ -730,7 +730,9 @@ public class BlockchainQueries {
*/ */
public Optional<MutableWorldState> getWorldState(final long blockNumber) { public Optional<MutableWorldState> getWorldState(final long blockNumber) {
final Optional<BlockHeader> header = blockchain.getBlockHeader(blockNumber); final Optional<BlockHeader> header = blockchain.getBlockHeader(blockNumber);
return header.map(BlockHeader::getStateRoot).flatMap(worldStateArchive::getMutable); return header.flatMap(
blockHeader ->
worldStateArchive.getMutable(blockHeader.getStateRoot(), blockHeader.getHash()));
} }
public Optional<Long> gasPrice() { public Optional<Long> gasPrice() {

@ -76,7 +76,7 @@ public class EthEstimateGasTest {
when(blockchain.getBlockHeader(eq(1L))).thenReturn(Optional.of(blockHeader)); when(blockchain.getBlockHeader(eq(1L))).thenReturn(Optional.of(blockHeader));
when(blockHeader.getGasLimit()).thenReturn(Long.MAX_VALUE); when(blockHeader.getGasLimit()).thenReturn(Long.MAX_VALUE);
when(blockHeader.getNumber()).thenReturn(1L); when(blockHeader.getNumber()).thenReturn(1L);
when(worldStateArchive.isWorldStateAvailable(any())).thenReturn(true); when(worldStateArchive.isWorldStateAvailable(any(), any())).thenReturn(true);
method = new EthEstimateGas(blockchainQueries, transactionSimulator); method = new EthEstimateGas(blockchainQueries, transactionSimulator);
} }
@ -223,7 +223,7 @@ public class EthEstimateGasTest {
@Test @Test
public void shouldReturnErrorWhenWorldStateIsNotAvailable() { public void shouldReturnErrorWhenWorldStateIsNotAvailable() {
when(worldStateArchive.isWorldStateAvailable(any())).thenReturn(false); when(worldStateArchive.isWorldStateAvailable(any(), any())).thenReturn(false);
final JsonRpcRequestContext request = final JsonRpcRequestContext request =
ethEstimateGasRequest(defaultLegacyTransactionCallParameter(Wei.ZERO)); ethEstimateGasRequest(defaultLegacyTransactionCallParameter(Wei.ZERO));
mockTransientProcessorResultGasEstimate(1L, false, false); mockTransientProcessorResultGasEstimate(1L, false, false);

@ -110,7 +110,7 @@ public class TransactionTracerTest {
when(blockHeader.getHash()).thenReturn(blockHash); when(blockHeader.getHash()).thenReturn(blockHash);
when(blockHeader.getParentHash()).thenReturn(previousBlockHash); when(blockHeader.getParentHash()).thenReturn(previousBlockHash);
when(previousBlockHeader.getStateRoot()).thenReturn(Hash.ZERO); 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(protocolSchedule.getByBlockNumber(12)).thenReturn(protocolSpec);
when(protocolSpec.getTransactionProcessor()).thenReturn(transactionProcessor); when(protocolSpec.getTransactionProcessor()).thenReturn(transactionProcessor);
when(protocolSpec.getMiningBeneficiaryCalculator()).thenReturn(BlockHeader::getCoinbase); when(protocolSpec.getMiningBeneficiaryCalculator()).thenReturn(BlockHeader::getCoinbase);

@ -204,8 +204,10 @@ public class BlockchainQueriesTest {
final BlockchainWithData data = setupBlockchain(3, addresses, storageKeys); final BlockchainWithData data = setupBlockchain(3, addresses, storageKeys);
final BlockchainQueries queries = data.blockchainQueries; final BlockchainQueries queries = data.blockchainQueries;
final Hash latestStateRoot0 = data.blockData.get(2).block.getHeader().getStateRoot(); final BlockHeader blockHeader0 = data.blockData.get(2).block.getHeader();
final WorldState worldState0 = data.worldStateArchive.get(latestStateRoot0).get(); final Hash latestStateRoot0 = blockHeader0.getStateRoot();
final WorldState worldState0 =
data.worldStateArchive.get(latestStateRoot0, blockHeader0.getHash()).get();
addresses.forEach( addresses.forEach(
address -> address ->
storageKeys.forEach( storageKeys.forEach(
@ -215,8 +217,10 @@ public class BlockchainQueriesTest {
assertThat(result).contains(actualAccount0.getStorageValue(storageKey)); assertThat(result).contains(actualAccount0.getStorageValue(storageKey));
})); }));
final Hash latestStateRoot1 = data.blockData.get(1).block.getHeader().getStateRoot(); final BlockHeader header1 = data.blockData.get(1).block.getHeader();
final WorldState worldState1 = data.worldStateArchive.get(latestStateRoot1).get(); final Hash latestStateRoot1 = header1.getStateRoot();
final WorldState worldState1 =
data.worldStateArchive.get(latestStateRoot1, header1.getHash()).get();
addresses.forEach( addresses.forEach(
address -> address ->
storageKeys.forEach( storageKeys.forEach(
@ -236,8 +240,9 @@ public class BlockchainQueriesTest {
for (int i = 0; i < blockCount; i++) { for (int i = 0; i < blockCount; i++) {
final long curBlockNumber = i; final long curBlockNumber = i;
final Hash stateRoot = data.blockData.get(i).block.getHeader().getStateRoot(); final BlockHeader header = data.blockData.get(i).block.getHeader();
final WorldState worldState = data.worldStateArchive.get(stateRoot).get(); final Hash stateRoot = header.getStateRoot();
final WorldState worldState = data.worldStateArchive.get(stateRoot, header.getHash()).get();
assertThat(addresses).isNotEmpty(); assertThat(addresses).isNotEmpty();
addresses.forEach( addresses.forEach(

@ -240,7 +240,7 @@ public abstract class AbstractBlockCreator implements AsyncBlockCreator {
final MutableWorldState worldState = final MutableWorldState worldState =
protocolContext protocolContext
.getWorldStateArchive() .getWorldStateArchive()
.getMutable(parentStateRoot) .getMutable(parentStateRoot, parentHeader.getHash())
.orElseThrow( .orElseThrow(
() -> { () -> {
LOG.info("Unable to create block because world state is not available"); LOG.info("Unable to create block because world state is not available");

@ -147,7 +147,7 @@ public class PrivacyPrecompiledContractIntegrationTest {
final MutableWorldState mutableWorldState = mock(MutableWorldState.class); final MutableWorldState mutableWorldState = mock(MutableWorldState.class);
when(mutableWorldState.updater()).thenReturn(mock(WorldUpdater.class)); when(mutableWorldState.updater()).thenReturn(mock(WorldUpdater.class));
when(worldStateArchive.getMutable()).thenReturn(mutableWorldState); 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); privateStateStorage = mock(PrivateStateStorage.class);
final PrivateStateStorage.Updater storageUpdater = mock(PrivateStateStorage.Updater.class); final PrivateStateStorage.Updater storageUpdater = mock(PrivateStateStorage.Updater.class);

@ -21,6 +21,7 @@ import org.hyperledger.besu.crypto.SECP256K1.KeyPair;
import org.hyperledger.besu.ethereum.chain.MutableBlockchain; import org.hyperledger.besu.ethereum.chain.MutableBlockchain;
import org.hyperledger.besu.ethereum.core.Account; import org.hyperledger.besu.ethereum.core.Account;
import org.hyperledger.besu.ethereum.core.Block; 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.ExecutionContextTestFixture;
import org.hyperledger.besu.ethereum.core.Gas; import org.hyperledger.besu.ethereum.core.Gas;
import org.hyperledger.besu.ethereum.core.MutableWorldState; import org.hyperledger.besu.ethereum.core.MutableWorldState;
@ -86,16 +87,19 @@ public class TraceTransactionIntegrationTest {
.value(Wei.ZERO) .value(Wei.ZERO)
.signAndBuild(keyPair); .signAndBuild(keyPair);
final BlockHeader genesisBlockHeader = genesisBlock.getHeader();
final MutableWorldState worldState = final MutableWorldState worldState =
worldStateArchive.getMutable(genesisBlock.getHeader().getStateRoot()).get(); worldStateArchive
.getMutable(genesisBlockHeader.getStateRoot(), genesisBlockHeader.getHash())
.get();
final WorldUpdater createTransactionUpdater = worldState.updater(); final WorldUpdater createTransactionUpdater = worldState.updater();
TransactionProcessingResult result = TransactionProcessingResult result =
transactionProcessor.processTransaction( transactionProcessor.processTransaction(
blockchain, blockchain,
createTransactionUpdater, createTransactionUpdater,
genesisBlock.getHeader(), genesisBlockHeader,
createTransaction, createTransaction,
genesisBlock.getHeader().getCoinbase(), genesisBlockHeader.getCoinbase(),
blockHashLookup, blockHashLookup,
false, false,
TransactionValidationParams.blockReplay()); TransactionValidationParams.blockReplay());
@ -125,9 +129,9 @@ public class TraceTransactionIntegrationTest {
transactionProcessor.processTransaction( transactionProcessor.processTransaction(
blockchain, blockchain,
storeUpdater, storeUpdater,
genesisBlock.getHeader(), genesisBlockHeader,
executeTransaction, executeTransaction,
genesisBlock.getHeader().getCoinbase(), genesisBlockHeader.getCoinbase(),
tracer, tracer,
blockHashLookup, blockHashLookup,
false); false);
@ -159,14 +163,18 @@ public class TraceTransactionIntegrationTest {
final Transaction transaction = final Transaction transaction =
Transaction.readFrom( Transaction.readFrom(
new BytesValueRLPInput(Bytes.fromHexString(CONTRACT_CREATION_TX), false)); new BytesValueRLPInput(Bytes.fromHexString(CONTRACT_CREATION_TX), false));
BlockHeader genesisBlockHeader = genesisBlock.getHeader();
transactionProcessor.processTransaction( transactionProcessor.processTransaction(
blockchain, blockchain,
worldStateArchive.getMutable(genesisBlock.getHeader().getStateRoot()).get().updater(), worldStateArchive
genesisBlock.getHeader(), .getMutable(genesisBlockHeader.getStateRoot(), genesisBlockHeader.getHash())
.get()
.updater(),
genesisBlockHeader,
transaction, transaction,
genesisBlock.getHeader().getCoinbase(), genesisBlockHeader.getCoinbase(),
tracer, tracer,
new BlockHashLookup(genesisBlock.getHeader(), blockchain), new BlockHashLookup(genesisBlockHeader, blockchain),
false); false);
final int expectedDepth = 0; // Reference impl returned 1. Why the difference? final int expectedDepth = 0; // Reference impl returned 1. Why the difference?

@ -137,9 +137,11 @@ public class PrunerIntegrationTest {
// Assert that blocks from mark point onward are still accessible // Assert that blocks from mark point onward are still accessible
for (int i = fullyMarkedBlockNum; i <= blockchain.getChainHeadBlockNumber(); i++) { for (int i = fullyMarkedBlockNum; i <= blockchain.getChainHeadBlockNumber(); i++) {
final Hash stateRoot = blockchain.getBlockHeader(i).get().getStateRoot(); final BlockHeader blockHeader = blockchain.getBlockHeader(i).get();
assertThat(worldStateArchive.get(stateRoot)).isPresent(); final Hash stateRoot = blockHeader.getStateRoot();
final WorldState markedState = worldStateArchive.get(stateRoot).get(); assertThat(worldStateArchive.get(stateRoot, blockHeader.getHash())).isPresent();
final WorldState markedState =
worldStateArchive.get(stateRoot, blockHeader.getHash()).get();
// Traverse accounts and make sure all are accessible // Traverse accounts and make sure all are accessible
final int expectedAccounts = accountsPerBlock * i; final int expectedAccounts = accountsPerBlock * i;
final long accounts = final long accounts =
@ -155,7 +157,8 @@ public class PrunerIntegrationTest {
for (int i = 0; i < fullyMarkedBlockNum; i++) { for (int i = 0; i < fullyMarkedBlockNum; i++) {
final BlockHeader curHeader = blockchain.getBlockHeader(i).get(); final BlockHeader curHeader = blockchain.getBlockHeader(i).get();
if (!curHeader.getStateRoot().equals(Hash.EMPTY_TRIE_HASH)) { 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) { private void generateBlockchainData(final int numBlocks, final int numAccounts) {
Block parentBlock = blockchain.getChainHeadBlock(); Block parentBlock = blockchain.getChainHeadBlock();
for (int i = 0; i < numBlocks; i++) { for (int i = 0; i < numBlocks; i++) {
final BlockHeader parentHeader = parentBlock.getHeader();
final Hash parentHash = parentBlock.getHash();
final MutableWorldState worldState = final MutableWorldState worldState =
worldStateArchive.getMutable(parentBlock.getHeader().getStateRoot()).get(); worldStateArchive.getMutable(parentHeader.getStateRoot(), parentHash).get();
gen.createRandomContractAccountsWithNonEmptyStorage(worldState, numAccounts); gen.createRandomContractAccountsWithNonEmptyStorage(worldState, numAccounts);
final Hash stateRoot = worldState.rootHash(); final Hash stateRoot = worldState.rootHash();
@ -181,8 +186,8 @@ public class PrunerIntegrationTest {
gen.block( gen.block(
BlockOptions.create() BlockOptions.create()
.setStateRoot(stateRoot) .setStateRoot(stateRoot)
.setBlockNumber(parentBlock.getHeader().getNumber() + 1L) .setBlockNumber(parentHeader.getNumber() + 1L)
.setParentHash(parentBlock.getHash())); .setParentHash(parentHash));
final List<TransactionReceipt> receipts = gen.receipts(block); final List<TransactionReceipt> receipts = gen.receipts(block);
blockchain.appendBlock(block, receipts); blockchain.appendBlock(block, receipts);
parentBlock = block; parentBlock = block;

@ -83,7 +83,9 @@ public class MainnetBlockValidator implements BlockValidator {
final MutableBlockchain blockchain = context.getBlockchain(); final MutableBlockchain blockchain = context.getBlockchain();
final Optional<MutableWorldState> maybeWorldState = final Optional<MutableWorldState> maybeWorldState =
context.getWorldStateArchive().getMutable(parentHeader.getStateRoot()); context
.getWorldStateArchive()
.getMutable(parentHeader.getStateRoot(), parentHeader.getHash());
if (!maybeWorldState.isPresent()) { if (!maybeWorldState.isPresent()) {
LOG.debug( LOG.debug(
"Unable to process block {} because parent world state {} is not available", "Unable to process block {} because parent world state {} is not available",

@ -53,7 +53,7 @@ public class BonsaiWorldStateArchive implements WorldStateArchive {
} }
@Override @Override
public Optional<WorldState> get(final Hash rootHash) { public Optional<WorldState> get(final Hash rootHash, final Hash blockHash) {
if (layeredWorldStates.containsKey(rootHash)) { if (layeredWorldStates.containsKey(rootHash)) {
return Optional.of(layeredWorldStates.get(rootHash)); return Optional.of(layeredWorldStates.get(rootHash));
} else if (rootHash.equals(persistedState.rootHash())) { } else if (rootHash.equals(persistedState.rootHash())) {
@ -68,13 +68,13 @@ public class BonsaiWorldStateArchive implements WorldStateArchive {
} }
@Override @Override
public boolean isWorldStateAvailable(final Hash rootHash) { public boolean isWorldStateAvailable(final Hash rootHash, final Hash blockHash) {
return layeredWorldStates.containsKey(rootHash) return layeredWorldStates.containsKey(rootHash)
|| persistedState.rootHash().equals(rootHash) /* || check disk storage */; || persistedState.rootHash().equals(rootHash) /* || check disk storage */;
} }
@Override @Override
public Optional<MutableWorldState> getMutable(final Hash rootHash) { public Optional<MutableWorldState> getMutable(final Hash rootHash, final Hash blockHash) {
if (rootHash.equals(persistedState.rootHash())) { if (rootHash.equals(persistedState.rootHash())) {
return Optional.of(persistedState); return Optional.of(persistedState);
} else { } else {

@ -147,7 +147,7 @@ public class OnChainPrivacyPrecompiledContract extends PrivacyPrecompiledContrac
privateStateRootResolver.resolveLastStateRoot(privacyGroupId, privateMetadataUpdater); privateStateRootResolver.resolveLastStateRoot(privacyGroupId, privateMetadataUpdater);
final MutableWorldState disposablePrivateState = final MutableWorldState disposablePrivateState =
privateWorldStateArchive.getMutable(lastRootHash).get(); privateWorldStateArchive.getMutable(lastRootHash, null).get();
final WorldUpdater privateWorldStateUpdater = disposablePrivateState.updater(); final WorldUpdater privateWorldStateUpdater = disposablePrivateState.updater();
@ -398,7 +398,7 @@ public class OnChainPrivacyPrecompiledContract extends PrivacyPrecompiledContrac
// privateTransactionProcessor.processTransaction(...) commits the state if the process was // privateTransactionProcessor.processTransaction(...) commits the state if the process was
// successful before it returns // successful before it returns
final MutableWorldState localMutableState = final MutableWorldState localMutableState =
privateWorldStateArchive.getMutable(disposablePrivateState.rootHash()).get(); privateWorldStateArchive.getMutable(disposablePrivateState.rootHash(), null).get();
final WorldUpdater updater = localMutableState.updater(); final WorldUpdater updater = localMutableState.updater();
return privateTransactionProcessor.processTransaction( return privateTransactionProcessor.processTransaction(

@ -158,7 +158,7 @@ public class PrivacyPrecompiledContract extends AbstractPrecompiledContract {
privateStateRootResolver.resolveLastStateRoot(privacyGroupId, privateMetadataUpdater); privateStateRootResolver.resolveLastStateRoot(privacyGroupId, privateMetadataUpdater);
final MutableWorldState disposablePrivateState = final MutableWorldState disposablePrivateState =
privateWorldStateArchive.getMutable(lastRootHash).get(); privateWorldStateArchive.getMutable(lastRootHash, null).get();
final WorldUpdater privateWorldStateUpdater = disposablePrivateState.updater(); final WorldUpdater privateWorldStateUpdater = disposablePrivateState.updater();

@ -40,10 +40,11 @@ public class ChainHeadPrivateNonceProvider implements PrivateNonceProvider {
@Override @Override
public long getNonce(final Address sender, final Bytes32 privacyGroupId) { public long getNonce(final Address sender, final Bytes32 privacyGroupId) {
final BlockHeader chainHeadHeader = blockchain.getChainHeadHeader(); final BlockHeader chainHeadHeader = blockchain.getChainHeadHeader();
Hash chainHeadHash = chainHeadHeader.getHash();
final Hash stateRoot = final Hash stateRoot =
privateStateRootResolver.resolveLastStateRoot(privacyGroupId, chainHeadHeader.getHash()); privateStateRootResolver.resolveLastStateRoot(privacyGroupId, chainHeadHash);
return privateWorldStateArchive return privateWorldStateArchive
.get(stateRoot) .get(stateRoot, chainHeadHash)
.map( .map(
privateWorldState -> { privateWorldState -> {
final Account account = privateWorldState.get(sender); final Account account = privateWorldState.get(sender);

@ -121,7 +121,7 @@ public class PrivateGroupRehydrationBlockProcessor {
privateStateRootResolver.resolveLastStateRoot(privacyGroupId, metadataUpdater); privateStateRootResolver.resolveLastStateRoot(privacyGroupId, metadataUpdater);
final MutableWorldState disposablePrivateState = final MutableWorldState disposablePrivateState =
privateWorldStateArchive.getMutable(lastRootHash).get(); privateWorldStateArchive.getMutable(lastRootHash, null).get();
final WorldUpdater privateStateUpdater = disposablePrivateState.updater(); final WorldUpdater privateStateUpdater = disposablePrivateState.updater();
maybeInjectDefaultManagementAndProxy( maybeInjectDefaultManagementAndProxy(
lastRootHash, disposablePrivateState, privateStateUpdater); lastRootHash, disposablePrivateState, privateStateUpdater);

@ -150,8 +150,9 @@ public class PrivateStateRehydration {
final MutableWorldState publicWorldState = final MutableWorldState publicWorldState =
blockchain blockchain
.getBlockHeader(blockHeader.getParentHash()) .getBlockHeader(blockHeader.getParentHash())
.map(BlockHeader::getStateRoot) .flatMap(
.flatMap(publicWorldStateArchive::getMutable) header ->
publicWorldStateArchive.getMutable(header.getStateRoot(), header.getHash()))
.orElseThrow(RuntimeException::new); .orElseThrow(RuntimeException::new);
privateGroupRehydrationBlockProcessor.processBlock( privateGroupRehydrationBlockProcessor.processBlock(

@ -94,7 +94,7 @@ public class PrivateTransactionSimulator {
} }
final MutableWorldState publicWorldState = final MutableWorldState publicWorldState =
worldStateArchive.getMutable(header.getStateRoot()).orElse(null); worldStateArchive.getMutable(header.getStateRoot(), header.getHash()).orElse(null);
if (publicWorldState == null) { if (publicWorldState == null) {
return Optional.empty(); return Optional.empty();
} }
@ -105,7 +105,10 @@ public class PrivateTransactionSimulator {
privateStateRootResolver.resolveLastStateRoot(privacyGroupId, header.getHash()); privateStateRootResolver.resolveLastStateRoot(privacyGroupId, header.getHash());
final MutableWorldState disposablePrivateState = final MutableWorldState disposablePrivateState =
privacyParameters.getPrivateWorldStateArchive().getMutable(lastRootHash).get(); privacyParameters
.getPrivateWorldStateArchive()
.getMutable(lastRootHash, header.getHash())
.get();
final PrivateTransaction transaction = final PrivateTransaction transaction =
getPrivateTransaction(callParams, header, privacyGroupId, disposablePrivateState); getPrivateTransaction(callParams, header, privacyGroupId, disposablePrivateState);

@ -50,7 +50,7 @@ public class PrivateWorldStateReader {
Bytes32.wrap(Bytes.fromBase64String(privacyGroupId)), blockHash); Bytes32.wrap(Bytes.fromBase64String(privacyGroupId)), blockHash);
return privateWorldStateArchive return privateWorldStateArchive
.get(latestStateRoot) .get(latestStateRoot, blockHash)
.flatMap(worldState -> Optional.ofNullable(worldState.get(contractAddress))) .flatMap(worldState -> Optional.ofNullable(worldState.get(contractAddress)))
.flatMap(account -> Optional.ofNullable(account.getCode())); .flatMap(account -> Optional.ofNullable(account.getCode()));
} }

@ -100,8 +100,9 @@ public class PrivateStorageMigration {
final MutableWorldState publicWorldState = final MutableWorldState publicWorldState =
blockchain blockchain
.getBlockHeader(blockHeader.getParentHash()) .getBlockHeader(blockHeader.getParentHash())
.map(BlockHeader::getStateRoot) .flatMap(
.flatMap(publicWorldStateArchive::getMutable) header ->
publicWorldStateArchive.getMutable(header.getStateRoot(), header.getHash()))
.orElseThrow(PrivateStorageMigrationException::new); .orElseThrow(PrivateStorageMigrationException::new);
final List<Transaction> transactionsToProcess = final List<Transaction> transactionsToProcess =

@ -113,7 +113,7 @@ public class TransactionSimulator {
return Optional.empty(); return Optional.empty();
} }
final MutableWorldState worldState = final MutableWorldState worldState =
worldStateArchive.getMutable(header.getStateRoot()).orElse(null); worldStateArchive.getMutable(header.getStateRoot(), header.getHash()).orElse(null);
if (worldState == null) { if (worldState == null) {
return Optional.empty(); return Optional.empty();
} }
@ -179,7 +179,7 @@ public class TransactionSimulator {
} }
final MutableWorldState worldState = final MutableWorldState worldState =
worldStateArchive.getMutable(header.getStateRoot()).orElse(null); worldStateArchive.getMutable(header.getStateRoot(), header.getHash()).orElse(null);
if (worldState == null) { if (worldState == null) {
return Optional.empty(); return Optional.empty();
} }

@ -44,17 +44,17 @@ public class DefaultWorldStateArchive implements WorldStateArchive {
} }
@Override @Override
public Optional<WorldState> get(final Hash rootHash) { public Optional<WorldState> get(final Hash rootHash, final Hash blockHash) {
return getMutable(rootHash).map(state -> state); return getMutable(rootHash, blockHash).map(state -> state);
} }
@Override @Override
public boolean isWorldStateAvailable(final Hash rootHash) { public boolean isWorldStateAvailable(final Hash rootHash, final Hash blockHash) {
return worldStateStorage.isWorldStateAvailable(rootHash); return worldStateStorage.isWorldStateAvailable(rootHash);
} }
@Override @Override
public Optional<MutableWorldState> getMutable(final Hash rootHash) { public Optional<MutableWorldState> getMutable(final Hash rootHash, final Hash blockHash) {
if (!worldStateStorage.isWorldStateAvailable(rootHash)) { if (!worldStateStorage.isWorldStateAvailable(rootHash)) {
return Optional.empty(); return Optional.empty();
} }
@ -63,7 +63,7 @@ public class DefaultWorldStateArchive implements WorldStateArchive {
@Override @Override
public MutableWorldState getMutable() { public MutableWorldState getMutable() {
return getMutable(EMPTY_ROOT_HASH).get(); return getMutable(EMPTY_ROOT_HASH, null).get();
} }
@Override @Override

@ -30,18 +30,16 @@ import org.apache.tuweni.units.bigints.UInt256;
public interface WorldStateArchive { public interface WorldStateArchive {
Hash EMPTY_ROOT_HASH = Hash.wrap(MerklePatriciaTrie.EMPTY_TRIE_NODE_HASH); Hash EMPTY_ROOT_HASH = Hash.wrap(MerklePatriciaTrie.EMPTY_TRIE_NODE_HASH);
Optional<WorldState> get(final Hash rootHash); Optional<WorldState> get(Hash rootHash, Hash blockHash);
boolean isWorldStateAvailable(final Hash rootHash); boolean isWorldStateAvailable(Hash rootHash, Hash blockHash);
Optional<MutableWorldState> getMutable(final Hash rootHash); Optional<MutableWorldState> getMutable(Hash rootHash, Hash blockHash);
MutableWorldState getMutable(); MutableWorldState getMutable();
Optional<Bytes> getNodeData(final Hash hash); Optional<Bytes> getNodeData(Hash hash);
Optional<WorldStateProof> getAccountProof( Optional<WorldStateProof> getAccountProof(
final Hash worldStateRoot, Hash worldStateRoot, Address accountAddress, List<UInt256> accountStorageKeys);
final Address accountAddress,
final List<UInt256> accountStorageKeys);
} }

@ -101,6 +101,6 @@ public class TestCodeExecutor {
accountSetup.accept(senderAccount); accountSetup.accept(senderAccount);
worldState.commit(); worldState.commit();
initialWorldState.persist(null); initialWorldState.persist(null);
return stateArchive.getMutable(initialWorldState.rootHash()).get().updater(); return stateArchive.getMutable(initialWorldState.rootHash(), null).get().updater();
} }
} }

@ -115,7 +115,8 @@ public class MainnetBlockValidatorTest {
eq(protocolContext), eq(protocolContext),
eq(HeaderValidationMode.DETACHED_ONLY))) eq(HeaderValidationMode.DETACHED_ONLY)))
.thenReturn(true); .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); assertThat(badBlockManager.getBadBlocks().size()).isEqualTo(0);
mainnetBlockValidator.validateAndProcessBlock( mainnetBlockValidator.validateAndProcessBlock(
@ -136,7 +137,7 @@ public class MainnetBlockValidatorTest {
eq(protocolContext), eq(protocolContext),
eq(HeaderValidationMode.DETACHED_ONLY))) eq(HeaderValidationMode.DETACHED_ONLY)))
.thenReturn(true); .thenReturn(true);
when(worldStateArchive.getMutable(any(Hash.class))) when(worldStateArchive.getMutable(any(Hash.class), any(Hash.class)))
.thenReturn(Optional.of(mock(MutableWorldState.class))); .thenReturn(Optional.of(mock(MutableWorldState.class)));
when(blockProcessor.processBlock(eq(blockchain), any(MutableWorldState.class), eq(badBlock))) when(blockProcessor.processBlock(eq(blockchain), any(MutableWorldState.class), eq(badBlock)))
.thenReturn( .thenReturn(
@ -171,7 +172,7 @@ public class MainnetBlockValidatorTest {
eq(protocolContext), eq(protocolContext),
eq(HeaderValidationMode.DETACHED_ONLY))) eq(HeaderValidationMode.DETACHED_ONLY)))
.thenReturn(true); .thenReturn(true);
when(worldStateArchive.getMutable(any(Hash.class))) when(worldStateArchive.getMutable(any(Hash.class), any(Hash.class)))
.thenReturn(Optional.of(mock(MutableWorldState.class))); .thenReturn(Optional.of(mock(MutableWorldState.class)));
when(blockProcessor.processBlock(eq(blockchain), any(MutableWorldState.class), eq(badBlock))) when(blockProcessor.processBlock(eq(blockchain), any(MutableWorldState.class), eq(badBlock)))
.thenReturn( .thenReturn(
@ -206,7 +207,7 @@ public class MainnetBlockValidatorTest {
eq(protocolContext), eq(protocolContext),
eq(HeaderValidationMode.DETACHED_ONLY))) eq(HeaderValidationMode.DETACHED_ONLY)))
.thenReturn(true); .thenReturn(true);
when(worldStateArchive.getMutable(any(Hash.class))) when(worldStateArchive.getMutable(any(Hash.class), any(Hash.class)))
.thenReturn(Optional.of(mock(MutableWorldState.class))); .thenReturn(Optional.of(mock(MutableWorldState.class)));
when(blockProcessor.processBlock(eq(blockchain), any(MutableWorldState.class), eq(badBlock))) when(blockProcessor.processBlock(eq(blockchain), any(MutableWorldState.class), eq(badBlock)))
.thenReturn( .thenReturn(

@ -150,9 +150,10 @@ public class PrivacyBlockProcessorTest {
when(blockchain.getBlockHeader(any())).thenReturn(Optional.of(firstBlock.getHeader())); when(blockchain.getBlockHeader(any())).thenReturn(Optional.of(firstBlock.getHeader()));
final ProtocolSpec protocolSpec = mockProtocolSpec(); final ProtocolSpec protocolSpec = mockProtocolSpec();
when(protocolSchedule.getByBlockNumber(anyLong())).thenReturn(protocolSpec); 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(); final MutableWorldState mockPrivateStateArchive = mockPrivateStateArchive();
when(privateWorldStateArchive.getMutable(any())) when(privateWorldStateArchive.getMutable(any(), any()))
.thenReturn(Optional.of(mockPrivateStateArchive)); .thenReturn(Optional.of(mockPrivateStateArchive));
final PrivacyGroupHeadBlockMap expected = final PrivacyGroupHeadBlockMap expected =

@ -107,7 +107,7 @@ public class OnChainPrivacyPrecompiledContractTest {
final MutableWorldState mutableWorldState = mock(MutableWorldState.class); final MutableWorldState mutableWorldState = mock(MutableWorldState.class);
when(mutableWorldState.updater()).thenReturn(mock(WorldUpdater.class)); when(mutableWorldState.updater()).thenReturn(mock(WorldUpdater.class));
when(worldStateArchive.getMutable()).thenReturn(mutableWorldState); 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); final PrivateStateStorage.Updater storageUpdater = mock(PrivateStateStorage.Updater.class);
when(privateStateStorage.getPrivacyGroupHeadBlockMap(any())) when(privateStateStorage.getPrivacyGroupHeadBlockMap(any()))

@ -110,7 +110,7 @@ public class PrivacyPrecompiledContractTest {
final MutableWorldState mutableWorldState = mock(MutableWorldState.class); final MutableWorldState mutableWorldState = mock(MutableWorldState.class);
when(mutableWorldState.updater()).thenReturn(mock(WorldUpdater.class)); when(mutableWorldState.updater()).thenReturn(mock(WorldUpdater.class));
when(worldStateArchive.getMutable()).thenReturn(mutableWorldState); 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()) when(privateMetadataUpdater.getPrivacyGroupHeadBlockMap())
.thenReturn(PrivacyGroupHeadBlockMap.empty()); .thenReturn(PrivacyGroupHeadBlockMap.empty());

@ -67,7 +67,8 @@ public class ChainHeadPrivateNonceProviderTest {
public void determineNonceForPrivacyGroupRequestWhenPrivateStateDoesNotExist() { public void determineNonceForPrivacyGroupRequestWhenPrivateStateDoesNotExist() {
when(privateStateRootResolver.resolveLastStateRoot(any(Bytes32.class), any(Hash.class))) when(privateStateRootResolver.resolveLastStateRoot(any(Bytes32.class), any(Hash.class)))
.thenReturn(Hash.ZERO); .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); 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(worldState.get(any(Address.class))).thenReturn(account);
when(privateStateRootResolver.resolveLastStateRoot(any(Bytes32.class), any(Hash.class))) when(privateStateRootResolver.resolveLastStateRoot(any(Bytes32.class), any(Hash.class)))
.thenReturn(Hash.ZERO); .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); final long nonce = privateNonceProvider.getNonce(ADDRESS, PRIVACY_GROUP_ID);
@ -91,7 +93,8 @@ public class ChainHeadPrivateNonceProviderTest {
public void determineNonceForPrivacyGroupRequestWhenAccountDoesNotExist() { public void determineNonceForPrivacyGroupRequestWhenAccountDoesNotExist() {
when(privateStateRootResolver.resolveLastStateRoot(any(Bytes32.class), any(Hash.class))) when(privateStateRootResolver.resolveLastStateRoot(any(Bytes32.class), any(Hash.class)))
.thenReturn(Hash.ZERO); .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); when(account.getNonce()).thenReturn(4L);
final long nonce = privateNonceProvider.getNonce(ADDRESS, PRIVACY_GROUP_ID); final long nonce = privateNonceProvider.getNonce(ADDRESS, PRIVACY_GROUP_ID);

@ -17,6 +17,7 @@ package org.hyperledger.besu.ethereum.privacy;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.hyperledger.besu.ethereum.core.PrivateTransactionDataFixture.generatePrivateBlockMetadata; 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.ArgumentMatchers.eq;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
@ -81,7 +82,7 @@ public class PrivateWorldStateReaderTest {
when(privateStateRootResolver.resolveLastStateRoot(eq(privacyGroupBytes), eq(blockHash))) when(privateStateRootResolver.resolveLastStateRoot(eq(privacyGroupBytes), eq(blockHash)))
.thenReturn(stateRootHash); .thenReturn(stateRootHash);
when(privateWorldStateArchive.get(eq(stateRootHash))).thenReturn(Optional.empty()); when(privateWorldStateArchive.get(eq(stateRootHash), any())).thenReturn(Optional.empty());
final Optional<Bytes> maybecontractCode = final Optional<Bytes> maybecontractCode =
privateWorldStateReader.getContractCode(PRIVACY_GROUP_ID, blockHash, contractAddress); privateWorldStateReader.getContractCode(PRIVACY_GROUP_ID, blockHash, contractAddress);
@ -96,7 +97,7 @@ public class PrivateWorldStateReaderTest {
when(privateStateRootResolver.resolveLastStateRoot(eq(privacyGroupBytes), eq(blockHash))) when(privateStateRootResolver.resolveLastStateRoot(eq(privacyGroupBytes), eq(blockHash)))
.thenReturn(stateRootHash); .thenReturn(stateRootHash);
when(privateWorldStateArchive.get(eq(stateRootHash))) when(privateWorldStateArchive.get(eq(stateRootHash), any()))
.thenReturn(Optional.of(privateWorldState)); .thenReturn(Optional.of(privateWorldState));
when(privateWorldState.get(eq(contractAddress))).thenReturn(null); when(privateWorldState.get(eq(contractAddress))).thenReturn(null);
@ -113,7 +114,7 @@ public class PrivateWorldStateReaderTest {
when(privateStateRootResolver.resolveLastStateRoot(eq(privacyGroupBytes), eq(blockHash))) when(privateStateRootResolver.resolveLastStateRoot(eq(privacyGroupBytes), eq(blockHash)))
.thenReturn(stateRootHash); .thenReturn(stateRootHash);
when(privateWorldStateArchive.get(eq(stateRootHash))) when(privateWorldStateArchive.get(eq(stateRootHash), any()))
.thenReturn(Optional.of(privateWorldState)); .thenReturn(Optional.of(privateWorldState));
when(privateWorldState.get(eq(contractAddress))).thenReturn(contractAccount); when(privateWorldState.get(eq(contractAddress))).thenReturn(contractAccount);
when(contractAccount.getCode()).thenReturn(null); when(contractAccount.getCode()).thenReturn(null);
@ -128,7 +129,7 @@ public class PrivateWorldStateReaderTest {
public void existingAccountWithCodeReturnsExpectedBytes() { public void existingAccountWithCodeReturnsExpectedBytes() {
when(privateStateRootResolver.resolveLastStateRoot(eq(PRIVACY_GROUP_ID_BYTES), eq(blockHash))) when(privateStateRootResolver.resolveLastStateRoot(eq(PRIVACY_GROUP_ID_BYTES), eq(blockHash)))
.thenReturn(stateRootHash); .thenReturn(stateRootHash);
when(privateWorldStateArchive.get(eq(stateRootHash))) when(privateWorldStateArchive.get(eq(stateRootHash), any()))
.thenReturn(Optional.of(privateWorldState)); .thenReturn(Optional.of(privateWorldState));
when(privateWorldState.get(eq(contractAddress))).thenReturn(contractAccount); when(privateWorldState.get(eq(contractAddress))).thenReturn(contractAccount);
when(contractAccount.getCode()).thenReturn(contractCode); when(contractAccount.getCode()).thenReturn(contractCode);

@ -33,6 +33,7 @@ import org.hyperledger.besu.ethereum.chain.Blockchain;
import org.hyperledger.besu.ethereum.core.Address; import org.hyperledger.besu.ethereum.core.Address;
import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.Block;
import org.hyperledger.besu.ethereum.core.BlockDataGenerator; 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.Hash;
import org.hyperledger.besu.ethereum.core.MutableWorldState; import org.hyperledger.besu.ethereum.core.MutableWorldState;
import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.Transaction;
@ -297,11 +298,13 @@ public class PrivateStorageMigrationTest {
} }
private void mockBlockInBlockchain(final Block block) { private void mockBlockInBlockchain(final Block block) {
when(blockchain.getBlockByNumber(block.getHeader().getNumber())).thenReturn(Optional.of(block)); final BlockHeader blockHeader = block.getHeader();
when(blockchain.getBlockHeader(block.getHash())).thenReturn(Optional.of(block.getHeader())); final Hash blockHash = block.getHash();
when(blockchain.getBlockBody(block.getHash())).thenReturn(Optional.of(block.getBody())); 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)); .thenReturn(Optional.of(publicMutableWorldState));
} }

@ -409,19 +409,19 @@ public class TransactionSimulatorTest {
final Hash stateRoot, final Address address, final long nonce) { final Hash stateRoot, final Address address, final long nonce) {
final Account account = mock(Account.class); final Account account = mock(Account.class);
when(account.getNonce()).thenReturn(nonce); 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); when(worldState.get(eq(address))).thenReturn(account);
} }
private void mockWorldStateForAbsentAccount(final Hash stateRoot) { 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); when(worldState.get(any())).thenReturn(null);
} }
private MutableAccount mockWorldUpdaterForAccount(final Hash stateRoot, final Address address) { private MutableAccount mockWorldUpdaterForAccount(final Hash stateRoot, final Address address) {
final EvmAccount account = mock(EvmAccount.class); final EvmAccount account = mock(EvmAccount.class);
final MutableAccount mutableAccount = mock(MutableAccount.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(worldState.updater()).thenReturn(worldUpdater);
when(worldUpdater.getOrCreate(eq(address))).thenReturn(account); when(worldUpdater.getOrCreate(eq(address))).thenReturn(account);
when(account.getMutable()).thenReturn(mutableAccount); when(account.getMutable()).thenReturn(mutableAccount);

@ -90,9 +90,11 @@ public class BlockchainReferenceTestTools {
} }
public static void executeTest(final BlockchainReferenceTestCaseSpec spec) { public static void executeTest(final BlockchainReferenceTestCaseSpec spec) {
final MutableWorldState worldState =
spec.getWorldStateArchive().getMutable(spec.getGenesisBlockHeader().getStateRoot()).get();
final BlockHeader genesisBlockHeader = spec.getGenesisBlockHeader(); final BlockHeader genesisBlockHeader = spec.getGenesisBlockHeader();
final MutableWorldState worldState =
spec.getWorldStateArchive()
.getMutable(genesisBlockHeader.getStateRoot(), genesisBlockHeader.getHash())
.get();
assertThat(worldState.rootHash()).isEqualTo(genesisBlockHeader.getStateRoot()); assertThat(worldState.rootHash()).isEqualTo(genesisBlockHeader.getStateRoot());
final ProtocolSchedule schedule = final ProtocolSchedule schedule =

@ -87,8 +87,9 @@ public class MarkSweepPrunerTest {
pruner.sweepBefore(markBlock.getNumber()); pruner.sweepBefore(markBlock.getNumber());
// Assert that the block we marked is still present and all accounts are accessible // Assert that the block we marked is still present and all accounts are accessible
assertThat(worldStateArchive.get(markBlock.getStateRoot())).isPresent(); assertThat(worldStateArchive.get(markBlock.getStateRoot(), markBlock.getHash())).isPresent();
final WorldState markedState = worldStateArchive.get(markBlock.getStateRoot()).get(); final WorldState markedState =
worldStateArchive.get(markBlock.getStateRoot(), markBlock.getHash()).get();
// Traverse accounts and make sure all are accessible // Traverse accounts and make sure all are accessible
final int expectedAccounts = numAccounts * markBlockNumber; final int expectedAccounts = numAccounts * markBlockNumber;
final long accounts = markedState.streamAccounts(Bytes32.ZERO, expectedAccounts * 2).count(); final long accounts = markedState.streamAccounts(Bytes32.ZERO, expectedAccounts * 2).count();
@ -104,7 +105,7 @@ public class MarkSweepPrunerTest {
if (curHeader.getNumber() == markBlock.getNumber()) { if (curHeader.getNumber() == markBlock.getNumber()) {
continue; continue;
} }
assertThat(worldStateArchive.get(curHeader.getStateRoot())).isEmpty(); assertThat(worldStateArchive.get(curHeader.getStateRoot(), curHeader.getHash())).isEmpty();
} }
// Check that storage contains only the values we expect // 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) { private void generateBlockchainData(final int numBlocks, final int numAccounts) {
Block parentBlock = blockchain.getChainHeadBlock(); Block parentBlock = blockchain.getChainHeadBlock();
for (int i = 0; i < numBlocks; i++) { for (int i = 0; i < numBlocks; i++) {
final BlockHeader parentHeader = parentBlock.getHeader();
final MutableWorldState worldState = final MutableWorldState worldState =
worldStateArchive.getMutable(parentBlock.getHeader().getStateRoot()).get(); worldStateArchive.getMutable(parentHeader.getStateRoot(), parentHeader.getHash()).get();
gen.createRandomContractAccountsWithNonEmptyStorage(worldState, numAccounts); gen.createRandomContractAccountsWithNonEmptyStorage(worldState, numAccounts);
final Hash stateRoot = worldState.rootHash(); final Hash stateRoot = worldState.rootHash();
@ -198,7 +200,7 @@ public class MarkSweepPrunerTest {
gen.block( gen.block(
BlockOptions.create() BlockOptions.create()
.setStateRoot(stateRoot) .setStateRoot(stateRoot)
.setBlockNumber(parentBlock.getHeader().getNumber() + 1L) .setBlockNumber(parentHeader.getNumber() + 1L)
.setParentHash(parentBlock.getHash())); .setParentHash(parentBlock.getHash()));
final List<TransactionReceipt> receipts = gen.receipts(block); final List<TransactionReceipt> receipts = gen.receipts(block);
blockchain.appendBlock(block, receipts); blockchain.appendBlock(block, receipts);

@ -56,7 +56,7 @@ class FullSyncTargetManager extends SyncTargetManager {
final BlockHeader commonAncestor = syncTarget.commonAncestor(); final BlockHeader commonAncestor = syncTarget.commonAncestor();
if (protocolContext if (protocolContext
.getWorldStateArchive() .getWorldStateArchive()
.isWorldStateAvailable(commonAncestor.getStateRoot())) { .isWorldStateAvailable(commonAncestor.getStateRoot(), commonAncestor.getHash())) {
return Optional.of(syncTarget); return Optional.of(syncTarget);
} else { } else {
LOG.warn( LOG.warn(

@ -251,7 +251,7 @@ public class TransactionPool implements BlockAddedObserver {
return protocolContext return protocolContext
.getWorldStateArchive() .getWorldStateArchive()
.get(chainHeadBlockHeader.getStateRoot()) .get(chainHeadBlockHeader.getStateRoot(), chainHeadBlockHeader.getHash())
.map( .map(
worldState -> { worldState -> {
final Account senderAccount = worldState.get(transaction.getSender()); final Account senderAccount = worldState.get(transaction.getSender());

@ -21,6 +21,7 @@ import static org.mockito.Mockito.when;
import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.chain.Blockchain;
import org.hyperledger.besu.ethereum.chain.MutableBlockchain; 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.BlockchainSetupUtil;
import org.hyperledger.besu.ethereum.core.Difficulty; import org.hyperledger.besu.ethereum.core.Difficulty;
import org.hyperledger.besu.ethereum.core.ProtocolScheduleFixture; import org.hyperledger.besu.ethereum.core.ProtocolScheduleFixture;
@ -90,7 +91,9 @@ public class FullSyncTargetManagerTest {
@Test @Test
public void findSyncTarget_withHeightEstimates() { public void findSyncTarget_withHeightEstimates() {
when(localWorldState.isWorldStateAvailable(localBlockchain.getChainHeadHeader().getStateRoot())) final BlockHeader chainHeadHeader = localBlockchain.getChainHeadHeader();
when(localWorldState.isWorldStateAvailable(
chainHeadHeader.getStateRoot(), chainHeadHeader.getHash()))
.thenReturn(true); .thenReturn(true);
final RespondingEthPeer bestPeer = final RespondingEthPeer bestPeer =
EthProtocolManagerTestUtil.createPeer(ethProtocolManager, Difficulty.MAX_VALUE, 4); EthProtocolManagerTestUtil.createPeer(ethProtocolManager, Difficulty.MAX_VALUE, 4);
@ -105,7 +108,9 @@ public class FullSyncTargetManagerTest {
@Test @Test
public void findSyncTarget_noHeightEstimates() { public void findSyncTarget_noHeightEstimates() {
when(localWorldState.isWorldStateAvailable(localBlockchain.getChainHeadHeader().getStateRoot())) final BlockHeader chainHeadHeader = localBlockchain.getChainHeadHeader();
when(localWorldState.isWorldStateAvailable(
chainHeadHeader.getStateRoot(), chainHeadHeader.getHash()))
.thenReturn(true); .thenReturn(true);
final RespondingEthPeer bestPeer = final RespondingEthPeer bestPeer =
EthProtocolManagerTestUtil.createPeer(ethProtocolManager, Difficulty.MAX_VALUE, 0); EthProtocolManagerTestUtil.createPeer(ethProtocolManager, Difficulty.MAX_VALUE, 0);
@ -118,7 +123,9 @@ public class FullSyncTargetManagerTest {
@Test @Test
public void shouldDisconnectPeerIfWorldStateIsUnavailableForCommonAncestor() { public void shouldDisconnectPeerIfWorldStateIsUnavailableForCommonAncestor() {
when(localWorldState.isWorldStateAvailable(localBlockchain.getChainHeadHeader().getStateRoot())) final BlockHeader chainHeadHeader = localBlockchain.getChainHeadHeader();
when(localWorldState.isWorldStateAvailable(
chainHeadHeader.getStateRoot(), chainHeadHeader.getHash()))
.thenReturn(false); .thenReturn(false);
final RespondingEthPeer bestPeer = final RespondingEthPeer bestPeer =
EthProtocolManagerTestUtil.createPeer(ethProtocolManager, 20); EthProtocolManagerTestUtil.createPeer(ethProtocolManager, 20);
@ -133,7 +140,9 @@ public class FullSyncTargetManagerTest {
@Test @Test
public void shouldAllowSyncTargetWhenIfWorldStateIsAvailableForCommonAncestor() { public void shouldAllowSyncTargetWhenIfWorldStateIsAvailableForCommonAncestor() {
when(localWorldState.isWorldStateAvailable(localBlockchain.getChainHeadHeader().getStateRoot())) final BlockHeader chainHeadHeader = localBlockchain.getChainHeadHeader();
when(localWorldState.isWorldStateAvailable(
chainHeadHeader.getStateRoot(), chainHeadHeader.getHash()))
.thenReturn(true); .thenReturn(true);
final RespondingEthPeer bestPeer = final RespondingEthPeer bestPeer =
EthProtocolManagerTestUtil.createPeer(ethProtocolManager, 20); EthProtocolManagerTestUtil.createPeer(ethProtocolManager, 20);

@ -266,7 +266,7 @@ public class WorldStateDownloaderTest {
// Check that all expected account data was downloaded // Check that all expected account data was downloaded
final WorldStateArchive localWorldStateArchive = final WorldStateArchive localWorldStateArchive =
new DefaultWorldStateArchive(localStorage, createPreimageStorage()); new DefaultWorldStateArchive(localStorage, createPreimageStorage());
final WorldState localWorldState = localWorldStateArchive.get(stateRoot).get(); final WorldState localWorldState = localWorldStateArchive.get(stateRoot, null).get();
assertThat(result).isDone(); assertThat(result).isDone();
assertAccountsMatch(localWorldState, accounts); assertAccountsMatch(localWorldState, accounts);
} }
@ -335,7 +335,7 @@ public class WorldStateDownloaderTest {
// Check that all expected account data was downloaded // Check that all expected account data was downloaded
final WorldStateArchive localWorldStateArchive = final WorldStateArchive localWorldStateArchive =
new DefaultWorldStateArchive(localStorage, createPreimageStorage()); new DefaultWorldStateArchive(localStorage, createPreimageStorage());
final WorldState localWorldState = localWorldStateArchive.get(stateRoot).get(); final WorldState localWorldState = localWorldStateArchive.get(stateRoot, null).get();
assertThat(result).isDone(); assertThat(result).isDone();
assertAccountsMatch(localWorldState, accounts); assertAccountsMatch(localWorldState, accounts);
} }
@ -501,7 +501,7 @@ public class WorldStateDownloaderTest {
// Check that all expected account data was downloaded // Check that all expected account data was downloaded
final WorldStateArchive localWorldStateArchive = final WorldStateArchive localWorldStateArchive =
new DefaultWorldStateArchive(localStorage, createPreimageStorage()); new DefaultWorldStateArchive(localStorage, createPreimageStorage());
final WorldState localWorldState = localWorldStateArchive.get(stateRoot).get(); final WorldState localWorldState = localWorldStateArchive.get(stateRoot, null).get();
assertThat(result).isDone(); assertThat(result).isDone();
assertAccountsMatch(localWorldState, accounts); assertAccountsMatch(localWorldState, accounts);
} }
@ -600,7 +600,7 @@ public class WorldStateDownloaderTest {
// Check that all expected account data was downloaded // Check that all expected account data was downloaded
final WorldStateArchive localWorldStateArchive = final WorldStateArchive localWorldStateArchive =
new DefaultWorldStateArchive(localStorage, createPreimageStorage()); new DefaultWorldStateArchive(localStorage, createPreimageStorage());
final WorldState localWorldState = localWorldStateArchive.get(stateRoot).get(); final WorldState localWorldState = localWorldStateArchive.get(stateRoot, null).get();
assertThat(result).isDone(); assertThat(result).isDone();
assertAccountsMatch(localWorldState, accounts); assertAccountsMatch(localWorldState, accounts);
} }
@ -732,7 +732,7 @@ public class WorldStateDownloaderTest {
assertThat(result).isDone(); assertThat(result).isDone();
final WorldStateArchive localWorldStateArchive = final WorldStateArchive localWorldStateArchive =
new DefaultWorldStateArchive(localStorage, createPreimageStorage()); new DefaultWorldStateArchive(localStorage, createPreimageStorage());
final WorldState localWorldState = localWorldStateArchive.get(stateRoot).get(); final WorldState localWorldState = localWorldStateArchive.get(stateRoot, null).get();
assertAccountsMatch(localWorldState, accounts); assertAccountsMatch(localWorldState, accounts);
} }
@ -875,7 +875,7 @@ public class WorldStateDownloaderTest {
} }
// Check that all expected account data was downloaded // 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(); assertThat(result).isDone();
assertAccountsMatch(localWorldState, accounts); assertAccountsMatch(localWorldState, accounts);

@ -166,7 +166,7 @@ public class TransactionPoolFactoryTest {
.thenReturn(ValidationResult.valid()); .thenReturn(ValidationResult.valid());
when(transactionValidator.validateForSender(any(), any(), any())) when(transactionValidator.validateForSender(any(), any(), any()))
.thenReturn(ValidationResult.valid()); .thenReturn(ValidationResult.valid());
when(worldStateArchive.get(any())).thenReturn(Optional.of(worldState)); when(worldStateArchive.get(any(), any())).thenReturn(Optional.of(worldState));
final TransactionPool pool = final TransactionPool pool =
TransactionPoolFactory.createTransactionPool( TransactionPoolFactory.createTransactionPool(

Loading…
Cancel
Save