Skip to content

Commit

Permalink
Call operation performance optimizations (hyperledger#5537)
Browse files Browse the repository at this point in the history
* Call Operation performance improvements

- Move values that are the same or shared across the transaction to
  TxValues record
- Move warm and cold storage to undoable sets and tables.
- Move transient storage to undoable table.
- Move address hashing inside of address with a memoized field.
- lazy create EOF return stack

Signed-off-by: Danno Ferrin <[email protected]>
  • Loading branch information
shemnon authored and garyschulte committed Aug 28, 2023
1 parent d1382e2 commit c0d148e
Show file tree
Hide file tree
Showing 54 changed files with 2,426 additions and 581 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,12 @@
import org.hyperledger.besu.ethereum.rlp.RLPException;
import org.hyperledger.besu.ethereum.rlp.RLPInput;

import java.util.concurrent.ExecutionException;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
import org.apache.tuweni.bytes.DelegatingBytes;
Expand Down Expand Up @@ -75,6 +80,18 @@ public class Address extends DelegatingBytes {
/** The constant ZERO. */
public static final Address ZERO = Address.fromHexString("0x0");

static LoadingCache<Address, Hash> hashCache =
CacheBuilder.newBuilder()
.maximumSize(4000)
// .weakKeys() // unless we "intern" all addresses we cannot use weak or soft keys.
.build(
new CacheLoader<>() {
@Override
public Hash load(final Address key) {
return Hash.hash(key);
}
});

/**
* Instantiates a new Address.
*
Expand Down Expand Up @@ -237,4 +254,17 @@ public static Address privateContractAddress(
out.endList();
})));
}

/**
* Returns the hash of the address. Backed by a cache for performance reasons.
*
* @return the hash of the address.
*/
public Hash addressHash() {
try {
return hashCache.get(this);
} catch (ExecutionException e) {
return Hash.hash(this);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -112,25 +112,19 @@ public MessageFrame createMessageFrame() {

public MessageFrame.Builder createMessageFrameBuilder() {
return MessageFrame.builder()
.parentMessageFrame(messageFrame)
.type(MessageFrame.Type.MESSAGE_CALL)
.messageFrameStack(messageFrame.getMessageFrameStack())
.worldUpdater(messageFrame.getWorldUpdater())
.initialGas(messageFrame.getRemainingGas())
.address(messageFrame.getContractAddress())
.originator(messageFrame.getOriginatorAddress())
.contract(messageFrame.getRecipientAddress())
.gasPrice(messageFrame.getGasPrice())
.inputData(messageFrame.getInputData())
.sender(messageFrame.getSenderAddress())
.value(messageFrame.getValue())
.apparentValue(messageFrame.getApparentValue())
.code(messageFrame.getCode())
.blockValues(messageFrame.getBlockValues())
.depth(messageFrame.getMessageStackDepth())
.isStatic(messageFrame.isStatic())
.completer(messageFrame -> {})
.miningBeneficiary(messageFrame.getMiningBeneficiary())
.maxStackSize(messageFrame.getMaxStackSize());
.completer(frame -> {});
}

public void cleanUp() throws IOException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ public BonsaiAccount(
this(
context,
address,
Hash.hash(address),
address.addressHash(),
stateTrieAccount.getNonce(),
stateTrieAccount.getBalance(),
stateTrieAccount.getStorageRoot(),
Expand Down Expand Up @@ -142,7 +142,7 @@ public static BonsaiAccount fromRLP(
in.leaveList();

return new BonsaiAccount(
context, address, Hash.hash(address), nonce, balance, storageRoot, codeHash, mutable);
context, address, address.addressHash(), nonce, balance, storageRoot, codeHash, mutable);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,11 +105,11 @@ public BonsaiWorldStateProvider(
this.persistedState = new BonsaiWorldState(this, worldStateStorage);
this.cachedMerkleTrieLoader = cachedMerkleTrieLoader;
blockchain
.getBlockHeader(persistedState.worldStateBlockHash)
.getBlockHeader(persistedState.getWorldStateBlockHash())
.ifPresent(
blockHeader ->
this.trieLogManager.addCachedLayer(
blockHeader, persistedState.worldStateRootHash, persistedState));
blockHeader, persistedState.getWorldStateRootHash(), persistedState));
}

@VisibleForTesting
Expand All @@ -124,11 +124,11 @@ public BonsaiWorldStateProvider(
this.persistedState = new BonsaiWorldState(this, worldStateStorage);
this.cachedMerkleTrieLoader = cachedMerkleTrieLoader;
blockchain
.getBlockHeader(persistedState.worldStateBlockHash)
.getBlockHeader(persistedState.getWorldStateBlockHash())
.ifPresent(
blockHeader ->
this.trieLogManager.addCachedLayer(
blockHeader, persistedState.worldStateRootHash, persistedState));
blockHeader, persistedState.getWorldStateRootHash(), persistedState));
}

@Override
Expand Down Expand Up @@ -300,7 +300,7 @@ public MutableWorldState getMutable() {
public void prepareStateHealing(final Address address, final Bytes location) {
final Set<Bytes> keysToDelete = new HashSet<>();
final BonsaiWorldStateKeyValueStorage.BonsaiUpdater updater = worldStateStorage.updater();
final Hash accountHash = Hash.hash(address);
final Hash accountHash = address.addressHash();
final StoredMerklePatriciaTrie<Bytes, Bytes> accountTrie =
new StoredMerklePatriciaTrie<>(
(l, h) -> {
Expand All @@ -310,7 +310,7 @@ public void prepareStateHealing(final Address address, final Bytes location) {
}
return node;
},
persistedState.worldStateRootHash,
persistedState.getWorldStateRootHash(),
Function.identity(),
Function.identity());
try {
Expand Down Expand Up @@ -359,7 +359,7 @@ public void resetArchiveStateTo(final BlockHeader blockHeader) {
persistedState.resetWorldStateTo(blockHeader);
this.trieLogManager.reset();
this.trieLogManager.addCachedLayer(
blockHeader, persistedState.worldStateRootHash, persistedState);
blockHeader, persistedState.getWorldStateRootHash(), persistedState);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,8 @@ public CachedMerkleTrieLoader(final ObservableMetricsSystem metricsSystem) {
CacheMetricsCollector cacheMetrics = new CacheMetricsCollector();
cacheMetrics.addCache("accountsNodes", accountNodes);
cacheMetrics.addCache("storageNodes", storageNodes);
if (metricsSystem instanceof PrometheusMetricsSystem)
((PrometheusMetricsSystem) metricsSystem)
.addCollector(BesuMetricCategory.BLOCKCHAIN, () -> cacheMetrics);
if (metricsSystem instanceof PrometheusMetricsSystem prometheusMetricsSystem)
prometheusMetricsSystem.addCollector(BesuMetricCategory.BLOCKCHAIN, () -> cacheMetrics);
}

public void preLoadAccount(
Expand Down Expand Up @@ -82,7 +81,7 @@ public void cacheAccountNodes(
worldStateRootHash,
Function.identity(),
Function.identity());
accountTrie.get(Hash.hash(account));
accountTrie.get(account.addressHash());
} catch (MerkleTrieException e) {
// ignore exception for the cache
} finally {
Expand All @@ -102,7 +101,7 @@ public void cacheStorageNodes(
final BonsaiWorldStateKeyValueStorage worldStateStorage,
final Address account,
final StorageSlotKey slotKey) {
final Hash accountHash = Hash.hash(account);
final Hash accountHash = account.addressHash();
final long storageSubscriberId = worldStateStorage.subscribe(this);
try {
worldStateStorage
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.LongStream;
import java.util.stream.Stream;

Expand Down Expand Up @@ -106,7 +105,7 @@ public synchronized void addCachedLayer(
.get()
.updateWorldStateStorage(
new BonsaiSnapshotWorldStateKeyValueStorage(
forWorldState.worldStateStorage, metricsSystem));
forWorldState.getWorldStateStorage(), metricsSystem));
}
} else {
LOG.atDebug()
Expand All @@ -120,7 +119,7 @@ public synchronized void addCachedLayer(
new CachedBonsaiWorldView(
blockHeader,
new BonsaiSnapshotWorldStateKeyValueStorage(
forWorldState.worldStateStorage, metricsSystem)));
forWorldState.getWorldStateStorage(), metricsSystem)));
} else {
// otherwise, add the layer to the cache
cachedWorldStatesByHash.put(
Expand Down Expand Up @@ -257,14 +256,12 @@ protected TrieLogFactory setupTrieLogFactory(final BesuContext pluginContext) {
TrieLogProvider getTrieLogProvider() {
return new TrieLogProvider() {
@Override
public <T extends TrieLog.LogTuple<?>> Optional<TrieLog> getTrieLogLayer(
final Hash blockHash) {
public Optional<TrieLog> getTrieLogLayer(final Hash blockHash) {
return CachedWorldStorageManager.this.getTrieLogLayer(blockHash);
}

@Override
public <T extends TrieLog.LogTuple<?>> Optional<TrieLog> getTrieLogLayer(
final long blockNumber) {
public Optional<TrieLog> getTrieLogLayer(final long blockNumber) {
return CachedWorldStorageManager.this
.blockchain
.getBlockHeader(blockNumber)
Expand All @@ -273,7 +270,7 @@ public <T extends TrieLog.LogTuple<?>> Optional<TrieLog> getTrieLogLayer(
}

@Override
public <T extends TrieLog.LogTuple<?>> List<TrieLogRangeTuple> getTrieLogsByRange(
public List<TrieLogRangeTuple> getTrieLogsByRange(
final long fromBlockNumber, final long toBlockNumber) {
return rangeAsStream(fromBlockNumber, toBlockNumber)
.map(blockchain::getBlockHeader)
Expand All @@ -289,7 +286,7 @@ public <T extends TrieLog.LogTuple<?>> List<TrieLogRangeTuple> getTrieLogsByRang
header.getBlockHash(), header.getNumber(), layer))))
.filter(Optional::isPresent)
.map(Optional::get)
.collect(Collectors.toList());
.toList();
}

Stream<Long> rangeAsStream(final long fromBlockNumber, final long toBlockNumber) {
Expand Down
Loading

0 comments on commit c0d148e

Please sign in to comment.