Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add SavepointStack.commit() #7935

Merged
merged 2 commits into from Aug 12, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -473,22 +473,18 @@ interface SavepointStack {
void createSavepoint();

/**
* Rolls back the changes up until the last savepoint.
* Commits all changes since the last savepoint.
*
* @throws IllegalStateException if the savepoint stack is empty
*/
default void rollback() {
rollback(1);
}
void commit();

/**
* Rolls back the last {@code count} savepoints.
* Rolls back the changes up until the last savepoint.
*
* @param count the number of savepoints to roll back
* @throws IllegalArgumentException if {@code count} is less than {@code 1}
* @throws IllegalStateException if the transaction stack contains fewer elements than {@code count}
* @throws IllegalStateException if the savepoint stack is empty
*/
void rollback(int count);
void rollback();

/**
* Returns the depth of the savepoint stack.
Expand Down
Expand Up @@ -114,6 +114,11 @@ public void commit() {
});
}

@Override
public String toString() {
return "MapWritableStates{" + "states=" + states + '}';
}

/**
* Creates a new {@link Builder}.
*
Expand Down
Expand Up @@ -22,6 +22,7 @@
import com.hedera.node.app.service.token.api.TokenServiceApi;
import com.hedera.node.app.spi.api.ServiceApiProvider;
import com.hedera.node.app.workflows.handle.stack.SavepointStackImpl;
import com.swirlds.config.api.Configuration;
import edu.umd.cs.findbugs.annotations.NonNull;
import java.util.Map;

Expand All @@ -30,12 +31,14 @@
*/
public class ServiceApiFactory {
private final SavepointStackImpl stack;
private final Configuration configuration;

private static final Map<Class<?>, ServiceApiProvider<?>> API_PROVIDER =
Map.of(TokenServiceApi.class, TOKEN_SERVICE_API_PROVIDER);

public ServiceApiFactory(@NonNull final SavepointStackImpl stack) {
public ServiceApiFactory(@NonNull final SavepointStackImpl stack, @NonNull final Configuration configuration) {
this.stack = requireNonNull(stack);
this.configuration = requireNonNull(configuration);
}

/**
Expand All @@ -45,9 +48,8 @@ public <C> C getApi(@NonNull final Class<C> apiInterface) throws IllegalArgument
requireNonNull(apiInterface);
final var provider = API_PROVIDER.get(apiInterface);
if (provider != null) {
final var config = stack.peek().configuration();
final var writableStates = stack.createWritableStates(provider.serviceName());
final var api = provider.newInstance(config, writableStates);
final var api = provider.newInstance(configuration, writableStates);
assert apiInterface.isInstance(api); // This needs to be ensured while apis are registered
return apiInterface.cast(api);
}
Expand Down
Expand Up @@ -24,7 +24,6 @@
import com.hedera.node.app.workflows.dispatcher.ReadableStoreFactory;
import com.hedera.node.app.workflows.dispatcher.WritableStoreFactory;
import com.hedera.node.app.workflows.handle.record.SingleTransactionRecordBuilderImpl;
import com.hedera.node.app.workflows.handle.stack.Savepoint;
import com.hedera.node.app.workflows.handle.stack.SavepointStackImpl;
import com.swirlds.config.api.Configuration;
import edu.umd.cs.findbugs.annotations.NonNull;
Expand All @@ -36,9 +35,9 @@
public class FinalizeContextImpl implements FinalizeContext {
private final AccountID payer;
private final SingleTransactionRecordBuilderImpl recordBuilder;
private final SavepointStackImpl stack;
private final Configuration configuration;
private final ReadableStoreFactory readableStoreFactory;
private final WritableStoreFactory writableStoreFactory;
private ReadableStoreFactory readableStoreFactory;

/**
* Constructs a {@link FinalizeContextImpl}.
Expand All @@ -50,17 +49,16 @@ public class FinalizeContextImpl implements FinalizeContext {
public FinalizeContextImpl(
@NonNull final AccountID payer,
@NonNull final SingleTransactionRecordBuilderImpl recordBuilder,
@NonNull final Configuration configuration,
@NonNull final SavepointStackImpl stack) {
this.payer = requireNonNull(payer, "payer must not be null");
this.recordBuilder = requireNonNull(recordBuilder, "recordBuilder must not be null");
this.stack = requireNonNull(stack, "stack must not be null");
this.configuration = requireNonNull(configuration, "configuration must not be null");
requireNonNull(stack, "stack must not be null");
this.readableStoreFactory = new ReadableStoreFactory(stack);
this.writableStoreFactory = new WritableStoreFactory(stack, TokenService.NAME);
}

private Savepoint current() {
return stack.peek();
}

@Override
@NonNull
public Instant consensusNow() {
Expand All @@ -76,14 +74,14 @@ public AccountID payer() {
@Override
@NonNull
public Configuration configuration() {
return current().configuration();
return configuration;
}

@Override
@NonNull
public <C> C readableStore(@NonNull final Class<C> storeInterface) {
requireNonNull(storeInterface, "storeInterface must not be null");
return readableStoreFactory().getStore(storeInterface);
return readableStoreFactory.getStore(storeInterface);
}

@Override
Expand All @@ -108,11 +106,4 @@ private static <T> T castRecordBuilder(
}
return recordBuilderClass.cast(recordBuilder);
}

private ReadableStoreFactory readableStoreFactory() {
if (readableStoreFactory == null) {
readableStoreFactory = new ReadableStoreFactory(stack);
}
return readableStoreFactory;
}
}
Expand Up @@ -49,6 +49,7 @@
import com.hedera.node.app.spi.workflows.PreCheckException;
import com.hedera.node.app.spi.workflows.TransactionKeys;
import com.hedera.node.app.spi.workflows.VerificationAssistant;
import com.hedera.node.app.state.WrappedHederaState;
import com.hedera.node.app.workflows.TransactionChecker;
import com.hedera.node.app.workflows.TransactionInfo;
import com.hedera.node.app.workflows.dispatcher.ReadableStoreFactory;
Expand All @@ -57,7 +58,6 @@
import com.hedera.node.app.workflows.dispatcher.WritableStoreFactory;
import com.hedera.node.app.workflows.handle.record.RecordListBuilder;
import com.hedera.node.app.workflows.handle.record.SingleTransactionRecordBuilderImpl;
import com.hedera.node.app.workflows.handle.stack.Savepoint;
import com.hedera.node.app.workflows.handle.stack.SavepointStackImpl;
import com.hedera.node.app.workflows.handle.validation.AttributeValidatorImpl;
import com.hedera.node.app.workflows.handle.validation.ExpiryValidatorImpl;
Expand Down Expand Up @@ -86,6 +86,7 @@ public class HandleContextImpl implements HandleContext {
private final TransactionCategory category;
private final SingleTransactionRecordBuilderImpl recordBuilder;
private final SavepointStackImpl stack;
private final Configuration configuration;
private final HandleContextVerifier verifier;
private final RecordListBuilder recordListBuilder;
private final TransactionChecker checker;
Expand All @@ -110,10 +111,11 @@ public class HandleContextImpl implements HandleContext {
* @param txInfo The {@link TransactionInfo} of the transaction
* @param payer The {@link AccountID} of the payer
* @param payerKey The {@link Key} of the payer
* @param networkInfo
* @param networkInfo The {@link NetworkInfo} of the network
* @param category The {@link TransactionCategory} of the transaction (either user, preceding, or child)
* @param recordBuilder The main {@link SingleTransactionRecordBuilderImpl}
* @param stack The {@link SavepointStackImpl} used to manage savepoints
* @param configuration The current {@link Configuration}
* @param verifier The {@link HandleContextVerifier} used to verify signatures and hollow accounts
* @param recordListBuilder The {@link RecordListBuilder} used to build the record stream
* @param checker The {@link TransactionChecker} used to check dispatched transaction
Expand All @@ -130,6 +132,7 @@ public HandleContextImpl(
@NonNull final TransactionCategory category,
@NonNull final SingleTransactionRecordBuilderImpl recordBuilder,
@NonNull final SavepointStackImpl stack,
@NonNull final Configuration configuration,
@NonNull final HandleContextVerifier verifier,
@NonNull final RecordListBuilder recordListBuilder,
@NonNull final TransactionChecker checker,
Expand All @@ -146,6 +149,7 @@ public HandleContextImpl(
this.category = requireNonNull(category, "category must not be null");
this.recordBuilder = requireNonNull(recordBuilder, "recordBuilder must not be null");
this.stack = requireNonNull(stack, "stack must not be null");
this.configuration = requireNonNull(configuration, "configuration must not be null");
this.verifier = requireNonNull(verifier, "verifier must not be null");
this.recordListBuilder = requireNonNull(recordListBuilder, "recordListBuilder must not be null");
this.checker = requireNonNull(checker, "checker must not be null");
Expand All @@ -156,12 +160,12 @@ public HandleContextImpl(
this.feeManager = requireNonNull(feeManager, "feeManager must not be null");
this.userTransactionConsensusTime =
requireNonNull(userTransactionConsensusTime, "userTransactionConsensusTime must not be null");
this.feeCalculatorCreator = (subType) -> feeManager.createFeeCalculator(
this.feeCalculatorCreator = subType -> feeManager.createFeeCalculator(
txInfo, payerKey, verifier.numSignaturesVerified(), userTransactionConsensusTime, subType);

final var serviceScope = serviceScopeLookup.getServiceName(txBody);
this.writableStoreFactory = new WritableStoreFactory(stack, serviceScope);
this.serviceApiFactory = new ServiceApiFactory(stack);
this.serviceApiFactory = new ServiceApiFactory(stack, configuration);

final var tokenApi = this.serviceApiFactory.getApi(TokenServiceApi.class);
this.feeAccumulator = new FeeAccumulator() {
Expand All @@ -177,7 +181,7 @@ public void refund(@NonNull AccountID receiver, @NonNull Fees fees) {
};
}

private Savepoint current() {
private WrappedHederaState current() {
return stack.peek();
}

Expand Down Expand Up @@ -220,7 +224,7 @@ public FeeAccumulator feeAccumulator() {
@Override
@NonNull
public Configuration configuration() {
return current().configuration();
return configuration;
}

@Override
Expand Down Expand Up @@ -371,7 +375,7 @@ public <T> T dispatchPrecedingTransaction(
"Cannot dispatch a preceding transaction when a savepoint has been created");
}

if (current().state().isModified()) {
if (current().isModified()) {
throw new IllegalStateException("Cannot dispatch a preceding transaction when the state has been modified");
}

Expand Down Expand Up @@ -458,7 +462,7 @@ private void dispatchSyntheticTxn(
return;
}

final var childStack = new SavepointStackImpl(current().state(), configuration());
final var childStack = new SavepointStackImpl(current());
HederaFunctionality function;
try {
function = functionOf(txBody);
Expand All @@ -476,6 +480,7 @@ private void dispatchSyntheticTxn(
childCategory,
childRecordBuilder,
childStack,
configuration,
childVerifier,
recordListBuilder,
checker,
Expand All @@ -488,8 +493,7 @@ private void dispatchSyntheticTxn(

try {
dispatcher.dispatchHandle(childContext);
stack.configuration(childContext.configuration());
childStack.commit();
childStack.commitFullStack();
} catch (HandleException e) {
childRecordBuilder.status(e.getStatus());
recordListBuilder.revertChildRecordBuilders(recordBuilder);
Expand Down
Expand Up @@ -222,6 +222,7 @@ private void handlePlatformTransaction(

// Setup context
final var stack = new SavepointStackImpl(state, configuration);
final var verifier = new BaseHandleContextVerifier(hederaConfig, preHandleResult.verificationResults());
final var context = new HandleContextImpl(
transactionInfo,
preHandleResult.payer(),
Expand All @@ -230,6 +231,7 @@ private void handlePlatformTransaction(
TransactionCategory.USER,
recordBuilder,
stack,
configuration,
verifier,
recordListBuilder,
checker,
Expand All @@ -249,14 +251,15 @@ private void handlePlatformTransaction(
dispatcher.dispatchHandle(context);

// TODO: Finalize transaction with the help of the token service
final var finalizationContext = new FinalizeContextImpl(preHandleResult.payer(), recordBuilder, stack);
final var finalizationContext =
new FinalizeContextImpl(preHandleResult.payer(), recordBuilder, configuration, stack);
transactionFinalizer.finalizeParentRecord(
finalizationContext, List.of()); // TODO Need actual list of child records?

recordBuilder.status(SUCCESS);

// commit state
stack.commit();
stack.commitFullStack();
} catch (final PreCheckException e) {
recordFailedTransaction(e.responseCode(), recordBuilder, recordListBuilder);
} catch (final HandleException e) {
Expand Down

This file was deleted.