diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/TransactionProcessor.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/TransactionProcessor.java index bd4185478dbf..22064a678bf7 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/TransactionProcessor.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/TransactionProcessor.java @@ -37,6 +37,7 @@ import edu.umd.cs.findbugs.annotations.Nullable; import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.evm.code.CodeFactory; +import org.hyperledger.besu.evm.gascalculator.GasCalculator; import org.hyperledger.besu.evm.processor.ContractCreationProcessor; /** @@ -52,6 +53,7 @@ public class TransactionProcessor { private final ContractCreationProcessor contractCreation; private final FeatureFlags featureFlags; private final CodeFactory codeFactory; + private final GasCalculator gasCalculator; public TransactionProcessor( @NonNull final FrameBuilder frameBuilder, @@ -60,14 +62,16 @@ public TransactionProcessor( @NonNull final CustomMessageCallProcessor messageCall, @NonNull final ContractCreationProcessor contractCreation, @NonNull final FeatureFlags featureFlags, - @NonNull final CodeFactory codeFactory) { + @NonNull final CodeFactory codeFactory, + @NonNull final GasCalculator gasCalculator) { this.frameBuilder = requireNonNull(frameBuilder); this.frameRunner = requireNonNull(frameRunner); this.gasCharging = requireNonNull(gasCharging); this.messageCall = requireNonNull(messageCall); this.contractCreation = requireNonNull(contractCreation); this.featureFlags = requireNonNull(featureFlags); - this.codeFactory = codeFactory; + this.codeFactory = requireNonNull(codeFactory); + this.gasCalculator = requireNonNull(gasCalculator); } /** @@ -129,6 +133,7 @@ private HederaEvmTransactionResult processTransactionWithParties( final var gasCharges = transaction.hookOwnerAddress() != null ? GasCharges.NONE : gasCharging.chargeForGas(parties.sender(), parties.relayer(), context, updater, transaction); + final var initialFrame = frameBuilder.buildInitialFrameWith( transaction, updater, @@ -139,7 +144,8 @@ private HederaEvmTransactionResult processTransactionWithParties( parties.sender().getAddress(), parties.receiverAddress(), gasCharges.intrinsicGas(), - codeFactory); + codeFactory, + gasCalculator); // Compute the result of running the frame to completion final var result = frameRunner.runToCompletion( diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/delegation/CodeDelegationProcessor.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/delegation/CodeDelegationProcessor.java index 1999f75a8786..416871a1627c 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/delegation/CodeDelegationProcessor.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/delegation/CodeDelegationProcessor.java @@ -2,6 +2,7 @@ package com.hedera.node.app.service.contract.impl.exec.delegation; import static org.hyperledger.besu.evm.account.Account.MAX_NONCE; +import static org.hyperledger.besu.evm.worldstate.CodeDelegationHelper.CODE_DELEGATION_PREFIX; import com.hedera.node.app.hapi.utils.ethereum.CodeDelegation; import com.hedera.node.app.hapi.utils.ethereum.EthTxSigs; @@ -28,8 +29,6 @@ public record CodeDelegationProcessor(long chainId) { private static final int MAX_Y_PARITY = 2 ^ 8; - public static final Bytes CODE_DELEGATION_PREFIX = Bytes.fromHexString("ef0100"); - /** The size of the delegated code */ public static final int DELEGATED_CODE_SIZE = CODE_DELEGATION_PREFIX.size() + Address.SIZE; diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/operations/CustomDelegateCallOperation.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/operations/CustomDelegateCallOperation.java index b352c14410fb..e7ccf9b2f205 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/operations/CustomDelegateCallOperation.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/operations/CustomDelegateCallOperation.java @@ -79,6 +79,8 @@ public OperationResult execute(@NonNull final MessageFrame frame, @NonNull final private boolean isRedirectFromNativeEntity(@NonNull final MessageFrame frame) { final var updater = (ProxyWorldUpdater) frame.getWorldUpdater(); final var recipient = requireNonNull(updater.getHederaAccount(frame.getRecipientAddress())); + // TODO(Pectra): update the condition below. Specifically recipient.isRegularAccount() no longer holds. + // Consider adding a frame variable (e.g. isFacadeExecution) or a different mechanism. return recipient.isTokenFacade() || recipient.isScheduleTxnFacade() || recipient.isRegularAccount(); } } diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/processors/CustomMessageCallProcessor.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/processors/CustomMessageCallProcessor.java index e0102df43c35..e3b2251c10a5 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/processors/CustomMessageCallProcessor.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/processors/CustomMessageCallProcessor.java @@ -4,6 +4,7 @@ import static com.hedera.hapi.streams.ContractActionType.PRECOMPILE; import static com.hedera.hapi.streams.ContractActionType.SYSTEM; import static com.hedera.node.app.service.contract.impl.exec.failure.CustomExceptionalHaltReason.*; +import static com.hedera.node.app.service.contract.impl.exec.systemcontracts.HasSystemContract.HAS_EVM_ADDRESS; import static com.hedera.node.app.service.contract.impl.exec.systemcontracts.HtsSystemContract.HTS_HOOKS_CONTRACT_ADDRESS; import static com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.create.CreateCommons.createMethodsSet; import static com.hedera.node.app.service.contract.impl.exec.utils.FrameUtils.*; @@ -19,12 +20,14 @@ import com.hedera.node.app.service.contract.impl.exec.AddressChecks; import com.hedera.node.app.service.contract.impl.exec.FeatureFlags; import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; +import com.hedera.node.app.service.contract.impl.exec.systemcontracts.HasSystemContract; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.HederaSystemContract; import com.hedera.node.app.service.contract.impl.exec.utils.FrameUtils; import com.hedera.node.app.service.contract.impl.state.ProxyEvmContract; import com.hedera.node.app.service.contract.impl.state.ProxyWorldUpdater; +import com.hedera.node.app.service.contract.impl.state.ScheduleEvmAccount; +import com.hedera.node.app.service.contract.impl.state.TokenEvmAccount; import edu.umd.cs.findbugs.annotations.NonNull; -import edu.umd.cs.findbugs.annotations.Nullable; import java.util.Arrays; import java.util.Map; import java.util.Objects; @@ -32,6 +35,7 @@ import org.apache.tuweni.bytes.Bytes; import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.evm.EVM; +import org.hyperledger.besu.evm.account.Account; import org.hyperledger.besu.evm.frame.ExceptionalHaltReason; import org.hyperledger.besu.evm.frame.MessageFrame; import org.hyperledger.besu.evm.operation.Operation; @@ -40,11 +44,12 @@ import org.hyperledger.besu.evm.precompile.PrecompiledContract.PrecompileContractResult; import org.hyperledger.besu.evm.processor.MessageCallProcessor; import org.hyperledger.besu.evm.tracing.OperationTracer; +import org.hyperledger.besu.evm.worldstate.CodeDelegationHelper; /** * A {@link MessageCallProcessor} customized to, *
This method inspects the first four bytes of the input data of the message frame - * to determine if it matches any of the known selectors for creating fungible or non-fungible tokens. - * - * @param frame the message frame to check - * @return true if the input data matches any of the known create selectors, false otherwise - */ - private boolean isTokenCreation(MessageFrame frame) { - if (frame.getInputData().isEmpty()) { - return false; + if (isSystemContractCall(context)) { + handleSystemContractCall(context); + } else if (isPrecompileCall(context)) { + handlePrecompileCall(context); + } else if (addressChecks.isSystemAccount(context.executableCodeAddress)) { + // Handle System Account that is neither System Contract nor Precompile + handleNonExtantSystemAccountCall(context); + } else { + handleRegularCall(context); } - var selector = frame.getInputData().slice(0, 4).toArray(); - return createMethodsSet.stream().anyMatch(s -> Arrays.equals(s.selector(), selector)); } - /** - * @return whether the implicit creation is currently enabled - */ - public boolean isImplicitCreationEnabled() { - return featureFlags.isImplicitCreationEnabled(); - } - - private void handleNonExtantSystemAccount( - @NonNull final MessageFrame frame, @NonNull final OperationTracer tracer) { - final PrecompileContractResult result = PrecompileContractResult.success(Bytes.EMPTY); - frame.clearGasRemaining(); - finishPrecompileExecution(frame, result, PRECOMPILE, (ActionSidecarContentTracer) tracer); + private boolean isSystemContractCall(@NonNull final CustomMessageCallContext context) { + return systemContracts.containsKey(context.executableCodeAddress); } - private void doExecutePrecompile( - @NonNull final PrecompiledContract precompile, - @NonNull final MessageFrame frame, - @NonNull final OperationTracer tracer) { - final var gasRequirement = precompile.gasRequirement(frame.getInputData()); - final PrecompileContractResult result; - if (frame.getRemainingGas() < gasRequirement) { - result = PrecompileContractResult.halt(Bytes.EMPTY, Optional.of(INSUFFICIENT_GAS)); - } else { - frame.decrementRemainingGas(gasRequirement); + private void handleSystemContractCall(@NonNull final CustomMessageCallContext context) { + if (context.isCodeDelegation) { + final var recipientIsTokenOrScheduleAccount = context.contractAccount.stream() + .anyMatch(a -> a instanceof TokenEvmAccount || a instanceof ScheduleEvmAccount); - final var opsDurationCounter = FrameUtils.opsDurationCounter(frame); - final var opsDurationSchedule = opsDurationCounter.schedule(); - final var opsDurationCost = gasRequirement - * opsDurationSchedule.precompileGasBasedDurationMultiplier() - / opsDurationSchedule.multipliersDenominator(); - opsDurationCounter.recordOpsDurationUnitsConsumed(opsDurationCost); - contractMetrics.opsDurationMetrics().recordPrecompileOpsDuration(precompile.getName(), opsDurationCost); + if (recipientIsTokenOrScheduleAccount) { + // Token and Schedule accounts are allowed to delegate code to an actual System Contract call, + // but value transfer isn't allowed. + if (context.transfersValue) { + doHalt(context, INVALID_CONTRACT_ID); + } else { + doExecuteSystemContract(context, systemContracts.get(context.executableCodeAddress)); + } + } else { + // For any other Hedera accounts: code delegation to System Contracts is a no-op - so just succeed. + context.frame.setState(MessageFrame.State.CODE_SUCCESS); - result = precompile.computePrecompile(frame.getInputData(), frame); - if (result.isRefundGas()) { - frame.incrementRemainingGas(gasRequirement); + // Even though execution is no-op, the call may still carry value transfer. + if (context.transfersValue) { + doTransferValueOrHalt(context); + } } + } else if (context.transfersValue && !isTokenCreation(context.frame)) { + // System Contract calls that transfer value aren't allowed, unless they're token creation. + doHalt(context, INVALID_CONTRACT_ID); + } else { + doExecuteSystemContract(context, systemContracts.get(context.executableCodeAddress)); } - // We must always call tracePrecompileResult() to ensure the tracer is in a consistent - // state, because AbstractMessageProcessor.process() will not invoke the tracer's - // tracePostExecution() method unless start() returns with a state of CODE_EXECUTING; - // but for a precompile call this never happens. - finishPrecompileExecution(frame, result, PRECOMPILE, (ActionSidecarContentTracer) tracer); } /** @@ -246,15 +221,13 @@ private void doExecutePrecompile( * the call to computePrecompile. Thus, the logic for checking for sufficient gas must be done in a different * order vs normal precompiles. * + * @param context the current call context * @param systemContract the system contract to execute - * @param frame the current frame - * @param tracer the operation tracer */ private void doExecuteSystemContract( - @NonNull final HederaSystemContract systemContract, - @NonNull final Address systemContractAddress, - @NonNull final MessageFrame frame, - @NonNull final OperationTracer tracer) { + @NonNull final CustomMessageCallContext context, @NonNull final HederaSystemContract systemContract) { + final var frame = context.frame; + final var systemContractAddress = context.executableCodeAddress; final var fullResult = systemContract.computeFully( ContractID.newBuilder() .contractNum(numberOfLongZero(systemContractAddress)) @@ -283,14 +256,14 @@ private void doExecuteSystemContract( result = fullResult.result(); } - finishPrecompileExecution(frame, result, SYSTEM, (ActionSidecarContentTracer) tracer); + finishPrecompileExecution(context, result, SYSTEM); } private void finishPrecompileExecution( - @NonNull final MessageFrame frame, + @NonNull final CustomMessageCallContext context, @NonNull final PrecompileContractResult result, - @NonNull final ContractActionType type, - @NonNull final ActionSidecarContentTracer tracer) { + @NonNull final ContractActionType type) { + final var frame = context.frame; if (result.state() == MessageFrame.State.REVERT) { frame.setRevertReason(result.output()); } else { @@ -298,16 +271,147 @@ private void finishPrecompileExecution( } frame.setState(result.state()); frame.setExceptionalHaltReason(result.haltReason()); - tracer.tracePrecompileResult(frame, type); + ((ActionSidecarContentTracer) context.tracer).tracePrecompileResult(frame, type); } - private void doTransferValueOrHalt( - @NonNull final MessageFrame frame, @NonNull final OperationTracer operationTracer) { + private boolean isPrecompileCall(@NonNull final CustomMessageCallContext context) { + final var evmPrecompile = precompiles.get(context.executableCodeAddress); + return evmPrecompile != null && isPrecompileEnabled(context.executableCodeAddress, context.frame); + } + + private void handlePrecompileCall(@NonNull final CustomMessageCallContext context) { + final var evmPrecompile = precompiles.get(context.executableCodeAddress); + + if (context.isCodeDelegation) { + // Code delegation to Precompile is a no-op - so just succeed. + context.frame.setState(MessageFrame.State.CODE_SUCCESS); + // Even though execution is no-op, the call may still carry value transfer. + if (context.transfersValue) { + doTransferValueOrHalt(context); + } + } else if (context.transfersValue) { + // Value transfer isn't allowed for precompile calls. + doHalt(context, INVALID_CONTRACT_ID); + } else { + doExecutePrecompile(context, evmPrecompile); + } + } + + private void doExecutePrecompile( + @NonNull final CustomMessageCallContext context, @NonNull final PrecompiledContract precompile) { + final var frame = context.frame; + final var gasRequirement = precompile.gasRequirement(frame.getInputData()); + final PrecompileContractResult result; + if (frame.getRemainingGas() < gasRequirement) { + result = PrecompileContractResult.halt(Bytes.EMPTY, Optional.of(INSUFFICIENT_GAS)); + } else { + frame.decrementRemainingGas(gasRequirement); + + final var opsDurationCounter = FrameUtils.opsDurationCounter(frame); + final var opsDurationSchedule = opsDurationCounter.schedule(); + final var opsDurationCost = gasRequirement + * opsDurationSchedule.precompileGasBasedDurationMultiplier() + / opsDurationSchedule.multipliersDenominator(); + opsDurationCounter.recordOpsDurationUnitsConsumed(opsDurationCost); + contractMetrics.opsDurationMetrics().recordPrecompileOpsDuration(precompile.getName(), opsDurationCost); + + result = precompile.computePrecompile(frame.getInputData(), frame); + if (result.isRefundGas()) { + frame.incrementRemainingGas(gasRequirement); + } + } + // We must always call tracePrecompileResult() to ensure the tracer is in a consistent + // state, because AbstractMessageProcessor.process() will not invoke the tracer's + // tracePostExecution() method unless start() returns with a state of CODE_EXECUTING; + // but for a precompile call this never happens. + finishPrecompileExecution(context, result, PRECOMPILE); + } + + private void handleNonExtantSystemAccountCall(CustomMessageCallContext context) { + if (context.isCodeDelegation) { + // Code delegation is a no-op - so just succeed. + context.frame.setState(MessageFrame.State.CODE_SUCCESS); + // Even though execution is no-op, the call may still carry value transfer. + if (context.transfersValue) { + doTransferValueOrHalt(context); + } + } else if (isAllowanceHook(context.frame, context.executableCodeAddress)) { + // Allowance hook execution is explicitly allowed + context.frame.setState(MessageFrame.State.CODE_EXECUTING); + } else if (context.transfersValue) { + doHalt(context, INVALID_CONTRACT_ID); + } else { + final var result = PrecompileContractResult.success(Bytes.EMPTY); + context.frame.clearGasRemaining(); + finishPrecompileExecution(context, result, PRECOMPILE); + } + } + + private void handleRegularCall(@NonNull final CustomMessageCallContext context) { + if (context.transfersValue) { + doTransferValueOrHalt(context); + if (alreadyHalted(context.frame)) { + return; + } + } + + // For mono-service fidelity, we need to consider called contracts + // as a special case eligible for staking rewards + if (isTopLevelTransaction(context.frame)) { + context.contractAccount + .filter(ProxyEvmContract.class::isInstance) + .map(ProxyEvmContract.class::cast) + .ifPresent(contract -> + recordBuilderFor(context.frame).trackExplicitRewardSituation(contract.hederaId())); + } + + context.frame.setState(MessageFrame.State.CODE_EXECUTING); + } + + /** + * Checks if the message frame is executing a hook dispatch and if the contract address is + * the allowance hook address + * + * @param codeAddress the address of the precompile to check + * @param frame the current message frame + * @return true if the frame is executing a hook dispatch and the code address is the allowance hook + * address, false otherwise + */ + private static boolean isAllowanceHook(final @NonNull MessageFrame frame, final Address codeAddress) { + return FrameUtils.isHookExecution(frame) && HTS_HOOKS_CONTRACT_ADDRESS.equals(codeAddress); + } + + /** + * Checks if the given message frame is a token creation scenario. + * + *
This method inspects the first four bytes of the input data of the message frame
+ * to determine if it matches any of the known selectors for creating fungible or non-fungible tokens.
+ *
+ * @param frame the message frame to check
+ * @return true if the input data matches any of the known create selectors, false otherwise
+ */
+ private boolean isTokenCreation(MessageFrame frame) {
+ if (frame.getInputData().isEmpty()) {
+ return false;
+ }
+ final var selector = frame.getInputData().slice(0, 4).toArray();
+ return createMethodsSet.stream().anyMatch(s -> Arrays.equals(s.selector(), selector));
+ }
+
+ /**
+ * @return whether the implicit creation is currently enabled
+ */
+ public boolean isImplicitCreationEnabled() {
+ return featureFlags.isImplicitCreationEnabled();
+ }
+
+ private void doTransferValueOrHalt(@NonNull final CustomMessageCallContext context) {
+ final var frame = context.frame;
final var proxyWorldUpdater = (ProxyWorldUpdater) frame.getWorldUpdater();
// Try to lazy-create the recipient address if it doesn't exist
if (!addressChecks.isPresent(frame.getRecipientAddress(), frame)) {
final var maybeReasonToHalt = proxyWorldUpdater.tryLazyCreation(frame.getRecipientAddress(), frame);
- maybeReasonToHalt.ifPresent(reason -> doHaltOnFailedLazyCreation(frame, reason, operationTracer));
+ maybeReasonToHalt.ifPresent(reason -> doHaltOnFailedLazyCreation(context, reason));
}
if (!alreadyHalted(frame)) {
final var maybeReasonToHalt = proxyWorldUpdater.tryTransfer(
@@ -319,37 +423,25 @@ private void doTransferValueOrHalt(
if (reason == INVALID_SIGNATURE) {
setPropagatedCallFailure(frame, MISSING_RECEIVER_SIGNATURE);
}
- doHalt(frame, reason, operationTracer);
+ doHalt(context, reason);
});
}
}
- private void doHaltIfInvalidSystemCall(
- @NonNull final MessageFrame frame, @NonNull final OperationTracer operationTracer) {
- if (transfersValue(frame)) {
- doHalt(frame, INVALID_CONTRACT_ID, operationTracer);
- }
- }
-
private void doHaltOnFailedLazyCreation(
- @NonNull final MessageFrame frame,
- @NonNull final ExceptionalHaltReason reason,
- @NonNull final OperationTracer tracer) {
- doHalt(frame, reason, tracer, ForLazyCreation.YES);
+ @NonNull final CustomMessageCallContext context, @NonNull final ExceptionalHaltReason reason) {
+ doHalt(context, reason, ForLazyCreation.YES);
}
- private void doHalt(
- @NonNull final MessageFrame frame,
- @NonNull final ExceptionalHaltReason reason,
- @NonNull final OperationTracer tracer) {
- doHalt(frame, reason, tracer, ForLazyCreation.NO);
+ private void doHalt(@NonNull final CustomMessageCallContext context, @NonNull final ExceptionalHaltReason reason) {
+ doHalt(context, reason, ForLazyCreation.NO);
}
private void doHalt(
- @NonNull final MessageFrame frame,
+ @NonNull final CustomMessageCallContext context,
@NonNull final ExceptionalHaltReason reason,
- @Nullable final OperationTracer operationTracer,
@NonNull final ForLazyCreation forLazyCreation) {
+ final var frame = context.frame;
frame.setState(EXCEPTIONAL_HALT);
frame.setExceptionalHaltReason(Optional.of(reason));
if (forLazyCreation == ForLazyCreation.YES) {
@@ -358,13 +450,10 @@ private void doHalt(
setPropagatedCallFailure(frame, RESULT_CANNOT_BE_EXTERNALIZED);
}
}
- if (operationTracer != null) {
- if (forLazyCreation == ForLazyCreation.YES) {
- operationTracer.traceAccountCreationResult(frame, Optional.of(reason));
- } else {
- operationTracer.tracePostExecution(
- frame, new Operation.OperationResult(frame.getRemainingGas(), reason));
- }
+ if (forLazyCreation == ForLazyCreation.YES) {
+ context.tracer.traceAccountCreationResult(frame, Optional.of(reason));
+ } else {
+ context.tracer.tracePostExecution(frame, new Operation.OperationResult(frame.getRemainingGas(), reason));
}
}
}
diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/HasSystemContract.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/HasSystemContract.java
index 63b1522b3d32..8701918de6c8 100644
--- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/HasSystemContract.java
+++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/HasSystemContract.java
@@ -14,6 +14,7 @@
import com.hedera.node.app.service.contract.impl.exec.utils.FrameUtils;
import com.hedera.node.app.service.contract.impl.exec.utils.FrameUtils.EntityType;
import edu.umd.cs.findbugs.annotations.NonNull;
+import java.util.Set;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.apache.tuweni.bytes.Bytes;
@@ -30,6 +31,20 @@ public class HasSystemContract extends AbstractNativeSystemContract implements H
.contractNum(numberOfLongZero(Address.fromHexString(HAS_EVM_ADDRESS)))
.build();
+ /**
+ * A set of call data prefixes (i.e. function selectors in the realm of Solidity)
+ * that are eligible for proxy redirection to the Hedera Account Service system contract.
+ */
+ private static final Set Since a {@link TokenEvmAccount} never needs its Hedera entity number, we may as well use
- * the long-zero address there, and here.
- *
- * @param address the token long-zero address
- * @return the redirect code for the token
- */
- @NonNull
- Bytes getTokenRedirectCode(@NonNull Address address);
-
/**
* @param contractID the contract to extract its code hash
* @return the code hash of the contract
@@ -206,57 +195,6 @@ void trackSelfDestructBeneficiary(
@NonNull
Hash getCodeHash(ContractID contractID, @NonNull final CodeFactory codeFactory);
- /**
- * Returns the hash of the redirect bytecode for the token with the given address, which must be a
- * long-zero address.
- *
- * Since a {@link TokenEvmAccount} never needs its Hedera entity number, we may as well use
- * the long-zero address there, and here.
- *
- * @param address the token long-zero address
- * @return the redirect code for the token
- */
- @NonNull
- Hash getTokenRedirectCodeHash(@NonNull Address address);
-
- /**
- * Returns the redirect bytecode for the account with the given address. This should only be called for regular accounts
- * that are not contracts.
- *
- * @param address the account address
- * @return the redirect code for the account
- */
- @NonNull
- Bytes getAccountRedirectCode(@Nullable Address address);
-
- /**
- * Returns the hash of the redirect bytecode for the account with the given address.
- *
- * @param address the account address
- * @return the redirect code for the account
- */
- @NonNull
- Hash getAccountRedirectCodeHash(@Nullable Address address);
-
- /**
- * Returns the redirect bytecode for the schedule with the given address. This should only be called for schedule
- * transaction entities
- *
- * @param address the schedule address
- * @return the redirect code for the schedule
- */
- @NonNull
- Bytes getScheduleRedirectCode(@Nullable Address address);
-
- /**
- * Returns the hash of the redirect bytecode for the schedule with the given address.
- *
- * @param address the schedule address
- * @return the redirect code for the schedule
- */
- @NonNull
- Hash getScheduleRedirectCodeHash(@Nullable Address address);
-
/**
* Returns the native account with the given account id.
*
diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/state/HederaEvmAccount.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/state/HederaEvmAccount.java
index 301b722ede7a..ed9e8dc3e7d9 100644
--- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/state/HederaEvmAccount.java
+++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/state/HederaEvmAccount.java
@@ -4,11 +4,7 @@
import com.hedera.hapi.node.base.AccountID;
import com.hedera.hapi.node.base.ContractID;
import edu.umd.cs.findbugs.annotations.NonNull;
-import org.apache.tuweni.bytes.Bytes;
-import org.hyperledger.besu.evm.Code;
-import org.hyperledger.besu.evm.account.Account;
import org.hyperledger.besu.evm.account.MutableAccount;
-import org.hyperledger.besu.evm.code.CodeFactory;
/**
* A Hedera specialization of a Besu {@link MutableAccount} that provides additional Hedera-specific information.
@@ -58,20 +54,4 @@ public interface HederaEvmAccount extends MutableAccount {
*/
@NonNull
ContractID hederaContractId();
-
- /**
- * Returns the EVM code for this account. Added here to avoid client code needing to manage a
- * cache of {@link org.hyperledger.besu.evm.Code} wrappers around raw bytecode returned by
- * {@link Account#getCode()}.
- *
- * @param functionSelector the function selector to use when fetching the code. If more than 4 bytes for the
- * function selector is passed in, only the first 4 bytes will be used.
- * Only relevant for regular accounts.
- *
- * @param codeFactory the factory used to construct an instance of {@link org.hyperledger.besu.evm.Code}
- * * from the raw bytecode associated with this account.
- * @return the EVM code for this account
- */
- @NonNull
- Code getEvmCode(@NonNull final Bytes functionSelector, @NonNull CodeFactory codeFactory);
}
diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/state/ProxyEvmAccount.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/state/ProxyEvmAccount.java
index 6388e77dbc96..bb7c8f1892b9 100644
--- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/state/ProxyEvmAccount.java
+++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/state/ProxyEvmAccount.java
@@ -1,66 +1,33 @@
// SPDX-License-Identifier: Apache-2.0
package com.hedera.node.app.service.contract.impl.state;
-import static com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.AbstractNativeSystemContract.FUNCTION_SELECTOR_LENGTH;
-
import com.hedera.hapi.node.base.AccountID;
import edu.umd.cs.findbugs.annotations.NonNull;
-import edu.umd.cs.findbugs.annotations.Nullable;
-import java.util.Set;
import org.apache.tuweni.bytes.Bytes;
-import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
-import org.hyperledger.besu.evm.Code;
import org.hyperledger.besu.evm.code.CodeFactory;
/**
- * A concrete subclass of {@link AbstractProxyEvmAccount} that represents a contract account.
- *
- * Responsible for retrieving the redirectForAccount proxy contract byte code from {@link EvmFrameState}
- * if the function selector is eligible for proxy redirection.
- * Otherwise, it returns the 0x bytecode.
- *
+ * A concrete subclass of {@link AbstractProxyEvmAccount} that represents a regular account.
+ * Responsible for retrieving the code (either EIP-7702 delegation indicator or empty)
+ * from the {@link EvmFrameState}.
*/
public class ProxyEvmAccount extends AbstractProxyEvmAccount {
+ private final CodeFactory codeFactory;
- /*
- * Four byte function selectors for the functions that are eligible for proxy redirection
- * in the Hedera Account Service system contract
- */
- private static final Set
- * Responsible for retrieving the contract byte code from the {@link EvmFrameState}
+ * Responsible for retrieving the contract byte code from the {@link EvmFrameState}.
*/
public class ProxyEvmContract extends AbstractProxyEvmAccount {
@@ -23,11 +21,6 @@ public ProxyEvmContract(
this.codeFactory = codeFactory;
}
- @Override
- public @NonNull Code getEvmCode(@NonNull final Bytes functionSelector, @NonNull final CodeFactory codeFactory) {
- return codeFactory.createCode(getCode(), false);
- }
-
@Override
public @NonNull Bytes getCode() {
return state.getCode(hederaContractId());
diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/state/ScheduleEvmAccount.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/state/ScheduleEvmAccount.java
index e6534dd865d4..5f8330790e94 100644
--- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/state/ScheduleEvmAccount.java
+++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/state/ScheduleEvmAccount.java
@@ -1,20 +1,19 @@
// SPDX-License-Identifier: Apache-2.0
package com.hedera.node.app.service.contract.impl.state;
-import static com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.AbstractNativeSystemContract.FUNCTION_SELECTOR_LENGTH;
+import static com.hedera.node.app.service.contract.impl.exec.systemcontracts.HssSystemContract.HSS_EVM_ADDRESS;
+import static org.hyperledger.besu.crypto.Hash.keccak256;
+import static org.hyperledger.besu.evm.worldstate.CodeDelegationHelper.CODE_DELEGATION_PREFIX;
import edu.umd.cs.findbugs.annotations.NonNull;
-import java.util.Set;
import org.apache.tuweni.bytes.Bytes;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
-import org.hyperledger.besu.evm.Code;
import org.hyperledger.besu.evm.account.Account;
import org.hyperledger.besu.evm.account.MutableAccount;
-import org.hyperledger.besu.evm.code.CodeFactory;
/**
- * An {@link Account} whose code proxies all calls to the {@code 0x16b} system contract, and thus can
+ * An {@link Account} whose code is an EIP-7702 delegation to the {@code 0x16b} system contract, and thus can
* never change its storage or nonce.
*
* It also cannot have a non-zero balance, as dispatching a {@code transferValue()} with a schedule
@@ -27,25 +26,14 @@
*/
public class ScheduleEvmAccount extends AbstractEvmEntityAccount {
- /*
- * Four byte function selectors for the functions that are eligible for proxy redirection
- * in the Hedera Schedule Service system contract
- */
- private static final Set It also cannot have a non-zero balance, as dispatching a {@code transferValue()} with a token
@@ -24,13 +26,15 @@
*/
public class TokenEvmAccount extends AbstractEvmEntityAccount {
+ // EIP-7702 delegation to HTS system contract
+ public static final Bytes CODE =
+ Bytes.concatenate(CODE_DELEGATION_PREFIX, Address.fromHexString(HTS_167_EVM_ADDRESS));
+ public static final Hash CODE_HASH = Hash.wrap(keccak256(CODE));
+
public TokenEvmAccount(@NonNull final Address address, @NonNull final EvmFrameState state) {
super(address, state);
}
- /**
- * {@inheritDoc}
- */
@Override
public boolean isTokenFacade() {
return true;
@@ -38,16 +42,11 @@ public boolean isTokenFacade() {
@Override
public Bytes getCode() {
- return state.getTokenRedirectCode(address);
- }
-
- @Override
- public @NonNull Code getEvmCode(@NonNull final Bytes functionSelector, @NonNull final CodeFactory codeFactory) {
- return codeFactory.createCode(getCode(), false);
+ return CODE;
}
@Override
public Hash getCodeHash() {
- return state.getTokenRedirectCodeHash(address);
+ return CODE_HASH;
}
}
diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/state/hooks/ProxyEvmHook.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/state/hooks/ProxyEvmHook.java
index 4481d8fddca3..a681b2dc5fb2 100644
--- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/state/hooks/ProxyEvmHook.java
+++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/state/hooks/ProxyEvmHook.java
@@ -14,10 +14,8 @@
import com.hedera.node.app.service.entityid.EntityIdFactory;
import edu.umd.cs.findbugs.annotations.NonNull;
import org.apache.tuweni.bytes.Bytes;
-import org.apache.tuweni.units.bigints.UInt256;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
-import org.hyperledger.besu.evm.Code;
import org.hyperledger.besu.evm.code.CodeFactory;
/**
@@ -49,11 +47,6 @@ public ProxyEvmHook(
this.entityIdFactory = requireNonNull(entityIdFactory);
}
- @Override
- public @NonNull Code getEvmCode(@NonNull final Bytes functionSelector, @NonNull final CodeFactory codeFactory) {
- return codeFactory.createCode(getCode(), false);
- }
-
@Override
public Address getAddress() {
return HTS_HOOKS_CONTRACT_ADDRESS;
@@ -75,11 +68,6 @@ public ContractID hederaContractId() {
return state.getCodeHash(hookState.hookContractIdOrThrow(), codeFactory);
}
- @Override
- public @NonNull UInt256 getStorageValue(@NonNull final UInt256 key) {
- return state.getStorageValue(entityIdFactory.newContractId(HTS_HOOKS_CONTRACT_NUM), key);
- }
-
@NonNull
private static AccountID getOwnerId(final @NonNull HookId hookId) {
// We always use account id for hook owner internally
diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/utils/RedirectBytecodeUtils.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/utils/RedirectBytecodeUtils.java
deleted file mode 100644
index 93c982abd3dd..000000000000
--- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/utils/RedirectBytecodeUtils.java
+++ /dev/null
@@ -1,95 +0,0 @@
-// SPDX-License-Identifier: Apache-2.0
-package com.hedera.node.app.service.contract.impl.utils;
-
-import static java.util.Objects.requireNonNull;
-
-import edu.umd.cs.findbugs.annotations.NonNull;
-import edu.umd.cs.findbugs.annotations.Nullable;
-import org.apache.tuweni.bytes.Bytes;
-import org.hyperledger.besu.datatypes.Address;
-
-public class RedirectBytecodeUtils {
-
- private static final String ADDRESS_BYTECODE_PATTERN = "fefefefefefefefefefefefefefefefefefefefe";
-
- public static final String PROXY_PRE_BYTES = "6080604052348015600f57600080fd5b50600061";
- public static final String PROXY_MID_BYTES = "905077";
- private static final String PROXY_POST_BYTES =
- ADDRESS_BYTECODE_PATTERN + "600052366000602037600080366018016008845af43d806000803e8160008114"
- + "605857816000f35b816000fdfea2646970667358221220d8378feed472ba49a0"
- + "005514ef7087017f707b45fb9bf56bb81bb93ff19a238b64736f6c634300080b0033";
-
- // The following hex string is created by compiling the contract defined in HIP-719.
- // (https://hips.hedera.com/hip/hip-719). The only exception is that the function selector for `redirectForToken`
- // (0x618dc65e)
- // has been pre substituted before the ADDRESS_BYTECODE_PATTERN.
- private static final String TOKEN_CALL_REDIRECT_CONTRACT_BINARY = PROXY_PRE_BYTES
- + "0167" // System contract address for HTS
- + PROXY_MID_BYTES
- + "618dc65e" // function selector for `redirectForToken`
- + PROXY_POST_BYTES;
-
- // The following byte code is created by compiling the contract defined in HIP-906
- // (https://hips.hedera.com/hip/hip-906). The only exception is that the function selector for `redirectForAccount`
- // (0xe4cbd3a7)
- // has been pre substituted before the ADDRESS_BYTECODE_PATTERN.
- private static final String ACCOUNT_CALL_REDIRECT_CONTRACT_BINARY = PROXY_PRE_BYTES
- + "016a" // System contract address for HAS
- + PROXY_MID_BYTES
- + "e4cbd3a7" // function selector for `redirectForAccount`
- + PROXY_POST_BYTES;
-
- // The following byte code is copied from the `redirectForToken` and `redirectForAccount` contract defined above.
- // The only exception is that the function selector for `redirectForScheduleTxn` (0x5c3889ca)
- // has been pre substituted before the ADDRESS_BYTECODE_PATTERN.
- private static final String SCHEDULE_CALL_REDIRECT_CONTRACT_BINARY = PROXY_PRE_BYTES
- + "016b" // System contract address for HSS
- + PROXY_MID_BYTES
- + "5c3889ca" // function selector for `redirectForScheduleTxn`
- + PROXY_POST_BYTES;
-
- private RedirectBytecodeUtils() {
- throw new UnsupportedOperationException("Utility Class");
- }
-
- public static Bytes tokenProxyBytecodeFor(@NonNull final Address address) {
- requireNonNull(address);
- return Bytes.fromHexString(
- TOKEN_CALL_REDIRECT_CONTRACT_BINARY.replace(ADDRESS_BYTECODE_PATTERN, address.toUnprefixedHexString()));
- }
-
- public static com.hedera.pbj.runtime.io.buffer.Bytes tokenProxyBytecodePjb(@Nullable final Address address) {
- return address == null
- ? com.hedera.pbj.runtime.io.buffer.Bytes.EMPTY
- : com.hedera.pbj.runtime.io.buffer.Bytes.fromHex(TOKEN_CALL_REDIRECT_CONTRACT_BINARY.replace(
- ADDRESS_BYTECODE_PATTERN, address.toUnprefixedHexString()));
- }
-
- public static Bytes accountProxyBytecodeFor(@Nullable final Address address) {
- return address == null
- ? Bytes.EMPTY
- : Bytes.fromHexString(ACCOUNT_CALL_REDIRECT_CONTRACT_BINARY.replace(
- ADDRESS_BYTECODE_PATTERN, address.toUnprefixedHexString()));
- }
-
- public static com.hedera.pbj.runtime.io.buffer.Bytes accountProxyBytecodePjb(@Nullable final Address address) {
- return address == null
- ? com.hedera.pbj.runtime.io.buffer.Bytes.EMPTY
- : com.hedera.pbj.runtime.io.buffer.Bytes.fromHex(ACCOUNT_CALL_REDIRECT_CONTRACT_BINARY.replace(
- ADDRESS_BYTECODE_PATTERN, address.toUnprefixedHexString()));
- }
-
- public static Bytes scheduleProxyBytecodeFor(@Nullable final Address address) {
- return address == null
- ? Bytes.EMPTY
- : Bytes.fromHexString(SCHEDULE_CALL_REDIRECT_CONTRACT_BINARY.replace(
- ADDRESS_BYTECODE_PATTERN, address.toUnprefixedHexString()));
- }
-
- public static com.hedera.pbj.runtime.io.buffer.Bytes scheduleProxyBytecodePjb(@Nullable final Address address) {
- return address == null
- ? com.hedera.pbj.runtime.io.buffer.Bytes.EMPTY
- : com.hedera.pbj.runtime.io.buffer.Bytes.fromHex(SCHEDULE_CALL_REDIRECT_CONTRACT_BINARY.replace(
- ADDRESS_BYTECODE_PATTERN, address.toUnprefixedHexString()));
- }
-}
diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/module-info.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/module-info.java
index b04c9c753404..971a5f149a6c 100644
--- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/module-info.java
+++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/module-info.java
@@ -6,7 +6,6 @@
requires transitive com.hedera.node.app.hapi.fees;
requires transitive com.hedera.node.app.hapi.utils;
requires transitive com.hedera.node.app.service.contract;
- requires transitive com.hedera.node.app.service.entityid;
requires transitive com.hedera.node.app.service.file;
requires transitive com.hedera.node.app.service.schedule;
requires transitive com.hedera.node.app.service.token;
diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/TestHelpers.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/TestHelpers.java
index a9281f5c5263..e4903b81ee52 100644
--- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/TestHelpers.java
+++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/TestHelpers.java
@@ -113,6 +113,7 @@
import org.hyperledger.besu.evm.Code;
import org.hyperledger.besu.evm.code.CodeFactory;
import org.hyperledger.besu.evm.frame.MessageFrame;
+import org.hyperledger.besu.evm.gascalculator.GasCalculator;
import org.hyperledger.besu.evm.log.Log;
import org.hyperledger.besu.evm.log.LogTopic;
import org.hyperledger.besu.evm.operation.Operation;
@@ -529,6 +530,7 @@ public class TestHelpers {
List.of(new ContractNonceInfo(CALLED_CONTRACT_ID, NONCE), new ContractNonceInfo(CHILD_CONTRACT_ID, 1L));
public static final EntityNumber CALLED_CONTRACT_ENTITY_NUMBER = new EntityNumber(666);
public static final CodeFactory CODE_FACTORY = new CodeFactory(0, 0);
+ public static final GasCalculator GAS_CALCULATOR = new HederaGasCalculatorImpl();
public static final Code CONTRACT_CODE = CODE_FACTORY.createCode(pbjToTuweniBytes(CALL_DATA), false);
public static final Log BESU_LOG = new Log(
NON_SYSTEM_LONG_ZERO_ADDRESS,
@@ -947,7 +949,7 @@ public static org.apache.tuweni.bytes.Bytes bytesForRedirect(
public static org.apache.tuweni.bytes.Bytes bytesForRedirect(final byte[] subSelector, final Address tokenAddress) {
return org.apache.tuweni.bytes.Bytes.concatenate(
- org.apache.tuweni.bytes.Bytes.wrap(HtsCallAttempt.REDIRECT_FOR_TOKEN.selector()),
+ org.apache.tuweni.bytes.Bytes.wrap(HtsCallAttempt.LEGACY_REDIRECT_FOR_TOKEN.selector()),
tokenAddress,
org.apache.tuweni.bytes.Bytes.of(subSelector));
}
@@ -962,7 +964,7 @@ public static org.apache.tuweni.bytes.Bytes bytesForRedirectAccount(
public static org.apache.tuweni.bytes.Bytes bytesForRedirectAccount(
final byte[] subSelector, final Address accountAddress) {
return org.apache.tuweni.bytes.Bytes.concatenate(
- org.apache.tuweni.bytes.Bytes.wrap(HasCallAttempt.REDIRECT_FOR_ACCOUNT.selector()),
+ org.apache.tuweni.bytes.Bytes.wrap(HasCallAttempt.LEGACY_REDIRECT_FOR_ACCOUNT.selector()),
accountAddress,
org.apache.tuweni.bytes.Bytes.of(subSelector));
}
@@ -970,7 +972,7 @@ public static org.apache.tuweni.bytes.Bytes bytesForRedirectAccount(
public static org.apache.tuweni.bytes.Bytes bytesForRedirectScheduleTxn(
final byte[] subSelector, final Address scheduleAddress) {
return org.apache.tuweni.bytes.Bytes.concatenate(
- org.apache.tuweni.bytes.Bytes.wrap(HssCallAttempt.REDIRECT_FOR_SCHEDULE_TXN.selector()),
+ org.apache.tuweni.bytes.Bytes.wrap(HssCallAttempt.LEGACY_REDIRECT_FOR_SCHEDULE_TXN.selector()),
scheduleAddress,
org.apache.tuweni.bytes.Bytes.of(subSelector));
}
diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/TransactionProcessorTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/TransactionProcessorTest.java
index 911655689a8e..e3e39682d252 100644
--- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/TransactionProcessorTest.java
+++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/TransactionProcessorTest.java
@@ -6,7 +6,33 @@
import static com.hedera.hapi.node.base.ResponseCodeEnum.INVALID_CONTRACT_ID;
import static com.hedera.hapi.node.base.ResponseCodeEnum.INVALID_TRANSACTION_BODY;
import static com.hedera.node.app.service.contract.impl.exec.utils.FrameUtils.TRACKER_CONTEXT_VARIABLE;
-import static com.hedera.node.app.service.contract.impl.test.TestHelpers.*;
+import static com.hedera.node.app.service.contract.impl.test.TestHelpers.CALLED_CONTRACT_ID;
+import static com.hedera.node.app.service.contract.impl.test.TestHelpers.CALL_DATA;
+import static com.hedera.node.app.service.contract.impl.test.TestHelpers.CHARGING_RESULT;
+import static com.hedera.node.app.service.contract.impl.test.TestHelpers.CODE_FACTORY;
+import static com.hedera.node.app.service.contract.impl.test.TestHelpers.EIP_1014_ADDRESS;
+import static com.hedera.node.app.service.contract.impl.test.TestHelpers.GAS_CALCULATOR;
+import static com.hedera.node.app.service.contract.impl.test.TestHelpers.GAS_LIMIT;
+import static com.hedera.node.app.service.contract.impl.test.TestHelpers.INVALID_CONTRACT_ADDRESS;
+import static com.hedera.node.app.service.contract.impl.test.TestHelpers.MAINNET_CHAIN_ID;
+import static com.hedera.node.app.service.contract.impl.test.TestHelpers.MAX_GAS_ALLOWANCE;
+import static com.hedera.node.app.service.contract.impl.test.TestHelpers.NETWORK_GAS_PRICE;
+import static com.hedera.node.app.service.contract.impl.test.TestHelpers.NONCE;
+import static com.hedera.node.app.service.contract.impl.test.TestHelpers.NON_SYSTEM_LONG_ZERO_ADDRESS;
+import static com.hedera.node.app.service.contract.impl.test.TestHelpers.NO_ALLOWANCE_CHARGING_RESULT;
+import static com.hedera.node.app.service.contract.impl.test.TestHelpers.RECEIVER_ID;
+import static com.hedera.node.app.service.contract.impl.test.TestHelpers.RELAYER_ID;
+import static com.hedera.node.app.service.contract.impl.test.TestHelpers.SENDER_ID;
+import static com.hedera.node.app.service.contract.impl.test.TestHelpers.SUCCESS_RESULT;
+import static com.hedera.node.app.service.contract.impl.test.TestHelpers.USER_OFFERED_GAS_PRICE;
+import static com.hedera.node.app.service.contract.impl.test.TestHelpers.VALID_CONTRACT_ADDRESS;
+import static com.hedera.node.app.service.contract.impl.test.TestHelpers.VALUE;
+import static com.hedera.node.app.service.contract.impl.test.TestHelpers.assertFailsWith;
+import static com.hedera.node.app.service.contract.impl.test.TestHelpers.wellKnownContextWith;
+import static com.hedera.node.app.service.contract.impl.test.TestHelpers.wellKnownHapiCall;
+import static com.hedera.node.app.service.contract.impl.test.TestHelpers.wellKnownHapiCreate;
+import static com.hedera.node.app.service.contract.impl.test.TestHelpers.wellKnownRelayedHapiCall;
+import static com.hedera.node.app.service.contract.impl.test.TestHelpers.wellKnownRelayedHapiCreate;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.catchThrowableOfType;
import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -133,7 +159,8 @@ void setUp() {
messageCallProcessor,
contractCreationProcessor,
featureFlags,
- CODE_FACTORY);
+ CODE_FACTORY,
+ GAS_CALCULATOR);
opsDurationCounter = OpsDurationCounter.disabled();
}
@@ -209,7 +236,8 @@ void lazyCreationAttemptWithValidAddress() {
EIP_1014_ADDRESS,
expectedToAddress,
CHARGING_RESULT.intrinsicGas(),
- CODE_FACTORY))
+ CODE_FACTORY,
+ GAS_CALCULATOR))
.willReturn(initialFrame);
given(senderAccount.getNonce()).willReturn(NONCE);
given(frameRunner.runToCompletion(
@@ -266,7 +294,8 @@ void lazyCreationAttemptCanCallNotExistingFeatureFlagOn() {
EIP_1014_ADDRESS,
expectedToAddress,
CHARGING_RESULT.intrinsicGas(),
- CODE_FACTORY))
+ CODE_FACTORY,
+ GAS_CALCULATOR))
.willReturn(initialFrame);
given(senderAccount.hederaId()).willReturn(SENDER_ID);
given(frameRunner.runToCompletion(
@@ -325,7 +354,8 @@ void callWithNoValueAndCanCallNotExistingFeatureFlagOn() {
EIP_1014_ADDRESS,
expectedToAddress,
CHARGING_RESULT.intrinsicGas(),
- CODE_FACTORY))
+ CODE_FACTORY,
+ GAS_CALCULATOR))
.willReturn(initialFrame);
given(senderAccount.hederaId()).willReturn(SENDER_ID);
given(frameRunner.runToCompletion(
@@ -441,7 +471,8 @@ void ethCreateHappyPathAsExpected() {
EIP_1014_ADDRESS,
expectedToAddress,
CHARGING_RESULT.intrinsicGas(),
- CODE_FACTORY))
+ CODE_FACTORY,
+ GAS_CALCULATOR))
.willReturn(initialFrame);
given(senderAccount.getNonce()).willReturn(NONCE);
given(frameRunner.runToCompletion(
@@ -475,7 +506,8 @@ void ethCreateHappyPathAsExpected() {
EIP_1014_ADDRESS,
expectedToAddress,
CHARGING_RESULT.intrinsicGas(),
- CODE_FACTORY);
+ CODE_FACTORY,
+ GAS_CALCULATOR);
inOrder.verify(frameRunner)
.runToCompletion(
transaction.gasLimit(),
@@ -523,7 +555,8 @@ void hapiCreateHappyPathAsExpected() {
EIP_1014_ADDRESS,
NON_SYSTEM_LONG_ZERO_ADDRESS,
NO_ALLOWANCE_CHARGING_RESULT.intrinsicGas(),
- CODE_FACTORY))
+ CODE_FACTORY,
+ GAS_CALCULATOR))
.willReturn(initialFrame);
given(frameRunner.runToCompletion(
transaction.gasLimit(),
@@ -552,7 +585,8 @@ void hapiCreateHappyPathAsExpected() {
EIP_1014_ADDRESS,
NON_SYSTEM_LONG_ZERO_ADDRESS,
NO_ALLOWANCE_CHARGING_RESULT.intrinsicGas(),
- CODE_FACTORY);
+ CODE_FACTORY,
+ GAS_CALCULATOR);
inOrder.verify(frameRunner)
.runToCompletion(
transaction.gasLimit(),
@@ -598,7 +632,8 @@ void ethCallHappyPathAsExpected() {
EIP_1014_ADDRESS,
NON_SYSTEM_LONG_ZERO_ADDRESS,
CHARGING_RESULT.intrinsicGas(),
- CODE_FACTORY))
+ CODE_FACTORY,
+ GAS_CALCULATOR))
.willReturn(initialFrame);
given(frameRunner.runToCompletion(
eq(transaction.gasLimit()),
@@ -626,7 +661,8 @@ void ethCallHappyPathAsExpected() {
EIP_1014_ADDRESS,
NON_SYSTEM_LONG_ZERO_ADDRESS,
CHARGING_RESULT.intrinsicGas(),
- CODE_FACTORY);
+ CODE_FACTORY,
+ GAS_CALCULATOR);
inOrder.verify(frameRunner)
.runToCompletion(
transaction.gasLimit(),
@@ -676,7 +712,8 @@ void ethCallHappyPathAsExpectedAndCanCallNotExistingFeatureFlagOn() {
EIP_1014_ADDRESS,
NON_SYSTEM_LONG_ZERO_ADDRESS,
CHARGING_RESULT.intrinsicGas(),
- CODE_FACTORY))
+ CODE_FACTORY,
+ GAS_CALCULATOR))
.willReturn(initialFrame);
given(senderAccount.hederaId()).willReturn(SENDER_ID);
given(frameRunner.runToCompletion(
@@ -708,7 +745,8 @@ void ethCallHappyPathAsExpectedAndCanCallNotExistingFeatureFlagOn() {
EIP_1014_ADDRESS,
NON_SYSTEM_LONG_ZERO_ADDRESS,
CHARGING_RESULT.intrinsicGas(),
- CODE_FACTORY);
+ CODE_FACTORY,
+ GAS_CALCULATOR);
inOrder.verify(frameRunner)
.runToCompletion(
transaction.gasLimit(),
@@ -756,7 +794,8 @@ void ethCallAsExpectedWithResourceExhaustionInCommit() {
EIP_1014_ADDRESS,
NON_SYSTEM_LONG_ZERO_ADDRESS,
CHARGING_RESULT.intrinsicGas(),
- CODE_FACTORY))
+ CODE_FACTORY,
+ GAS_CALCULATOR))
.willReturn(initialFrame);
given(frameRunner.runToCompletion(
eq(transaction.gasLimit()),
diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/delegation/CodeDelegationProcessorTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/delegation/CodeDelegationProcessorTest.java
index 3c516b6eae70..3a76340569bb 100644
--- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/delegation/CodeDelegationProcessorTest.java
+++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/delegation/CodeDelegationProcessorTest.java
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: Apache-2.0
package com.hedera.node.app.service.contract.impl.test.exec.delegation;
+import static org.hyperledger.besu.evm.worldstate.CodeDelegationHelper.CODE_DELEGATION_PREFIX;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrowsExactly;
@@ -199,7 +200,7 @@ void createsNewAccountAndDelegatesWhenMissingAndNonceZero() throws Exception {
final var acct = mock(MutableAccount.class);
final var authAddr = Address.fromHexString("0x00000000000000000000000000000000000000AA");
- final var expectedCode = Bytes.concatenate(CodeDelegationProcessor.CODE_DELEGATION_PREFIX, authAddr);
+ final var expectedCode = Bytes.concatenate(CODE_DELEGATION_PREFIX, authAddr);
when(tx.codeDelegations()).thenReturn(List.of(del));
when(del.getChainId()).thenReturn(CHAIN_ID);
@@ -264,7 +265,7 @@ void updatesExistingAccountWithEmptyCodeAndMatchingNonce() throws Exception {
final var acct = mock(MutableAccount.class);
final var authAddr = Address.fromHexString("0x00000000000000000000000000000000000000AC");
- final var expectedCode = Bytes.concatenate(CodeDelegationProcessor.CODE_DELEGATION_PREFIX, authAddr);
+ final var expectedCode = Bytes.concatenate(CODE_DELEGATION_PREFIX, authAddr);
when(tx.codeDelegations()).thenReturn(List.of(del));
when(del.getChainId()).thenReturn(CHAIN_ID);
diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/processors/CustomMessageCallProcessorTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/processors/CustomMessageCallProcessorTest.java
index e1a8f74492d8..fb9a41affd7a 100644
--- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/processors/CustomMessageCallProcessorTest.java
+++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/processors/CustomMessageCallProcessorTest.java
@@ -12,6 +12,7 @@
import static com.hedera.node.app.service.contract.impl.test.TestHelpers.REMAINING_GAS;
import static com.hedera.node.app.service.contract.impl.test.TestHelpers.isSameResult;
import static org.hyperledger.besu.evm.frame.ExceptionalHaltReason.INSUFFICIENT_GAS;
+import static org.hyperledger.besu.evm.worldstate.CodeDelegationHelper.CODE_DELEGATION_PREFIX;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.argThat;
@@ -43,6 +44,7 @@
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.evm.EVM;
+import org.hyperledger.besu.evm.account.Account;
import org.hyperledger.besu.evm.frame.ExceptionalHaltReason;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.operation.Operation;
@@ -129,6 +131,7 @@ void callPrngSystemContractHappyPath() {
given(frame.getValue()).willReturn(Wei.ZERO);
given(frame.getMessageFrameStack()).willReturn(stack);
given(frame.getContextVariable(OPS_DURATION_COUNTER)).willReturn(OpsDurationCounter.disabled());
+ given(frame.getWorldUpdater()).willReturn(proxyWorldUpdater);
given(stack.getLast()).willReturn(frame);
given(result.output()).willReturn(OUTPUT_DATA);
given(result.state()).willReturn(MessageFrame.State.CODE_SUCCESS);
@@ -226,6 +229,7 @@ void haltsAndTracesInsufficientGasIfPrecompileGasRequirementExceedsRemaining() {
givenEvmPrecompileCall();
given(nativePrecompile.gasRequirement(INPUT_DATA)).willReturn(GAS_REQUIREMENT);
given(frame.getRemainingGas()).willReturn(1L);
+ given(frame.getValue()).willReturn(Wei.ZERO);
subject.start(frame, operationTracer);
@@ -242,6 +246,7 @@ void updatesFrameBySuccessfulPrecompileResultWithGasRefund() {
given(nativePrecompile.computePrecompile(INPUT_DATA, frame)).willReturn(result);
given(nativePrecompile.gasRequirement(INPUT_DATA)).willReturn(GAS_REQUIREMENT);
given(frame.getRemainingGas()).willReturn(3L);
+ given(frame.getValue()).willReturn(Wei.ZERO);
given(frame.getMessageFrameStack()).willReturn(stack);
given(frame.getContextVariable(OPS_DURATION_COUNTER)).willReturn(OpsDurationCounter.disabled());
given(stack.getLast()).willReturn(frame);
@@ -268,6 +273,7 @@ void revertsFrameFromPrecompileResult() {
given(frame.getContextVariable(OPS_DURATION_COUNTER)).willReturn(OpsDurationCounter.disabled());
given(stack.getLast()).willReturn(frame);
given(frame.getContractAddress()).willReturn(Address.ALTBN128_ADD);
+ given(frame.getValue()).willReturn(Wei.ZERO);
subject.start(frame, operationTracer);
@@ -320,6 +326,49 @@ void callsToDisabledPrecompile() {
verify(frame).setExceptionalHaltReason(Optional.empty());
}
+ @Test
+ void codeDelegationToPrecompileIsNoOp() {
+ given(registry.get(ADDRESS_6)).willReturn(nativePrecompile);
+ final var eoaAddress = Address.fromHexString("0x1234");
+ final var eoaAccount = mock(Account.class);
+ given(eoaAccount.getCode()).willReturn(Bytes.concatenate(CODE_DELEGATION_PREFIX, ADDRESS_6));
+ given(proxyWorldUpdater.get(eoaAddress)).willReturn(eoaAccount);
+ given(frame.getContractAddress()).willReturn(eoaAddress);
+ given(frame.getInputData()).willReturn(Bytes.EMPTY);
+ given(frame.getMessageFrameStack()).willReturn(stack);
+ given(frame.getContextVariable(CONFIG_CONTEXT_VARIABLE)).willReturn(DEFAULT_CONFIG);
+ given(frame.getWorldUpdater()).willReturn(proxyWorldUpdater);
+ given(stack.getLast()).willReturn(frame);
+ given(frame.getValue()).willReturn(Wei.ZERO);
+
+ subject.start(frame, operationTracer);
+
+ verifyNoInteractions(nativePrecompile);
+ verify(frame).setState(MessageFrame.State.CODE_SUCCESS);
+ }
+
+ @Test
+ void codeDelegationToPrecompileIsNoOpWithValueTransfer() {
+ givenExecutingFrame();
+ given(registry.get(ADDRESS_6)).willReturn(nativePrecompile);
+ final var eoaAddress = Address.fromHexString("0x1234");
+ final var eoaAccount = mock(Account.class);
+ given(eoaAccount.getCode()).willReturn(Bytes.concatenate(CODE_DELEGATION_PREFIX, ADDRESS_6));
+ given(proxyWorldUpdater.get(eoaAddress)).willReturn(eoaAccount);
+ given(frame.getContractAddress()).willReturn(eoaAddress);
+ given(frame.getRecipientAddress()).willReturn(eoaAddress);
+ given(frame.getInputData()).willReturn(Bytes.EMPTY);
+ given(frame.getContextVariable(CONFIG_CONTEXT_VARIABLE)).willReturn(DEFAULT_CONFIG);
+ given(frame.getWorldUpdater()).willReturn(proxyWorldUpdater);
+ given(frame.getValue()).willReturn(Wei.ONE);
+
+ subject.start(frame, operationTracer);
+
+ verifyNoInteractions(nativePrecompile);
+ verify(frame).setState(MessageFrame.State.CODE_SUCCESS);
+ verify(proxyWorldUpdater).tryTransfer(frame.getSenderAddress(), eoaAddress, 1, false);
+ }
+
private void givenHaltableFrame(@NonNull final AtomicBoolean isHalted) {
doAnswer(invocation -> {
isHalted.set(true);
@@ -327,7 +376,9 @@ private void givenHaltableFrame(@NonNull final AtomicBoolean isHalted) {
})
.when(frame)
.setExceptionalHaltReason(any());
- doAnswer(invocation -> isHalted.get() ? MessageFrame.State.EXCEPTIONAL_HALT : MessageFrame.State.NOT_STARTED)
+ lenient()
+ .doAnswer(invocation ->
+ isHalted.get() ? MessageFrame.State.EXCEPTIONAL_HALT : MessageFrame.State.NOT_STARTED)
.when(frame)
.getState();
}
@@ -343,12 +394,14 @@ private void givenCallWithIsTopLevelTransaction(@NonNull final AtomicBoolean isT
private void givenCallWithCode(@NonNull final Address contract) {
given(frame.getContractAddress()).willReturn(contract);
+ given(frame.getWorldUpdater()).willReturn(proxyWorldUpdater);
}
private void givenWellKnownUserSpaceCall() {
given(frame.getContractAddress()).willReturn(CODE_ADDRESS);
given(frame.getRecipientAddress()).willReturn(RECEIVER_ADDRESS);
given(frame.getSenderAddress()).willReturn(SENDER_ADDRESS);
+ given(frame.getWorldUpdater()).willReturn(proxyWorldUpdater);
}
private void givenEvmPrecompileCall() {
@@ -358,6 +411,7 @@ private void givenEvmPrecompileCall() {
given(frame.getInputData()).willReturn(INPUT_DATA);
given(frame.getMessageFrameStack()).willReturn(stack);
given(frame.getContextVariable(CONFIG_CONTEXT_VARIABLE)).willReturn(DEFAULT_CONFIG);
+ given(frame.getWorldUpdater()).willReturn(proxyWorldUpdater);
}
private void givenDisabledEvmPrecompileCall() {
@@ -370,6 +424,7 @@ private void givenDisabledEvmPrecompileCall() {
given(frame.getMessageFrameStack()).willReturn(stack);
given(frame.getContextVariable(CONFIG_CONTEXT_VARIABLE)).willReturn(DISABLED_PRECOMPILE_CONFIG);
when(frame.getValue()).thenReturn(Wei.ZERO);
+ given(frame.getWorldUpdater()).willReturn(proxyWorldUpdater);
given(addressChecks.isSystemAccount(ADDRESS_6)).willReturn(true);
}
diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/common/CallAttemptTestBase.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/common/CallAttemptTestBase.java
index 4200aa6f765a..c69af99a6670 100644
--- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/common/CallAttemptTestBase.java
+++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/common/CallAttemptTestBase.java
@@ -2,8 +2,11 @@
package com.hedera.node.app.service.contract.impl.test.exec.systemcontracts.common;
import static com.hedera.node.app.service.contract.impl.exec.systemcontracts.HasSystemContract.HAS_CONTRACT_ID;
+import static com.hedera.node.app.service.contract.impl.exec.systemcontracts.HasSystemContract.HAS_EVM_ADDRESS;
import static com.hedera.node.app.service.contract.impl.exec.systemcontracts.HssSystemContract.HSS_CONTRACT_ID;
+import static com.hedera.node.app.service.contract.impl.exec.systemcontracts.HssSystemContract.HSS_EVM_ADDRESS;
import static com.hedera.node.app.service.contract.impl.exec.systemcontracts.HtsSystemContract.HTS_167_CONTRACT_ID;
+import static com.hedera.node.app.service.contract.impl.exec.systemcontracts.HtsSystemContract.HTS_167_EVM_ADDRESS;
import static com.hedera.node.app.service.contract.impl.test.TestHelpers.DEFAULT_CONFIG;
import static com.hedera.node.app.service.contract.impl.test.TestHelpers.EIP_1014_ADDRESS;
import static com.hedera.node.app.service.contract.impl.test.TestHelpers.NON_SYSTEM_LONG_ZERO_ADDRESS;
@@ -161,6 +164,7 @@ protected HtsCallAttempt createHtsCallAttempt(
new CallAttemptOptions<>(
contractID,
senderAddress,
+ Address.fromHexString(HTS_167_EVM_ADDRESS),
authorizingAddress,
onlyDelegatableContractKeysActive,
mockEnhancement(),
@@ -200,6 +204,7 @@ protected HasCallAttempt createHasCallAttempt(
new CallAttemptOptions<>(
HAS_CONTRACT_ID,
OWNER_BESU_ADDRESS,
+ Address.fromHexString(HAS_EVM_ADDRESS),
OWNER_BESU_ADDRESS,
false,
mockEnhancement(),
@@ -244,6 +249,7 @@ protected HssCallAttempt createHssCallAttempt(
new CallAttemptOptions<>(
HSS_CONTRACT_ID,
senderAddress,
+ Address.fromHexString(HSS_EVM_ADDRESS),
senderAddress,
onlyDelegatableContractKeysActive,
mockEnhancement(),
diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/has/HasCallFactoryTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/has/HasCallFactoryTest.java
index 4cbabe2e6124..2a9c5dd3aac8 100644
--- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/has/HasCallFactoryTest.java
+++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/has/HasCallFactoryTest.java
@@ -2,6 +2,7 @@
package com.hedera.node.app.service.contract.impl.test.exec.systemcontracts.has;
import static com.hedera.node.app.service.contract.impl.exec.systemcontracts.HasSystemContract.HAS_CONTRACT_ID;
+import static com.hedera.node.app.service.contract.impl.exec.systemcontracts.HasSystemContract.HAS_EVM_ADDRESS;
import static com.hedera.node.app.service.contract.impl.test.TestHelpers.A_NEW_ACCOUNT_ID;
import static com.hedera.node.app.service.contract.impl.test.TestHelpers.B_NEW_ACCOUNT_ID;
import static com.hedera.node.app.service.contract.impl.test.TestHelpers.CALLED_EOA_ID;
@@ -101,6 +102,7 @@ void instantiatesCallWithInContextEnhancementAndDelegateCallInfo() {
given(frame.getWorldUpdater()).willReturn(updater);
given(updater.enhancement()).willReturn(mockEnhancement());
given(frame.getSenderAddress()).willReturn(EIP_1014_ADDRESS);
+ given(frame.getRecipientAddress()).willReturn(Address.fromHexString(HAS_EVM_ADDRESS));
given(addressChecks.hasParentDelegateCall(frame)).willReturn(true);
given(syntheticIds.converterFor(nativeOperations)).willReturn(idConverter);
given(idConverter.convert(asHeadlongAddress(NON_SYSTEM_BUT_IS_LONG_ZERO_ADDRESS)))
@@ -130,6 +132,7 @@ void instantiatesDirectCall() {
given(frame.getWorldUpdater()).willReturn(updater);
given(updater.enhancement()).willReturn(mockEnhancement());
given(frame.getSenderAddress()).willReturn(Address.ALTBN128_ADD);
+ given(frame.getRecipientAddress()).willReturn(Address.fromHexString(HAS_EVM_ADDRESS));
given(idConverter.convertSender(Address.ALTBN128_ADD)).willReturn(A_NEW_ACCOUNT_ID);
given(addressChecks.hasParentDelegateCall(frame)).willReturn(true);
given(syntheticIds.converterFor(nativeOperations)).willReturn(idConverter);
diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hss/HssCallFactoryTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hss/HssCallFactoryTest.java
index 54d7c957368a..17c6313a3b99 100644
--- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hss/HssCallFactoryTest.java
+++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hss/HssCallFactoryTest.java
@@ -2,6 +2,7 @@
package com.hedera.node.app.service.contract.impl.test.exec.systemcontracts.hss;
import static com.hedera.node.app.service.contract.impl.exec.systemcontracts.HssSystemContract.HSS_CONTRACT_ID;
+import static com.hedera.node.app.service.contract.impl.exec.systemcontracts.HssSystemContract.HSS_EVM_ADDRESS;
import static com.hedera.node.app.service.contract.impl.test.TestHelpers.A_NEW_ACCOUNT_ID;
import static com.hedera.node.app.service.contract.impl.test.TestHelpers.CALLED_SCHEDULE_ID;
import static com.hedera.node.app.service.contract.impl.test.TestHelpers.DEFAULT_CONFIG;
@@ -35,6 +36,7 @@
import java.util.Deque;
import java.util.List;
import java.util.Objects;
+import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -106,6 +108,7 @@ void instantiatesCallWithInContextEnhancementAndDelegateCallInfo() {
given(frame.getWorldUpdater()).willReturn(updater);
given(updater.enhancement()).willReturn(mockEnhancement());
given(frame.getSenderAddress()).willReturn(EIP_1014_ADDRESS);
+ given(frame.getRecipientAddress()).willReturn(Address.fromHexString(HSS_EVM_ADDRESS));
given(addressChecks.hasParentDelegateCall(frame)).willReturn(true);
given(syntheticIds.converterFor(nativeOperations)).willReturn(idConverter);
given(nativeOperations.getSchedule(CALLED_SCHEDULE_ID)).willReturn(schedule);
@@ -138,6 +141,7 @@ void instantiatesDirectCall() {
given(frame.getWorldUpdater()).willReturn(updater);
given(updater.enhancement()).willReturn(mockEnhancement());
given(frame.getSenderAddress()).willReturn(ALTBN128_ADD);
+ given(frame.getRecipientAddress()).willReturn(Address.fromHexString(HSS_EVM_ADDRESS));
given(idConverter.convertSender(ALTBN128_ADD)).willReturn(A_NEW_ACCOUNT_ID);
given(addressChecks.hasParentDelegateCall(frame)).willReturn(true);
given(syntheticIds.converterFor(nativeOperations)).willReturn(idConverter);
diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/HtsCallAttemptTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/HtsCallAttemptTest.java
index b06ddadeb582..28ac1b263ef7 100644
--- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/HtsCallAttemptTest.java
+++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/HtsCallAttemptTest.java
@@ -424,7 +424,7 @@ void constructsMints(String hexedSelector, LinkedTokenType linkedTokenType) {
private Bytes encodeInput(final boolean useExplicitCall, final boolean isRedirect, final byte[] selector) {
if (isRedirect) {
return useExplicitCall
- ? Bytes.wrap(HtsCallAttempt.REDIRECT_FOR_TOKEN
+ ? Bytes.wrap(HtsCallAttempt.LEGACY_REDIRECT_FOR_TOKEN
.encodeCallWithArgs(
asHeadlongAddress(NON_SYSTEM_LONG_ZERO_ADDRESS.toArrayUnsafe()),
Bytes.wrap(selector).toArrayUnsafe())
diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/HtsCallFactoryTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/HtsCallFactoryTest.java
index d818c927ae69..cdb7ab4def8e 100644
--- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/HtsCallFactoryTest.java
+++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/HtsCallFactoryTest.java
@@ -2,6 +2,7 @@
package com.hedera.node.app.service.contract.impl.test.exec.systemcontracts.hts;
import static com.hedera.node.app.service.contract.impl.exec.systemcontracts.HtsSystemContract.HTS_167_CONTRACT_ID;
+import static com.hedera.node.app.service.contract.impl.exec.systemcontracts.HtsSystemContract.HTS_167_EVM_ADDRESS;
import static com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.balanceof.BalanceOfTranslator.BALANCE_OF;
import static com.hedera.node.app.service.contract.impl.test.TestHelpers.A_NEW_ACCOUNT_ID;
import static com.hedera.node.app.service.contract.impl.test.TestHelpers.DEFAULT_CONFIG;
@@ -96,6 +97,7 @@ void instantiatesCallWithInContextEnhancementAndDelegateCallInfo() {
given(nativeOperations.getToken(FUNGIBLE_TOKEN_ID)).willReturn(FUNGIBLE_TOKEN);
given(nativeOperations.entityIdFactory()).willReturn(entityIdFactory);
given(frame.getSenderAddress()).willReturn(EIP_1014_ADDRESS);
+ given(frame.getRecipientAddress()).willReturn(Address.fromHexString(HTS_167_EVM_ADDRESS));
given(addressChecks.hasParentDelegateCall(frame)).willReturn(true);
given(syntheticIds.converterFor(nativeOperations)).willReturn(idConverter);
@@ -122,8 +124,8 @@ void instantiatesQualifiedDelegateCallWithRecipientAsSender() {
given(nativeOperations.getToken(FUNGIBLE_TOKEN_ID)).willReturn(FUNGIBLE_TOKEN);
given(nativeOperations.entityIdFactory()).willReturn(entityIdFactory);
given(frame.getSenderAddress()).willReturn(Address.ALTBN128_ADD);
+ given(frame.getRecipientAddress()).willReturn(Address.fromHexString(HTS_167_EVM_ADDRESS));
given(idConverter.convertSender(Address.ALTBN128_ADD)).willReturn(A_NEW_ACCOUNT_ID);
- given(frame.getRecipientAddress()).willReturn(EIP_1014_ADDRESS);
given(addressChecks.hasParentDelegateCall(frame)).willReturn(true);
given(syntheticIds.converterFor(nativeOperations)).willReturn(idConverter);
diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/utils/FrameBuilderTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/utils/FrameBuilderTest.java
index d6db23f3e67c..a9df02fca88a 100644
--- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/utils/FrameBuilderTest.java
+++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/utils/FrameBuilderTest.java
@@ -6,11 +6,11 @@
import static com.hedera.node.app.service.contract.impl.exec.utils.FrameUtils.selfDestructBeneficiariesFor;
import static com.hedera.node.app.service.contract.impl.exec.utils.FrameUtils.tinybarValuesFor;
import static com.hedera.node.app.service.contract.impl.test.TestHelpers.CALLED_CONTRACT_ID;
-import static com.hedera.node.app.service.contract.impl.test.TestHelpers.CALL_DATA;
import static com.hedera.node.app.service.contract.impl.test.TestHelpers.CODE_FACTORY;
import static com.hedera.node.app.service.contract.impl.test.TestHelpers.CONTRACT_CODE;
import static com.hedera.node.app.service.contract.impl.test.TestHelpers.DEFAULT_COINBASE;
import static com.hedera.node.app.service.contract.impl.test.TestHelpers.EIP_1014_ADDRESS;
+import static com.hedera.node.app.service.contract.impl.test.TestHelpers.GAS_CALCULATOR;
import static com.hedera.node.app.service.contract.impl.test.TestHelpers.GAS_LIMIT;
import static com.hedera.node.app.service.contract.impl.test.TestHelpers.INTRINSIC_GAS;
import static com.hedera.node.app.service.contract.impl.test.TestHelpers.NETWORK_GAS_PRICE;
@@ -107,8 +107,7 @@ void constructsExpectedFrameForCallToExtantContractIncludingOptionalContextVaria
givenContractExists();
final var recordBuilder = mock(ContractOperationStreamBuilder.class);
given(worldUpdater.getHederaAccount(CALLED_CONTRACT_ID)).willReturn(account);
- given(account.getEvmCode(Bytes.wrap(CALL_DATA.toByteArray()), CODE_FACTORY))
- .willReturn(CONTRACT_CODE);
+ given(account.getCode()).willReturn(CONTRACT_CODE.getBytes());
given(worldUpdater.updater()).willReturn(stackedUpdater);
given(blocks.blockValuesOf(GAS_LIMIT)).willReturn(blockValues);
final var config = HederaTestConfigBuilder.create()
@@ -124,7 +123,8 @@ void constructsExpectedFrameForCallToExtantContractIncludingOptionalContextVaria
EIP_1014_ADDRESS,
NON_SYSTEM_LONG_ZERO_ADDRESS,
INTRINSIC_GAS,
- CODE_FACTORY);
+ CODE_FACTORY,
+ GAS_CALCULATOR);
given(blocks.blockHashOf(frame, SOME_BLOCK_NO)).willReturn(Hash.EMPTY);
assertEquals(1024, frame.getMaxStackSize());
@@ -146,7 +146,7 @@ void constructsExpectedFrameForCallToExtantContractIncludingOptionalContextVaria
assertEquals(NON_SYSTEM_LONG_ZERO_ADDRESS, frame.getRecipientAddress());
assertEquals(NON_SYSTEM_LONG_ZERO_ADDRESS, frame.getContractAddress());
assertEquals(transaction.evmPayload(), frame.getInputData());
- assertSame(CONTRACT_CODE, frame.getCode());
+ assertSame(CONTRACT_CODE.getBytes(), frame.getCode().getBytes());
assertNotNull(accessTrackerFor(frame));
assertSame(tinybarValues, tinybarValuesFor(frame));
assertSame(recordBuilder, selfDestructBeneficiariesFor(frame));
@@ -160,8 +160,7 @@ void constructsExpectedFrameForCallToExtantContractNotIncludingAccessTrackerWith
given(worldUpdater.updater()).willReturn(stackedUpdater);
given(blocks.blockValuesOf(GAS_LIMIT)).willReturn(blockValues);
given(worldUpdater.getHederaAccount(CALLED_CONTRACT_ID)).willReturn(account);
- given(account.getEvmCode(Bytes.wrap(CALL_DATA.toByteArray()), CODE_FACTORY))
- .willReturn(CONTRACT_CODE);
+ given(account.getCode()).willReturn(CONTRACT_CODE.getBytes());
final var config = HederaTestConfigBuilder.create()
.withValue("ledger.fundingAccount", DEFAULT_COINBASE)
.withValue("contracts.sidecars", "CONTRACT_BYTECODE,CONTRACT_ACTION")
@@ -177,7 +176,8 @@ void constructsExpectedFrameForCallToExtantContractNotIncludingAccessTrackerWith
EIP_1014_ADDRESS,
NON_SYSTEM_LONG_ZERO_ADDRESS,
INTRINSIC_GAS,
- CODE_FACTORY);
+ CODE_FACTORY,
+ GAS_CALCULATOR);
given(blocks.blockHashOf(frame, SOME_BLOCK_NO)).willReturn(Hash.EMPTY);
assertEquals(1024, frame.getMaxStackSize());
@@ -199,7 +199,7 @@ void constructsExpectedFrameForCallToExtantContractNotIncludingAccessTrackerWith
assertEquals(NON_SYSTEM_LONG_ZERO_ADDRESS, frame.getRecipientAddress());
assertEquals(NON_SYSTEM_LONG_ZERO_ADDRESS, frame.getContractAddress());
assertEquals(transaction.evmPayload(), frame.getInputData());
- assertSame(CONTRACT_CODE, frame.getCode());
+ assertSame(CONTRACT_CODE.getBytes(), frame.getCode().getBytes());
assertNull(accessTrackerFor(frame));
assertSame(tinybarValues, tinybarValuesFor(frame));
}
@@ -227,7 +227,8 @@ void callFailsWhenContractNotFound() {
EIP_1014_ADDRESS,
NON_SYSTEM_LONG_ZERO_ADDRESS,
INTRINSIC_GAS,
- CODE_FACTORY));
+ CODE_FACTORY,
+ GAS_CALCULATOR));
}
@Test
@@ -237,8 +238,7 @@ void callSucceedsWhenContractNotFoundIfPermitted() {
given(worldUpdater.updater()).willReturn(stackedUpdater);
given(blocks.blockValuesOf(GAS_LIMIT)).willReturn(blockValues);
given(worldUpdater.getHederaAccount(CALLED_CONTRACT_ID)).willReturn(account);
- given(account.getEvmCode(Bytes.wrap(CALL_DATA.toByteArray()), CODE_FACTORY))
- .willReturn(CONTRACT_CODE);
+ given(account.getCode()).willReturn(CONTRACT_CODE.getBytes());
final var config = HederaTestConfigBuilder.create().getOrCreateConfig();
final var frame = subject.buildInitialFrameWith(
@@ -251,7 +251,8 @@ void callSucceedsWhenContractNotFoundIfPermitted() {
EIP_1014_ADDRESS,
NON_SYSTEM_LONG_ZERO_ADDRESS,
INTRINSIC_GAS,
- CODE_FACTORY);
+ CODE_FACTORY,
+ GAS_CALCULATOR);
assertEquals(1024, frame.getMaxStackSize());
assertSame(stackedUpdater, frame.getWorldUpdater());
@@ -270,7 +271,7 @@ void callSucceedsWhenContractNotFoundIfPermitted() {
assertEquals(NON_SYSTEM_LONG_ZERO_ADDRESS, frame.getRecipientAddress());
assertEquals(NON_SYSTEM_LONG_ZERO_ADDRESS, frame.getContractAddress());
assertEquals(transaction.evmPayload(), frame.getInputData());
- assertSame(CONTRACT_CODE, frame.getCode());
+ assertSame(CONTRACT_CODE.getBytes(), frame.getCode().getBytes());
assertSame(tinybarValues, tinybarValuesFor(frame));
}
@@ -293,7 +294,8 @@ void callSucceedsWhenContractFoundButDeleted() {
EIP_1014_ADDRESS,
NON_SYSTEM_LONG_ZERO_ADDRESS,
INTRINSIC_GAS,
- CODE_FACTORY);
+ CODE_FACTORY,
+ GAS_CALCULATOR);
assertEquals(1024, frame.getMaxStackSize());
assertSame(stackedUpdater, frame.getWorldUpdater());
@@ -337,7 +339,8 @@ void constructsExpectedFrameForCallToMissingContract() {
EIP_1014_ADDRESS,
NON_SYSTEM_LONG_ZERO_ADDRESS,
INTRINSIC_GAS,
- CODE_FACTORY);
+ CODE_FACTORY,
+ GAS_CALCULATOR);
given(blocks.blockHashOf(frame, SOME_BLOCK_NO)).willReturn(Hash.EMPTY);
assertTrue(FrameUtils.hasActionValidationEnabled(frame));
@@ -384,7 +387,8 @@ void constructsExpectedFrameForCreate() {
EIP_1014_ADDRESS,
NON_SYSTEM_LONG_ZERO_ADDRESS,
INTRINSIC_GAS,
- CODE_FACTORY);
+ CODE_FACTORY,
+ GAS_CALCULATOR);
given(blocks.blockHashOf(frame, SOME_BLOCK_NO)).willReturn(Hash.EMPTY);
assertEquals(1024, frame.getMaxStackSize());
diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/handlers/ContractGetBytecodeHandlerTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/handlers/ContractGetBytecodeHandlerTest.java
index 925d260b4aa2..9841ad7f0bab 100644
--- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/handlers/ContractGetBytecodeHandlerTest.java
+++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/handlers/ContractGetBytecodeHandlerTest.java
@@ -5,6 +5,7 @@
import static com.hedera.hapi.node.base.ResponseCodeEnum.INVALID_CONTRACT_ID;
import static com.hedera.hapi.node.base.ResponseCodeEnum.OK;
import static com.hedera.hapi.node.base.ResponseType.ANSWER_ONLY;
+import static com.hedera.node.app.service.contract.impl.utils.ConversionUtils.tuweniToPbjBytes;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.assertj.core.api.AssertionsForClassTypes.assertThatCode;
@@ -28,7 +29,8 @@
import com.hedera.node.app.hapi.utils.fee.SigValueObj;
import com.hedera.node.app.service.contract.impl.handlers.ContractGetBytecodeHandler;
import com.hedera.node.app.service.contract.impl.state.ContractStateStore;
-import com.hedera.node.app.service.contract.impl.utils.RedirectBytecodeUtils;
+import com.hedera.node.app.service.contract.impl.state.ScheduleEvmAccount;
+import com.hedera.node.app.service.contract.impl.state.TokenEvmAccount;
import com.hedera.node.app.service.entityid.EntityIdFactory;
import com.hedera.node.app.service.schedule.ReadableScheduleStore;
import com.hedera.node.app.service.token.ReadableAccountStore;
@@ -41,7 +43,6 @@
import com.hederahashgraph.api.proto.java.FeeComponents;
import java.util.Objects;
import java.util.function.Function;
-import org.hyperledger.besu.datatypes.Address;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
@@ -214,6 +215,7 @@ void validateIfNoContractAccountTest() {
@Test
void computeFeesIfNoContractAccountTest() {
givenNoContractAccount();
+ given(entityIdFactory.newAccountId(contractID.contractNumOrElse(0L))).willReturn(accountId);
QueryHeader defaultHeader =
QueryHeader.newBuilder().responseType(ANSWER_ONLY).build();
given(contractGetBytecodeQuery.headerOrElse(QueryHeader.DEFAULT)).willReturn(defaultHeader);
@@ -225,6 +227,7 @@ void computeFeesIfNoContractAccountTest() {
@Test
void findResponseFailsIfNoContractAccountTest() {
givenNoContractAccount();
+ given(entityIdFactory.newAccountId(contractID.contractNumOrElse(0L))).willReturn(accountId);
given(responseHeader.nodeTransactionPrecheckCode()).willReturn(OK);
given(responseHeader.responseType()).willReturn(ANSWER_ONLY);
assertThat(Objects.requireNonNull(
@@ -297,6 +300,7 @@ void validateFailsIfTokenWasDeletedTest() {
@Test
void computeFeesIfTokenWasDeletedTest() {
givenTokenWasDeleted();
+ given(entityIdFactory.newAccountId(contractID.contractNumOrElse(0L))).willReturn(accountId);
QueryHeader defaultHeader =
QueryHeader.newBuilder().responseType(ANSWER_ONLY).build();
given(contractGetBytecodeQuery.headerOrElse(QueryHeader.DEFAULT)).willReturn(defaultHeader);
@@ -308,6 +312,7 @@ void computeFeesIfTokenWasDeletedTest() {
@Test
void findResponseIfTokenWasDeletedTest() {
givenTokenWasDeleted();
+ given(entityIdFactory.newAccountId(contractID.contractNumOrElse(0L))).willReturn(accountId);
given(responseHeader.nodeTransactionPrecheckCode()).willReturn(OK);
given(responseHeader.responseType()).willReturn(ANSWER_ONLY);
assertThat(Objects.requireNonNull(
@@ -365,7 +370,6 @@ void findResponsePositiveTest() {
given(contractGetBytecodeQuery.contractIDOrElse(ContractID.DEFAULT)).willReturn(contractID);
given(context.createStore(ReadableAccountStore.class)).willReturn(contractStore);
given(contractStore.getContractById(contractID)).willReturn(account);
- given(account.smartContract()).willReturn(true);
given(account.accountIdOrThrow()).willReturn(accountId);
given(context.createStore(ContractStateStore.class)).willReturn(stateStore);
@@ -403,6 +407,13 @@ void validateAccountIdAsContractId() {
@Test
void computeFeesAccountIdAsContractId() {
givenAccountIdAsContractId();
+ given(account.accountIdOrThrow()).willReturn(accountId);
+
+ given(context.createStore(ContractStateStore.class)).willReturn(stateStore);
+ final var expectedResult = Bytes.wrap(new byte[] {1, 2, 3, 4, 5});
+ final var bytecode = Bytecode.newBuilder().code(expectedResult).build();
+ given(stateStore.getBytecode(any())).willReturn(bytecode);
+
QueryHeader defaultHeader =
QueryHeader.newBuilder().responseType(ANSWER_ONLY).build();
given(contractGetBytecodeQuery.headerOrElse(QueryHeader.DEFAULT)).willReturn(defaultHeader);
@@ -414,12 +425,18 @@ void computeFeesAccountIdAsContractId() {
@Test
void findResponseAccountIdAsContractId() {
givenAccountIdAsContractId();
+ given(account.accountIdOrThrow()).willReturn(accountId);
+ given(context.createStore(ContractStateStore.class)).willReturn(stateStore);
+ final var expectedResult = Bytes.wrap(new byte[] {1, 2, 3, 4, 5});
+ final var bytecode = Bytecode.newBuilder().code(expectedResult).build();
+ given(stateStore.getBytecode(any())).willReturn(bytecode);
+
given(responseHeader.nodeTransactionPrecheckCode()).willReturn(OK);
given(responseHeader.responseType()).willReturn(ANSWER_ONLY);
- Bytes bytecode = Objects.requireNonNull(
+ Bytes resp = Objects.requireNonNull(
subject.findResponse(context, responseHeader).contractGetBytecodeResponse())
.bytecode();
- assertThat(bytecode).isEqualTo(RedirectBytecodeUtils.accountProxyBytecodePjb(Address.ZERO));
+ assertThat(resp).isEqualTo(expectedResult);
}
private void givenTokenIdAsContractId() {
@@ -459,7 +476,7 @@ void findResponseTokenIdAsContractId() {
Bytes bytecode = Objects.requireNonNull(
subject.findResponse(context, responseHeader).contractGetBytecodeResponse())
.bytecode();
- assertThat(bytecode).isEqualTo(RedirectBytecodeUtils.tokenProxyBytecodePjb(Address.ZERO));
+ assertThat(bytecode).isEqualTo(tuweniToPbjBytes(TokenEvmAccount.CODE));
}
private void givenScheduleIdAsContractId() {
@@ -501,6 +518,6 @@ void findResponseScheduleIdAsContractId() {
Bytes bytecode = Objects.requireNonNull(
subject.findResponse(context, responseHeader).contractGetBytecodeResponse())
.bytecode();
- assertThat(bytecode).isEqualTo(RedirectBytecodeUtils.scheduleProxyBytecodePjb(Address.ZERO));
+ assertThat(bytecode).isEqualTo(tuweniToPbjBytes(ScheduleEvmAccount.CODE));
}
}
diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/state/DispatchingEvmFrameStateTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/state/DispatchingEvmFrameStateTest.java
index ed050c04ebc3..31d139ee1749 100644
--- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/state/DispatchingEvmFrameStateTest.java
+++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/state/DispatchingEvmFrameStateTest.java
@@ -80,8 +80,6 @@
@ExtendWith(MockitoExtension.class)
class DispatchingEvmFrameStateTest {
- private static final int REDIRECT_CODE_FIXED_PREFIX_LEN =
- "6080604052348015600f57600080fd5b506000610167905077618dc65e".length();
private static final int NUM_KV_SLOTS = 42;
private static final long EXPIRY = 1_234_567L;
private static final long ACCOUNT_NUM = 0x9abcdefabcdefbbbL;
@@ -294,100 +292,10 @@ void getsZeroWordForEmptySlotValue() {
@Test
void getsExtantCode() {
givenWellKnownBytecode();
-
final var actualCode = subject.getCode(A_CONTRACT_ID);
-
assertEquals(pbjToTuweniBytes(SOME_PRETEND_CODE), actualCode);
}
- @Test
- void interpolatesTokenCodeByAddress() {
- final var actualCode = subject.getTokenRedirectCode(TOKEN_ADDRESS);
-
- assertEquals(
- TOKEN_ADDRESS.toUnprefixedHexString(),
- actualCode
- .toUnprefixedHexString()
- // EVM 20-byte address is 40 hex chars
- .substring(REDIRECT_CODE_FIXED_PREFIX_LEN, REDIRECT_CODE_FIXED_PREFIX_LEN + 40));
- }
-
- @Test
- void hashesInterpolatesTokenCode() {
- final var code = subject.getTokenRedirectCode(TOKEN_ADDRESS);
- final var expectedHash = Hash.hash(code);
-
- assertEquals(expectedHash, subject.getTokenRedirectCodeHash(TOKEN_ADDRESS));
- }
-
- @Test
- void interpolatesAccountCodeByAddress() {
- final var actualCode = subject.getAccountRedirectCode(LONG_ZERO_ADDRESS);
-
- assertEquals(
- LONG_ZERO_ADDRESS.toUnprefixedHexString(),
- actualCode
- .toUnprefixedHexString()
- // EVM 20-byte address is 40 hex chars
- .substring(REDIRECT_CODE_FIXED_PREFIX_LEN, REDIRECT_CODE_FIXED_PREFIX_LEN + 40));
- }
-
- @Test
- void hashesInterpolatesAccountCode() {
- final var code = subject.getAccountRedirectCode(LONG_ZERO_ADDRESS);
- final var expectedHash = Hash.hash(code);
-
- assertEquals(expectedHash, subject.getAccountRedirectCodeHash(LONG_ZERO_ADDRESS));
- }
-
- @Test
- void interpolatesAccountCodeWhenAddressNull() {
- final var actualCode = subject.getAccountRedirectCode(null);
-
- assertEquals(org.apache.tuweni.bytes.Bytes.EMPTY, actualCode);
- }
-
- @Test
- void hashesInterpolatesAccountCodeWhenNull() {
- final var expectedHash = Hash.hash(org.apache.tuweni.bytes.Bytes.EMPTY);
-
- assertEquals(expectedHash, subject.getAccountRedirectCodeHash(null));
- }
-
- @Test
- void interpolatesScheduleCodeByAddress() {
- final var actualCode = subject.getScheduleRedirectCode(LONG_ZERO_ADDRESS);
-
- assertEquals(
- LONG_ZERO_ADDRESS.toUnprefixedHexString(),
- actualCode
- .toUnprefixedHexString()
- // EVM 20-byte address is 40 hex chars
- .substring(REDIRECT_CODE_FIXED_PREFIX_LEN, REDIRECT_CODE_FIXED_PREFIX_LEN + 40));
- }
-
- @Test
- void hashesInterpolatesScheduleCode() {
- final var code = subject.getScheduleRedirectCode(LONG_ZERO_ADDRESS);
- final var expectedHash = Hash.hash(code);
-
- assertEquals(expectedHash, subject.getScheduleRedirectCodeHash(LONG_ZERO_ADDRESS));
- }
-
- @Test
- void interpolatesScheduleCodeWhenAddressNull() {
- final var actualCode = subject.getScheduleRedirectCode(null);
-
- assertEquals(org.apache.tuweni.bytes.Bytes.EMPTY, actualCode);
- }
-
- @Test
- void hashesInterpolatesScheduleCodeWhenNull() {
- final var expectedHash = Hash.hash(org.apache.tuweni.bytes.Bytes.EMPTY);
-
- assertEquals(expectedHash, subject.getScheduleRedirectCodeHash(null));
- }
-
@Test
void getsEmptyCodeForMissing() {
final var actualCode = subject.getCode(A_CONTRACT_ID);
@@ -416,7 +324,6 @@ void getsExtantCodeHash() {
@Test
void getsEmptyCodeHashForMissing() {
final var actualCodeHash = subject.getCodeHash(A_CONTRACT_ID, CODE_FACTORY);
-
assertSame(Hash.EMPTY, actualCodeHash);
}
diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/state/ProxyEvmAccountTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/state/ProxyEvmAccountTest.java
index a2737ac957fb..f47394030024 100644
--- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/state/ProxyEvmAccountTest.java
+++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/state/ProxyEvmAccountTest.java
@@ -1,21 +1,12 @@
// SPDX-License-Identifier: Apache-2.0
package com.hedera.node.app.service.contract.impl.test.state;
-import static com.hedera.node.app.service.contract.impl.exec.systemcontracts.has.hbarallowance.HbarAllowanceTranslator.HBAR_ALLOWANCE_PROXY;
-import static com.hedera.node.app.service.contract.impl.test.TestHelpers.ACCOUNT_CALL_REDIRECT_CONTRACT_BINARY;
-import static com.hedera.node.app.service.contract.impl.test.TestHelpers.ADDRESS_BYTECODE_PATTERN;
import static com.hedera.node.app.service.contract.impl.test.TestHelpers.CODE_FACTORY;
-import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.BDDMockito.given;
-import static org.mockito.Mockito.when;
import com.hedera.hapi.node.base.AccountID;
import com.hedera.node.app.service.contract.impl.state.DispatchingEvmFrameState;
import com.hedera.node.app.service.contract.impl.state.ProxyEvmAccount;
-import com.hedera.pbj.runtime.io.buffer.Bytes;
-import org.hyperledger.besu.datatypes.Address;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
@@ -27,7 +18,6 @@ class ProxyEvmAccountTest {
private static final long ACCOUNT_NUM = 0x9abcdefabcdefbbbL;
private static final AccountID ACCOUNT_ID =
AccountID.newBuilder().accountNum(ACCOUNT_NUM).build();
- private static final Bytes SOME_PRETEND_CODE = Bytes.wrap("