Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

feat: implement system contract versioning foundation #17611

Merged
merged 3 commits into from
Feb 3, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
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 @@ -126,6 +126,8 @@ public record ContractsConfig(
@ConfigProperty(value = "systemContract.setUnlimitedAutoAssociations.enabled", defaultValue = "true")
@NetworkProperty
boolean systemContractSetUnlimitedAutoAssociationsEnabled,
@ConfigProperty(value = "systemContract.callable.hts.address", defaultValue = "359")
david-bakin-sl marked this conversation as resolved.
Show resolved Hide resolved
Set<Long> callableHTSAddresses,
@ConfigProperty(value = "evm.ethTransaction.zeroHapiFees.enabled", defaultValue = "false") @NetworkProperty
boolean evmEthTransactionZeroHapiFeesEnabled,
@ConfigProperty(value = "evm.allowCallsToNonContractAccounts", defaultValue = "true") @NetworkProperty
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import static com.hedera.node.app.service.contract.impl.exec.utils.FrameUtils.transfersValue;
import static com.hedera.node.app.service.contract.impl.hevm.HevmPropagatedCallFailure.MISSING_RECEIVER_SIGNATURE;
import static com.hedera.node.app.service.contract.impl.hevm.HevmPropagatedCallFailure.RESULT_CANNOT_BE_EXTERNALIZED;
import static com.hedera.node.app.service.contract.impl.utils.ConversionUtils.asNumberedContractId;
import static org.hyperledger.besu.evm.frame.ExceptionalHaltReason.INSUFFICIENT_GAS;
import static org.hyperledger.besu.evm.frame.MessageFrame.State.EXCEPTIONAL_HALT;

Expand Down Expand Up @@ -137,7 +138,7 @@ public void start(@NonNull final MessageFrame frame, @NonNull final OperationTra
return;
}
}
doExecuteSystemContract(systemContracts.get(codeAddress), frame, tracer);
doExecuteSystemContract(systemContracts.get(codeAddress), codeAddress, frame, tracer);
return;
}

Expand Down Expand Up @@ -252,9 +253,11 @@ private void doExecutePrecompile(
*/
private void doExecuteSystemContract(
@NonNull final HederaSystemContract systemContract,
@NonNull final Address systemContractAddress,
@NonNull final MessageFrame frame,
@NonNull final OperationTracer tracer) {
final var fullResult = systemContract.computeFully(frame.getInputData(), frame);
final var fullResult =
systemContract.computeFully(asNumberedContractId(systemContractAddress), frame.getInputData(), frame);
final var gasRequirement = fullResult.gasRequirement();
final PrecompileContractResult result;
if (frame.getRemainingGas() < gasRequirement) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright (C) 2023-2025 Hedera Hashgraph, LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.hedera.node.app.service.contract.impl.exec.processors;

import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.CallTranslator;
import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallAttempt;
import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.address_0x16c.balanceof.BalanceOfTranslator;
import dagger.Module;
import dagger.Provides;
import dagger.multibindings.IntoSet;
import edu.umd.cs.findbugs.annotations.NonNull;
import javax.inject.Named;
import javax.inject.Singleton;

/**
* Provides the {@link CallTranslator} implementations for the HTS system contract at address 0x16c.
*/
@Module
public interface Hts0x16cTranslatorsModule {

@Provides
@Singleton
@IntoSet
@Named("HtsTranslators")
static CallTranslator<HtsCallAttempt> provideBalanceOfTranslator(@NonNull final BalanceOfTranslator translator) {
return translator;
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2023-2024 Hedera Hashgraph, LLC
* Copyright (C) 2023-2025 Hedera Hashgraph, LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -478,4 +478,19 @@ static CallTranslator<HtsCallAttempt> provideTokenRejectsTranslator(
@NonNull final RejectTokensTranslator translator) {
return translator;
}

/**
* Provides Translator for HTS System Contraact at address 0x16c
david-bakin-sl marked this conversation as resolved.
Show resolved Hide resolved
*/
@Provides
@Singleton
@IntoSet
@Named("HtsTranslators")
static CallTranslator<HtsCallAttempt> provideBalanceOfTranslator_16c(
david-bakin-sl marked this conversation as resolved.
Show resolved Hide resolved
@NonNull
final com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.address_0x16c.balanceof
.BalanceOfTranslator
translator) {
return translator;
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2023-2024 Hedera Hashgraph, LLC
* Copyright (C) 2023-2025 Hedera Hashgraph, LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -19,7 +19,8 @@
import static com.hedera.node.app.service.contract.impl.exec.systemcontracts.ExchangeRateSystemContract.EXCHANGE_RATE_SYSTEM_CONTRACT_ADDRESS;
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_EVM_ADDRESS;
import static com.hedera.node.app.service.contract.impl.exec.systemcontracts.HtsSystemContract.HTS_EVM_ADDRESS;
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.HtsSystemContract.HTS_16C_EVM_ADDRESS;
import static com.hedera.node.app.service.contract.impl.exec.systemcontracts.PrngSystemContract.PRNG_PRECOMPILE_ADDRESS;
import static java.util.Map.entry;
import static java.util.Objects.requireNonNull;
Expand All @@ -41,7 +42,13 @@
import org.hyperledger.besu.evm.contractvalidation.MaxCodeSizeRule;
import org.hyperledger.besu.evm.contractvalidation.PrefixCodeRule;

@Module(includes = {HtsTranslatorsModule.class, HasTranslatorsModule.class, HssTranslatorsModule.class})
@Module(
includes = {
HtsTranslatorsModule.class,
Hts0x16cTranslatorsModule.class,
david-bakin-sl marked this conversation as resolved.
Show resolved Hide resolved
HasTranslatorsModule.class,
HssTranslatorsModule.class
})
public interface ProcessorModule {
long INITIAL_CONTRACT_NONCE = 1L;
boolean REQUIRE_CODE_DEPOSIT_TO_SUCCEED = true;
Expand Down Expand Up @@ -70,7 +77,8 @@ static Map<Address, HederaSystemContract> provideHederaSystemContracts(
@NonNull final HasSystemContract hasSystemContract,
@NonNull final HssSystemContract hssSystemContract) {
return Map.ofEntries(
entry(Address.fromHexString(HTS_EVM_ADDRESS), requireNonNull(htsSystemContract)),
entry(Address.fromHexString(HTS_167_EVM_ADDRESS), requireNonNull(htsSystemContract)),
entry(Address.fromHexString(HTS_16C_EVM_ADDRESS), requireNonNull(htsSystemContract)),
entry(
Address.fromHexString(EXCHANGE_RATE_SYSTEM_CONTRACT_ADDRESS),
requireNonNull(exchangeRateSystemContract)),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2022-2024 Hedera Hashgraph, LLC
* Copyright (C) 2022-2025 Hedera Hashgraph, LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -19,18 +19,21 @@
import static com.hedera.node.app.hapi.utils.ValidationUtils.validateTrue;
import static com.hedera.node.app.service.contract.impl.exec.utils.FrameUtils.contractsConfigOf;
import static com.hedera.node.app.service.contract.impl.exec.utils.FrameUtils.proxyUpdaterFor;
import static com.hedera.node.app.service.contract.impl.utils.ConversionUtils.asNumberedContractId;
import static com.hederahashgraph.api.proto.java.ResponseCodeEnum.INVALID_TRANSACTION_BODY;
import static java.util.Objects.requireNonNull;

import com.esaulpaugh.headlong.abi.BigIntegerType;
import com.esaulpaugh.headlong.abi.TypeFactory;
import com.hedera.hapi.node.base.ContractID;
import com.hedera.node.app.service.contract.impl.utils.ConversionUtils;
import edu.umd.cs.findbugs.annotations.NonNull;
import java.math.BigInteger;
import java.util.Optional;
import javax.inject.Inject;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.evm.frame.ExceptionalHaltReason;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.gascalculator.GasCalculator;
Expand All @@ -45,6 +48,9 @@ public class ExchangeRateSystemContract extends AbstractFullContract implements
public static final int TO_TINYCENTS_SELECTOR = 0x43a88229;

public static final String EXCHANGE_RATE_SYSTEM_CONTRACT_ADDRESS = "0x168";
public static final ContractID EXCHANGE_RATE_CONTRACT_ID =
asNumberedContractId(Address.fromHexString(EXCHANGE_RATE_SYSTEM_CONTRACT_ADDRESS));

private long gasRequirement;

@Inject
Expand All @@ -54,7 +60,8 @@ public ExchangeRateSystemContract(@NonNull final GasCalculator gasCalculator) {

@Override
@NonNull
public FullResult computeFully(@NonNull Bytes input, @NonNull MessageFrame messageFrame) {
public FullResult computeFully(
@NonNull ContractID contractID, @NonNull Bytes input, @NonNull MessageFrame messageFrame) {
requireNonNull(input);
requireNonNull(messageFrame);
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
@NonNull final GasCalculator gasCalculator,
@NonNull final HasCallFactory callFactory,
@NonNull final ContractMetrics contractMetrics) {
super(HAS_SYSTEM_CONTRACT_NAME, callFactory, HAS_CONTRACT_ID, gasCalculator, contractMetrics);
super(HAS_SYSTEM_CONTRACT_NAME, callFactory, gasCalculator, contractMetrics);
}

@Override
Expand All @@ -56,7 +56,8 @@
}

@Override
public FullResult computeFully(@NonNull final Bytes input, @NonNull final MessageFrame frame) {
public FullResult computeFully(
@NonNull ContractID contractID, @NonNull final Bytes input, @NonNull final MessageFrame frame) {
requireNonNull(input);
requireNonNull(frame);

Expand All @@ -65,6 +66,6 @@
return haltResult(NOT_SUPPORTED, frame.getRemainingGas());
}

return super.computeFully(input, frame);
return super.computeFully(contractID, input, frame);

Check warning on line 69 in hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/HasSystemContract.java

View check run for this annotation

Codecov / codecov/patch

hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/HasSystemContract.java#L69

Added line #L69 was not covered by tests
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2023-2024 Hedera Hashgraph, LLC
* Copyright (C) 2023-2025 Hedera Hashgraph, LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -16,6 +16,7 @@

package com.hedera.node.app.service.contract.impl.exec.systemcontracts;

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.frame.MessageFrame;
Expand All @@ -35,11 +36,13 @@ public interface HederaSystemContract extends PrecompiledContract {
/**
* Computes the result of this contract, and also returns the gas requirement.
*
* @param contractID the contractID of the called system contract
* @param input the input to the contract
* @param messageFrame the message frame
* @return the result of the computation, and its gas requirement
*/
default FullResult computeFully(@NonNull Bytes input, @NonNull MessageFrame messageFrame) {
default FullResult computeFully(
@NonNull ContractID contractID, @NonNull Bytes input, @NonNull MessageFrame messageFrame) {
return new FullResult(computePrecompile(input, messageFrame), gasRequirement(input), null);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
@NonNull final GasCalculator gasCalculator,
@NonNull final HssCallFactory callFactory,
@NonNull final ContractMetrics contractMetrics) {
super(HSS_SYSTEM_CONTRACT_NAME, callFactory, HSS_CONTRACT_ID, gasCalculator, contractMetrics);
super(HSS_SYSTEM_CONTRACT_NAME, callFactory, gasCalculator, contractMetrics);
}

@Override
Expand All @@ -59,7 +59,8 @@
}

@Override
public FullResult computeFully(@NonNull final Bytes input, @NonNull final MessageFrame frame) {
public FullResult computeFully(
@NonNull ContractID contractID, @NonNull final Bytes input, @NonNull final MessageFrame frame) {
requireNonNull(input);
requireNonNull(frame);

Expand All @@ -68,6 +69,6 @@
return haltResult(NOT_SUPPORTED, frame.getRemainingGas());
}

return super.computeFully(input, frame);
return super.computeFully(contractID, input, frame);

Check warning on line 72 in hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/HssSystemContract.java

View check run for this annotation

Codecov / codecov/patch

hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/HssSystemContract.java#L72

Added line #L72 was not covered by tests
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@

package com.hedera.node.app.service.contract.impl.exec.systemcontracts;

import static com.hedera.node.app.service.contract.impl.exec.failure.CustomExceptionalHaltReason.NOT_SUPPORTED;
import static com.hedera.node.app.service.contract.impl.exec.systemcontracts.FullResult.haltResult;
import static com.hedera.node.app.service.contract.impl.exec.utils.FrameUtils.contractsConfigOf;
import static com.hedera.node.app.service.contract.impl.utils.ConversionUtils.asNumberedContractId;

import com.hedera.hapi.node.base.ContractID;
Expand All @@ -27,26 +30,43 @@
import edu.umd.cs.findbugs.annotations.NonNull;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.apache.tuweni.bytes.Bytes;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.gascalculator.GasCalculator;

@Singleton
public class HtsSystemContract extends AbstractNativeSystemContract implements HederaSystemContract {
public static final String HTS_SYSTEM_CONTRACT_NAME = "HTS";
public static final String HTS_EVM_ADDRESS = "0x167";
public static final ContractID HTS_CONTRACT_ID = asNumberedContractId(Address.fromHexString(HTS_EVM_ADDRESS));
public static final String HTS_SYSTEM_CONTRACT_NAME = "HTS_167";
david-bakin-sl marked this conversation as resolved.
Show resolved Hide resolved
public static final String HTS_167_EVM_ADDRESS = "0x167";
public static final String HTS_16C_EVM_ADDRESS = "0x16C";
public static final ContractID HTS_167_CONTRACT_ID =
asNumberedContractId(Address.fromHexString(HTS_167_EVM_ADDRESS));
public static final ContractID HTS_16C_CONTRACT_ID =
asNumberedContractId(Address.fromHexString(HTS_16C_EVM_ADDRESS));

@Inject
public HtsSystemContract(
@NonNull final GasCalculator gasCalculator,
@NonNull final HtsCallFactory callFactory,
@NonNull final ContractMetrics contractMetrics) {
super(HTS_SYSTEM_CONTRACT_NAME, callFactory, HTS_CONTRACT_ID, gasCalculator, contractMetrics);
super(HTS_SYSTEM_CONTRACT_NAME, callFactory, gasCalculator, contractMetrics);
}

@Override
protected FrameUtils.CallType callTypeOf(@NonNull MessageFrame frame) {
return FrameUtils.callTypeOf(frame, EntityType.TOKEN);
}

@Override
public FullResult computeFully(
@NonNull ContractID contractID, @NonNull final Bytes input, @NonNull final MessageFrame frame) {

// Check if calls to the current contract address are enabled
if (!contractsConfigOf(frame).callableHTSAddresses().contains(contractID.contractNum())) {
return haltResult(NOT_SUPPORTED, frame.getRemainingGas());

Check warning on line 67 in hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/HtsSystemContract.java

View check run for this annotation

Codecov / codecov/patch

hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/HtsSystemContract.java#L67

Added line #L67 was not covered by tests
}

return super.computeFully(contractID, input, frame);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2022-2024 Hedera Hashgraph, LLC
* Copyright (C) 2022-2025 Hedera Hashgraph, LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -20,7 +20,7 @@
import static com.hedera.node.app.hapi.utils.CommonPbjConverters.toPbj;
import static com.hedera.node.app.hapi.utils.ValidationUtils.validateTrue;
import static com.hedera.node.app.service.contract.impl.exec.utils.FrameUtils.systemContractGasCalculatorOf;
import static com.hedera.node.app.service.contract.impl.utils.ConversionUtils.asEvmContractId;
import static com.hedera.node.app.service.contract.impl.utils.ConversionUtils.asNumberedContractId;
import static com.hedera.node.app.service.contract.impl.utils.ConversionUtils.tuweniToPbjBytes;
import static com.hedera.node.app.service.contract.impl.utils.SystemContractUtils.successResultOfZeroValueTraceable;
import static com.hederahashgraph.api.proto.java.ResponseCodeEnum.FAIL_INVALID;
Expand Down Expand Up @@ -63,6 +63,8 @@ public class PrngSystemContract extends AbstractFullContract implements HederaSy
// random256BitGenerator(uint256)
static final int PSEUDORANDOM_SEED_GENERATOR_SELECTOR = 0xd83bf9a1;
public static final String PRNG_PRECOMPILE_ADDRESS = "0x169";
public static final ContractID PRNG_CONTRACT_ID =
asNumberedContractId(Address.fromHexString(PRNG_PRECOMPILE_ADDRESS));
private long gasRequirement;

@Inject
Expand All @@ -71,16 +73,14 @@ public PrngSystemContract(@NonNull final GasCalculator gasCalculator) {
}

@Override
public FullResult computeFully(@NonNull final Bytes input, @NonNull final MessageFrame frame) {
public FullResult computeFully(
@NonNull ContractID contractID, @NonNull final Bytes input, @NonNull final MessageFrame frame) {
requireNonNull(input);
requireNonNull(frame);

// compute the gas requirement
gasRequirement = calculateGas(frame);

// get the contract ID
final ContractID contractID = asEvmContractId(Address.fromHexString(PRNG_PRECOMPILE_ADDRESS));

try {
validateTrue(input.size() >= 4, INVALID_TRANSACTION_BODY);
// compute the pseudorandom number
Expand Down
Loading