Skip to content

Commit

Permalink
refactor: remove AbortException (#15004)
Browse files Browse the repository at this point in the history
Signed-off-by: lukelee-sl <[email protected]>
  • Loading branch information
lukelee-sl authored Sep 12, 2024
1 parent c518976 commit 7a4616b
Show file tree
Hide file tree
Showing 8 changed files with 146 additions and 172 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,8 @@ public record ContractsConfig(
boolean evmVersionDynamic,
@ConfigProperty(value = "evm.allowCallsToNonContractAccounts", defaultValue = "true") @NetworkProperty
boolean evmAllowCallsToNonContractAccounts,
@ConfigProperty(value = "evm.chargeGasOnPreEvmException", defaultValue = "true") @NetworkProperty
boolean chargeGasOnPreEvmException,
@ConfigProperty(value = "evm.chargeGasOnEvmHandleException", defaultValue = "true") @NetworkProperty
boolean chargeGasOnEvmHandleException,
@ConfigProperty(value = "evm.nonExtantContractsFail", defaultValue = "0") @NetworkProperty
Set<Long> evmNonExtantContractsFail,
@ConfigProperty(value = "evm.version", defaultValue = "v0.50") @NetworkProperty String evmVersion) {}
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@
import static com.hedera.hapi.node.base.ResponseCodeEnum.INVALID_CONTRACT_ID;
import static java.util.Objects.requireNonNull;

import com.hedera.hapi.node.base.AccountID;
import com.hedera.hapi.node.base.ContractID;
import com.hedera.hapi.streams.ContractBytecode;
import com.hedera.node.app.hapi.utils.ethereum.EthTxData;
import com.hedera.node.app.service.contract.impl.annotations.TransactionScope;
import com.hedera.node.app.service.contract.impl.exec.failure.AbortException;
import com.hedera.node.app.service.contract.impl.exec.gas.CustomGasCharging;
import com.hedera.node.app.service.contract.impl.exec.tracers.AddOnEvmActionTracer;
import com.hedera.node.app.service.contract.impl.exec.tracers.EvmActionTracer;
Expand All @@ -33,6 +33,7 @@
import com.hedera.node.app.service.contract.impl.hevm.HederaWorldUpdater;
import com.hedera.node.app.service.contract.impl.hevm.HydratedEthTxData;
import com.hedera.node.app.service.contract.impl.infra.HevmTransactionFactory;
import com.hedera.node.app.service.contract.impl.state.HederaEvmAccount;
import com.hedera.node.app.service.contract.impl.state.RootProxyWorldUpdater;
import com.hedera.node.app.spi.workflows.HandleContext;
import com.hedera.node.app.spi.workflows.HandleException;
Expand Down Expand Up @@ -109,8 +110,12 @@ public CallOutcome call() {
// if an exception occurs during a ContractCall, charge fees to the sender and return a CallOutcome reflecting
// the error.
final var hevmTransaction = safeCreateHevmTransaction();
if (hevmTransaction.isException() && contractsConfig.chargeGasOnPreEvmException()) {
return chargeFeesAndReturnOutcome(hevmTransaction);
if (hevmTransaction.isException()) {
return maybeChargeFeesAndReturnOutcome(
hevmTransaction,
context.body().transactionIDOrThrow().accountIDOrThrow(),
null,
contractsConfig.chargeGasOnEvmHandleException());
}

// Process the transaction and return its outcome
Expand All @@ -135,30 +140,15 @@ public CallOutcome call() {
}
return CallOutcome.fromResultsWithMaybeSidecars(
result.asProtoResultOf(ethTxDataIfApplicable(), rootProxyWorldUpdater), result);
} catch (AbortException e) {
if (e.isChargeable() && contractsConfig.chargeGasOnPreEvmException()) {
gasCharging.chargeGasForAbortedTransaction(
requireNonNull(e.senderId()), hederaEvmContext, rootProxyWorldUpdater, hevmTransaction);
}
// Commit any HAPI fees that were charged before aborting
rootProxyWorldUpdater.commit();

ContractID recipientId = null;
if (!INVALID_CONTRACT_ID.equals(e.getStatus())) {
recipientId = hevmTransaction.contractId();
}

var result = HederaEvmTransactionResult.fromAborted(e.senderId(), recipientId, e.getStatus());

if (context.body().hasEthereumTransaction()) {
final var sender = rootProxyWorldUpdater.getHederaAccount(e.senderId());
if (sender != null) {
result = result.withSignerNonce(sender.getNonce());
}
}

return CallOutcome.fromResultsWithoutSidecars(
result.asProtoResultOf(ethTxDataIfApplicable(), rootProxyWorldUpdater), result);
} catch (HandleException e) {
final var sender = rootProxyWorldUpdater.getHederaAccount(hevmTransaction.senderId());
final var senderId = sender != null ? sender.hederaId() : hevmTransaction.senderId();

return maybeChargeFeesAndReturnOutcome(
hevmTransaction.withException(e),
senderId,
sender,
hevmTransaction.isContractCall() && contractsConfig.chargeGasOnEvmHandleException());
}
}

Expand All @@ -171,16 +161,28 @@ private HederaEvmTransaction safeCreateHevmTransaction() {
}
}

private CallOutcome chargeFeesAndReturnOutcome(@NonNull final HederaEvmTransaction hevmTransaction) {
// If there was an exception while creating the HederaEvmTransaction and the transaction is a ContractCall
// charge fees to the sender and return a CallOutcome reflecting the error.
final var senderId = context.body().transactionIDOrThrow().accountIDOrThrow();
gasCharging.chargeGasForAbortedTransaction(senderId, hederaEvmContext, rootProxyWorldUpdater, hevmTransaction);
private CallOutcome maybeChargeFeesAndReturnOutcome(
@NonNull final HederaEvmTransaction hevmTransaction,
@NonNull final AccountID senderId,
@Nullable final HederaEvmAccount sender,
final boolean chargeGas) {
final var status = requireNonNull(hevmTransaction.exception()).getStatus();
if (chargeGas) {
gasCharging.chargeGasForAbortedTransaction(
senderId, hederaEvmContext, rootProxyWorldUpdater, hevmTransaction);
}
rootProxyWorldUpdater.commit();
final var result = HederaEvmTransactionResult.fromAborted(
senderId,
hevmTransaction.contractId(),
hevmTransaction.exception().getStatus());
ContractID recipientId = null;
if (!INVALID_CONTRACT_ID.equals(status)) {
recipientId = hevmTransaction.contractId();
}

var result = HederaEvmTransactionResult.fromAborted(senderId, recipientId, status);

if (context.body().hasEthereumTransaction() && sender != null) {
result = result.withSignerNonce(sender.getNonce());
}

return CallOutcome.fromResultsWithoutSidecars(
result.asProtoResultOf(ethTxDataIfApplicable(), rootProxyWorldUpdater), result);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
import static com.hedera.hapi.node.base.ResponseCodeEnum.INVALID_ACCOUNT_ID;
import static com.hedera.hapi.node.base.ResponseCodeEnum.INVALID_CONTRACT_ID;
import static com.hedera.hapi.node.base.ResponseCodeEnum.WRONG_NONCE;
import static com.hedera.node.app.service.contract.impl.exec.failure.AbortException.validateTrueOrAbort;
import static com.hedera.node.app.service.contract.impl.hevm.HederaEvmTransactionResult.resourceExhaustionFrom;
import static com.hedera.node.app.service.contract.impl.utils.ConversionUtils.contractIDToBesuAddress;
import static com.hedera.node.app.service.contract.impl.utils.ConversionUtils.isEvmAddress;
Expand All @@ -31,7 +30,6 @@
import com.hedera.hapi.node.base.AccountID;
import com.hedera.hapi.node.base.ResponseCodeEnum;
import com.hedera.hapi.node.contract.ContractCreateTransactionBody;
import com.hedera.node.app.service.contract.impl.exec.failure.AbortException;
import com.hedera.node.app.service.contract.impl.exec.gas.CustomGasCharging;
import com.hedera.node.app.service.contract.impl.exec.processors.CustomMessageCallProcessor;
import com.hedera.node.app.service.contract.impl.exec.utils.FrameBuilder;
Expand All @@ -40,7 +38,6 @@
import com.hedera.node.app.service.contract.impl.hevm.HederaEvmTransactionResult;
import com.hedera.node.app.service.contract.impl.hevm.HederaWorldUpdater;
import com.hedera.node.app.service.contract.impl.state.HederaEvmAccount;
import com.hedera.node.app.spi.workflows.HandleException;
import com.hedera.node.app.spi.workflows.ResourceExhaustedException;
import com.hedera.node.config.data.ContractsConfig;
import com.swirlds.config.api.Configuration;
Expand Down Expand Up @@ -113,7 +110,6 @@ public FeatureFlags featureFlags() {
* @param tracer the tracer to use
* @param config the node configuration
* @return the result of running the transaction to completion
* @throws AbortException if processing failed before initiating the EVM transaction
*/
public HederaEvmTransactionResult processTransaction(
@NonNull final HederaEvmTransaction transaction,
Expand All @@ -123,14 +119,7 @@ public HederaEvmTransactionResult processTransaction(
@NonNull final ActionSidecarContentTracer tracer,
@NonNull final Configuration config) {
final var parties = computeInvolvedPartiesOrAbort(transaction, updater, config);
try {
return processTransactionWithParties(
transaction, updater, feesOnlyUpdater, context, tracer, config, parties);
} catch (HandleException e) {
final var sender = updater.getHederaAccount(transaction.senderId());
final var senderId = sender != null ? sender.hederaId() : transaction.senderId();
throw new AbortException(e.getStatus(), senderId);
}
return processTransactionWithParties(transaction, updater, feesOnlyUpdater, context, tracer, config, parties);
}

private HederaEvmTransactionResult processTransactionWithParties(
Expand Down Expand Up @@ -175,13 +164,7 @@ private InvolvedParties computeInvolvedPartiesOrAbort(
@NonNull final HederaEvmTransaction transaction,
@NonNull final HederaWorldUpdater updater,
@NonNull final Configuration config) {
try {
return computeInvolvedParties(transaction, updater, config);
} catch (AbortException e) {
throw e;
} catch (HandleException e) {
throw new AbortException(e.getStatus(), transaction.senderId(), null, true);
}
return computeInvolvedParties(transaction, updater, config);
}

private HederaEvmTransactionResult safeCommit(
Expand Down Expand Up @@ -243,12 +226,11 @@ private InvolvedParties computeInvolvedParties(
@NonNull final HederaWorldUpdater updater,
@NonNull final Configuration config) {
final var sender = updater.getHederaAccount(transaction.senderId());
validateTrueOrAbort(sender != null, INVALID_ACCOUNT_ID, transaction.senderId());
final var senderId = sender.hederaId();
validateTrue(sender != null, INVALID_ACCOUNT_ID);
HederaEvmAccount relayer = null;
if (transaction.isEthereumTransaction()) {
relayer = updater.getHederaAccount(requireNonNull(transaction.relayerId()));
validateTrueOrAbort(relayer != null, INVALID_ACCOUNT_ID, senderId);
validateTrue(relayer != null, INVALID_ACCOUNT_ID);
}
final InvolvedParties parties;
if (transaction.isCreate()) {
Expand All @@ -270,7 +252,7 @@ private InvolvedParties computeInvolvedParties(
}
}
if (transaction.isEthereumTransaction()) {
validateTrueOrAbort(transaction.nonce() == parties.sender().getNonce(), WRONG_NONCE, senderId);
validateTrue(transaction.nonce() == parties.sender().getNonce(), WRONG_NONCE);
}
return parties;
}
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,6 @@ public boolean isAllowCallsToNonContractAccountsEnabled(

@Override
public boolean isChargeGasOnPreEvmException(@NonNull Configuration config) {
return config.getConfigData(ContractsConfig.class).chargeGasOnPreEvmException();
return config.getConfigData(ContractsConfig.class).chargeGasOnEvmHandleException();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -127,4 +127,23 @@ public long offeredGasCost() {
public boolean requiresFullRelayerAllowance() {
return offeredGasPrice == 0L;
}

/**
* @return a copy of this transaction with the given {@code exception}
*/
public HederaEvmTransaction withException(@NonNull final HandleException exception) {
return new HederaEvmTransaction(
this.senderId,
this.relayerId,
this.contractId,
this.nonce,
this.payload,
this.chainId,
this.value,
this.gasLimit,
this.offeredGasPrice,
this.maxGasAllowance,
this.hapiCreation,
exception);
}
}
Loading

0 comments on commit 7a4616b

Please sign in to comment.