Skip to content

Commit

Permalink
Clean-up of the response builders
Browse files Browse the repository at this point in the history
Progressively removing the node from them
  • Loading branch information
spoto committed May 4, 2024
1 parent 0af5b4d commit f2be1f2
Show file tree
Hide file tree
Showing 20 changed files with 121 additions and 136 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package io.hotmoka.node.local;

import io.hotmoka.node.api.TransactionRejectedException;
import io.hotmoka.node.api.nodes.ConsensusConfig;
import io.hotmoka.node.api.requests.InitialTransactionRequest;
import io.hotmoka.node.api.responses.InitialTransactionResponse;
import io.hotmoka.node.api.transactions.TransactionReference;
Expand All @@ -41,8 +42,8 @@ public abstract class AbstractInitialResponseBuilder<Request extends InitialTran
* @param node the node that is creating the response
* @throws TransactionRejectedException if the builder cannot be created
*/
protected AbstractInitialResponseBuilder(TransactionReference reference, Request request, StoreTransaction<?> transaction, AbstractLocalNodeImpl<?,?> node) throws TransactionRejectedException {
super(reference, request, transaction, node);
protected AbstractInitialResponseBuilder(TransactionReference reference, Request request, StoreTransaction<?> transaction, ConsensusConfig<?,?> consensus, AbstractLocalNodeImpl<?,?> node) throws TransactionRejectedException {
super(reference, request, transaction, consensus, node);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@

package io.hotmoka.node.local;

import java.math.BigInteger;

import io.hotmoka.node.api.TransactionRejectedException;
import io.hotmoka.node.api.nodes.ConsensusConfig;
import io.hotmoka.node.api.requests.NonInitialTransactionRequest;
import io.hotmoka.node.api.responses.NonInitialTransactionResponse;
import io.hotmoka.node.api.transactions.TransactionReference;
Expand All @@ -32,8 +35,7 @@
* @param <Request> the type of the request of the transaction
* @param <Response> the type of the response of the transaction
*/
public abstract class AbstractNonInitialResponseBuilder<Request extends NonInitialTransactionRequest<Response>, Response extends NonInitialTransactionResponse>
extends NonInitialResponseBuilderImpl<Request, Response> {
public abstract class AbstractNonInitialResponseBuilder<Request extends NonInitialTransactionRequest<Response>, Response extends NonInitialTransactionResponse> extends NonInitialResponseBuilderImpl<Request, Response> {

/**
* Creates a the builder of the response.
Expand All @@ -43,8 +45,8 @@ public abstract class AbstractNonInitialResponseBuilder<Request extends NonIniti
* @param node the node that is creating the response
* @throws TransactionRejectedException if the builder cannot be built
*/
protected AbstractNonInitialResponseBuilder(TransactionReference reference, Request request, StoreTransaction<?> transaction, AbstractLocalNodeImpl<?,?> node) throws TransactionRejectedException {
super(reference, request, transaction, node);
protected AbstractNonInitialResponseBuilder(TransactionReference reference, Request request, StoreTransaction<?> storeTransaction, ConsensusConfig<?,?> consensus, BigInteger maxGasAllowedForTransaction, AbstractLocalNodeImpl<?,?> node) throws TransactionRejectedException {
super(reference, request, storeTransaction, consensus, maxGasAllowedForTransaction, node);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -593,13 +593,13 @@ public final Optional<StorageValue> runInstanceMethodCallTransaction(InstanceMet

Optional<StorageValue> result;

var transaction = store.beginTransaction(System.currentTimeMillis());
var storeTransaction = store.beginTransaction(System.currentTimeMillis());

synchronized (deliverTransactionLock) {
result = getOutcome(new InstanceViewMethodCallResponseBuilder(reference, request, transaction, this).getResponse());
result = getOutcome(new InstanceViewMethodCallResponseBuilder(reference, request, storeTransaction, caches.getConsensusParams(), getLocalNodeConfig().getMaxGasPerViewTransaction(), this).getResponse());
}

transaction.abort();
storeTransaction.abort();

LOGGER.info(reference + ": running success");
return result;
Expand All @@ -616,7 +616,7 @@ public final Optional<StorageValue> runStaticMethodCallTransaction(StaticMethodC
var transaction = store.beginTransaction(System.currentTimeMillis());

synchronized (deliverTransactionLock) {
result = getOutcome(new StaticViewMethodCallResponseBuilder(reference, request, transaction, this).getResponse());
result = getOutcome(new StaticViewMethodCallResponseBuilder(reference, request, transaction, caches.getConsensusParams(), getLocalNodeConfig().getMaxGasPerViewTransaction(), this).getResponse());
}

transaction.abort();
Expand Down Expand Up @@ -912,19 +912,19 @@ protected void invalidateCachesIfNeeded(TransactionResponse response, EngineClas
*/
protected ResponseBuilder<?,?> responseBuilderFor(TransactionReference reference, TransactionRequest<?> request, StoreTransaction<?> transaction) throws TransactionRejectedException {
if (request instanceof JarStoreInitialTransactionRequest jsitr)
return new JarStoreInitialResponseBuilder(reference, jsitr, transaction, this);
return new JarStoreInitialResponseBuilder(reference, jsitr, transaction, caches.getConsensusParams(), this);
else if (request instanceof GameteCreationTransactionRequest gctr)
return new GameteCreationResponseBuilder(reference, gctr, transaction, this);
return new GameteCreationResponseBuilder(reference, gctr, transaction, caches.getConsensusParams(), this);
else if (request instanceof JarStoreTransactionRequest jstr)
return new JarStoreResponseBuilder(reference, jstr, transaction, this);
return new JarStoreResponseBuilder(reference, jstr, transaction, caches.getConsensusParams(), this);
else if (request instanceof ConstructorCallTransactionRequest cctr)
return new ConstructorCallResponseBuilder(reference, cctr, transaction, this);
return new ConstructorCallResponseBuilder(reference, cctr, transaction, caches.getConsensusParams(), caches.getConsensusParams().getMaxGasPerTransaction(), this);
else if (request instanceof AbstractInstanceMethodCallTransactionRequest aimctr)
return new InstanceMethodCallResponseBuilder(reference, aimctr, transaction, this);
return new InstanceMethodCallResponseBuilder(reference, aimctr, transaction, caches.getConsensusParams(), this);
else if (request instanceof StaticMethodCallTransactionRequest smctr)
return new StaticMethodCallResponseBuilder(reference, smctr, transaction, this);
return new StaticMethodCallResponseBuilder(reference, smctr, transaction, caches.getConsensusParams(), this);
else if (request instanceof InitializationTransactionRequest itr)
return new InitializationResponseBuilder(reference, itr, transaction, this);
return new InitializationResponseBuilder(reference, itr, transaction, caches.getConsensusParams(), this);
else
throw new TransactionRejectedException("Unexpected transaction request of class " + request.getClass().getName());
}
Expand Down Expand Up @@ -1103,17 +1103,16 @@ private void takeNoteForNextReward(TransactionRequest<?> request, TransactionRes
if (!(request instanceof SystemTransactionRequest)) {
numberOfTransactionsSinceLastReward = numberOfTransactionsSinceLastReward.add(ONE);

if (response instanceof NonInitialTransactionResponse) {
var responseAsNonInitial = (NonInitialTransactionResponse) response;
if (response instanceof NonInitialTransactionResponse responseAsNonInitial) {
BigInteger gasConsumedButPenalty = responseAsNonInitial.getGasConsumedForCPU()
.add(responseAsNonInitial.getGasConsumedForStorage())
.add(responseAsNonInitial.getGasConsumedForRAM());

gasConsumedSinceLastReward = gasConsumedSinceLastReward.add(gasConsumedButPenalty);

BigInteger gasConsumedTotal = gasConsumedButPenalty;
if (response instanceof FailedTransactionResponse)
gasConsumedTotal = gasConsumedTotal.add(((FailedTransactionResponse) response).getGasConsumedForPenalty());
if (response instanceof FailedTransactionResponse ftr)
gasConsumedTotal = gasConsumedTotal.add(ftr.getGasConsumedForPenalty());

BigInteger gasPrice = ((NonInitialTransactionRequest<?>) request).getGasPrice();
BigInteger reward = gasConsumedTotal.multiply(gasPrice);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import java.util.concurrent.Callable;

import io.hotmoka.node.api.TransactionRejectedException;
import io.hotmoka.node.api.nodes.ConsensusConfig;
import io.hotmoka.node.api.requests.InitialTransactionRequest;
import io.hotmoka.node.api.responses.InitialTransactionResponse;
import io.hotmoka.node.api.transactions.TransactionReference;
Expand All @@ -42,8 +43,8 @@ public abstract class InitialResponseBuilderImpl<Request extends InitialTransact
* @param node the node that is creating the response
* @throws TransactionRejectedException if the builder cannot be created
*/
protected InitialResponseBuilderImpl(TransactionReference reference, Request request, StoreTransaction<?> storeTransaction, AbstractLocalNodeImpl<?,?> node) throws TransactionRejectedException {
super(reference, request, storeTransaction, node);
protected InitialResponseBuilderImpl(TransactionReference reference, Request request, StoreTransaction<?> storeTransaction, ConsensusConfig<?,?> consensus, AbstractLocalNodeImpl<?,?> node) throws TransactionRejectedException {
super(reference, request, storeTransaction, consensus, node);

try {
if (storeTransaction.nodeIsInitializedUncommitted())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,7 @@ private boolean consensusParametersMightHaveChanged(TransactionResponse response
* @throws StoreException
*/
private boolean isInitializedUncommitted() throws StoreException {
return node.getManifestUncommitted().isPresent();
return node.getStoreTransaction().getManifestUncommitted().isPresent();
}

private boolean isConsensusUpdateEvent(StorageReference event, EngineClassLoader classLoader) throws ClassNotFoundException {
Expand Down Expand Up @@ -423,14 +423,13 @@ private boolean inflationMightHaveChanged(TransactionResponse response, EngineCl

try {
// we check if there are events of type InflationUpdate triggered by the validators object
if (isInitializedUncommitted() && response instanceof TransactionResponseWithEvents) {
Stream<StorageReference> events = ((TransactionResponseWithEvents) response).getEvents();
if (isInitializedUncommitted() && response instanceof TransactionResponseWithEvents trwe) {
StorageReference validators = node.getStoreTransaction().getValidatorsUncommitted().get();

return check(ClassNotFoundException.class, () ->
events.filter(uncheck(event -> isInflationUpdateEvent(event, classLoader)))
.map(node.getStoreTransaction()::getCreatorUncommitted)
.anyMatch(validators::equals)
trwe.getEvents().filter(uncheck(event -> isInflationUpdateEvent(event, classLoader)))
.map(node.getStoreTransaction()::getCreatorUncommitted)
.anyMatch(validators::equals)
);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
import io.hotmoka.node.api.NodeException;
import io.hotmoka.node.api.TransactionRejectedException;
import io.hotmoka.node.api.UnknownReferenceException;
import io.hotmoka.node.api.nodes.ConsensusConfig;
import io.hotmoka.node.api.requests.NonInitialTransactionRequest;
import io.hotmoka.node.api.requests.SignedTransactionRequest;
import io.hotmoka.node.api.responses.NonInitialTransactionResponse;
Expand All @@ -46,7 +47,6 @@
import io.hotmoka.node.api.updates.ClassTag;
import io.hotmoka.node.api.updates.Update;
import io.hotmoka.node.api.updates.UpdateOfField;
import io.hotmoka.node.api.values.StorageReference;
import io.hotmoka.node.local.internal.transactions.AbstractResponseBuilder;
import io.hotmoka.stores.EngineClassLoader;
import io.hotmoka.stores.StoreException;
Expand All @@ -71,16 +71,17 @@ public abstract class NonInitialResponseBuilderImpl<Request extends NonInitialTr
* @param reference the reference to the transaction that is building the response
* @param request the request of the transaction
* @param node the node that is creating the response
* @param maxGasAllowedForTransaction the maximal gas allowed for this transaction. If the gas limit of the request is larger
* than this, then the transaction will be rejected
* @throws TransactionRejectedException if the builder cannot be built
*/
protected NonInitialResponseBuilderImpl(TransactionReference reference, Request request, StoreTransaction<?> storeTransaction, AbstractLocalNodeImpl<?,?> node) throws TransactionRejectedException {
super(reference, request, storeTransaction, node);
protected NonInitialResponseBuilderImpl(TransactionReference reference, Request request, StoreTransaction<?> storeTransaction, ConsensusConfig<?,?> consensus, BigInteger maxGasAllowedForTransaction, AbstractLocalNodeImpl<?,?> node) throws TransactionRejectedException {
super(reference, request, storeTransaction, consensus, node);

try {
this.gasCostModel = node.getGasCostModel();
callerMustBeExternallyOwnedAccount();
payerMustBeContract();
gasLimitIsInsideBounds();
gasLimitIsInsideBounds(maxGasAllowedForTransaction);
requestPromisesEnoughGas();
gasPriceIsLargeEnough();
requestMustHaveCorrectChainId();
Expand Down Expand Up @@ -128,29 +129,6 @@ protected BigInteger minimalGasRequiredForTransaction() {
return result;
}

/**
* Determine if the response can be executed without checking if the offered gas price is at least
* as large as the current gas price. Normally, this only occurs if the consensus
* specifies to ignore the gas price. But this might also be the case for specific calls,
* such as those for creating accounts in the account ledger or for minting and burning coins,
* if the consensus allows it.
*
* @return true if the gas price must be ignored
*/
protected boolean ignoreGasPrice() {
return consensus.ignoresGasPrice();
}

/**
* Extracts the payer from the request. Normally, this is its caller,
* but subclasses might redefine.
*
* @return the payer
*/
protected StorageReference getPayerFromRequest() {
return request.getCaller();
}

/**
* Yields the cost for storage a failed response for the transaction that is being built.
*
Expand Down Expand Up @@ -219,31 +197,6 @@ private void callerMustBeExternallyOwnedAccount() throws TransactionRejectedExce
}
}

/**
* Checks if the payer is a contract or subclass.
*
* @throws TransactionRejectedException if the payer is not a contract
* @throws ClassNotFoundException if the class of the payer cannot be determined
* @throws NodeException
* @throws NoSuchElementException
* @throws UnknownReferenceException
*/
private void payerMustBeContract() throws TransactionRejectedException, ClassNotFoundException, NodeException, UnknownReferenceException {
StorageReference payer = getPayerFromRequest();

if (payer.equals(request.getCaller()))
// if the payer coincides with the caller, as it is normally the case,
// then there is nothing to check, since we know that the caller
// is an externally owned account, hence a contract
return;

// otherwise we check
ClassTag classTag = storeTransaction.getClassTagUncommitted(payer);
Class<?> clazz = classLoader.loadClass(classTag.getClazz().getName());
if (!classLoader.getContract().isAssignableFrom(clazz))
throw new TransactionRejectedException("the payer of a request must be a contract");
}

/**
* Checks that the request is signed with the private key of its caller.
*
Expand Down Expand Up @@ -313,20 +266,11 @@ private void requestPromisesEnoughGas() throws TransactionRejectedException {
*
* @throws TransactionRejectedException if the gas is outside these bounds
*/
private void gasLimitIsInsideBounds() throws TransactionRejectedException {
private void gasLimitIsInsideBounds(BigInteger maxGasAllowedForTransaction) throws TransactionRejectedException {
if (request.getGasLimit().compareTo(ZERO) < 0)
throw new TransactionRejectedException("the gas limit cannot be negative");

BigInteger maxGas;

// view requests have a fixed maximum gas, overriding what is specified in the consensus parameters
if (isView())
maxGas = node.getLocalNodeConfig().getMaxGasPerViewTransaction();
else
maxGas = consensus.getMaxGasPerTransaction();

if (request.getGasLimit().compareTo(maxGas) > 0)
throw new TransactionRejectedException("the gas limit of the request is larger than the maximum allowed (" + request.getGasLimit() + " > " + maxGas + ")");
else if (request.getGasLimit().compareTo(maxGasAllowedForTransaction) > 0)
throw new TransactionRejectedException("the gas limit of the request is larger than the maximum allowed (" + request.getGasLimit() + " > " + maxGasAllowedForTransaction + ")");
}

/**
Expand All @@ -337,7 +281,7 @@ private void gasLimitIsInsideBounds() throws TransactionRejectedException {
private void gasPriceIsLargeEnough() throws TransactionRejectedException {
// before initialization, the gas price is not yet available
try {
if (transactionIsSigned() && storeTransaction.nodeIsInitializedUncommitted() && !ignoreGasPrice()) {
if (transactionIsSigned() && storeTransaction.nodeIsInitializedUncommitted() && !consensus.ignoresGasPrice()) {
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 @@ -356,7 +300,7 @@ private void gasPriceIsLargeEnough() throws TransactionRejectedException {
*/
private void payerCanPayForAllPromisedGas() throws TransactionRejectedException {
BigInteger cost = costOf(request.getGasLimit());
BigInteger totalBalance = storeTransaction.getTotalBalanceUncommitted(getPayerFromRequest());
BigInteger totalBalance = storeTransaction.getTotalBalanceUncommitted(request.getCaller());

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 @@ -95,13 +95,13 @@ public abstract class AbstractResponseBuilder<Request extends TransactionRequest
* @param node the node that is creating the response
* @throws TransactionRejectedException if the builder cannot be created
*/
protected AbstractResponseBuilder(TransactionReference reference, Request request, StoreTransaction<?> storeTransaction, AbstractLocalNodeImpl<?,?> node) throws TransactionRejectedException {
protected AbstractResponseBuilder(TransactionReference reference, Request request, StoreTransaction<?> storeTransaction, ConsensusConfig<?,?> consensus, AbstractLocalNodeImpl<?,?> node) throws TransactionRejectedException {
try {
this.storeTransaction = storeTransaction;
this.request = request;
this.reference = reference;
this.node = node;
this.consensus = node.caches.getConsensusParams();
this.consensus = consensus;
this.classLoader = mkClassLoader();
}
catch (Throwable t) {
Expand Down Expand Up @@ -163,11 +163,6 @@ public abstract class ResponseCreator {
*/
protected final UpdatesExtractorFromRAM updatesExtractor;

/**
* The time of execution of the transaction.
*/
private final long now;

/**
* The counter for the next storage object created during the transaction.
*/
Expand All @@ -177,7 +172,6 @@ protected ResponseCreator() throws TransactionRejectedException {
try {
this.deserializer = new Deserializer(AbstractResponseBuilder.this);
this.updatesExtractor = new UpdatesExtractorFromRAM(AbstractResponseBuilder.this);
this.now = storeTransaction.getNow();
}
catch (Throwable t) {
throw new TransactionRejectedException(t);
Expand Down Expand Up @@ -214,7 +208,7 @@ public final Response create() throws TransactionRejectedException {
* @return the UTC time, as returned by {@link java.lang.System#currentTimeMillis()}
*/
public final long now() {
return now;
return storeTransaction.getNow();
}

/**
Expand Down
Loading

0 comments on commit f2be1f2

Please sign in to comment.