Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,9 @@ private <T> Optional<T> performActionWithBlock(
return Optional.empty();
}
final MutableWorldState mutableWorldState =
worldStateArchive.getMutable(previous.getStateRoot(), previous.getHash()).orElse(null);
worldStateArchive
.getMutable(previous.getStateRoot(), previous.getHash(), false)
.orElse(null);
if (mutableWorldState == null) {
return Optional.empty();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,8 @@ public void setUp() throws Exception {
when(blockHeader.getHash()).thenReturn(blockHash);
when(blockHeader.getParentHash()).thenReturn(previousBlockHash);
when(previousBlockHeader.getStateRoot()).thenReturn(Hash.ZERO);
when(worldStateArchive.getMutable(Hash.ZERO, null)).thenReturn(Optional.of(mutableWorldState));
when(worldStateArchive.getMutable(Hash.ZERO, null, false))
.thenReturn(Optional.of(mutableWorldState));
when(protocolSchedule.getByBlockNumber(12)).thenReturn(protocolSpec);
when(protocolSpec.getTransactionProcessor()).thenReturn(transactionProcessor);
when(protocolSpec.getMiningBeneficiaryCalculator()).thenReturn(BlockHeader::getCoinbase);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ public UInt256 getStorageValue(final UInt256 key) {

@Override
public UInt256 getOriginalStorageValue(final UInt256 key) {
return context.getOriginalStorageValue(address, key);
return context.getPriorStorageValue(address, key);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package org.hyperledger.besu.ethereum.bonsai;

import org.hyperledger.besu.ethereum.chain.Blockchain;
import org.hyperledger.besu.ethereum.core.Account;
import org.hyperledger.besu.ethereum.core.Address;
import org.hyperledger.besu.ethereum.core.BlockHeader;
Expand All @@ -37,28 +38,42 @@
/** A World State backed first by trie log layer and then by another world state. */
public class BonsaiLayeredWorldState implements MutableWorldState, BonsaiWorldView, WorldState {

private final BonsaiWorldStateArchive worldStateArchive;
private final BonsaiWorldView parent;
private Optional<BonsaiWorldView> nextWorldView;
protected final long height;
protected final TrieLogLayer trieLog;

private final Hash worldStateRootHash;

private final Blockchain blockchain;
private final BonsaiWorldStateArchive archive;

BonsaiLayeredWorldState(
final BonsaiWorldStateArchive worldStateArchive,
final BonsaiWorldView parent,
final Blockchain blockchain,
final BonsaiWorldStateArchive archive,
final Optional<BonsaiWorldView> nextWorldView,
final long height,
final Hash worldStateRootHash,
final TrieLogLayer trieLog) {
this.worldStateArchive = worldStateArchive;
this.parent = parent;
this.blockchain = blockchain;
this.archive = archive;
this.nextWorldView = nextWorldView;
this.height = height;
this.worldStateRootHash = worldStateRootHash;
this.trieLog = trieLog;
}

public BonsaiWorldView getParent() {
return parent;
public Optional<BonsaiWorldView> getNextWorldView() {
if (nextWorldView.isEmpty()) {
final Optional<Hash> blockHashByNumber = blockchain.getBlockHashByNumber(height + 1);
nextWorldView =
blockHashByNumber
.map(hash -> archive.getMutable(null, hash, false).map(BonsaiWorldView.class::cast))
.orElseGet(() -> Optional.of(archive.getMutable()).map(BonsaiWorldView.class::cast));
}
return nextWorldView;
}

public void setNextWorldView(final Optional<BonsaiWorldView> nextWorldView) {
this.nextWorldView = nextWorldView;
}

public TrieLogLayer getTrieLog() {
Expand All @@ -71,29 +86,23 @@ public long getHeight() {

@Override
public Optional<Bytes> getCode(final Address address) {
// this must be iterative and lambda light because the stack may blow up
// mainly because we don't have tail calls.
BonsaiLayeredWorldState currentLayer = this;
while (currentLayer != null) {
final Optional<Bytes> maybeCode = currentLayer.trieLog.getCode(address);
if (maybeCode.isPresent()) {
final Optional<Bytes> maybePriorCode = currentLayer.trieLog.getPriorCode(address);
if (currentLayer == this && maybeCode.isPresent()) {
return maybeCode;
} else if (maybePriorCode.isPresent()) {
return maybePriorCode;
} else if (maybeCode.isPresent()) {
return Optional.empty();
}
final Optional<Hash> maybeLastChangedCodeLocation =
currentLayer.trieLog.getLastChangedCodeLocation(address);
if (maybeLastChangedCodeLocation.isPresent()) {
final Optional<TrieLogLayer> maybeTrieLogLayer =
worldStateArchive.getTrieLogLayer(maybeLastChangedCodeLocation.get());
if (maybeTrieLogLayer.isPresent()) {
return maybeTrieLogLayer.get().getCode(address);
}
}
if (currentLayer.parent == null) {
if (currentLayer.getNextWorldView().isEmpty()) {
currentLayer = null;
} else if (currentLayer.parent instanceof BonsaiLayeredWorldState) {
currentLayer = (BonsaiLayeredWorldState) currentLayer.parent;
} else if (currentLayer.getNextWorldView().get() instanceof BonsaiLayeredWorldState) {
currentLayer = (BonsaiLayeredWorldState) currentLayer.getNextWorldView().get();
} else {
return currentLayer.parent.getCode(address);
return currentLayer.getNextWorldView().get().getCode(address);
}
}
return Optional.empty();
Expand All @@ -105,12 +114,12 @@ public Optional<Bytes> getStateTrieNode(final Bytes location) {
// mainly because we don't have tail calls.
BonsaiLayeredWorldState currentLayer = this;
while (currentLayer != null) {
if (currentLayer.parent == null) {
if (currentLayer.getNextWorldView().isEmpty()) {
currentLayer = null;
} else if (currentLayer.parent instanceof BonsaiLayeredWorldState) {
currentLayer = (BonsaiLayeredWorldState) currentLayer.parent;
} else if (currentLayer.getNextWorldView().get() instanceof BonsaiLayeredWorldState) {
currentLayer = (BonsaiLayeredWorldState) currentLayer.getNextWorldView().get();
} else {
return currentLayer.parent.getStateTrieNode(location);
return currentLayer.getNextWorldView().get().getStateTrieNode(location);
}
}
return Optional.empty();
Expand All @@ -129,22 +138,28 @@ public Optional<UInt256> getStorageValueBySlotHash(final Address address, final
while (currentLayer != null) {
final Optional<UInt256> maybeValue =
currentLayer.trieLog.getStorageBySlotHash(address, slotHash);
if (maybeValue.isPresent()) {
final Optional<UInt256> maybePriorValue =
currentLayer.trieLog.getPriorStorageBySlotHash(address, slotHash);
if (currentLayer == this && maybeValue.isPresent()) {
return maybeValue;
} else if (maybePriorValue.isPresent()) {
return maybePriorValue;
} else if (maybeValue.isPresent()) {
return Optional.empty();
}
if (currentLayer.parent == null) {
if (currentLayer.getNextWorldView().isEmpty()) {
currentLayer = null;
} else if (currentLayer.parent instanceof BonsaiLayeredWorldState) {
currentLayer = (BonsaiLayeredWorldState) currentLayer.parent;
} else if (currentLayer.getNextWorldView().get() instanceof BonsaiLayeredWorldState) {
currentLayer = (BonsaiLayeredWorldState) currentLayer.getNextWorldView().get();
} else {
return currentLayer.parent.getStorageValueBySlotHash(address, slotHash);
return currentLayer.getNextWorldView().get().getStorageValueBySlotHash(address, slotHash);
}
}
return Optional.empty();
}

@Override
public UInt256 getOriginalStorageValue(final Address address, final UInt256 key) {
public UInt256 getPriorStorageValue(final Address address, final UInt256 key) {
// This is the base layer for a block, all values are original.
return getStorageValue(address, key);
}
Expand All @@ -169,12 +184,12 @@ public Map<Bytes32, Bytes> getAllAccountStorage(final Address address, final Has
}
});
}
if (currentLayer.parent == null) {
if (currentLayer.getNextWorldView().isEmpty()) {
currentLayer = null;
} else if (currentLayer.parent instanceof BonsaiLayeredWorldState) {
currentLayer = (BonsaiLayeredWorldState) currentLayer.parent;
} else if (currentLayer.getNextWorldView().get() instanceof BonsaiLayeredWorldState) {
currentLayer = (BonsaiLayeredWorldState) currentLayer.getNextWorldView().get();
} else {
final Account account = currentLayer.parent.get(address);
final Account account = currentLayer.getNextWorldView().get().get(address);
if (account != null) {
account
.storageEntriesFrom(Hash.ZERO, Integer.MAX_VALUE)
Expand All @@ -199,16 +214,23 @@ public Account get(final Address address) {
while (currentLayer != null) {
final Optional<StateTrieAccountValue> maybeStateTrieAccount =
currentLayer.trieLog.getAccount(address);
if (maybeStateTrieAccount.isPresent()) {
final Optional<StateTrieAccountValue> maybePriorStateTrieAccount =
currentLayer.trieLog.getPriorAccount(address);
if (currentLayer == this && maybeStateTrieAccount.isPresent()) {
return new BonsaiAccount(
BonsaiLayeredWorldState.this, address, maybeStateTrieAccount.get(), false);
} else if (maybePriorStateTrieAccount.isPresent()) {
return new BonsaiAccount(
BonsaiLayeredWorldState.this, address, maybePriorStateTrieAccount.get(), false);
} else if (maybeStateTrieAccount.isPresent()) {
return null;
}
if (currentLayer.parent == null) {
if (currentLayer.getNextWorldView().isEmpty()) {
currentLayer = null;
} else if (currentLayer.parent instanceof BonsaiLayeredWorldState) {
currentLayer = (BonsaiLayeredWorldState) currentLayer.parent;
} else if (currentLayer.getNextWorldView().get() instanceof BonsaiLayeredWorldState) {
currentLayer = (BonsaiLayeredWorldState) currentLayer.getNextWorldView().get();
} else {
return currentLayer.parent.get(address);
return currentLayer.getNextWorldView().get().get(address);
}
}
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
import org.hyperledger.besu.plugin.services.exception.StorageException;
import org.hyperledger.besu.plugin.services.storage.KeyValueStorageTransaction;

import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
Expand All @@ -57,8 +56,6 @@ public class BonsaiPersistedWorldState implements MutableWorldState, BonsaiWorld
private Hash worldStateRootHash;
private Hash worldStateBlockHash;

private final Map<Address, Hash> contractCodeChangesHistory;

public BonsaiPersistedWorldState(
final BonsaiWorldStateArchive archive,
final BonsaiWorldStateKeyValueStorage worldStateStorage) {
Expand All @@ -70,12 +67,6 @@ public BonsaiPersistedWorldState(
worldStateBlockHash =
Hash.wrap(Bytes32.wrap(worldStateStorage.getWorldStateBlockHash().orElse(Hash.ZERO)));
updater = new BonsaiWorldStateUpdater(this);
contractCodeChangesHistory =
worldStateStorage
.getTrieLog(worldStateBlockHash)
.map(TrieLogLayer::fromBytes)
.map(TrieLogLayer::getContractCodeChangesHistory)
.orElse(new HashMap<>());
}

public BonsaiWorldStateArchive getArchive() {
Expand Down Expand Up @@ -142,7 +133,7 @@ private Hash calculateRootHash(final BonsaiWorldStateKeyValueStorage.Updater sta
final Hash updatedAddressHash = Hash.hash(updatedAddress);
final BonsaiValue<BonsaiAccount> accountValue =
updater.getAccountsToUpdate().get(updatedAddress);
final BonsaiAccount accountOriginal = accountValue.getOriginal();
final BonsaiAccount accountOriginal = accountValue.getPrior();
final Hash storageRoot =
(accountOriginal == null) ? Hash.EMPTY_TRIE_HASH : accountOriginal.getStorageRoot();
final StoredMerklePatriciaTrie<Bytes, Bytes> storageTrie =
Expand Down Expand Up @@ -258,12 +249,9 @@ public void persist(final BlockHeader blockHeader) {
.put(WORLD_BLOCK_HASH_KEY, worldStateBlockHash.toArrayUnsafe());
if (originalBlockHash.equals(blockHeader.getParentHash())) {
LOG.debug("Writing Trie Log for {}", worldStateBlockHash);
final TrieLogLayer trieLog =
updater.generateTrieLog(worldStateBlockHash, contractCodeChangesHistory);
final TrieLogLayer trieLog = updater.generateTrieLog(worldStateBlockHash);
trieLog.freeze();
archive.addLayeredWorldState(
new BonsaiLayeredWorldState(
getArchive(), this, blockHeader.getNumber(), worldStateRootHash, trieLog));
archive.addLayeredWorldState(this, blockHeader.getNumber(), worldStateRootHash, trieLog);
final BytesValueRLPOutput rlpLog = new BytesValueRLPOutput();
trieLog.writeTo(rlpLog);

Expand Down Expand Up @@ -390,7 +378,7 @@ public Optional<UInt256> getStorageValueBySlotHash(final Address address, final
}

@Override
public UInt256 getOriginalStorageValue(final Address address, final UInt256 storageKey) {
public UInt256 getPriorStorageValue(final Address address, final UInt256 storageKey) {
return getStorageValue(address, storageKey);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,24 +22,24 @@
import java.util.function.BiConsumer;

public class BonsaiValue<T> {
private T original;
private T prior;
private T updated;

BonsaiValue(final T original, final T updated) {
this.original = original;
BonsaiValue(final T prior, final T updated) {
this.prior = prior;
this.updated = updated;
}

public T getOriginal() {
return original;
public T getPrior() {
return prior;
}

public T getUpdated() {
return updated;
}

public void setOriginal(final T original) {
this.original = original;
public void setPrior(final T prior) {
this.prior = prior;
}

public void setUpdated(final T updated) {
Expand All @@ -53,10 +53,10 @@ void writeRlp(final RLPOutput output, final BiConsumer<RLPOutput, T> writer) {
}

void writeInnerRlp(final RLPOutput output, final BiConsumer<RLPOutput, T> writer) {
if (original == null) {
if (prior == null) {
output.writeNull();
} else {
writer.accept(output, original);
writer.accept(output, prior);
}
if (updated == null) {
output.writeNull();
Expand All @@ -66,11 +66,11 @@ void writeInnerRlp(final RLPOutput output, final BiConsumer<RLPOutput, T> writer
}

boolean isUnchanged() {
return Objects.equals(updated, original);
return Objects.equals(updated, prior);
}

@Override
public String toString() {
return "BonsaiValue{" + "original=" + original + ", updated=" + updated + '}';
return "BonsaiValue{" + "prior=" + prior + ", updated=" + updated + '}';
}
}
Loading