Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ description = "Default Hedera Smart Contract Service Implementation"

// Remove the following line to enable all 'javac' lint checks that we have turned on by default
// and then fix the reported issues.
tasks.withType<JavaCompile>().configureEach { options.compilerArgs.add("-Xlint:-exports") }
// TODO(Pectra): restore to `options.compilerArgs.add("-Xlint:-exports")`
tasks.withType<JavaCompile>().configureEach { options.compilerArgs.clear() }

mainModuleInfo { annotationProcessor("dagger.compiler") }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

/**
Expand All @@ -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,
Expand All @@ -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);
}

/**
Expand Down Expand Up @@ -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,
Expand All @@ -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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
}

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
import com.hedera.node.app.service.contract.impl.exec.scope.VerificationStrategy;
import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.AddressIdConverter;
import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod;
import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.SystemContract;
import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry;
import com.hedera.node.app.service.contract.impl.hevm.HederaWorldUpdater;
import com.swirlds.config.api.Configuration;
Expand All @@ -21,6 +20,7 @@
import java.nio.BufferUnderflowException;
import java.util.Arrays;
import java.util.Optional;
import java.util.Set;
import org.apache.tuweni.bytes.Bytes;
import org.hyperledger.besu.datatypes.Address;

Expand All @@ -35,51 +35,58 @@ public abstract class AbstractCallAttempt<T extends AbstractCallAttempt<T>> {
protected final AccountID senderId;
protected final Bytes input;
protected final byte[] selector;
// If non-null, the address of a non-contract entity (e.g., account or token) whose
// "bytecode" redirects all calls to a system contract address, and was determined
// to be the redirecting entity for this call attempt
protected @Nullable final Address redirectAddress;
protected final Optional<Address> maybeRedirectAddress;

private boolean matchesFnSelector(Function fn, Bytes input) {
final var selector = fn.selector();
return Arrays.equals(input.toArrayUnsafe(), 0, selector.length, selector, 0, selector.length);
}

/**
* @param input the input in bytes
* @param options the AbstractCallAttempt parameters and options
* @param redirectFunction the redirect function
*/
public AbstractCallAttempt(
// we are keeping the 'input' out of the 'options' for not duplicate and keep close to related params
@NonNull final Bytes input,
@NonNull final CallAttemptOptions<T> options,
@NonNull final Function redirectFunction) {
Set<Address> systemContractAddresses,
Function legacyRedirectFunction) {
requireNonNull(input);
requireNonNull(redirectFunction);
this.options = requireNonNull(options);
this.senderId = options.addressIdConverter().convertSender(options.senderAddress());

if (isRedirectSelector(redirectFunction.selector(), input.toArrayUnsafe())) {
// If the recipient address of this call doesn't match the system contract address
// it means we're running an EIP-7702 delegation (i.e. a facade/redirect call).
final var isDelegationRedirect = !systemContractAddresses.contains(options.recipientAddress());
if (isDelegationRedirect) {
this.maybeRedirectAddress = Optional.of(options.recipientAddress());
this.input = input;
} else if (matchesFnSelector(legacyRedirectFunction, input)) {
Tuple abiCall = null;
try {
// First try to decode the redirect with standard ABI encoding using a 32-byte address
abiCall = redirectFunction.decodeCall(input.toArrayUnsafe());
abiCall = legacyRedirectFunction.decodeCall(input.toArrayUnsafe());
} catch (IllegalArgumentException | BufferUnderflowException | IndexOutOfBoundsException ignore) {
// Otherwise use the "packed" encoding with a 20-byte address
// no-op
}
if (abiCall != null) {
this.redirectAddress = Address.fromHexString(abiCall.get(0).toString());
this.maybeRedirectAddress =
Optional.of(Address.fromHexString(abiCall.get(0).toString()));
this.input = Bytes.wrap((byte[]) abiCall.get(1));
} else {
this.redirectAddress = Address.wrap(input.slice(4, 20));
// TODO(Pectra): consider dropping support for proxy calls that don't confirm to ABI
this.maybeRedirectAddress = Optional.of(Address.wrap(input.slice(4, 20)));
this.input = input.slice(24);
}
} else {
this.redirectAddress = null;
// A regular call; neither EIP-7702 redirect nor legacy redirect function. Process as-is.
this.maybeRedirectAddress = Optional.empty();
this.input = input;
}

this.selector = this.input.slice(0, 4).toArrayUnsafe();
}

protected abstract SystemContract systemContractKind();

protected abstract T self();

/**
Expand Down Expand Up @@ -216,7 +223,7 @@ public boolean isStaticCall() {
* @return whether the current call attempt is redirected to a system contract address
*/
public boolean isRedirect() {
return redirectAddress != null;
return this.maybeRedirectAddress.isPresent();
}

/**
Expand Down Expand Up @@ -262,16 +269,6 @@ public boolean isSelectorIfConfigEnabled(
return configEnabled && isSelector(methods);
}

/**
* Returns whether this call attempt is a selector for any of the given functions.
* @param functionSelector bytes of the function selector
* @param input input bytes
* @return true if the function selector at the start of the input bytes
*/
private boolean isRedirectSelector(@NonNull final byte[] functionSelector, @NonNull final byte[] input) {
return Arrays.equals(input, 0, functionSelector.length, functionSelector, 0, functionSelector.length);
}

/**
* Returns whether only delegate contract keys are active.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
public record CallAttemptOptions<T extends AbstractCallAttempt<T>>(
@NonNull ContractID contractID,
@NonNull Address senderAddress,
@NonNull Address recipientAddress,
@NonNull Address authorizingAddress,
boolean onlyDelegatableContractKeysActive,
@NonNull HederaWorldUpdater.Enhancement enhancement,
Expand All @@ -32,6 +33,7 @@ public record CallAttemptOptions<T extends AbstractCallAttempt<T>>(
/**
* @param contractID the target system contract ID
* @param senderAddress the address of the sender of this call
* @param recipientAddress the recipient address of this call
* @param authorizingAddress the contract whose keys are to be activated
* @param onlyDelegatableContractKeysActive whether the strategy should require a delegatable contract id key
* @param enhancement the enhancement to get the native operations to look up the contract's number
Expand All @@ -46,6 +48,7 @@ public record CallAttemptOptions<T extends AbstractCallAttempt<T>>(
public CallAttemptOptions(
@NonNull final ContractID contractID,
@NonNull final Address senderAddress,
@NonNull final Address recipientAddress,
@NonNull final Address authorizingAddress,
final boolean onlyDelegatableContractKeysActive,
@NonNull final Enhancement enhancement,
Expand All @@ -58,6 +61,7 @@ public CallAttemptOptions(
final boolean isStaticCall) {
this.contractID = requireNonNull(contractID);
this.senderAddress = requireNonNull(senderAddress);
this.recipientAddress = requireNonNull(recipientAddress);
this.authorizingAddress = requireNonNull(authorizingAddress);
this.onlyDelegatableContractKeysActive = onlyDelegatableContractKeysActive;
this.enhancement = requireNonNull(enhancement);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: Apache-2.0
package com.hedera.node.app.service.contract.impl.exec.systemcontracts.has;

import static com.hedera.node.app.service.contract.impl.exec.systemcontracts.HasSystemContract.HAS_EVM_ADDRESS;
import static com.hedera.node.app.service.contract.impl.utils.ConversionUtils.isLongZero;
import static com.hedera.node.app.service.contract.impl.utils.ConversionUtils.numberOfLongZero;
import static java.util.Objects.requireNonNull;
Expand All @@ -13,12 +14,11 @@
import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.AbstractCallAttempt;
import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.Call;
import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.CallAttemptOptions;
import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod;
import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.SystemContract;
import com.hedera.node.app.spi.signatures.SignatureVerifier;
import com.hedera.node.config.data.HederaConfig;
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;

Expand All @@ -28,8 +28,9 @@
* everything it will need to execute.
*/
public class HasCallAttempt extends AbstractCallAttempt<HasCallAttempt> {
/** Selector for redirectForAccount(address,bytes) method. */
public static final Function REDIRECT_FOR_ACCOUNT = new Function("redirectForAccount(address,bytes)");
private static final Set<Address> HAS_ADDRESSES = Set.of(Address.fromHexString(HAS_EVM_ADDRESS));

public static final Function LEGACY_REDIRECT_FOR_ACCOUNT = new Function("redirectForAccount(address,bytes)");

@Nullable
private final Account redirectAccount;
Expand All @@ -41,18 +42,12 @@ public HasCallAttempt(
@NonNull final Bytes input,
@NonNull final CallAttemptOptions<HasCallAttempt> options,
@NonNull final SignatureVerifier signatureVerifier) {
super(input, options, REDIRECT_FOR_ACCOUNT);
if (isRedirect()) {
this.redirectAccount = linkedAccount(requireNonNull(redirectAddress));
} else {
this.redirectAccount = null;
}
this.signatureVerifier = requireNonNull(signatureVerifier);
}
super(input, options, HAS_ADDRESSES, LEGACY_REDIRECT_FOR_ACCOUNT);

@Override
protected SystemContract systemContractKind() {
return SystemContractMethod.SystemContract.HAS;
this.redirectAccount =
this.maybeRedirectAddress.map(this::linkedAccount).orElse(null);

this.signatureVerifier = requireNonNull(signatureVerifier);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: Apache-2.0
package com.hedera.node.app.service.contract.impl.exec.systemcontracts.has;

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.utils.FrameUtils.configOf;
import static com.hedera.node.app.service.contract.impl.exec.utils.FrameUtils.proxyUpdaterFor;
import static com.hedera.node.app.service.contract.impl.exec.utils.FrameUtils.systemContractGasCalculatorOf;
Expand All @@ -18,10 +19,12 @@
import com.hedera.node.app.spi.signatures.SignatureVerifier;
import edu.umd.cs.findbugs.annotations.NonNull;
import java.util.List;
import java.util.Optional;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import org.apache.tuweni.bytes.Bytes;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.evm.frame.MessageFrame;

/**
Expand Down Expand Up @@ -69,11 +72,19 @@ public HasCallFactory(
requireNonNull(input);
requireNonNull(frame);
final var enhancement = proxyUpdaterFor(frame).enhancement();

// If we're executing a HAS call, but the recipient isn't the HAS address
// then it must be a redirect/delegate call.
final var isRedirect = !frame.getRecipientAddress().equals(Address.fromHexString(HAS_EVM_ADDRESS));
final Optional<Address> maybeRedirectAddress =
isRedirect ? Optional.of(frame.getRecipientAddress()) : Optional.empty();

return new HasCallAttempt(
input,
new CallAttemptOptions<>(
contractID,
frame.getSenderAddress(),
frame.getRecipientAddress(),
frame.getSenderAddress(),
addressChecks.hasParentDelegateCall(frame),
enhancement,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: Apache-2.0
package com.hedera.node.app.service.contract.impl.exec.systemcontracts.hss;

import static com.hedera.node.app.service.contract.impl.exec.systemcontracts.HssSystemContract.HSS_EVM_ADDRESS;
import static com.hedera.node.app.service.contract.impl.utils.ConversionUtils.isLongZero;
import static com.hedera.node.app.service.contract.impl.utils.ConversionUtils.maybeMissingNumberOf;
import static com.hedera.node.app.service.contract.impl.utils.ConversionUtils.numberOfLongZero;
Expand All @@ -15,8 +16,6 @@
import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.AbstractCallAttempt;
import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.Call;
import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.CallAttemptOptions;
import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod;
import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.SystemContract;
import com.hedera.node.app.spi.signatures.SignatureVerifier;
import edu.umd.cs.findbugs.annotations.NonNull;
import edu.umd.cs.findbugs.annotations.Nullable;
Expand All @@ -30,8 +29,10 @@
* everything it will need to execute.
*/
public class HssCallAttempt extends AbstractCallAttempt<HssCallAttempt> {
/** Selector for redirectForScheduleTxn(address,bytes) method. */
public static final Function REDIRECT_FOR_SCHEDULE_TXN = new Function("redirectForScheduleTxn(address,bytes)");
private static final Set<Address> HSS_ADDRESSES = Set.of(Address.fromHexString(HSS_EVM_ADDRESS));

public static final Function LEGACY_REDIRECT_FOR_SCHEDULE_TXN =
new Function("redirectForScheduleTxn(address,bytes)");

@Nullable
private final Schedule redirectScheduleTxn;
Expand All @@ -43,18 +44,12 @@ public HssCallAttempt(
@NonNull final Bytes input,
@NonNull final CallAttemptOptions<HssCallAttempt> options,
@NonNull final SignatureVerifier signatureVerifier) {
super(input, options, REDIRECT_FOR_SCHEDULE_TXN);
if (isRedirect()) {
this.redirectScheduleTxn = linkedSchedule(requireNonNull(redirectAddress));
} else {
this.redirectScheduleTxn = null;
}
this.signatureVerifier = signatureVerifier;
}
super(input, options, HSS_ADDRESSES, LEGACY_REDIRECT_FOR_SCHEDULE_TXN);

@Override
protected SystemContract systemContractKind() {
return SystemContractMethod.SystemContract.HSS;
this.redirectScheduleTxn =
this.maybeRedirectAddress.map(this::linkedSchedule).orElse(null);

this.signatureVerifier = signatureVerifier;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ public HssCallFactory(
new CallAttemptOptions<>(
contractID,
frame.getSenderAddress(),
frame.getRecipientAddress(),
frame.getSenderAddress(),
addressChecks.hasParentDelegateCall(frame),
enhancement,
Expand Down
Loading
Loading