Skip to content

Commit

Permalink
Started moving the store utilities inside the store transaction
Browse files Browse the repository at this point in the history
  • Loading branch information
spoto committed May 2, 2024
1 parent b05576a commit 8c0bc93
Show file tree
Hide file tree
Showing 12 changed files with 376 additions and 92 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ protected DiskStore mkStore() {
}

@Override
public StoreTransaction<?> getTransaction() {
public StoreTransaction<?> getStoreTransaction() {
return transaction;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,58 +43,74 @@ public long getNow() {
return System.currentTimeMillis();
}

public boolean isJustStore() {
synchronized (getLock()) {
return requests.isEmpty() && responses.isEmpty() && histories.isEmpty();
}
}

@Override
public Optional<TransactionResponse> getResponseUncommitted(TransactionReference reference) {
var uncommittedResponse = responses.get(reference);
if (uncommittedResponse != null)
return Optional.of(uncommittedResponse);
else
return getStore().getResponse(reference);
synchronized (getLock()) {
var uncommittedResponse = responses.get(reference);
if (uncommittedResponse != null)
return Optional.of(uncommittedResponse);
else
return getStore().getResponse(reference);
}
}

@Override
public Stream<TransactionReference> getHistoryUncommitted(StorageReference object) throws StoreException {
var uncommittedHistory = histories.get(object);
if (uncommittedHistory != null)
return Stream.of(uncommittedHistory);
else
return getStore().getHistory(object);
synchronized (getLock()) {
var uncommittedHistory = histories.get(object);
if (uncommittedHistory != null)
return Stream.of(uncommittedHistory);
else
return getStore().getHistory(object);
}
}

@Override
public Optional<StorageReference> getManifestUncommitted() {
var uncommittedManifest = manifest.get();
if (uncommittedManifest != null)
return Optional.of(uncommittedManifest);
else
return getStore().getManifest();
synchronized (getLock()) {
var uncommittedManifest = manifest.get();
if (uncommittedManifest != null)
return Optional.of(uncommittedManifest);
else
return getStore().getManifest();
}
}

@Override
public DiskStore commit() throws StoreException {
var store = getStore();

// we report all the updates occurred during this transaction into the store
var manifest = this.manifest.get();
if (manifest != null)
store.setManifest(manifest);
synchronized (getLock()) {
// we report all the updates occurred during this transaction into the store
var manifest = this.manifest.get();
if (manifest != null)
store.setManifest(manifest);

for (var entry: errors.entrySet())
store.setError(entry.getKey(), entry.getValue());
for (var entry: errors.entrySet())
store.setError(entry.getKey(), entry.getValue());

for (var entry: histories.entrySet())
store.setHistory(entry.getKey(), Stream.of(entry.getValue()));
int progressive = 0;
for (var entry: requests.entrySet())
store.setRequest(progressive++, entry.getKey(), entry.getValue());

int progressive = 0;
for (var entry: requests.entrySet())
store.setRequest(progressive++, entry.getKey(), entry.getValue());
progressive = 0;
for (var entry: responses.entrySet())
store.setResponse(progressive++, entry.getKey(), entry.getValue());

progressive = 0;
for (var entry: responses.entrySet())
store.setResponse(progressive++, entry.getKey(), entry.getValue());
// it's important to write the histories at the end, so that there are no
// dangling references in the histories (ie, references to responses not yet in store)
for (var entry: histories.entrySet())
store.setHistory(entry.getKey(), Stream.of(entry.getValue()));

if (progressive > 0)
store.increaseBlockNumber();
if (progressive > 0)
store.increaseBlockNumber();
}

return store;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import io.hotmoka.node.api.updates.Update;
import io.hotmoka.node.api.updates.UpdateOfField;
import io.hotmoka.node.api.values.StorageReference;
import io.hotmoka.stores.Store;
import io.hotmoka.stores.StoreException;

/**
Expand All @@ -38,6 +39,7 @@
*/
public interface StoreUtility {

Store<?> getStore();
/**
* Determines if the node is initialized, that is, its manifest has been set,
* although possibly not yet committed.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@ private AbstractLocalNodeImpl(C config, ConsensusConfig<?,?> consensus, boolean
*
* @return the currently executing transaction
*/
public abstract StoreTransaction<?> getTransaction();
public abstract StoreTransaction<?> getStoreTransaction();

/**
* Determines if this node has not been closed yet.
Expand Down Expand Up @@ -693,17 +693,17 @@ public final TransactionResponse deliverTransaction(TransactionRequest<?> reques
var reference = TransactionReferences.of(hasher.hash(request));

try {
var transaction = getTransaction();
var storeTransaction = getStoreTransaction();

try {
LOGGER.info(reference + ": delivering start (" + request.getClass().getSimpleName() + ')');

TransactionResponse response;

synchronized (deliverTransactionLock) {
ResponseBuilder<?,?> responseBuilder = responseBuilderFor(reference, request, transaction);
ResponseBuilder<?,?> responseBuilder = responseBuilderFor(reference, request, storeTransaction);
response = responseBuilder.getResponse();
transaction.push(reference, request, response);
storeTransaction.push(reference, request, response);
responseBuilder.replaceReverifiedResponses();
scheduleForNotificationOfEvents(response);
takeNoteForNextReward(request, response);
Expand All @@ -714,18 +714,18 @@ public final TransactionResponse deliverTransaction(TransactionRequest<?> reques
return response;
}
catch (TransactionRejectedException e) {
transaction.push(reference, request, trimmedMessage(e));
storeTransaction.push(reference, request, trimmedMessage(e));
LOGGER.info(reference + ": delivering failed: " + trimmedMessage(e));
LOGGER.log(Level.INFO, "transaction rejected", e);
throw e;
}
catch (ClassNotFoundException | NodeException | UnknownReferenceException e) {
transaction.push(reference, request, trimmedMessage(e));
storeTransaction.push(reference, request, trimmedMessage(e));
LOGGER.log(Level.SEVERE, reference + ": delivering failed with unexpected exception", e);
throw new RuntimeException(e);
}
catch (RuntimeException e) {
transaction.push(reference, request, trimmedMessage(e));
storeTransaction.push(reference, request, trimmedMessage(e));
LOGGER.log(Level.WARNING, reference + ": delivering failed with unexpected exception", e);
throw e;
}
Expand Down Expand Up @@ -759,7 +759,7 @@ public final boolean rewardValidators(String behaving, String misbehaving) {
return false;

try {
Optional<StorageReference> manifest = getTransaction().getManifestUncommitted();
Optional<StorageReference> manifest = getStoreTransaction().getManifestUncommitted();
if (manifest.isPresent()) {
// we use the manifest as caller, since it is an externally-owned account
StorageReference caller = manifest.get();
Expand Down Expand Up @@ -796,7 +796,7 @@ else if (minted.signum() < 0) {
StorageValues.bigIntegerOf(gasConsumedSinceLastReward), StorageValues.bigIntegerOf(numberOfTransactionsSinceLastReward));

checkTransaction(request);
ResponseBuilder<?,?> responseBuilder = responseBuilderFor(TransactionReferences.of(hasher.hash(request)), request, getTransaction());
ResponseBuilder<?,?> responseBuilder = responseBuilderFor(TransactionReferences.of(hasher.hash(request)), request, getStoreTransaction());
TransactionResponse response = responseBuilder.getResponse();
// if there is only one update, it is the update of the nonce of the manifest: we prefer not to expand
// the store with the transaction, so that the state stabilizes, which might give
Expand Down Expand Up @@ -920,7 +920,7 @@ else if (request instanceof InitializationTransactionRequest itr)
throw new TransactionRejectedException("Unexpected transaction request of class " + request.getClass().getName());
}

protected void setStore(Store<?> store) {
public void setStore(Store<?> store) {
this.store = (S) store; // TODO
}

Expand Down Expand Up @@ -950,7 +950,7 @@ protected void setStore(Store<?> store) {
* @return the response, if any
*/
Optional<TransactionResponse> getResponseUncommitted(TransactionReference reference) throws StoreException {
var transaction = getTransaction();
var transaction = getStoreTransaction();
if (transaction != null)
return transaction.getResponseUncommitted(reference);
else
Expand All @@ -967,7 +967,7 @@ Optional<TransactionResponse> getResponseUncommitted(TransactionReference refere
* @throws StoreException if the store is not able to perform the operation
*/
Stream<TransactionReference> getHistoryUncommitted(StorageReference object) throws StoreException {
var transaction = getTransaction();
var transaction = getStoreTransaction();
if (transaction != null)
return transaction.getHistoryUncommitted(object);
else
Expand All @@ -982,7 +982,7 @@ Stream<TransactionReference> getHistoryUncommitted(StorageReference object) thro
* @throws StoreException if the store is not able to complete the operation correctly
*/
Optional<StorageReference> getManifestUncommitted() throws StoreException {
var transaction = getTransaction();
var transaction = getStoreTransaction();
if (transaction != null)
return transaction.getManifestUncommitted();
else
Expand Down Expand Up @@ -1142,11 +1142,8 @@ private BigInteger addInflation(BigInteger gas) {
}

private void scheduleForNotificationOfEvents(TransactionResponse response) {
if (response instanceof TransactionResponseWithEvents) {
var responseWithEvents = (TransactionResponseWithEvents) response;
if (responseWithEvents.getEvents().count() > 0L)
scheduleForNotificationOfEvents(responseWithEvents);
}
if (response instanceof TransactionResponseWithEvents responseWithEvents && responseWithEvents.getEvents().count() > 0L)
scheduleForNotificationOfEvents(responseWithEvents);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ private void payerMustBeContract() throws TransactionRejectedException, ClassNot
*/
private void signatureMustBeValid() throws Exception {
// if the node is not initialized yet, the signature is not checked
if (transactionIsSigned() && node.getStoreUtilities().nodeIsInitializedUncommitted()
if (transactionIsSigned() && storeTransaction.nodeIsInitializedUncommitted()
&& !node.caches.signatureIsValid((SignedTransactionRequest<?>) request, determineSignatureAlgorithm()))
throw new TransactionRejectedException("invalid request signature");
}
Expand All @@ -253,7 +253,7 @@ private void requestMustHaveCorrectChainId() throws TransactionRejectedException
// unsigned transactions do not check the chain identifier;
// if the node is not initialized yet, the chain id is not checked
try {
if (transactionIsSigned() && node.getStoreUtilities().nodeIsInitializedUncommitted()) {
if (transactionIsSigned() && storeTransaction.nodeIsInitializedUncommitted()) {
String chainIdOfNode = consensus.getChainId();
String chainId = ((SignedTransactionRequest<?>) request).getChainId();
if (!chainIdOfNode.equals(chainId))
Expand All @@ -273,8 +273,7 @@ private void requestMustHaveCorrectChainId() throws TransactionRejectedException
private void callerAndRequestMustAgreeOnNonce() throws TransactionRejectedException {
// calls to @View methods do not check the nonce
if (!isView()) {
BigInteger expected = node.getStoreUtilities().getNonceUncommitted(request.getCaller());

BigInteger expected = storeTransaction.getNonceUncommitted(request.getCaller());
if (!expected.equals(request.getNonce()))
throw new TransactionRejectedException("Incorrect nonce: the request reports " + request.getNonce()
+ " but the account " + request.getCaller() + " contains " + expected);
Expand Down Expand Up @@ -321,7 +320,7 @@ private void gasLimitIsInsideBounds() throws TransactionRejectedException {
private void gasPriceIsLargeEnough() throws TransactionRejectedException {
// before initialization, the gas price is not yet available
try {
if (transactionIsSigned() && node.getStoreUtilities().nodeIsInitializedUncommitted() && !ignoreGasPrice()) {
if (transactionIsSigned() && storeTransaction.nodeIsInitializedUncommitted() && !ignoreGasPrice()) {
BigInteger currentGasPrice = node.caches.getGasPrice().get();
if (request.getGasPrice().compareTo(currentGasPrice) < 0)
throw new TransactionRejectedException("the gas price of the request is smaller than the current gas price (" + request.getGasPrice() + " < " + currentGasPrice + ")");
Expand All @@ -340,7 +339,7 @@ private void gasPriceIsLargeEnough() throws TransactionRejectedException {
*/
private void payerCanPayForAllPromisedGas() throws TransactionRejectedException {
BigInteger cost = costOf(request.getGasLimit());
BigInteger totalBalance = node.getStoreUtilities().getTotalBalanceUncommitted(getPayerFromRequest());
BigInteger totalBalance = storeTransaction.getTotalBalanceUncommitted(getPayerFromRequest());

if (totalBalance.subtract(cost).signum() < 0)
throw new TransactionRejectedException("the payer has not enough funds to buy " + request.getGasLimit() + " units of gas");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ public StoreUtilityImpl(AbstractLocalNodeImpl<?, ?> node) {
this.node = node;
}

private Store<?> getStore() {
public Store<?> getStore() {
return store != null ? store : node.getStore();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ public abstract class AbstractResponseBuilder<Request extends TransactionRequest
*/
public final AbstractLocalNodeImpl<?,?> node;

public final StoreTransaction<?> transaction;
public final StoreTransaction<?> storeTransaction;

/**
* The object that translates storage types into their run-time class tag.
Expand Down Expand Up @@ -97,13 +97,13 @@ public abstract class AbstractResponseBuilder<Request extends TransactionRequest
*
* @param reference the reference to the transaction that is building the response
* @param request the request for which the response is being built
* @param transaction the transaction where the updates to the store get accumulated
* @param storeTransaction the transaction where the updates to the store get accumulated
* @param node the node that is creating the response
* @throws TransactionRejectedException if the builder cannot be created
*/
protected AbstractResponseBuilder(TransactionReference reference, Request request, StoreTransaction<?> transaction, AbstractLocalNodeImpl<?,?> node) throws TransactionRejectedException {
protected AbstractResponseBuilder(TransactionReference reference, Request request, StoreTransaction<?> storeTransaction, AbstractLocalNodeImpl<?,?> node) throws TransactionRejectedException {
try {
this.transaction = transaction;
this.storeTransaction = storeTransaction;
this.request = request;
this.reference = reference;
this.node = node;
Expand All @@ -128,7 +128,7 @@ public final EngineClassLoader getClassLoader() {

@Override
public final void replaceReverifiedResponses() throws NoSuchElementException, UnknownReferenceException, NodeException {
((EngineClassLoaderImpl) classLoader).replaceReverifiedResponses(transaction);
((EngineClassLoaderImpl) classLoader).replaceReverifiedResponses(storeTransaction);
}

/**
Expand All @@ -149,7 +149,7 @@ public final void replaceReverifiedResponses() throws NoSuchElementException, Un
* @return the wrapped or original exception
*/
protected static TransactionRejectedException wrapAsTransactionRejectedException(Throwable t) {
return t instanceof TransactionRejectedException ? (TransactionRejectedException) t : new TransactionRejectedException(t);
return t instanceof TransactionRejectedException tre ? tre : new TransactionRejectedException(t);
}

/**
Expand Down Expand Up @@ -184,7 +184,7 @@ protected ResponseCreator() throws TransactionRejectedException {
try {
this.deserializer = new Deserializer(AbstractResponseBuilder.this, node.getStoreUtilities());
this.updatesExtractor = new UpdatesExtractorFromRAM(AbstractResponseBuilder.this);
this.now = transaction.getNow();
this.now = storeTransaction.getNow();
}
catch (Throwable t) {
throw new TransactionRejectedException(t);
Expand Down Expand Up @@ -282,7 +282,7 @@ public final boolean isSystemCall() {
*/
public final Object deserializeLastUpdateFor(StorageReference object, FieldSignature field) {
try {
UpdateOfField update = node.getStoreUtilities().getLastUpdateToFieldUncommitted(object, field)
UpdateOfField update = storeTransaction.getLastUpdateToFieldUncommitted(object, field)
.orElseThrow(() -> new DeserializationError("did not find the last update for " + field + " of " + object));
return deserializer.deserialize(update.getValue());
}
Expand All @@ -301,7 +301,7 @@ public final Object deserializeLastUpdateFor(StorageReference object, FieldSigna
* @return the value of the field
*/
public final Object deserializeLastUpdateForFinal(StorageReference object, FieldSignature field) {
UpdateOfField update = node.getStoreUtilities().getLastUpdateToFinalFieldUncommitted(object, field)
UpdateOfField update = storeTransaction.getLastUpdateToFinalFieldUncommitted(object, field)
.orElseThrow(() -> new DeserializationError("did not find the last update for " + field + " of " + object));

return deserializer.deserialize(update.getValue());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ protected void ensureWhiteListingOf(Method executable, Object[] actuals) throws
*/
private void mintCoinsForRewardToValidators() {
try {
Optional<StorageReference> manifest = node.getStoreUtilities().getManifestUncommitted();
Optional<StorageReference> manifest = storeTransaction.getManifestUncommitted();
if (isSystemCall() && request.getStaticTarget().equals(MethodSignatures.VALIDATORS_REWARD) && manifest.isPresent() && request.getCaller().equals(manifest.get())) {
Optional<StorageValue> firstArg = request.actuals().findFirst();
if (firstArg.isPresent()) {
Expand All @@ -283,7 +283,7 @@ private void mintCoinsForRewardToValidators() {
*/
private Object[] addExtraActualsForFromContract() {
int al = deserializedActuals.length;
Object[] result = new Object[al + 2];
var result = new Object[al + 2];
System.arraycopy(deserializedActuals, 0, result, 0, al);
result[al] = getDeserializedCaller();
result[al + 1] = null; // Dummy is not used
Expand Down
Loading

0 comments on commit 8c0bc93

Please sign in to comment.