From ae5cb0a67c43152fbe9342defb286a2e7a7b0f34 Mon Sep 17 00:00:00 2001 From: David S Bakin <117694041+david-bakin-sl@users.noreply.github.com> Date: Tue, 3 Dec 2024 15:21:57 -0800 Subject: [PATCH] Smart contract service metrics, P2 priority. These are the metrics that are interesting now and we can collect in the consensus node, but later we'll collect in other ways. E.g., from block nodes. (All these metrics are for post-consensus transactions and will show up in the record/block stream.) Does _not_ include metrics for ExchangeRate and PNRG system contracts: Those system contracts are coded differently (don't use the same base (abstract) classes as HAS/HSS/HTS) and so will need a bit more work. Related issue(s): Fixes #16088 Reviewer notes: Changes a boatload of files. Each of the ~60 FooTranslator classes (about one for each system contract method) needs a small change, but that's a change to the construtor, and so it had effects on all the unit tests for those classes as well. You'll quickly see the pattern ... Signed-off-by: David S Bakin <117694041+david-bakin-sl@users.noreply.github.com> --- .../com/hedera/node/app/spi/RpcService.java | 12 +- .../main/java/com/hedera/node/app/Hedera.java | 13 +- .../impl/ContractServiceComponent.java | 26 +- .../contract/impl/ContractServiceImpl.java | 38 +- .../impl/exec/metrics/ContractMetrics.java | 413 ++++++++++++++---- .../CustomMessageCallProcessor.java | 6 +- .../systemcontracts/HasSystemContract.java | 10 +- .../systemcontracts/HssSystemContract.java | 10 +- .../systemcontracts/HtsSystemContract.java | 10 +- .../systemcontracts/common/AbstractCall.java | 12 +- .../common/AbstractCallAttempt.java | 44 +- .../common/AbstractCallTranslator.java | 63 ++- .../common/AbstractNativeSystemContract.java | 27 +- .../exec/systemcontracts/common/Call.java | 9 +- .../common/CallTranslator.java | 25 +- .../systemcontracts/has/HasCallAttempt.java | 12 +- .../systemcontracts/has/HasCallFactory.java | 9 +- .../EvmAddressAliasTranslator.java | 29 +- .../HbarAllowanceTranslator.java | 37 +- .../hbarapprove/HbarApproveTranslator.java | 34 +- .../HederaAccountNumAliasTranslator.java | 29 +- .../isauthorized/IsAuthorizedTranslator.java | 28 +- .../IsAuthorizedRawTranslator.java | 30 +- .../isvalidalias/IsValidAliasTranslator.java | 28 +- ...etUnlimitedAutoAssociationsTranslator.java | 27 +- .../systemcontracts/hss/HssCallAttempt.java | 10 + .../systemcontracts/hss/HssCallFactory.java | 9 +- .../ScheduleNativeTranslator.java | 37 +- .../signschedule/SignScheduleTranslator.java | 43 +- .../systemcontracts/hts/HtsCallAttempt.java | 12 +- .../systemcontracts/hts/HtsCallFactory.java | 9 +- .../hts/airdrops/TokenAirdropTranslator.java | 29 +- .../hts/allowance/GetAllowanceTranslator.java | 39 +- .../associations/AssociationsTranslator.java | 57 ++- .../hts/balanceof/BalanceOfTranslator.java | 31 +- .../hts/burn/BurnTranslator.java | 35 +- .../TokenCancelAirdropDecoder.java | 4 +- .../TokenCancelAirdropTranslator.java | 49 ++- .../TokenClaimAirdropDecoder.java | 4 +- .../TokenClaimAirdropTranslator.java | 51 ++- .../hts/create/CreateTranslator.java | 340 ++++++++------ .../customfees/TokenCustomFeesTranslator.java | 35 +- .../hts/decimals/DecimalsTranslator.java | 30 +- .../DefaultFreezeStatusTranslator.java | 33 +- .../DefaultKycStatusTranslator.java | 33 +- .../hts/delete/DeleteTranslator.java | 28 +- .../hts/freeze/FreezeUnfreezeTranslator.java | 33 +- .../FungibleTokenInfoCall.java | 4 +- .../FungibleTokenInfoTranslator.java | 49 ++- .../getapproved/GetApprovedTranslator.java | 38 +- .../GrantApprovalTranslator.java | 49 ++- .../GrantRevokeKycTranslator.java | 33 +- .../IsApprovedForAllTranslator.java | 35 +- .../isassociated/IsAssociatedTranslator.java | 27 +- .../hts/isfrozen/IsFrozenTranslator.java | 32 +- .../hts/iskyc/IsKycTranslator.java | 32 +- .../hts/istoken/IsTokenTranslator.java | 32 +- .../hts/mint/MintTranslator.java | 36 +- .../hts/name/NameTranslator.java | 30 +- .../hts/nfttokeninfo/NftTokenInfoCall.java | 4 +- .../nfttokeninfo/NftTokenInfoTranslator.java | 47 +- .../hts/ownerof/OwnerOfTranslator.java | 30 +- .../hts/pauses/PausesTranslator.java | 34 +- .../rejecttokens/RejectTokensTranslator.java | 51 ++- .../SetApprovalForAllTranslator.java | 39 +- .../hts/symbol/SymbolTranslator.java | 30 +- .../tokenexpiry/TokenExpiryTranslator.java | 33 +- .../hts/tokeninfo/TokenInfoCall.java | 4 +- .../hts/tokeninfo/TokenInfoTranslator.java | 49 ++- .../hts/tokenkey/TokenKeyTranslator.java | 33 +- .../hts/tokentype/TokenTypeTranslator.java | 32 +- .../hts/tokenuri/TokenUriTranslator.java | 30 +- .../totalsupply/TotalSupplyTranslator.java | 28 +- .../transfer/ClassicTransfersTranslator.java | 104 +++-- .../transfer/Erc20TransfersTranslator.java | 39 +- .../Erc721TransferFromTranslator.java | 31 +- .../hts/update/UpdateExpiryTranslator.java | 35 +- .../hts/update/UpdateKeysTranslator.java | 27 +- .../update/UpdateNFTsMetadataTranslator.java | 32 +- .../hts/update/UpdateTranslator.java | 69 ++- .../UpdateTokenCustomFeesTranslator.java | 41 +- .../hts/wipe/WipeTranslator.java | 42 +- .../impl/exec/utils/SystemContractMethod.java | 365 ++++++++++++++++ .../utils/SystemContractMethodRegistry.java | 130 ++++++ .../AbstractContractTransactionHandler.java | 7 +- .../impl/handlers/ContractCallHandler.java | 4 +- .../handlers/ContractCallLocalHandler.java | 9 +- .../impl/handlers/ContractCreateHandler.java | 4 +- .../handlers/EthereumTransactionHandler.java | 6 +- .../exec/metrics/ContractMetricsTest.java | 24 +- .../systemcontracts/CallAttemptHelpers.java | 205 ++++++++- .../HasSystemContractTest.java | 8 +- .../HssSystemContractTest.java | 8 +- .../HtsSystemContractTest.java | 8 +- .../has/HasCallAttemptTest.java | 19 +- .../has/HasCallFactoryTest.java | 14 +- .../EvmAddressAliasTranslatorTest.java | 23 +- .../HbarAllowanceTranslatorTest.java | 28 +- .../HbarApproveTranslatorTest.java | 28 +- .../HederaAccountNumAliasTranslatorTest.java | 23 +- .../IsAuthorizedTranslatorTest.java | 24 +- .../IsAuthorizedRawTranslatorTest.java | 26 +- .../IsValidAliasTranslatorTest.java | 23 +- ...limitedAutoAssociationsTranslatorTest.java | 19 +- .../hss/HssCallAttemptTest.java | 12 +- .../hss/HssCallFactoryTest.java | 14 +- .../ScheduleNativeTranslatorTest.java | 19 +- .../SignScheduleTranslatorTest.java | 68 ++- .../hts/HtsCallAttemptTest.java | 52 ++- .../hts/HtsCallFactoryTest.java | 15 +- .../airdrops/TokenAirdropTranslatorTest.java | 26 +- .../allowance/GetAllowanceTranslatorTest.java | 39 +- .../hts/burn/BurnTranslatorTest.java | 39 +- .../TokenCancelAirdropDecoderTest.java | 12 +- .../TokenCancelAirdropTranslatorTest.java | 78 ++-- .../TokenClaimAirdropDecoderTest.java | 12 +- .../TokenClaimAirdropTranslatorTest.java | 87 ++-- .../hts/create/CreateTranslatorTest.java | 97 ++-- .../TokenCustomFeesTranslatorTest.java | 33 +- .../DefaultFreezeStatusTranslatorTest.java | 33 +- .../DefaultKycStatusTranslatorTest.java | 33 +- .../hts/delete/DeleteTranslatorTest.java | 33 +- .../freeze/FreezeUnfreezeTranslatorTest.java | 44 +- .../FungibleTokenInfoCallTest.java | 28 +- .../FungibleTokenInfoTranslatorTest.java | 36 +- .../GetApprovedTranslatorTest.java | 43 +- .../GrantApprovalTranslatorTest.java | 59 ++- .../GrantRevokeKycTranslatorTest.java | 44 +- .../IsAssociatedTranslatorTest.java | 36 +- .../hts/isfrozen/IsFrozenTranslatorTest.java | 33 +- .../hts/iskyc/IsKycTranslatorTest.java | 33 +- .../hts/istoken/IsTokenTranslatorTest.java | 33 +- .../hts/mint/MintTranslatorTest.java | 44 +- .../nfttokeninfo/NftTokenInfoCallTest.java | 14 +- .../NftTokenInfoTranslatorTest.java | 31 +- .../hts/pauses/PausesTranslatorTest.java | 46 +- .../RejectTokensTranslatorTest.java | 82 ++-- .../SetApprovalForAllTranslatorTest.java | 39 +- .../TokenExpiryTranslatorTest.java | 33 +- .../hts/tokeninfo/TokenInfoCallTest.java | 20 +- .../tokeninfo/TokenInfoTranslatorTest.java | 37 +- .../hts/tokenkey/TokenKeyTranslatorTest.java | 33 +- .../tokentype/TokenTypeTranslatorTest.java | 33 +- .../ClassicTransfersTranslatorTest.java | 19 +- .../update/UpdateExpiryTranslatorTest.java | 28 +- .../hts/update/UpdateKeysTranslatorTest.java | 24 +- .../UpdateNFTsMetadataTranslatorTest.java | 21 +- .../hts/update/UpdateTranslatorTest.java | 36 +- .../UpdateTokenCustomFeesTranslatorTest.java | 24 +- .../hts/wipe/WipeTranslatorTest.java | 54 ++- .../SystemContractMethodRegistryTest.java | 148 +++++++ .../handlers/ContractCallHandlerTest.java | 10 +- .../ContractCallLocalHandlerTest.java | 14 +- .../handlers/ContractCreateHandlerTest.java | 10 +- .../EthereumTransactionHandlerTest.java | 10 +- 155 files changed, 4543 insertions(+), 1556 deletions(-) create mode 100644 hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/utils/SystemContractMethod.java create mode 100644 hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/utils/SystemContractMethodRegistry.java create mode 100644 hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/utils/SystemContractMethodRegistryTest.java diff --git a/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/RpcService.java b/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/RpcService.java index 44a6334a3e0b..3819e9121325 100644 --- a/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/RpcService.java +++ b/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/RpcService.java @@ -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. @@ -33,4 +33,14 @@ public interface RpcService extends Service { */ @NonNull Set rpcDefinitions(); + + /** + * Services may have initialization to be done which can't be done in the constructor (too soon) + * but should/must be done before the system starts processing transactions. This is the hook + * for that. + * + * Called on each Service when `Hedera.onStateInitialized() is called for `InitTrigger.GENESIS`. + * Services module is still single-threaded when this happens. + */ + default void onStateInitializedForGenesis() {} } diff --git a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/Hedera.java b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/Hedera.java index 57a5ade1bf0e..358b75810678 100644 --- a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/Hedera.java +++ b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/Hedera.java @@ -90,10 +90,12 @@ import com.hedera.node.app.services.AppContextImpl; import com.hedera.node.app.services.ServiceMigrator; import com.hedera.node.app.services.ServicesRegistry; +import com.hedera.node.app.services.ServicesRegistry.Registration; import com.hedera.node.app.signature.AppSignatureVerifier; import com.hedera.node.app.signature.impl.SignatureExpanderImpl; import com.hedera.node.app.signature.impl.SignatureVerifierImpl; import com.hedera.node.app.spi.AppContext; +import com.hedera.node.app.spi.RpcService; import com.hedera.node.app.spi.workflows.PreCheckException; import com.hedera.node.app.state.StateLifecyclesImpl; import com.hedera.node.app.state.recordcache.RecordCacheService; @@ -604,7 +606,16 @@ public void onStateInitialized( } // With the States API grounded in the working state, we can create the object graph from it initializeDagger(state, trigger); - contractServiceImpl.registerMetrics(); + + // Tell each service it can do its final initialization (if needed) before the system starts + // processing transactions. + if (trigger == GENESIS) { + servicesRegistry.registrations().stream() + .map(Registration::service) + .filter(RpcService.class::isInstance) + .map(RpcService.class::cast) + .forEach(RpcService::onStateInitializedForGenesis); + } } /** diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/ContractServiceComponent.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/ContractServiceComponent.java index 16ebea137121..281ba7125acf 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/ContractServiceComponent.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/ContractServiceComponent.java @@ -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. @@ -18,6 +18,11 @@ import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.scope.VerificationStrategies; +import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.CallTranslator; +import com.hedera.node.app.service.contract.impl.exec.systemcontracts.has.HasCallAttempt; +import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hss.HssCallAttempt; +import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallAttempt; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.handlers.ContractHandlers; import com.hedera.node.app.spi.signatures.SignatureVerifier; import dagger.BindsInstance; @@ -26,6 +31,8 @@ import java.time.InstantSource; import java.util.List; import java.util.function.Supplier; +import javax.inject.Named; +import javax.inject.Provider; import javax.inject.Singleton; import org.hyperledger.besu.evm.tracing.OperationTracer; @@ -52,7 +59,8 @@ ContractServiceComponent create( @BindsInstance SignatureVerifier signatureVerifier, @BindsInstance VerificationStrategies verificationStrategies, @BindsInstance @Nullable Supplier> addOnTracers, - @BindsInstance ContractMetrics contractMetrics); + @BindsInstance ContractMetrics contractMetrics, + @BindsInstance SystemContractMethodRegistry systemContractMethodRegistry); } /** @@ -64,4 +72,18 @@ ContractServiceComponent create( * @return contract metrics collection, instance */ ContractMetrics contractMetrics(); + + /** + * @return method registry for system contracts + */ + SystemContractMethodRegistry systemContractMethodRegistry(); + + @Named("HasTranslators") + Provider>> hasCallTranslators(); + + @Named("HssTranslators") + Provider>> hssCallTranslators(); + + @Named("HtsTranslators") + Provider>> htsCallTranslators(); } diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/ContractServiceImpl.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/ContractServiceImpl.java index 1e0b8e14e094..c9161b92dd0d 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/ContractServiceImpl.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/ContractServiceImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020-2024 Hedera Hashgraph, LLC + * Copyright (C) 2020-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. @@ -22,6 +22,9 @@ import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.scope.DefaultVerificationStrategies; import com.hedera.node.app.service.contract.impl.exec.scope.VerificationStrategies; +import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.AbstractCallAttempt; +import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.CallTranslator; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.handlers.ContractHandlers; import com.hedera.node.app.service.contract.impl.schemas.V0490ContractSchema; import com.hedera.node.app.service.contract.impl.schemas.V0500ContractSchema; @@ -30,6 +33,7 @@ import com.swirlds.state.lifecycle.SchemaRegistry; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; +import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.function.Supplier; @@ -39,6 +43,7 @@ * Implementation of the {@link ContractService}. */ public class ContractServiceImpl implements ContractService { + /** * Minimum gas required for contract operations. */ @@ -66,7 +71,10 @@ public ContractServiceImpl( final var metricsSupplier = requireNonNull(appContext.metricsSupplier()); final Supplier contractsConfigSupplier = () -> appContext.configSupplier().get().getConfigData(ContractsConfig.class); - final var contractMetrics = new ContractMetrics(metricsSupplier, contractsConfigSupplier); + final var systemContractMethodRegistry = new SystemContractMethodRegistry(); + final var contractMetrics = + new ContractMetrics(metricsSupplier, contractsConfigSupplier, systemContractMethodRegistry); + this.component = DaggerContractServiceComponent.factory() .create( appContext.instantSource(), @@ -75,7 +83,8 @@ public ContractServiceImpl( appContext.signatureVerifier(), Optional.ofNullable(verificationStrategies).orElseGet(DefaultVerificationStrategies::new), addOnTracers, - contractMetrics); + contractMetrics, + systemContractMethodRegistry); } @Override @@ -84,12 +93,15 @@ public void registerSchemas(@NonNull final SchemaRegistry registry) { registry.register(new V0500ContractSchema()); } - /** - * Create the metrics for the smart contracts service. This needs to be delayed until _after_ - * the metrics are available - which happens after `Hedera.initializeStatesApi`. - */ - public void registerMetrics() { - component.contractMetrics().createContractMetrics(); + @Override + public void onStateInitializedForGenesis() { + // Force call translators to be instantiated now, so that all the system contract methods + // will be registered, so the secondary metrics can be created. (Left to its own devices + // Dagger would delay instantiating them until transactions started flowing.) + final var allTranslators = allCallTranslators(); + + component.contractMetrics().createContractPrimaryMetrics(); + component.contractMetrics().createContractSecondaryMetrics(); } /** @@ -98,4 +110,12 @@ public void registerMetrics() { public ContractHandlers handlers() { return component.handlers(); } + + private @NonNull List>> allCallTranslators() { + final var allCallTranslators = new ArrayList>>(); + allCallTranslators.addAll(component.hasCallTranslators().get()); + allCallTranslators.addAll(component.hssCallTranslators().get()); + allCallTranslators.addAll(component.htsCallTranslators().get()); + return allCallTranslators; + } } diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/metrics/ContractMetrics.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/metrics/ContractMetrics.java index 421528bdcddc..832205d6c9f8 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/metrics/ContractMetrics.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/metrics/ContractMetrics.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2024 Hedera Hashgraph, LLC + * Copyright (C) 2024-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. @@ -24,20 +24,30 @@ import com.google.common.annotations.VisibleForTesting; import com.hedera.hapi.node.base.HederaFunctionality; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Category; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.config.data.ContractsConfig; +import com.swirlds.common.metrics.platform.prometheus.NameConverter; import com.swirlds.metrics.api.Counter; import com.swirlds.metrics.api.Metric; import com.swirlds.metrics.api.Metrics; import edu.umd.cs.findbugs.annotations.NonNull; +import java.util.EnumSet; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Consumer; import java.util.function.Supplier; import java.util.stream.Collectors; -import java.util.stream.Stream; import javax.inject.Inject; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.hyperledger.besu.evm.frame.MessageFrame; +import org.hyperledger.besu.evm.frame.MessageFrame.State; /** * Metrics collection management for Smart Contracts service @@ -52,14 +62,56 @@ public class ContractMetrics { private final Supplier metricsSupplier; private final Supplier contractsConfigSupplier; private boolean p1MetricsEnabled; + private boolean p2MetricsEnabled; + private final SystemContractMethodRegistry systemContractMethodRegistry; + + // Counters that are the P1 metrics private final HashMap rejectedTxsCounters = new HashMap<>(); private final HashMap rejectedTxsLackingIntrinsicGas = new HashMap<>(); private Counter rejectedEthType3Counter; + private enum MethodMetricType { + TOTAL(0, "total"), + FAILED(1, "failed"); + public final int index; + public final String name; + + private MethodMetricType(final int index, @NonNull final String name) { + this.index = index; + this.name = name; + } + + public @NonNull String toString() { + return this.name; + } + }; + + // Counters that are the P2 metrics, and maps that take `SystemContractMethods` into the specific counters + + // Counters for SystemContract usage (i.e., calls to HAS, HSS, HTS) + private final Map systemContractMethodCounters = new HashMap<>(); + + // Counters for DIRECT vs PROXY usage + private final Map systemContractMethodCountersVia = new HashMap<>(); + + // Counters for ERC-20 and ERC-721 usage (there's overlap as some methods are defined in _both_), plus the map + // that takes a `SystemContract` to the ERC types (if any) + private final Map> systemContractMethodErcMembers = + new HashMap<>(); + private final Map systemContractERCTypeCounters = new HashMap<>(); + + // Counters for the "method groups" (e.g., transfers vs creates vs burns etc), plus the map that takes a + // `SystemContract` to the method group(s) it is part of + private final Map> systemContractMethodGroupMembers = + new HashMap<>(); + private final Map systemContractMethodGroupCounters = new HashMap<>(); + private static final Map POSSIBLE_FAILING_TX_TYPES = Map.of( CONTRACT_CALL, "contractCallTx", CONTRACT_CREATE, "contractCreateTx", ETHEREUM_TRANSACTION, "ethereumTx"); + // String templates and other stringish things used to create metrics' names and descriptions + private static final String METRIC_CATEGORY = "app"; private static final String METRIC_SERVICE = "SmartContractService"; private static final String METRIC_TXN_UNIT = "txs"; @@ -74,77 +126,164 @@ public class ContractMetrics { private static final String REJECTED_TXN_SHORT_DESCR = "txns"; private static final String REJECTED_TYPE3_SHORT_DESCR = "Ethereum Type 3 txns"; private static final String REJECTED_FOR_GAS_SHORT_DESCR = "txns with not even intrinsic gas"; - private static final String REJECTED_TYPE3_FUNCTIONALITY = "ethType3BlobTransaction"; + // The `SystemContractMethod.Category` enum has "categories" for both ERC-20/ERC-721, and method groups: + // These maps distinguish them + + private static final EnumSet ERC_TYPES = EnumSet.of(Category.ERC20, Category.ERC721); + private static final EnumSet METHOD_GROUPS = EnumSet.complementOf(ERC_TYPES); + + // %1$s - metric name (system contract name or method category (group)) + // %2$s = METRIC_SERVICE + // %3$s - METHOD_METRIC_TYPE + // %4%s - clarification + private static final String METHOD_METRIC_NAME_TEMPLATE = "%2$s:Method_%1$s_%3$s"; + private static final String METHOD_METRIC_DESCR_TEMPLATE = "system contract method %1$s %3$s %4$s"; + @Inject public ContractMetrics( @NonNull final Supplier metricsSupplier, - @NonNull final Supplier contractsConfigSupplier) { + @NonNull final Supplier contractsConfigSupplier, + @NonNull final SystemContractMethodRegistry systemContractMethodRegistry) { this.metricsSupplier = requireNonNull( metricsSupplier, "metrics supplier (from platform via ServicesMain/Hedera must not be null"); this.contractsConfigSupplier = requireNonNull(contractsConfigSupplier, "contracts configuration supplier must not be null"); + this.systemContractMethodRegistry = + requireNonNull(systemContractMethodRegistry, "systemContractMethodRegistry must not be null"); } - private final Object metricsCreationLock = new Object(); - private volatile boolean primaryMetricsAreCreated = false; + // -------------------- + // Creating the metrics - public void createContractMetrics() { + /** + * Primary metrics are a fixed set and can be created when `Hedera` initializes the system. But + * it actually must wait until the platform calls `Hedera.onStateInitialized`, and then for + * GENESIS only. + */ + public void createContractPrimaryMetrics() { + final var contractsConfig = requireNonNull(contractsConfigSupplier.get()); + this.p1MetricsEnabled = contractsConfig.metricsSmartContractPrimaryEnabled(); - // Primary metrics are a fixed set and can be created when `Hedera` initializes the system. - // But it actually must wait until the platform calls `Hedera.onStateInitialized` and, - // remarkably, that can happen more than once. We must only create the metrics the - // _first_ time. Hence, the simple gate here. + if (p1MetricsEnabled) { + final var metrics = requireNonNull(metricsSupplier.get()); + + // Rejected transactions counters + for (final var txKind : POSSIBLE_FAILING_TX_TYPES.keySet()) { + final var name = toRejectedName(txKind, REJECTED_TXN_SHORT_DESCR); + final var descr = toRejectedDescr(txKind, REJECTED_TXN_SHORT_DESCR); + final var config = new Counter.Config(METRIC_CATEGORY, name) + .withDescription(descr) + .withUnit(METRIC_TXN_UNIT); + final var metric = newCounter(metrics, config); + rejectedTxsCounters.put(txKind, metric); + } - synchronized (metricsCreationLock) { - if (!primaryMetricsAreCreated) { + // Rejected transactions because they don't even have intrinsic gas + for (final var txKind : POSSIBLE_FAILING_TX_TYPES.keySet()) { + final var functionalityName = POSSIBLE_FAILING_TX_TYPES.get(txKind) + "DueToIntrinsicGas"; + final var name = toRejectedName(functionalityName, REJECTED_FOR_GAS_SHORT_DESCR); + final var descr = toRejectedDescr(functionalityName, REJECTED_FOR_GAS_SHORT_DESCR); + final var config = new Counter.Config(METRIC_CATEGORY, name) + .withDescription(descr) + .withUnit(METRIC_TXN_UNIT); + final var metric = newCounter(metrics, config); + rejectedTxsLackingIntrinsicGas.put(txKind, metric); + } - final var contractsConfig = requireNonNull(contractsConfigSupplier.get()); - this.p1MetricsEnabled = contractsConfig.metricsSmartContractPrimaryEnabled(); + // Rejected transactions for ethereum calls that are in type 3 blob transaction format + { + final var name = toRejectedName(REJECTED_TYPE3_FUNCTIONALITY, REJECTED_TYPE3_SHORT_DESCR); + final var descr = toRejectedDescr(REJECTED_TYPE3_FUNCTIONALITY, REJECTED_TYPE3_SHORT_DESCR); + final var config = new Counter.Config(METRIC_CATEGORY, name) + .withDescription(descr) + .withUnit(METRIC_TXN_UNIT); + final var metric = newCounter(metrics, config); + rejectedEthType3Counter = metric; + } + } + } - final var metrics = requireNonNull(metricsSupplier.get()); + private @NonNull Counter makeCounter( + @NonNull final MethodMetricType metricType, + @NonNull final String nam, + @NonNull final String clarification) { + final var name = toMethodMetricName(nam, metricType); + final var descr = toMethodMetricDescr(nam, metricType, clarification); + final var config = + new Counter.Config(METRIC_CATEGORY, name).withDescription(descr).withUnit(METRIC_TXN_UNIT); + return newCounter(metricsSupplier.get(), config); + } - if (p1MetricsEnabled) { - // Rejected transactions counters - for (final var txKind : POSSIBLE_FAILING_TX_TYPES.keySet()) { - final var name = toRejectedName(txKind, REJECTED_TXN_SHORT_DESCR); - final var descr = toRejectedDescr(txKind, REJECTED_TXN_SHORT_DESCR); - final var config = new Counter.Config(METRIC_CATEGORY, name) - .withDescription(descr) - .withUnit(METRIC_TXN_UNIT); - final var metric = newCounter(metrics, config); - rejectedTxsCounters.put(txKind, metric); - } + private @NonNull Counter[] makeCounterPair(@NonNull final String nam, @NonNull final String clarification) { + final var metricPair = new Counter[2]; + metricPair[MethodMetricType.TOTAL.index] = makeCounter(MethodMetricType.TOTAL, nam, clarification); + metricPair[MethodMetricType.FAILED.index] = makeCounter(MethodMetricType.FAILED, nam, clarification); + return metricPair; + } - // Rejected transactions because they don't even have intrinsic gas - for (final var txKind : POSSIBLE_FAILING_TX_TYPES.keySet()) { - final var functionalityName = POSSIBLE_FAILING_TX_TYPES.get(txKind) + "DueToIntrinsicGas"; - final var name = toRejectedName(functionalityName, REJECTED_FOR_GAS_SHORT_DESCR); - final var descr = toRejectedDescr(functionalityName, REJECTED_FOR_GAS_SHORT_DESCR); - final var config = new Counter.Config(METRIC_CATEGORY, name) - .withDescription(descr) - .withUnit(METRIC_TXN_UNIT); - final var metric = newCounter(metrics, config); - rejectedTxsLackingIntrinsicGas.put(txKind, metric); - } + /** + * Secondary metrics are based on the system contract methods themselves, split into various categories that + * are based on their attributes. + */ + public void createContractSecondaryMetrics() { - // Rejected transactions for ethereum calls that are in type 3 blob transaction format - { - final var name = toRejectedName(REJECTED_TYPE3_FUNCTIONALITY, REJECTED_TYPE3_SHORT_DESCR); - final var descr = toRejectedDescr(REJECTED_TYPE3_FUNCTIONALITY, REJECTED_TYPE3_SHORT_DESCR); - final var config = new Counter.Config(METRIC_CATEGORY, name) - .withDescription(descr) - .withUnit(METRIC_TXN_UNIT); - final var metric = newCounter(metrics, config); - rejectedEthType3Counter = metric; - } - } - primaryMetricsAreCreated = true; + if (systemContractMethodRegistry.size() == 0) { + // Something went wrong with the order in which components were initialized + log.warn("no system contract methods registered when trying to create secondary metrics"); + } + + final var contractsConfig = requireNonNull(contractsConfigSupplier.get()); + this.p2MetricsEnabled = contractsConfig.metricsSmartContractSecondaryEnabled(); + + if (p2MetricsEnabled) { + final var metrics = requireNonNull(metricsSupplier.get()); + + // P2 metrics come in pairs: a total count of something, and the error count for that same thing + + // By system contract + // Collect all system contracts in use and create counters + final var allSystemContracts = systemContractMethodRegistry.allMethods().stream() + .map(m -> m.systemContract().orElseThrow()) + .collect(Collectors.toSet()); + for (final var systemContract : allSystemContracts) { + systemContractMethodCounters.put(systemContract, makeCounterPair(systemContract.name(), "")); + } + + // By via: DIRECT vs PROXY + for (final var callVia : SystemContractMethod.CallVia.values()) { + systemContractMethodCountersVia.put(callVia, makeCounterPair(callVia.name(), "")); + } + + // By ERC type + + for (final var method : systemContractMethodRegistry.allMethods()) { + final var ercMembership = intersect(method.categories(), ERC_TYPES); + systemContractMethodErcMembers.put(method, ercMembership); + } + + for (final var ercType : ERC_TYPES) { + systemContractERCTypeCounters.put(ercType, makeCounterPair(ercType.name(), ercType.clarification())); + } + + // By Method Group + + for (final var method : systemContractMethodRegistry.allMethods()) { + final var groupMembership = intersect(method.categories(), METHOD_GROUPS); + systemContractMethodGroupMembers.put(method, groupMembership); + } + + for (final var methodGroup : METHOD_GROUPS) { + systemContractMethodGroupCounters.put( + methodGroup, makeCounterPair(methodGroup.name(), methodGroup.clarification())); } } } + // --------------------------------- + // P1 metrics: `pureCheck` failures + public void incrementRejectedTx(@NonNull final HederaFunctionality txKind) { bumpRejectedTx(txKind, 1); } @@ -174,48 +313,143 @@ public void bumpRejectedType3EthTx(final long bumpBy) { } } + // --------------------------------------------- + // P2 metrics: System contract per-method counts + + enum MethodResult { + SUCCESS, + FAILURE; + + public static @NonNull MethodResult from(@NonNull final MessageFrame.State state) { + return switch (state) { + case State.CODE_SUCCESS, State.COMPLETED_SUCCESS -> SUCCESS; + default -> FAILURE; + }; + } + } + + public void incrementSystemMethodCall( + @NonNull SystemContractMethod systemContractMethod, @NonNull final MessageFrame.State state) { + systemContractMethod = + systemContractMethodRegistry.fromMissingContractGetWithContract(requireNonNull(systemContractMethod)); + requireNonNull(state); + + final var result = MethodResult.from(state); + if (p2MetricsEnabled) { + // Handle each of the P2 metrics kinds + + try { + final Consumer bumpMetricsPair = metricsPair -> { + metricsPair[MethodMetricType.TOTAL.index].increment(); + if (MethodResult.FAILURE == result) { + metricsPair[MethodMetricType.FAILED.index].increment(); + } + }; + + bumpMetricsPair.accept(systemContractMethodCounters.get( + systemContractMethod.systemContract().orElse(null))); + bumpMetricsPair.accept(systemContractMethodCountersVia.get(systemContractMethod.via())); + systemContractMethodErcMembers + .get(systemContractMethod) + .forEach(ercType -> bumpMetricsPair.accept(systemContractERCTypeCounters.get(ercType))); + systemContractMethodGroupMembers + .get(systemContractMethod) + .forEach(group -> bumpMetricsPair.accept(systemContractMethodGroupCounters.get(group))); + } catch (final NullPointerException e) { + // ignore: should never happen, but ... just in case ... don't fail tx because of bad + // metrics code + } + } + } + + private final ConcurrentHashMap methodsThatHaveCallsWithNullMethod = + new ConcurrentHashMap<>(50); + + public void logWarnMissingSystemContractMethodOnCall(@NonNull final SystemContractMethod systemContractMethod) { + // Log, but only first time you see it for a specific method (to avoid spew) + requireNonNull(systemContractMethod); + if (methodsThatHaveCallsWithNullMethod.containsKey(systemContractMethod)) { + log.warn("Found `Call` without `SystemContractMethod`, %s" + .formatted(systemContractMethod.fullyDecoratedMethodName())); + } else { + methodsThatHaveCallsWithNullMethod.put(systemContractMethod, systemContractMethod); + } + } + + // ----------------- + // Unit test helpers + + @VisibleForTesting + public @NonNull Set getAllP1Counters() { + final var allCounters = new HashSet(200); + allCounters.addAll(rejectedTxsCounters.values()); + allCounters.addAll(rejectedTxsLackingIntrinsicGas.values()); + if (rejectedEthType3Counter != null) allCounters.add(rejectedEthType3Counter); + return allCounters; + } + + @VisibleForTesting + public @NonNull Set getAllP2Counters() { + final var allCounters = new HashSet(200); + + final Consumer> adder = map -> { + map.values().forEach(counterPair -> { + allCounters.add(counterPair[MethodMetricType.TOTAL.index]); + allCounters.add(counterPair[MethodMetricType.FAILED.index]); + }); + }; + adder.accept(systemContractMethodCounters); + adder.accept(systemContractMethodCountersVia); + adder.accept(systemContractERCTypeCounters); + adder.accept(systemContractMethodGroupCounters); + + return allCounters; + } + + @VisibleForTesting + public @NonNull Set getAllCounters() { + final var allCounters = getAllP1Counters(); + allCounters.addAll(getAllP2Counters()); + return allCounters; + } + @VisibleForTesting - public @NonNull Map getAllCounters() { - return Stream.concat( - Stream.concat( - rejectedTxsCounters.values().stream(), - rejectedTxsLackingIntrinsicGas.values().stream()), - Stream.ofNullable(rejectedEthType3Counter)) - .collect(toMap(Counter::getName, Counter::get)); + public @NonNull Map getAllP1CounterValues() { + return getAllP1Counters().stream().collect(toMap(Counter::getName, Counter::get)); + } + + @VisibleForTesting + public @NonNull Map getAllCounterValues() { + return getAllCounters().stream().collect(toMap(Counter::getName, Counter::get)); + } + + @VisibleForTesting + public @NonNull List getAllP1CounterNames() { + return getAllP1Counters().stream().map(Metric::getName).sorted().toList(); } @VisibleForTesting public @NonNull List getAllCounterNames() { - return Stream.concat( - Stream.concat( - rejectedTxsCounters.values().stream(), - rejectedTxsLackingIntrinsicGas.values().stream()), - Stream.ofNullable(rejectedEthType3Counter)) - .map(Metric::getName) - .sorted() - .toList(); + final var n = getAllCounters().stream().map(Metric::getDescription).count(); + return getAllCounters().stream().map(Metric::getName).sorted().toList(); } @VisibleForTesting public @NonNull List getAllCounterDescriptions() { - return Stream.concat( - Stream.concat( - rejectedTxsCounters.values().stream(), - rejectedTxsLackingIntrinsicGas.values().stream()), - Stream.ofNullable(rejectedEthType3Counter)) - .map(Metric::getDescription) - .sorted() - .toList(); + return getAllCounters().stream().map(Metric::getDescription).sorted().toList(); } @VisibleForTesting public @NonNull String allCountersToString() { - return getAllCounters().entrySet().stream() + return getAllCounterValues().entrySet().stream() .sorted(Map.Entry.comparingByKey()) .map(e -> e.getKey() + ": " + e.getValue()) .collect(Collectors.joining(", ", "{", "}")); } + // --------------------------------- + // Helpers for making metrics' names + private @NonNull Counter newCounter(@NonNull final Metrics metrics, @NonNull final Counter.Config config) { return metrics.getOrCreate(config); } @@ -240,10 +474,39 @@ public void bumpRejectedType3EthTx(final long bumpBy) { return toString(REJECTED_DESCR_TEMPLATE, functionality, shortDescription); } + private static @NonNull String toMethodMetricName( + @NonNull final String name, @NonNull final MethodMetricType type) { + return toString(METHOD_METRIC_NAME_TEMPLATE, name, type, ""); + } + + private static @NonNull String toMethodMetricDescr( + @NonNull final String name, @NonNull final MethodMetricType type, @NonNull final String clarification) { + return toString(METHOD_METRIC_DESCR_TEMPLATE, name, type, clarification); + } + private static @NonNull String toString( @NonNull final String template, @NonNull final String functionality, @NonNull final String shortDescription) { - return template.formatted(functionality, METRIC_SERVICE, shortDescription); + final var possiblyUnacceptableName = template.formatted(functionality, METRIC_SERVICE, shortDescription); + final var definitelyAcceptableName = NameConverter.fix(possiblyUnacceptableName); + return definitelyAcceptableName; + } + + private static @NonNull String toString( + @NonNull final String template, + @NonNull final String name, + @NonNull final MethodMetricType type, + @NonNull final String clarification) { + final var possiblyUnacceptableName = template.formatted(name, METRIC_SERVICE, type, clarification); + final var definitelyAcceptableName = NameConverter.fix(possiblyUnacceptableName); + return definitelyAcceptableName; + } + + private > @NonNull EnumSet intersect( + @NonNull final EnumSet set1, @NonNull final EnumSet set2) { + final var r = set1.clone(); + r.retainAll(set2); + return r; } } 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 dc342952650c..9b1c2f1e7f93 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 @@ -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. @@ -21,7 +21,7 @@ import static com.hedera.node.app.service.contract.impl.exec.failure.CustomExceptionalHaltReason.INSUFFICIENT_CHILD_RECORDS; import static com.hedera.node.app.service.contract.impl.exec.failure.CustomExceptionalHaltReason.INVALID_CONTRACT_ID; import static com.hedera.node.app.service.contract.impl.exec.failure.CustomExceptionalHaltReason.INVALID_SIGNATURE; -import static com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.create.CreateTranslator.createSelectorsMap; +import static com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.create.CreateTranslator.createMethodsMap; import static com.hedera.node.app.service.contract.impl.exec.utils.FrameUtils.acquiredSenderAuthorizationViaDelegateCall; import static com.hedera.node.app.service.contract.impl.exec.utils.FrameUtils.alreadyHalted; import static com.hedera.node.app.service.contract.impl.exec.utils.FrameUtils.isTopLevelTransaction; @@ -195,7 +195,7 @@ private boolean isTokenCreation(MessageFrame frame) { return false; } var selector = frame.getInputData().slice(0, 4).toArray(); - return createSelectorsMap.keySet().stream().anyMatch(s -> Arrays.equals(s.selector(), selector)); + return createMethodsMap.keySet().stream().anyMatch(s -> Arrays.equals(s.selector(), selector)); } /** 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 767e7240ae30..0432aeb5bd8b 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 @@ -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. @@ -23,6 +23,7 @@ import static java.util.Objects.requireNonNull; import com.hedera.hapi.node.base.ContractID; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.AbstractNativeSystemContract; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.has.HasCallFactory; import com.hedera.node.app.service.contract.impl.exec.utils.FrameUtils; @@ -42,8 +43,11 @@ public class HasSystemContract extends AbstractNativeSystemContract implements H public static final ContractID HAS_CONTRACT_ID = asNumberedContractId(Address.fromHexString(HAS_EVM_ADDRESS)); @Inject - public HasSystemContract(@NonNull final GasCalculator gasCalculator, @NonNull final HasCallFactory callFactory) { - super(HAS_SYSTEM_CONTRACT_NAME, callFactory, HAS_CONTRACT_ID, gasCalculator); + public HasSystemContract( + @NonNull final GasCalculator gasCalculator, + @NonNull final HasCallFactory callFactory, + @NonNull final ContractMetrics contractMetrics) { + super(HAS_SYSTEM_CONTRACT_NAME, callFactory, HAS_CONTRACT_ID, gasCalculator, contractMetrics); } @Override diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/HssSystemContract.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/HssSystemContract.java index beb29fd7d3be..358ec1b92af6 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/HssSystemContract.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/HssSystemContract.java @@ -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. @@ -23,6 +23,7 @@ import static java.util.Objects.requireNonNull; import com.hedera.hapi.node.base.ContractID; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.AbstractNativeSystemContract; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hss.HssCallFactory; import com.hedera.node.app.service.contract.impl.exec.utils.FrameUtils; @@ -45,8 +46,11 @@ public class HssSystemContract extends AbstractNativeSystemContract implements H public static final ContractID HSS_CONTRACT_ID = asNumberedContractId(Address.fromHexString(HSS_EVM_ADDRESS)); @Inject - public HssSystemContract(@NonNull final GasCalculator gasCalculator, @NonNull final HssCallFactory callFactory) { - super(HSS_SYSTEM_CONTRACT_NAME, callFactory, HSS_CONTRACT_ID, gasCalculator); + public HssSystemContract( + @NonNull final GasCalculator gasCalculator, + @NonNull final HssCallFactory callFactory, + @NonNull final ContractMetrics contractMetrics) { + super(HSS_SYSTEM_CONTRACT_NAME, callFactory, HSS_CONTRACT_ID, gasCalculator, contractMetrics); } @Override diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/HtsSystemContract.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/HtsSystemContract.java index 1fd08a99a7f2..e479e98652cf 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/HtsSystemContract.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/HtsSystemContract.java @@ -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. @@ -19,6 +19,7 @@ import static com.hedera.node.app.service.contract.impl.utils.ConversionUtils.asNumberedContractId; import com.hedera.hapi.node.base.ContractID; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.AbstractNativeSystemContract; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallFactory; import com.hedera.node.app.service.contract.impl.exec.utils.FrameUtils; @@ -37,8 +38,11 @@ public class HtsSystemContract extends AbstractNativeSystemContract implements H public static final ContractID HTS_CONTRACT_ID = asNumberedContractId(Address.fromHexString(HTS_EVM_ADDRESS)); @Inject - public HtsSystemContract(@NonNull final GasCalculator gasCalculator, @NonNull final HtsCallFactory callFactory) { - super(HTS_SYSTEM_CONTRACT_NAME, callFactory, HTS_CONTRACT_ID, gasCalculator); + 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); } @Override diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/common/AbstractCall.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/common/AbstractCall.java index 6d7cda70e042..b39e41d5cc55 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/common/AbstractCall.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/common/AbstractCall.java @@ -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. @@ -29,6 +29,7 @@ import com.hedera.node.app.service.contract.impl.exec.scope.HederaNativeOperations; import com.hedera.node.app.service.contract.impl.exec.scope.HederaOperations; import com.hedera.node.app.service.contract.impl.exec.scope.SystemContractOperations; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod; import com.hedera.node.app.service.contract.impl.hevm.HederaWorldUpdater; import com.hedera.node.app.service.contract.impl.records.ContractCallStreamBuilder; import com.hedera.node.app.service.token.ReadableAccountStore; @@ -43,6 +44,7 @@ public abstract class AbstractCall implements Call { protected final SystemContractGasCalculator gasCalculator; protected final HederaWorldUpdater.Enhancement enhancement; private final boolean isViewCall; + private SystemContractMethod systemContractMethod; protected AbstractCall( @NonNull final SystemContractGasCalculator gasCalculator, @@ -53,6 +55,14 @@ protected AbstractCall( this.isViewCall = isViewCall; } + public void setSystemContractMethod(@NonNull final SystemContractMethod systemContractMethod) { + this.systemContractMethod = systemContractMethod; + } + + public SystemContractMethod getSystemContractMethod() { + return systemContractMethod; + } + protected HederaOperations operations() { return enhancement.operations(); } diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/common/AbstractCallAttempt.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/common/AbstractCallAttempt.java index c05adca731c0..af077acac5ed 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/common/AbstractCallAttempt.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/common/AbstractCallAttempt.java @@ -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. @@ -26,6 +26,9 @@ import com.hedera.node.app.service.contract.impl.exec.scope.VerificationStrategies; 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; import edu.umd.cs.findbugs.annotations.NonNull; @@ -33,6 +36,7 @@ import java.nio.BufferUnderflowException; import java.util.Arrays; import java.util.List; +import java.util.Optional; import org.apache.tuweni.bytes.Bytes; import org.hyperledger.besu.datatypes.Address; @@ -54,6 +58,7 @@ public abstract class AbstractCallAttempt> { private final VerificationStrategies verificationStrategies; private final SystemContractGasCalculator gasCalculator; private final List> callTranslators; + private final SystemContractMethodRegistry systemContractMethodRegistry; private final boolean isStaticCall; // If non-null, the address of a non-contract entity (e.g., account or token) whose @@ -89,6 +94,7 @@ public AbstractCallAttempt( @NonNull final SystemContractGasCalculator gasCalculator, @NonNull final List> callTranslators, final boolean isStaticCall, + @NonNull final SystemContractMethodRegistry systemContractMethodRegistry, @NonNull final com.esaulpaugh.headlong.abi.Function redirectFunction) { requireNonNull(input); requireNonNull(redirectFunction); @@ -101,6 +107,7 @@ public AbstractCallAttempt( this.enhancement = requireNonNull(enhancement); this.verificationStrategies = requireNonNull(verificationStrategies); this.onlyDelegatableContractKeysActive = onlyDelegatableContractKeysActive; + this.systemContractMethodRegistry = requireNonNull(systemContractMethodRegistry); if (isRedirectSelector(redirectFunction.selector(), input.toArrayUnsafe())) { Tuple abiCall = null; @@ -127,6 +134,8 @@ public AbstractCallAttempt( this.isStaticCall = isStaticCall; } + protected abstract SystemContract systemContractKind(); + protected abstract T self(); /** @@ -277,6 +286,24 @@ public boolean isSelector(@NonNull final Function... functions) { return false; } + /** + * Returns whether this call attempt is a selector for any of the given functions. + * @param methods selectors to match against + * @return boolean result + */ + public boolean isSelector(@NonNull final SystemContractMethod... methods) { + return isMethod(methods).isPresent(); + } + + public @NonNull Optional isMethod(@NonNull final SystemContractMethod... methods) { + for (final var method : methods) { + if (Arrays.equals(method.selector(), this.selector())) { + return Optional.of(method); + } + } + return Optional.empty(); + } + /** * Returns whether this call attempt is a selector for any of the given functions. * @param configEnabled whether the config is enabled @@ -287,6 +314,17 @@ public boolean isSelectorIfConfigEnabled(final boolean configEnabled, @NonNull f return configEnabled && isSelector(functions); } + /** + * Returns whether this call attempt is a selector for any of the given functions. + * @param configEnabled whether the config is enabled + * @param methods selectors to match against + * @return boolean result + */ + public boolean isSelectorIfConfigEnabled( + final boolean configEnabled, @NonNull final SystemContractMethod... methods) { + 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 @@ -305,4 +343,8 @@ private boolean isRedirectSelector(@NonNull final byte[] functionSelector, @NonN public boolean isOnlyDelegatableContractKeysActive() { return onlyDelegatableContractKeysActive; } + + public SystemContractMethodRegistry getSystemContractMethodRegistry() { + return systemContractMethodRegistry; + } } diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/common/AbstractCallTranslator.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/common/AbstractCallTranslator.java index e2bc2c7904ad..da4b5fbb2263 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/common/AbstractCallTranslator.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/common/AbstractCallTranslator.java @@ -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. @@ -18,8 +18,15 @@ import static java.util.Objects.requireNonNull; +import com.google.common.annotations.VisibleForTesting; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; +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 edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; /** * Basic implementation support for a {@link CallTranslator} that returns a translated @@ -27,15 +34,63 @@ * @param the type of the abstract call translator */ public abstract class AbstractCallTranslator> implements CallTranslator { + + private static final Logger log = LogManager.getLogger(AbstractCallTranslator.class); + + private final SystemContract systemContractKind; + private final SystemContractMethodRegistry systemContractMethodRegistry; + private final ContractMetrics contractMetrics; + + public AbstractCallTranslator( + @NonNull final SystemContract systemContractKind, + @NonNull final SystemContractMethodRegistry systemContractMethodRegistry, + @NonNull final ContractMetrics contractMetrics) { + this.systemContractKind = requireNonNull(systemContractKind); + this.systemContractMethodRegistry = requireNonNull(systemContractMethodRegistry); + this.contractMetrics = requireNonNull(contractMetrics); + } + /** * {@inheritDoc} */ @Override public @Nullable Call translateCallAttempt(@NonNull final T attempt) { requireNonNull(attempt); - if (matches(attempt)) { - return callFrom(attempt); + final var call = identifyMethod(attempt) + .map(systemContractMethodRegistry::fromMissingContractGetWithContract) + .map(systemContractMethod -> callFrom(attempt, systemContractMethod)) + .orElse(null); + if (call != null) { + if (call.getSystemContractMethod() == null) { + contractMetrics.logWarnMissingSystemContractMethodOnCall( + identifyMethod(attempt).orElseThrow()); + } + } + return call; + } + + public void registerMethods(@NonNull final SystemContractMethod... methods) { + requireNonNull(methods); + for (@NonNull final var method : methods) { + requireNonNull(method); + registerMethod(method, method.withContract(systemContractKind)); } - return null; + } + + private void registerMethod( + @NonNull final SystemContractMethod methodWithoutContract, + @NonNull final SystemContractMethod methodWithContract) { + requireNonNull(methodWithoutContract); + requireNonNull(methodWithContract); + methodWithContract.verifyComplete(); + + if (systemContractMethodRegistry != null) { + systemContractMethodRegistry.register(methodWithoutContract, methodWithContract); + } + } + + @VisibleForTesting + public @NonNull String kind() { + return systemContractKind != null ? systemContractKind.name() : ""; } } diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/common/AbstractNativeSystemContract.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/common/AbstractNativeSystemContract.java index e69218d53ae4..db45be1e6909 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/common/AbstractNativeSystemContract.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/common/AbstractNativeSystemContract.java @@ -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. @@ -35,6 +35,7 @@ import com.hedera.hapi.node.base.ContractID; import com.hedera.hapi.node.base.ResponseCodeEnum; import com.hedera.node.app.service.contract.impl.exec.failure.CustomExceptionalHaltReason; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.AbstractFullContract; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.FullResult; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.HederaSystemContract; @@ -64,15 +65,18 @@ public abstract class AbstractNativeSystemContract extends AbstractFullContract private final CallFactory callFactory; private final ContractID contractID; + private final ContractMetrics contractMetrics; protected AbstractNativeSystemContract( @NonNull String name, @NonNull CallFactory callFactory, @NonNull ContractID contractID, - @NonNull GasCalculator gasCalculator) { + @NonNull GasCalculator gasCalculator, + @NonNull ContractMetrics contractMetrics) { super(name, gasCalculator); this.callFactory = requireNonNull(callFactory); this.contractID = requireNonNull(contractID); + this.contractMetrics = requireNonNull(contractMetrics); } @Override @@ -103,7 +107,7 @@ public FullResult computeFully(@NonNull final Bytes input, @NonNull final Messag } @SuppressWarnings({"java:S2637", "java:S2259"}) // this function is going to be refactored soon. - private static FullResult resultOfExecuting( + private FullResult resultOfExecuting( @NonNull final AbstractCallAttempt attempt, @NonNull final Call call, @NonNull final Bytes input, @@ -156,12 +160,23 @@ private static FullResult resultOfExecuting( } } } catch (final HandleException handleException) { - return haltHandleException(handleException, frame.getRemainingGas()); + final var fullResult = haltHandleException(handleException, frame.getRemainingGas()); + reportToMetrics(call, fullResult); + return fullResult; } catch (final Exception internal) { log.error("Unhandled failure for input {} to native system contract", input, internal); - return haltResult(PRECOMPILE_ERROR, frame.getRemainingGas()); + final var fullResult = haltResult(PRECOMPILE_ERROR, frame.getRemainingGas()); + reportToMetrics(call, fullResult); + return fullResult; } - return pricedResult.fullResult(); + final var fullResult = pricedResult.fullResult(); + reportToMetrics(call, fullResult); + return fullResult; + } + + private void reportToMetrics(@NonNull final Call call, @NonNull final FullResult fullResult) { + contractMetrics.incrementSystemMethodCall( + call.getSystemContractMethod(), fullResult.result().getState()); } private static void externalizeFailure( diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/common/Call.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/common/Call.java index d1ce988f0ac8..27899a3e5d87 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/common/Call.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/common/Call.java @@ -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. @@ -26,6 +26,7 @@ import com.hedera.hapi.node.contract.ContractFunctionResult; import com.hedera.hapi.node.scheduled.SchedulableTransactionBody; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.FullResult; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod; import com.hedera.node.app.service.contract.impl.records.ContractCallStreamBuilder; import com.hedera.pbj.runtime.io.buffer.Bytes; import edu.umd.cs.findbugs.annotations.NonNull; @@ -37,7 +38,7 @@ */ public interface Call { /** - * Encapsulates the result of a call to the HTS system contract. There are two elements, + * Encapsulates the result of a call to the HAS/HSS/HTS system contract. There are two elements, *
    *
  1. The "full result" of the call, including both its EVM-standard {@link PrecompileContractResult} * and gas requirement (which is often difficult to compute without executing the call); as well as @@ -161,4 +162,8 @@ default boolean allowsStaticFrame() { default SchedulableTransactionBody asSchedulableDispatchIn() { throw new UnsupportedOperationException("Needs scheduleNative() support"); } + + void setSystemContractMethod(@NonNull final SystemContractMethod systemContractMethod); + + SystemContractMethod getSystemContractMethod(); } diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/common/CallTranslator.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/common/CallTranslator.java index f6074a40746b..a89481504d67 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/common/CallTranslator.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/common/CallTranslator.java @@ -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. @@ -17,8 +17,10 @@ package com.hedera.node.app.service.contract.impl.exec.systemcontracts.common; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallAttempt; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; +import java.util.Optional; /** * Strategy interface for translating {@link HtsCallAttempt}s into {@link Call}s. @@ -36,12 +38,11 @@ public interface CallTranslator { Call translateCallAttempt(@NonNull T attempt); /** - * Returns true if the attempt matches the selector of the call this translator is responsible for. - * - * @param attempt the selector to match - * @return true if the selector matches the selector of the call this translator is responsible for + * Returns the SystemContractMethod for this attempt's selector, if the selector is known. + * @param attempt the selector to match (in the Attempt) + * @return the SystemContractMethod for the attempt (or it can be empty if unknown) */ - boolean matches(@NonNull T attempt); + abstract @NonNull Optional identifyMethod(@NonNull final T attempt); /** * Returns a call from the given attempt. @@ -50,4 +51,16 @@ public interface CallTranslator { * @return a call from the given attempt */ Call callFrom(@NonNull T attempt); + + /** Returns a call from the given attempt + * + * @param attempt the attempt to get the call from + * @param systemContractMethod system contract method the attempt is calling + * @return a call from the given attempt hascall + */ + default Call callFrom(@NonNull final T attempt, @NonNull final SystemContractMethod systemContractMethod) { + final var call = callFrom(attempt); + call.setSystemContractMethod(systemContractMethod); + return call; + } } diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/has/HasCallAttempt.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/has/HasCallAttempt.java index a6cf40fedd88..e4fbf1ccde9a 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/has/HasCallAttempt.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/has/HasCallAttempt.java @@ -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. @@ -31,6 +31,9 @@ import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.Call; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.CallTranslator; 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.hedera.node.app.spi.signatures.SignatureVerifier; import com.swirlds.config.api.Configuration; @@ -68,6 +71,7 @@ public HasCallAttempt( @NonNull final SignatureVerifier signatureVerifier, @NonNull final SystemContractGasCalculator gasCalculator, @NonNull final List> callTranslators, + @NonNull final SystemContractMethodRegistry systemContractMethodRegistry, final boolean isStaticCall) { super( input, @@ -81,6 +85,7 @@ public HasCallAttempt( gasCalculator, callTranslators, isStaticCall, + systemContractMethodRegistry, REDIRECT_FOR_ACCOUNT); if (isRedirect()) { this.redirectAccount = linkedAccount(requireNonNull(redirectAddress)); @@ -90,6 +95,11 @@ public HasCallAttempt( this.signatureVerifier = requireNonNull(signatureVerifier); } + @Override + protected SystemContract systemContractKind() { + return SystemContractMethod.SystemContract.HAS; + } + @Override protected HasCallAttempt self() { return this; diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/has/HasCallFactory.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/has/HasCallFactory.java index 16b7a2360b4f..1c8ee528d884 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/has/HasCallFactory.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/has/HasCallFactory.java @@ -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. @@ -27,6 +27,7 @@ import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.CallTranslator; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.SyntheticIds; import com.hedera.node.app.service.contract.impl.exec.utils.FrameUtils; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.spi.signatures.SignatureVerifier; import edu.umd.cs.findbugs.annotations.NonNull; import java.util.List; @@ -46,6 +47,7 @@ public class HasCallFactory implements CallFactory { private final VerificationStrategies verificationStrategies; private final SignatureVerifier signatureVerifier; private final List> callTranslators; + private final SystemContractMethodRegistry systemContractMethodRegistry; @Inject public HasCallFactory( @@ -53,12 +55,14 @@ public HasCallFactory( @NonNull final CallAddressChecks addressChecks, @NonNull final VerificationStrategies verificationStrategies, @NonNull final SignatureVerifier signatureVerifier, - @NonNull @Named("HasTranslators") final List> callTranslators) { + @NonNull @Named("HasTranslators") final List> callTranslators, + @NonNull final SystemContractMethodRegistry systemContractMethodRegistry) { this.syntheticIds = requireNonNull(syntheticIds); this.addressChecks = requireNonNull(addressChecks); this.verificationStrategies = requireNonNull(verificationStrategies); this.signatureVerifier = requireNonNull(signatureVerifier); this.callTranslators = requireNonNull(callTranslators); + this.systemContractMethodRegistry = requireNonNull(systemContractMethodRegistry); } /** @@ -88,6 +92,7 @@ public HasCallFactory( signatureVerifier, systemContractGasCalculatorOf(frame), callTranslators, + systemContractMethodRegistry, frame.isStatic()); } } diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/has/getevmaddressalias/EvmAddressAliasTranslator.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/has/getevmaddressalias/EvmAddressAliasTranslator.java index 85b056884397..12bf62016058 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/has/getevmaddressalias/EvmAddressAliasTranslator.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/has/getevmaddressalias/EvmAddressAliasTranslator.java @@ -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. @@ -19,11 +19,16 @@ import static java.util.Objects.requireNonNull; import com.esaulpaugh.headlong.abi.Address; -import com.esaulpaugh.headlong.abi.Function; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.AbstractCallTranslator; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.has.HasCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.ReturnTypes; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Category; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Modifier; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import edu.umd.cs.findbugs.annotations.NonNull; +import java.util.Optional; import javax.inject.Inject; import javax.inject.Singleton; @@ -33,12 +38,19 @@ @Singleton public class EvmAddressAliasTranslator extends AbstractCallTranslator { /** Selector for getEvmAddressAlias(address) method. */ - public static final Function EVM_ADDRESS_ALIAS = - new Function("getEvmAddressAlias(address)", ReturnTypes.RESPONSE_CODE_ADDRESS); + public static final SystemContractMethod EVM_ADDRESS_ALIAS = SystemContractMethod.declare( + "getEvmAddressAlias(address)", ReturnTypes.RESPONSE_CODE_ADDRESS) + .withModifier(Modifier.VIEW) + .withCategories(Category.ALIASES); @Inject - public EvmAddressAliasTranslator() { + public EvmAddressAliasTranslator( + @NonNull final SystemContractMethodRegistry systemContractMethodRegistry, + @NonNull final ContractMetrics contractMetrics) { // Dagger + super(SystemContractMethod.SystemContract.HAS, systemContractMethodRegistry, contractMetrics); + + registerMethods(EVM_ADDRESS_ALIAS); } /** @@ -52,12 +64,9 @@ public EvmAddressAliasTranslator() { return new EvmAddressAliasCall(attempt, address); } - /** - * {@inheritDoc} - */ @Override - public boolean matches(@NonNull final HasCallAttempt attempt) { + public @NonNull Optional identifyMethod(@NonNull final HasCallAttempt attempt) { requireNonNull(attempt, "attempt"); - return attempt.isSelector(EVM_ADDRESS_ALIAS); + return attempt.isMethod(EVM_ADDRESS_ALIAS); } } diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/has/hbarallowance/HbarAllowanceTranslator.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/has/hbarallowance/HbarAllowanceTranslator.java index 3a687a45ae58..ee044db41b45 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/has/hbarallowance/HbarAllowanceTranslator.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/has/hbarallowance/HbarAllowanceTranslator.java @@ -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. @@ -18,12 +18,18 @@ import static java.util.Objects.requireNonNull; -import com.esaulpaugh.headlong.abi.Function; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.AbstractCallTranslator; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.Call; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.has.HasCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.ReturnTypes; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.CallVia; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Category; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Modifier; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import edu.umd.cs.findbugs.annotations.NonNull; +import java.util.Optional; import javax.inject.Inject; import javax.inject.Singleton; @@ -34,25 +40,32 @@ public class HbarAllowanceTranslator extends AbstractCallTranslator { /** Selector for hbarAllowance(address) method. */ - public static final Function HBAR_ALLOWANCE_PROXY = - new Function("hbarAllowance(address)", ReturnTypes.RESPONSE_CODE_INT256); + public static final SystemContractMethod HBAR_ALLOWANCE_PROXY = SystemContractMethod.declare( + "hbarAllowance(address)", ReturnTypes.RESPONSE_CODE_INT256) + .withVia(CallVia.PROXY) + .withModifier(Modifier.VIEW) + .withCategories(Category.ALLOWANCE); /** Selector for hbarAllowance(address,address) method. */ - public static final Function HBAR_ALLOWANCE = - new Function("hbarAllowance(address,address)", ReturnTypes.RESPONSE_CODE_INT256); + public static final SystemContractMethod HBAR_ALLOWANCE = SystemContractMethod.declare( + "hbarAllowance(address,address)", ReturnTypes.RESPONSE_CODE_INT256) + .withModifier(Modifier.VIEW) + .withCategories(Category.ALLOWANCE); @Inject - public HbarAllowanceTranslator() { + public HbarAllowanceTranslator( + @NonNull final SystemContractMethodRegistry systemContractMethodRegistry, + @NonNull final ContractMetrics contractMetrics) { // Dagger2 + super(SystemContractMethod.SystemContract.HAS, systemContractMethodRegistry, contractMetrics); + + registerMethods(HBAR_ALLOWANCE, HBAR_ALLOWANCE_PROXY); } - /** - * {@inheritDoc} - */ @Override - public boolean matches(@NonNull final HasCallAttempt attempt) { + public @NonNull Optional identifyMethod(@NonNull final HasCallAttempt attempt) { requireNonNull(attempt); - return attempt.isSelector(HBAR_ALLOWANCE, HBAR_ALLOWANCE_PROXY); + return attempt.isMethod(HBAR_ALLOWANCE, HBAR_ALLOWANCE_PROXY); } /** diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/has/hbarapprove/HbarApproveTranslator.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/has/hbarapprove/HbarApproveTranslator.java index d02d21909d61..3888a6a188e5 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/has/hbarapprove/HbarApproveTranslator.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/has/hbarapprove/HbarApproveTranslator.java @@ -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. @@ -18,17 +18,22 @@ import static java.util.Objects.requireNonNull; -import com.esaulpaugh.headlong.abi.Function; import com.hedera.hapi.node.base.AccountID; import com.hedera.hapi.node.token.CryptoAllowance; import com.hedera.hapi.node.token.CryptoApproveAllowanceTransactionBody; import com.hedera.hapi.node.transaction.TransactionBody; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.AbstractCallTranslator; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.Call; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.has.HasCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.ReturnTypes; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.CallVia; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Category; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import edu.umd.cs.findbugs.annotations.NonNull; import java.math.BigInteger; +import java.util.Optional; import javax.inject.Inject; import javax.inject.Singleton; @@ -39,28 +44,35 @@ public class HbarApproveTranslator extends AbstractCallTranslator { /** Selector for hbarApprove(address,int256) method. */ - public static final Function HBAR_APPROVE_PROXY = new Function("hbarApprove(address,int256)", ReturnTypes.INT_64); + public static final SystemContractMethod HBAR_APPROVE_PROXY = SystemContractMethod.declare( + "hbarApprove(address,int256)", ReturnTypes.INT_64) + .withVia(CallVia.PROXY) + .withCategories(Category.APPROVAL); /** Selector for hbarApprove(address,address,int256) method. */ - public static final Function HBAR_APPROVE = new Function("hbarApprove(address,address,int256)", ReturnTypes.INT_64); + public static final SystemContractMethod HBAR_APPROVE = SystemContractMethod.declare( + "hbarApprove(address,address,int256)", ReturnTypes.INT_64) + .withCategories(Category.APPROVAL); /** * Default constructor for injection. */ @Inject - public HbarApproveTranslator() { + public HbarApproveTranslator( + @NonNull final SystemContractMethodRegistry systemContractMethodRegistry, + @NonNull final ContractMetrics contractMetrics) { // Dagger2 + super(SystemContractMethod.SystemContract.HAS, systemContractMethodRegistry, contractMetrics); + + registerMethods(HBAR_APPROVE, HBAR_APPROVE_PROXY); } - /** - * {@inheritDoc} - */ @Override - public boolean matches(@NonNull final HasCallAttempt attempt) { + public @NonNull Optional identifyMethod(@NonNull final HasCallAttempt attempt) { requireNonNull(attempt); - return attempt.isSelector(HBAR_APPROVE, HBAR_APPROVE_PROXY); - } + return attempt.isMethod(HBAR_APPROVE, HBAR_APPROVE_PROXY); + } /** * {@inheritDoc} */ diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/has/hederaaccountnumalias/HederaAccountNumAliasTranslator.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/has/hederaaccountnumalias/HederaAccountNumAliasTranslator.java index 430a2ef8b7a7..774bd68b5640 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/has/hederaaccountnumalias/HederaAccountNumAliasTranslator.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/has/hederaaccountnumalias/HederaAccountNumAliasTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2024 Hedera Hashgraph, LLC + * Copyright (C) 2024-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. @@ -19,25 +19,39 @@ import static java.util.Objects.requireNonNull; import com.esaulpaugh.headlong.abi.Address; -import com.esaulpaugh.headlong.abi.Function; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.AbstractCallTranslator; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.has.HasCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.ReturnTypes; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Category; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Modifier; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import edu.umd.cs.findbugs.annotations.NonNull; +import java.util.Optional; import javax.inject.Inject; +import javax.inject.Singleton; +@Singleton public class HederaAccountNumAliasTranslator extends AbstractCallTranslator { /** Selector for getHederaAccountNumAlias(address) method. */ - public static final Function HEDERA_ACCOUNT_NUM_ALIAS = - new Function("getHederaAccountNumAlias(address)", ReturnTypes.RESPONSE_CODE_ADDRESS); + public static final SystemContractMethod HEDERA_ACCOUNT_NUM_ALIAS = SystemContractMethod.declare( + "getHederaAccountNumAlias(address)", ReturnTypes.RESPONSE_CODE_ADDRESS) + .withModifier(Modifier.VIEW) + .withCategories(Category.ALIASES); /** * Default constructor for injection. */ @Inject - public HederaAccountNumAliasTranslator() { + public HederaAccountNumAliasTranslator( + @NonNull final SystemContractMethodRegistry systemContractMethodRegistry, + @NonNull final ContractMetrics contractMetrics) { // Dagger + super(SystemContractMethod.SystemContract.HAS, systemContractMethodRegistry, contractMetrics); + + registerMethods(HEDERA_ACCOUNT_NUM_ALIAS); } /** @@ -52,8 +66,9 @@ public HederaAccountNumAliasTranslator() { } @Override - public boolean matches(@NonNull HasCallAttempt attempt) { + public @NonNull Optional identifyMethod(@NonNull final HasCallAttempt attempt) { requireNonNull(attempt, "attempt"); - return attempt.isSelector(HEDERA_ACCOUNT_NUM_ALIAS); + + return attempt.isMethod(HEDERA_ACCOUNT_NUM_ALIAS); } } diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/has/isauthorized/IsAuthorizedTranslator.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/has/isauthorized/IsAuthorizedTranslator.java index eb18982fc789..6b09f77db092 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/has/isauthorized/IsAuthorizedTranslator.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/has/isauthorized/IsAuthorizedTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2024 Hedera Hashgraph, LLC + * Copyright (C) 2024-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. @@ -19,24 +19,29 @@ import static java.util.Objects.requireNonNull; import com.esaulpaugh.headlong.abi.Address; -import com.esaulpaugh.headlong.abi.Function; import com.hedera.node.app.service.contract.impl.annotations.ServicesV051; import com.hedera.node.app.service.contract.impl.exec.FeatureFlags; import com.hedera.node.app.service.contract.impl.exec.gas.CustomGasCalculator; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.AbstractCallTranslator; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.Call; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.has.HasCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.ReturnTypes; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Category; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.config.data.ContractsConfig; import edu.umd.cs.findbugs.annotations.NonNull; +import java.util.Optional; import javax.inject.Inject; import javax.inject.Singleton; @Singleton public class IsAuthorizedTranslator extends AbstractCallTranslator { - public static final Function IS_AUTHORIZED = - new Function("isAuthorized(address,bytes,bytes)", ReturnTypes.RESPONSE_CODE64_BOOL); + public static final SystemContractMethod IS_AUTHORIZED = SystemContractMethod.declare( + "isAuthorized(address,bytes,bytes)", ReturnTypes.RESPONSE_CODE64_BOOL) + .withCategories(Category.IS_AUTHORIZED); private static final int ADDRESS_ARG = 0; private static final int MESSAGE_ARG = 1; private static final int SIGNATURE_BLOB_ARG = 2; @@ -46,19 +51,26 @@ public class IsAuthorizedTranslator extends AbstractCallTranslator identifyMethod(@NonNull HasCallAttempt attempt) { requireNonNull(attempt, "attempt"); - final boolean callEnabled = attempt.configuration() + final var callEnabled = attempt.configuration() .getConfigData(ContractsConfig.class) .systemContractAccountServiceIsAuthorizedEnabled(); - return callEnabled && attempt.isSelector(IS_AUTHORIZED); + + if (attempt.isSelectorIfConfigEnabled(callEnabled, IS_AUTHORIZED)) return Optional.of(IS_AUTHORIZED); + return Optional.empty(); } @Override diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/has/isauthorizedraw/IsAuthorizedRawTranslator.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/has/isauthorizedraw/IsAuthorizedRawTranslator.java index 609e54c01592..4dde677e0d16 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/has/isauthorizedraw/IsAuthorizedRawTranslator.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/has/isauthorizedraw/IsAuthorizedRawTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2024 Hedera Hashgraph, LLC + * Copyright (C) 2024-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. @@ -19,16 +19,20 @@ import static java.util.Objects.requireNonNull; import com.esaulpaugh.headlong.abi.Address; -import com.esaulpaugh.headlong.abi.Function; import com.hedera.node.app.service.contract.impl.annotations.ServicesV051; import com.hedera.node.app.service.contract.impl.exec.FeatureFlags; import com.hedera.node.app.service.contract.impl.exec.gas.CustomGasCalculator; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.AbstractCallTranslator; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.Call; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.has.HasCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.ReturnTypes; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Category; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.config.data.ContractsConfig; import edu.umd.cs.findbugs.annotations.NonNull; +import java.util.Optional; import javax.inject.Inject; import javax.inject.Singleton; @@ -39,8 +43,9 @@ public class IsAuthorizedRawTranslator extends AbstractCallTranslator { /** Selector for isAuthorizedRaw(address,bytes,bytes) method. */ - public static final Function IS_AUTHORIZED_RAW = - new Function("isAuthorizedRaw(address,bytes,bytes)", ReturnTypes.BOOL); + public static final SystemContractMethod IS_AUTHORIZED_RAW = SystemContractMethod.declare( + "isAuthorizedRaw(address,bytes,bytes)", ReturnTypes.BOOL) + .withCategories(Category.IS_AUTHORIZED); private static final int ADDRESS_ARG = 0; private static final int HASH_ARG = 1; @@ -51,22 +56,25 @@ public class IsAuthorizedRawTranslator extends AbstractCallTranslator identifyMethod(@NonNull final HasCallAttempt attempt) { requireNonNull(attempt, "attempt"); - final boolean callEnabled = attempt.configuration() + final var callEnabled = attempt.configuration() .getConfigData(ContractsConfig.class) .systemContractAccountServiceIsAuthorizedRawEnabled(); - return callEnabled && attempt.isSelector(IS_AUTHORIZED_RAW); + if (attempt.isSelectorIfConfigEnabled(callEnabled, IS_AUTHORIZED_RAW)) return Optional.of(IS_AUTHORIZED_RAW); + return Optional.empty(); } /** diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/has/isvalidalias/IsValidAliasTranslator.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/has/isvalidalias/IsValidAliasTranslator.java index 45f425931336..f1c3dbcc036c 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/has/isvalidalias/IsValidAliasTranslator.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/has/isvalidalias/IsValidAliasTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2024 Hedera Hashgraph, LLC + * Copyright (C) 2024-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. @@ -19,25 +19,40 @@ import static java.util.Objects.requireNonNull; import com.esaulpaugh.headlong.abi.Address; -import com.esaulpaugh.headlong.abi.Function; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.AbstractCallTranslator; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.Call; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.has.HasCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.ReturnTypes; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Category; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Modifier; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import edu.umd.cs.findbugs.annotations.NonNull; +import java.util.Optional; import javax.inject.Inject; +import javax.inject.Singleton; +@Singleton public class IsValidAliasTranslator extends AbstractCallTranslator { /** Selector for isValidAlias(address) method. */ - public static final Function IS_VALID_ALIAS = new Function("isValidAlias(address)", ReturnTypes.BOOL); + public static final SystemContractMethod IS_VALID_ALIAS = SystemContractMethod.declare( + "isValidAlias(address)", ReturnTypes.BOOL) + .withModifier(Modifier.VIEW) + .withCategories(Category.ALIASES); /** * Default constructor for injection. */ @Inject - public IsValidAliasTranslator() { + public IsValidAliasTranslator( + @NonNull final SystemContractMethodRegistry systemContractMethodRegistry, + @NonNull final ContractMetrics contractMetrics) { // Dagger + super(SystemContractMethod.SystemContract.HAS, systemContractMethodRegistry, contractMetrics); + + registerMethods(IS_VALID_ALIAS); } @Override @@ -48,8 +63,9 @@ public IsValidAliasTranslator() { } @Override - public boolean matches(@NonNull HasCallAttempt attempt) { + public @NonNull Optional identifyMethod(@NonNull final HasCallAttempt attempt) { requireNonNull(attempt, "attempt"); - return attempt.isSelector(IS_VALID_ALIAS); + + return attempt.isMethod(IS_VALID_ALIAS); } } diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/has/setunlimitedautoassociations/SetUnlimitedAutoAssociationsTranslator.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/has/setunlimitedautoassociations/SetUnlimitedAutoAssociationsTranslator.java index 4c289164d8b0..8fb48ffce1e6 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/has/setunlimitedautoassociations/SetUnlimitedAutoAssociationsTranslator.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/has/setunlimitedautoassociations/SetUnlimitedAutoAssociationsTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2024 Hedera Hashgraph, LLC + * Copyright (C) 2024-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. @@ -18,38 +18,51 @@ import static java.util.Objects.requireNonNull; -import com.esaulpaugh.headlong.abi.Function; import com.hedera.hapi.node.token.CryptoUpdateTransactionBody; import com.hedera.hapi.node.transaction.TransactionBody; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.AbstractCallTranslator; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.Call; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.has.HasCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.ReturnTypes; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Category; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.config.data.ContractsConfig; import edu.umd.cs.findbugs.annotations.NonNull; +import java.util.Optional; import javax.inject.Inject; import javax.inject.Singleton; @Singleton public class SetUnlimitedAutoAssociationsTranslator extends AbstractCallTranslator { - public static final Function SET_UNLIMITED_AUTO_ASSOC = - new Function("setUnlimitedAutomaticAssociations(bool)", ReturnTypes.INT_64); + public static final SystemContractMethod SET_UNLIMITED_AUTO_ASSOC = SystemContractMethod.declare( + "setUnlimitedAutomaticAssociations(bool)", ReturnTypes.INT_64) + .withCategories(Category.ASSOCIATION); private static final int UNLIMITED_AUTO_ASSOCIATIONS = -1; private static final int NO_AUTO_ASSOCIATIONS = 0; @Inject - public SetUnlimitedAutoAssociationsTranslator() { + public SetUnlimitedAutoAssociationsTranslator( + @NonNull final SystemContractMethodRegistry systemContractMethodRegistry, + @NonNull final ContractMetrics contractMetrics) { // Dagger2 + super(SystemContractMethod.SystemContract.HAS, systemContractMethodRegistry, contractMetrics); + + registerMethods(SET_UNLIMITED_AUTO_ASSOC); } @Override - public boolean matches(@NonNull final HasCallAttempt attempt) { + public @NonNull Optional identifyMethod(@NonNull final HasCallAttempt attempt) { final var setUnlimitedAutoAssocEnabled = attempt.configuration() .getConfigData(ContractsConfig.class) .systemContractSetUnlimitedAutoAssociationsEnabled(); - return attempt.isSelectorIfConfigEnabled(setUnlimitedAutoAssocEnabled, SET_UNLIMITED_AUTO_ASSOC); + + if (attempt.isSelectorIfConfigEnabled(setUnlimitedAutoAssocEnabled, SET_UNLIMITED_AUTO_ASSOC)) + return Optional.of(SET_UNLIMITED_AUTO_ASSOC); + return Optional.empty(); } @Override diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hss/HssCallAttempt.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hss/HssCallAttempt.java index fecfc73df24e..a3b69d72309d 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hss/HssCallAttempt.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hss/HssCallAttempt.java @@ -34,6 +34,9 @@ import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.Call; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.CallTranslator; 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.hedera.node.app.spi.signatures.SignatureVerifier; import com.swirlds.config.api.Configuration; @@ -72,6 +75,7 @@ public HssCallAttempt( @NonNull final SignatureVerifier signatureVerifier, @NonNull final SystemContractGasCalculator gasCalculator, @NonNull final List> callTranslators, + @NonNull final SystemContractMethodRegistry systemContractMethodRegistry, final boolean isStaticCall) { super( input, @@ -85,6 +89,7 @@ public HssCallAttempt( gasCalculator, callTranslators, isStaticCall, + systemContractMethodRegistry, REDIRECT_FOR_SCHEDULE_TXN); if (isRedirect()) { this.redirectScheduleTxn = linkedSchedule(requireNonNull(redirectAddress)); @@ -94,6 +99,11 @@ public HssCallAttempt( this.signatureVerifier = signatureVerifier; } + @Override + protected SystemContract systemContractKind() { + return SystemContractMethod.SystemContract.HSS; + } + @Override protected HssCallAttempt self() { return this; diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hss/HssCallFactory.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hss/HssCallFactory.java index bf76ef12d013..84b277c4cf26 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hss/HssCallFactory.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hss/HssCallFactory.java @@ -27,6 +27,7 @@ import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.CallTranslator; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.SyntheticIds; import com.hedera.node.app.service.contract.impl.exec.utils.FrameUtils; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.spi.signatures.SignatureVerifier; import edu.umd.cs.findbugs.annotations.NonNull; import java.util.List; @@ -44,8 +45,9 @@ public class HssCallFactory implements CallFactory { private final SyntheticIds syntheticIds; private final CallAddressChecks addressChecks; private final VerificationStrategies verificationStrategies; - private final List> callTranslators; private final SignatureVerifier signatureVerifier; + private final List> callTranslators; + private final SystemContractMethodRegistry systemContractMethodRegistry; @Inject public HssCallFactory( @@ -53,12 +55,14 @@ public HssCallFactory( @NonNull final CallAddressChecks addressChecks, @NonNull final VerificationStrategies verificationStrategies, @NonNull final SignatureVerifier signatureVerifier, - @NonNull @Named("HssTranslators") final List> callTranslators) { + @NonNull @Named("HssTranslators") final List> callTranslators, + @NonNull final SystemContractMethodRegistry systemContractMethodRegistry) { this.syntheticIds = requireNonNull(syntheticIds); this.addressChecks = requireNonNull(addressChecks); this.verificationStrategies = requireNonNull(verificationStrategies); this.signatureVerifier = requireNonNull(signatureVerifier); this.callTranslators = requireNonNull(callTranslators); + this.systemContractMethodRegistry = requireNonNull(systemContractMethodRegistry); } /** @@ -88,6 +92,7 @@ public HssCallFactory( signatureVerifier, systemContractGasCalculatorOf(frame), callTranslators, + systemContractMethodRegistry, frame.isStatic()); } } diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hss/schedulenative/ScheduleNativeTranslator.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hss/schedulenative/ScheduleNativeTranslator.java index 059e745e9c41..f78838dcb6ca 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hss/schedulenative/ScheduleNativeTranslator.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hss/schedulenative/ScheduleNativeTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2024 Hedera Hashgraph, LLC + * Copyright (C) 2024-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. @@ -17,28 +17,31 @@ package com.hedera.node.app.service.contract.impl.exec.systemcontracts.hss.schedulenative; 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.hts.create.CreateTranslator.createSelectorsMap; -import static com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.update.UpdateTranslator.updateSelectorsMap; +import static com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.create.CreateTranslator.createMethodsMap; +import static com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.update.UpdateTranslator.updateMethodsMap; import static com.hedera.node.app.spi.workflows.HandleException.validateTrue; import static java.util.Objects.requireNonNull; import static org.hyperledger.besu.datatypes.Address.fromHexString; import com.esaulpaugh.headlong.abi.Address; -import com.esaulpaugh.headlong.abi.Function; import com.hedera.hapi.node.base.AccountID; import com.hedera.hapi.node.base.ResponseCodeEnum; import com.hedera.hapi.node.transaction.TransactionBody; import com.hedera.node.app.service.contract.impl.exec.gas.DispatchType; import com.hedera.node.app.service.contract.impl.exec.gas.SystemContractGasCalculator; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.AbstractCallTranslator; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.Call; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hss.HssCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallFactory; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.ReturnTypes; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.hevm.HederaWorldUpdater; import com.hedera.node.config.data.ContractsConfig; import edu.umd.cs.findbugs.annotations.NonNull; import java.util.Arrays; +import java.util.Optional; import javax.inject.Inject; import javax.inject.Singleton; import org.apache.tuweni.bytes.Bytes; @@ -46,8 +49,8 @@ @Singleton public class ScheduleNativeTranslator extends AbstractCallTranslator { - public static final Function SCHEDULED_NATIVE_CALL = - new Function("scheduleNative(address,bytes,address)", ReturnTypes.RESPONSE_CODE_ADDRESS); + public static final SystemContractMethod SCHEDULED_NATIVE_CALL = + SystemContractMethod.declare("scheduleNative(address,bytes,address)", ReturnTypes.RESPONSE_CODE_ADDRESS); private static final int SCHEDULE_CONTRACT_ADDRESS = 0; private static final int SCHEDULE_CALL_DATA = 1; private static final int SCHEDULE_PAYER = 2; @@ -55,17 +58,27 @@ public class ScheduleNativeTranslator extends AbstractCallTranslator identifyMethod(@NonNull final HssCallAttempt attempt) { final var scheduleNativeEnabled = attempt.configuration().getConfigData(ContractsConfig.class).systemContractScheduleNativeEnabled(); - return attempt.isSelectorIfConfigEnabled(scheduleNativeEnabled, SCHEDULED_NATIVE_CALL) - && innerCallValidation(attempt); + + if (!attempt.isSelectorIfConfigEnabled(scheduleNativeEnabled, SCHEDULED_NATIVE_CALL)) return Optional.empty(); + if (!innerCallValidation(attempt)) return Optional.empty(); + return Optional.of(SCHEDULED_NATIVE_CALL); } @Override @@ -116,9 +129,9 @@ private boolean innerCallValidation(@NonNull final HssCallAttempt attempt) { final var innerCallSelector = Bytes.wrap((byte[]) call.get(SCHEDULE_CALL_DATA)).slice(0, 4).toArray(); final var canBeCreateToken = - createSelectorsMap.keySet().stream().anyMatch(s -> Arrays.equals(s.selector(), innerCallSelector)); + createMethodsMap.keySet().stream().anyMatch(s -> Arrays.equals(s.selector(), innerCallSelector)); final var canBeUpdateToken = - updateSelectorsMap.keySet().stream().anyMatch(s -> Arrays.equals(s.selector(), innerCallSelector)); + updateMethodsMap.keySet().stream().anyMatch(s -> Arrays.equals(s.selector(), innerCallSelector)); return canBeCreateToken || canBeUpdateToken; } diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hss/signschedule/SignScheduleTranslator.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hss/signschedule/SignScheduleTranslator.java index 33e357e5713d..dbc6c2b11287 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hss/signschedule/SignScheduleTranslator.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hss/signschedule/SignScheduleTranslator.java @@ -27,7 +27,6 @@ import static java.util.Objects.requireNonNull; import com.esaulpaugh.headlong.abi.Address; -import com.esaulpaugh.headlong.abi.Function; import com.esaulpaugh.headlong.abi.Tuple; import com.google.common.annotations.VisibleForTesting; import com.hedera.hapi.node.base.AccountID; @@ -38,11 +37,16 @@ import com.hedera.hapi.node.transaction.TransactionBody; import com.hedera.node.app.service.contract.impl.exec.gas.DispatchType; import com.hedera.node.app.service.contract.impl.exec.gas.SystemContractGasCalculator; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.AbstractCallTranslator; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.Call; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hss.DispatchForResponseCodeHssCall; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hss.HssCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.ReturnTypes; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.CallVia; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Category; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.hevm.HederaWorldUpdater; import com.hedera.node.app.spi.signatures.SignatureVerifier.MessageType; import com.hedera.node.app.spi.signatures.SignatureVerifier.SimpleKeyStatus; @@ -53,6 +57,7 @@ import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; import java.util.HashSet; +import java.util.Optional; import java.util.Set; import javax.inject.Inject; import javax.inject.Singleton; @@ -62,19 +67,34 @@ */ @Singleton public class SignScheduleTranslator extends AbstractCallTranslator { - public static final Function SIGN_SCHEDULE = new Function("signSchedule(address,bytes)", ReturnTypes.INT_64); - public static final Function SIGN_SCHEDULE_PROXY = new Function("signSchedule()", ReturnTypes.INT_64); - public static final Function AUTHORIZE_SCHEDULE = new Function("authorizeSchedule(address)", ReturnTypes.INT_64); + + public static final SystemContractMethod SIGN_SCHEDULE = SystemContractMethod.declare( + "signSchedule(address,bytes)", ReturnTypes.INT_64) + .withCategories(Category.SCHEDULE); private static final int SCHEDULE_ID_INDEX = 0; private static final int SIGNATURE_MAP_INDEX = 1; + public static final SystemContractMethod SIGN_SCHEDULE_PROXY = SystemContractMethod.declare( + "signSchedule()", ReturnTypes.INT_64) + .withVia(CallVia.PROXY) + .withCategories(Category.SCHEDULE); + + public static final SystemContractMethod AUTHORIZE_SCHEDULE = SystemContractMethod.declare( + "authorizeSchedule(address)", ReturnTypes.INT_64) + .withCategories(Category.SCHEDULE); + @Inject - public SignScheduleTranslator() { + public SignScheduleTranslator( + @NonNull final SystemContractMethodRegistry systemContractMethodRegistry, + @NonNull final ContractMetrics contractMetrics) { // Dagger2 + super(SystemContractMethod.SystemContract.HSS, systemContractMethodRegistry, contractMetrics); + + registerMethods(SIGN_SCHEDULE, AUTHORIZE_SCHEDULE, SIGN_SCHEDULE_PROXY); } @Override - public boolean matches(@NonNull final HssCallAttempt attempt) { + public @NonNull Optional identifyMethod(@NonNull final HssCallAttempt attempt) { requireNonNull(attempt); final var signScheduleEnabled = attempt.configuration().getConfigData(ContractsConfig.class).systemContractSignScheduleEnabled(); @@ -83,9 +103,14 @@ public boolean matches(@NonNull final HssCallAttempt attempt) { .systemContractSignScheduleFromContractEnabled(); final var authorizeScheduleEnabled = attempt.configuration().getConfigData(ContractsConfig.class).systemContractAuthorizeScheduleEnabled(); - return attempt.isSelectorIfConfigEnabled(signScheduleEnabled, SIGN_SCHEDULE_PROXY) - || attempt.isSelectorIfConfigEnabled(signScheduleFromContractEnabled, SIGN_SCHEDULE) - || attempt.isSelectorIfConfigEnabled(authorizeScheduleEnabled, AUTHORIZE_SCHEDULE); + + if (attempt.isSelectorIfConfigEnabled(signScheduleEnabled, SIGN_SCHEDULE_PROXY)) + return Optional.of(SIGN_SCHEDULE_PROXY); + if (attempt.isSelectorIfConfigEnabled(authorizeScheduleEnabled, AUTHORIZE_SCHEDULE)) + return Optional.of(AUTHORIZE_SCHEDULE); + if (attempt.isSelectorIfConfigEnabled(signScheduleFromContractEnabled, SIGN_SCHEDULE)) + return Optional.of(SIGN_SCHEDULE); + return Optional.empty(); } @Override diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/HtsCallAttempt.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/HtsCallAttempt.java index b7557667ad4d..cce95c1729aa 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/HtsCallAttempt.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/HtsCallAttempt.java @@ -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. @@ -31,6 +31,9 @@ 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.CallTranslator; +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; import edu.umd.cs.findbugs.annotations.NonNull; @@ -73,6 +76,7 @@ public HtsCallAttempt( @NonNull final VerificationStrategies verificationStrategies, @NonNull final SystemContractGasCalculator gasCalculator, @NonNull final List> callTranslators, + @NonNull final SystemContractMethodRegistry systemContractMethodRegistry, final boolean isStaticCall) { super( input, @@ -86,6 +90,7 @@ public HtsCallAttempt( gasCalculator, callTranslators, isStaticCall, + systemContractMethodRegistry, REDIRECT_FOR_TOKEN); if (isRedirect()) { this.redirectToken = linkedToken(redirectAddress); @@ -96,6 +101,11 @@ public HtsCallAttempt( (authorizingAddress != senderAddress) ? addressIdConverter.convertSender(authorizingAddress) : senderId; } + @Override + protected SystemContract systemContractKind() { + return SystemContractMethod.SystemContract.HTS; + } + @Override protected HtsCallAttempt self() { return this; diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/HtsCallFactory.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/HtsCallFactory.java index 6607ae0a5eb4..ccc3c0178bbc 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/HtsCallFactory.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/HtsCallFactory.java @@ -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. @@ -27,6 +27,7 @@ import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.CallFactory; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.CallTranslator; import com.hedera.node.app.service.contract.impl.exec.utils.FrameUtils.CallType; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import edu.umd.cs.findbugs.annotations.NonNull; import java.util.List; import javax.inject.Inject; @@ -44,17 +45,20 @@ public class HtsCallFactory implements CallFactory { private final CallAddressChecks addressChecks; private final VerificationStrategies verificationStrategies; private final List> callTranslators; + private final SystemContractMethodRegistry systemContractMethodRegistry; @Inject public HtsCallFactory( @NonNull final SyntheticIds syntheticIds, @NonNull final CallAddressChecks addressChecks, @NonNull final VerificationStrategies verificationStrategies, - @NonNull @Named("HtsTranslators") final List> callTranslators) { + @NonNull @Named("HtsTranslators") final List> callTranslators, + @NonNull final SystemContractMethodRegistry systemContractMethodRegistry) { this.syntheticIds = requireNonNull(syntheticIds); this.addressChecks = requireNonNull(addressChecks); this.verificationStrategies = requireNonNull(verificationStrategies); this.callTranslators = requireNonNull(callTranslators); + this.systemContractMethodRegistry = requireNonNull(systemContractMethodRegistry); } /** @@ -93,6 +97,7 @@ public HtsCallFactory( verificationStrategies, systemContractGasCalculatorOf(frame), callTranslators, + systemContractMethodRegistry, frame.isStatic()); } } diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/airdrops/TokenAirdropTranslator.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/airdrops/TokenAirdropTranslator.java index c0cb03b4afff..bf5af933971c 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/airdrops/TokenAirdropTranslator.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/airdrops/TokenAirdropTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2024 Hedera Hashgraph, LLC + * Copyright (C) 2024-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. @@ -18,38 +18,53 @@ import static java.util.Objects.requireNonNull; -import com.esaulpaugh.headlong.abi.Function; import com.hedera.hapi.node.base.AccountID; import com.hedera.hapi.node.transaction.TransactionBody; import com.hedera.node.app.service.contract.impl.exec.gas.DispatchType; import com.hedera.node.app.service.contract.impl.exec.gas.SystemContractGasCalculator; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.AbstractCallTranslator; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.Call; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.DispatchForResponseCodeHtsCall; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallAttempt; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Category; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.hevm.HederaWorldUpdater; import com.hedera.node.config.data.ContractsConfig; import edu.umd.cs.findbugs.annotations.NonNull; +import java.util.Optional; import javax.inject.Inject; +import javax.inject.Singleton; +@Singleton public class TokenAirdropTranslator extends AbstractCallTranslator { - public static final Function TOKEN_AIRDROP = - new Function("airdropTokens((address,(address,int64,bool)[],(address,address,int64,bool)[])[])", "(int32)"); + public static final SystemContractMethod TOKEN_AIRDROP = SystemContractMethod.declare( + "airdropTokens((address,(address,int64,bool)[],(address,address,int64,bool)[])[])", "(int32)") + .withCategories(Category.AIRDROP); private final TokenAirdropDecoder decoder; @Inject - public TokenAirdropTranslator(@NonNull final TokenAirdropDecoder decoder) { + public TokenAirdropTranslator( + @NonNull final TokenAirdropDecoder decoder, + @NonNull final SystemContractMethodRegistry systemContractMethodRegistry, + @NonNull final ContractMetrics contractMetrics) { + super(SystemContractMethod.SystemContract.HTS, systemContractMethodRegistry, contractMetrics); requireNonNull(decoder); this.decoder = decoder; + + registerMethods(TOKEN_AIRDROP); } @Override - public boolean matches(@NonNull final HtsCallAttempt attempt) { + public @NonNull Optional identifyMethod(@NonNull final HtsCallAttempt attempt) { + requireNonNull(attempt); final var airdropEnabled = attempt.configuration().getConfigData(ContractsConfig.class).systemContractAirdropTokensEnabled(); - return attempt.isSelectorIfConfigEnabled(airdropEnabled, TOKEN_AIRDROP); + if (!airdropEnabled) return Optional.empty(); + return attempt.isMethod(TOKEN_AIRDROP); } public static long gasRequirement( diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/allowance/GetAllowanceTranslator.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/allowance/GetAllowanceTranslator.java index 7f70aef71567..a362922ed957 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/allowance/GetAllowanceTranslator.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/allowance/GetAllowanceTranslator.java @@ -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. @@ -16,15 +16,23 @@ package com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.allowance; +import static java.util.Objects.requireNonNull; + import com.esaulpaugh.headlong.abi.Address; -import com.esaulpaugh.headlong.abi.Function; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.AbstractCallTranslator; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.Call; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.ReturnTypes; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.CallVia; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Category; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Modifier; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.utils.ConversionUtils; import edu.umd.cs.findbugs.annotations.NonNull; import java.util.Arrays; +import java.util.Optional; import javax.inject.Inject; import javax.inject.Singleton; @@ -37,27 +45,36 @@ public class GetAllowanceTranslator extends AbstractCallTranslator identifyMethod(@NonNull final HtsCallAttempt attempt) { + requireNonNull(attempt); + return attempt.isMethod(GET_ALLOWANCE, ERC_GET_ALLOWANCE); } /** diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/associations/AssociationsTranslator.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/associations/AssociationsTranslator.java index a44cc64c4b14..86e2d67a4cc1 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/associations/AssociationsTranslator.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/associations/AssociationsTranslator.java @@ -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. @@ -16,18 +16,25 @@ package com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.associations; -import com.esaulpaugh.headlong.abi.Function; +import static java.util.Objects.requireNonNull; + import com.hedera.hapi.node.base.AccountID; import com.hedera.hapi.node.transaction.TransactionBody; import com.hedera.node.app.service.contract.impl.exec.gas.DispatchType; import com.hedera.node.app.service.contract.impl.exec.gas.SystemContractGasCalculator; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.AbstractCallTranslator; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.Call; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.DispatchForResponseCodeHtsCall; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.ReturnTypes; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.CallVia; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Category; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.hevm.HederaWorldUpdater; import edu.umd.cs.findbugs.annotations.NonNull; +import java.util.Optional; import javax.inject.Inject; import javax.inject.Singleton; @@ -40,29 +47,41 @@ public class AssociationsTranslator extends AbstractCallTranslator identifyMethod(@NonNull final HtsCallAttempt attempt) { + requireNonNull(attempt); return attempt.isTokenRedirect() - ? attempt.isSelector(HRC_ASSOCIATE, HRC_DISSOCIATE) - : attempt.isSelector(ASSOCIATE_ONE, ASSOCIATE_MANY, DISSOCIATE_ONE, DISSOCIATE_MANY); + ? attempt.isMethod(HRC_ASSOCIATE, HRC_DISSOCIATE) + : attempt.isMethod(ASSOCIATE_ONE, ASSOCIATE_MANY, DISSOCIATE_ONE, DISSOCIATE_MANY); } /** diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/balanceof/BalanceOfTranslator.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/balanceof/BalanceOfTranslator.java index 21eb94220fc1..014b876cebdd 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/balanceof/BalanceOfTranslator.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/balanceof/BalanceOfTranslator.java @@ -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. @@ -16,12 +16,19 @@ package com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.balanceof; +import static java.util.Objects.requireNonNull; + import com.esaulpaugh.headlong.abi.Address; -import com.esaulpaugh.headlong.abi.Function; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.AbstractCallTranslator; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.ReturnTypes; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Category; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Modifier; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import edu.umd.cs.findbugs.annotations.NonNull; +import java.util.Optional; import javax.inject.Inject; import javax.inject.Singleton; @@ -33,14 +40,22 @@ public class BalanceOfTranslator extends AbstractCallTranslator /** * Selector for balanceOf(address) method. */ - public static final Function BALANCE_OF = new Function("balanceOf(address)", ReturnTypes.INT); + public static final SystemContractMethod BALANCE_OF = SystemContractMethod.declare( + "balanceOf(address)", ReturnTypes.INT) + .withModifier(Modifier.VIEW) + .withCategory(Category.TOKEN_QUERY); /** * Default constructor for injection. */ @Inject - public BalanceOfTranslator() { + public BalanceOfTranslator( + @NonNull final SystemContractMethodRegistry systemContractMethodRegistry, + @NonNull final ContractMetrics contractMetrics) { // Dagger2 + super(SystemContractMethod.SystemContract.HTS, systemContractMethodRegistry, contractMetrics); + + registerMethods(BALANCE_OF); } /** @@ -55,11 +70,9 @@ public BalanceOfCall callFrom(@NonNull final HtsCallAttempt attempt) { attempt.enhancement(), attempt.systemContractGasCalculator(), attempt.redirectToken(), owner); } - /** - * {@inheritDoc} - */ @Override - public boolean matches(@NonNull final HtsCallAttempt attempt) { - return attempt.isSelector(BALANCE_OF); + public @NonNull Optional identifyMethod(@NonNull final HtsCallAttempt attempt) { + requireNonNull(attempt); + return attempt.isMethod(BALANCE_OF); } } diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/burn/BurnTranslator.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/burn/BurnTranslator.java index 106d80a0c420..5c06dfed4e9d 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/burn/BurnTranslator.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/burn/BurnTranslator.java @@ -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. @@ -18,32 +18,46 @@ import static com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.ReturnTypes.INT64_INT64; import static com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.burn.BurnDecoder.BURN_OUTPUT_FN; +import static java.util.Objects.requireNonNull; -import com.esaulpaugh.headlong.abi.Function; import com.hedera.hapi.node.base.AccountID; import com.hedera.hapi.node.transaction.TransactionBody; import com.hedera.node.app.service.contract.impl.exec.gas.DispatchType; import com.hedera.node.app.service.contract.impl.exec.gas.SystemContractGasCalculator; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.AbstractCallTranslator; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.Call; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.DispatchForResponseCodeHtsCall; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallAttempt; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Category; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Variant; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.hevm.HederaWorldUpdater; import edu.umd.cs.findbugs.annotations.NonNull; +import java.util.Optional; import javax.inject.Inject; +import javax.inject.Singleton; /** * Translator class for burn calls */ +@Singleton public class BurnTranslator extends AbstractCallTranslator { /** * Selector for burnToken(address,uint64,int64[]) method. */ - public static final Function BURN_TOKEN_V1 = new Function("burnToken(address,uint64,int64[])", INT64_INT64); + public static final SystemContractMethod BURN_TOKEN_V1 = SystemContractMethod.declare( + "burnToken(address,uint64,int64[])", INT64_INT64) + .withVariant(Variant.V1) + .withCategories(Category.MINT_BURN); /** * Selector for burnToken(address,int64,int64[]) method. */ - public static final Function BURN_TOKEN_V2 = new Function("burnToken(address,int64,int64[])", INT64_INT64); + public static final SystemContractMethod BURN_TOKEN_V2 = SystemContractMethod.declare( + "burnToken(address,int64,int64[])", INT64_INT64) + .withVariant(Variant.V2) + .withCategories(Category.MINT_BURN); BurnDecoder decoder; @@ -52,13 +66,20 @@ public class BurnTranslator extends AbstractCallTranslator { * @param decoder the decoder to use for decoding burn calls */ @Inject - public BurnTranslator(@NonNull final BurnDecoder decoder) { + public BurnTranslator( + @NonNull final BurnDecoder decoder, + @NonNull final SystemContractMethodRegistry systemContractMethodRegistry, + @NonNull final ContractMetrics contractMetrics) { + super(SystemContractMethod.SystemContract.HTS, systemContractMethodRegistry, contractMetrics); this.decoder = decoder; + + registerMethods(BURN_TOKEN_V1, BURN_TOKEN_V2); } @Override - public boolean matches(@NonNull HtsCallAttempt attempt) { - return attempt.isSelector(BURN_TOKEN_V1, BURN_TOKEN_V2); + public @NonNull Optional identifyMethod(@NonNull HtsCallAttempt attempt) { + requireNonNull(attempt); + return attempt.isMethod(BURN_TOKEN_V1, BURN_TOKEN_V2); } @Override diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/cancelairdrops/TokenCancelAirdropDecoder.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/cancelairdrops/TokenCancelAirdropDecoder.java index c684ac60dc82..9ab4bdb1d1a8 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/cancelairdrops/TokenCancelAirdropDecoder.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/cancelairdrops/TokenCancelAirdropDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2024 Hedera Hashgraph, LLC + * Copyright (C) 2024-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. @@ -52,7 +52,7 @@ public TokenCancelAirdropDecoder() { } public TransactionBody decodeCancelAirdrop(@NonNull final HtsCallAttempt attempt) { - final var call = TokenCancelAirdropTranslator.CANCEL_AIRDROP.decodeCall(attempt.inputBytes()); + final var call = TokenCancelAirdropTranslator.CANCEL_AIRDROPS.decodeCall(attempt.inputBytes()); final var maxPendingAirdropsToCancel = attempt.configuration().getConfigData(TokensConfig.class).maxAllowedPendingAirdropsToCancel(); final var transferList = (Tuple[]) call.get(TRANSFER_LIST); diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/cancelairdrops/TokenCancelAirdropTranslator.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/cancelairdrops/TokenCancelAirdropTranslator.java index 3515e354776e..84f0c921b22b 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/cancelairdrops/TokenCancelAirdropTranslator.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/cancelairdrops/TokenCancelAirdropTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2024 Hedera Hashgraph, LLC + * Copyright (C) 2024-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. @@ -18,46 +18,71 @@ import static java.util.Objects.requireNonNull; -import com.esaulpaugh.headlong.abi.Function; import com.hedera.hapi.node.base.AccountID; import com.hedera.hapi.node.transaction.TransactionBody; import com.hedera.node.app.service.contract.impl.exec.gas.DispatchType; import com.hedera.node.app.service.contract.impl.exec.gas.SystemContractGasCalculator; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.AbstractCallTranslator; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.Call; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.DispatchForResponseCodeHtsCall; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.ReturnTypes; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.CallVia; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Category; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Variant; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.hevm.HederaWorldUpdater; import com.hedera.node.config.data.ContractsConfig; import edu.umd.cs.findbugs.annotations.NonNull; +import java.util.Optional; import javax.inject.Inject; +import javax.inject.Singleton; +@Singleton public class TokenCancelAirdropTranslator extends AbstractCallTranslator { // Actual signature definition with struct name before flattening // cancelAirdrops(PendingAirdrop[]) - public static final Function CANCEL_AIRDROP = - new Function("cancelAirdrops((address,address,address,int64)[])", ReturnTypes.INT_64); - public static final Function HRC_CANCEL_AIRDROP_FT = new Function("cancelAirdropFT(address)", ReturnTypes.INT_64); - public static final Function HRC_CANCEL_AIRDROP_NFT = - new Function("cancelAirdropNFT(address,int64)", ReturnTypes.INT_64); + public static final SystemContractMethod CANCEL_AIRDROPS = SystemContractMethod.declare( + "cancelAirdrops((address,address,address,int64)[])", ReturnTypes.INT_64) + .withCategories(Category.AIRDROP); + public static final SystemContractMethod HRC_CANCEL_AIRDROP_FT = SystemContractMethod.declare( + "cancelAirdropFT(address)", ReturnTypes.INT_64) + .withVia(CallVia.PROXY) + .withVariant(Variant.FT) + .withCategories(Category.AIRDROP); + public static final SystemContractMethod HRC_CANCEL_AIRDROP_NFT = SystemContractMethod.declare( + "cancelAirdropNFT(address,int64)", ReturnTypes.INT_64) + .withVia(CallVia.PROXY) + .withVariant(Variant.NFT) + .withCategories(Category.AIRDROP); private final TokenCancelAirdropDecoder decoder; @Inject - public TokenCancelAirdropTranslator(@NonNull final TokenCancelAirdropDecoder decoder) { + public TokenCancelAirdropTranslator( + @NonNull final TokenCancelAirdropDecoder decoder, + @NonNull final SystemContractMethodRegistry systemContractMethodRegistry, + @NonNull final ContractMetrics contractMetrics) { + super(SystemContractMethod.SystemContract.HTS, systemContractMethodRegistry, contractMetrics); requireNonNull(decoder); this.decoder = decoder; + + registerMethods(CANCEL_AIRDROPS, HRC_CANCEL_AIRDROP_FT, HRC_CANCEL_AIRDROP_NFT); } @Override - public boolean matches(@NonNull final HtsCallAttempt attempt) { + public @NonNull Optional identifyMethod(@NonNull final HtsCallAttempt attempt) { + requireNonNull(attempt); final var cancelAirdropEnabled = attempt.configuration().getConfigData(ContractsConfig.class).systemContractCancelAirdropsEnabled(); + + if (!cancelAirdropEnabled) return Optional.empty(); return attempt.isTokenRedirect() - ? attempt.isSelectorIfConfigEnabled(cancelAirdropEnabled, HRC_CANCEL_AIRDROP_FT, HRC_CANCEL_AIRDROP_NFT) - : attempt.isSelectorIfConfigEnabled(cancelAirdropEnabled, CANCEL_AIRDROP); + ? attempt.isMethod(HRC_CANCEL_AIRDROP_FT, HRC_CANCEL_AIRDROP_NFT) + : attempt.isMethod(CANCEL_AIRDROPS); } @Override @@ -67,7 +92,7 @@ public Call callFrom(@NonNull final HtsCallAttempt attempt) { } private TransactionBody bodyFor(@NonNull final HtsCallAttempt attempt) { - if (attempt.isSelector(CANCEL_AIRDROP)) { + if (attempt.isSelector(CANCEL_AIRDROPS)) { return decoder.decodeCancelAirdrop(attempt); } else if (attempt.isSelector(HRC_CANCEL_AIRDROP_FT)) { return decoder.decodeCancelAirdropFT(attempt); diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/claimairdrops/TokenClaimAirdropDecoder.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/claimairdrops/TokenClaimAirdropDecoder.java index 8071cedf201c..d70baeed51aa 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/claimairdrops/TokenClaimAirdropDecoder.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/claimairdrops/TokenClaimAirdropDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2024 Hedera Hashgraph, LLC + * Copyright (C) 2024-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. @@ -52,7 +52,7 @@ public TokenClaimAirdropDecoder() { } public TransactionBody decodeTokenClaimAirdrop(@NonNull final HtsCallAttempt attempt) { - final var call = TokenClaimAirdropTranslator.CLAIM_AIRDROP.decodeCall(attempt.inputBytes()); + final var call = TokenClaimAirdropTranslator.CLAIM_AIRDROPS.decodeCall(attempt.inputBytes()); final var maxPendingAirdropsToClaim = attempt.configuration().getConfigData(TokensConfig.class).maxAllowedPendingAirdropsToClaim(); final var transferList = (Tuple[]) call.get(TRANSFER_LIST); diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/claimairdrops/TokenClaimAirdropTranslator.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/claimairdrops/TokenClaimAirdropTranslator.java index 92ae61d762f5..0e90dda05e45 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/claimairdrops/TokenClaimAirdropTranslator.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/claimairdrops/TokenClaimAirdropTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2024 Hedera Hashgraph, LLC + * Copyright (C) 2024-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. @@ -16,49 +16,76 @@ package com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.claimairdrops; -import com.esaulpaugh.headlong.abi.Function; +import static java.util.Objects.requireNonNull; + import com.hedera.hapi.node.base.AccountID; import com.hedera.hapi.node.transaction.TransactionBody; import com.hedera.node.app.service.contract.impl.exec.gas.DispatchType; import com.hedera.node.app.service.contract.impl.exec.gas.SystemContractGasCalculator; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.AbstractCallTranslator; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.Call; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.DispatchForResponseCodeHtsCall; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.ReturnTypes; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.CallVia; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Category; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Variant; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.hevm.HederaWorldUpdater; import com.hedera.node.config.data.ContractsConfig; import edu.umd.cs.findbugs.annotations.NonNull; +import java.util.Optional; import javax.inject.Inject; +import javax.inject.Singleton; +@Singleton public class TokenClaimAirdropTranslator extends AbstractCallTranslator { - public static final Function CLAIM_AIRDROP = - new Function("claimAirdrops((address,address,address,int64)[])", ReturnTypes.INT_64); - public static final Function HRC_CLAIM_AIRDROP_FT = new Function("claimAirdropFT(address)", ReturnTypes.INT_64); - public static final Function HRC_CLAIM_AIRDROP_NFT = - new Function("claimAirdropNFT(address,int64)", ReturnTypes.INT_64); + public static final SystemContractMethod CLAIM_AIRDROPS = SystemContractMethod.declare( + "claimAirdrops((address,address,address,int64)[])", ReturnTypes.INT_64) + .withCategories(Category.AIRDROP); + public static final SystemContractMethod HRC_CLAIM_AIRDROP_FT = SystemContractMethod.declare( + "claimAirdropFT(address)", ReturnTypes.INT_64) + .withVia(CallVia.PROXY) + .withVariant(Variant.FT) + .withCategories(Category.AIRDROP); + public static final SystemContractMethod HRC_CLAIM_AIRDROP_NFT = SystemContractMethod.declare( + "claimAirdropNFT(address,int64)", ReturnTypes.INT_64) + .withVia(CallVia.PROXY) + .withVariant(Variant.NFT) + .withCategories(Category.AIRDROP); private final TokenClaimAirdropDecoder decoder; @Inject - public TokenClaimAirdropTranslator(@NonNull final TokenClaimAirdropDecoder decoder) { + public TokenClaimAirdropTranslator( + @NonNull final TokenClaimAirdropDecoder decoder, + @NonNull final SystemContractMethodRegistry systemContractMethodRegistry, + @NonNull final ContractMetrics contractMetrics) { + super(SystemContractMethod.SystemContract.HTS, systemContractMethodRegistry, contractMetrics); this.decoder = decoder; + + registerMethods(CLAIM_AIRDROPS, HRC_CLAIM_AIRDROP_FT, HRC_CLAIM_AIRDROP_NFT); } @Override - public boolean matches(@NonNull final HtsCallAttempt attempt) { + public @NonNull Optional identifyMethod(@NonNull final HtsCallAttempt attempt) { + requireNonNull(attempt); final var claimAirdropEnabled = attempt.configuration().getConfigData(ContractsConfig.class).systemContractClaimAirdropsEnabled(); + + if (!claimAirdropEnabled) return Optional.empty(); return attempt.isTokenRedirect() - ? attempt.isSelectorIfConfigEnabled(claimAirdropEnabled, HRC_CLAIM_AIRDROP_FT, HRC_CLAIM_AIRDROP_NFT) - : attempt.isSelectorIfConfigEnabled(claimAirdropEnabled, CLAIM_AIRDROP); + ? attempt.isMethod(HRC_CLAIM_AIRDROP_FT, HRC_CLAIM_AIRDROP_NFT) + : attempt.isMethod(CLAIM_AIRDROPS); } @Override public Call callFrom(@NonNull final HtsCallAttempt attempt) { return new DispatchForResponseCodeHtsCall( attempt, - attempt.isSelector(CLAIM_AIRDROP) ? bodyForClassic(attempt) : bodyForHRC(attempt), + attempt.isSelector(CLAIM_AIRDROPS) ? bodyForClassic(attempt) : bodyForHRC(attempt), TokenClaimAirdropTranslator::gasRequirement); } diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/create/CreateTranslator.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/create/CreateTranslator.java index 058906ddc1dd..6a8fe9ab1e53 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/create/CreateTranslator.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/create/CreateTranslator.java @@ -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. @@ -27,147 +27,191 @@ import static com.hedera.node.app.hapi.utils.contracts.ParsingConstants.HEDERA_TOKEN_WITH_METADATA; import static com.hedera.node.app.hapi.utils.contracts.ParsingConstants.ROYALTY_FEE; import static com.hedera.node.app.hapi.utils.contracts.ParsingConstants.ROYALTY_FEE_V2; +import static java.util.Objects.requireNonNull; -import com.esaulpaugh.headlong.abi.Function; import com.hedera.hapi.node.transaction.TransactionBody; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.AbstractCallTranslator; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallAttempt; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Category; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Variant; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.config.data.ContractsConfig; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; import java.util.HashMap; import java.util.Map; -import java.util.Set; +import java.util.Optional; import javax.inject.Inject; +import javax.inject.Singleton; /** * Translates {@code createFungibleToken}, {@code createNonFungibleToken}, * {@code createFungibleTokenWithCustomFees} and {@code createNonFungibleTokenWithCustomFees} calls to the HTS system contract. */ +@Singleton public class CreateTranslator extends AbstractCallTranslator { /** Selector for createFungibleToken(HEDERA_TOKEN_V1,uint,uint) method. */ - public static final Function CREATE_FUNGIBLE_TOKEN_V1 = - new Function("createFungibleToken(" + HEDERA_TOKEN_V1 + ",uint,uint)", "(int64,address)"); + public static final SystemContractMethod CREATE_FUNGIBLE_TOKEN_V1 = SystemContractMethod.declare( + "createFungibleToken(" + HEDERA_TOKEN_V1 + ",uint,uint)", "(int64,address)") + .withVariants(Variant.V1, Variant.FT) + .withCategory(Category.CREATE_DELETE_TOKEN); /** Selector for createFungibleToken(HEDERA_TOKEN_V2,uint64,uint32) method. */ - public static final Function CREATE_FUNGIBLE_TOKEN_V2 = - new Function("createFungibleToken(" + HEDERA_TOKEN_V2 + ",uint64,uint32)", "(int64,address)"); + public static final SystemContractMethod CREATE_FUNGIBLE_TOKEN_V2 = SystemContractMethod.declare( + "createFungibleToken(" + HEDERA_TOKEN_V2 + ",uint64,uint32)", "(int64,address)") + .withVariants(Variant.V2, Variant.FT) + .withCategory(Category.CREATE_DELETE_TOKEN); /** Selector for createFungibleToken(HEDERA_TOKEN_V3,int64,int32) method. */ - public static final Function CREATE_FUNGIBLE_TOKEN_V3 = - new Function("createFungibleToken(" + HEDERA_TOKEN_V3 + ",int64,int32)", "(int64,address)"); + public static final SystemContractMethod CREATE_FUNGIBLE_TOKEN_V3 = SystemContractMethod.declare( + "createFungibleToken(" + HEDERA_TOKEN_V3 + ",int64,int32)", "(int64,address)") + .withVariants(Variant.V3, Variant.FT) + .withCategory(Category.CREATE_DELETE_TOKEN); /** Selector for createFungibleTokenWithCustomFees(HEDERA_TOKEN_V1,uint,uint,FIXED_FEE[],FRACTIONAL_FEE[]) method. */ - public static final Function CREATE_FUNGIBLE_WITH_CUSTOM_FEES_V1 = new Function( - "createFungibleTokenWithCustomFees(" - + HEDERA_TOKEN_V1 - + ",uint,uint," - + FIXED_FEE - + ARRAY_BRACKETS - + "," - + FRACTIONAL_FEE - + ARRAY_BRACKETS - + ")", - "(int64,address)"); + public static final SystemContractMethod CREATE_FUNGIBLE_WITH_CUSTOM_FEES_V1 = SystemContractMethod.declare( + "createFungibleTokenWithCustomFees(" + + HEDERA_TOKEN_V1 + + ",uint,uint," + + FIXED_FEE + + ARRAY_BRACKETS + + "," + + FRACTIONAL_FEE + + ARRAY_BRACKETS + + ")", + "(int64,address)") + .withVariants(Variant.V1, Variant.FT, Variant.WITH_CUSTOM_FEES) + .withCategory(Category.CREATE_DELETE_TOKEN); /** Selector for createFungibleTokenWithCustomFees(HEDERA_TOKEN_V2,uint64,uint32,FIXED_FEE[],FRACTIONAL_FEE[]) method. */ - public static final Function CREATE_FUNGIBLE_WITH_CUSTOM_FEES_V2 = new Function( - "createFungibleTokenWithCustomFees(" - + HEDERA_TOKEN_V2 - + ",uint64,uint32," - + FIXED_FEE - + ARRAY_BRACKETS - + "," - + FRACTIONAL_FEE - + ARRAY_BRACKETS - + ")", - "(int64,address)"); + public static final SystemContractMethod CREATE_FUNGIBLE_WITH_CUSTOM_FEES_V2 = SystemContractMethod.declare( + "createFungibleTokenWithCustomFees(" + + HEDERA_TOKEN_V2 + + ",uint64,uint32," + + FIXED_FEE + + ARRAY_BRACKETS + + "," + + FRACTIONAL_FEE + + ARRAY_BRACKETS + + ")", + "(int64,address)") + .withVariants(Variant.V2, Variant.FT, Variant.WITH_CUSTOM_FEES) + .withCategory(Category.CREATE_DELETE_TOKEN); /** Selector for createFungibleTokenWithCustomFees(HEDERA_TOKEN_V3,int64,int32,FIXED_FEE_V2[],FRACTIONAL_FEE_V2[]) method. */ - public static final Function CREATE_FUNGIBLE_WITH_CUSTOM_FEES_V3 = new Function( - "createFungibleTokenWithCustomFees(" - + HEDERA_TOKEN_V3 - + ",int64,int32," - + FIXED_FEE_V2 - + ARRAY_BRACKETS - + "," - + FRACTIONAL_FEE_V2 - + ARRAY_BRACKETS - + ")", - "(int64,address)"); + public static final SystemContractMethod CREATE_FUNGIBLE_WITH_CUSTOM_FEES_V3 = SystemContractMethod.declare( + "createFungibleTokenWithCustomFees(" + + HEDERA_TOKEN_V3 + + ",int64,int32," + + FIXED_FEE_V2 + + ARRAY_BRACKETS + + "," + + FRACTIONAL_FEE_V2 + + ARRAY_BRACKETS + + ")", + "(int64,address)") + .withVariants(Variant.V3, Variant.FT, Variant.WITH_CUSTOM_FEES) + .withCategory(Category.CREATE_DELETE_TOKEN); /** Selector for createNonFungibleToken(HEDERA_TOKEN_V1) method. */ - public static final Function CREATE_NON_FUNGIBLE_TOKEN_V1 = - new Function("createNonFungibleToken(" + HEDERA_TOKEN_V1 + ")", "(int64,address)"); + public static final SystemContractMethod CREATE_NON_FUNGIBLE_TOKEN_V1 = SystemContractMethod.declare( + "createNonFungibleToken(" + HEDERA_TOKEN_V1 + ")", "(int64,address)") + .withVariants(Variant.V1, Variant.NFT) + .withCategory(Category.CREATE_DELETE_TOKEN); /** Selector for createNonFungibleToken(HEDERA_TOKEN_V2) method. */ - public static final Function CREATE_NON_FUNGIBLE_TOKEN_V2 = - new Function("createNonFungibleToken(" + HEDERA_TOKEN_V2 + ")", "(int64,address)"); + public static final SystemContractMethod CREATE_NON_FUNGIBLE_TOKEN_V2 = SystemContractMethod.declare( + "createNonFungibleToken(" + HEDERA_TOKEN_V2 + ")", "(int64,address)") + .withVariants(Variant.V2, Variant.NFT) + .withCategory(Category.CREATE_DELETE_TOKEN); /** Selector for createNonFungibleToken(HEDERA_TOKEN_V3) method. */ - public static final Function CREATE_NON_FUNGIBLE_TOKEN_V3 = - new Function("createNonFungibleToken(" + HEDERA_TOKEN_V3 + ")", "(int64,address)"); + public static final SystemContractMethod CREATE_NON_FUNGIBLE_TOKEN_V3 = SystemContractMethod.declare( + "createNonFungibleToken(" + HEDERA_TOKEN_V3 + ")", "(int64,address)") + .withVariants(Variant.V3, Variant.NFT) + .withCategory(Category.CREATE_DELETE_TOKEN); /** Selector for createNonFungibleTokenWithCustomFees(HEDERA_TOKEN_V1,int64,int32,FIXED_FEE[],FRACTIONAL_FEE[]) method. */ - public static final Function CREATE_NON_FUNGIBLE_TOKEN_WITH_CUSTOM_FEES_V1 = new Function( - "createNonFungibleTokenWithCustomFees(" - + HEDERA_TOKEN_V1 - + "," - + FIXED_FEE - + ARRAY_BRACKETS - + "," - + ROYALTY_FEE - + ARRAY_BRACKETS - + ")", - "(int64,address)"); + public static final SystemContractMethod CREATE_NON_FUNGIBLE_TOKEN_WITH_CUSTOM_FEES_V1 = + SystemContractMethod.declare( + "createNonFungibleTokenWithCustomFees(" + + HEDERA_TOKEN_V1 + + "," + + FIXED_FEE + + ARRAY_BRACKETS + + "," + + ROYALTY_FEE + + ARRAY_BRACKETS + + ")", + "(int64,address)") + .withVariants(Variant.V1, Variant.NFT, Variant.WITH_CUSTOM_FEES) + .withCategory(Category.CREATE_DELETE_TOKEN); /** Selector for createNonFungibleTokenWithCustomFees(HEDERA_TOKEN_V2,int64,int32,FIXED_FEE[],FRACTIONAL_FEE[]) method. */ - public static final Function CREATE_NON_FUNGIBLE_TOKEN_WITH_CUSTOM_FEES_V2 = new Function( - "createNonFungibleTokenWithCustomFees(" - + HEDERA_TOKEN_V2 - + "," - + FIXED_FEE - + ARRAY_BRACKETS - + "," - + ROYALTY_FEE - + ARRAY_BRACKETS - + ")", - "(int64,address)"); + public static final SystemContractMethod CREATE_NON_FUNGIBLE_TOKEN_WITH_CUSTOM_FEES_V2 = + SystemContractMethod.declare( + "createNonFungibleTokenWithCustomFees(" + + HEDERA_TOKEN_V2 + + "," + + FIXED_FEE + + ARRAY_BRACKETS + + "," + + ROYALTY_FEE + + ARRAY_BRACKETS + + ")", + "(int64,address)") + .withVariants(Variant.V2, Variant.NFT, Variant.WITH_CUSTOM_FEES) + .withCategory(Category.CREATE_DELETE_TOKEN); /** Selector for createNonFungibleTokenWithCustomFees(HEDERA_TOKEN_V3,int64,int32,FIXED_FEE_2[],FRACTIONAL_FEE_2[]) method. */ - public static final Function CREATE_NON_FUNGIBLE_TOKEN_WITH_CUSTOM_FEES_V3 = new Function( - "createNonFungibleTokenWithCustomFees(" - + HEDERA_TOKEN_V3 - + "," - + FIXED_FEE_V2 - + ARRAY_BRACKETS - + "," - + ROYALTY_FEE_V2 - + ARRAY_BRACKETS - + ")", - "(int64,address)"); + public static final SystemContractMethod CREATE_NON_FUNGIBLE_TOKEN_WITH_CUSTOM_FEES_V3 = + SystemContractMethod.declare( + "createNonFungibleTokenWithCustomFees(" + + HEDERA_TOKEN_V3 + + "," + + FIXED_FEE_V2 + + ARRAY_BRACKETS + + "," + + ROYALTY_FEE_V2 + + ARRAY_BRACKETS + + ")", + "(int64,address)") + .withVariants(Variant.V3, Variant.NFT, Variant.WITH_CUSTOM_FEES) + .withCategory(Category.CREATE_DELETE_TOKEN); /** Selector for createFungibleTokenWithCustomFees(HEDERA_TOKEN_WITH_METADATA,int64,int32) method. */ - public static final Function CREATE_FUNGIBLE_TOKEN_WITH_METADATA = - new Function("createFungibleToken(" + HEDERA_TOKEN_WITH_METADATA + ",int64,int32)", "(int64,address)"); + public static final SystemContractMethod CREATE_FUNGIBLE_TOKEN_WITH_METADATA = SystemContractMethod.declare( + "createFungibleToken(" + HEDERA_TOKEN_WITH_METADATA + ",int64,int32)", "(int64,address)") + .withVariants(Variant.FT, Variant.WITH_METADATA) + .withCategory(Category.CREATE_DELETE_TOKEN); /** Selector for createFungibleTokenWithCustomFees(HEDERA_TOKEN_WITH_METADATA,int64,int32,FIXED_FEE_2[],FRACTIONAL_FEE_2[]) method. */ - public static final Function CREATE_FUNGIBLE_TOKEN_WITH_METADATA_AND_CUSTOM_FEES = new Function( - "createFungibleTokenWithCustomFees(" - + HEDERA_TOKEN_WITH_METADATA - + ",int64,int32," - + FIXED_FEE_V2 - + ARRAY_BRACKETS - + "," - + FRACTIONAL_FEE_V2 - + ARRAY_BRACKETS - + ")", - "(int64,address)"); + public static final SystemContractMethod CREATE_FUNGIBLE_TOKEN_WITH_METADATA_AND_CUSTOM_FEES = + SystemContractMethod.declare( + "createFungibleTokenWithCustomFees(" + + HEDERA_TOKEN_WITH_METADATA + + ",int64,int32," + + FIXED_FEE_V2 + + ARRAY_BRACKETS + + "," + + FRACTIONAL_FEE_V2 + + ARRAY_BRACKETS + + ")", + "(int64,address)") + .withVariants(Variant.FT, Variant.WITH_METADATA, Variant.WITH_CUSTOM_FEES) + .withCategory(Category.CREATE_DELETE_TOKEN); /** Selector for createNonFungibleToken(HEDERA_TOKEN_WITH_METADATA) method. */ - public static final Function CREATE_NON_FUNGIBLE_TOKEN_WITH_METADATA = - new Function("createNonFungibleToken(" + HEDERA_TOKEN_WITH_METADATA + ")", "(int64,address)"); + public static final SystemContractMethod CREATE_NON_FUNGIBLE_TOKEN_WITH_METADATA = SystemContractMethod.declare( + "createNonFungibleToken(" + HEDERA_TOKEN_WITH_METADATA + ")", "(int64,address)") + .withVariants(Variant.NFT, Variant.WITH_METADATA) + .withCategory(Category.CREATE_DELETE_TOKEN); /** Selector for createNonFungibleTokenWithCustomFees(HEDERA_TOKEN_WITH_METADATA,FIXED_FEE_2[],FRACTIONAL_FEE_2[]) method. */ - public static final Function CREATE_NON_FUNGIBLE_TOKEN_WITH_METADATA_AND_CUSTOM_FEES = new Function( - "createNonFungibleTokenWithCustomFees(" - + HEDERA_TOKEN_WITH_METADATA - + "," - + FIXED_FEE_V2 - + ARRAY_BRACKETS - + "," - + ROYALTY_FEE_V2 - + ARRAY_BRACKETS - + ")", - "(int64,address)"); + public static final SystemContractMethod CREATE_NON_FUNGIBLE_TOKEN_WITH_METADATA_AND_CUSTOM_FEES = + SystemContractMethod.declare( + "createNonFungibleTokenWithCustomFees(" + + HEDERA_TOKEN_WITH_METADATA + + "," + + FIXED_FEE_V2 + + ARRAY_BRACKETS + + "," + + ROYALTY_FEE_V2 + + ARRAY_BRACKETS + + ")", + "(int64,address)") + .withVariants(Variant.NFT, Variant.WITH_METADATA, Variant.WITH_CUSTOM_FEES) + .withCategory(Category.CREATE_DELETE_TOKEN); /** * A set of `Function` objects representing various create functions for fungible and non-fungible tokens. @@ -175,52 +219,76 @@ public class CreateTranslator extends AbstractCallTranslator { * to determine if a given call attempt is a creation call, because we do not allow sending value to Hedera system contracts * except in the case of token creation */ - public static final Map createSelectorsMap = new HashMap<>(); + public static final Map createMethodsMap = new HashMap<>(); /** * Constructor for injection. * @param decoder the decoder used to decode create calls */ @Inject - public CreateTranslator(final CreateDecoder decoder) { - createSelectorsMap.put(CREATE_FUNGIBLE_TOKEN_V1, decoder::decodeCreateFungibleTokenV1); - createSelectorsMap.put(CREATE_FUNGIBLE_TOKEN_V2, decoder::decodeCreateFungibleTokenV2); - createSelectorsMap.put(CREATE_FUNGIBLE_TOKEN_V3, decoder::decodeCreateFungibleTokenV3); - createSelectorsMap.put(CREATE_FUNGIBLE_TOKEN_WITH_METADATA, decoder::decodeCreateFungibleTokenWithMetadata); - createSelectorsMap.put(CREATE_FUNGIBLE_WITH_CUSTOM_FEES_V1, decoder::decodeCreateFungibleTokenWithCustomFeesV1); - createSelectorsMap.put(CREATE_FUNGIBLE_WITH_CUSTOM_FEES_V2, decoder::decodeCreateFungibleTokenWithCustomFeesV2); - createSelectorsMap.put(CREATE_FUNGIBLE_WITH_CUSTOM_FEES_V3, decoder::decodeCreateFungibleTokenWithCustomFeesV3); - createSelectorsMap.put( + public CreateTranslator( + final CreateDecoder decoder, + @NonNull final SystemContractMethodRegistry systemContractMethodRegistry, + @NonNull final ContractMetrics contractMetrics) { + super(SystemContractMethod.SystemContract.HTS, systemContractMethodRegistry, contractMetrics); + + registerMethods( + CREATE_FUNGIBLE_TOKEN_V1, + CREATE_FUNGIBLE_TOKEN_V2, + CREATE_FUNGIBLE_TOKEN_V3, + CREATE_FUNGIBLE_TOKEN_WITH_METADATA, + CREATE_FUNGIBLE_WITH_CUSTOM_FEES_V1, + CREATE_FUNGIBLE_WITH_CUSTOM_FEES_V2, + CREATE_FUNGIBLE_WITH_CUSTOM_FEES_V3, + CREATE_FUNGIBLE_TOKEN_WITH_METADATA_AND_CUSTOM_FEES, + CREATE_NON_FUNGIBLE_TOKEN_V1, + CREATE_NON_FUNGIBLE_TOKEN_V2, + CREATE_NON_FUNGIBLE_TOKEN_V3, + CREATE_NON_FUNGIBLE_TOKEN_WITH_METADATA, + CREATE_NON_FUNGIBLE_TOKEN_WITH_CUSTOM_FEES_V1, + CREATE_NON_FUNGIBLE_TOKEN_WITH_CUSTOM_FEES_V2, + CREATE_NON_FUNGIBLE_TOKEN_WITH_CUSTOM_FEES_V3, + CREATE_NON_FUNGIBLE_TOKEN_WITH_METADATA_AND_CUSTOM_FEES); + + createMethodsMap.put(CREATE_FUNGIBLE_TOKEN_V1, decoder::decodeCreateFungibleTokenV1); + createMethodsMap.put(CREATE_FUNGIBLE_TOKEN_V2, decoder::decodeCreateFungibleTokenV2); + createMethodsMap.put(CREATE_FUNGIBLE_TOKEN_V3, decoder::decodeCreateFungibleTokenV3); + createMethodsMap.put(CREATE_FUNGIBLE_TOKEN_WITH_METADATA, decoder::decodeCreateFungibleTokenWithMetadata); + createMethodsMap.put(CREATE_FUNGIBLE_WITH_CUSTOM_FEES_V1, decoder::decodeCreateFungibleTokenWithCustomFeesV1); + createMethodsMap.put(CREATE_FUNGIBLE_WITH_CUSTOM_FEES_V2, decoder::decodeCreateFungibleTokenWithCustomFeesV2); + createMethodsMap.put(CREATE_FUNGIBLE_WITH_CUSTOM_FEES_V3, decoder::decodeCreateFungibleTokenWithCustomFeesV3); + createMethodsMap.put( CREATE_FUNGIBLE_TOKEN_WITH_METADATA_AND_CUSTOM_FEES, decoder::decodeCreateFungibleTokenWithMetadataAndCustomFees); - createSelectorsMap.put(CREATE_NON_FUNGIBLE_TOKEN_V1, decoder::decodeCreateNonFungibleV1); - createSelectorsMap.put(CREATE_NON_FUNGIBLE_TOKEN_V2, decoder::decodeCreateNonFungibleV2); - createSelectorsMap.put(CREATE_NON_FUNGIBLE_TOKEN_V3, decoder::decodeCreateNonFungibleV3); - createSelectorsMap.put(CREATE_NON_FUNGIBLE_TOKEN_WITH_METADATA, decoder::decodeCreateNonFungibleWithMetadata); - createSelectorsMap.put( + createMethodsMap.put(CREATE_NON_FUNGIBLE_TOKEN_V1, decoder::decodeCreateNonFungibleV1); + createMethodsMap.put(CREATE_NON_FUNGIBLE_TOKEN_V2, decoder::decodeCreateNonFungibleV2); + createMethodsMap.put(CREATE_NON_FUNGIBLE_TOKEN_V3, decoder::decodeCreateNonFungibleV3); + createMethodsMap.put(CREATE_NON_FUNGIBLE_TOKEN_WITH_METADATA, decoder::decodeCreateNonFungibleWithMetadata); + createMethodsMap.put( CREATE_NON_FUNGIBLE_TOKEN_WITH_CUSTOM_FEES_V1, decoder::decodeCreateNonFungibleWithCustomFeesV1); - createSelectorsMap.put( + createMethodsMap.put( CREATE_NON_FUNGIBLE_TOKEN_WITH_CUSTOM_FEES_V2, decoder::decodeCreateNonFungibleWithCustomFeesV2); - createSelectorsMap.put( + createMethodsMap.put( CREATE_NON_FUNGIBLE_TOKEN_WITH_CUSTOM_FEES_V3, decoder::decodeCreateNonFungibleWithCustomFeesV3); - createSelectorsMap.put( + createMethodsMap.put( CREATE_NON_FUNGIBLE_TOKEN_WITH_METADATA_AND_CUSTOM_FEES, decoder::decodeCreateNonFungibleWithMetadataAndCustomFees); } @Override - public boolean matches(@NonNull HtsCallAttempt attempt) { + public @NonNull Optional identifyMethod(@NonNull HtsCallAttempt attempt) { + requireNonNull(attempt); final var metaConfigEnabled = attempt.configuration().getConfigData(ContractsConfig.class).metadataKeyAndFieldEnabled(); - final var metaSelectors = Set.of( - CREATE_FUNGIBLE_TOKEN_WITH_METADATA, - CREATE_FUNGIBLE_TOKEN_WITH_METADATA_AND_CUSTOM_FEES, - CREATE_NON_FUNGIBLE_TOKEN_WITH_METADATA, - CREATE_NON_FUNGIBLE_TOKEN_WITH_METADATA_AND_CUSTOM_FEES); - return createSelectorsMap.keySet().stream() - .anyMatch(selector -> metaSelectors.contains(selector) - ? attempt.isSelectorIfConfigEnabled(metaConfigEnabled, selector) - : attempt.isSelector(selector)); + + for (final var method : createMethodsMap.keySet()) { + final var isMetadataMethod = method.hasVariant(Variant.WITH_METADATA); + Optional m = isMetadataMethod + ? metaConfigEnabled ? attempt.isMethod(method) : Optional.empty() + : attempt.isMethod(method); + if (m.isPresent()) return m; + } + return Optional.empty(); } @Override @@ -239,7 +307,7 @@ public ClassicCreatesCall callFrom(@NonNull HtsCallAttempt attempt) { final var nativeOperations = attempt.nativeOperations(); final var addressIdConverter = attempt.addressIdConverter(); - return createSelectorsMap.entrySet().stream() + return createMethodsMap.entrySet().stream() .filter(entry -> attempt.isSelector(entry.getKey())) .map(entry -> entry.getValue().decode(inputBytes, senderId, nativeOperations, addressIdConverter)) .findFirst() diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/customfees/TokenCustomFeesTranslator.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/customfees/TokenCustomFeesTranslator.java index 0b81af6212e9..36e6035f0ca7 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/customfees/TokenCustomFeesTranslator.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/customfees/TokenCustomFeesTranslator.java @@ -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. @@ -17,31 +17,46 @@ package com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.customfees; import static com.hedera.node.app.service.contract.impl.utils.ConversionUtils.fromHeadlongAddress; +import static java.util.Objects.requireNonNull; -import com.esaulpaugh.headlong.abi.Function; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.AbstractCallTranslator; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.Call; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.ReturnTypes; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Category; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Modifier; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Variant; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import edu.umd.cs.findbugs.annotations.NonNull; +import java.util.Optional; import javax.inject.Inject; +import javax.inject.Singleton; +@Singleton public class TokenCustomFeesTranslator extends AbstractCallTranslator { - public static final Function TOKEN_CUSTOM_FEES = - new Function("getTokenCustomFees(address)", ReturnTypes.RESPONSE_CODE_CUSTOM_FEES); + public static final SystemContractMethod TOKEN_CUSTOM_FEES = SystemContractMethod.declare( + "getTokenCustomFees(address)", ReturnTypes.RESPONSE_CODE_CUSTOM_FEES) + .withModifier(Modifier.VIEW) + .withVariant(Variant.WITH_CUSTOM_FEES) + .withCategory(Category.TOKEN_QUERY); @Inject - public TokenCustomFeesTranslator() { + public TokenCustomFeesTranslator( + @NonNull final SystemContractMethodRegistry systemContractMethodRegistry, + @NonNull final ContractMetrics contractMetrics) { // Dagger2 + super(SystemContractMethod.SystemContract.HTS, systemContractMethodRegistry, contractMetrics); + + registerMethods(TOKEN_CUSTOM_FEES); } - /** - * {@inheritDoc} - */ @Override - public boolean matches(@NonNull final HtsCallAttempt attempt) { - return attempt.isSelector(TOKEN_CUSTOM_FEES); + public @NonNull Optional identifyMethod(@NonNull final HtsCallAttempt attempt) { + requireNonNull(attempt); + return attempt.isMethod(TOKEN_CUSTOM_FEES); } /** diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/decimals/DecimalsTranslator.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/decimals/DecimalsTranslator.java index cf8f65fe0a3d..c77007890b46 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/decimals/DecimalsTranslator.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/decimals/DecimalsTranslator.java @@ -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. @@ -16,12 +16,19 @@ package com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.decimals; -import com.esaulpaugh.headlong.abi.Function; +import static java.util.Objects.requireNonNull; + +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.AbstractCallTranslator; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.Call; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.ReturnTypes; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Category; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Modifier; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import edu.umd.cs.findbugs.annotations.NonNull; +import java.util.Optional; import javax.inject.Inject; import javax.inject.Singleton; @@ -31,22 +38,27 @@ @Singleton public class DecimalsTranslator extends AbstractCallTranslator { /** Selector for updateTokenKeys(address, TOKEN_KEY[]) method. */ - public static final Function DECIMALS = new Function("decimals()", ReturnTypes.BYTE); + public static final SystemContractMethod DECIMALS = SystemContractMethod.declare("decimals()", ReturnTypes.BYTE) + .withModifier(Modifier.VIEW) + .withCategory(Category.TOKEN_QUERY); /** * Default constructor for injection. */ @Inject - public DecimalsTranslator() { + public DecimalsTranslator( + @NonNull final SystemContractMethodRegistry systemContractMethodRegistry, + @NonNull final ContractMetrics contractMetrics) { // Dagger2 + super(SystemContractMethod.SystemContract.HTS, systemContractMethodRegistry, contractMetrics); + + registerMethods(DECIMALS); } - /** - * {@inheritDoc} - */ @Override - public boolean matches(@NonNull final HtsCallAttempt attempt) { - return attempt.isSelector(DECIMALS); + public @NonNull Optional identifyMethod(@NonNull final HtsCallAttempt attempt) { + requireNonNull(attempt); + return attempt.isMethod(DECIMALS); } /** diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/defaultfreezestatus/DefaultFreezeStatusTranslator.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/defaultfreezestatus/DefaultFreezeStatusTranslator.java index cc1d75cca579..351bd935bcca 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/defaultfreezestatus/DefaultFreezeStatusTranslator.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/defaultfreezestatus/DefaultFreezeStatusTranslator.java @@ -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. @@ -17,37 +17,50 @@ package com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.defaultfreezestatus; import static com.hedera.node.app.service.contract.impl.utils.ConversionUtils.fromHeadlongAddress; +import static java.util.Objects.requireNonNull; -import com.esaulpaugh.headlong.abi.Function; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.AbstractCallTranslator; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.Call; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.ReturnTypes; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Category; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Modifier; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import edu.umd.cs.findbugs.annotations.NonNull; +import java.util.Optional; import javax.inject.Inject; +import javax.inject.Singleton; /** * Translates {@code getTokenDefaultFreezeStatus()} calls to the HTS system contract. */ +@Singleton public class DefaultFreezeStatusTranslator extends AbstractCallTranslator { /** Selector for getTokenDefaultFreezeStatus(address) method. */ - public static final Function DEFAULT_FREEZE_STATUS = - new Function("getTokenDefaultFreezeStatus(address)", ReturnTypes.RESPONSE_CODE_BOOL); + public static final SystemContractMethod DEFAULT_FREEZE_STATUS = SystemContractMethod.declare( + "getTokenDefaultFreezeStatus(address)", ReturnTypes.RESPONSE_CODE_BOOL) + .withModifier(Modifier.VIEW) + .withCategory(Category.TOKEN_QUERY); /** * Default constructor for injection. */ @Inject - public DefaultFreezeStatusTranslator() { + public DefaultFreezeStatusTranslator( + @NonNull final SystemContractMethodRegistry systemContractMethodRegistry, + @NonNull final ContractMetrics contractMetrics) { // Dagger2 + super(SystemContractMethod.SystemContract.HTS, systemContractMethodRegistry, contractMetrics); + + registerMethods(DEFAULT_FREEZE_STATUS); } - /** - * {@inheritDoc} - */ @Override - public boolean matches(@NonNull final HtsCallAttempt attempt) { - return attempt.isSelector(DEFAULT_FREEZE_STATUS); + public @NonNull Optional identifyMethod(@NonNull final HtsCallAttempt attempt) { + requireNonNull(attempt); + return attempt.isMethod(DEFAULT_FREEZE_STATUS); } /** diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/defaultkycstatus/DefaultKycStatusTranslator.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/defaultkycstatus/DefaultKycStatusTranslator.java index 58a51c41a9af..9b9d06eeca7b 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/defaultkycstatus/DefaultKycStatusTranslator.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/defaultkycstatus/DefaultKycStatusTranslator.java @@ -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. @@ -17,37 +17,50 @@ package com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.defaultkycstatus; import static com.hedera.node.app.service.contract.impl.utils.ConversionUtils.fromHeadlongAddress; +import static java.util.Objects.requireNonNull; -import com.esaulpaugh.headlong.abi.Function; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.AbstractCallTranslator; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.Call; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.ReturnTypes; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Category; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Modifier; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import edu.umd.cs.findbugs.annotations.NonNull; +import java.util.Optional; import javax.inject.Inject; +import javax.inject.Singleton; /** * Translates {@code getTokenDefaultKycStatus()} calls to the HTS system contract. */ +@Singleton public class DefaultKycStatusTranslator extends AbstractCallTranslator { /** Selector for getTokenDefaultKycStatus(address) method. */ - public static final Function DEFAULT_KYC_STATUS = - new Function("getTokenDefaultKycStatus(address)", ReturnTypes.RESPONSE_CODE_BOOL); + public static final SystemContractMethod DEFAULT_KYC_STATUS = SystemContractMethod.declare( + "getTokenDefaultKycStatus(address)", ReturnTypes.RESPONSE_CODE_BOOL) + .withModifier(Modifier.VIEW) + .withCategory(Category.TOKEN_QUERY); /** * Default constructor for injection. */ @Inject - public DefaultKycStatusTranslator() { + public DefaultKycStatusTranslator( + @NonNull final SystemContractMethodRegistry systemContractMethodRegistry, + @NonNull final ContractMetrics contractMetrics) { // Dagger2 + super(SystemContractMethod.SystemContract.HTS, systemContractMethodRegistry, contractMetrics); + + registerMethods(DEFAULT_KYC_STATUS); } - /** - * {@inheritDoc} - */ @Override - public boolean matches(@NonNull final HtsCallAttempt attempt) { - return attempt.isSelector(DEFAULT_KYC_STATUS); + public @NonNull Optional identifyMethod(@NonNull final HtsCallAttempt attempt) { + requireNonNull(attempt); + return attempt.isMethod(DEFAULT_KYC_STATUS); } /** diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/delete/DeleteTranslator.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/delete/DeleteTranslator.java index cd764819e3a3..95fe8746fa80 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/delete/DeleteTranslator.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/delete/DeleteTranslator.java @@ -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. @@ -16,40 +16,56 @@ package com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.delete; -import com.esaulpaugh.headlong.abi.Function; +import static java.util.Objects.requireNonNull; + import com.hedera.hapi.node.base.AccountID; import com.hedera.hapi.node.token.TokenDeleteTransactionBody; import com.hedera.hapi.node.transaction.TransactionBody; import com.hedera.node.app.service.contract.impl.exec.gas.DispatchType; import com.hedera.node.app.service.contract.impl.exec.gas.SystemContractGasCalculator; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.AbstractCallTranslator; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.Call; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.DispatchForResponseCodeHtsCall; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.ReturnTypes; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Category; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.hevm.HederaWorldUpdater; import com.hedera.node.app.service.contract.impl.utils.ConversionUtils; import edu.umd.cs.findbugs.annotations.NonNull; +import java.util.Optional; import javax.inject.Inject; +import javax.inject.Singleton; /** * Translates {@code delete} calls to the HTS system contract. */ +@Singleton public class DeleteTranslator extends AbstractCallTranslator { /** Selector for deleteToken(address) method. */ - public static final Function DELETE_TOKEN = new Function("deleteToken(address)", ReturnTypes.INT); + public static final SystemContractMethod DELETE_TOKEN = SystemContractMethod.declare( + "deleteToken(address)", ReturnTypes.INT) + .withCategories(Category.CREATE_DELETE_TOKEN); /** * Default constructor to delete. */ @Inject - public DeleteTranslator() { + public DeleteTranslator( + @NonNull final SystemContractMethodRegistry systemContractMethodRegistry, + @NonNull final ContractMetrics contractMetrics) { // Dagger2 + super(SystemContractMethod.SystemContract.HTS, systemContractMethodRegistry, contractMetrics); + + registerMethods(DELETE_TOKEN); } @Override - public boolean matches(@NonNull HtsCallAttempt attempt) { - return attempt.isSelector(DELETE_TOKEN); + public @NonNull Optional identifyMethod(@NonNull final HtsCallAttempt attempt) { + requireNonNull(attempt); + return attempt.isMethod(DELETE_TOKEN); } @Override diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/freeze/FreezeUnfreezeTranslator.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/freeze/FreezeUnfreezeTranslator.java index de0989201d0e..f40cee667e46 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/freeze/FreezeUnfreezeTranslator.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/freeze/FreezeUnfreezeTranslator.java @@ -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. @@ -17,20 +17,25 @@ package com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.freeze; import static com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.DispatchForResponseCodeHtsCall.FailureCustomizer.NOOP_CUSTOMIZER; +import static java.util.Objects.requireNonNull; -import com.esaulpaugh.headlong.abi.Function; import com.hedera.hapi.node.base.AccountID; import com.hedera.hapi.node.transaction.TransactionBody; import com.hedera.node.app.service.contract.impl.exec.gas.DispatchType; import com.hedera.node.app.service.contract.impl.exec.gas.SystemContractGasCalculator; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.AbstractCallTranslator; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.Call; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.DispatchForResponseCodeHtsCall; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.ReturnTypes; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Category; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.hevm.HederaWorldUpdater; import edu.umd.cs.findbugs.annotations.NonNull; import java.util.Arrays; +import java.util.Optional; import javax.inject.Inject; import javax.inject.Singleton; @@ -40,9 +45,13 @@ @Singleton public class FreezeUnfreezeTranslator extends AbstractCallTranslator { /** Selector for freezeToken(address,address) method. */ - public static final Function FREEZE = new Function("freezeToken(address,address)", ReturnTypes.INT_64); + public static final SystemContractMethod FREEZE = SystemContractMethod.declare( + "freezeToken(address,address)", ReturnTypes.INT_64) + .withCategories(Category.FREEZE_UNFREEZE); /** Selector for unfreezeToken(address,address) method. */ - public static final Function UNFREEZE = new Function("unfreezeToken(address,address)", ReturnTypes.INT_64); + public static final SystemContractMethod UNFREEZE = SystemContractMethod.declare( + "unfreezeToken(address,address)", ReturnTypes.INT_64) + .withCategories(Category.FREEZE_UNFREEZE); private final FreezeUnfreezeDecoder decoder; @@ -50,16 +59,20 @@ public class FreezeUnfreezeTranslator extends AbstractCallTranslator identifyMethod(@NonNull final HtsCallAttempt attempt) { + requireNonNull(attempt); + return attempt.isMethod(FREEZE, UNFREEZE); } /** diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/fungibletokeninfo/FungibleTokenInfoCall.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/fungibletokeninfo/FungibleTokenInfoCall.java index 69fa08c2b07c..e1241856e36f 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/fungibletokeninfo/FungibleTokenInfoCall.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/fungibletokeninfo/FungibleTokenInfoCall.java @@ -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. @@ -84,7 +84,7 @@ public FungibleTokenInfoCall( return revertResult(status, gasRequirement); } - return function.getName().equals(FUNGIBLE_TOKEN_INFO.getName()) + return function.getName().equals(FUNGIBLE_TOKEN_INFO.methodName()) ? successResult( FUNGIBLE_TOKEN_INFO .getOutputs() diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/fungibletokeninfo/FungibleTokenInfoTranslator.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/fungibletokeninfo/FungibleTokenInfoTranslator.java index 6ace95c8ab34..7ab268f18256 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/fungibletokeninfo/FungibleTokenInfoTranslator.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/fungibletokeninfo/FungibleTokenInfoTranslator.java @@ -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. @@ -19,43 +19,60 @@ import static com.hedera.node.app.service.contract.impl.utils.ConversionUtils.fromHeadlongAddress; import static java.util.Objects.requireNonNull; -import com.esaulpaugh.headlong.abi.Function; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.AbstractCallTranslator; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.Call; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.ReturnTypes; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Category; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Variant; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.config.data.ContractsConfig; import edu.umd.cs.findbugs.annotations.NonNull; +import java.util.Optional; import javax.inject.Inject; +import javax.inject.Singleton; +@Singleton public class FungibleTokenInfoTranslator extends AbstractCallTranslator { /** Selector for getFungibleTokenInfo(address) method. */ - public static final Function FUNGIBLE_TOKEN_INFO = - new Function("getFungibleTokenInfo(address)", ReturnTypes.RESPONSE_CODE_FUNGIBLE_TOKEN_INFO); + public static final SystemContractMethod FUNGIBLE_TOKEN_INFO = SystemContractMethod.declare( + "getFungibleTokenInfo(address)", ReturnTypes.RESPONSE_CODE_FUNGIBLE_TOKEN_INFO) + .withVariants(Variant.V1, Variant.FT) + .withCategory(Category.TOKEN_QUERY); /** Selector for getFungibleTokenInfoV2(address) method. */ - public static final Function FUNGIBLE_TOKEN_INFO_V2 = - new Function("getFungibleTokenInfoV2(address)", ReturnTypes.RESPONSE_CODE_FUNGIBLE_TOKEN_INFO_V2); + public static final SystemContractMethod FUNGIBLE_TOKEN_INFO_V2 = SystemContractMethod.declare( + "getFungibleTokenInfoV2(address)", ReturnTypes.RESPONSE_CODE_FUNGIBLE_TOKEN_INFO_V2) + .withVariants(Variant.V2, Variant.FT) + .withCategory(Category.TOKEN_QUERY); /** * Default constructor for injection. */ @Inject - public FungibleTokenInfoTranslator() { + public FungibleTokenInfoTranslator( + @NonNull final SystemContractMethodRegistry systemContractMethodRegistry, + @NonNull final ContractMetrics contractMetrics) { // Dagger2 + super(SystemContractMethod.SystemContract.HTS, systemContractMethodRegistry, contractMetrics); + + registerMethods(FUNGIBLE_TOKEN_INFO, FUNGIBLE_TOKEN_INFO_V2); } - /** - * {@inheritDoc} - */ @Override - public boolean matches(@NonNull final HtsCallAttempt attempt) { + public @NonNull Optional identifyMethod(@NonNull final HtsCallAttempt attempt) { requireNonNull(attempt); + final var v2Enabled = attempt.configuration().getConfigData(ContractsConfig.class).systemContractTokenInfoV2Enabled(); - return attempt.isSelector(FUNGIBLE_TOKEN_INFO) - || attempt.isSelectorIfConfigEnabled(v2Enabled, FUNGIBLE_TOKEN_INFO_V2); + + if (attempt.isMethod(FUNGIBLE_TOKEN_INFO).isPresent()) return Optional.of(FUNGIBLE_TOKEN_INFO); + if (attempt.isSelectorIfConfigEnabled(v2Enabled, FUNGIBLE_TOKEN_INFO_V2)) + return Optional.of(FUNGIBLE_TOKEN_INFO_V2); + return Optional.empty(); } /** @@ -64,8 +81,8 @@ public boolean matches(@NonNull final HtsCallAttempt attempt) { @Override public Call callFrom(@NonNull final HtsCallAttempt attempt) { requireNonNull(attempt); - final var function = attempt.isSelector(FUNGIBLE_TOKEN_INFO) ? FUNGIBLE_TOKEN_INFO : FUNGIBLE_TOKEN_INFO_V2; - final var args = function.decodeCall(attempt.input().toArrayUnsafe()); + final var method = attempt.isSelector(FUNGIBLE_TOKEN_INFO) ? FUNGIBLE_TOKEN_INFO : FUNGIBLE_TOKEN_INFO_V2; + final var args = method.decodeCall(attempt.input().toArrayUnsafe()); final var token = attempt.linkedToken(fromHeadlongAddress(args.get(0))); return new FungibleTokenInfoCall( attempt.systemContractGasCalculator(), @@ -73,6 +90,6 @@ public Call callFrom(@NonNull final HtsCallAttempt attempt) { attempt.isStaticCall(), token, attempt.configuration(), - function); + method.function()); } } diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/getapproved/GetApprovedTranslator.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/getapproved/GetApprovedTranslator.java index 0b6bb0eee6cf..09a28962cd5c 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/getapproved/GetApprovedTranslator.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/getapproved/GetApprovedTranslator.java @@ -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. @@ -18,12 +18,19 @@ import static com.hedera.node.app.service.contract.impl.utils.ConversionUtils.asExactLongValueOrZero; import static com.hedera.node.app.service.contract.impl.utils.ConversionUtils.fromHeadlongAddress; +import static java.util.Objects.requireNonNull; -import com.esaulpaugh.headlong.abi.Function; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.AbstractCallTranslator; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.ReturnTypes; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.CallVia; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Category; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Modifier; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import edu.umd.cs.findbugs.annotations.NonNull; +import java.util.Optional; import javax.inject.Inject; import javax.inject.Singleton; @@ -34,24 +41,35 @@ public class GetApprovedTranslator extends AbstractCallTranslator { /** Selector for getApproved(address,uint256) method. */ - public static final Function HAPI_GET_APPROVED = new Function("getApproved(address,uint256)", "(int32,address)"); + public static final SystemContractMethod HAPI_GET_APPROVED = SystemContractMethod.declare( + "getApproved(address,uint256)", "(int32,address)") + .withModifier(Modifier.VIEW) + .withCategories(Category.TOKEN_QUERY, Category.APPROVAL); /** Selector for getApproved(uint256) method. */ - public static final Function ERC_GET_APPROVED = new Function("getApproved(uint256)", ReturnTypes.ADDRESS); + public static final SystemContractMethod ERC_GET_APPROVED = SystemContractMethod.declare( + "getApproved(uint256)", ReturnTypes.ADDRESS) + .withVia(CallVia.PROXY) + .withModifier(Modifier.VIEW) + .withCategories(Category.ERC721, Category.TOKEN_QUERY, Category.APPROVAL); /** * Default constructor for injection. */ @Inject - public GetApprovedTranslator() { + public GetApprovedTranslator( + @NonNull final SystemContractMethodRegistry systemContractMethodRegistry, + @NonNull final ContractMetrics contractMetrics) { // Dagger2 + super(SystemContractMethod.SystemContract.HTS, systemContractMethodRegistry, contractMetrics); + + registerMethods(HAPI_GET_APPROVED, ERC_GET_APPROVED); } - /** - * {@inheritDoc} - */ @Override - public boolean matches(@NonNull final HtsCallAttempt attempt) { - return attempt.isTokenRedirect() ? attempt.isSelector(ERC_GET_APPROVED) : attempt.isSelector(HAPI_GET_APPROVED); + public @NonNull Optional identifyMethod(@NonNull final HtsCallAttempt attempt) { + requireNonNull(attempt); + + return attempt.isTokenRedirect() ? attempt.isMethod(ERC_GET_APPROVED) : attempt.isMethod(HAPI_GET_APPROVED); } /** diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/grantapproval/GrantApprovalTranslator.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/grantapproval/GrantApprovalTranslator.java index 8892d642a519..c76637342149 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/grantapproval/GrantApprovalTranslator.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/grantapproval/GrantApprovalTranslator.java @@ -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. @@ -19,21 +19,27 @@ import static java.util.Objects.requireNonNull; import com.esaulpaugh.headlong.abi.Address; -import com.esaulpaugh.headlong.abi.Function; import com.hedera.hapi.node.base.AccountID; import com.hedera.hapi.node.base.TokenType; import com.hedera.hapi.node.transaction.TransactionBody; import com.hedera.node.app.service.contract.impl.exec.gas.DispatchType; import com.hedera.node.app.service.contract.impl.exec.gas.SystemContractGasCalculator; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.AbstractCallTranslator; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.Call; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.DispatchForResponseCodeHtsCall; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.ReturnTypes; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.CallVia; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Category; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Variant; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.hevm.HederaWorldUpdater; 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 javax.inject.Singleton; @@ -44,14 +50,27 @@ public class GrantApprovalTranslator extends AbstractCallTranslator { /** Selector for approve(address,uint256) method. */ - public static final Function ERC_GRANT_APPROVAL = new Function("approve(address,uint256)", ReturnTypes.BOOL); + public static final SystemContractMethod ERC_GRANT_APPROVAL = SystemContractMethod.declare( + "approve(address,uint256)", ReturnTypes.BOOL) + .withVia(CallVia.PROXY) + .withVariant(Variant.FT) + .withCategories(Category.ERC20, Category.APPROVAL); /** Selector for approve(address,uint256) method. */ - public static final Function ERC_GRANT_APPROVAL_NFT = new Function("approve(address,uint256)"); + public static final SystemContractMethod ERC_GRANT_APPROVAL_NFT = SystemContractMethod.declare( + "approve(address,uint256)") + .withVia(CallVia.PROXY) + .withVariant(Variant.NFT) + .withCategories(Category.ERC721, Category.APPROVAL); /** Selector for approve(address,address,uint256) method. */ - public static final Function GRANT_APPROVAL = new Function("approve(address,address,uint256)", "(int32,bool)"); + public static final SystemContractMethod GRANT_APPROVAL = SystemContractMethod.declare( + "approve(address,address,uint256)", "(int32,bool)") + .withVariant(Variant.FT) + .withCategories(Category.ERC721, Category.APPROVAL); /** Selector for approveNFT(address,address,uint256) method. */ - public static final Function GRANT_APPROVAL_NFT = - new Function("approveNFT(address,address,uint256)", ReturnTypes.INT_64); + public static final SystemContractMethod GRANT_APPROVAL_NFT = SystemContractMethod.declare( + "approveNFT(address,address,uint256)", ReturnTypes.INT_64) + .withVariant(Variant.NFT) + .withCategories(Category.APPROVAL); private final GrantApprovalDecoder decoder; @@ -60,16 +79,20 @@ public class GrantApprovalTranslator extends AbstractCallTranslator identifyMethod(@NonNull final HtsCallAttempt attempt) { + requireNonNull(attempt); + return attempt.isMethod(GRANT_APPROVAL, GRANT_APPROVAL_NFT, ERC_GRANT_APPROVAL); } /** diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/grantrevokekyc/GrantRevokeKycTranslator.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/grantrevokekyc/GrantRevokeKycTranslator.java index 14db3f20a93e..487969d9f963 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/grantrevokekyc/GrantRevokeKycTranslator.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/grantrevokekyc/GrantRevokeKycTranslator.java @@ -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. @@ -17,17 +17,22 @@ package com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.grantrevokekyc; import static com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.DispatchForResponseCodeHtsCall.FailureCustomizer.NOOP_CUSTOMIZER; +import static java.util.Objects.requireNonNull; -import com.esaulpaugh.headlong.abi.Function; import com.hedera.hapi.node.base.AccountID; import com.hedera.hapi.node.transaction.TransactionBody; import com.hedera.node.app.service.contract.impl.exec.gas.DispatchType; import com.hedera.node.app.service.contract.impl.exec.gas.SystemContractGasCalculator; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.AbstractCallTranslator; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.Call; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.*; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Category; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.hevm.HederaWorldUpdater; import edu.umd.cs.findbugs.annotations.NonNull; +import java.util.Optional; import javax.inject.Inject; import javax.inject.Singleton; @@ -40,11 +45,15 @@ public class GrantRevokeKycTranslator extends AbstractCallTranslator identifyMethod(@NonNull HtsCallAttempt attempt) { + requireNonNull(attempt); + return attempt.isMethod(GRANT_KYC, REVOKE_KYC); } /** diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/isapprovedforall/IsApprovedForAllTranslator.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/isapprovedforall/IsApprovedForAllTranslator.java index 67d087ad4b90..7c219aa82893 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/isapprovedforall/IsApprovedForAllTranslator.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/isapprovedforall/IsApprovedForAllTranslator.java @@ -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. @@ -17,11 +17,17 @@ package com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.isapprovedforall; import static com.hedera.node.app.service.contract.impl.utils.ConversionUtils.fromHeadlongAddress; +import static java.util.Objects.requireNonNull; -import com.esaulpaugh.headlong.abi.Function; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.AbstractCallTranslator; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallAttempt; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.CallVia; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Category; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import edu.umd.cs.findbugs.annotations.NonNull; +import java.util.Optional; import javax.inject.Inject; import javax.inject.Singleton; @@ -31,25 +37,32 @@ @Singleton public class IsApprovedForAllTranslator extends AbstractCallTranslator { /** Selector for isApprovedForAll(address,address,address) method. */ - public static final Function CLASSIC_IS_APPROVED_FOR_ALL = - new Function("isApprovedForAll(address,address,address)", "(int64,bool)"); + public static final SystemContractMethod CLASSIC_IS_APPROVED_FOR_ALL = SystemContractMethod.declare( + "isApprovedForAll(address,address,address)", "(int64,bool)") + .withCategories(Category.TOKEN_QUERY, Category.APPROVAL); /** Selector for isApprovedForAll(address,address) method. */ - public static final Function ERC_IS_APPROVED_FOR_ALL = new Function("isApprovedForAll(address,address)", "(bool)"); + public static final SystemContractMethod ERC_IS_APPROVED_FOR_ALL = SystemContractMethod.declare( + "isApprovedForAll(address,address)", "(bool)") + .withVia(CallVia.PROXY) + .withCategories(Category.TOKEN_QUERY, Category.APPROVAL); /** * Default constructor for injection. */ @Inject - public IsApprovedForAllTranslator() { + public IsApprovedForAllTranslator( + @NonNull final SystemContractMethodRegistry systemContractMethodRegistry, + @NonNull final ContractMetrics contractMetrics) { // Dagger2 + super(SystemContractMethod.SystemContract.HTS, systemContractMethodRegistry, contractMetrics); + + registerMethods(CLASSIC_IS_APPROVED_FOR_ALL, ERC_IS_APPROVED_FOR_ALL); } - /** - * {@inheritDoc} - */ @Override - public boolean matches(@NonNull final HtsCallAttempt attempt) { - return attempt.isSelector(CLASSIC_IS_APPROVED_FOR_ALL, ERC_IS_APPROVED_FOR_ALL); + public @NonNull Optional identifyMethod(@NonNull final HtsCallAttempt attempt) { + requireNonNull(attempt); + return attempt.isMethod(CLASSIC_IS_APPROVED_FOR_ALL, ERC_IS_APPROVED_FOR_ALL); } /** diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/isassociated/IsAssociatedTranslator.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/isassociated/IsAssociatedTranslator.java index 01b61a4449a9..be7bd160063f 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/isassociated/IsAssociatedTranslator.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/isassociated/IsAssociatedTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2024 Hedera Hashgraph, LLC + * Copyright (C) 2024-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. @@ -18,31 +18,46 @@ import static java.util.Objects.requireNonNull; -import com.esaulpaugh.headlong.abi.Function; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.AbstractCallTranslator; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.Call; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.ReturnTypes; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Category; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Modifier; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import edu.umd.cs.findbugs.annotations.NonNull; +import java.util.Optional; import javax.inject.Inject; import javax.inject.Singleton; @Singleton public class IsAssociatedTranslator extends AbstractCallTranslator { /** Selector for isAssociated() method. */ - public static final Function IS_ASSOCIATED = new Function("isAssociated()", ReturnTypes.BOOL); + public static final SystemContractMethod IS_ASSOCIATED = SystemContractMethod.declare( + "isAssociated()", ReturnTypes.BOOL) + .withModifier(Modifier.VIEW) + .withCategories(Category.TOKEN_QUERY, Category.ASSOCIATION); /** * Default constructor for injection. */ @Inject - public IsAssociatedTranslator() { + public IsAssociatedTranslator( + @NonNull final SystemContractMethodRegistry systemContractMethodRegistry, + @NonNull final ContractMetrics contractMetrics) { // Dagger2 + super(SystemContractMethod.SystemContract.HTS, systemContractMethodRegistry, contractMetrics); + + registerMethods(IS_ASSOCIATED); } @Override - public final boolean matches(@NonNull final HtsCallAttempt attempt) { - return attempt.isTokenRedirect() && attempt.isSelector(IS_ASSOCIATED); + public @NonNull Optional identifyMethod(@NonNull final HtsCallAttempt attempt) { + requireNonNull(attempt); + if (!attempt.isTokenRedirect()) return Optional.empty(); + return attempt.isMethod(IS_ASSOCIATED); } @Override diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/isfrozen/IsFrozenTranslator.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/isfrozen/IsFrozenTranslator.java index e6e887e20435..1e5f7d84c3e9 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/isfrozen/IsFrozenTranslator.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/isfrozen/IsFrozenTranslator.java @@ -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. @@ -17,33 +17,47 @@ package com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.isfrozen; import static com.hedera.node.app.service.contract.impl.utils.ConversionUtils.fromHeadlongAddress; +import static java.util.Objects.requireNonNull; -import com.esaulpaugh.headlong.abi.Function; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.AbstractCallTranslator; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.Call; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.ReturnTypes; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Category; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Modifier; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import edu.umd.cs.findbugs.annotations.NonNull; +import java.util.Optional; import javax.inject.Inject; +import javax.inject.Singleton; +@Singleton public class IsFrozenTranslator extends AbstractCallTranslator { /** Selector for isFrozen(address,address) method. */ - public static final Function IS_FROZEN = new Function("isFrozen(address,address)", ReturnTypes.RESPONSE_CODE_BOOL); + public static final SystemContractMethod IS_FROZEN = SystemContractMethod.declare( + "isFrozen(address,address)", ReturnTypes.RESPONSE_CODE_BOOL) + .withModifier(Modifier.VIEW) + .withCategories(Category.TOKEN_QUERY, Category.FREEZE_UNFREEZE); /** * Default constructor for injection. */ @Inject - public IsFrozenTranslator() { + public IsFrozenTranslator( + @NonNull final SystemContractMethodRegistry systemContractMethodRegistry, + @NonNull final ContractMetrics contractMetrics) { // Dagger2 + super(SystemContractMethod.SystemContract.HTS, systemContractMethodRegistry, contractMetrics); + + registerMethods(IS_FROZEN); } - /** - * {@inheritDoc} - */ @Override - public boolean matches(@NonNull final HtsCallAttempt attempt) { - return attempt.isSelector(IS_FROZEN); + public @NonNull Optional identifyMethod(@NonNull final HtsCallAttempt attempt) { + requireNonNull(attempt); + return attempt.isMethod(IS_FROZEN); } /** diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/iskyc/IsKycTranslator.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/iskyc/IsKycTranslator.java index 565dd9ede328..433578eab567 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/iskyc/IsKycTranslator.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/iskyc/IsKycTranslator.java @@ -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. @@ -17,33 +17,47 @@ package com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.iskyc; import static com.hedera.node.app.service.contract.impl.utils.ConversionUtils.fromHeadlongAddress; +import static java.util.Objects.requireNonNull; -import com.esaulpaugh.headlong.abi.Function; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.AbstractCallTranslator; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.Call; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.ReturnTypes; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Category; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Modifier; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import edu.umd.cs.findbugs.annotations.NonNull; +import java.util.Optional; import javax.inject.Inject; +import javax.inject.Singleton; +@Singleton public class IsKycTranslator extends AbstractCallTranslator { /** Selector for isKyc(address,address) method. */ - public static final Function IS_KYC = new Function("isKyc(address,address)", ReturnTypes.RESPONSE_CODE_BOOL); + public static final SystemContractMethod IS_KYC = SystemContractMethod.declare( + "isKyc(address,address)", ReturnTypes.RESPONSE_CODE_BOOL) + .withModifier(Modifier.VIEW) + .withCategories(Category.TOKEN_QUERY, Category.KYC); /** * Default constructor for injection. */ @Inject - public IsKycTranslator() { + public IsKycTranslator( + @NonNull final SystemContractMethodRegistry systemContractMethodRegistry, + @NonNull final ContractMetrics contractMetrics) { // Dagger2 + super(SystemContractMethod.SystemContract.HTS, systemContractMethodRegistry, contractMetrics); + + registerMethods(IS_KYC); } - /** - * {@inheritDoc} - */ @Override - public boolean matches(@NonNull final HtsCallAttempt attempt) { - return attempt.isSelector(IS_KYC); + public @NonNull Optional identifyMethod(@NonNull final HtsCallAttempt attempt) { + requireNonNull(attempt); + return attempt.isMethod(IS_KYC); } /** diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/istoken/IsTokenTranslator.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/istoken/IsTokenTranslator.java index e91401ee4e48..c8d45557498e 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/istoken/IsTokenTranslator.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/istoken/IsTokenTranslator.java @@ -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. @@ -17,33 +17,47 @@ package com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.istoken; import static com.hedera.node.app.service.contract.impl.utils.ConversionUtils.fromHeadlongAddress; +import static java.util.Objects.requireNonNull; -import com.esaulpaugh.headlong.abi.Function; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.AbstractCallTranslator; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.Call; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.ReturnTypes; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Category; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Modifier; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import edu.umd.cs.findbugs.annotations.NonNull; +import java.util.Optional; import javax.inject.Inject; +import javax.inject.Singleton; +@Singleton public class IsTokenTranslator extends AbstractCallTranslator { /** Selector for isToken(address) method. */ - public static final Function IS_TOKEN = new Function("isToken(address)", ReturnTypes.RESPONSE_CODE_BOOL); + public static final SystemContractMethod IS_TOKEN = SystemContractMethod.declare( + "isToken(address)", ReturnTypes.RESPONSE_CODE_BOOL) + .withModifier(Modifier.VIEW) + .withCategory(Category.TOKEN_QUERY); /** * Default constructor for injection. */ @Inject - public IsTokenTranslator() { + public IsTokenTranslator( + @NonNull final SystemContractMethodRegistry systemContractMethodRegistry, + @NonNull final ContractMetrics contractMetrics) { // Dagger2 + super(SystemContractMethod.SystemContract.HTS, systemContractMethodRegistry, contractMetrics); + + registerMethods(IS_TOKEN); } - /** - * {@inheritDoc} - */ @Override - public boolean matches(@NonNull final HtsCallAttempt attempt) { - return attempt.isSelector(IS_TOKEN); + public @NonNull Optional identifyMethod(@NonNull final HtsCallAttempt attempt) { + requireNonNull(attempt); + return attempt.isMethod(IS_TOKEN); } /** diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/mint/MintTranslator.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/mint/MintTranslator.java index 64a127958b57..7ddf92e24bcc 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/mint/MintTranslator.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/mint/MintTranslator.java @@ -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. @@ -17,18 +17,24 @@ package com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.mint; import static com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.mint.MintDecoder.MINT_OUTPUT_FN; +import static java.util.Objects.requireNonNull; -import com.esaulpaugh.headlong.abi.Function; import com.hedera.hapi.node.base.AccountID; import com.hedera.hapi.node.transaction.TransactionBody; import com.hedera.node.app.service.contract.impl.exec.gas.DispatchType; import com.hedera.node.app.service.contract.impl.exec.gas.SystemContractGasCalculator; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.AbstractCallTranslator; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.Call; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.DispatchForResponseCodeHtsCall; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallAttempt; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Category; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Variant; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.hevm.HederaWorldUpdater; import edu.umd.cs.findbugs.annotations.NonNull; +import java.util.Optional; import javax.inject.Inject; import javax.inject.Singleton; @@ -38,9 +44,15 @@ @Singleton public class MintTranslator extends AbstractCallTranslator { /** Selector for mintToken(address,uint64,bytes[]) method. */ - public static final Function MINT = new Function("mintToken(address,uint64,bytes[])", "(int64,int64,int64[])"); + public static final SystemContractMethod MINT = SystemContractMethod.declare( + "mintToken(address,uint64,bytes[])", "(int64,int64,int64[])") + .withVariant(Variant.V1) + .withCategories(Category.MINT_BURN); /** Selector for mintToken(address,int64,bytes[]) method. */ - public static final Function MINT_V2 = new Function("mintToken(address,int64,bytes[])", "(int64,int64,int64[])"); + public static final SystemContractMethod MINT_V2 = SystemContractMethod.declare( + "mintToken(address,int64,bytes[])", "(int64,int64,int64[])") + .withVariant(Variant.V2) + .withCategories(Category.MINT_BURN); private final MintDecoder decoder; @@ -48,16 +60,20 @@ public class MintTranslator extends AbstractCallTranslator { * @param decoder the decoder to use for mint calls */ @Inject - public MintTranslator(@NonNull final MintDecoder decoder) { + public MintTranslator( + @NonNull final MintDecoder decoder, + @NonNull final SystemContractMethodRegistry systemContractMethodRegistry, + @NonNull final ContractMetrics contractMetrics) { + super(SystemContractMethod.SystemContract.HTS, systemContractMethodRegistry, contractMetrics); this.decoder = decoder; + + registerMethods(MINT, MINT_V2); } - /** - * {@inheritDoc} - */ @Override - public boolean matches(@NonNull final HtsCallAttempt attempt) { - return attempt.isSelector(MINT, MINT_V2); + public @NonNull Optional identifyMethod(@NonNull final HtsCallAttempt attempt) { + requireNonNull(attempt); + return attempt.isMethod(MINT, MINT_V2); } @Override diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/name/NameTranslator.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/name/NameTranslator.java index fd153112ca0c..b88621e025ab 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/name/NameTranslator.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/name/NameTranslator.java @@ -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. @@ -16,11 +16,18 @@ package com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.name; -import com.esaulpaugh.headlong.abi.Function; +import static java.util.Objects.requireNonNull; + +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.AbstractCallTranslator; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.ReturnTypes; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Category; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Modifier; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import edu.umd.cs.findbugs.annotations.NonNull; +import java.util.Optional; import javax.inject.Inject; import javax.inject.Singleton; @@ -30,22 +37,27 @@ @Singleton public class NameTranslator extends AbstractCallTranslator { /** Selector for name() method. */ - public static final Function NAME = new Function("name()", ReturnTypes.STRING); + public static final SystemContractMethod NAME = SystemContractMethod.declare("name()", ReturnTypes.STRING) + .withModifier(Modifier.VIEW) + .withCategory(Category.TOKEN_QUERY); /** * Default constructor for injection. */ @Inject - public NameTranslator() { + public NameTranslator( + @NonNull final SystemContractMethodRegistry systemContractMethodRegistry, + @NonNull final ContractMetrics contractMetrics) { // Dagger2 + super(SystemContractMethod.SystemContract.HTS, systemContractMethodRegistry, contractMetrics); + + registerMethods(NAME); } - /** - * {@inheritDoc} - */ @Override - public boolean matches(@NonNull final HtsCallAttempt attempt) { - return attempt.isSelector(NAME); + public @NonNull Optional identifyMethod(@NonNull final HtsCallAttempt attempt) { + requireNonNull(attempt); + return attempt.isMethod(NAME); } /** diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/nfttokeninfo/NftTokenInfoCall.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/nfttokeninfo/NftTokenInfoCall.java index e24bdb55c558..ea8769266cf7 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/nfttokeninfo/NftTokenInfoCall.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/nfttokeninfo/NftTokenInfoCall.java @@ -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. @@ -98,7 +98,7 @@ public NftTokenInfoCall( final var ledgerConfig = configuration.getConfigData(LedgerConfig.class); final var ledgerId = Bytes.wrap(ledgerConfig.id().toByteArray()).toString(); - return function.getName().equals(NON_FUNGIBLE_TOKEN_INFO.getName()) + return function.getName().equals(NON_FUNGIBLE_TOKEN_INFO.methodName()) ? successResult( NON_FUNGIBLE_TOKEN_INFO .getOutputs() diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/nfttokeninfo/NftTokenInfoTranslator.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/nfttokeninfo/NftTokenInfoTranslator.java index b6468797c7f3..0d0c8c3a04b3 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/nfttokeninfo/NftTokenInfoTranslator.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/nfttokeninfo/NftTokenInfoTranslator.java @@ -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. @@ -19,43 +19,58 @@ import static com.hedera.node.app.service.contract.impl.utils.ConversionUtils.fromHeadlongAddress; import static java.util.Objects.requireNonNull; -import com.esaulpaugh.headlong.abi.Function; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.AbstractCallTranslator; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.Call; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.ReturnTypes; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Category; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Variant; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.config.data.ContractsConfig; import edu.umd.cs.findbugs.annotations.NonNull; +import java.util.Optional; import javax.inject.Inject; +import javax.inject.Singleton; +@Singleton public class NftTokenInfoTranslator extends AbstractCallTranslator { /** Selector for getNonFungibleTokenInfo(address,int64) method. */ - public static final Function NON_FUNGIBLE_TOKEN_INFO = - new Function("getNonFungibleTokenInfo(address,int64)", ReturnTypes.RESPONSE_CODE_NON_FUNGIBLE_TOKEN_INFO); + public static final SystemContractMethod NON_FUNGIBLE_TOKEN_INFO = SystemContractMethod.declare( + "getNonFungibleTokenInfo(address,int64)", ReturnTypes.RESPONSE_CODE_NON_FUNGIBLE_TOKEN_INFO) + .withVariants(Variant.V1, Variant.NFT) + .withCategory(Category.TOKEN_QUERY); /** Selector for getNonFungibleTokenInfoV2(address,int64) method. */ - public static final Function NON_FUNGIBLE_TOKEN_INFO_V2 = new Function( - "getNonFungibleTokenInfoV2(address,int64)", ReturnTypes.RESPONSE_CODE_NON_FUNGIBLE_TOKEN_INFO_V2); + public static final SystemContractMethod NON_FUNGIBLE_TOKEN_INFO_V2 = SystemContractMethod.declare( + "getNonFungibleTokenInfoV2(address,int64)", ReturnTypes.RESPONSE_CODE_NON_FUNGIBLE_TOKEN_INFO_V2) + .withVariants(Variant.V2, Variant.NFT) + .withCategory(Category.TOKEN_QUERY); /** * Default constructor for injection. */ @Inject - public NftTokenInfoTranslator() { + public NftTokenInfoTranslator( + @NonNull final SystemContractMethodRegistry systemContractMethodRegistry, + @NonNull final ContractMetrics contractMetrics) { // Dagger2 + super(SystemContractMethod.SystemContract.HTS, systemContractMethodRegistry, contractMetrics); + + registerMethods(NON_FUNGIBLE_TOKEN_INFO, NON_FUNGIBLE_TOKEN_INFO_V2); } - /** - * {@inheritDoc} - */ @Override - public boolean matches(@NonNull final HtsCallAttempt attempt) { + public @NonNull Optional identifyMethod(@NonNull final HtsCallAttempt attempt) { requireNonNull(attempt); final var v2Enabled = attempt.configuration().getConfigData(ContractsConfig.class).systemContractTokenInfoV2Enabled(); - return attempt.isSelector(NON_FUNGIBLE_TOKEN_INFO) - || attempt.isSelectorIfConfigEnabled(v2Enabled, NON_FUNGIBLE_TOKEN_INFO_V2); + if (attempt.isMethod(NON_FUNGIBLE_TOKEN_INFO).isPresent()) return Optional.of(NON_FUNGIBLE_TOKEN_INFO); + if (attempt.isSelectorIfConfigEnabled(v2Enabled, NON_FUNGIBLE_TOKEN_INFO_V2)) + return Optional.of(NON_FUNGIBLE_TOKEN_INFO_V2); + return Optional.empty(); } /** @@ -64,9 +79,9 @@ public boolean matches(@NonNull final HtsCallAttempt attempt) { @Override public Call callFrom(@NonNull final HtsCallAttempt attempt) { requireNonNull(attempt); - final var function = + final var method = attempt.isSelector(NON_FUNGIBLE_TOKEN_INFO) ? NON_FUNGIBLE_TOKEN_INFO : NON_FUNGIBLE_TOKEN_INFO_V2; - final var args = function.decodeCall(attempt.input().toArrayUnsafe()); + final var args = method.decodeCall(attempt.input().toArrayUnsafe()); final var token = attempt.linkedToken(fromHeadlongAddress(args.get(0))); return new NftTokenInfoCall( attempt.systemContractGasCalculator(), @@ -75,6 +90,6 @@ public Call callFrom(@NonNull final HtsCallAttempt attempt) { token, args.get(1), attempt.configuration(), - function); + method.function()); } } diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/ownerof/OwnerOfTranslator.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/ownerof/OwnerOfTranslator.java index 77e8cdd12f85..33835e4e3dff 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/ownerof/OwnerOfTranslator.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/ownerof/OwnerOfTranslator.java @@ -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. @@ -17,12 +17,18 @@ package com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.ownerof; import static com.hedera.node.app.service.contract.impl.utils.ConversionUtils.asExactLongValueOrZero; +import static java.util.Objects.requireNonNull; -import com.esaulpaugh.headlong.abi.Function; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.AbstractCallTranslator; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.ReturnTypes; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Category; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Modifier; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import edu.umd.cs.findbugs.annotations.NonNull; +import java.util.Optional; import javax.inject.Inject; import javax.inject.Singleton; @@ -32,22 +38,28 @@ @Singleton public class OwnerOfTranslator extends AbstractCallTranslator { /** Selector for ownerOf(uint256) method. */ - public static final Function OWNER_OF = new Function("ownerOf(uint256)", ReturnTypes.ADDRESS); + public static final SystemContractMethod OWNER_OF = SystemContractMethod.declare( + "ownerOf(uint256)", ReturnTypes.ADDRESS) + .withModifier(Modifier.VIEW) + .withCategory(Category.TOKEN_QUERY); /** * Default constructor for injection. */ @Inject - public OwnerOfTranslator() { + public OwnerOfTranslator( + @NonNull final SystemContractMethodRegistry systemContractMethodRegistry, + @NonNull final ContractMetrics contractMetrics) { // Dagger2 + super(SystemContractMethod.SystemContract.HTS, systemContractMethodRegistry, contractMetrics); + + registerMethods(OWNER_OF); } - /** - * {@inheritDoc} - */ @Override - public boolean matches(@NonNull final HtsCallAttempt attempt) { - return attempt.isSelector(OWNER_OF); + public @NonNull Optional identifyMethod(@NonNull final HtsCallAttempt attempt) { + requireNonNull(attempt); + return attempt.isMethod(OWNER_OF); } /** diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/pauses/PausesTranslator.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/pauses/PausesTranslator.java index 165e4b39a359..27949d4d56b4 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/pauses/PausesTranslator.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/pauses/PausesTranslator.java @@ -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. @@ -16,18 +16,24 @@ package com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.pauses; -import com.esaulpaugh.headlong.abi.Function; +import static java.util.Objects.requireNonNull; + import com.hedera.hapi.node.base.AccountID; import com.hedera.hapi.node.transaction.TransactionBody; import com.hedera.node.app.service.contract.impl.exec.gas.DispatchType; import com.hedera.node.app.service.contract.impl.exec.gas.SystemContractGasCalculator; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.AbstractCallTranslator; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.Call; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.DispatchForResponseCodeHtsCall; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.ReturnTypes; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Category; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.hevm.HederaWorldUpdater; import edu.umd.cs.findbugs.annotations.NonNull; +import java.util.Optional; import javax.inject.Inject; import javax.inject.Singleton; @@ -38,9 +44,13 @@ @Singleton public class PausesTranslator extends AbstractCallTranslator { /** Selector for pauseToken(address) method. */ - public static final Function PAUSE = new Function("pauseToken(address)", ReturnTypes.INT_64); + public static final SystemContractMethod PAUSE = SystemContractMethod.declare( + "pauseToken(address)", ReturnTypes.INT_64) + .withCategories(Category.PAUSE_UNPAUSE); /** Selector for unpauseToken(address) method. */ - public static final Function UNPAUSE = new Function("unpauseToken(address)", ReturnTypes.INT_64); + public static final SystemContractMethod UNPAUSE = SystemContractMethod.declare( + "unpauseToken(address)", ReturnTypes.INT_64) + .withCategories(Category.PAUSE_UNPAUSE); private final PausesDecoder decoder; @@ -48,16 +58,20 @@ public class PausesTranslator extends AbstractCallTranslator { * @param decoder the decoder to use for pause calls */ @Inject - public PausesTranslator(@NonNull final PausesDecoder decoder) { + public PausesTranslator( + @NonNull final PausesDecoder decoder, + @NonNull final SystemContractMethodRegistry systemContractMethodRegistry, + @NonNull final ContractMetrics contractMetrics) { + super(SystemContractMethod.SystemContract.HTS, systemContractMethodRegistry, contractMetrics); this.decoder = decoder; + + registerMethods(PAUSE, UNPAUSE); } - /** - * {@inheritDoc} - */ @Override - public boolean matches(@NonNull final HtsCallAttempt attempt) { - return attempt.isSelector(PAUSE, UNPAUSE); + public @NonNull Optional identifyMethod(@NonNull final HtsCallAttempt attempt) { + requireNonNull(attempt); + return attempt.isMethod(PAUSE, UNPAUSE); } /** diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/rejecttokens/RejectTokensTranslator.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/rejecttokens/RejectTokensTranslator.java index b21bdb77d5b4..1d25be920e30 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/rejecttokens/RejectTokensTranslator.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/rejecttokens/RejectTokensTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2024 Hedera Hashgraph, LLC + * Copyright (C) 2024-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. @@ -22,43 +22,70 @@ import com.hedera.node.app.service.contract.impl.exec.gas.DispatchGasCalculator; import com.hedera.node.app.service.contract.impl.exec.gas.DispatchType; import com.hedera.node.app.service.contract.impl.exec.gas.SystemContractGasCalculator; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.AbstractCallTranslator; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.Call; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.DispatchForResponseCodeHtsCall; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.ReturnTypes; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.CallVia; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Category; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Variant; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.hevm.HederaWorldUpdater; import com.hedera.node.config.data.ContractsConfig; import edu.umd.cs.findbugs.annotations.NonNull; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; +import java.util.Optional; import javax.inject.Inject; +import javax.inject.Singleton; +@Singleton public class RejectTokensTranslator extends AbstractCallTranslator { - public static final Function TOKEN_REJECT = - new Function("rejectTokens(address,address[],(address,int64)[])", ReturnTypes.INT_64); - public static final Function HRC_TOKEN_REJECT_FT = new Function("rejectTokenFT()", ReturnTypes.INT_64); - public static final Function HRC_TOKEN_REJECT_NFT = new Function("rejectTokenNFTs(int64[])", ReturnTypes.INT_64); + public static final SystemContractMethod TOKEN_REJECT = SystemContractMethod.declare( + "rejectTokens(address,address[],(address,int64)[])", ReturnTypes.INT_64) + .withCategories(Category.REJECT); + public static final SystemContractMethod HRC_TOKEN_REJECT_FT = SystemContractMethod.declare( + "rejectTokenFT()", ReturnTypes.INT_64) + .withVia(CallVia.PROXY) + .withVariant(Variant.FT) + .withCategories(Category.REJECT); + public static final SystemContractMethod HRC_TOKEN_REJECT_NFT = SystemContractMethod.declare( + "rejectTokenNFTs(int64[])", ReturnTypes.INT_64) + .withVia(CallVia.PROXY) + .withVariant(Variant.NFT) + .withCategories(Category.REJECT); private final RejectTokensDecoder decoder; private final Map gasCalculators = new HashMap<>(); @Inject - public RejectTokensTranslator(@NonNull final RejectTokensDecoder decoder) { + public RejectTokensTranslator( + @NonNull final RejectTokensDecoder decoder, + @NonNull final SystemContractMethodRegistry systemContractMethodRegistry, + @NonNull final ContractMetrics contractMetrics) { + super(SystemContractMethod.SystemContract.HTS, systemContractMethodRegistry, contractMetrics); this.decoder = decoder; - gasCalculators.put(TOKEN_REJECT, RejectTokensTranslator::gasRequirement); - gasCalculators.put(HRC_TOKEN_REJECT_FT, RejectTokensTranslator::gasRequirementHRCFungible); - gasCalculators.put(HRC_TOKEN_REJECT_NFT, RejectTokensTranslator::gasRequirementHRCNft); + + registerMethods(TOKEN_REJECT, HRC_TOKEN_REJECT_FT, HRC_TOKEN_REJECT_NFT); + + gasCalculators.put(TOKEN_REJECT.function(), RejectTokensTranslator::gasRequirement); + gasCalculators.put(HRC_TOKEN_REJECT_FT.function(), RejectTokensTranslator::gasRequirementHRCFungible); + gasCalculators.put(HRC_TOKEN_REJECT_NFT.function(), RejectTokensTranslator::gasRequirementHRCNft); } @Override - public boolean matches(@NonNull final HtsCallAttempt attempt) { + public @NonNull Optional identifyMethod(@NonNull final HtsCallAttempt attempt) { final var rejectEnabled = attempt.configuration().getConfigData(ContractsConfig.class).systemContractRejectTokensEnabled(); + + if (!rejectEnabled) return Optional.empty(); return attempt.isTokenRedirect() - ? attempt.isSelectorIfConfigEnabled(rejectEnabled, HRC_TOKEN_REJECT_FT, HRC_TOKEN_REJECT_NFT) - : attempt.isSelectorIfConfigEnabled(rejectEnabled, TOKEN_REJECT); + ? attempt.isMethod(HRC_TOKEN_REJECT_FT, HRC_TOKEN_REJECT_NFT) + : attempt.isMethod(TOKEN_REJECT); } @Override diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/setapproval/SetApprovalForAllTranslator.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/setapproval/SetApprovalForAllTranslator.java index 96e3fbb8ff7e..99f4ff4d373f 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/setapproval/SetApprovalForAllTranslator.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/setapproval/SetApprovalForAllTranslator.java @@ -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. @@ -16,32 +16,42 @@ package com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.setapproval; -import com.esaulpaugh.headlong.abi.Function; import com.hedera.hapi.node.base.AccountID; import com.hedera.hapi.node.transaction.TransactionBody; import com.hedera.node.app.service.contract.impl.exec.gas.DispatchType; import com.hedera.node.app.service.contract.impl.exec.gas.SystemContractGasCalculator; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.AbstractCallTranslator; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.Call; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.DispatchForResponseCodeHtsCall; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.ReturnTypes; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.CallVia; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Category; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.hevm.HederaWorldUpdater; import edu.umd.cs.findbugs.annotations.NonNull; +import java.util.Optional; import javax.inject.Inject; +import javax.inject.Singleton; /** * Translates setApprovalForAll (including ERC) call to the HTS system contract. There are no special cases for these * calls, so the returned {@link Call} is simply an instance of {@link DispatchForResponseCodeHtsCall}. */ +@Singleton public class SetApprovalForAllTranslator extends AbstractCallTranslator { /** Selector for setApprovalForAll(address,address,bool) method. */ - public static final Function SET_APPROVAL_FOR_ALL = - new Function("setApprovalForAll(address,address,bool)", ReturnTypes.INT); + public static final SystemContractMethod SET_APPROVAL_FOR_ALL = SystemContractMethod.declare( + "setApprovalForAll(address,address,bool)", ReturnTypes.INT) + .withCategory(Category.APPROVAL); /** Selector for setApprovalForAll(address,bool) method. */ - public static final Function ERC721_SET_APPROVAL_FOR_ALL = - new Function("setApprovalForAll(address,bool)", ReturnTypes.INT); + public static final SystemContractMethod ERC721_SET_APPROVAL_FOR_ALL = SystemContractMethod.declare( + "setApprovalForAll(address,bool)", ReturnTypes.INT) + .withVia(CallVia.PROXY) + .withCategories(Category.ERC721, Category.APPROVAL); private final SetApprovalForAllDecoder decoder; @@ -49,18 +59,21 @@ public class SetApprovalForAllTranslator extends AbstractCallTranslator identifyMethod(@NonNull final HtsCallAttempt attempt) { return attempt.isTokenRedirect() - ? attempt.isSelector(ERC721_SET_APPROVAL_FOR_ALL) - : attempt.isSelector(SET_APPROVAL_FOR_ALL); + ? attempt.isMethod(ERC721_SET_APPROVAL_FOR_ALL) + : attempt.isMethod(SET_APPROVAL_FOR_ALL); } /** diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/symbol/SymbolTranslator.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/symbol/SymbolTranslator.java index 90aacbd24666..1841eda86701 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/symbol/SymbolTranslator.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/symbol/SymbolTranslator.java @@ -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. @@ -16,11 +16,18 @@ package com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.symbol; -import com.esaulpaugh.headlong.abi.Function; +import static java.util.Objects.requireNonNull; + +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.AbstractCallTranslator; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.ReturnTypes; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Category; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Modifier; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import edu.umd.cs.findbugs.annotations.NonNull; +import java.util.Optional; import javax.inject.Inject; import javax.inject.Singleton; @@ -30,22 +37,27 @@ @Singleton public class SymbolTranslator extends AbstractCallTranslator { /** Selector for symbol() method. */ - public static final Function SYMBOL = new Function("symbol()", ReturnTypes.STRING); + public static final SystemContractMethod SYMBOL = SystemContractMethod.declare("symbol()", ReturnTypes.STRING) + .withModifier(Modifier.VIEW) + .withCategories(Category.ERC20, Category.ERC721, Category.TOKEN_QUERY); /** * Default constructor for injection. */ @Inject - public SymbolTranslator() { + public SymbolTranslator( + @NonNull final SystemContractMethodRegistry systemContractMethodRegistry, + @NonNull final ContractMetrics contractMetrics) { // Dagger2 + super(SystemContractMethod.SystemContract.HTS, systemContractMethodRegistry, contractMetrics); + + registerMethods(SYMBOL); } - /** - * {@inheritDoc} - */ @Override - public boolean matches(@NonNull final HtsCallAttempt attempt) { - return attempt.isSelector(SYMBOL); + public @NonNull Optional identifyMethod(@NonNull final HtsCallAttempt attempt) { + requireNonNull(attempt); + return attempt.isMethod(SYMBOL); } /** diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/tokenexpiry/TokenExpiryTranslator.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/tokenexpiry/TokenExpiryTranslator.java index f92d1a31c4fc..40706299cbdd 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/tokenexpiry/TokenExpiryTranslator.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/tokenexpiry/TokenExpiryTranslator.java @@ -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. @@ -17,37 +17,50 @@ package com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.tokenexpiry; import static com.hedera.node.app.service.contract.impl.utils.ConversionUtils.fromHeadlongAddress; +import static java.util.Objects.requireNonNull; -import com.esaulpaugh.headlong.abi.Function; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.AbstractCallTranslator; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.Call; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.ReturnTypes; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Category; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Modifier; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import edu.umd.cs.findbugs.annotations.NonNull; +import java.util.Optional; import javax.inject.Inject; +import javax.inject.Singleton; /** * Translates {@code getTokenExpiry()} calls to the HTS system contract. */ +@Singleton public class TokenExpiryTranslator extends AbstractCallTranslator { /** Selector for getTokenExpiryInfo(address) method. */ - public static final Function TOKEN_EXPIRY = - new Function("getTokenExpiryInfo(address)", ReturnTypes.RESPONSE_CODE_EXPIRY); + public static final SystemContractMethod TOKEN_EXPIRY = SystemContractMethod.declare( + "getTokenExpiryInfo(address)", ReturnTypes.RESPONSE_CODE_EXPIRY) + .withModifier(Modifier.VIEW) + .withCategory(Category.TOKEN_QUERY); /** * Default constructor for injection. */ @Inject - public TokenExpiryTranslator() { + public TokenExpiryTranslator( + @NonNull final SystemContractMethodRegistry systemContractMethodRegistry, + @NonNull final ContractMetrics contractMetrics) { // Dagger2 + super(SystemContractMethod.SystemContract.HTS, systemContractMethodRegistry, contractMetrics); + + registerMethods(TOKEN_EXPIRY); } - /** - * {@inheritDoc} - */ @Override - public boolean matches(@NonNull final HtsCallAttempt attempt) { - return attempt.isSelector(TOKEN_EXPIRY); + public @NonNull Optional identifyMethod(@NonNull final HtsCallAttempt attempt) { + requireNonNull(attempt); + return attempt.isMethod(TOKEN_EXPIRY); } /** diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/tokeninfo/TokenInfoCall.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/tokeninfo/TokenInfoCall.java index 7a5f607ec273..99a7cde7d9d5 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/tokeninfo/TokenInfoCall.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/tokeninfo/TokenInfoCall.java @@ -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. @@ -83,7 +83,7 @@ public TokenInfoCall( return revertResult(status, gasRequirement); } - return function.getName().equals(TOKEN_INFO.getName()) + return function.getName().equals(TOKEN_INFO.methodName()) ? successResult( TOKEN_INFO .getOutputs() diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/tokeninfo/TokenInfoTranslator.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/tokeninfo/TokenInfoTranslator.java index d65f7a9d0bc5..3cdf876057c9 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/tokeninfo/TokenInfoTranslator.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/tokeninfo/TokenInfoTranslator.java @@ -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. @@ -19,43 +19,62 @@ import static com.hedera.node.app.service.contract.impl.utils.ConversionUtils.fromHeadlongAddress; import static java.util.Objects.requireNonNull; -import com.esaulpaugh.headlong.abi.Function; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.AbstractCallTranslator; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.Call; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.ReturnTypes; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Category; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Modifier; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Variant; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.config.data.ContractsConfig; import edu.umd.cs.findbugs.annotations.NonNull; +import java.util.Optional; import javax.inject.Inject; +import javax.inject.Singleton; /** * Translates {@code getTokenInfo()} calls to the HTS system contract. */ +@Singleton public class TokenInfoTranslator extends AbstractCallTranslator { /** Selector for getTokenInfo(address) method. */ - public static final Function TOKEN_INFO = - new Function("getTokenInfo(address)", ReturnTypes.RESPONSE_CODE_TOKEN_INFO); + public static final SystemContractMethod TOKEN_INFO = SystemContractMethod.declare( + "getTokenInfo(address)", ReturnTypes.RESPONSE_CODE_TOKEN_INFO) + .withModifier(Modifier.VIEW) + .withVariant(Variant.V1) + .withCategory(Category.TOKEN_QUERY); /** Selector for getTokenInfoV2(address) method. */ - public static final Function TOKEN_INFO_V2 = - new Function("getTokenInfoV2(address)", ReturnTypes.RESPONSE_CODE_TOKEN_INFO_V2); + public static final SystemContractMethod TOKEN_INFO_V2 = SystemContractMethod.declare( + "getTokenInfoV2(address)", ReturnTypes.RESPONSE_CODE_TOKEN_INFO_V2) + .withModifier(Modifier.VIEW) + .withVariant(Variant.V2) + .withCategory(Category.TOKEN_QUERY); /** * Default constructor for injection. */ @Inject - public TokenInfoTranslator() { + public TokenInfoTranslator( + @NonNull final SystemContractMethodRegistry systemContractMethodRegistry, + @NonNull final ContractMetrics contractMetrics) { // Dagger2 + super(SystemContractMethod.SystemContract.HTS, systemContractMethodRegistry, contractMetrics); + + registerMethods(TOKEN_INFO, TOKEN_INFO_V2); } - /** - * {@inheritDoc} - */ @Override - public boolean matches(@NonNull final HtsCallAttempt attempt) { + public @NonNull Optional identifyMethod(@NonNull final HtsCallAttempt attempt) { requireNonNull(attempt); + final var v2Enabled = attempt.configuration().getConfigData(ContractsConfig.class).systemContractTokenInfoV2Enabled(); - return attempt.isSelector(TOKEN_INFO) || attempt.isSelectorIfConfigEnabled(v2Enabled, TOKEN_INFO_V2); + if (attempt.isSelector(TOKEN_INFO)) return Optional.of(TOKEN_INFO); + if (attempt.isSelectorIfConfigEnabled(v2Enabled, TOKEN_INFO_V2)) return Optional.of(TOKEN_INFO_V2); + return Optional.empty(); } /** @@ -64,8 +83,8 @@ public boolean matches(@NonNull final HtsCallAttempt attempt) { @Override public Call callFrom(@NonNull final HtsCallAttempt attempt) { requireNonNull(attempt); - final var function = attempt.isSelector(TOKEN_INFO) ? TOKEN_INFO : TOKEN_INFO_V2; - final var args = function.decodeCall(attempt.input().toArrayUnsafe()); + final var method = attempt.isSelector(TOKEN_INFO) ? TOKEN_INFO : TOKEN_INFO_V2; + final var args = method.decodeCall(attempt.input().toArrayUnsafe()); final var token = attempt.linkedToken(fromHeadlongAddress(args.get(0))); return new TokenInfoCall( attempt.systemContractGasCalculator(), @@ -73,6 +92,6 @@ public Call callFrom(@NonNull final HtsCallAttempt attempt) { attempt.isStaticCall(), token, attempt.configuration(), - function); + method.function()); } } diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/tokenkey/TokenKeyTranslator.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/tokenkey/TokenKeyTranslator.java index 0565b69dd5dc..988dadefe3f9 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/tokenkey/TokenKeyTranslator.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/tokenkey/TokenKeyTranslator.java @@ -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. @@ -17,42 +17,55 @@ package com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.tokenkey; import static com.hedera.node.app.service.contract.impl.utils.ConversionUtils.fromHeadlongAddress; +import static java.util.Objects.requireNonNull; -import com.esaulpaugh.headlong.abi.Function; import com.hedera.hapi.node.base.Key; import com.hedera.hapi.node.state.token.Token; import com.hedera.node.app.hapi.utils.InvalidTransactionException; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.AbstractCallTranslator; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.Call; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.ReturnTypes; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Category; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Modifier; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.config.data.ContractsConfig; import edu.umd.cs.findbugs.annotations.NonNull; import java.math.BigInteger; +import java.util.Optional; import javax.inject.Inject; +import javax.inject.Singleton; /** * Translates {@code getTokenKey()} calls to the HTS system contract. */ +@Singleton public class TokenKeyTranslator extends AbstractCallTranslator { /** Selector for getTokenKey(address,uint) method. */ - public static final Function TOKEN_KEY = - new Function("getTokenKey(address,uint)", ReturnTypes.RESPONSE_CODE_TOKEN_KEY); + public static final SystemContractMethod TOKEN_KEY = SystemContractMethod.declare( + "getTokenKey(address,uint)", ReturnTypes.RESPONSE_CODE_TOKEN_KEY) + .withModifier(Modifier.VIEW) + .withCategory(Category.TOKEN_QUERY); /** * Default constructor for injection. */ @Inject - public TokenKeyTranslator() { + public TokenKeyTranslator( + @NonNull final SystemContractMethodRegistry systemContractMethodRegistry, + @NonNull final ContractMetrics contractMetrics) { // Dagger2 + super(SystemContractMethod.SystemContract.HTS, systemContractMethodRegistry, contractMetrics); + + registerMethods(TOKEN_KEY); } - /** - * {@inheritDoc} - */ @Override - public boolean matches(@NonNull final HtsCallAttempt attempt) { - return attempt.isSelector(TOKEN_KEY); + public @NonNull Optional identifyMethod(@NonNull final HtsCallAttempt attempt) { + requireNonNull(attempt); + return attempt.isMethod(TOKEN_KEY); } /** diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/tokentype/TokenTypeTranslator.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/tokentype/TokenTypeTranslator.java index fed5aa7aef00..674507804884 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/tokentype/TokenTypeTranslator.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/tokentype/TokenTypeTranslator.java @@ -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. @@ -17,36 +17,50 @@ package com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.tokentype; import static com.hedera.node.app.service.contract.impl.utils.ConversionUtils.fromHeadlongAddress; +import static java.util.Objects.requireNonNull; -import com.esaulpaugh.headlong.abi.Function; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.AbstractCallTranslator; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.Call; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.ReturnTypes; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Category; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Modifier; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import edu.umd.cs.findbugs.annotations.NonNull; +import java.util.Optional; import javax.inject.Inject; +import javax.inject.Singleton; /** * Translates {@code getTokenType()} calls to the HTS system contract. */ +@Singleton public class TokenTypeTranslator extends AbstractCallTranslator { /** Selector for getTokenType(address) method. */ - public static final Function TOKEN_TYPE = new Function("getTokenType(address)", ReturnTypes.RESPONSE_CODE_INT32); + public static final SystemContractMethod TOKEN_TYPE = SystemContractMethod.declare( + "getTokenType(address)", ReturnTypes.RESPONSE_CODE_INT32) + .withModifier(Modifier.VIEW) + .withCategory(Category.TOKEN_QUERY); /** * Default constructor for injection. */ @Inject - public TokenTypeTranslator() { + public TokenTypeTranslator( + @NonNull final SystemContractMethodRegistry systemContractMethodRegistry, + @NonNull final ContractMetrics contractMetrics) { // Dagger2 + super(SystemContractMethod.SystemContract.HTS, systemContractMethodRegistry, contractMetrics); + + registerMethods(TOKEN_TYPE); } - /** - * {@inheritDoc} - */ @Override - public boolean matches(@NonNull final HtsCallAttempt attempt) { - return attempt.isSelector(TOKEN_TYPE); + public @NonNull Optional identifyMethod(@NonNull final HtsCallAttempt attempt) { + requireNonNull(attempt); + return attempt.isMethod(TOKEN_TYPE); } /** diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/tokenuri/TokenUriTranslator.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/tokenuri/TokenUriTranslator.java index 425753d7bbb2..230b7ced67bf 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/tokenuri/TokenUriTranslator.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/tokenuri/TokenUriTranslator.java @@ -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. @@ -17,13 +17,19 @@ package com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.tokenuri; import static com.hedera.node.app.service.contract.impl.utils.ConversionUtils.asExactLongValueOrZero; +import static java.util.Objects.requireNonNull; -import com.esaulpaugh.headlong.abi.Function; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.AbstractCallTranslator; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.Call; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.ReturnTypes; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Category; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Modifier; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import edu.umd.cs.findbugs.annotations.NonNull; +import java.util.Optional; import javax.inject.Inject; import javax.inject.Singleton; @@ -33,22 +39,28 @@ @Singleton public class TokenUriTranslator extends AbstractCallTranslator { /** Selector for tokenURI(uint256) method. */ - public static final Function TOKEN_URI = new Function("tokenURI(uint256)", ReturnTypes.STRING); + public static final SystemContractMethod TOKEN_URI = SystemContractMethod.declare( + "tokenURI(uint256)", ReturnTypes.STRING) + .withModifier(Modifier.VIEW) + .withCategories(Category.ERC721, Category.TOKEN_QUERY); /** * Default constructor for injection. */ @Inject - public TokenUriTranslator() { + public TokenUriTranslator( + @NonNull final SystemContractMethodRegistry systemContractMethodRegistry, + @NonNull final ContractMetrics contractMetrics) { // Dagger2 + super(SystemContractMethod.SystemContract.HTS, systemContractMethodRegistry, contractMetrics); + + registerMethods(TOKEN_URI); } - /** - * {@inheritDoc} - */ @Override - public boolean matches(@NonNull final HtsCallAttempt attempt) { - return attempt.isSelector(TOKEN_URI); + public @NonNull Optional identifyMethod(@NonNull final HtsCallAttempt attempt) { + requireNonNull(attempt); + return attempt.isMethod(TOKEN_URI); } /** diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/totalsupply/TotalSupplyTranslator.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/totalsupply/TotalSupplyTranslator.java index fc30f4754d08..56375f913c82 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/totalsupply/TotalSupplyTranslator.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/totalsupply/TotalSupplyTranslator.java @@ -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. @@ -16,11 +16,16 @@ package com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.totalsupply; -import com.esaulpaugh.headlong.abi.Function; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.AbstractCallTranslator; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.ReturnTypes; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Category; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Modifier; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import edu.umd.cs.findbugs.annotations.NonNull; +import java.util.Optional; import javax.inject.Inject; import javax.inject.Singleton; @@ -30,22 +35,27 @@ @Singleton public class TotalSupplyTranslator extends AbstractCallTranslator { /** Selector for totalSupply() method. */ - public static final Function TOTAL_SUPPLY = new Function("totalSupply()", ReturnTypes.INT); + public static final SystemContractMethod TOTAL_SUPPLY = SystemContractMethod.declare( + "totalSupply()", ReturnTypes.INT) + .withModifier(Modifier.VIEW) + .withCategories(Category.ERC20, Category.ERC721, Category.TOKEN_QUERY); /** * Default constructor for injection. */ @Inject - public TotalSupplyTranslator() { + public TotalSupplyTranslator( + @NonNull final SystemContractMethodRegistry systemContractMethodRegistry, + @NonNull final ContractMetrics contractMetrics) { // Dagger2 + super(SystemContractMethod.SystemContract.HTS, systemContractMethodRegistry, contractMetrics); + + registerMethods(TOTAL_SUPPLY); } - /** - * {@inheritDoc} - */ @Override - public boolean matches(@NonNull final HtsCallAttempt attempt) { - return attempt.isSelector(TOTAL_SUPPLY); + public @NonNull Optional identifyMethod(@NonNull final HtsCallAttempt attempt) { + return attempt.isMethod(TOTAL_SUPPLY); } /** diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/transfer/ClassicTransfersTranslator.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/transfer/ClassicTransfersTranslator.java index bfee6100667c..436897e7ec97 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/transfer/ClassicTransfersTranslator.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/transfer/ClassicTransfersTranslator.java @@ -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. @@ -21,13 +21,18 @@ import static com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.transfer.SpecialRewardReceivers.SPECIAL_REWARD_RECEIVERS; import static com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.transfer.SystemAccountCreditScreen.SYSTEM_ACCOUNT_CREDIT_SCREEN; -import com.esaulpaugh.headlong.abi.Function; import com.hedera.hapi.node.transaction.TransactionBody; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.AbstractCallTranslator; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.ReturnTypes; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Category; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Variant; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; +import java.util.Optional; import javax.inject.Inject; import javax.inject.Singleton; @@ -39,44 +44,59 @@ public class ClassicTransfersTranslator extends AbstractCallTranslator identifyMethod(@NonNull final HtsCallAttempt attempt) { + if (attempt.isTokenRedirect()) return Optional.empty(); + return attempt.isMethod( + CRYPTO_TRANSFER, + CRYPTO_TRANSFER_V2, + TRANSFER_TOKENS, + TRANSFER_TOKEN, + TRANSFER_NFTS, + TRANSFER_NFT, + TRANSFER_FROM, + TRANSFER_NFT_FROM); } @Override @@ -143,11 +182,18 @@ public ClassicTransfersCall callFrom(@NonNull final HtsCallAttempt attempt) { } private boolean isClassicCall(@NonNull final HtsCallAttempt attempt) { - return attempt.isSelector( - CRYPTO_TRANSFER, CRYPTO_TRANSFER_V2, TRANSFER_TOKENS, TRANSFER_TOKEN, TRANSFER_NFTS, TRANSFER_NFT); + return attempt.isMethod( + CRYPTO_TRANSFER, + CRYPTO_TRANSFER_V2, + TRANSFER_TOKENS, + TRANSFER_TOKEN, + TRANSFER_NFTS, + TRANSFER_NFT) + .isPresent(); } private boolean isClassicCallSupportingQualifiedDelegate(@NonNull final HtsCallAttempt attempt) { - return attempt.isSelector(TRANSFER_TOKENS, TRANSFER_TOKEN, TRANSFER_NFTS, TRANSFER_NFT); + return attempt.isMethod(TRANSFER_TOKENS, TRANSFER_TOKEN, TRANSFER_NFTS, TRANSFER_NFT) + .isPresent(); } } diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/transfer/Erc20TransfersTranslator.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/transfer/Erc20TransfersTranslator.java index f956029043b7..c8d733c4bd89 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/transfer/Erc20TransfersTranslator.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/transfer/Erc20TransfersTranslator.java @@ -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. @@ -21,14 +21,19 @@ import static java.util.Objects.requireNonNull; import com.esaulpaugh.headlong.abi.Address; -import com.esaulpaugh.headlong.abi.Function; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.AbstractCallTranslator; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.Call; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.ReturnTypes; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.CallVia; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Category; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; import java.math.BigInteger; +import java.util.Optional; import javax.inject.Inject; import javax.inject.Singleton; @@ -40,27 +45,39 @@ public class Erc20TransfersTranslator extends AbstractCallTranslator identifyMethod(@NonNull final HtsCallAttempt attempt) { + // Here, for ERC-20 == fungible tokens, we allow `transferFrom` (signature shared by ERC-20 + // and ERC-721) even if the token type doesn't exist. (This is the case when `redirectTokenType()` + // returns `null`.) + if (!attempt.isTokenRedirect()) return Optional.empty(); + if (attempt.redirectTokenType() == NON_FUNGIBLE_UNIQUE) return Optional.empty(); + return attempt.isMethod(ERC_20_TRANSFER, ERC_20_TRANSFER_FROM); } @Override diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/transfer/Erc721TransferFromTranslator.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/transfer/Erc721TransferFromTranslator.java index 21173a4185c2..e0873caded83 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/transfer/Erc721TransferFromTranslator.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/transfer/Erc721TransferFromTranslator.java @@ -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. @@ -20,12 +20,17 @@ import static com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.transfer.SpecialRewardReceivers.SPECIAL_REWARD_RECEIVERS; import static java.util.Objects.requireNonNull; -import com.esaulpaugh.headlong.abi.Function; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.AbstractCallTranslator; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.Call; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallAttempt; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.CallVia; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Category; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import edu.umd.cs.findbugs.annotations.NonNull; import java.math.BigInteger; +import java.util.Optional; import javax.inject.Inject; import javax.inject.Singleton; @@ -38,22 +43,30 @@ public class Erc721TransferFromTranslator extends AbstractCallTranslator identifyMethod(@NonNull final HtsCallAttempt attempt) { + // Here, for ERC-721 == non-fungible tokens, the token type must exist + if (!attempt.isTokenRedirect()) return Optional.empty(); + if (attempt.redirectTokenType() != NON_FUNGIBLE_UNIQUE) return Optional.empty(); + return attempt.isMethod(ERC_721_TRANSFER_FROM); } @Override diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/update/UpdateExpiryTranslator.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/update/UpdateExpiryTranslator.java index 1d91cf22dce1..775eb67e135d 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/update/UpdateExpiryTranslator.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/update/UpdateExpiryTranslator.java @@ -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. @@ -20,35 +20,46 @@ import static com.hedera.node.app.hapi.utils.contracts.ParsingConstants.EXPIRY_V2; import static com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.update.UpdateDecoder.FAILURE_CUSTOMIZER; -import com.esaulpaugh.headlong.abi.Function; import com.hedera.hapi.node.base.AccountID; import com.hedera.hapi.node.transaction.TransactionBody; import com.hedera.node.app.service.contract.impl.exec.gas.DispatchType; import com.hedera.node.app.service.contract.impl.exec.gas.SystemContractGasCalculator; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.AbstractCallTranslator; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.Call; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.DispatchForResponseCodeHtsCall; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.ReturnTypes; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Category; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Variant; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.hevm.HederaWorldUpdater; import edu.umd.cs.findbugs.annotations.NonNull; import java.util.Arrays; +import java.util.Optional; import javax.inject.Inject; +import javax.inject.Singleton; /** * Translates ERC-721 {@code updateTokenExpiryInfo()} calls to the HTS system contract. */ +@Singleton public class UpdateExpiryTranslator extends AbstractCallTranslator { /** * Selector for updateTokenExpiryInfo(address, EXPIRY) method. */ - public static final Function UPDATE_TOKEN_EXPIRY_INFO_V1 = - new Function("updateTokenExpiryInfo(address," + EXPIRY + ")", ReturnTypes.INT); + public static final SystemContractMethod UPDATE_TOKEN_EXPIRY_INFO_V1 = SystemContractMethod.declare( + "updateTokenExpiryInfo(address," + EXPIRY + ")", ReturnTypes.INT) + .withVariant(Variant.V1) + .withCategories(Category.UPDATE); /** * Selector for updateTokenExpiryInfo(address, EXPIRY_V2) method. */ - public static final Function UPDATE_TOKEN_EXPIRY_INFO_V2 = - new Function("updateTokenExpiryInfo(address," + EXPIRY_V2 + ")", ReturnTypes.INT); + public static final SystemContractMethod UPDATE_TOKEN_EXPIRY_INFO_V2 = SystemContractMethod.declare( + "updateTokenExpiryInfo(address," + EXPIRY_V2 + ")", ReturnTypes.INT) + .withVariant(Variant.V2) + .withCategories(Category.UPDATE); private final UpdateDecoder decoder; @@ -56,13 +67,19 @@ public class UpdateExpiryTranslator extends AbstractCallTranslator identifyMethod(@NonNull final HtsCallAttempt attempt) { + return attempt.isMethod(UPDATE_TOKEN_EXPIRY_INFO_V1, UPDATE_TOKEN_EXPIRY_INFO_V2); } @Override diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/update/UpdateKeysTranslator.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/update/UpdateKeysTranslator.java index 3076a6a433d8..51cebed55210 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/update/UpdateKeysTranslator.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/update/UpdateKeysTranslator.java @@ -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. @@ -20,24 +20,31 @@ import static com.hedera.node.app.hapi.utils.contracts.ParsingConstants.TOKEN_KEY; import static com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.update.UpdateDecoder.FAILURE_CUSTOMIZER; -import com.esaulpaugh.headlong.abi.Function; import com.hedera.hapi.node.base.AccountID; import com.hedera.hapi.node.transaction.TransactionBody; import com.hedera.node.app.service.contract.impl.exec.gas.DispatchType; import com.hedera.node.app.service.contract.impl.exec.gas.SystemContractGasCalculator; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.AbstractCallTranslator; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.Call; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.DispatchForResponseCodeHtsCall; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.ReturnTypes; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Category; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.hevm.HederaWorldUpdater; import edu.umd.cs.findbugs.annotations.NonNull; +import java.util.Optional; import javax.inject.Inject; +import javax.inject.Singleton; +@Singleton public class UpdateKeysTranslator extends AbstractCallTranslator { /** Selector for updateTokenKeys(address, TOKEN_KEY[]) method. */ - public static final Function TOKEN_UPDATE_KEYS_FUNCTION = - new Function("updateTokenKeys(address," + TOKEN_KEY + ARRAY_BRACKETS + ")", ReturnTypes.INT); + public static final SystemContractMethod TOKEN_UPDATE_KEYS_FUNCTION = SystemContractMethod.declare( + "updateTokenKeys(address," + TOKEN_KEY + ARRAY_BRACKETS + ")", ReturnTypes.INT) + .withCategories(Category.UPDATE); private final UpdateDecoder decoder; @@ -45,13 +52,19 @@ public class UpdateKeysTranslator extends AbstractCallTranslator * @param decoder the decoder to use for token update keys calls */ @Inject - public UpdateKeysTranslator(UpdateDecoder decoder) { + public UpdateKeysTranslator( + @NonNull final UpdateDecoder decoder, + @NonNull final SystemContractMethodRegistry systemContractMethodRegistry, + @NonNull final ContractMetrics contractMetrics) { + super(SystemContractMethod.SystemContract.HTS, systemContractMethodRegistry, contractMetrics); this.decoder = decoder; + + registerMethods(TOKEN_UPDATE_KEYS_FUNCTION); } @Override - public boolean matches(@NonNull HtsCallAttempt attempt) { - return attempt.isSelector(TOKEN_UPDATE_KEYS_FUNCTION); + public @NonNull Optional identifyMethod(@NonNull final HtsCallAttempt attempt) { + return attempt.isMethod(TOKEN_UPDATE_KEYS_FUNCTION); } @Override diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/update/UpdateNFTsMetadataTranslator.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/update/UpdateNFTsMetadataTranslator.java index ada69222db8d..b6df7bac5fdd 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/update/UpdateNFTsMetadataTranslator.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/update/UpdateNFTsMetadataTranslator.java @@ -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. @@ -16,25 +16,34 @@ package com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.update; -import com.esaulpaugh.headlong.abi.Function; import com.hedera.hapi.node.base.AccountID; import com.hedera.hapi.node.transaction.TransactionBody; import com.hedera.node.app.service.contract.impl.exec.gas.DispatchType; import com.hedera.node.app.service.contract.impl.exec.gas.SystemContractGasCalculator; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.AbstractCallTranslator; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.Call; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.DispatchForResponseCodeHtsCall; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.ReturnTypes; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Category; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Variant; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.hevm.HederaWorldUpdater; import com.hedera.node.config.data.ContractsConfig; import edu.umd.cs.findbugs.annotations.NonNull; +import java.util.Optional; import javax.inject.Inject; +import javax.inject.Singleton; +@Singleton public class UpdateNFTsMetadataTranslator extends AbstractCallTranslator { /** Selector for updateNFTsMetadata(address,int64[],bytes) method. */ - public static final Function UPDATE_NFTs_METADATA = - new Function("updateNFTsMetadata(address,int64[],bytes)", ReturnTypes.INT); + public static final SystemContractMethod UPDATE_NFTs_METADATA = SystemContractMethod.declare( + "updateNFTsMetadata(address,int64[],bytes)", ReturnTypes.INT) + .withVariants(Variant.NFT, Variant.WITH_METADATA) + .withCategories(Category.UPDATE); private final UpdateDecoder decoder; @@ -42,14 +51,21 @@ public class UpdateNFTsMetadataTranslator extends AbstractCallTranslator identifyMethod(@NonNull final HtsCallAttempt attempt) { + if (!attempt.configuration().getConfigData(ContractsConfig.class).systemContractUpdateNFTsMetadataEnabled()) + return Optional.empty(); + return attempt.isMethod(UPDATE_NFTs_METADATA); } @Override diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/update/UpdateTranslator.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/update/UpdateTranslator.java index 162a449c5c59..bd84cacd2755 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/update/UpdateTranslator.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/update/UpdateTranslator.java @@ -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. @@ -22,23 +22,30 @@ import static com.hedera.node.app.hapi.utils.contracts.ParsingConstants.HEDERA_TOKEN_WITH_METADATA; import static com.hedera.node.app.hapi.utils.contracts.ParsingConstants.TOKEN_KEY; -import com.esaulpaugh.headlong.abi.Function; import com.hedera.hapi.node.base.AccountID; import com.hedera.hapi.node.transaction.TransactionBody; import com.hedera.node.app.service.contract.impl.exec.gas.DispatchType; import com.hedera.node.app.service.contract.impl.exec.gas.SystemContractGasCalculator; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.AbstractCallTranslator; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.Call; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.DispatchForResponseCodeHtsCall; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.ReturnTypes; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Category; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Variant; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.hevm.HederaWorldUpdater; import com.hedera.node.config.data.ContractsConfig; import edu.umd.cs.findbugs.annotations.NonNull; import java.util.HashMap; import java.util.Map; +import java.util.Optional; import javax.inject.Inject; +import javax.inject.Singleton; +@Singleton public class UpdateTranslator extends AbstractCallTranslator { private static final String UPDATE_TOKEN_INFO_STRING = "updateTokenInfo(address,"; private static final String HEDERA_TOKEN_STRUCT = @@ -48,40 +55,58 @@ public class UpdateTranslator extends AbstractCallTranslator { private static final String HEDERA_TOKEN_STRUCT_V3 = "(string,string,address,string,bool,int64,bool," + TOKEN_KEY + ARRAY_BRACKETS + "," + EXPIRY_V2 + ")"; /** Selector for updateTokenInfo(address, HEDERA_TOKEN_STRUCT) method. */ - public static final Function TOKEN_UPDATE_INFO_FUNCTION_V1 = - new Function(UPDATE_TOKEN_INFO_STRING + HEDERA_TOKEN_STRUCT + ")", ReturnTypes.INT); + public static final SystemContractMethod TOKEN_UPDATE_INFO_FUNCTION_V1 = SystemContractMethod.declare( + UPDATE_TOKEN_INFO_STRING + HEDERA_TOKEN_STRUCT + ")", ReturnTypes.INT) + .withVariant(Variant.V1) + .withCategories(Category.UPDATE); /** Selector for updateTokenInfo(address, HEDERA_TOKEN_STRUCT_V2) method. */ - public static final Function TOKEN_UPDATE_INFO_FUNCTION_V2 = - new Function(UPDATE_TOKEN_INFO_STRING + HEDERA_TOKEN_STRUCT_V2 + ")", ReturnTypes.INT); + public static final SystemContractMethod TOKEN_UPDATE_INFO_FUNCTION_V2 = SystemContractMethod.declare( + UPDATE_TOKEN_INFO_STRING + HEDERA_TOKEN_STRUCT_V2 + ")", ReturnTypes.INT) + .withVariant(Variant.V2) + .withCategories(Category.UPDATE); /** Selector for updateTokenInfo(address, HEDERA_TOKEN_STRUCT_V3) method. */ - public static final Function TOKEN_UPDATE_INFO_FUNCTION_V3 = - new Function(UPDATE_TOKEN_INFO_STRING + HEDERA_TOKEN_STRUCT_V3 + ")", ReturnTypes.INT); + public static final SystemContractMethod TOKEN_UPDATE_INFO_FUNCTION_V3 = SystemContractMethod.declare( + UPDATE_TOKEN_INFO_STRING + HEDERA_TOKEN_STRUCT_V3 + ")", ReturnTypes.INT) + .withVariant(Variant.V3) + .withCategories(Category.UPDATE); /** Selector for updateTokenInfo(address, HEDERA_TOKEN_WITH_METADATA) method. */ - public static final Function TOKEN_UPDATE_INFO_FUNCTION_WITH_METADATA = - new Function(UPDATE_TOKEN_INFO_STRING + HEDERA_TOKEN_WITH_METADATA + ")", ReturnTypes.INT); + public static final SystemContractMethod TOKEN_UPDATE_INFO_FUNCTION_WITH_METADATA = SystemContractMethod.declare( + UPDATE_TOKEN_INFO_STRING + HEDERA_TOKEN_WITH_METADATA + ")", ReturnTypes.INT) + .withVariant(Variant.WITH_METADATA) + .withCategories(Category.UPDATE); - public static final Map updateSelectorsMap = new HashMap<>(); + public static final Map updateMethodsMap = new HashMap<>(); /** * @param decoder the decoder to use for token update info calls */ @Inject - public UpdateTranslator(final UpdateDecoder decoder) { - updateSelectorsMap.put(TOKEN_UPDATE_INFO_FUNCTION_V1, decoder::decodeTokenUpdateV1); - updateSelectorsMap.put(TOKEN_UPDATE_INFO_FUNCTION_V2, decoder::decodeTokenUpdateV2); - updateSelectorsMap.put(TOKEN_UPDATE_INFO_FUNCTION_V3, decoder::decodeTokenUpdateV3); - updateSelectorsMap.put(TOKEN_UPDATE_INFO_FUNCTION_WITH_METADATA, decoder::decodeTokenUpdateWithMetadata); + public UpdateTranslator( + final UpdateDecoder decoder, + @NonNull final SystemContractMethodRegistry systemContractMethodRegistry, + @NonNull final ContractMetrics contractMetrics) { + super(SystemContractMethod.SystemContract.HTS, systemContractMethodRegistry, contractMetrics); + + registerMethods( + TOKEN_UPDATE_INFO_FUNCTION_V1, + TOKEN_UPDATE_INFO_FUNCTION_V2, + TOKEN_UPDATE_INFO_FUNCTION_V3, + TOKEN_UPDATE_INFO_FUNCTION_WITH_METADATA); + + updateMethodsMap.put(TOKEN_UPDATE_INFO_FUNCTION_V1, decoder::decodeTokenUpdateV1); + updateMethodsMap.put(TOKEN_UPDATE_INFO_FUNCTION_V2, decoder::decodeTokenUpdateV2); + updateMethodsMap.put(TOKEN_UPDATE_INFO_FUNCTION_V3, decoder::decodeTokenUpdateV3); + updateMethodsMap.put(TOKEN_UPDATE_INFO_FUNCTION_WITH_METADATA, decoder::decodeTokenUpdateWithMetadata); } @Override - public boolean matches(@NonNull HtsCallAttempt attempt) { + public @NonNull Optional identifyMethod(@NonNull final HtsCallAttempt attempt) { final boolean metadataSupport = attempt.configuration().getConfigData(ContractsConfig.class).metadataKeyAndFieldEnabled(); - return updateSelectorsMap.keySet().stream() - .anyMatch(selector -> selector.equals(TOKEN_UPDATE_INFO_FUNCTION_WITH_METADATA) - ? attempt.isSelectorIfConfigEnabled(metadataSupport, selector) - : attempt.isSelector(selector)); + if (attempt.isSelectorIfConfigEnabled(metadataSupport, TOKEN_UPDATE_INFO_FUNCTION_WITH_METADATA)) + return Optional.of(TOKEN_UPDATE_INFO_FUNCTION_WITH_METADATA); + return updateMethodsMap.keySet().stream().filter(attempt::isSelector).findFirst(); } @Override @@ -106,7 +131,7 @@ public static long gasRequirement( } private TransactionBody nominalBodyFor(@NonNull final HtsCallAttempt attempt) { - return updateSelectorsMap.entrySet().stream() + return updateMethodsMap.entrySet().stream() .filter(entry -> attempt.isSelector(entry.getKey())) .map(entry -> entry.getValue().decode(attempt)) .findFirst() diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/updatetokencustomfees/UpdateTokenCustomFeesTranslator.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/updatetokencustomfees/UpdateTokenCustomFeesTranslator.java index 75788816cfd1..535818a50fbe 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/updatetokencustomfees/UpdateTokenCustomFeesTranslator.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/updatetokencustomfees/UpdateTokenCustomFeesTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2024 Hedera Hashgraph, LLC + * Copyright (C) 2024-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. @@ -20,44 +20,63 @@ import static com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.updatetokencustomfees.UpdateTokenCustomFeesDecoder.UPDATE_NON_FUNGIBLE_TOKEN_CUSTOM_FEES_STRING; import static java.util.Objects.requireNonNull; -import com.esaulpaugh.headlong.abi.Function; import com.hedera.hapi.node.base.AccountID; import com.hedera.hapi.node.transaction.TransactionBody; import com.hedera.node.app.service.contract.impl.exec.gas.DispatchType; import com.hedera.node.app.service.contract.impl.exec.gas.SystemContractGasCalculator; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.AbstractCallTranslator; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.Call; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.DispatchForResponseCodeHtsCall; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.ReturnTypes; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Category; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Variant; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.hevm.HederaWorldUpdater; import com.hedera.node.config.data.ContractsConfig; import edu.umd.cs.findbugs.annotations.NonNull; import java.util.Arrays; +import java.util.Optional; import javax.inject.Inject; +import javax.inject.Singleton; +@Singleton public class UpdateTokenCustomFeesTranslator extends AbstractCallTranslator { /** Selector for updateFungibleTokenCustomFees(address,(int64,address,bool,bool,address)[],(int64,int64,int64,int64,bool,address)[]) method. */ - public static final Function UPDATE_FUNGIBLE_TOKEN_CUSTOM_FEES_FUNCTION = - new Function(UPDATE_FUNGIBLE_TOKEN_CUSTOM_FEES_STRING, ReturnTypes.INT); + public static final SystemContractMethod UPDATE_FUNGIBLE_TOKEN_CUSTOM_FEES_FUNCTION = SystemContractMethod.declare( + UPDATE_FUNGIBLE_TOKEN_CUSTOM_FEES_STRING, ReturnTypes.INT) + .withVariants(Variant.FT, Variant.WITH_CUSTOM_FEES) + .withCategories(Category.UPDATE); /** Selector for updateNonFungibleTokenCustomFees(address,(int64,address,bool,bool,address)[],(int64,int64,int64,address,bool,address)[]) method. */ - public static final Function UPDATE_NON_FUNGIBLE_TOKEN_CUSTOM_FEES_FUNCTION = - new Function(UPDATE_NON_FUNGIBLE_TOKEN_CUSTOM_FEES_STRING, ReturnTypes.INT); + public static final SystemContractMethod UPDATE_NON_FUNGIBLE_TOKEN_CUSTOM_FEES_FUNCTION = + SystemContractMethod.declare(UPDATE_NON_FUNGIBLE_TOKEN_CUSTOM_FEES_STRING, ReturnTypes.INT) + .withVariants(Variant.NFT, Variant.WITH_CUSTOM_FEES) + .withCategories(Category.UPDATE); private final UpdateTokenCustomFeesDecoder decoder; @Inject - public UpdateTokenCustomFeesTranslator(@NonNull final UpdateTokenCustomFeesDecoder decoder) { + public UpdateTokenCustomFeesTranslator( + @NonNull final UpdateTokenCustomFeesDecoder decoder, + @NonNull final SystemContractMethodRegistry systemContractMethodRegistry, + @NonNull final ContractMetrics contractMetrics) { + super(SystemContractMethod.SystemContract.HTS, systemContractMethodRegistry, contractMetrics); + requireNonNull(decoder); this.decoder = decoder; + + registerMethods(UPDATE_FUNGIBLE_TOKEN_CUSTOM_FEES_FUNCTION, UPDATE_NON_FUNGIBLE_TOKEN_CUSTOM_FEES_FUNCTION); } @Override - public boolean matches(@NonNull HtsCallAttempt attempt) { - return attempt.configuration().getConfigData(ContractsConfig.class).systemContractUpdateCustomFeesEnabled() - && attempt.isSelector( - UPDATE_FUNGIBLE_TOKEN_CUSTOM_FEES_FUNCTION, UPDATE_NON_FUNGIBLE_TOKEN_CUSTOM_FEES_FUNCTION); + public @NonNull Optional identifyMethod(@NonNull final HtsCallAttempt attempt) { + if (!attempt.configuration().getConfigData(ContractsConfig.class).systemContractUpdateCustomFeesEnabled()) + return Optional.empty(); + return attempt.isMethod( + UPDATE_FUNGIBLE_TOKEN_CUSTOM_FEES_FUNCTION, UPDATE_NON_FUNGIBLE_TOKEN_CUSTOM_FEES_FUNCTION); } /** diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/wipe/WipeTranslator.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/wipe/WipeTranslator.java index 9d7e43bfecc3..55d50486abe1 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/wipe/WipeTranslator.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/systemcontracts/hts/wipe/WipeTranslator.java @@ -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. @@ -18,18 +18,23 @@ import static com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.DispatchForResponseCodeHtsCall.FailureCustomizer.NOOP_CUSTOMIZER; -import com.esaulpaugh.headlong.abi.Function; import com.hedera.hapi.node.base.AccountID; import com.hedera.hapi.node.transaction.TransactionBody; import com.hedera.node.app.service.contract.impl.exec.gas.DispatchType; import com.hedera.node.app.service.contract.impl.exec.gas.SystemContractGasCalculator; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.AbstractCallTranslator; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.Call; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.DispatchForResponseCodeHtsCall; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.ReturnTypes; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Category; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Variant; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.hevm.HederaWorldUpdater; import edu.umd.cs.findbugs.annotations.NonNull; +import java.util.Optional; import javax.inject.Inject; import javax.inject.Singleton; @@ -37,28 +42,37 @@ public class WipeTranslator extends AbstractCallTranslator { /** Selector for wipeTokenAccount(address,address,uint32) method. */ - public static final Function WIPE_FUNGIBLE_V1 = - new Function("wipeTokenAccount(address,address,uint32)", ReturnTypes.INT); + public static final SystemContractMethod WIPE_FUNGIBLE_V1 = SystemContractMethod.declare( + "wipeTokenAccount(address,address,uint32)", ReturnTypes.INT) + .withVariants(Variant.V1, Variant.FT) + .withCategories(Category.WIPE); /** Selector for wipeTokenAccount(address,address,int64) method. */ - public static final Function WIPE_FUNGIBLE_V2 = - new Function("wipeTokenAccount(address,address,int64)", ReturnTypes.INT); + public static final SystemContractMethod WIPE_FUNGIBLE_V2 = SystemContractMethod.declare( + "wipeTokenAccount(address,address,int64)", ReturnTypes.INT) + .withVariants(Variant.V2, Variant.FT) + .withCategories(Category.WIPE); /** Selector for wipeTokenAccountNFT(address,address,int64[]) method. */ - public static final Function WIPE_NFT = - new Function("wipeTokenAccountNFT(address,address,int64[])", ReturnTypes.INT); + public static final SystemContractMethod WIPE_NFT = SystemContractMethod.declare( + "wipeTokenAccountNFT(address,address,int64[])", ReturnTypes.INT) + .withVariant(Variant.NFT) + .withCategories(Category.WIPE); private final WipeDecoder decoder; @Inject - public WipeTranslator(@NonNull final WipeDecoder decoder) { + public WipeTranslator( + @NonNull final WipeDecoder decoder, + @NonNull final SystemContractMethodRegistry systemContractMethodRegistry, + @NonNull final ContractMetrics contractMetrics) { + super(SystemContractMethod.SystemContract.HTS, systemContractMethodRegistry, contractMetrics); this.decoder = decoder; + + registerMethods(WIPE_FUNGIBLE_V1, WIPE_FUNGIBLE_V2, WIPE_NFT); } - /** - * {@inheritDoc} - */ @Override - public boolean matches(@NonNull final HtsCallAttempt attempt) { - return attempt.isSelector(WIPE_FUNGIBLE_V1, WIPE_FUNGIBLE_V2, WIPE_NFT); + public @NonNull Optional identifyMethod(@NonNull final HtsCallAttempt attempt) { + return attempt.isMethod(WIPE_FUNGIBLE_V1, WIPE_FUNGIBLE_V2, WIPE_NFT); } /** diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/utils/SystemContractMethod.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/utils/SystemContractMethod.java new file mode 100644 index 000000000000..9f0e81073f82 --- /dev/null +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/utils/SystemContractMethod.java @@ -0,0 +1,365 @@ +/* + * Copyright (C) 2024-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.utils; + +import static java.util.Objects.requireNonNull; + +import com.esaulpaugh.headlong.abi.Function; +import com.esaulpaugh.headlong.abi.Tuple; +import com.esaulpaugh.headlong.abi.TupleType; +import edu.umd.cs.findbugs.annotations.NonNull; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.Arrays; +import java.util.EnumSet; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; +import org.apache.tuweni.bytes.Bytes; + +/** + * Represents a system contract method: It's signature + outputs, and other information about how it is declared + * @param function A headlong description of this method: signature + outputs, selector + * @param systemContract Which system contract this method is part of (HAS, HSS, HTS, PRNG, EXCHANGE) + * @param via Whether called directly or via redirect (aka proxy) + * @param categories Set of category flags possibly empty + * @param modifier An optional Solidity function modifier (e.g., pure or view) + * @param variants Set of method variants (e.g., version number, or FT vs NFT), possibly empty + */ +public record SystemContractMethod( + @NonNull Function function, + @NonNull Optional systemContract, + @NonNull CallVia via, + @NonNull EnumSet categories, + @NonNull Optional modifier, + @NonNull EnumSet variants) { + + public SystemContractMethod { + requireNonNull(function); + requireNonNull(systemContract); + requireNonNull(via); + requireNonNull(categories); + requireNonNull(modifier); + requireNonNull(variants); + } + + /** + * Factory to create a SystemContractMethod given its signature and outputs + * + * This SystemContractMethod is incomplete in that it doesn't have the SystemContract field, + * which must be added later (with `withContract`) + */ + public static SystemContractMethod declare(@NonNull final String signature, @NonNull final String outputs) { + final var function = new com.esaulpaugh.headlong.abi.Function(signature, outputs); + return new SystemContractMethod( + function, + Optional.empty(), + CallVia.DIRECT, + EnumSet.noneOf(Category.class), + Optional.empty(), + EnumSet.noneOf(Variant.class)); + } + + /** + * Factory to create a SystemContractMethod given its signature when it returns nothing + * + * This SystemContractMethod is incomplete in that it doesn't have the SystemContract field, + * which must be added later (with `withContract`) + */ + public static SystemContractMethod declare(@NonNull final String signature) { + final var function = new com.esaulpaugh.headlong.abi.Function(signature); + return new SystemContractMethod( + function, + Optional.empty(), + CallVia.DIRECT, + EnumSet.noneOf(Category.class), + Optional.empty(), + EnumSet.noneOf(Variant.class)); + } + + /** + * Verify that the SystemContractMethod was created correctly + * + * Specifically, check that a SystemContract was provided for it eventually + */ + public void verifyComplete() { + if (systemContract.isEmpty()) { + throw new IllegalStateException("System contract %s is empty".formatted(function.getName())); + } + } + + /** The system contract "kind" for this SystemContractMethod */ + public enum SystemContract { + HTS, + HAS, + HSS, + PNRG, + EXCHANGE + } + + public interface AsSuffix { + @NonNull + String asSuffix(); + } + + /** Says that this SystemContractMethod is called directly or via redirect/proxy */ + public enum CallVia implements AsSuffix { + DIRECT(""), + PROXY("[PROXY]"); + + private final String asSuffix; + + CallVia(@NonNull final String viaSuffix) { + asSuffix = viaSuffix; + } + + public @NonNull String asSuffix() { + return asSuffix; + } + } + + /** + * Says that this SystemContractMethod is a view function or a pure function (as in Solidity). + * + * If neither is specified then it is a normal (state-changing) function. + */ + public enum Modifier implements AsSuffix { + VIEW("VIEW"), + PURE("PURE"); + + private final String asSuffix; + + Modifier(String modifierSuffix) { + this.asSuffix = modifierSuffix; + } + + public @NonNull String asSuffix() { + return asSuffix; + } + } + + /** + * Categorizes the SystemContractMethod. None, one, or more of these categories can be specified. + * + * Useful for grouping methods together. + */ + public enum Category implements AsSuffix { + ERC20("ERC20", "(can overlap with ERC721)"), + ERC721("ERC721", "(can overlap with ERC20)"), + + SCHEDULE("SCHEDULE"), + TOKEN_QUERY("TOKEN_QUERY", "(any token field query)"), + + ALIASES("ALIASES"), + IS_AUTHORIZED("IS_AUTHORIZED", "(IsAuthorized, IsAuthorizedRaw)"), + + AIRDROP("AIRDROP"), + ALLOWANCE("ALLOWANCE", "(Allowance related)"), + APPROVAL("APPROVAL", "(Approval related)"), + ASSOCIATION("ASSOCIATION"), + CREATE_DELETE_TOKEN("CREATE_OR_DELETE_TOKEN", "(Create or Delete Token)"), + FREEZE_UNFREEZE("FREEZE_UNFREEZE", "(Freeze or Unfreeze Token)"), + KYC("KYC"), + MINT_BURN("MINT_OR_BURN", "(Mint or Burn Token)"), + PAUSE_UNPAUSE("PAUSE_UNPAUSE", "(Pause or Unpause Token)"), + REJECT("REJECT_TOKEN"), + TRANSFER("TRANSFER_TOKEN", "(any token transfer transaction"), + UPDATE("UPDATE_TOKEN", "(any token field update)"), + WIPE("WIPE_TOKEN"); + + private final String asSuffix; + private final String clarification; + + Category(@NonNull final String categorySuffix) { + this.asSuffix = requireNonNull(categorySuffix); + this.clarification = "(%s)".formatted(this.asSuffix); + } + + Category(@NonNull final String categorySuffix, @NonNull final String clarification) { + this.asSuffix = requireNonNull(categorySuffix); + this.clarification = requireNonNull(clarification); + } + + public @NonNull String asSuffix() { + return asSuffix; + } + + public @NonNull String clarification() { + return clarification; + } + } + + /** + * Distinguishes overloads of SystemContractMethods that have the same simple name. + */ + public enum Variant implements AsSuffix { + FT, + NFT, + V1, + V2, + V3, + WITH_METADATA, + WITH_CUSTOM_FEES; + + public @NonNull String asSuffix() { + return name(); + } + } + + // Fluent builders + + public @NonNull SystemContractMethod withContract(@NonNull final SystemContract systemContract) { + return new SystemContractMethod(function, Optional.of(systemContract), via, categories, modifier, variants); + } + + public @NonNull SystemContractMethod withVia(@NonNull final CallVia via) { + return new SystemContractMethod(function, systemContract, via, categories, modifier, variants); + } + + public @NonNull SystemContractMethod withCategories(@NonNull final Category... categories) { + final var c = EnumSet.copyOf(this.categories); + c.addAll(Arrays.asList(categories)); + return new SystemContractMethod(function, systemContract, via, c, modifier, variants); + } + + public @NonNull SystemContractMethod withCategory(@NonNull final Category category) { + final var c = EnumSet.copyOf(categories); + c.add(category); + return new SystemContractMethod(function, systemContract, via, c, modifier, variants); + } + + public @NonNull SystemContractMethod withModifier(@NonNull final Modifier modifier) { + return new SystemContractMethod(function, systemContract, via, categories, Optional.of(modifier), variants); + } + + public @NonNull SystemContractMethod withVariants(@NonNull final Variant... variants) { + final var v = EnumSet.copyOf(this.variants); + v.addAll(Arrays.asList(variants)); + return new SystemContractMethod(function, systemContract, via, categories, modifier, v); + } + + public @NonNull SystemContractMethod withVariant(@NonNull final Variant variant) { + final var v = EnumSet.copyOf(variants); + v.add(variant); + return new SystemContractMethod(function, systemContract, via, categories, modifier, v); + } + + // Forwarding to com.esaulpaugh.headlong.abi.Function + + public Tuple decodeCall(byte[] call) { + return function.decodeCall(call); + } + + public ByteBuffer encodeCall(Tuple tuple) { + return function.encodeCall(tuple); + } + + public ByteBuffer encodeCallWithArgs(Object... args) { + return function.encodeCallWithArgs(args); + } + + public TupleType getOutputs() { + return function.getOutputs(); + } + + public @NonNull String signature() { + return function.getCanonicalSignature(); + } + + public @NonNull String signatureWithReturn() { + return signature() + ':' + function.getOutputs(); + } + + public @NonNull byte[] selector() { + return function.selector(); + } + + public long selectorLong() { + return Bytes.wrap(function.selector()).toLong(ByteOrder.BIG_ENDIAN); + } + + public @NonNull String selectorHex() { + return function.selectorHex(); + } + + public boolean hasVariant(@NonNull final Variant variant) { + return variants.contains(variant); + } + + public boolean hasCategory(@NonNull final Category category) { + return categories.contains(category); + } + + public boolean hasCategory(@NonNull final Set categories) { + var intersection = this.categories.clone(); + intersection.retainAll(categories); + return !intersection.isEmpty(); + } + + /** + * Return the method's name (simple, undecorated) + * @return the method's name + */ + public @NonNull String methodName() { + return function.getName(); + } + + /** + * Return the method's name with variant decorations + * + * The variant decorations (e.g., `_V1` and `_V2`) distinguish overloads of the method + * @return the method names with the variants as suffix + */ + public @NonNull String variatedMethodName() { + return methodName() + variantsSuffix(); + } + + public @NonNull String fullyDecoratedMethodName() { + var name = qualifiedMethodName(); + name += modifiersSuffix(); + name += categoriesSuffix(); + return name; + } + + /** + * "Qualified" method name has the contract name in front of it, and the variants appended to it. + */ + public @NonNull String qualifiedMethodName() { + final var systemContractName = systemContract.map(Enum::name).orElse("???"); + final var methodName = + switch (via) { + case DIRECT -> systemContractName + "." + variatedMethodName(); + case PROXY -> systemContractName + "(PROXY)." + variatedMethodName(); + }; + return methodName; + } + + private @NonNull String variantsSuffix() { + if (variants.isEmpty()) return ""; + return variants.stream().map(Variant::asSuffix).sorted().collect(Collectors.joining("_", "_", "")); + } + + private @NonNull String categoriesSuffix() { + if (categories.isEmpty()) return ""; + return categories.stream().map(Category::asSuffix).sorted().collect(Collectors.joining(",", "_[", "]")); + } + + private @NonNull String modifiersSuffix() { + if (modifier.isEmpty()) return ""; + return "_[" + modifier.get().asSuffix() + "]"; + } +} diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/utils/SystemContractMethodRegistry.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/utils/SystemContractMethodRegistry.java new file mode 100644 index 000000000000..5a1ac4ad97d6 --- /dev/null +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/utils/SystemContractMethodRegistry.java @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2024-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.utils; + +import static java.util.Comparator.comparing; +import static java.util.Objects.requireNonNull; + +import com.google.common.annotations.VisibleForTesting; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.CallVia; +import edu.umd.cs.findbugs.annotations.NonNull; +import java.util.Collection; +import java.util.SequencedCollection; +import java.util.concurrent.ConcurrentHashMap; +import javax.inject.Inject; +import javax.inject.Singleton; + +/** + * A registry for all the system contract methods - their names, selectors, and signatures. + * + * Methods are added to this registry when they're defined in the various `FooTranslator` classes, + * which, since they're all (or should be) Dagger singletons, is done as the smart contract service + * is coming up. Thus, the completed registry is available once processing starts, and so is ready + * for use to enumerate all system contract methods. + * + * The principal use case for this registry is to be able to generate various per-system-contract-method + * metrics. + */ +@Singleton +public class SystemContractMethodRegistry { + + private static final int EXPECTED_SYSTEM_CONTRACT_METHODS_UPPER_BOUND = 250; + private final ConcurrentHashMap byName = + new ConcurrentHashMap<>(EXPECTED_SYSTEM_CONTRACT_METHODS_UPPER_BOUND); + + // The static constant `SystemContractMethod`s in each of the translator classes do _not_ have + // the `SystemContract` field set. That's set later after all the static fields are created. + // So there needs to be a way to get from the version _without_ the system contract to the version + // _with_ the system contract. That's this map. + // + // Thus, in the running system there are two instances of `SystemContractMethod` for each system + // contract method: One without the `SystemContract`, one with. This is an acceptable fixed + // overhead. Alternative would have been to bite the bullet and explicitly set the system contract + // field in the constructor of each of the static constants in each of the translator classes. + // Perhaps that's a refactor that would be worth it sometime. + private final ConcurrentHashMap withoutToWithSystemContract = + new ConcurrentHashMap<>(EXPECTED_SYSTEM_CONTRACT_METHODS_UPPER_BOUND); + + @Inject + public SystemContractMethodRegistry() { + requireNonNull(SystemContractMethod.SystemContract.HTS); // DEBUGGING + } + + /** + * Add a system contract method into the registry of system contract methods + */ + public void register( + @NonNull final SystemContractMethod systemContractMethodWithoutContract, + @NonNull final SystemContractMethod systemContractMethodWithContract) { + requireNonNull(systemContractMethodWithoutContract); + requireNonNull(systemContractMethodWithContract); + + var keyName = systemContractMethodWithContract.variatedMethodName(); + if (systemContractMethodWithContract.via() == CallVia.PROXY) + keyName += systemContractMethodWithContract.via().asSuffix(); + + byName.putIfAbsent(keyName, systemContractMethodWithContract); + withoutToWithSystemContract.putIfAbsent(systemContractMethodWithoutContract, systemContractMethodWithContract); + } + + // Queries: + + public long size() { + return byName.size(); + } + + public @NonNull SystemContractMethod fromMissingContractGetWithContract( + @NonNull final SystemContractMethod systemContractMethodWithoutContract) { + if (systemContractMethodWithoutContract.systemContract().isPresent()) + return systemContractMethodWithoutContract; + else return withoutToWithSystemContract.get(systemContractMethodWithoutContract); + } + + public @NonNull SequencedCollection allQualifiedMethods() { + return allMethodsGivenMapper(SystemContractMethod::qualifiedMethodName); + } + + public @NonNull SequencedCollection allSignatures() { + return allMethodsGivenMapper(SystemContractMethod::signature); + } + + public @NonNull SequencedCollection allSignaturesWithReturns() { + return allMethodsGivenMapper(SystemContractMethod::signatureWithReturn); + } + + public @NonNull SequencedCollection allMethodsGivenMapper( + @NonNull final java.util.function.Function methodMapper) { + return byName.values().stream().map(methodMapper).sorted().toList(); + } + + public @NonNull Collection allMethods() { + return byName.values(); + } + + @VisibleForTesting + public @NonNull String allMethodsAsTable() { + final var allMethods = allMethods().stream() + .sorted(comparing(SystemContractMethod::qualifiedMethodName)) + .toList(); + final var sb = new StringBuilder(); + for (final var method : allMethods) { + sb.append("%s: 0x%s - %s\n" + .formatted(method.qualifiedMethodName(), method.selectorHex(), method.signatureWithReturn())); + } + return sb.toString(); + } +} diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/handlers/AbstractContractTransactionHandler.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/handlers/AbstractContractTransactionHandler.java index f2ab8b4aeb79..5d65440ce327 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/handlers/AbstractContractTransactionHandler.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/handlers/AbstractContractTransactionHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2024 Hedera Hashgraph, LLC + * Copyright (C) 2024-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. @@ -104,4 +104,9 @@ protected void bumpExceptionMetrics(@NonNull final HederaFunctionality functiona @NonNull final SigValueObj sigValObj) { throw new IllegalStateException("must be overridden if `calculateFees` _not_ overridden"); } + + protected @NonNull TransactionComponent getTransactionComponent( + @NonNull final HandleContext context, @NonNull final HederaFunctionality functionality) { + return provider.get().create(context, functionality); + } } diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/handlers/ContractCallHandler.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/handlers/ContractCallHandler.java index 33eaf3c5a5c8..55def5f6c095 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/handlers/ContractCallHandler.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/handlers/ContractCallHandler.java @@ -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. @@ -65,7 +65,7 @@ public ContractCallHandler( @Override public void handle(@NonNull final HandleContext context) throws HandleException { // Create the transaction-scoped component - final var component = provider.get().create(context, CONTRACT_CALL); + final var component = getTransactionComponent(context, CONTRACT_CALL); // Run its in-scope transaction and get the outcome final var outcome = component.contextTransactionProcessor().call(); diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/handlers/ContractCallLocalHandler.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/handlers/ContractCallLocalHandler.java index 4c08ffcfedfd..c553a36187f4 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/handlers/ContractCallLocalHandler.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/handlers/ContractCallLocalHandler.java @@ -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. @@ -39,6 +39,7 @@ import com.hedera.hapi.node.transaction.Response; import com.hedera.node.app.hapi.utils.CommonPbjConverters; import com.hedera.node.app.hapi.utils.fee.SmartContractFeeBuilder; +import com.hedera.node.app.service.contract.impl.ContractServiceComponent; import com.hedera.node.app.service.contract.impl.exec.QueryComponent; import com.hedera.node.app.service.contract.impl.exec.QueryComponent.Factory; import com.hedera.node.app.service.token.ReadableAccountStore; @@ -65,6 +66,7 @@ public class ContractCallLocalHandler extends PaidQueryHandler { private final Provider provider; private final GasCalculator gasCalculator; private final InstantSource instantSource; + private final ContractServiceComponent contractServiceComponent; /** * Constructs a {@link ContractCreateHandler} with the given {@link Provider}, {@link GasCalculator} and {@link InstantSource}. @@ -77,10 +79,12 @@ public class ContractCallLocalHandler extends PaidQueryHandler { public ContractCallLocalHandler( @NonNull final Provider provider, @NonNull final GasCalculator gasCalculator, - @NonNull final InstantSource instantSource) { + @NonNull final InstantSource instantSource, + @NonNull final ContractServiceComponent contractServiceComponent) { this.provider = requireNonNull(provider); this.gasCalculator = requireNonNull(gasCalculator); this.instantSource = requireNonNull(instantSource); + this.contractServiceComponent = requireNonNull(contractServiceComponent); } @Override @@ -142,6 +146,7 @@ public Response findResponse(@NonNull final QueryContext context, @NonNull final requireNonNull(header); final var component = provider.get().create(context, instantSource.instant(), CONTRACT_CALL_LOCAL); + final var outcome = component.contextQueryProcessor().call(); final var responseHeader = outcome.isSuccess() diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/handlers/ContractCreateHandler.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/handlers/ContractCreateHandler.java index c5b05858dd09..d1d390477320 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/handlers/ContractCreateHandler.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/handlers/ContractCreateHandler.java @@ -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. @@ -68,7 +68,7 @@ public ContractCreateHandler( @Override public void handle(@NonNull final HandleContext context) throws HandleException { // Create the transaction-scoped component - final var component = provider.get().create(context, CONTRACT_CREATE); + final var component = getTransactionComponent(context, CONTRACT_CREATE); // Run its in-scope transaction and get the outcome final var outcome = component.contextTransactionProcessor().call(); diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/handlers/EthereumTransactionHandler.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/handlers/EthereumTransactionHandler.java index f93e8e890cac..3d7c419643bf 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/handlers/EthereumTransactionHandler.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/handlers/EthereumTransactionHandler.java @@ -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. @@ -155,7 +155,7 @@ public void pureChecks(@NonNull final TransactionBody txn) throws PreCheckExcept @Override public void handle(@NonNull final HandleContext context) throws HandleException { // Create the transaction-scoped component - final var component = provider.get().create(context, ETHEREUM_TRANSACTION); + final var component = getTransactionComponent(context, ETHEREUM_TRANSACTION); // Run its in-scope transaction and get the outcome final var outcome = component.contextTransactionProcessor().call(); @@ -180,7 +180,7 @@ public void handle(@NonNull final HandleContext context) throws HandleException * @param context the handle context */ public void handleThrottled(@NonNull final HandleContext context) { - final var component = provider.get().create(context, ETHEREUM_TRANSACTION); + final var component = getTransactionComponent(context, ETHEREUM_TRANSACTION); final var ethTxData = requireNonNull(requireNonNull(component.hydratedEthTxData()).ethTxData()); context.savepointStack() diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/metrics/ContractMetricsTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/metrics/ContractMetricsTest.java index b47b70bfac03..4f0986bae352 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/metrics/ContractMetricsTest.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/metrics/ContractMetricsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2024 Hedera Hashgraph, LLC + * Copyright (C) 2024-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. @@ -22,6 +22,8 @@ import com.hedera.hapi.node.base.HederaFunctionality; import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; +import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.wipe.WipeTranslator; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.config.data.ContractsConfig; import com.hedera.node.config.testfixtures.HederaTestConfigBuilder; import com.swirlds.common.metrics.config.MetricsConfig; @@ -34,6 +36,7 @@ import java.util.Map; import java.util.concurrent.Executors; import java.util.function.Supplier; +import org.hyperledger.besu.evm.frame.MessageFrame.State; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; @@ -47,9 +50,13 @@ public class ContractMetricsTest { @Mock private ContractsConfig contractsConfig; + private final SystemContractMethodRegistry systemContractMethodRegistry = new SystemContractMethodRegistry(); + public @NonNull ContractMetrics getSubject() { - final var contractMetrics = new ContractMetrics(metricsSupplier, () -> contractsConfig); - contractMetrics.createContractMetrics(); + final var contractMetrics = + new ContractMetrics(metricsSupplier, () -> contractsConfig, systemContractMethodRegistry); + contractMetrics.createContractPrimaryMetrics(); + contractMetrics.createContractSecondaryMetrics(); return contractMetrics; } @@ -69,7 +76,7 @@ public void rejectedTxCountersGetBumpedWhenEnabled() { subject.bumpRejectedType3EthTx(20); - assertThat(subject.getAllCounterNames()) + assertThat(subject.getAllP1CounterNames()) .containsExactlyInAnyOrder( "SmartContractService:Rejected_ethereumTxDueToIntrinsicGas_total", "SmartContractService:Rejected_ethereumTx_total", @@ -78,7 +85,7 @@ public void rejectedTxCountersGetBumpedWhenEnabled() { "SmartContractService:Rejected_contractCreateTxDueToIntrinsicGas_total", "SmartContractService:Rejected_contractCreateTx_total", "SmartContractService:Rejected_ethType3BlobTransaction_total"); - assertThat(subject.getAllCounters()) + assertThat(subject.getAllP1CounterValues()) .containsExactlyInAnyOrderEntriesOf(Map.of( "SmartContractService:Rejected_ethereumTxDueToIntrinsicGas_total", 14L, @@ -102,8 +109,9 @@ public void rejectedTxCountersGetBumpedWhenEnabled() { } @Test - public void rejectedTxCountersGetIgnoredWhenDisabled() { + public void countersGetIgnoredWhenDisabled() { given(contractsConfig.metricsSmartContractPrimaryEnabled()).willReturn(false); + given(contractsConfig.metricsSmartContractSecondaryEnabled()).willReturn(false); final var subject = getSubject(); @@ -117,8 +125,10 @@ public void rejectedTxCountersGetIgnoredWhenDisabled() { subject.bumpRejectedType3EthTx(20); + subject.incrementSystemMethodCall(WipeTranslator.WIPE_FUNGIBLE_V1, State.EXCEPTIONAL_HALT); + assertThat(subject.getAllCounterNames()).isEmpty(); - assertThat(subject.getAllCounters()).isEmpty(); + assertThat(subject.getAllCounterValues()).isEmpty(); } private static final long DEFAULT_NODE_ID = 3; diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/CallAttemptHelpers.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/CallAttemptHelpers.java index bd9446d89b8d..ebf2aec77e41 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/CallAttemptHelpers.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/CallAttemptHelpers.java @@ -28,6 +28,8 @@ import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hss.HssCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.AddressIdConverter; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallAttempt; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.hevm.HederaWorldUpdater; import com.hedera.node.app.service.contract.impl.test.TestHelpers; import com.hedera.node.app.spi.signatures.SignatureVerifier; @@ -55,7 +57,8 @@ public static HtsCallAttempt prepareHtsAttemptWithSelector( final HederaWorldUpdater.Enhancement enhancement, final AddressIdConverter addressIdConverter, final VerificationStrategies verificationStrategies, - final SystemContractGasCalculator gasCalculator) { + final SystemContractGasCalculator gasCalculator, + final SystemContractMethodRegistry systemContractMethodRegistry) { final var input = Bytes.wrap(function.selector()); return new HtsCallAttempt( @@ -69,6 +72,32 @@ public static HtsCallAttempt prepareHtsAttemptWithSelector( verificationStrategies, gasCalculator, List.of(translator), + systemContractMethodRegistry, + false); + } + + public static HtsCallAttempt prepareHtsAttemptWithSelector( + final SystemContractMethod systemContractMethod, + final CallTranslator translator, + final HederaWorldUpdater.Enhancement enhancement, + final AddressIdConverter addressIdConverter, + final VerificationStrategies verificationStrategies, + final SystemContractGasCalculator gasCalculator, + final SystemContractMethodRegistry systemContractMethodRegistry) { + final var input = Bytes.wrap(systemContractMethod.selector()); + + return new HtsCallAttempt( + input, + OWNER_BESU_ADDRESS, + OWNER_BESU_ADDRESS, + false, + enhancement, + DEFAULT_CONFIG, + addressIdConverter, + verificationStrategies, + gasCalculator, + List.of(translator), + systemContractMethodRegistry, false); } @@ -87,7 +116,8 @@ public static HtsCallAttempt prepareHtsAttemptWithSelectorForRedirect( final HederaWorldUpdater.Enhancement enhancement, final AddressIdConverter addressIdConverter, final VerificationStrategies verificationStrategies, - final SystemContractGasCalculator gasCalculator) { + final SystemContractGasCalculator gasCalculator, + final SystemContractMethodRegistry systemContractMethodRegistry) { final var input = TestHelpers.bytesForRedirect(function.selector(), NON_SYSTEM_LONG_ZERO_ADDRESS); return new HtsCallAttempt( @@ -101,6 +131,32 @@ public static HtsCallAttempt prepareHtsAttemptWithSelectorForRedirect( verificationStrategies, gasCalculator, List.of(translator), + systemContractMethodRegistry, + false); + } + + public static HtsCallAttempt prepareHtsAttemptWithSelectorForRedirect( + final SystemContractMethod systemContractMethod, + final CallTranslator translator, + final HederaWorldUpdater.Enhancement enhancement, + final AddressIdConverter addressIdConverter, + final VerificationStrategies verificationStrategies, + final SystemContractGasCalculator gasCalculator, + final SystemContractMethodRegistry systemContractMethodRegistry) { + final var input = TestHelpers.bytesForRedirect(systemContractMethod.selector(), NON_SYSTEM_LONG_ZERO_ADDRESS); + + return new HtsCallAttempt( + input, + OWNER_BESU_ADDRESS, + OWNER_BESU_ADDRESS, + false, + enhancement, + DEFAULT_CONFIG, + addressIdConverter, + verificationStrategies, + gasCalculator, + List.of(translator), + systemContractMethodRegistry, false); } @@ -121,6 +177,7 @@ public static HtsCallAttempt prepareHtsAttemptWithSelectorForRedirectWithConfig( final AddressIdConverter addressIdConverter, final VerificationStrategies verificationStrategies, final SystemContractGasCalculator gasCalculator, + final SystemContractMethodRegistry systemContractMethodRegistry, final Configuration config) { final var input = TestHelpers.bytesForRedirect(function.selector(), NON_SYSTEM_LONG_ZERO_ADDRESS); @@ -135,6 +192,33 @@ public static HtsCallAttempt prepareHtsAttemptWithSelectorForRedirectWithConfig( verificationStrategies, gasCalculator, List.of(translator), + systemContractMethodRegistry, + false); + } + + public static HtsCallAttempt prepareHtsAttemptWithSelectorForRedirectWithConfig( + final SystemContractMethod systemContractMethod, + final CallTranslator translator, + final HederaWorldUpdater.Enhancement enhancement, + final AddressIdConverter addressIdConverter, + final VerificationStrategies verificationStrategies, + final SystemContractGasCalculator gasCalculator, + final SystemContractMethodRegistry systemContractMethodRegistry, + final Configuration config) { + final var input = TestHelpers.bytesForRedirect(systemContractMethod.selector(), NON_SYSTEM_LONG_ZERO_ADDRESS); + + return new HtsCallAttempt( + input, + OWNER_BESU_ADDRESS, + OWNER_BESU_ADDRESS, + false, + enhancement, + config, + addressIdConverter, + verificationStrategies, + gasCalculator, + List.of(translator), + systemContractMethodRegistry, false); } @@ -155,6 +239,7 @@ public static HtsCallAttempt prepareHtsAttemptWithSelectorAndCustomConfig( final AddressIdConverter addressIdConverter, final VerificationStrategies verificationStrategies, final SystemContractGasCalculator gasCalculator, + final SystemContractMethodRegistry systemContractMethodRegistry, final Configuration config) { final var input = Bytes.wrap(function.selector()); @@ -169,11 +254,38 @@ public static HtsCallAttempt prepareHtsAttemptWithSelectorAndCustomConfig( verificationStrategies, gasCalculator, List.of(translator), + systemContractMethodRegistry, + false); + } + + public static HtsCallAttempt prepareHtsAttemptWithSelectorAndCustomConfig( + final SystemContractMethod systemContractMethod, + final CallTranslator translator, + final HederaWorldUpdater.Enhancement enhancement, + final AddressIdConverter addressIdConverter, + final VerificationStrategies verificationStrategies, + final SystemContractGasCalculator gasCalculator, + final SystemContractMethodRegistry systemContractMethodRegistry, + final Configuration config) { + final var input = Bytes.wrap(systemContractMethod.selector()); + + return new HtsCallAttempt( + input, + OWNER_BESU_ADDRESS, + OWNER_BESU_ADDRESS, + false, + enhancement, + config, + addressIdConverter, + verificationStrategies, + gasCalculator, + List.of(translator), + systemContractMethodRegistry, false); } /** - * @param function the selector to match against + * @param systemContractMethod the selector to match against (as a `SystemContractMethod`) * @param translator the translator for this specific call attempt * @param enhancement the enhancement that is used * @param addressIdConverter the address ID converter for this call @@ -183,26 +295,28 @@ public static HtsCallAttempt prepareHtsAttemptWithSelectorAndCustomConfig( * @return the call attempt */ public static HasCallAttempt prepareHasAttemptWithSelector( - final Function function, + final SystemContractMethod systemContractMethod, final CallTranslator translator, final HederaWorldUpdater.Enhancement enhancement, final AddressIdConverter addressIdConverter, final VerificationStrategies verificationStrategies, final SignatureVerifier signatureVerifier, - final SystemContractGasCalculator gasCalculator) { + final SystemContractGasCalculator gasCalculator, + final SystemContractMethodRegistry systemContractMethodRegistry) { return prepareHasAttemptWithSelectorAndCustomConfig( - function, + systemContractMethod, translator, enhancement, addressIdConverter, verificationStrategies, signatureVerifier, gasCalculator, + systemContractMethodRegistry, DEFAULT_CONFIG); } /** - * @param function the selector to match against + * @param systemContractMethod the selector to match against (as a `SystemContractMethod`) * @param translator the translator for this specific call attempt * @param enhancement the enhancement that is used * @param addressIdConverter the address ID converter for this call @@ -213,28 +327,29 @@ public static HasCallAttempt prepareHasAttemptWithSelector( * @return the call attempt */ public static HasCallAttempt prepareHasAttemptWithSelectorAndCustomConfig( - final Function function, + final SystemContractMethod systemContractMethod, final CallTranslator translator, final HederaWorldUpdater.Enhancement enhancement, final AddressIdConverter addressIdConverter, final VerificationStrategies verificationStrategies, final SignatureVerifier signatureVerifier, final SystemContractGasCalculator gasCalculator, + final SystemContractMethodRegistry systemContractMethodRegistry, final Configuration config) { return prepareHasAttemptWithSelectorAndInputAndCustomConfig( - function, - TestHelpers.bytesForRedirectAccount(function.selector(), NON_SYSTEM_LONG_ZERO_ADDRESS), + systemContractMethod, + TestHelpers.bytesForRedirectAccount(systemContractMethod.selector(), NON_SYSTEM_LONG_ZERO_ADDRESS), translator, enhancement, addressIdConverter, verificationStrategies, signatureVerifier, gasCalculator, + systemContractMethodRegistry, config); } /** - * @param function the selector to match against * @param input the input in bytes * @param translator the translator for this specific call attempt * @param enhancement the enhancement that is used @@ -246,7 +361,6 @@ public static HasCallAttempt prepareHasAttemptWithSelectorAndCustomConfig( * @return the call attempt */ public static HasCallAttempt prepareHasAttemptWithSelectorAndInputAndCustomConfig( - final Function function, final Bytes input, final CallTranslator translator, final HederaWorldUpdater.Enhancement enhancement, @@ -254,6 +368,33 @@ public static HasCallAttempt prepareHasAttemptWithSelectorAndInputAndCustomConfi final VerificationStrategies verificationStrategies, final SignatureVerifier signatureVerifier, final SystemContractGasCalculator gasCalculator, + final SystemContractMethodRegistry systemContractMethodRegistry, + final Configuration config) { + return new HasCallAttempt( + input, + OWNER_BESU_ADDRESS, + false, + enhancement, + config, + addressIdConverter, + verificationStrategies, + signatureVerifier, + gasCalculator, + List.of(translator), + systemContractMethodRegistry, + false); + } + + public static HasCallAttempt prepareHasAttemptWithSelectorAndInputAndCustomConfig( + final SystemContractMethod systemContractMethod, + final Bytes input, + final CallTranslator translator, + final HederaWorldUpdater.Enhancement enhancement, + final AddressIdConverter addressIdConverter, + final VerificationStrategies verificationStrategies, + final SignatureVerifier signatureVerifier, + final SystemContractGasCalculator gasCalculator, + final SystemContractMethodRegistry systemContractMethodRegistry, final Configuration config) { return new HasCallAttempt( input, @@ -266,11 +407,12 @@ public static HasCallAttempt prepareHasAttemptWithSelectorAndInputAndCustomConfi signatureVerifier, gasCalculator, List.of(translator), + systemContractMethodRegistry, false); } /** - * @param function the selector to match against + * @param systemContractMethod the selector to match against (as a `SystemContractMethod`) * @param translator the translator for this specific call attempt * @param enhancement the enhancement that is used * @param addressIdConverter the address ID converter for this call @@ -280,15 +422,43 @@ public static HasCallAttempt prepareHasAttemptWithSelectorAndInputAndCustomConfi * @return the call attempt */ public static HssCallAttempt prepareHssAttemptWithSelectorAndCustomConfig( - final Function function, + final SystemContractMethod systemContractMethod, final CallTranslator translator, final HederaWorldUpdater.Enhancement enhancement, final AddressIdConverter addressIdConverter, final VerificationStrategies verificationStrategies, final SignatureVerifier signatureVerifier, final SystemContractGasCalculator gasCalculator, + final SystemContractMethodRegistry systemContractMethodRegistry, final Configuration config) { - final var input = Bytes.wrap(function.selector()); + final var input = Bytes.wrap(systemContractMethod.selector()); + + return new HssCallAttempt( + input, + OWNER_BESU_ADDRESS, + false, + enhancement, + config, + addressIdConverter, + verificationStrategies, + signatureVerifier, + gasCalculator, + List.of(translator), + systemContractMethodRegistry, + false); + } + + public static HssCallAttempt prepareHssAttemptWithSelectorAndCustomConfig( + final SystemContractMethod systemContractMethod, + final CallTranslator translator, + final HederaWorldUpdater.Enhancement enhancement, + final AddressIdConverter addressIdConverter, + final VerificationStrategies verificationStrategies, + final SystemContractGasCalculator gasCalculator, + final SignatureVerifier signatureVerifier, + final SystemContractMethodRegistry systemContractMethodRegistry, + final Configuration config) { + final var input = Bytes.wrap(systemContractMethod.selector()); return new HssCallAttempt( input, @@ -301,6 +471,7 @@ public static HssCallAttempt prepareHssAttemptWithSelectorAndCustomConfig( signatureVerifier, gasCalculator, List.of(translator), + systemContractMethodRegistry, false); } @@ -312,6 +483,7 @@ public static HssCallAttempt prepareHssAttemptWithBytesAndCustomConfig( final VerificationStrategies verificationStrategies, final SignatureVerifier signatureVerifier, final SystemContractGasCalculator gasCalculator, + final SystemContractMethodRegistry systemContractMethodRegistry, final Configuration config) { return new HssCallAttempt( @@ -325,6 +497,7 @@ public static HssCallAttempt prepareHssAttemptWithBytesAndCustomConfig( signatureVerifier, gasCalculator, List.of(translator), + systemContractMethodRegistry, false); } @@ -336,6 +509,7 @@ public static HssCallAttempt prepareHssAttemptWithBytesAndCustomConfigAndDelegat final VerificationStrategies verificationStrategies, final SignatureVerifier signatureVerifier, final SystemContractGasCalculator gasCalculator, + final SystemContractMethodRegistry systemContractMethodRegistry, final Configuration config) { return new HssCallAttempt( @@ -349,6 +523,7 @@ public static HssCallAttempt prepareHssAttemptWithBytesAndCustomConfigAndDelegat signatureVerifier, gasCalculator, List.of(translator), + systemContractMethodRegistry, false); } } diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/HasSystemContractTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/HasSystemContractTest.java index 7109dd2a083e..91c9f9c2c1a9 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/HasSystemContractTest.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/HasSystemContractTest.java @@ -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. @@ -22,6 +22,7 @@ import static com.hedera.node.app.service.contract.impl.test.TestHelpers.assertSamePrecompileResult; import static org.mockito.Mockito.when; +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.has.HasCallFactory; import com.hedera.node.app.service.contract.impl.exec.utils.FrameUtils; @@ -52,6 +53,9 @@ class HasSystemContractTest { @Mock private GasCalculator gasCalculator; + @Mock + private ContractMetrics contractMetrics; + private MockedStatic frameUtils; private HasSystemContract subject; @@ -60,7 +64,7 @@ class HasSystemContractTest { @BeforeEach void setUp() { frameUtils = Mockito.mockStatic(FrameUtils.class); - subject = new HasSystemContract(gasCalculator, attemptFactory); + subject = new HasSystemContract(gasCalculator, attemptFactory, contractMetrics); } @AfterEach diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/HssSystemContractTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/HssSystemContractTest.java index 88be76d82ffb..16e1c72628e8 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/HssSystemContractTest.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/HssSystemContractTest.java @@ -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. @@ -22,6 +22,7 @@ import static com.hedera.node.app.service.contract.impl.test.TestHelpers.assertSamePrecompileResult; import static org.mockito.Mockito.when; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.HssSystemContract; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hss.HssCallFactory; import com.hedera.node.app.service.contract.impl.exec.utils.FrameUtils; @@ -52,6 +53,9 @@ class HssSystemContractTest { @Mock private GasCalculator gasCalculator; + @Mock + private ContractMetrics contractMetrics; + private MockedStatic frameUtils; private HssSystemContract subject; @@ -60,7 +64,7 @@ class HssSystemContractTest { @BeforeEach void setUp() { frameUtils = Mockito.mockStatic(FrameUtils.class); - subject = new HssSystemContract(gasCalculator, attemptFactory); + subject = new HssSystemContract(gasCalculator, attemptFactory, contractMetrics); } @AfterEach diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/HtsSystemContractTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/HtsSystemContractTest.java index 27a57285961a..e991977d6582 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/HtsSystemContractTest.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/HtsSystemContractTest.java @@ -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. @@ -29,6 +29,7 @@ import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.lenient; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.scope.SystemContractOperations; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.HtsSystemContract; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.Call; @@ -78,6 +79,9 @@ class HtsSystemContractTest { @Mock private GasCalculator gasCalculator; + @Mock + private ContractMetrics contractMetrics; + private MockedStatic frameUtils; private HtsSystemContract subject; @@ -86,7 +90,7 @@ class HtsSystemContractTest { @BeforeEach void setUp() { frameUtils = Mockito.mockStatic(FrameUtils.class); - subject = new HtsSystemContract(gasCalculator, attemptFactory); + subject = new HtsSystemContract(gasCalculator, attemptFactory, contractMetrics); } @AfterEach diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/has/HasCallAttemptTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/has/HasCallAttemptTest.java index d27d040adf6e..f89e014f5af9 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/has/HasCallAttemptTest.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/has/HasCallAttemptTest.java @@ -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. @@ -28,6 +28,7 @@ import static org.junit.jupiter.api.Assertions.assertNull; import static org.mockito.BDDMockito.given; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.scope.VerificationStrategies; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.CallTranslator; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.has.HasCallAttempt; @@ -36,6 +37,7 @@ import com.hedera.node.app.service.contract.impl.exec.systemcontracts.has.hbarapprove.HbarApproveCall; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.has.hbarapprove.HbarApproveTranslator; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.AddressIdConverter; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.test.TestHelpers; import com.hedera.node.app.service.contract.impl.test.exec.systemcontracts.common.CallTestBase; import com.hedera.node.app.spi.signatures.SignatureVerifier; @@ -56,11 +58,18 @@ class HasCallAttemptTest extends CallTestBase { @Mock private AddressIdConverter addressIdConverter; + @Mock + private ContractMetrics contractMetrics; + private List> callTranslators; + private final SystemContractMethodRegistry systemContractMethodRegistry = new SystemContractMethodRegistry(); + @BeforeEach void setUp() { - callTranslators = List.of(new HbarAllowanceTranslator(), new HbarApproveTranslator()); + callTranslators = List.of( + new HbarAllowanceTranslator(systemContractMethodRegistry, contractMetrics), + new HbarApproveTranslator(systemContractMethodRegistry, contractMetrics)); } @Test @@ -80,6 +89,7 @@ void returnNullAccountIfAccountNotFound() { signatureVerifier, gasCalculator, callTranslators, + systemContractMethodRegistry, false); assertNull(subject.redirectAccount()); } @@ -98,6 +108,7 @@ void invalidSelectorLeadsToMissingCall() { signatureVerifier, gasCalculator, callTranslators, + systemContractMethodRegistry, false); assertNull(subject.asExecutableCall()); } @@ -122,6 +133,7 @@ void constructsHbarAllowanceProxy() { signatureVerifier, gasCalculator, callTranslators, + systemContractMethodRegistry, false); assertInstanceOf(HbarAllowanceCall.class, subject.asExecutableCall()); } @@ -148,6 +160,7 @@ void constructsHbarAllowanceDirect() { signatureVerifier, gasCalculator, callTranslators, + systemContractMethodRegistry, false); assertInstanceOf(HbarAllowanceCall.class, subject.asExecutableCall()); } @@ -174,6 +187,7 @@ void constructsHbarApproveProxy() { signatureVerifier, gasCalculator, callTranslators, + systemContractMethodRegistry, false); assertInstanceOf(HbarApproveCall.class, subject.asExecutableCall()); } @@ -201,6 +215,7 @@ void constructsHbarApproveDirect() { signatureVerifier, gasCalculator, callTranslators, + systemContractMethodRegistry, false); assertInstanceOf(HbarApproveCall.class, subject.asExecutableCall()); } 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 762cab3c5c75..a91ae8f9477d 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 @@ -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. @@ -30,6 +30,7 @@ import static org.mockito.BDDMockito.given; import com.hedera.node.app.service.contract.impl.exec.gas.SystemContractGasCalculator; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.scope.VerificationStrategies; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.CallAddressChecks; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.has.HasCallFactory; @@ -38,6 +39,7 @@ import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.AddressIdConverter; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.SyntheticIds; import com.hedera.node.app.service.contract.impl.exec.utils.FrameUtils; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.state.ProxyWorldUpdater; import com.hedera.node.app.service.contract.impl.test.exec.systemcontracts.common.CallTestBase; import com.hedera.node.app.spi.signatures.SignatureVerifier; @@ -77,11 +79,16 @@ class HasCallFactoryTest extends CallTestBase { @Mock private MessageFrame initialFrame; - private Deque stack = new ArrayDeque<>(); + private final Deque stack = new ArrayDeque<>(); @Mock private ProxyWorldUpdater updater; + @Mock + private ContractMetrics contractMetrics; + + private final SystemContractMethodRegistry systemContractMethodRegistry = new SystemContractMethodRegistry(); + private HasCallFactory subject; @BeforeEach @@ -91,7 +98,8 @@ void setUp() { addressChecks, verificationStrategies, signatureVerifier, - List.of(new HbarAllowanceTranslator())); + List.of(new HbarAllowanceTranslator(systemContractMethodRegistry, contractMetrics)), + systemContractMethodRegistry); } @Test diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/has/evmaddressalias/EvmAddressAliasTranslatorTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/has/evmaddressalias/EvmAddressAliasTranslatorTest.java index 6e32d80b0db6..0009b0748e39 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/has/evmaddressalias/EvmAddressAliasTranslatorTest.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/has/evmaddressalias/EvmAddressAliasTranslatorTest.java @@ -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. @@ -22,18 +22,18 @@ import static com.hedera.node.app.service.contract.impl.test.exec.systemcontracts.CallAttemptHelpers.prepareHasAttemptWithSelector; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.BDDMockito.given; import com.esaulpaugh.headlong.abi.Tuple; import com.hedera.node.app.service.contract.impl.exec.gas.SystemContractGasCalculator; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.scope.HederaNativeOperations; import com.hedera.node.app.service.contract.impl.exec.scope.VerificationStrategies; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.has.HasCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.has.getevmaddressalias.EvmAddressAliasCall; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.has.getevmaddressalias.EvmAddressAliasTranslator; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.AddressIdConverter; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.hevm.HederaWorldUpdater; import com.hedera.node.app.spi.signatures.SignatureVerifier; import org.apache.tuweni.bytes.Bytes; @@ -66,11 +66,16 @@ class EvmAddressAliasTranslatorTest { @Mock private HederaNativeOperations nativeOperations; + @Mock + private ContractMetrics contractMetrics; + + private final SystemContractMethodRegistry systemContractMethodRegistry = new SystemContractMethodRegistry(); + private EvmAddressAliasTranslator subject; @BeforeEach void setUp() { - subject = new EvmAddressAliasTranslator(); + subject = new EvmAddressAliasTranslator(systemContractMethodRegistry, contractMetrics); } @Test @@ -83,8 +88,9 @@ void matchesEvmAddressAlias() { addressIdConverter, verificationStrategies, signatureVerifier, - gasCalculator); - assertTrue(subject.matches(attempt)); + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isPresent(); assertEquals("0xdea3d081" /*copied from HIP-632*/, "0x" + EVM_ADDRESS_ALIAS.selectorHex()); } @@ -98,8 +104,9 @@ void failsOnInvalidSelector() { addressIdConverter, verificationStrategies, signatureVerifier, - gasCalculator); - assertFalse(subject.matches(attempt)); + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isEmpty(); } @Test diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/has/hbarAllowance/HbarAllowanceTranslatorTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/has/hbarAllowance/HbarAllowanceTranslatorTest.java index 90dd7017d092..afffc9f28781 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/has/hbarAllowance/HbarAllowanceTranslatorTest.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/has/hbarAllowance/HbarAllowanceTranslatorTest.java @@ -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. @@ -25,18 +25,18 @@ import static com.hedera.node.app.service.contract.impl.test.TestHelpers.UNAUTHORIZED_SPENDER_HEADLONG_ADDRESS; import static com.hedera.node.app.service.contract.impl.test.exec.systemcontracts.CallAttemptHelpers.prepareHasAttemptWithSelector; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.BDDMockito.given; import com.esaulpaugh.headlong.abi.Tuple; import com.hedera.node.app.service.contract.impl.exec.gas.SystemContractGasCalculator; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.scope.HederaNativeOperations; import com.hedera.node.app.service.contract.impl.exec.scope.VerificationStrategies; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.has.HasCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.has.hbarallowance.HbarAllowanceCall; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.has.hbarallowance.HbarAllowanceTranslator; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.AddressIdConverter; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.hevm.HederaWorldUpdater; import com.hedera.node.app.spi.signatures.SignatureVerifier; import org.apache.tuweni.bytes.Bytes; @@ -69,11 +69,16 @@ public class HbarAllowanceTranslatorTest { @Mock private HederaNativeOperations nativeOperations; + @Mock + private ContractMetrics contractMetrics; + + private final SystemContractMethodRegistry systemContractMethodRegistry = new SystemContractMethodRegistry(); + private HbarAllowanceTranslator subject; @BeforeEach void setUp() { - subject = new HbarAllowanceTranslator(); + subject = new HbarAllowanceTranslator(systemContractMethodRegistry, contractMetrics); } @Test @@ -86,8 +91,9 @@ void matchesHbarAllowance() { addressIdConverter, verificationStrategies, signatureVerifier, - gasCalculator); - assertTrue(subject.matches(attempt)); + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isPresent(); attempt = prepareHasAttemptWithSelector( HBAR_ALLOWANCE_PROXY, @@ -96,8 +102,9 @@ void matchesHbarAllowance() { addressIdConverter, verificationStrategies, signatureVerifier, - gasCalculator); - assertTrue(subject.matches(attempt)); + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test @@ -110,8 +117,9 @@ void failsOnInvalidSelector() { addressIdConverter, verificationStrategies, signatureVerifier, - gasCalculator); - assertFalse(subject.matches(attempt)); + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isEmpty(); } @Test diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/has/hbarApprove/HbarApproveTranslatorTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/has/hbarApprove/HbarApproveTranslatorTest.java index 706aa22cba96..5e122dbf5a7e 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/has/hbarApprove/HbarApproveTranslatorTest.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/has/hbarApprove/HbarApproveTranslatorTest.java @@ -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. @@ -25,18 +25,18 @@ import static com.hedera.node.app.service.contract.impl.test.TestHelpers.UNAUTHORIZED_SPENDER_HEADLONG_ADDRESS; import static com.hedera.node.app.service.contract.impl.test.exec.systemcontracts.CallAttemptHelpers.prepareHasAttemptWithSelector; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.BDDMockito.given; import com.esaulpaugh.headlong.abi.Tuple; import com.hedera.node.app.service.contract.impl.exec.gas.SystemContractGasCalculator; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.scope.HederaNativeOperations; import com.hedera.node.app.service.contract.impl.exec.scope.VerificationStrategies; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.has.HasCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.has.hbarapprove.HbarApproveCall; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.has.hbarapprove.HbarApproveTranslator; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.AddressIdConverter; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.hevm.HederaWorldUpdater; import com.hedera.node.app.spi.signatures.SignatureVerifier; import java.math.BigInteger; @@ -70,11 +70,16 @@ public class HbarApproveTranslatorTest { @Mock private HederaNativeOperations nativeOperations; + @Mock + private ContractMetrics contractMetrics; + + private final SystemContractMethodRegistry systemContractMethodRegistry = new SystemContractMethodRegistry(); + private HbarApproveTranslator subject; @BeforeEach void setUp() { - subject = new HbarApproveTranslator(); + subject = new HbarApproveTranslator(systemContractMethodRegistry, contractMetrics); } @Test @@ -87,8 +92,9 @@ void matchesHbarApprove() { addressIdConverter, verificationStrategies, signatureVerifier, - gasCalculator); - assertTrue(subject.matches(attempt)); + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isPresent(); attempt = prepareHasAttemptWithSelector( HBAR_APPROVE_PROXY, @@ -97,8 +103,9 @@ void matchesHbarApprove() { addressIdConverter, verificationStrategies, signatureVerifier, - gasCalculator); - assertTrue(subject.matches(attempt)); + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test @@ -111,8 +118,9 @@ void failsOnInvalidSelector() { addressIdConverter, verificationStrategies, signatureVerifier, - gasCalculator); - assertFalse(subject.matches(attempt)); + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isEmpty(); } @Test diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/has/hederaaccountnumalias/HederaAccountNumAliasTranslatorTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/has/hederaaccountnumalias/HederaAccountNumAliasTranslatorTest.java index b70092cde1e9..1c822d84b644 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/has/hederaaccountnumalias/HederaAccountNumAliasTranslatorTest.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/has/hederaaccountnumalias/HederaAccountNumAliasTranslatorTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2024 Hedera Hashgraph, LLC + * Copyright (C) 2024-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. @@ -22,18 +22,18 @@ import static com.hedera.node.app.service.contract.impl.test.exec.systemcontracts.CallAttemptHelpers.prepareHasAttemptWithSelector; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.BDDMockito.given; import com.esaulpaugh.headlong.abi.Tuple; import com.hedera.node.app.service.contract.impl.exec.gas.SystemContractGasCalculator; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.scope.HederaNativeOperations; import com.hedera.node.app.service.contract.impl.exec.scope.VerificationStrategies; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.has.HasCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.has.hederaaccountnumalias.HederaAccountNumAliasCall; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.has.hederaaccountnumalias.HederaAccountNumAliasTranslator; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.AddressIdConverter; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.hevm.HederaWorldUpdater; import com.hedera.node.app.spi.signatures.SignatureVerifier; import org.apache.tuweni.bytes.Bytes; @@ -67,11 +67,16 @@ public class HederaAccountNumAliasTranslatorTest { @Mock private HederaNativeOperations nativeOperations; + @Mock + private ContractMetrics contractMetrics; + + private final SystemContractMethodRegistry systemContractMethodRegistry = new SystemContractMethodRegistry(); + private HederaAccountNumAliasTranslator subject; @BeforeEach void setUp() { - subject = new HederaAccountNumAliasTranslator(); + subject = new HederaAccountNumAliasTranslator(systemContractMethodRegistry, contractMetrics); } @Test @@ -84,8 +89,9 @@ void matchesHederaAccountNumAlias() { addressIdConverter, verificationStrategies, signatureVerifier, - gasCalculator); - assertTrue(subject.matches(attempt)); + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isPresent(); assertEquals("0xbbf12d2e" /*copied from HIP-632*/, "0x" + HEDERA_ACCOUNT_NUM_ALIAS.selectorHex()); } @@ -99,8 +105,9 @@ void failsOnInvalidSelector() { addressIdConverter, verificationStrategies, signatureVerifier, - gasCalculator); - assertFalse(subject.matches(attempt)); + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isEmpty(); } @Test diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/has/isauthorized/IsAuthorizedTranslatorTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/has/isauthorized/IsAuthorizedTranslatorTest.java index fd2ab6294a5c..a9f355517d78 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/has/isauthorized/IsAuthorizedTranslatorTest.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/has/isauthorized/IsAuthorizedTranslatorTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2024 Hedera Hashgraph, LLC + * Copyright (C) 2024-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. @@ -24,19 +24,19 @@ import static com.hedera.node.app.service.contract.impl.test.exec.systemcontracts.CallAttemptHelpers.prepareHasAttemptWithSelectorAndCustomConfig; import static com.hedera.node.app.service.contract.impl.test.exec.systemcontracts.CallAttemptHelpers.prepareHasAttemptWithSelectorAndInputAndCustomConfig; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.BDDMockito.given; import com.esaulpaugh.headlong.abi.Tuple; import com.hedera.node.app.service.contract.impl.exec.gas.CustomGasCalculator; import com.hedera.node.app.service.contract.impl.exec.gas.SystemContractGasCalculator; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.scope.HederaNativeOperations; import com.hedera.node.app.service.contract.impl.exec.scope.VerificationStrategies; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.has.HasCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.has.isauthorized.IsAuthorizedCall; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.has.isauthorized.IsAuthorizedTranslator; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.AddressIdConverter; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.exec.v051.Version051FeatureFlags; import com.hedera.node.app.service.contract.impl.hevm.HederaWorldUpdater; import com.hedera.node.app.spi.signatures.SignatureVerifier; @@ -78,12 +78,18 @@ public class IsAuthorizedTranslatorTest { @Mock private HederaNativeOperations nativeOperations; + @Mock + private ContractMetrics contractMetrics; + + private final SystemContractMethodRegistry systemContractMethodRegistry = new SystemContractMethodRegistry(); + private IsAuthorizedTranslator subject; @BeforeEach void setUp() { final var featureFlags = new Version051FeatureFlags(); - subject = new IsAuthorizedTranslator(featureFlags, customGasCalculator); + subject = new IsAuthorizedTranslator( + featureFlags, customGasCalculator, systemContractMethodRegistry, contractMetrics); given(enhancement.nativeOperations()).willReturn(nativeOperations); } @@ -98,8 +104,9 @@ void matchesIsAuthorizedWhenEnabled() { verificationStrategies, signatureVerifier, gasCalculator, + systemContractMethodRegistry, getTestConfiguration(true)); - assertTrue(subject.matches(attempt)); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test @@ -112,8 +119,9 @@ void doesNotMatchIsAuthorizedWhenDisabled() { verificationStrategies, signatureVerifier, gasCalculator, + systemContractMethodRegistry, getTestConfiguration(false)); - assertFalse(subject.matches(attempt)); + assertThat(subject.identifyMethod(attempt)).isEmpty(); } @Test @@ -126,8 +134,9 @@ void failsOnInvalidSelector() { verificationStrategies, signatureVerifier, gasCalculator, + systemContractMethodRegistry, getTestConfiguration(true)); - assertFalse(subject.matches(attempt)); + assertThat(subject.identifyMethod(attempt)).isEmpty(); } @Test @@ -144,6 +153,7 @@ void callFromIsAuthorizedTest() { verificationStrategies, signatureVerifier, gasCalculator, + systemContractMethodRegistry, getTestConfiguration(true)); final var call = subject.callFrom(attempt); diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/has/isauthorizedraw/IsAuthorizedRawTranslatorTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/has/isauthorizedraw/IsAuthorizedRawTranslatorTest.java index 658702406105..babefe16b64a 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/has/isauthorizedraw/IsAuthorizedRawTranslatorTest.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/has/isauthorizedraw/IsAuthorizedRawTranslatorTest.java @@ -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. @@ -23,20 +23,21 @@ import static com.hedera.node.app.service.contract.impl.test.TestHelpers.signature; import static com.hedera.node.app.service.contract.impl.test.exec.systemcontracts.CallAttemptHelpers.prepareHasAttemptWithSelectorAndCustomConfig; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.BDDMockito.given; import com.esaulpaugh.headlong.abi.Tuple; import com.hedera.node.app.service.contract.impl.exec.gas.CustomGasCalculator; import com.hedera.node.app.service.contract.impl.exec.gas.SystemContractGasCalculator; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.scope.HederaNativeOperations; import com.hedera.node.app.service.contract.impl.exec.scope.VerificationStrategies; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.has.HasCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.has.isauthorizedraw.IsAuthorizedRawCall; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.has.isauthorizedraw.IsAuthorizedRawTranslator; 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.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.exec.v051.Version051FeatureFlags; import com.hedera.node.app.service.contract.impl.hevm.HederaWorldUpdater; import com.hedera.node.app.spi.signatures.SignatureVerifier; @@ -78,12 +79,18 @@ public class IsAuthorizedRawTranslatorTest { @Mock private HederaNativeOperations nativeOperations; + @Mock + private ContractMetrics contractMetrics; + + private final SystemContractMethodRegistry systemContractMethodRegistry = new SystemContractMethodRegistry(); + private IsAuthorizedRawTranslator subject; @BeforeEach void setUp() { final var featureFlags = new Version051FeatureFlags(); - subject = new IsAuthorizedRawTranslator(featureFlags, customGasCalculator); + subject = new IsAuthorizedRawTranslator( + featureFlags, customGasCalculator, systemContractMethodRegistry, contractMetrics); } @Test @@ -97,8 +104,9 @@ void matchesIsAuthorizedRawWhenEnabled() { verificationStrategies, signatureVerifier, gasCalculator, + systemContractMethodRegistry, getTestConfiguration(true)); - assertTrue(subject.matches(attempt)); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test @@ -112,8 +120,9 @@ void doesNotMatchIsAuthorizedRawWhenDisabled() { verificationStrategies, signatureVerifier, gasCalculator, + systemContractMethodRegistry, getTestConfiguration(false)); - assertFalse(subject.matches(attempt)); + assertThat(subject.identifyMethod(attempt)).isEmpty(); } @Test @@ -127,8 +136,9 @@ void failsOnInvalidSelector() { verificationStrategies, signatureVerifier, gasCalculator, + systemContractMethodRegistry, getTestConfiguration(true)); - assertFalse(subject.matches(attempt)); + assertThat(subject.identifyMethod(attempt)).isEmpty(); } @Test @@ -144,8 +154,8 @@ void callFromIsAuthorizedRawTest() { private void givenCommonForCall(Bytes inputBytes) { given(attempt.inputBytes()).willReturn(inputBytes.toArray()); - given(attempt.isSelector(any())).willReturn(true); given(attempt.enhancement()).willReturn(enhancement); + given(attempt.isSelector((SystemContractMethod) any())).willReturn(true); given(attempt.systemContractGasCalculator()).willReturn(gasCalculator); given(attempt.signatureVerifier()).willReturn(signatureVerifier); } diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/has/isvalidalias/IsValidAliasTranslatorTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/has/isvalidalias/IsValidAliasTranslatorTest.java index bdd6c1442289..647f1f0fe798 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/has/isvalidalias/IsValidAliasTranslatorTest.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/has/isvalidalias/IsValidAliasTranslatorTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2024 Hedera Hashgraph, LLC + * Copyright (C) 2024-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. @@ -22,18 +22,18 @@ import static com.hedera.node.app.service.contract.impl.test.exec.systemcontracts.CallAttemptHelpers.prepareHasAttemptWithSelector; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.BDDMockito.given; import com.esaulpaugh.headlong.abi.Tuple; import com.hedera.node.app.service.contract.impl.exec.gas.SystemContractGasCalculator; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.scope.HederaNativeOperations; import com.hedera.node.app.service.contract.impl.exec.scope.VerificationStrategies; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.has.HasCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.has.isvalidalias.IsValidAliasCall; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.has.isvalidalias.IsValidAliasTranslator; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.AddressIdConverter; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.hevm.HederaWorldUpdater; import com.hedera.node.app.spi.signatures.SignatureVerifier; import org.apache.tuweni.bytes.Bytes; @@ -67,11 +67,16 @@ public class IsValidAliasTranslatorTest { @Mock private HederaNativeOperations nativeOperations; + @Mock + private ContractMetrics contractMetrics; + + private final SystemContractMethodRegistry systemContractMethodRegistry = new SystemContractMethodRegistry(); + private IsValidAliasTranslator subject; @BeforeEach void setUp() { - subject = new IsValidAliasTranslator(); + subject = new IsValidAliasTranslator(systemContractMethodRegistry, contractMetrics); } @Test @@ -84,8 +89,9 @@ void matchesIsValidAliasSelector() { addressIdConverter, verificationStrategies, signatureVerifier, - gasCalculator); - assertTrue(subject.matches(attempt)); + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isPresent(); assertEquals("0x308ef301" /*copied from HIP-632*/, "0x" + IS_VALID_ALIAS.selectorHex()); } @@ -99,8 +105,9 @@ void failsOnInvalidSelector() { addressIdConverter, verificationStrategies, signatureVerifier, - gasCalculator); - assertFalse(subject.matches(attempt)); + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isEmpty(); } @Test diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/has/setunlimitedautoassociations/SetUnlimitedAutoAssociationsTranslatorTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/has/setunlimitedautoassociations/SetUnlimitedAutoAssociationsTranslatorTest.java index 8a05d30fd662..f421b475d102 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/has/setunlimitedautoassociations/SetUnlimitedAutoAssociationsTranslatorTest.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/has/setunlimitedautoassociations/SetUnlimitedAutoAssociationsTranslatorTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2024 Hedera Hashgraph, LLC + * Copyright (C) 2024-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. @@ -19,17 +19,17 @@ import static com.hedera.node.app.service.contract.impl.exec.systemcontracts.has.setunlimitedautoassociations.SetUnlimitedAutoAssociationsTranslator.SET_UNLIMITED_AUTO_ASSOC; import static com.hedera.node.app.service.contract.impl.test.exec.systemcontracts.CallAttemptHelpers.prepareHasAttemptWithSelectorAndCustomConfig; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.BDDMockito.given; import com.hedera.node.app.service.contract.impl.exec.gas.SystemContractGasCalculator; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.scope.HederaNativeOperations; import com.hedera.node.app.service.contract.impl.exec.scope.VerificationStrategies; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.has.HasCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.has.setunlimitedautoassociations.SetUnlimitedAutoAssociationsCall; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.has.setunlimitedautoassociations.SetUnlimitedAutoAssociationsTranslator; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.AddressIdConverter; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.hevm.HederaWorldUpdater; import com.hedera.node.app.spi.signatures.SignatureVerifier; import com.hedera.node.config.data.ContractsConfig; @@ -70,11 +70,16 @@ class SetUnlimitedAutoAssociationsTranslatorTest { @Mock private ContractsConfig contractsConfig; + @Mock + private ContractMetrics contractMetrics; + + private final SystemContractMethodRegistry systemContractMethodRegistry = new SystemContractMethodRegistry(); + private SetUnlimitedAutoAssociationsTranslator subject; @BeforeEach void setUp() { - subject = new SetUnlimitedAutoAssociationsTranslator(); + subject = new SetUnlimitedAutoAssociationsTranslator(systemContractMethodRegistry, contractMetrics); } @Test @@ -91,8 +96,9 @@ void matchesWhenEnabled() { verificationStrategies, signatureVerifier, gasCalculator, + systemContractMethodRegistry, configuration); - assertTrue(subject.matches(attempt)); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test @@ -109,8 +115,9 @@ void matchesWhenDisabled() { verificationStrategies, signatureVerifier, gasCalculator, + systemContractMethodRegistry, configuration); - assertFalse(subject.matches(attempt)); + assertThat(subject.identifyMethod(attempt)).isEmpty(); } @Test diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hss/HssCallAttemptTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hss/HssCallAttemptTest.java index 578022ed3327..fb33427e82f7 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hss/HssCallAttemptTest.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hss/HssCallAttemptTest.java @@ -24,11 +24,13 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.BDDMockito.given; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.scope.VerificationStrategies; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.CallTranslator; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hss.HssCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hss.signschedule.SignScheduleTranslator; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.AddressIdConverter; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.test.TestHelpers; import com.hedera.node.app.service.contract.impl.test.exec.systemcontracts.common.CallTestBase; import com.hedera.node.app.spi.signatures.SignatureVerifier; @@ -49,9 +51,14 @@ class HssCallAttemptTest extends CallTestBase { private List> callTranslators; + @Mock + private ContractMetrics contractMetrics; + + private final SystemContractMethodRegistry systemContractMethodRegistry = new SystemContractMethodRegistry(); + @BeforeEach void setUp() { - callTranslators = List.of(new SignScheduleTranslator()); + callTranslators = List.of(new SignScheduleTranslator(systemContractMethodRegistry, contractMetrics)); } @Test @@ -70,6 +77,7 @@ void returnNullScheduleIfScheduleNotFound() { signatureVerifier, gasCalculator, callTranslators, + systemContractMethodRegistry, false); assertNull(subject.redirectScheduleTxn()); } @@ -88,6 +96,7 @@ void invalidSelectorLeadsToMissingCall() { signatureVerifier, gasCalculator, callTranslators, + systemContractMethodRegistry, false); assertNull(subject.asExecutableCall()); } @@ -106,6 +115,7 @@ void isOnlyDelegatableContractKeysActiveTest() { signatureVerifier, gasCalculator, callTranslators, + systemContractMethodRegistry, false); assertTrue(subject.isOnlyDelegatableContractKeysActive()); } 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 daaa6e98e116..f12003174554 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 @@ -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. @@ -31,6 +31,7 @@ import com.hedera.hapi.node.base.Key; import com.hedera.hapi.node.state.schedule.Schedule; import com.hedera.node.app.service.contract.impl.exec.gas.SystemContractGasCalculator; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.scope.VerificationStrategies; import com.hedera.node.app.service.contract.impl.exec.scope.VerificationStrategy; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.CallAddressChecks; @@ -40,6 +41,7 @@ import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.AddressIdConverter; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.SyntheticIds; import com.hedera.node.app.service.contract.impl.exec.utils.FrameUtils; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.state.ProxyWorldUpdater; import com.hedera.node.app.service.contract.impl.test.exec.systemcontracts.common.CallTestBase; import com.hedera.node.app.spi.signatures.SignatureVerifier; @@ -80,7 +82,7 @@ class HssCallFactoryTest extends CallTestBase { @Mock private MessageFrame initialFrame; - private Deque stack = new ArrayDeque<>(); + private final Deque stack = new ArrayDeque<>(); @Mock private ProxyWorldUpdater updater; @@ -91,6 +93,11 @@ class HssCallFactoryTest extends CallTestBase { @Mock private Key maybeEthSenderKey; + @Mock + private ContractMetrics contractMetrics; + + private final SystemContractMethodRegistry systemContractMethodRegistry = new SystemContractMethodRegistry(); + private HssCallFactory subject; @BeforeEach @@ -100,7 +107,8 @@ void setUp() { addressChecks, verificationStrategies, signatureVerifier, - List.of(new SignScheduleTranslator())); + List.of(new SignScheduleTranslator(systemContractMethodRegistry, contractMetrics)), + systemContractMethodRegistry); } @Test diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hss/schedulenative/ScheduleNativeTranslatorTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hss/schedulenative/ScheduleNativeTranslatorTest.java index 4b18bd35968e..351d83b04c3d 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hss/schedulenative/ScheduleNativeTranslatorTest.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hss/schedulenative/ScheduleNativeTranslatorTest.java @@ -37,6 +37,7 @@ import com.hedera.hapi.node.transaction.TransactionBody; import com.hedera.node.app.service.contract.impl.exec.gas.DispatchType; import com.hedera.node.app.service.contract.impl.exec.gas.SystemContractGasCalculator; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.scope.VerificationStrategies; import com.hedera.node.app.service.contract.impl.exec.scope.VerificationStrategy; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hss.HssCallAttempt; @@ -46,6 +47,7 @@ import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallFactory; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.create.CreateDecoder; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.create.CreateTranslator; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.test.exec.systemcontracts.common.CallTestBase; import com.hedera.node.app.spi.signatures.SignatureVerifier; import com.hedera.node.config.data.ContractsConfig; @@ -100,12 +102,17 @@ class ScheduleNativeTranslatorTest extends CallTestBase { private CreateTranslator createTranslator; + @Mock + private ContractMetrics contractMetrics; + + private final SystemContractMethodRegistry systemContractMethodRegistry = new SystemContractMethodRegistry(); + private ScheduleNativeTranslator subject; @BeforeEach void setUp() { - createTranslator = new CreateTranslator(decoder); - subject = new ScheduleNativeTranslator(htsCallFactory); + createTranslator = new CreateTranslator(decoder, systemContractMethodRegistry, contractMetrics); + subject = new ScheduleNativeTranslator(htsCallFactory, systemContractMethodRegistry, contractMetrics); } @Test @@ -126,11 +133,10 @@ void matchesScheduleCreate() { verificationStrategies, signatureVerifier, gasCalculator, + systemContractMethodRegistry, configuration); // when/then - // we need to fill in the create translator map for this test to work. - new CreateTranslator(new CreateDecoder()); - assertTrue(subject.matches(attempt)); + assertTrue(subject.identifyMethod(attempt).isPresent()); } @Test @@ -144,10 +150,11 @@ void matchesFailsForOtherSelector() { verificationStrategies, signatureVerifier, gasCalculator, + systemContractMethodRegistry, DEFAULT_CONFIG); // when/then - assertFalse(subject.matches(attempt)); + assertFalse(subject.identifyMethod(attempt).isPresent()); } @Test diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hss/signschedule/SignScheduleTranslatorTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hss/signschedule/SignScheduleTranslatorTest.java index 2f079980c019..0578b4e7caf6 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hss/signschedule/SignScheduleTranslatorTest.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hss/signschedule/SignScheduleTranslatorTest.java @@ -27,9 +27,7 @@ import static com.hedera.node.app.service.contract.impl.test.exec.systemcontracts.CallAttemptHelpers.prepareHssAttemptWithSelectorAndCustomConfig; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.BDDMockito.given; @@ -45,6 +43,7 @@ import com.hedera.hapi.node.transaction.TransactionBody; import com.hedera.node.app.service.contract.impl.exec.gas.DispatchType; import com.hedera.node.app.service.contract.impl.exec.gas.SystemContractGasCalculator; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.scope.HederaNativeOperations; import com.hedera.node.app.service.contract.impl.exec.scope.SystemContractOperations; import com.hedera.node.app.service.contract.impl.exec.scope.VerificationStrategies; @@ -54,6 +53,7 @@ import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hss.signschedule.SignScheduleTranslator; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.AddressIdConverter; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.mint.MintTranslator; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.hevm.HederaWorldUpdater; import com.hedera.node.app.spi.signatures.SignatureVerifier; import com.hedera.node.app.spi.workflows.HandleException; @@ -113,6 +113,11 @@ class SignScheduleTranslatorTest { @Mock private ScheduleID scheduleID; + @Mock + ContractMetrics contractMetrics; + + private final SystemContractMethodRegistry systemContractMethodRegistry = new SystemContractMethodRegistry(); + @Mock private Key key; @@ -132,12 +137,11 @@ class SignScheduleTranslatorTest { @BeforeEach void setUp() { - subject = new SignScheduleTranslator(); + subject = new SignScheduleTranslator(systemContractMethodRegistry, contractMetrics); } @Test void testMatchesWhenSignScheduleEnabled() { - // given: given(configuration.getConfigData(ContractsConfig.class)).willReturn(contractsConfig); given(contractsConfig.systemContractSignScheduleEnabled()).willReturn(true); attempt = prepareHssAttemptWithSelectorAndCustomConfig( @@ -148,18 +152,13 @@ void testMatchesWhenSignScheduleEnabled() { verificationStrategies, signatureVerifier, gasCalculator, + systemContractMethodRegistry, configuration); - - // when: - boolean matches = subject.matches(attempt); - - // then: - assertTrue(matches); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test void testFailsMatchesWhenSignScheduleEnabled() { - // given: given(configuration.getConfigData(ContractsConfig.class)).willReturn(contractsConfig); given(contractsConfig.systemContractSignScheduleEnabled()).willReturn(false); attempt = prepareHssAttemptWithSelectorAndCustomConfig( @@ -170,18 +169,13 @@ void testFailsMatchesWhenSignScheduleEnabled() { verificationStrategies, signatureVerifier, gasCalculator, + systemContractMethodRegistry, configuration); - - // when: - boolean matches = subject.matches(attempt); - - // then: - assertFalse(matches); + assertThat(subject.identifyMethod(attempt)).isEmpty(); } @Test void testMatchesWhenAuthorizeScheduleEnabled() { - // given: given(configuration.getConfigData(ContractsConfig.class)).willReturn(contractsConfig); given(contractsConfig.systemContractAuthorizeScheduleEnabled()).willReturn(true); attempt = prepareHssAttemptWithSelectorAndCustomConfig( @@ -192,18 +186,13 @@ void testMatchesWhenAuthorizeScheduleEnabled() { verificationStrategies, signatureVerifier, gasCalculator, + systemContractMethodRegistry, configuration); - - // when: - boolean matches = subject.matches(attempt); - - // then: - assertTrue(matches); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test void testFailsMatchesWhenAuthorizeScheduleEnabled() { - // given: given(configuration.getConfigData(ContractsConfig.class)).willReturn(contractsConfig); given(contractsConfig.systemContractAuthorizeScheduleEnabled()).willReturn(false); attempt = prepareHssAttemptWithSelectorAndCustomConfig( @@ -214,18 +203,13 @@ void testFailsMatchesWhenAuthorizeScheduleEnabled() { verificationStrategies, signatureVerifier, gasCalculator, + systemContractMethodRegistry, configuration); - - // when: - boolean matches = subject.matches(attempt); - - // then: - assertFalse(matches); + assertThat(subject.identifyMethod(attempt)).isEmpty(); } @Test void testMatchesFailsOnRandomSelector() { - // given: given(configuration.getConfigData(ContractsConfig.class)).willReturn(contractsConfig); given(contractsConfig.systemContractSignScheduleEnabled()).willReturn(true); attempt = prepareHssAttemptWithSelectorAndCustomConfig( @@ -236,13 +220,9 @@ void testMatchesFailsOnRandomSelector() { verificationStrategies, signatureVerifier, gasCalculator, + systemContractMethodRegistry, configuration); - - // when: - boolean matches = subject.matches(attempt); - - // then: - assertFalse(matches); + assertThat(subject.identifyMethod(attempt)).isEmpty(); } @Test @@ -266,6 +246,7 @@ void testAttemptForSignScheduleProxy() { verificationStrategies, signatureVerifier, gasCalculator, + systemContractMethodRegistry, configuration); // then: @@ -296,6 +277,7 @@ void testScheduleIdForSignScheduleProxyEthSender() { verificationStrategies, signatureVerifier, gasCalculator, + systemContractMethodRegistry, configuration); // then: @@ -319,6 +301,7 @@ void testScheduleIdForWrongSelectorThrows() { verificationStrategies, signatureVerifier, gasCalculator, + systemContractMethodRegistry, configuration); // then: @@ -346,6 +329,7 @@ void testAttemptForAuthorizeSchedule() { verificationStrategies, signatureVerifier, gasCalculator, + systemContractMethodRegistry, configuration); // then: @@ -375,6 +359,7 @@ void testScheduleIdForAuthorizeScheduleDelegatableContractKeys() { verificationStrategies, signatureVerifier, gasCalculator, + systemContractMethodRegistry, configuration); // then: @@ -418,6 +403,7 @@ void testScheduleIdForSignScheduleProxy() { verificationStrategies, signatureVerifier, gasCalculator, + systemContractMethodRegistry, configuration); final var returnedScheduleId = subject.scheduleIdFor(attempt); @@ -439,6 +425,7 @@ void testScheduleIdForAuthorizeSchedule() { verificationStrategies, signatureVerifier, gasCalculator, + systemContractMethodRegistry, configuration); final var returnedScheduleId = subject.scheduleIdFor(attempt); @@ -460,6 +447,7 @@ void testScheduleIdForScheduleService() { verificationStrategies, signatureVerifier, gasCalculator, + systemContractMethodRegistry, configuration); final var returnedScheduleId = subject.scheduleIdFor(attempt); @@ -486,6 +474,7 @@ void testGetKeysForSignScheduleWhenVerified() { verificationStrategies, signatureVerifier, gasCalculator, + systemContractMethodRegistry, configuration); final var keySet = SignScheduleTranslator.getKeyForSignSchedule(attempt); @@ -513,6 +502,7 @@ void testGetKeysForSignScheduleWhenNotVerified() { verificationStrategies, signatureVerifier, gasCalculator, + systemContractMethodRegistry, configuration); final var keySet = SignScheduleTranslator.getKeyForSignSchedule(attempt); @@ -538,6 +528,7 @@ void testGetKeysForSignScheduleThrowsWhenWrongChainId() { verificationStrategies, signatureVerifier, gasCalculator, + systemContractMethodRegistry, configuration); assertThrows(HandleException.class, () -> SignScheduleTranslator.getKeyForSignSchedule(attempt)); @@ -561,6 +552,7 @@ void testGetKeysForSignScheduleWhenUnknownKeyType() { verificationStrategies, signatureVerifier, gasCalculator, + systemContractMethodRegistry, configuration); final var keySet = SignScheduleTranslator.getKeyForSignSchedule(attempt); 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 cbaefda4b7d7..da4b73db2a98 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 @@ -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. @@ -38,6 +38,7 @@ import com.hedera.hapi.node.token.TokenMintTransactionBody; import com.hedera.hapi.node.transaction.TransactionBody; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.scope.VerificationStrategies; import com.hedera.node.app.service.contract.impl.exec.scope.VerificationStrategy; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.CallTranslator; @@ -71,6 +72,7 @@ import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.transfer.Erc20TransfersTranslator; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.transfer.Erc721TransferFromCall; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.transfer.Erc721TransferFromTranslator; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.test.TestHelpers; import com.hedera.node.app.service.contract.impl.test.exec.systemcontracts.common.CallTestBase; import com.swirlds.common.utility.CommonUtils; @@ -103,24 +105,29 @@ class HtsCallAttemptTest extends CallTestBase { @Mock private MintDecoder mintDecoder; + @Mock + private ContractMetrics contractMetrics; + private List> callTranslators; + private final SystemContractMethodRegistry systemContractMethodRegistry = new SystemContractMethodRegistry(); + @BeforeEach void setUp() { callTranslators = List.of( - new AssociationsTranslator(associationsDecoder), - new Erc20TransfersTranslator(), - new Erc721TransferFromTranslator(), - new MintTranslator(mintDecoder), - new ClassicTransfersTranslator(classicTransfersDecoder), - new BalanceOfTranslator(), - new IsApprovedForAllTranslator(), - new NameTranslator(), - new TotalSupplyTranslator(), - new SymbolTranslator(), - new TokenUriTranslator(), - new OwnerOfTranslator(), - new DecimalsTranslator()); + new AssociationsTranslator(associationsDecoder, systemContractMethodRegistry, contractMetrics), + new Erc20TransfersTranslator(systemContractMethodRegistry, contractMetrics), + new Erc721TransferFromTranslator(systemContractMethodRegistry, contractMetrics), + new MintTranslator(mintDecoder, systemContractMethodRegistry, contractMetrics), + new ClassicTransfersTranslator(classicTransfersDecoder, systemContractMethodRegistry, contractMetrics), + new BalanceOfTranslator(systemContractMethodRegistry, contractMetrics), + new IsApprovedForAllTranslator(systemContractMethodRegistry, contractMetrics), + new NameTranslator(systemContractMethodRegistry, contractMetrics), + new TotalSupplyTranslator(systemContractMethodRegistry, contractMetrics), + new SymbolTranslator(systemContractMethodRegistry, contractMetrics), + new TokenUriTranslator(systemContractMethodRegistry, contractMetrics), + new OwnerOfTranslator(systemContractMethodRegistry, contractMetrics), + new DecimalsTranslator(systemContractMethodRegistry, contractMetrics)); } @Test @@ -138,6 +145,7 @@ void nonLongZeroAddressesArentTokens() { verificationStrategies, gasCalculator, callTranslators, + systemContractMethodRegistry, false); assertNull(subject.redirectToken()); verifyNoInteractions(nativeOperations); @@ -159,6 +167,7 @@ void invalidSelectorLeadsToMissingCall() { verificationStrategies, gasCalculator, callTranslators, + systemContractMethodRegistry, false); assertNull(subject.asExecutableCall()); } @@ -178,6 +187,7 @@ void constructsDecimals() { verificationStrategies, gasCalculator, callTranslators, + systemContractMethodRegistry, false); assertInstanceOf(DecimalsCall.class, subject.asExecutableCall()); } @@ -197,6 +207,7 @@ void constructsTokenUri() { verificationStrategies, gasCalculator, callTranslators, + systemContractMethodRegistry, false); assertInstanceOf(TokenUriCall.class, subject.asExecutableCall()); } @@ -216,6 +227,7 @@ void constructsOwnerOf() { verificationStrategies, gasCalculator, callTranslators, + systemContractMethodRegistry, false); assertInstanceOf(OwnerOfCall.class, subject.asExecutableCall()); } @@ -238,6 +250,7 @@ void constructsBalanceOf() { verificationStrategies, gasCalculator, callTranslators, + systemContractMethodRegistry, false); assertInstanceOf(BalanceOfCall.class, subject.asExecutableCall()); } @@ -261,6 +274,7 @@ void constructsIsApprovedForAllErc() { verificationStrategies, gasCalculator, callTranslators, + systemContractMethodRegistry, false); assertInstanceOf(IsApprovedForAllCall.class, subject.asExecutableCall()); } @@ -282,6 +296,7 @@ void constructsIsApprovedForAllClassic() { verificationStrategies, gasCalculator, callTranslators, + systemContractMethodRegistry, false); assertInstanceOf(IsApprovedForAllCall.class, subject.asExecutableCall()); } @@ -301,6 +316,7 @@ void constructsTotalSupply() { verificationStrategies, gasCalculator, callTranslators, + systemContractMethodRegistry, false); assertInstanceOf(TotalSupplyCall.class, subject.asExecutableCall()); } @@ -320,6 +336,7 @@ void constructsName() { verificationStrategies, gasCalculator, callTranslators, + systemContractMethodRegistry, false); assertInstanceOf(NameCall.class, subject.asExecutableCall()); } @@ -339,6 +356,7 @@ void constructsSymbol() { verificationStrategies, gasCalculator, callTranslators, + systemContractMethodRegistry, false); assertInstanceOf(SymbolCall.class, subject.asExecutableCall()); } @@ -369,6 +387,7 @@ void constructsErc721TransferFromRedirectToNonfungible() { verificationStrategies, gasCalculator, callTranslators, + systemContractMethodRegistry, false); assertInstanceOf(Erc721TransferFromCall.class, subject.asExecutableCall()); } @@ -399,6 +418,7 @@ void constructsErc20TransferFromRedirectToFungible() { verificationStrategies, gasCalculator, callTranslators, + systemContractMethodRegistry, false); assertInstanceOf(Erc20TransfersCall.class, subject.asExecutableCall()); } @@ -426,6 +446,7 @@ void constructsErc20TransferRedirectToFungible() { verificationStrategies, gasCalculator, callTranslators, + systemContractMethodRegistry, false); assertInstanceOf(Erc20TransfersCall.class, subject.asExecutableCall()); } @@ -479,6 +500,7 @@ void constructsAssociations(boolean useExplicitCall, boolean isRedirect, String verificationStrategies, gasCalculator, callTranslators, + systemContractMethodRegistry, false); assertInstanceOf(DispatchForResponseCodeHtsCall.class, subject.asExecutableCall()); @@ -542,6 +564,7 @@ void constructsClassicTransfers(String hexedSelector) { verificationStrategies, gasCalculator, callTranslators, + systemContractMethodRegistry, false); assertInstanceOf(ClassicTransfersCall.class, subject.asExecutableCall()); @@ -613,6 +636,7 @@ void constructsMints(String hexedSelector, LinkedTokenType linkedTokenType) { verificationStrategies, gasCalculator, callTranslators, + systemContractMethodRegistry, false); assertInstanceOf(DispatchForResponseCodeHtsCall.class, subject.asExecutableCall()); 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 3766b82242f3..44fd6fa57f86 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 @@ -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. @@ -29,6 +29,7 @@ import static org.mockito.BDDMockito.given; import com.hedera.node.app.service.contract.impl.exec.gas.SystemContractGasCalculator; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.scope.VerificationStrategies; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.CallAddressChecks; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.AddressIdConverter; @@ -37,6 +38,7 @@ import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.balanceof.BalanceOfCall; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.balanceof.BalanceOfTranslator; import com.hedera.node.app.service.contract.impl.exec.utils.FrameUtils; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.state.ProxyWorldUpdater; import com.hedera.node.app.service.contract.impl.test.exec.systemcontracts.common.CallTestBase; import java.util.ArrayDeque; @@ -76,12 +78,21 @@ class HtsCallFactoryTest extends CallTestBase { @Mock private ProxyWorldUpdater updater; + @Mock + private ContractMetrics contractMetrics; + private HtsCallFactory subject; + private SystemContractMethodRegistry systemContractMethodRegistry = new SystemContractMethodRegistry(); + @BeforeEach void setUp() { subject = new HtsCallFactory( - syntheticIds, addressChecks, verificationStrategies, List.of(new BalanceOfTranslator())); + syntheticIds, + addressChecks, + verificationStrategies, + List.of(new BalanceOfTranslator(systemContractMethodRegistry, contractMetrics)), + systemContractMethodRegistry); } @Test diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/airdrops/TokenAirdropTranslatorTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/airdrops/TokenAirdropTranslatorTest.java index cd1d0d159f05..2439e4a786fd 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/airdrops/TokenAirdropTranslatorTest.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/airdrops/TokenAirdropTranslatorTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2024 Hedera Hashgraph, LLC + * Copyright (C) 2024-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. @@ -19,9 +19,8 @@ import static com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.airdrops.TokenAirdropTranslator.TOKEN_AIRDROP; import static com.hedera.node.app.service.contract.impl.test.TestHelpers.SENDER_ID; import static com.hedera.node.app.service.contract.impl.test.exec.systemcontracts.CallAttemptHelpers.prepareHtsAttemptWithSelectorAndCustomConfig; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.verify; @@ -31,6 +30,7 @@ import com.hedera.hapi.node.transaction.TransactionBody; import com.hedera.node.app.service.contract.impl.exec.gas.DispatchType; import com.hedera.node.app.service.contract.impl.exec.gas.SystemContractGasCalculator; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.scope.VerificationStrategies; import com.hedera.node.app.service.contract.impl.exec.scope.VerificationStrategy; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.AddressIdConverter; @@ -39,6 +39,7 @@ import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.airdrops.TokenAirdropDecoder; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.airdrops.TokenAirdropTranslator; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.mint.MintTranslator; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.hevm.HederaWorldUpdater; import com.hedera.node.app.service.contract.impl.test.exec.systemcontracts.common.CallTestBase; import com.hedera.node.config.data.ContractsConfig; @@ -87,11 +88,16 @@ class TokenAirdropTranslatorTest extends CallTestBase { @Mock private AccountID payerId; + @Mock + private ContractMetrics contractMetrics; + + private final SystemContractMethodRegistry systemContractMethodRegistry = new SystemContractMethodRegistry(); + private TokenAirdropTranslator translator; @BeforeEach void setUp() { - translator = new TokenAirdropTranslator(decoder); + translator = new TokenAirdropTranslator(decoder, systemContractMethodRegistry, contractMetrics); } @Test @@ -103,8 +109,9 @@ void matchesWhenAirdropEnabled() { addressIdConverter, verificationStrategies, gasCalculator, + systemContractMethodRegistry, getTestConfiguration(true)); - assertTrue(translator.matches(attempt)); + assertThat(translator.identifyMethod(attempt)).isPresent(); } @Test @@ -116,8 +123,9 @@ void doesNotMatchWhenAirdropDisabled() { addressIdConverter, verificationStrategies, gasCalculator, + systemContractMethodRegistry, getTestConfiguration(false)); - assertFalse(translator.matches(attempt)); + assertThat(translator.identifyMethod(attempt)).isEmpty(); } @Test @@ -131,11 +139,9 @@ void matchesFailsForRandomSelector() { addressIdConverter, verificationStrategies, gasCalculator, + systemContractMethodRegistry, configuration); - - boolean result = translator.matches(attempt); - - assertFalse(result); + assertThat(translator.identifyMethod(attempt)).isEmpty(); } @Test diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/allowance/GetAllowanceTranslatorTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/allowance/GetAllowanceTranslatorTest.java index e5eb55a61a3f..edbbc6591db3 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/allowance/GetAllowanceTranslatorTest.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/allowance/GetAllowanceTranslatorTest.java @@ -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. @@ -24,17 +24,17 @@ import static com.hedera.node.app.service.contract.impl.test.TestHelpers.OWNER_HEADLONG_ADDRESS; import static com.hedera.node.app.service.contract.impl.test.exec.systemcontracts.CallAttemptHelpers.prepareHtsAttemptWithSelector; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.BDDMockito.given; import com.esaulpaugh.headlong.abi.Tuple; import com.hedera.node.app.service.contract.impl.exec.gas.SystemContractGasCalculator; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.scope.VerificationStrategies; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.AddressIdConverter; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.allowance.GetAllowanceCall; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.allowance.GetAllowanceTranslator; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.hevm.HederaWorldUpdater; import org.apache.tuweni.bytes.Bytes; import org.junit.jupiter.api.BeforeEach; @@ -63,25 +63,43 @@ public class GetAllowanceTranslatorTest { @Mock private VerificationStrategies verificationStrategies; + @Mock + private ContractMetrics contractMetrics; + private GetAllowanceTranslator subject; + private final SystemContractMethodRegistry systemContractMethodRegistry = new SystemContractMethodRegistry(); + @BeforeEach void setUp() { - subject = new GetAllowanceTranslator(); + subject = new GetAllowanceTranslator(systemContractMethodRegistry, contractMetrics); } @Test void matchesGetAllowance() { attempt = prepareHtsAttemptWithSelector( - GET_ALLOWANCE, subject, enhancement, addressIdConverter, verificationStrategies, gasCalculator); - assertTrue(subject.matches(attempt)); + GET_ALLOWANCE, + subject, + enhancement, + addressIdConverter, + verificationStrategies, + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test void matchesERCGetAllowance() { attempt = prepareHtsAttemptWithSelector( - ERC_GET_ALLOWANCE, subject, enhancement, addressIdConverter, verificationStrategies, gasCalculator); - assertTrue(subject.matches(attempt)); + ERC_GET_ALLOWANCE, + subject, + enhancement, + addressIdConverter, + verificationStrategies, + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isPresent(); + ; } @Test @@ -92,8 +110,9 @@ void failsOnInvalidSelector() { enhancement, addressIdConverter, verificationStrategies, - gasCalculator); - assertFalse(subject.matches(attempt)); + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isEmpty(); } @Test diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/burn/BurnTranslatorTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/burn/BurnTranslatorTest.java index dbc41b5506d4..df6553d537d3 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/burn/BurnTranslatorTest.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/burn/BurnTranslatorTest.java @@ -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. @@ -20,15 +20,16 @@ import static com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.burn.BurnTranslator.BURN_TOKEN_V2; import static com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.update.UpdateTranslator.TOKEN_UPDATE_INFO_FUNCTION_V3; import static com.hedera.node.app.service.contract.impl.test.exec.systemcontracts.CallAttemptHelpers.prepareHtsAttemptWithSelector; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; import com.hedera.node.app.service.contract.impl.exec.gas.SystemContractGasCalculator; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.scope.VerificationStrategies; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.AddressIdConverter; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.burn.BurnDecoder; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.burn.BurnTranslator; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.hevm.HederaWorldUpdater; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -54,27 +55,44 @@ class BurnTranslatorTest { @Mock private VerificationStrategies verificationStrategies; + @Mock + private ContractMetrics contractMetrics; + + private final SystemContractMethodRegistry systemContractMethodRegistry = new SystemContractMethodRegistry(); + private BurnTranslator subject; private final BurnDecoder decoder = new BurnDecoder(); @BeforeEach void setUp() { - subject = new BurnTranslator(decoder); + subject = new BurnTranslator(decoder, systemContractMethodRegistry, contractMetrics); } @Test void matchesBurnTokenV1() { attempt = prepareHtsAttemptWithSelector( - BURN_TOKEN_V1, subject, enhancement, addressIdConverter, verificationStrategies, gasCalculator); - assertTrue(subject.matches(attempt)); + BURN_TOKEN_V1, + subject, + enhancement, + addressIdConverter, + verificationStrategies, + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test void matchesBurnTokenV2() { attempt = prepareHtsAttemptWithSelector( - BURN_TOKEN_V2, subject, enhancement, addressIdConverter, verificationStrategies, gasCalculator); - assertTrue(subject.matches(attempt)); + BURN_TOKEN_V2, + subject, + enhancement, + addressIdConverter, + verificationStrategies, + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test @@ -85,7 +103,8 @@ void matchFailsOnInvalidSelector() { enhancement, addressIdConverter, verificationStrategies, - gasCalculator); - assertFalse(subject.matches(attempt)); + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isEmpty(); } } diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/cancelairdrops/TokenCancelAirdropDecoderTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/cancelairdrops/TokenCancelAirdropDecoderTest.java index a0a699bc70f6..216eb699fb0a 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/cancelairdrops/TokenCancelAirdropDecoderTest.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/cancelairdrops/TokenCancelAirdropDecoderTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2024 Hedera Hashgraph, LLC + * Copyright (C) 2024-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. @@ -18,7 +18,7 @@ import static com.hedera.hapi.node.base.ResponseCodeEnum.INVALID_TOKEN_ID; import static com.hedera.hapi.node.base.ResponseCodeEnum.PENDING_AIRDROP_ID_LIST_TOO_LONG; -import static com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.cancelairdrops.TokenCancelAirdropTranslator.CANCEL_AIRDROP; +import static com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.cancelairdrops.TokenCancelAirdropTranslator.CANCEL_AIRDROPS; import static com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.cancelairdrops.TokenCancelAirdropTranslator.HRC_CANCEL_AIRDROP_FT; import static com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.cancelairdrops.TokenCancelAirdropTranslator.HRC_CANCEL_AIRDROP_NFT; import static com.hedera.node.app.service.contract.impl.test.TestHelpers.FUNGIBLE_TOKEN; @@ -99,7 +99,7 @@ void cancelAirdropDecoder1FTTest() { .willReturn(SENDER_ID); given(addressIdConverter.convert(OWNER_ACCOUNT_AS_ADDRESS)).willReturn(OWNER_ID); - final var encoded = Bytes.wrapByteBuffer(CANCEL_AIRDROP.encodeCall(Tuple.singleton(new Tuple[] { + final var encoded = Bytes.wrapByteBuffer(CANCEL_AIRDROPS.encodeCall(Tuple.singleton(new Tuple[] { Tuple.of( asHeadlongAddress(SENDER_ID.accountNum()), OWNER_ACCOUNT_AS_ADDRESS, @@ -133,7 +133,7 @@ void failsIfPendingAirdropsAboveLimit() { FUNGIBLE_TOKEN_HEADLONG_ADDRESS, 0L); final var encoded = - Bytes.wrapByteBuffer(CANCEL_AIRDROP.encodeCall(Tuple.singleton(new Tuple[] {tuple, tuple, tuple}))); + Bytes.wrapByteBuffer(CANCEL_AIRDROPS.encodeCall(Tuple.singleton(new Tuple[] {tuple, tuple, tuple}))); given(attempt.inputBytes()).willReturn(encoded.toArrayUnsafe()); assertThatExceptionOfType(HandleException.class) @@ -150,7 +150,7 @@ void failsIfTokenIsNull() { .willReturn(SENDER_ID); given(addressIdConverter.convert(OWNER_ACCOUNT_AS_ADDRESS)).willReturn(OWNER_ID); - final var encoded = Bytes.wrapByteBuffer(CANCEL_AIRDROP.encodeCall(Tuple.singleton(new Tuple[] { + final var encoded = Bytes.wrapByteBuffer(CANCEL_AIRDROPS.encodeCall(Tuple.singleton(new Tuple[] { Tuple.of( asHeadlongAddress(SENDER_ID.accountNum()), OWNER_ACCOUNT_AS_ADDRESS, @@ -173,7 +173,7 @@ void cancelAirdropDecoder1NFTTest() { .willReturn(SENDER_ID); given(addressIdConverter.convert(OWNER_ACCOUNT_AS_ADDRESS)).willReturn(OWNER_ID); - final var encoded = Bytes.wrapByteBuffer(CANCEL_AIRDROP.encodeCall(Tuple.singleton(new Tuple[] { + final var encoded = Bytes.wrapByteBuffer(CANCEL_AIRDROPS.encodeCall(Tuple.singleton(new Tuple[] { Tuple.of( asHeadlongAddress(SENDER_ID.accountNum()), OWNER_ACCOUNT_AS_ADDRESS, diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/cancelairdrops/TokenCancelAirdropTranslatorTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/cancelairdrops/TokenCancelAirdropTranslatorTest.java index 26568e3d7d0a..93114ba4cabe 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/cancelairdrops/TokenCancelAirdropTranslatorTest.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/cancelairdrops/TokenCancelAirdropTranslatorTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2024 Hedera Hashgraph, LLC + * Copyright (C) 2024-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. @@ -19,9 +19,8 @@ import static com.hedera.node.app.service.contract.impl.test.TestHelpers.SENDER_ID; import static com.hedera.node.app.service.contract.impl.test.exec.systemcontracts.CallAttemptHelpers.prepareHtsAttemptWithSelectorAndCustomConfig; import static com.hedera.node.app.service.contract.impl.test.exec.systemcontracts.CallAttemptHelpers.prepareHtsAttemptWithSelectorForRedirectWithConfig; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.BDDMockito.given; @@ -31,6 +30,7 @@ import com.hedera.hapi.node.transaction.TransactionBody; import com.hedera.node.app.service.contract.impl.exec.gas.DispatchType; import com.hedera.node.app.service.contract.impl.exec.gas.SystemContractGasCalculator; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.scope.HederaNativeOperations; import com.hedera.node.app.service.contract.impl.exec.scope.VerificationStrategies; import com.hedera.node.app.service.contract.impl.exec.scope.VerificationStrategy; @@ -40,6 +40,7 @@ import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.cancelairdrops.TokenCancelAirdropDecoder; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.cancelairdrops.TokenCancelAirdropTranslator; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.mint.MintTranslator; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.hevm.HederaWorldUpdater.Enhancement; import com.hedera.node.config.data.ContractsConfig; import com.swirlds.config.api.Configuration; @@ -88,37 +89,37 @@ class TokenCancelAirdropTranslatorTest { @Mock private AccountID payerId; + @Mock + private ContractMetrics contractMetrics; + + private final SystemContractMethodRegistry systemContractMethodRegistry = new SystemContractMethodRegistry(); + private TokenCancelAirdropTranslator subject; @BeforeEach void setUp() { - subject = new TokenCancelAirdropTranslator(decoder); + subject = new TokenCancelAirdropTranslator(decoder, systemContractMethodRegistry, contractMetrics); } @Test void matchesHTSCancelAirdropEnabled() { - // given: given(configuration.getConfigData(ContractsConfig.class)).willReturn(contractsConfig); given(contractsConfig.systemContractCancelAirdropsEnabled()).willReturn(true); attempt = prepareHtsAttemptWithSelectorAndCustomConfig( - TokenCancelAirdropTranslator.CANCEL_AIRDROP, + TokenCancelAirdropTranslator.CANCEL_AIRDROPS, subject, enhancement, addressIdConverter, verificationStrategies, gasCalculator, + systemContractMethodRegistry, configuration); - // when: - boolean matches = subject.matches(attempt); - - // then: - assertTrue(matches); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test void matchesFailsOnWrongSelector() { - // given: given(configuration.getConfigData(ContractsConfig.class)).willReturn(contractsConfig); given(contractsConfig.systemContractCancelAirdropsEnabled()).willReturn(true); attempt = prepareHtsAttemptWithSelectorAndCustomConfig( @@ -128,39 +129,31 @@ void matchesFailsOnWrongSelector() { addressIdConverter, verificationStrategies, gasCalculator, + systemContractMethodRegistry, configuration); - // when: - boolean matches = subject.matches(attempt); - - // then: - assertFalse(matches); + assertThat(subject.identifyMethod(attempt)).isEmpty(); } @Test void matchesHTSCancelAirdropDisabled() { - // given: given(configuration.getConfigData(ContractsConfig.class)).willReturn(contractsConfig); given(contractsConfig.systemContractCancelAirdropsEnabled()).willReturn(false); attempt = prepareHtsAttemptWithSelectorAndCustomConfig( - TokenCancelAirdropTranslator.CANCEL_AIRDROP, + TokenCancelAirdropTranslator.CANCEL_AIRDROPS, subject, enhancement, addressIdConverter, verificationStrategies, gasCalculator, + systemContractMethodRegistry, configuration); - // when: - boolean matches = subject.matches(attempt); - - // then: - assertFalse(matches); + assertThat(subject.identifyMethod(attempt)).isEmpty(); } @Test void matchesHRCCancelFTAirdropEnabled() { - // given: given(configuration.getConfigData(ContractsConfig.class)).willReturn(contractsConfig); given(contractsConfig.systemContractCancelAirdropsEnabled()).willReturn(true); given(enhancement.nativeOperations()).willReturn(nativeOperations); @@ -171,18 +164,14 @@ void matchesHRCCancelFTAirdropEnabled() { addressIdConverter, verificationStrategies, gasCalculator, + systemContractMethodRegistry, configuration); - // when: - boolean matches = subject.matches(attempt); - - // then: - assertTrue(matches); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test void matchesHRCCancelAirdropDisabled() { - // given: given(configuration.getConfigData(ContractsConfig.class)).willReturn(contractsConfig); given(contractsConfig.systemContractCancelAirdropsEnabled()).willReturn(false); given(enhancement.nativeOperations()).willReturn(nativeOperations); @@ -193,18 +182,14 @@ void matchesHRCCancelAirdropDisabled() { addressIdConverter, verificationStrategies, gasCalculator, + systemContractMethodRegistry, configuration); - // when: - boolean matches = subject.matches(attempt); - - // then: - assertFalse(matches); + assertThat(subject.identifyMethod(attempt)).isEmpty(); } @Test void matchesHRCCancelNFTAirdropEnabled() { - // given: given(configuration.getConfigData(ContractsConfig.class)).willReturn(contractsConfig); given(contractsConfig.systemContractCancelAirdropsEnabled()).willReturn(true); given(enhancement.nativeOperations()).willReturn(nativeOperations); @@ -215,18 +200,14 @@ void matchesHRCCancelNFTAirdropEnabled() { addressIdConverter, verificationStrategies, gasCalculator, + systemContractMethodRegistry, configuration); - // when: - boolean matches = subject.matches(attempt); - - // then: - assertTrue(matches); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test void matchesHRCCancelNFTAirdropDisabled() { - // given: given(configuration.getConfigData(ContractsConfig.class)).willReturn(contractsConfig); given(contractsConfig.systemContractCancelAirdropsEnabled()).willReturn(false); given(enhancement.nativeOperations()).willReturn(nativeOperations); @@ -237,12 +218,10 @@ void matchesHRCCancelNFTAirdropDisabled() { addressIdConverter, verificationStrategies, gasCalculator, + systemContractMethodRegistry, configuration); - // when: - boolean matches = subject.matches(attempt); - // then: - assertFalse(matches); + assertThat(subject.identifyMethod(attempt)).isEmpty(); } @Test @@ -263,12 +242,13 @@ void callFromHtsCancelAirdrop() { given(verificationStrategies.activatingOnlyContractKeysFor(any(), anyBoolean(), any())) .willReturn(verificationStrategy); attempt = prepareHtsAttemptWithSelectorAndCustomConfig( - TokenCancelAirdropTranslator.CANCEL_AIRDROP, + TokenCancelAirdropTranslator.CANCEL_AIRDROPS, subject, enhancement, addressIdConverter, verificationStrategies, gasCalculator, + systemContractMethodRegistry, configuration); // when: @@ -292,6 +272,7 @@ void callFromHRCCancelFTAirdrop() { addressIdConverter, verificationStrategies, gasCalculator, + systemContractMethodRegistry, configuration); // when: @@ -315,6 +296,7 @@ void callFromHRCCancelNFTAirdrop() { addressIdConverter, verificationStrategies, gasCalculator, + systemContractMethodRegistry, configuration); // when: diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/claimairdrops/TokenClaimAirdropDecoderTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/claimairdrops/TokenClaimAirdropDecoderTest.java index bcb244eb2303..d328f5885a02 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/claimairdrops/TokenClaimAirdropDecoderTest.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/claimairdrops/TokenClaimAirdropDecoderTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2024 Hedera Hashgraph, LLC + * Copyright (C) 2024-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. @@ -17,7 +17,7 @@ package com.hedera.node.app.service.contract.impl.test.exec.systemcontracts.hts.claimairdrops; import static com.hedera.hapi.node.base.ResponseCodeEnum.INVALID_TOKEN_ID; -import static com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.claimairdrops.TokenClaimAirdropTranslator.CLAIM_AIRDROP; +import static com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.claimairdrops.TokenClaimAirdropTranslator.CLAIM_AIRDROPS; import static com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.claimairdrops.TokenClaimAirdropTranslator.HRC_CLAIM_AIRDROP_FT; import static com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.claimairdrops.TokenClaimAirdropTranslator.HRC_CLAIM_AIRDROP_NFT; import static com.hedera.node.app.service.contract.impl.test.TestHelpers.FUNGIBLE_TOKEN; @@ -99,7 +99,7 @@ void claimAirdropDecoder1FTTest() { given(addressIdConverter.convert(asHeadlongAddress(SENDER_ID.accountNum()))) .willReturn(SENDER_ID); - final var encoded = Bytes.wrapByteBuffer(CLAIM_AIRDROP.encodeCall(Tuple.singleton(new Tuple[] { + final var encoded = Bytes.wrapByteBuffer(CLAIM_AIRDROPS.encodeCall(Tuple.singleton(new Tuple[] { Tuple.of( asHeadlongAddress(SENDER_ID.accountNum()), OWNER_ACCOUNT_AS_ADDRESS, @@ -129,7 +129,7 @@ void failsIfPendingAirdropsAboveLimit() { given(configuration.getConfigData(TokensConfig.class)).willReturn(tokensConfig); given(tokensConfig.maxAllowedPendingAirdropsToClaim()).willReturn(10); - final var encoded = Bytes.wrapByteBuffer(CLAIM_AIRDROP.encodeCall(Tuple.singleton(new Tuple[] { + final var encoded = Bytes.wrapByteBuffer(CLAIM_AIRDROPS.encodeCall(Tuple.singleton(new Tuple[] { Tuple.of( asHeadlongAddress(SENDER_ID.accountNum()), OWNER_ACCOUNT_AS_ADDRESS, @@ -204,7 +204,7 @@ void failsIfTokenIsNull() { .willReturn(SENDER_ID); given(addressIdConverter.convert(OWNER_ACCOUNT_AS_ADDRESS)).willReturn(OWNER_ID); - final var encoded = Bytes.wrapByteBuffer(CLAIM_AIRDROP.encodeCall(Tuple.singleton(new Tuple[] { + final var encoded = Bytes.wrapByteBuffer(CLAIM_AIRDROPS.encodeCall(Tuple.singleton(new Tuple[] { Tuple.of( asHeadlongAddress(SENDER_ID.accountNum()), OWNER_ACCOUNT_AS_ADDRESS, @@ -252,7 +252,7 @@ void claimAirdropDecoder1NFTTest() { .willReturn(SENDER_ID); given(addressIdConverter.convert(OWNER_ACCOUNT_AS_ADDRESS)).willReturn(OWNER_ID); - final var encoded = Bytes.wrapByteBuffer(CLAIM_AIRDROP.encodeCall(Tuple.singleton(new Tuple[] { + final var encoded = Bytes.wrapByteBuffer(CLAIM_AIRDROPS.encodeCall(Tuple.singleton(new Tuple[] { Tuple.of( asHeadlongAddress(SENDER_ID.accountNum()), OWNER_ACCOUNT_AS_ADDRESS, diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/claimairdrops/TokenClaimAirdropTranslatorTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/claimairdrops/TokenClaimAirdropTranslatorTest.java index ee5655def64e..9b4ae6c22128 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/claimairdrops/TokenClaimAirdropTranslatorTest.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/claimairdrops/TokenClaimAirdropTranslatorTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2024 Hedera Hashgraph, LLC + * Copyright (C) 2024-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. @@ -19,9 +19,8 @@ import static com.hedera.node.app.service.contract.impl.test.TestHelpers.SENDER_ID; import static com.hedera.node.app.service.contract.impl.test.exec.systemcontracts.CallAttemptHelpers.prepareHtsAttemptWithSelectorAndCustomConfig; import static com.hedera.node.app.service.contract.impl.test.exec.systemcontracts.CallAttemptHelpers.prepareHtsAttemptWithSelectorForRedirectWithConfig; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.BDDMockito.given; @@ -32,6 +31,7 @@ import com.hedera.hapi.node.transaction.TransactionBody; import com.hedera.node.app.service.contract.impl.exec.gas.DispatchType; import com.hedera.node.app.service.contract.impl.exec.gas.SystemContractGasCalculator; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.scope.HederaNativeOperations; import com.hedera.node.app.service.contract.impl.exec.scope.VerificationStrategies; import com.hedera.node.app.service.contract.impl.exec.scope.VerificationStrategy; @@ -41,6 +41,7 @@ import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.claimairdrops.TokenClaimAirdropDecoder; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.claimairdrops.TokenClaimAirdropTranslator; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.mint.MintTranslator; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.hevm.HederaWorldUpdater; import com.hedera.node.config.data.ContractsConfig; import com.swirlds.config.api.Configuration; @@ -89,37 +90,36 @@ class TokenClaimAirdropTranslatorTest { @Mock private AccountID payerId; + @Mock + private ContractMetrics contractMetrics; + + private final SystemContractMethodRegistry systemContractMethodRegistry = new SystemContractMethodRegistry(); + private TokenClaimAirdropTranslator subject; @BeforeEach void setUp() { - subject = new TokenClaimAirdropTranslator(decoder); + subject = new TokenClaimAirdropTranslator(decoder, systemContractMethodRegistry, contractMetrics); } @Test void testMatchesWhenClaimAirdropEnabled() { - // given: given(configuration.getConfigData(ContractsConfig.class)).willReturn(contractsConfig); given(contractsConfig.systemContractClaimAirdropsEnabled()).willReturn(true); attempt = prepareHtsAttemptWithSelectorAndCustomConfig( - TokenClaimAirdropTranslator.CLAIM_AIRDROP, + TokenClaimAirdropTranslator.CLAIM_AIRDROPS, subject, enhancement, addressIdConverter, verificationStrategies, gasCalculator, + systemContractMethodRegistry, configuration); - - // when: - boolean matches = subject.matches(attempt); - - // then: - assertTrue(matches); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test void testMatchesFailsOnRandomSelector() { - // given: given(configuration.getConfigData(ContractsConfig.class)).willReturn(contractsConfig); given(contractsConfig.systemContractClaimAirdropsEnabled()).willReturn(true); attempt = prepareHtsAttemptWithSelectorAndCustomConfig( @@ -129,40 +129,29 @@ void testMatchesFailsOnRandomSelector() { addressIdConverter, verificationStrategies, gasCalculator, + systemContractMethodRegistry, configuration); - - // when: - boolean matches = subject.matches(attempt); - - // then: - assertFalse(matches); + assertThat(subject.identifyMethod(attempt)).isEmpty(); } @Test void testMatchesWhenClaimAirdropDisabled() { - // given: - given(configuration.getConfigData(ContractsConfig.class)).willReturn(contractsConfig); given(contractsConfig.systemContractClaimAirdropsEnabled()).willReturn(false); attempt = prepareHtsAttemptWithSelectorAndCustomConfig( - TokenClaimAirdropTranslator.CLAIM_AIRDROP, + TokenClaimAirdropTranslator.CLAIM_AIRDROPS, subject, enhancement, addressIdConverter, verificationStrategies, gasCalculator, + systemContractMethodRegistry, configuration); - - // when: - boolean matches = subject.matches(attempt); - - // then: - assertFalse(matches); + assertThat(subject.identifyMethod(attempt)).isEmpty(); } @Test void testMatchesHRCClaimFT() { - // given: given(configuration.getConfigData(ContractsConfig.class)).willReturn(contractsConfig); given(contractsConfig.systemContractClaimAirdropsEnabled()).willReturn(true); given(enhancement.nativeOperations()).willReturn(nativeOperations); @@ -173,18 +162,13 @@ void testMatchesHRCClaimFT() { addressIdConverter, verificationStrategies, gasCalculator, + systemContractMethodRegistry, configuration); - - // when: - boolean matches = subject.matches(attempt); - - // then: - assertTrue(matches); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test void testMatchesHRCClaimNFT() { - // given: given(configuration.getConfigData(ContractsConfig.class)).willReturn(contractsConfig); given(contractsConfig.systemContractClaimAirdropsEnabled()).willReturn(true); given(enhancement.nativeOperations()).willReturn(nativeOperations); @@ -195,18 +179,13 @@ void testMatchesHRCClaimNFT() { addressIdConverter, verificationStrategies, gasCalculator, + systemContractMethodRegistry, configuration); - - // when: - boolean matches = subject.matches(attempt); - - // then: - assertTrue(matches); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test void testMatchesHRCClaimFTDisabled() { - // given: given(configuration.getConfigData(ContractsConfig.class)).willReturn(contractsConfig); given(contractsConfig.systemContractClaimAirdropsEnabled()).willReturn(false); given(enhancement.nativeOperations()).willReturn(nativeOperations); @@ -217,18 +196,13 @@ void testMatchesHRCClaimFTDisabled() { addressIdConverter, verificationStrategies, gasCalculator, + systemContractMethodRegistry, configuration); - - // when: - boolean matches = subject.matches(attempt); - - // then: - assertFalse(matches); + assertThat(subject.identifyMethod(attempt)).isEmpty(); } @Test void testMatchesHRCClaimNFTDisabled() { - // given: given(configuration.getConfigData(ContractsConfig.class)).willReturn(contractsConfig); given(contractsConfig.systemContractClaimAirdropsEnabled()).willReturn(false); given(enhancement.nativeOperations()).willReturn(nativeOperations); @@ -239,13 +213,9 @@ void testMatchesHRCClaimNFTDisabled() { addressIdConverter, verificationStrategies, gasCalculator, + systemContractMethodRegistry, configuration); - - // when: - boolean matches = subject.matches(attempt); - - // then: - assertFalse(matches); + assertThat(subject.identifyMethod(attempt)).isEmpty(); } @Test @@ -255,12 +225,13 @@ void testCallFromForClassic() { given(verificationStrategies.activatingOnlyContractKeysFor(any(), anyBoolean(), any())) .willReturn(verificationStrategy); attempt = prepareHtsAttemptWithSelectorAndCustomConfig( - TokenClaimAirdropTranslator.CLAIM_AIRDROP, + TokenClaimAirdropTranslator.CLAIM_AIRDROPS, subject, enhancement, addressIdConverter, verificationStrategies, gasCalculator, + systemContractMethodRegistry, configuration); // when: @@ -284,6 +255,7 @@ void callFromHRCClaimFTAirdrop() { addressIdConverter, verificationStrategies, gasCalculator, + systemContractMethodRegistry, configuration); // when: @@ -307,6 +279,7 @@ void callFromHRCCancelNFTAirdrop() { addressIdConverter, verificationStrategies, gasCalculator, + systemContractMethodRegistry, configuration); // when: diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/create/CreateTranslatorTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/create/CreateTranslatorTest.java index 2218e31402b0..cd614b2b495e 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/create/CreateTranslatorTest.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/create/CreateTranslatorTest.java @@ -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. @@ -53,11 +53,10 @@ import static com.hedera.node.app.service.contract.impl.test.exec.systemcontracts.hts.create.CreateTestHelper.CREATE_NON_FUNGIBLE_WITH_META_AND_FEES_TUPLE; import static com.hedera.node.app.service.contract.impl.test.exec.systemcontracts.hts.create.CreateTestHelper.CREATE_NON_FUNGIBLE_WITH_META_TUPLE; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.BDDMockito.given; import com.hedera.node.app.service.contract.impl.exec.gas.SystemContractGasCalculator; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.scope.VerificationStrategies; import com.hedera.node.app.service.contract.impl.exec.scope.VerificationStrategy; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.AddressIdConverter; @@ -65,6 +64,7 @@ import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.create.ClassicCreatesCall; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.create.CreateDecoder; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.create.CreateTranslator; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.hevm.HederaWorldUpdater; import com.hedera.node.app.service.contract.impl.test.exec.systemcontracts.common.CallTestBase; import com.hedera.node.config.data.ContractsConfig; @@ -106,13 +106,18 @@ public class CreateTranslatorTest extends CallTestBase { @Mock Configuration configuration; - private CreateDecoder decoder = new CreateDecoder(); + @Mock + private ContractMetrics contractMetrics; + + private final SystemContractMethodRegistry systemContractMethodRegistry = new SystemContractMethodRegistry(); + + private final CreateDecoder decoder = new CreateDecoder(); private CreateTranslator subject; @BeforeEach void setUp() { - subject = new CreateTranslator(decoder); + subject = new CreateTranslator(decoder, systemContractMethodRegistry, contractMetrics); } @Test @@ -123,8 +128,9 @@ void matchesCreateFungibleTokenV1() { enhancement, addressIdConverter, verificationStrategies, - gasCalculator); - assertTrue(subject.matches(attempt)); + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test @@ -135,8 +141,9 @@ void matchesCreateFungibleTokenV2() { enhancement, addressIdConverter, verificationStrategies, - gasCalculator); - assertTrue(subject.matches(attempt)); + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test @@ -147,8 +154,9 @@ void matchesCreateFungibleTokenV3() { enhancement, addressIdConverter, verificationStrategies, - gasCalculator); - assertTrue(subject.matches(attempt)); + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test @@ -161,8 +169,9 @@ void matchesCreateFungibleTokenWithMetadata() { addressIdConverter, verificationStrategies, gasCalculator, + systemContractMethodRegistry, configuration); - assertTrue(subject.matches(attempt)); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test @@ -173,8 +182,9 @@ void matchesCreateFungibleTokenWithCustomFeesV1() { enhancement, addressIdConverter, verificationStrategies, - gasCalculator); - assertTrue(subject.matches(attempt)); + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test @@ -185,8 +195,9 @@ void matchesCreateFungibleTokenWithCustomFeesV2() { enhancement, addressIdConverter, verificationStrategies, - gasCalculator); - assertTrue(subject.matches(attempt)); + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test @@ -197,8 +208,9 @@ void matchesCreateFungibleTokenWithCustomFeesV3() { enhancement, addressIdConverter, verificationStrategies, - gasCalculator); - assertTrue(subject.matches(attempt)); + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test @@ -211,8 +223,9 @@ void matchesCreateFungibleTokenWithMetadataAndCustomFees() { addressIdConverter, verificationStrategies, gasCalculator, + systemContractMethodRegistry, configuration); - assertTrue(subject.matches(attempt)); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test @@ -223,8 +236,9 @@ void matchesCreateNonFungibleTokenV1() { enhancement, addressIdConverter, verificationStrategies, - gasCalculator); - assertTrue(subject.matches(attempt)); + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test @@ -235,8 +249,9 @@ void matchesCreateNonFungibleTokenV2() { enhancement, addressIdConverter, verificationStrategies, - gasCalculator); - assertTrue(subject.matches(attempt)); + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test @@ -247,8 +262,9 @@ void matchesCreateNonFungibleTokenV3() { enhancement, addressIdConverter, verificationStrategies, - gasCalculator); - assertTrue(subject.matches(attempt)); + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test @@ -261,8 +277,9 @@ void matchesCreateNonFungibleTokenWithMetadata() { addressIdConverter, verificationStrategies, gasCalculator, + systemContractMethodRegistry, configuration); - assertTrue(subject.matches(attempt)); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test @@ -273,8 +290,9 @@ void matchesCreateNonFungibleTokenWithCustomFeesV1() { enhancement, addressIdConverter, verificationStrategies, - gasCalculator); - assertTrue(subject.matches(attempt)); + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test @@ -285,8 +303,9 @@ void matchesCreateNonFungibleTokenWithCustomFeesV2() { enhancement, addressIdConverter, verificationStrategies, - gasCalculator); - assertTrue(subject.matches(attempt)); + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test @@ -297,8 +316,9 @@ void matchesCreateNonFungibleTokenWithCustomFeesV3() { enhancement, addressIdConverter, verificationStrategies, - gasCalculator); - assertTrue(subject.matches(attempt)); + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test @@ -311,15 +331,22 @@ void matchesCreateNonFungibleTokenWithMetadataAndCustomFees() { addressIdConverter, verificationStrategies, gasCalculator, + systemContractMethodRegistry, configuration); - assertTrue(subject.matches(attempt)); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test void falseOnInvalidSelector() { attempt = prepareHtsAttemptWithSelector( - BURN_TOKEN_V2, subject, enhancement, addressIdConverter, verificationStrategies, gasCalculator); - assertFalse(subject.matches(attempt)); + BURN_TOKEN_V2, + subject, + enhancement, + addressIdConverter, + verificationStrategies, + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isEmpty(); } @Test diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/customfees/TokenCustomFeesTranslatorTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/customfees/TokenCustomFeesTranslatorTest.java index 9fc99c88e126..36119f7a6112 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/customfees/TokenCustomFeesTranslatorTest.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/customfees/TokenCustomFeesTranslatorTest.java @@ -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. @@ -21,17 +21,17 @@ import static com.hedera.node.app.service.contract.impl.test.TestHelpers.FUNGIBLE_TOKEN_HEADLONG_ADDRESS; import static com.hedera.node.app.service.contract.impl.test.exec.systemcontracts.CallAttemptHelpers.prepareHtsAttemptWithSelector; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.BDDMockito.given; import com.esaulpaugh.headlong.abi.Tuple; import com.hedera.node.app.service.contract.impl.exec.gas.SystemContractGasCalculator; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.scope.VerificationStrategies; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.AddressIdConverter; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.customfees.TokenCustomFeesCall; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.customfees.TokenCustomFeesTranslator; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.hevm.HederaWorldUpdater.Enhancement; import org.apache.tuweni.bytes.Bytes; import org.junit.jupiter.api.BeforeEach; @@ -57,25 +57,42 @@ class TokenCustomFeesTranslatorTest { @Mock private VerificationStrategies verificationStrategies; + @Mock + private ContractMetrics contractMetrics; + + private final SystemContractMethodRegistry systemContractMethodRegistry = new SystemContractMethodRegistry(); + private TokenCustomFeesTranslator subject; @BeforeEach void setUp() { - subject = new TokenCustomFeesTranslator(); + subject = new TokenCustomFeesTranslator(systemContractMethodRegistry, contractMetrics); } @Test void matchesTokenCustomFeesTranslatorTest() { attempt = prepareHtsAttemptWithSelector( - TOKEN_CUSTOM_FEES, subject, enhancement, addressIdConverter, verificationStrategies, gasCalculator); - assertTrue(subject.matches(attempt)); + TOKEN_CUSTOM_FEES, + subject, + enhancement, + addressIdConverter, + verificationStrategies, + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test void matchesFailsIfIncorrectSelectorTest() { attempt = prepareHtsAttemptWithSelector( - BURN_TOKEN_V2, subject, enhancement, addressIdConverter, verificationStrategies, gasCalculator); - assertFalse(subject.matches(attempt)); + BURN_TOKEN_V2, + subject, + enhancement, + addressIdConverter, + verificationStrategies, + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isEmpty(); } @Test diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/defaultfreezestatus/DefaultFreezeStatusTranslatorTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/defaultfreezestatus/DefaultFreezeStatusTranslatorTest.java index 298efd01b86e..f04ccfa3fb09 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/defaultfreezestatus/DefaultFreezeStatusTranslatorTest.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/defaultfreezestatus/DefaultFreezeStatusTranslatorTest.java @@ -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. @@ -21,17 +21,17 @@ import static com.hedera.node.app.service.contract.impl.test.TestHelpers.FUNGIBLE_TOKEN_HEADLONG_ADDRESS; import static com.hedera.node.app.service.contract.impl.test.exec.systemcontracts.CallAttemptHelpers.prepareHtsAttemptWithSelector; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.BDDMockito.given; import com.esaulpaugh.headlong.abi.Tuple; import com.hedera.node.app.service.contract.impl.exec.gas.SystemContractGasCalculator; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.scope.VerificationStrategies; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.AddressIdConverter; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.defaultfreezestatus.DefaultFreezeStatusCall; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.defaultfreezestatus.DefaultFreezeStatusTranslator; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.hevm.HederaWorldUpdater.Enhancement; import org.apache.tuweni.bytes.Bytes; import org.junit.jupiter.api.BeforeEach; @@ -57,25 +57,42 @@ class DefaultFreezeStatusTranslatorTest { @Mock private VerificationStrategies verificationStrategies; + @Mock + private ContractMetrics contractMetrics; + + private final SystemContractMethodRegistry systemContractMethodRegistry = new SystemContractMethodRegistry(); + private DefaultFreezeStatusTranslator subject; @BeforeEach void setUp() { - subject = new DefaultFreezeStatusTranslator(); + subject = new DefaultFreezeStatusTranslator(systemContractMethodRegistry, contractMetrics); } @Test void matchesDefaultFreezeTranslatorTest() { attempt = prepareHtsAttemptWithSelector( - DEFAULT_FREEZE_STATUS, subject, enhancement, addressIdConverter, verificationStrategies, gasCalculator); - assertTrue(subject.matches(attempt)); + DEFAULT_FREEZE_STATUS, + subject, + enhancement, + addressIdConverter, + verificationStrategies, + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test void matchesFailsIfIncorrectSelectorTest() { attempt = prepareHtsAttemptWithSelector( - BURN_TOKEN_V2, subject, enhancement, addressIdConverter, verificationStrategies, gasCalculator); - assertFalse(subject.matches(attempt)); + BURN_TOKEN_V2, + subject, + enhancement, + addressIdConverter, + verificationStrategies, + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isEmpty(); } @Test diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/defaultkycstatus/DefaultKycStatusTranslatorTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/defaultkycstatus/DefaultKycStatusTranslatorTest.java index 659ec1afd115..25fa7d5c7589 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/defaultkycstatus/DefaultKycStatusTranslatorTest.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/defaultkycstatus/DefaultKycStatusTranslatorTest.java @@ -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. @@ -21,17 +21,17 @@ import static com.hedera.node.app.service.contract.impl.test.TestHelpers.FUNGIBLE_TOKEN_HEADLONG_ADDRESS; import static com.hedera.node.app.service.contract.impl.test.exec.systemcontracts.CallAttemptHelpers.prepareHtsAttemptWithSelector; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.BDDMockito.given; import com.esaulpaugh.headlong.abi.Tuple; import com.hedera.node.app.service.contract.impl.exec.gas.SystemContractGasCalculator; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.scope.VerificationStrategies; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.AddressIdConverter; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.defaultkycstatus.DefaultKycStatusCall; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.defaultkycstatus.DefaultKycStatusTranslator; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.hevm.HederaWorldUpdater.Enhancement; import org.apache.tuweni.bytes.Bytes; import org.junit.jupiter.api.BeforeEach; @@ -57,25 +57,42 @@ class DefaultKycStatusTranslatorTest { @Mock private VerificationStrategies verificationStrategies; + @Mock + private ContractMetrics contractMetrics; + + private final SystemContractMethodRegistry systemContractMethodRegistry = new SystemContractMethodRegistry(); + private DefaultKycStatusTranslator subject; @BeforeEach void setUp() { - subject = new DefaultKycStatusTranslator(); + subject = new DefaultKycStatusTranslator(systemContractMethodRegistry, contractMetrics); } @Test void matchesDefaultKycTranslatorTest() { attempt = prepareHtsAttemptWithSelector( - DEFAULT_KYC_STATUS, subject, enhancement, addressIdConverter, verificationStrategies, gasCalculator); - assertTrue(subject.matches(attempt)); + DEFAULT_KYC_STATUS, + subject, + enhancement, + addressIdConverter, + verificationStrategies, + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test void matchesFailsIfIncorrectSelectorTest() { attempt = prepareHtsAttemptWithSelector( - BURN_TOKEN_V2, subject, enhancement, addressIdConverter, verificationStrategies, gasCalculator); - assertFalse(subject.matches(attempt)); + BURN_TOKEN_V2, + subject, + enhancement, + addressIdConverter, + verificationStrategies, + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isEmpty(); } @Test diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/delete/DeleteTranslatorTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/delete/DeleteTranslatorTest.java index f7197a42a9b4..fd740c9a9e6c 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/delete/DeleteTranslatorTest.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/delete/DeleteTranslatorTest.java @@ -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. @@ -22,19 +22,19 @@ import static com.hedera.node.app.service.contract.impl.test.TestHelpers.NON_SYSTEM_ACCOUNT_ID; import static com.hedera.node.app.service.contract.impl.test.exec.systemcontracts.CallAttemptHelpers.prepareHtsAttemptWithSelector; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.BDDMockito.given; import com.esaulpaugh.headlong.abi.Tuple; import com.hedera.node.app.service.contract.impl.exec.gas.SystemContractGasCalculator; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.scope.VerificationStrategies; 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.systemcontracts.hts.DispatchForResponseCodeHtsCall; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.delete.DeleteTranslator; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.hevm.HederaWorldUpdater; import org.apache.tuweni.bytes.Bytes; import org.junit.jupiter.api.BeforeEach; @@ -63,25 +63,42 @@ class DeleteTranslatorTest { @Mock private VerificationStrategies verificationStrategies; + @Mock + private ContractMetrics contractMetrics; + + private final SystemContractMethodRegistry systemContractMethodRegistry = new SystemContractMethodRegistry(); + private DeleteTranslator subject; @BeforeEach void setUp() { - subject = new DeleteTranslator(); + subject = new DeleteTranslator(systemContractMethodRegistry, contractMetrics); } @Test void matchesDelete() { attempt = prepareHtsAttemptWithSelector( - DELETE_TOKEN, subject, enhancement, addressIdConverter, verificationStrategies, gasCalculator); - assertTrue(subject.matches(attempt)); + DELETE_TOKEN, + subject, + enhancement, + addressIdConverter, + verificationStrategies, + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test void matchesFailsIfIncorrectSelectorTest() { attempt = prepareHtsAttemptWithSelector( - BURN_TOKEN_V2, subject, enhancement, addressIdConverter, verificationStrategies, gasCalculator); - assertFalse(subject.matches(attempt)); + BURN_TOKEN_V2, + subject, + enhancement, + addressIdConverter, + verificationStrategies, + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isEmpty(); } @Test diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/freeze/FreezeUnfreezeTranslatorTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/freeze/FreezeUnfreezeTranslatorTest.java index f7b385fedb4d..2abbd17f6e78 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/freeze/FreezeUnfreezeTranslatorTest.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/freeze/FreezeUnfreezeTranslatorTest.java @@ -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. @@ -20,15 +20,16 @@ import static com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.freeze.FreezeUnfreezeTranslator.FREEZE; import static com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.freeze.FreezeUnfreezeTranslator.UNFREEZE; import static com.hedera.node.app.service.contract.impl.test.exec.systemcontracts.CallAttemptHelpers.prepareHtsAttemptWithSelector; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; import com.hedera.node.app.service.contract.impl.exec.gas.SystemContractGasCalculator; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.scope.VerificationStrategies; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.AddressIdConverter; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.freeze.FreezeUnfreezeDecoder; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.freeze.FreezeUnfreezeTranslator; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.hevm.HederaWorldUpdater.Enhancement; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -54,32 +55,55 @@ class FreezeUnfreezeTranslatorTest { @Mock private VerificationStrategies verificationStrategies; + @Mock + private ContractMetrics contractMetrics; + + private final SystemContractMethodRegistry systemContractMethodRegistry = new SystemContractMethodRegistry(); + private final FreezeUnfreezeDecoder decoder = new FreezeUnfreezeDecoder(); private FreezeUnfreezeTranslator subject; @BeforeEach void setUp() { - subject = new FreezeUnfreezeTranslator(decoder); + subject = new FreezeUnfreezeTranslator(decoder, systemContractMethodRegistry, contractMetrics); } @Test void freezeMatches() { attempt = prepareHtsAttemptWithSelector( - FREEZE, subject, enhancement, addressIdConverter, verificationStrategies, gasCalculator); - assertTrue(subject.matches(attempt)); + FREEZE, + subject, + enhancement, + addressIdConverter, + verificationStrategies, + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test void unfreezeMatches() { attempt = prepareHtsAttemptWithSelector( - UNFREEZE, subject, enhancement, addressIdConverter, verificationStrategies, gasCalculator); - assertTrue(subject.matches(attempt)); + UNFREEZE, + subject, + enhancement, + addressIdConverter, + verificationStrategies, + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test void falseOnInvalidSelector() { attempt = prepareHtsAttemptWithSelector( - BURN_TOKEN_V2, subject, enhancement, addressIdConverter, verificationStrategies, gasCalculator); - assertFalse(subject.matches(attempt)); + BURN_TOKEN_V2, + subject, + enhancement, + addressIdConverter, + verificationStrategies, + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isEmpty(); } } diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/fungibletokeninfo/FungibleTokenInfoCallTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/fungibletokeninfo/FungibleTokenInfoCallTest.java index e05e758382e9..02d9a30b8b35 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/fungibletokeninfo/FungibleTokenInfoCallTest.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/fungibletokeninfo/FungibleTokenInfoCallTest.java @@ -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. @@ -63,7 +63,12 @@ void returnsFungibleTokenInfoStatusForPresentToken() { when(ledgerConfig.id()).thenReturn(expectedLedgerId); final var subject = new FungibleTokenInfoCall( - gasCalculator, mockEnhancement(), false, FUNGIBLE_EVERYTHING_TOKEN, config, FUNGIBLE_TOKEN_INFO); + gasCalculator, + mockEnhancement(), + false, + FUNGIBLE_EVERYTHING_TOKEN, + config, + FUNGIBLE_TOKEN_INFO.function()); final var result = subject.execute().fullResult().result(); @@ -106,7 +111,12 @@ void returnsFungibleTokenInfoStatusForPresentTokenV2() { when(ledgerConfig.id()).thenReturn(expectedLedgerId); final var subject = new FungibleTokenInfoCall( - gasCalculator, mockEnhancement(), false, FUNGIBLE_EVERYTHING_TOKEN_V2, config, FUNGIBLE_TOKEN_INFO_V2); + gasCalculator, + mockEnhancement(), + false, + FUNGIBLE_EVERYTHING_TOKEN_V2, + config, + FUNGIBLE_TOKEN_INFO_V2.function()); final var result = subject.execute().fullResult().result(); @@ -150,8 +160,8 @@ void returnsFungibleTokenInfoStatusForMissingToken() { final var expectedLedgerId = com.hedera.pbj.runtime.io.buffer.Bytes.fromHex("01"); when(ledgerConfig.id()).thenReturn(expectedLedgerId); - final var subject = - new FungibleTokenInfoCall(gasCalculator, mockEnhancement(), false, null, config, FUNGIBLE_TOKEN_INFO); + final var subject = new FungibleTokenInfoCall( + gasCalculator, mockEnhancement(), false, null, config, FUNGIBLE_TOKEN_INFO.function()); final var result = subject.execute().fullResult().result(); @@ -192,8 +202,8 @@ void returnsFungibleTokenInfoStatusForMissingTokenStaticCall() { when(config.getConfigData(LedgerConfig.class)).thenReturn(ledgerConfig); when(ledgerConfig.id()).thenReturn(com.hedera.pbj.runtime.io.buffer.Bytes.fromHex("01")); - final var subject = - new FungibleTokenInfoCall(gasCalculator, mockEnhancement(), true, null, config, FUNGIBLE_TOKEN_INFO); + final var subject = new FungibleTokenInfoCall( + gasCalculator, mockEnhancement(), true, null, config, FUNGIBLE_TOKEN_INFO.function()); final var result = subject.execute().fullResult().result(); @@ -206,8 +216,8 @@ void returnsFungibleTokenInfoStatusForMissingTokenStaticCallV2() { when(config.getConfigData(LedgerConfig.class)).thenReturn(ledgerConfig); when(ledgerConfig.id()).thenReturn(com.hedera.pbj.runtime.io.buffer.Bytes.fromHex("01")); - final var subject = - new FungibleTokenInfoCall(gasCalculator, mockEnhancement(), true, null, config, FUNGIBLE_TOKEN_INFO_V2); + final var subject = new FungibleTokenInfoCall( + gasCalculator, mockEnhancement(), true, null, config, FUNGIBLE_TOKEN_INFO_V2.function()); final var result = subject.execute().fullResult().result(); diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/fungibletokeninfo/FungibleTokenInfoTranslatorTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/fungibletokeninfo/FungibleTokenInfoTranslatorTest.java index 7e2ea0055dcd..a068649cf15c 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/fungibletokeninfo/FungibleTokenInfoTranslatorTest.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/fungibletokeninfo/FungibleTokenInfoTranslatorTest.java @@ -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. @@ -23,17 +23,17 @@ import static com.hedera.node.app.service.contract.impl.test.exec.systemcontracts.CallAttemptHelpers.prepareHtsAttemptWithSelector; import static com.hedera.node.app.service.contract.impl.test.exec.systemcontracts.CallAttemptHelpers.prepareHtsAttemptWithSelectorAndCustomConfig; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.BDDMockito.given; import com.esaulpaugh.headlong.abi.Tuple; import com.hedera.node.app.service.contract.impl.exec.gas.SystemContractGasCalculator; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.scope.VerificationStrategies; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.AddressIdConverter; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.fungibletokeninfo.FungibleTokenInfoCall; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.fungibletokeninfo.FungibleTokenInfoTranslator; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.hevm.HederaWorldUpdater.Enhancement; import com.hedera.node.config.data.ContractsConfig; import com.swirlds.config.api.Configuration; @@ -67,18 +67,29 @@ class FungibleTokenInfoTranslatorTest { @Mock private ContractsConfig contractsConfig; + @Mock + private ContractMetrics contractMetrics; + + private final SystemContractMethodRegistry systemContractMethodRegistry = new SystemContractMethodRegistry(); + private FungibleTokenInfoTranslator subject; @BeforeEach void setUp() { - subject = new FungibleTokenInfoTranslator(); + subject = new FungibleTokenInfoTranslator(systemContractMethodRegistry, contractMetrics); } @Test void matchesFungibleTokenInfoTranslatorTest() { attempt = prepareHtsAttemptWithSelector( - FUNGIBLE_TOKEN_INFO, subject, enhancement, addressIdConverter, verificationStrategies, gasCalculator); - assertTrue(subject.matches(attempt)); + FUNGIBLE_TOKEN_INFO, + subject, + enhancement, + addressIdConverter, + verificationStrategies, + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test @@ -92,15 +103,22 @@ void matchesFungibleTokenInfoTranslatorTestV2() { addressIdConverter, verificationStrategies, gasCalculator, + systemContractMethodRegistry, configuration); - assertTrue(subject.matches(attempt)); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test void matchesFailsIfIncorrectSelectorTest() { attempt = prepareHtsAttemptWithSelector( - BURN_TOKEN_V2, subject, enhancement, addressIdConverter, verificationStrategies, gasCalculator); - assertFalse(subject.matches(attempt)); + BURN_TOKEN_V2, + subject, + enhancement, + addressIdConverter, + verificationStrategies, + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isEmpty(); } @Test diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/getapproved/GetApprovedTranslatorTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/getapproved/GetApprovedTranslatorTest.java index 0a28fc47cf6a..3d5dca5a31cb 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/getapproved/GetApprovedTranslatorTest.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/getapproved/GetApprovedTranslatorTest.java @@ -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. @@ -24,20 +24,20 @@ import static com.hedera.node.app.service.contract.impl.test.exec.systemcontracts.CallAttemptHelpers.prepareHtsAttemptWithSelectorForRedirect; import static com.hedera.node.app.service.contract.impl.utils.ConversionUtils.fromHeadlongAddress; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.BDDMockito.given; import com.esaulpaugh.headlong.abi.Tuple; import com.hedera.hapi.node.state.token.Token; import com.hedera.node.app.service.contract.impl.exec.gas.SystemContractGasCalculator; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.scope.HederaNativeOperations; import com.hedera.node.app.service.contract.impl.exec.scope.VerificationStrategies; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.AddressIdConverter; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.getapproved.GetApprovedCall; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.getapproved.GetApprovedTranslator; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.hevm.HederaWorldUpdater; import java.math.BigInteger; import org.apache.tuweni.bytes.Bytes; @@ -73,11 +73,16 @@ public class GetApprovedTranslatorTest { @Mock private HederaNativeOperations nativeOperations; + @Mock + private ContractMetrics contractMetrics; + + private final SystemContractMethodRegistry systemContractMethodRegistry = new SystemContractMethodRegistry(); + private GetApprovedTranslator subject; @BeforeEach void setUp() { - subject = new GetApprovedTranslator(); + subject = new GetApprovedTranslator(systemContractMethodRegistry, contractMetrics); } @Test @@ -85,22 +90,40 @@ void matchesErcGetApprovedTest() { given(enhancement.nativeOperations()).willReturn(nativeOperations); given(nativeOperations.getToken(anyLong())).willReturn(FUNGIBLE_TOKEN); attempt = prepareHtsAttemptWithSelectorForRedirect( - ERC_GET_APPROVED, subject, enhancement, addressIdConverter, verificationStrategies, gasCalculator); - assertTrue(subject.matches(attempt)); + ERC_GET_APPROVED, + subject, + enhancement, + addressIdConverter, + verificationStrategies, + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test void matchesHapiGetApprovedTest() { attempt = prepareHtsAttemptWithSelector( - HAPI_GET_APPROVED, subject, enhancement, addressIdConverter, verificationStrategies, gasCalculator); - assertTrue(subject.matches(attempt)); + HAPI_GET_APPROVED, + subject, + enhancement, + addressIdConverter, + verificationStrategies, + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test void matchesFailsOnIncorrectSelectorTest() { attempt = prepareHtsAttemptWithSelector( - BURN_TOKEN_V2, subject, enhancement, addressIdConverter, verificationStrategies, gasCalculator); - assertFalse(subject.matches(attempt)); + BURN_TOKEN_V2, + subject, + enhancement, + addressIdConverter, + verificationStrategies, + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isEmpty(); } @Test diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/grantapproval/GrantApprovalTranslatorTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/grantapproval/GrantApprovalTranslatorTest.java index f04ef6829ca9..1d2ad4ff7fac 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/grantapproval/GrantApprovalTranslatorTest.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/grantapproval/GrantApprovalTranslatorTest.java @@ -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. @@ -30,9 +30,8 @@ import static com.hedera.node.app.service.contract.impl.test.TestHelpers.UNAUTHORIZED_SPENDER_ID; import static com.hedera.node.app.service.contract.impl.test.exec.systemcontracts.CallAttemptHelpers.prepareHtsAttemptWithSelector; import static com.hedera.node.app.service.contract.impl.test.exec.systemcontracts.CallAttemptHelpers.prepareHtsAttemptWithSelectorForRedirect; -import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertInstanceOf; -import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.BDDMockito.given; @@ -40,6 +39,7 @@ import com.esaulpaugh.headlong.abi.Tuple; import com.hedera.hapi.node.base.TokenType; import com.hedera.node.app.service.contract.impl.exec.gas.SystemContractGasCalculator; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.scope.HederaNativeOperations; import com.hedera.node.app.service.contract.impl.exec.scope.VerificationStrategies; import com.hedera.node.app.service.contract.impl.exec.scope.VerificationStrategy; @@ -49,6 +49,7 @@ import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.grantapproval.ERCGrantApprovalCall; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.grantapproval.GrantApprovalDecoder; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.grantapproval.GrantApprovalTranslator; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.hevm.HederaWorldUpdater; import java.math.BigInteger; import org.apache.tuweni.bytes.Bytes; @@ -82,19 +83,30 @@ class GrantApprovalTranslatorTest { @Mock private HederaNativeOperations nativeOperations; + @Mock + private ContractMetrics contractMetrics; + + private final SystemContractMethodRegistry systemContractMethodRegistry = new SystemContractMethodRegistry(); + private final GrantApprovalDecoder decoder = new GrantApprovalDecoder(); private GrantApprovalTranslator subject; @BeforeEach void setUp() { - subject = new GrantApprovalTranslator(decoder); + subject = new GrantApprovalTranslator(decoder, systemContractMethodRegistry, contractMetrics); } @Test void grantApprovalMatches() { attempt = prepareHtsAttemptWithSelector( - GRANT_APPROVAL, subject, enhancement, addressIdConverter, verificationStrategies, gasCalculator); - assertTrue(subject.matches(attempt)); + GRANT_APPROVAL, + subject, + enhancement, + addressIdConverter, + verificationStrategies, + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test @@ -102,8 +114,14 @@ void ERCGrantApprovalMatches() { given(enhancement.nativeOperations()).willReturn(nativeOperations); given(nativeOperations.getToken(anyLong())).willReturn(FUNGIBLE_TOKEN); attempt = prepareHtsAttemptWithSelectorForRedirect( - ERC_GRANT_APPROVAL, subject, enhancement, addressIdConverter, verificationStrategies, gasCalculator); - assertTrue(subject.matches(attempt)); + ERC_GRANT_APPROVAL, + subject, + enhancement, + addressIdConverter, + verificationStrategies, + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test @@ -116,22 +134,35 @@ void ERCGrantApprovalNFTMatches() { enhancement, addressIdConverter, verificationStrategies, - gasCalculator); - assertTrue(subject.matches(attempt)); + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test void grantApprovalNFTMatches() { attempt = prepareHtsAttemptWithSelector( - GRANT_APPROVAL_NFT, subject, enhancement, addressIdConverter, verificationStrategies, gasCalculator); - assertTrue(subject.matches(attempt)); + GRANT_APPROVAL_NFT, + subject, + enhancement, + addressIdConverter, + verificationStrategies, + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test void falseOnInvalidSelector() { attempt = prepareHtsAttemptWithSelector( - BURN_TOKEN_V2, subject, enhancement, addressIdConverter, verificationStrategies, gasCalculator); - assertFalse(subject.matches(attempt)); + BURN_TOKEN_V2, + subject, + enhancement, + addressIdConverter, + verificationStrategies, + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isEmpty(); } @Test diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/grantrevokekyc/GrantRevokeKycTranslatorTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/grantrevokekyc/GrantRevokeKycTranslatorTest.java index bf770ec30f67..ec5b312c6651 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/grantrevokekyc/GrantRevokeKycTranslatorTest.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/grantrevokekyc/GrantRevokeKycTranslatorTest.java @@ -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. @@ -20,15 +20,16 @@ import static com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.grantrevokekyc.GrantRevokeKycTranslator.GRANT_KYC; import static com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.grantrevokekyc.GrantRevokeKycTranslator.REVOKE_KYC; import static com.hedera.node.app.service.contract.impl.test.exec.systemcontracts.CallAttemptHelpers.prepareHtsAttemptWithSelector; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; import com.hedera.node.app.service.contract.impl.exec.gas.SystemContractGasCalculator; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.scope.VerificationStrategies; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.AddressIdConverter; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.grantrevokekyc.GrantRevokeKycDecoder; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.grantrevokekyc.GrantRevokeKycTranslator; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.hevm.HederaWorldUpdater.Enhancement; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -53,32 +54,55 @@ class GrantRevokeKycTranslatorTest { @Mock private VerificationStrategies verificationStrategies; + @Mock + private ContractMetrics contractMetrics; + + private final SystemContractMethodRegistry systemContractMethodRegistry = new SystemContractMethodRegistry(); + private final GrantRevokeKycDecoder decoder = new GrantRevokeKycDecoder(); private GrantRevokeKycTranslator subject; @BeforeEach void setUp() { - subject = new GrantRevokeKycTranslator(decoder); + subject = new GrantRevokeKycTranslator(decoder, systemContractMethodRegistry, contractMetrics); } @Test void matchesGrantKycTest() { attempt = prepareHtsAttemptWithSelector( - GRANT_KYC, subject, enhancement, addressIdConverter, verificationStrategies, gasCalculator); - assertTrue(subject.matches(attempt)); + GRANT_KYC, + subject, + enhancement, + addressIdConverter, + verificationStrategies, + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test void matchesRevokeKycTest() { attempt = prepareHtsAttemptWithSelector( - REVOKE_KYC, subject, enhancement, addressIdConverter, verificationStrategies, gasCalculator); - assertTrue(subject.matches(attempt)); + REVOKE_KYC, + subject, + enhancement, + addressIdConverter, + verificationStrategies, + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test void matchesFailsWithIncorrectSelector() { attempt = prepareHtsAttemptWithSelector( - BURN_TOKEN_V2, subject, enhancement, addressIdConverter, verificationStrategies, gasCalculator); - assertFalse(subject.matches(attempt)); + BURN_TOKEN_V2, + subject, + enhancement, + addressIdConverter, + verificationStrategies, + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isEmpty(); } } diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/isassociated/IsAssociatedTranslatorTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/isassociated/IsAssociatedTranslatorTest.java index 90031120546d..450922514eb7 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/isassociated/IsAssociatedTranslatorTest.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/isassociated/IsAssociatedTranslatorTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2024 Hedera Hashgraph, LLC + * Copyright (C) 2024-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. @@ -20,9 +20,8 @@ import static com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.isassociated.IsAssociatedTranslator.IS_ASSOCIATED; import static com.hedera.node.app.service.contract.impl.test.TestHelpers.FUNGIBLE_TOKEN; import static com.hedera.node.app.service.contract.impl.test.exec.systemcontracts.CallAttemptHelpers.prepareHtsAttemptWithSelectorForRedirect; -import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertInstanceOf; -import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.when; @@ -30,12 +29,14 @@ import com.hedera.hapi.node.base.AccountID; import com.hedera.hapi.node.state.token.Token; import com.hedera.node.app.service.contract.impl.exec.gas.SystemContractGasCalculator; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.scope.HederaNativeOperations; import com.hedera.node.app.service.contract.impl.exec.scope.VerificationStrategies; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.AddressIdConverter; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.isassociated.IsAssociatedCall; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.isassociated.IsAssociatedTranslator; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.hevm.HederaWorldUpdater.Enhancement; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -64,11 +65,16 @@ class IsAssociatedTranslatorTest { @Mock private HederaNativeOperations nativeOperations; + @Mock + private ContractMetrics contractMetrics; + + private final SystemContractMethodRegistry systemContractMethodRegistry = new SystemContractMethodRegistry(); + private IsAssociatedTranslator translator; @BeforeEach void setUp() { - translator = new IsAssociatedTranslator(); + translator = new IsAssociatedTranslator(systemContractMethodRegistry, contractMetrics); } @Test @@ -76,8 +82,14 @@ void matchesWithCorrectSelectorAndTokenRedirectReturnsTrue() { given(enhancement.nativeOperations()).willReturn(nativeOperations); given(nativeOperations.getToken(anyLong())).willReturn(FUNGIBLE_TOKEN); mockAttempt = prepareHtsAttemptWithSelectorForRedirect( - IS_ASSOCIATED, translator, enhancement, addressIdConverter, verificationStrategies, gasCalculator); - assertTrue(translator.matches(mockAttempt)); + IS_ASSOCIATED, + translator, + enhancement, + addressIdConverter, + verificationStrategies, + gasCalculator, + systemContractMethodRegistry); + assertThat(translator.identifyMethod(mockAttempt)).isPresent(); } @Test @@ -85,14 +97,20 @@ void matchesWithIncorrectSelectorReturnsFalse() { given(enhancement.nativeOperations()).willReturn(nativeOperations); given(nativeOperations.getToken(anyLong())).willReturn(FUNGIBLE_TOKEN); mockAttempt = prepareHtsAttemptWithSelectorForRedirect( - BURN_TOKEN_V2, translator, enhancement, addressIdConverter, verificationStrategies, gasCalculator); - assertFalse(translator.matches(mockAttempt)); + BURN_TOKEN_V2, + translator, + enhancement, + addressIdConverter, + verificationStrategies, + gasCalculator, + systemContractMethodRegistry); + assertThat(translator.identifyMethod(mockAttempt)).isEmpty(); } @Test void matchesWithTokenRedirectFalseReturnsFalse() { when(mockAttempt.isTokenRedirect()).thenReturn(false); - assertFalse(translator.matches(mockAttempt)); + assertThat(translator.identifyMethod(mockAttempt)).isEmpty(); } @Test diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/isfrozen/IsFrozenTranslatorTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/isfrozen/IsFrozenTranslatorTest.java index bcd26241eaf3..c53636eab1dc 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/isfrozen/IsFrozenTranslatorTest.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/isfrozen/IsFrozenTranslatorTest.java @@ -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. @@ -23,18 +23,18 @@ import static com.hedera.node.app.service.contract.impl.test.exec.systemcontracts.CallAttemptHelpers.prepareHtsAttemptWithSelector; import static com.hedera.node.app.service.contract.impl.utils.ConversionUtils.fromHeadlongAddress; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.BDDMockito.given; import com.esaulpaugh.headlong.abi.Tuple; import com.hedera.hapi.node.state.token.Token; import com.hedera.node.app.service.contract.impl.exec.gas.SystemContractGasCalculator; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.scope.VerificationStrategies; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.AddressIdConverter; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.isfrozen.IsFrozenCall; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.isfrozen.IsFrozenTranslator; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.hevm.HederaWorldUpdater.Enhancement; import org.apache.tuweni.bytes.Bytes; import org.junit.jupiter.api.BeforeEach; @@ -63,25 +63,42 @@ class IsFrozenTranslatorTest { @Mock private VerificationStrategies verificationStrategies; + @Mock + private ContractMetrics contractMetrics; + + private final SystemContractMethodRegistry systemContractMethodRegistry = new SystemContractMethodRegistry(); + private IsFrozenTranslator subject; @BeforeEach void setUp() { - subject = new IsFrozenTranslator(); + subject = new IsFrozenTranslator(systemContractMethodRegistry, contractMetrics); } @Test void matchesIsFrozenTest() { attempt = prepareHtsAttemptWithSelector( - IS_FROZEN, subject, enhancement, addressIdConverter, verificationStrategies, gasCalculator); - assertTrue(subject.matches(attempt)); + IS_FROZEN, + subject, + enhancement, + addressIdConverter, + verificationStrategies, + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test void matchesFailsIfIncorrectSelectorTest() { attempt = prepareHtsAttemptWithSelector( - BURN_TOKEN_V2, subject, enhancement, addressIdConverter, verificationStrategies, gasCalculator); - assertFalse(subject.matches(attempt)); + BURN_TOKEN_V2, + subject, + enhancement, + addressIdConverter, + verificationStrategies, + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isEmpty(); } @Test diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/iskyc/IsKycTranslatorTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/iskyc/IsKycTranslatorTest.java index 9d7b901b7b73..eea06d079904 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/iskyc/IsKycTranslatorTest.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/iskyc/IsKycTranslatorTest.java @@ -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. @@ -23,18 +23,18 @@ import static com.hedera.node.app.service.contract.impl.test.exec.systemcontracts.CallAttemptHelpers.prepareHtsAttemptWithSelector; import static com.hedera.node.app.service.contract.impl.utils.ConversionUtils.fromHeadlongAddress; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.BDDMockito.given; import com.esaulpaugh.headlong.abi.Tuple; import com.hedera.hapi.node.state.token.Token; import com.hedera.node.app.service.contract.impl.exec.gas.SystemContractGasCalculator; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.scope.VerificationStrategies; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.AddressIdConverter; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.iskyc.IsKycCall; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.iskyc.IsKycTranslator; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.hevm.HederaWorldUpdater.Enhancement; import org.apache.tuweni.bytes.Bytes; import org.junit.jupiter.api.BeforeEach; @@ -63,25 +63,42 @@ class IsKycTranslatorTest { @Mock private VerificationStrategies verificationStrategies; + @Mock + private ContractMetrics contractMetrics; + + private final SystemContractMethodRegistry systemContractMethodRegistry = new SystemContractMethodRegistry(); + private IsKycTranslator subject; @BeforeEach void setUp() { - subject = new IsKycTranslator(); + subject = new IsKycTranslator(systemContractMethodRegistry, contractMetrics); } @Test void matchesIsKycTest() { attempt = prepareHtsAttemptWithSelector( - IS_KYC, subject, enhancement, addressIdConverter, verificationStrategies, gasCalculator); - assertTrue(subject.matches(attempt)); + IS_KYC, + subject, + enhancement, + addressIdConverter, + verificationStrategies, + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test void matchesFailsIfIncorrectSelectorTest() { attempt = prepareHtsAttemptWithSelector( - BURN_TOKEN_V2, subject, enhancement, addressIdConverter, verificationStrategies, gasCalculator); - assertFalse(subject.matches(attempt)); + BURN_TOKEN_V2, + subject, + enhancement, + addressIdConverter, + verificationStrategies, + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isEmpty(); } @Test diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/istoken/IsTokenTranslatorTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/istoken/IsTokenTranslatorTest.java index e1bb35eb85c6..08ffc3ad43d9 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/istoken/IsTokenTranslatorTest.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/istoken/IsTokenTranslatorTest.java @@ -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. @@ -21,17 +21,17 @@ import static com.hedera.node.app.service.contract.impl.test.TestHelpers.FUNGIBLE_TOKEN_HEADLONG_ADDRESS; import static com.hedera.node.app.service.contract.impl.test.exec.systemcontracts.CallAttemptHelpers.prepareHtsAttemptWithSelector; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.BDDMockito.given; import com.esaulpaugh.headlong.abi.Tuple; import com.hedera.node.app.service.contract.impl.exec.gas.SystemContractGasCalculator; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.scope.VerificationStrategies; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.AddressIdConverter; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.istoken.IsTokenCall; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.istoken.IsTokenTranslator; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.hevm.HederaWorldUpdater.Enhancement; import org.apache.tuweni.bytes.Bytes; import org.junit.jupiter.api.BeforeEach; @@ -57,25 +57,42 @@ class IsTokenTranslatorTest { @Mock private VerificationStrategies verificationStrategies; + @Mock + private ContractMetrics contractMetrics; + + private final SystemContractMethodRegistry systemContractMethodRegistry = new SystemContractMethodRegistry(); + private IsTokenTranslator subject; @BeforeEach void setUp() { - subject = new IsTokenTranslator(); + subject = new IsTokenTranslator(systemContractMethodRegistry, contractMetrics); } @Test void matchesIsTokenTest() { attempt = prepareHtsAttemptWithSelector( - IS_TOKEN, subject, enhancement, addressIdConverter, verificationStrategies, gasCalculator); - assertTrue(subject.matches(attempt)); + IS_TOKEN, + subject, + enhancement, + addressIdConverter, + verificationStrategies, + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test void matchesFailsIfIncorrectSelectorTest() { attempt = prepareHtsAttemptWithSelector( - BURN_TOKEN_V2, subject, enhancement, addressIdConverter, verificationStrategies, gasCalculator); - assertFalse(subject.matches(attempt)); + BURN_TOKEN_V2, + subject, + enhancement, + addressIdConverter, + verificationStrategies, + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isEmpty(); } @Test diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/mint/MintTranslatorTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/mint/MintTranslatorTest.java index 2e7bd891de75..6afada400dcb 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/mint/MintTranslatorTest.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/mint/MintTranslatorTest.java @@ -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. @@ -20,15 +20,16 @@ import static com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.mint.MintTranslator.MINT; import static com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.mint.MintTranslator.MINT_V2; import static com.hedera.node.app.service.contract.impl.test.exec.systemcontracts.CallAttemptHelpers.prepareHtsAttemptWithSelector; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; import com.hedera.node.app.service.contract.impl.exec.gas.SystemContractGasCalculator; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.scope.VerificationStrategies; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.AddressIdConverter; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.mint.MintDecoder; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.mint.MintTranslator; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.hevm.HederaWorldUpdater.Enhancement; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -53,33 +54,56 @@ class MintTranslatorTest { @Mock private VerificationStrategies verificationStrategies; + @Mock + private ContractMetrics contractMetrics; + + private final SystemContractMethodRegistry systemContractMethodRegistry = new SystemContractMethodRegistry(); + private MintTranslator subject; private final MintDecoder decoder = new MintDecoder(); @BeforeEach void setUp() { - subject = new MintTranslator(decoder); + subject = new MintTranslator(decoder, systemContractMethodRegistry, contractMetrics); } @Test void matchesMintV1Test() { attempt = prepareHtsAttemptWithSelector( - MINT, subject, enhancement, addressIdConverter, verificationStrategies, gasCalculator); - assertTrue(subject.matches(attempt)); + MINT, + subject, + enhancement, + addressIdConverter, + verificationStrategies, + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test void matchesMintV2Test() { attempt = prepareHtsAttemptWithSelector( - MINT_V2, subject, enhancement, addressIdConverter, verificationStrategies, gasCalculator); - assertTrue(subject.matches(attempt)); + MINT_V2, + subject, + enhancement, + addressIdConverter, + verificationStrategies, + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test void matchFailsOnIncorrectSelectorTest() { attempt = prepareHtsAttemptWithSelector( - BURN_TOKEN_V2, subject, enhancement, addressIdConverter, verificationStrategies, gasCalculator); - assertFalse(subject.matches(attempt)); + BURN_TOKEN_V2, + subject, + enhancement, + addressIdConverter, + verificationStrategies, + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isEmpty(); } } diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/nfttokeninfo/NftTokenInfoCallTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/nfttokeninfo/NftTokenInfoCallTest.java index 23a9afcfee0a..054b758e2ce9 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/nfttokeninfo/NftTokenInfoCallTest.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/nfttokeninfo/NftTokenInfoCallTest.java @@ -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. @@ -80,7 +80,7 @@ void returnsNftTokenInfoStatusForPresentToken() { FUNGIBLE_EVERYTHING_TOKEN, 2L, config, - NON_FUNGIBLE_TOKEN_INFO); + NON_FUNGIBLE_TOKEN_INFO.function()); final var result = subject.execute().fullResult().result(); @@ -139,7 +139,7 @@ void returnsNftTokenInfoStatusForPresentTokenV2() { FUNGIBLE_EVERYTHING_TOKEN_V2, 2L, config, - NON_FUNGIBLE_TOKEN_INFO_V2); + NON_FUNGIBLE_TOKEN_INFO_V2.function()); final var result = subject.execute().fullResult().result(); @@ -189,7 +189,7 @@ void returnsNftTokenInfoStatusForMissingToken() { when(ledgerConfig.id()).thenReturn(expectedLedgerId); final var subject = new NftTokenInfoCall( - gasCalculator, mockEnhancement(), false, null, 0L, config, NON_FUNGIBLE_TOKEN_INFO); + gasCalculator, mockEnhancement(), false, null, 0L, config, NON_FUNGIBLE_TOKEN_INFO.function()); final var result = subject.execute().fullResult().result(); @@ -231,8 +231,8 @@ void returnsNftTokenInfoStatusForMissingToken() { @Test void returnsNftTokenInfoStatusForMissingTokenStaticCall() { - final var subject = - new NftTokenInfoCall(gasCalculator, mockEnhancement(), true, null, 0L, config, NON_FUNGIBLE_TOKEN_INFO); + final var subject = new NftTokenInfoCall( + gasCalculator, mockEnhancement(), true, null, 0L, config, NON_FUNGIBLE_TOKEN_INFO.function()); final var result = subject.execute().fullResult().result(); @@ -243,7 +243,7 @@ void returnsNftTokenInfoStatusForMissingTokenStaticCall() { @Test void returnsNftTokenInfoStatusForMissingTokenStaticCallV2() { final var subject = new NftTokenInfoCall( - gasCalculator, mockEnhancement(), true, null, 0L, config, NON_FUNGIBLE_TOKEN_INFO_V2); + gasCalculator, mockEnhancement(), true, null, 0L, config, NON_FUNGIBLE_TOKEN_INFO_V2.function()); final var result = subject.execute().fullResult().result(); diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/nfttokeninfo/NftTokenInfoTranslatorTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/nfttokeninfo/NftTokenInfoTranslatorTest.java index 5516a98a808e..051c985b4556 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/nfttokeninfo/NftTokenInfoTranslatorTest.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/nfttokeninfo/NftTokenInfoTranslatorTest.java @@ -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. @@ -23,17 +23,17 @@ import static com.hedera.node.app.service.contract.impl.test.exec.systemcontracts.CallAttemptHelpers.prepareHtsAttemptWithSelector; import static com.hedera.node.app.service.contract.impl.test.exec.systemcontracts.CallAttemptHelpers.prepareHtsAttemptWithSelectorAndCustomConfig; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.BDDMockito.given; import com.esaulpaugh.headlong.abi.Tuple; import com.hedera.node.app.service.contract.impl.exec.gas.SystemContractGasCalculator; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.scope.VerificationStrategies; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.AddressIdConverter; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.nfttokeninfo.NftTokenInfoCall; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.nfttokeninfo.NftTokenInfoTranslator; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.hevm.HederaWorldUpdater.Enhancement; import com.hedera.node.config.data.ContractsConfig; import com.swirlds.config.api.Configuration; @@ -67,11 +67,16 @@ class NftTokenInfoTranslatorTest { @Mock private VerificationStrategies verificationStrategies; + @Mock + private ContractMetrics contractMetrics; + + private final SystemContractMethodRegistry systemContractMethodRegistry = new SystemContractMethodRegistry(); + private NftTokenInfoTranslator subject; @BeforeEach void setUp() { - subject = new NftTokenInfoTranslator(); + subject = new NftTokenInfoTranslator(systemContractMethodRegistry, contractMetrics); } @Test @@ -82,8 +87,9 @@ void matchesTokenInfoTranslatorTest() { enhancement, addressIdConverter, verificationStrategies, - gasCalculator); - assertTrue(subject.matches(attempt)); + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test @@ -97,15 +103,22 @@ void matchesTokenInfoTranslatorTestV2() { addressIdConverter, verificationStrategies, gasCalculator, + systemContractMethodRegistry, configuration); - assertTrue(subject.matches(attempt)); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test void matchesFailsIfIncorrectSelectorTest() { attempt = prepareHtsAttemptWithSelector( - BURN_TOKEN_V2, subject, enhancement, addressIdConverter, verificationStrategies, gasCalculator); - assertFalse(subject.matches(attempt)); + BURN_TOKEN_V2, + subject, + enhancement, + addressIdConverter, + verificationStrategies, + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isEmpty(); } @Test diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/pauses/PausesTranslatorTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/pauses/PausesTranslatorTest.java index 123e8d40255f..12e1fec23f0e 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/pauses/PausesTranslatorTest.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/pauses/PausesTranslatorTest.java @@ -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. @@ -20,15 +20,16 @@ import static com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.pauses.PausesTranslator.PAUSE; import static com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.pauses.PausesTranslator.UNPAUSE; import static com.hedera.node.app.service.contract.impl.test.exec.systemcontracts.CallAttemptHelpers.prepareHtsAttemptWithSelector; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; import com.hedera.node.app.service.contract.impl.exec.gas.SystemContractGasCalculator; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.scope.VerificationStrategies; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.AddressIdConverter; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.pauses.PausesDecoder; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.pauses.PausesTranslator; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.hevm.HederaWorldUpdater.Enhancement; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -53,33 +54,56 @@ public class PausesTranslatorTest { @Mock private VerificationStrategies verificationStrategies; - private PausesDecoder decoder = new PausesDecoder(); + @Mock + private ContractMetrics contractMetrics; + + private final SystemContractMethodRegistry systemContractMethodRegistry = new SystemContractMethodRegistry(); + + private final PausesDecoder decoder = new PausesDecoder(); private PausesTranslator subject; @BeforeEach void setUp() { - subject = new PausesTranslator(decoder); + subject = new PausesTranslator(decoder, systemContractMethodRegistry, contractMetrics); } @Test void matchesPauseTest() { attempt = prepareHtsAttemptWithSelector( - PAUSE, subject, enhancement, addressIdConverter, verificationStrategies, gasCalculator); - assertTrue(subject.matches(attempt)); + PAUSE, + subject, + enhancement, + addressIdConverter, + verificationStrategies, + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test void matchesUnpauseTest() { attempt = prepareHtsAttemptWithSelector( - UNPAUSE, subject, enhancement, addressIdConverter, verificationStrategies, gasCalculator); - assertTrue(subject.matches(attempt)); + UNPAUSE, + subject, + enhancement, + addressIdConverter, + verificationStrategies, + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test void matchesFailsOnIncorrectSelector() { attempt = prepareHtsAttemptWithSelector( - BURN_TOKEN_V2, subject, enhancement, addressIdConverter, verificationStrategies, gasCalculator); - assertFalse(subject.matches(attempt)); + BURN_TOKEN_V2, + subject, + enhancement, + addressIdConverter, + verificationStrategies, + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isEmpty(); } } diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/rejecttokens/RejectTokensTranslatorTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/rejecttokens/RejectTokensTranslatorTest.java index 62036e369899..90adf02d4a8a 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/rejecttokens/RejectTokensTranslatorTest.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/rejecttokens/RejectTokensTranslatorTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2024 Hedera Hashgraph, LLC + * Copyright (C) 2024-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. @@ -20,9 +20,8 @@ import static com.hedera.node.app.service.contract.impl.test.TestHelpers.SENDER_ID; import static com.hedera.node.app.service.contract.impl.test.exec.systemcontracts.CallAttemptHelpers.prepareHtsAttemptWithSelectorAndCustomConfig; import static com.hedera.node.app.service.contract.impl.test.exec.systemcontracts.CallAttemptHelpers.prepareHtsAttemptWithSelectorForRedirectWithConfig; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.BDDMockito.given; @@ -34,6 +33,7 @@ import com.hedera.hapi.node.transaction.TransactionBody; import com.hedera.node.app.service.contract.impl.exec.gas.DispatchType; import com.hedera.node.app.service.contract.impl.exec.gas.SystemContractGasCalculator; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.scope.HederaNativeOperations; import com.hedera.node.app.service.contract.impl.exec.scope.VerificationStrategies; import com.hedera.node.app.service.contract.impl.exec.scope.VerificationStrategy; @@ -43,6 +43,7 @@ import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.burn.BurnTranslator; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.rejecttokens.RejectTokensDecoder; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.rejecttokens.RejectTokensTranslator; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.hevm.HederaWorldUpdater.Enhancement; import com.hedera.node.config.data.ContractsConfig; import com.swirlds.config.api.Configuration; @@ -91,37 +92,36 @@ public class RejectTokensTranslatorTest { @Mock private AccountID payerId; + @Mock + private ContractMetrics contractMetrics; + + private final SystemContractMethodRegistry systemContractMethodRegistry = new SystemContractMethodRegistry(); + private RejectTokensTranslator subject; @BeforeEach void setUp() { - subject = new RejectTokensTranslator(decoder); + subject = new RejectTokensTranslator(decoder, systemContractMethodRegistry, contractMetrics); } @Test void matchesHTSWithInvalidSig() { - // given: given(configuration.getConfigData(ContractsConfig.class)).willReturn(contractsConfig); given(contractsConfig.systemContractRejectTokensEnabled()).willReturn(true); attempt = prepareHtsAttemptWithSelectorAndCustomConfig( - BurnTranslator.BURN_TOKEN_V1, + BurnTranslator.BURN_TOKEN_V1, // obvs wrong selector subject, enhancement, addressIdConverter, verificationStrategies, gasCalculator, + systemContractMethodRegistry, configuration); - - // when: - boolean matches = subject.matches(attempt); - - // then: - assertFalse(matches); + assertThat(subject.identifyMethod(attempt)).isEmpty(); } @Test void matchesHTSWithConfigEnabled() { - // given: given(configuration.getConfigData(ContractsConfig.class)).willReturn(contractsConfig); given(contractsConfig.systemContractRejectTokensEnabled()).willReturn(true); attempt = prepareHtsAttemptWithSelectorAndCustomConfig( @@ -131,18 +131,13 @@ void matchesHTSWithConfigEnabled() { addressIdConverter, verificationStrategies, gasCalculator, + systemContractMethodRegistry, configuration); - - // when: - boolean matches = subject.matches(attempt); - - // then: - assertTrue(matches); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test void matchesHTSWithConfigDisabled() { - // given: given(configuration.getConfigData(ContractsConfig.class)).willReturn(contractsConfig); given(contractsConfig.systemContractRejectTokensEnabled()).willReturn(false); attempt = prepareHtsAttemptWithSelectorAndCustomConfig( @@ -152,18 +147,13 @@ void matchesHTSWithConfigDisabled() { addressIdConverter, verificationStrategies, gasCalculator, + systemContractMethodRegistry, configuration); - - // when: - boolean matches = subject.matches(attempt); - - // then: - assertFalse(matches); + assertThat(subject.identifyMethod(attempt)).isEmpty(); } @Test void matchesFungibleHRCWithConfigEnabled() { - // given: given(configuration.getConfigData(ContractsConfig.class)).willReturn(contractsConfig); given(contractsConfig.systemContractRejectTokensEnabled()).willReturn(true); given(enhancement.nativeOperations()).willReturn(nativeOperations); @@ -174,18 +164,13 @@ void matchesFungibleHRCWithConfigEnabled() { addressIdConverter, verificationStrategies, gasCalculator, + systemContractMethodRegistry, configuration); - - // when: - boolean matches = subject.matches(attempt); - - // then: - assertTrue(matches); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test void matchesFungibleHRCWithConfigDisabled() { - // given: given(configuration.getConfigData(ContractsConfig.class)).willReturn(contractsConfig); given(contractsConfig.systemContractRejectTokensEnabled()).willReturn(false); given(enhancement.nativeOperations()).willReturn(nativeOperations); @@ -196,18 +181,13 @@ void matchesFungibleHRCWithConfigDisabled() { addressIdConverter, verificationStrategies, gasCalculator, + systemContractMethodRegistry, configuration); - - // when: - boolean matches = subject.matches(attempt); - - // then: - assertFalse(matches); + assertThat(subject.identifyMethod(attempt)).isEmpty(); } @Test void matchesNftHRCWithConfigEnabled() { - // given: given(configuration.getConfigData(ContractsConfig.class)).willReturn(contractsConfig); given(contractsConfig.systemContractRejectTokensEnabled()).willReturn(true); given(enhancement.nativeOperations()).willReturn(nativeOperations); @@ -218,18 +198,13 @@ void matchesNftHRCWithConfigEnabled() { addressIdConverter, verificationStrategies, gasCalculator, + systemContractMethodRegistry, configuration); - - // when: - boolean matches = subject.matches(attempt); - - // then: - assertTrue(matches); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test void matchesNftHRCWithConfigDisabled() { - // given: given(configuration.getConfigData(ContractsConfig.class)).willReturn(contractsConfig); given(contractsConfig.systemContractRejectTokensEnabled()).willReturn(false); given(enhancement.nativeOperations()).willReturn(nativeOperations); @@ -240,13 +215,9 @@ void matchesNftHRCWithConfigDisabled() { addressIdConverter, verificationStrategies, gasCalculator, + systemContractMethodRegistry, configuration); - - // when: - boolean matches = subject.matches(attempt); - - // then: - assertFalse(matches); + assertThat(subject.identifyMethod(attempt)).isEmpty(); } @Test @@ -302,6 +273,7 @@ void callFromHtsTokenReject() { addressIdConverter, verificationStrategies, gasCalculator, + systemContractMethodRegistry, configuration); // when: @@ -325,6 +297,7 @@ void callFromHRCCancelFTAirdrop() { addressIdConverter, verificationStrategies, gasCalculator, + systemContractMethodRegistry, configuration); // when: @@ -348,6 +321,7 @@ void callFromHRCCancelNFTAirdrop() { addressIdConverter, verificationStrategies, gasCalculator, + systemContractMethodRegistry, configuration); // when: diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/setapproval/SetApprovalForAllTranslatorTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/setapproval/SetApprovalForAllTranslatorTest.java index 287dd55eb857..7bce8627431b 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/setapproval/SetApprovalForAllTranslatorTest.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/setapproval/SetApprovalForAllTranslatorTest.java @@ -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. @@ -22,18 +22,19 @@ import static com.hedera.node.app.service.contract.impl.test.TestHelpers.FUNGIBLE_TOKEN; import static com.hedera.node.app.service.contract.impl.test.exec.systemcontracts.CallAttemptHelpers.prepareHtsAttemptWithSelector; import static com.hedera.node.app.service.contract.impl.test.exec.systemcontracts.CallAttemptHelpers.prepareHtsAttemptWithSelectorForRedirect; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.BDDMockito.given; import com.hedera.node.app.service.contract.impl.exec.gas.SystemContractGasCalculator; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.scope.HederaNativeOperations; import com.hedera.node.app.service.contract.impl.exec.scope.VerificationStrategies; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.AddressIdConverter; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.setapproval.SetApprovalForAllDecoder; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.setapproval.SetApprovalForAllTranslator; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.hevm.HederaWorldUpdater.Enhancement; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -62,20 +63,31 @@ public class SetApprovalForAllTranslatorTest { @Mock private HederaNativeOperations nativeOperations; + @Mock + private ContractMetrics contractMetrics; + private final SetApprovalForAllDecoder decoder = new SetApprovalForAllDecoder(); + private final SystemContractMethodRegistry systemContractMethodRegistry = new SystemContractMethodRegistry(); + private SetApprovalForAllTranslator subject; @BeforeEach void setUp() { - subject = new SetApprovalForAllTranslator(decoder); + subject = new SetApprovalForAllTranslator(decoder, systemContractMethodRegistry, contractMetrics); } @Test void matchesClassicalSelectorTest() { attempt = prepareHtsAttemptWithSelector( - SET_APPROVAL_FOR_ALL, subject, enhancement, addressIdConverter, verificationStrategies, gasCalculator); - assertTrue(subject.matches(attempt)); + SET_APPROVAL_FOR_ALL, + subject, + enhancement, + addressIdConverter, + verificationStrategies, + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test @@ -88,14 +100,21 @@ void matchesERCSelectorTest() { enhancement, addressIdConverter, verificationStrategies, - gasCalculator); - assertTrue(subject.matches(attempt)); + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test void falseOnInvalidSelector() { attempt = prepareHtsAttemptWithSelector( - BURN_TOKEN_V2, subject, enhancement, addressIdConverter, verificationStrategies, gasCalculator); - assertFalse(subject.matches(attempt)); + BURN_TOKEN_V2, + subject, + enhancement, + addressIdConverter, + verificationStrategies, + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isEmpty(); } } diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/tokenexpiry/TokenExpiryTranslatorTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/tokenexpiry/TokenExpiryTranslatorTest.java index f315e1cd12cd..4447b8be7760 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/tokenexpiry/TokenExpiryTranslatorTest.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/tokenexpiry/TokenExpiryTranslatorTest.java @@ -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. @@ -21,17 +21,17 @@ import static com.hedera.node.app.service.contract.impl.test.TestHelpers.FUNGIBLE_TOKEN_HEADLONG_ADDRESS; import static com.hedera.node.app.service.contract.impl.test.exec.systemcontracts.CallAttemptHelpers.prepareHtsAttemptWithSelector; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.BDDMockito.given; import com.esaulpaugh.headlong.abi.Tuple; import com.hedera.node.app.service.contract.impl.exec.gas.SystemContractGasCalculator; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.scope.VerificationStrategies; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.AddressIdConverter; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.tokenexpiry.TokenExpiryCall; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.tokenexpiry.TokenExpiryTranslator; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.hevm.HederaWorldUpdater.Enhancement; import org.apache.tuweni.bytes.Bytes; import org.junit.jupiter.api.BeforeEach; @@ -57,25 +57,42 @@ class TokenExpiryTranslatorTest { @Mock private VerificationStrategies verificationStrategies; + @Mock + private ContractMetrics contractMetrics; + + private final SystemContractMethodRegistry systemContractMethodRegistry = new SystemContractMethodRegistry(); + private TokenExpiryTranslator subject; @BeforeEach void setUp() { - subject = new TokenExpiryTranslator(); + subject = new TokenExpiryTranslator(systemContractMethodRegistry, contractMetrics); } @Test void matchesTokenExpiryTranslatorTest() { attempt = prepareHtsAttemptWithSelector( - TOKEN_EXPIRY, subject, enhancement, addressIdConverter, verificationStrategies, gasCalculator); - assertTrue(subject.matches(attempt)); + TOKEN_EXPIRY, + subject, + enhancement, + addressIdConverter, + verificationStrategies, + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test void matchesFailsIfIncorrectSelectorTest() { attempt = prepareHtsAttemptWithSelector( - BURN_TOKEN_V2, subject, enhancement, addressIdConverter, verificationStrategies, gasCalculator); - assertFalse(subject.matches(attempt)); + BURN_TOKEN_V2, + subject, + enhancement, + addressIdConverter, + verificationStrategies, + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isEmpty(); } @Test diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/tokeninfo/TokenInfoCallTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/tokeninfo/TokenInfoCallTest.java index 0799ec5d4d1c..ea76d8bd3779 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/tokeninfo/TokenInfoCallTest.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/tokeninfo/TokenInfoCallTest.java @@ -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. @@ -64,7 +64,7 @@ void returnsTokenInfoStatusForPresentToken() { when(ledgerConfig.id()).thenReturn(expectedLedgerId); final var subject = new TokenInfoCall( - gasCalculator, mockEnhancement(), false, FUNGIBLE_EVERYTHING_TOKEN, config, TOKEN_INFO); + gasCalculator, mockEnhancement(), false, FUNGIBLE_EVERYTHING_TOKEN, config, TOKEN_INFO.function()); final var result = subject.execute().fullResult().result(); @@ -105,7 +105,12 @@ void returnsTokenInfoStatusForPresentTokenV2() { when(ledgerConfig.id()).thenReturn(expectedLedgerId); final var subject = new TokenInfoCall( - gasCalculator, mockEnhancement(), false, FUNGIBLE_EVERYTHING_TOKEN_V2, config, TOKEN_INFO_V2); + gasCalculator, + mockEnhancement(), + false, + FUNGIBLE_EVERYTHING_TOKEN_V2, + config, + TOKEN_INFO_V2.function()); final var result = subject.execute().fullResult().result(); @@ -147,7 +152,8 @@ void returnsTokenInfoStatusForMissingToken() { final var expectedLedgerId = com.hedera.pbj.runtime.io.buffer.Bytes.fromHex("01"); when(ledgerConfig.id()).thenReturn(expectedLedgerId); - final var subject = new TokenInfoCall(gasCalculator, mockEnhancement(), false, null, config, TOKEN_INFO); + final var subject = + new TokenInfoCall(gasCalculator, mockEnhancement(), false, null, config, TOKEN_INFO.function()); final var result = subject.execute().fullResult().result(); @@ -186,7 +192,8 @@ void returnsTokenInfoStatusForMissingTokenStaticCall() { when(config.getConfigData(LedgerConfig.class)).thenReturn(ledgerConfig); when(ledgerConfig.id()).thenReturn(com.hedera.pbj.runtime.io.buffer.Bytes.fromHex("01")); - final var subject = new TokenInfoCall(gasCalculator, mockEnhancement(), true, null, config, TOKEN_INFO); + final var subject = + new TokenInfoCall(gasCalculator, mockEnhancement(), true, null, config, TOKEN_INFO.function()); final var result = subject.execute().fullResult().result(); @@ -199,7 +206,8 @@ void returnsTokenInfoStatusForMissingTokenStaticCallV2() { when(config.getConfigData(LedgerConfig.class)).thenReturn(ledgerConfig); when(ledgerConfig.id()).thenReturn(com.hedera.pbj.runtime.io.buffer.Bytes.fromHex("01")); - final var subject = new TokenInfoCall(gasCalculator, mockEnhancement(), true, null, config, TOKEN_INFO_V2); + final var subject = + new TokenInfoCall(gasCalculator, mockEnhancement(), true, null, config, TOKEN_INFO_V2.function()); final var result = subject.execute().fullResult().result(); diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/tokeninfo/TokenInfoTranslatorTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/tokeninfo/TokenInfoTranslatorTest.java index 8f493844c995..bbabe5f9cda0 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/tokeninfo/TokenInfoTranslatorTest.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/tokeninfo/TokenInfoTranslatorTest.java @@ -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. @@ -23,17 +23,17 @@ import static com.hedera.node.app.service.contract.impl.test.exec.systemcontracts.CallAttemptHelpers.prepareHtsAttemptWithSelector; import static com.hedera.node.app.service.contract.impl.test.exec.systemcontracts.CallAttemptHelpers.prepareHtsAttemptWithSelectorAndCustomConfig; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.BDDMockito.given; import com.esaulpaugh.headlong.abi.Tuple; import com.hedera.node.app.service.contract.impl.exec.gas.SystemContractGasCalculator; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.scope.VerificationStrategies; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.AddressIdConverter; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.tokeninfo.TokenInfoCall; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.tokeninfo.TokenInfoTranslator; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.hevm.HederaWorldUpdater.Enhancement; import com.hedera.node.config.data.ContractsConfig; import com.swirlds.config.api.Configuration; @@ -67,18 +67,29 @@ class TokenInfoTranslatorTest { @Mock private VerificationStrategies verificationStrategies; + @Mock + private ContractMetrics contractMetrics; + + private final SystemContractMethodRegistry systemContractMethodRegistry = new SystemContractMethodRegistry(); + private TokenInfoTranslator subject; @BeforeEach void setUp() { - subject = new TokenInfoTranslator(); + subject = new TokenInfoTranslator(systemContractMethodRegistry, contractMetrics); } @Test void matchesTokenInfoTranslatorTest() { attempt = prepareHtsAttemptWithSelector( - TOKEN_INFO, subject, enhancement, addressIdConverter, verificationStrategies, gasCalculator); - assertTrue(subject.matches(attempt)); + TOKEN_INFO, + subject, + enhancement, + addressIdConverter, + verificationStrategies, + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test @@ -92,15 +103,23 @@ void matchesTokenInfoTranslatorTestV2() { addressIdConverter, verificationStrategies, gasCalculator, + systemContractMethodRegistry, configuration); - assertTrue(subject.matches(attempt)); + assertThat(subject.identifyMethod(attempt)).isPresent(); + ; } @Test void matchesFailsIfIncorrectSelectorTest() { attempt = prepareHtsAttemptWithSelector( - BURN_TOKEN_V2, subject, enhancement, addressIdConverter, verificationStrategies, gasCalculator); - assertFalse(subject.matches(attempt)); + BURN_TOKEN_V2, + subject, + enhancement, + addressIdConverter, + verificationStrategies, + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isEmpty(); } @Test diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/tokenkey/TokenKeyTranslatorTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/tokenkey/TokenKeyTranslatorTest.java index daab372ef262..232275c8c47f 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/tokenkey/TokenKeyTranslatorTest.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/tokenkey/TokenKeyTranslatorTest.java @@ -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. @@ -21,19 +21,19 @@ import static com.hedera.node.app.service.contract.impl.test.TestHelpers.FUNGIBLE_TOKEN_HEADLONG_ADDRESS; import static com.hedera.node.app.service.contract.impl.test.exec.systemcontracts.CallAttemptHelpers.prepareHtsAttemptWithSelector; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.BDDMockito.given; import com.esaulpaugh.headlong.abi.Tuple; import com.hedera.hapi.node.base.Key; import com.hedera.hapi.node.state.token.Token; import com.hedera.node.app.service.contract.impl.exec.gas.SystemContractGasCalculator; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.scope.VerificationStrategies; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.AddressIdConverter; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.tokenkey.TokenKeyCall; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.tokenkey.TokenKeyTranslator; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.hevm.HederaWorldUpdater.Enhancement; import com.hedera.node.config.testfixtures.HederaTestConfigBuilder; import com.hedera.pbj.runtime.io.buffer.Bytes; @@ -63,25 +63,42 @@ class TokenKeyTranslatorTest { @Mock private VerificationStrategies verificationStrategies; + @Mock + private ContractMetrics contractMetrics; + + private final SystemContractMethodRegistry systemContractMethodRegistry = new SystemContractMethodRegistry(); + private TokenKeyTranslator subject; @BeforeEach void setUp() { - subject = new TokenKeyTranslator(); + subject = new TokenKeyTranslator(systemContractMethodRegistry, contractMetrics); } @Test void matchesTokenKeyTranslatorTest() { attempt = prepareHtsAttemptWithSelector( - TOKEN_KEY, subject, enhancement, addressIdConverter, verificationStrategies, gasCalculator); - assertTrue(subject.matches(attempt)); + TOKEN_KEY, + subject, + enhancement, + addressIdConverter, + verificationStrategies, + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test void matchesFailsIfIncorrectSelectorTest() { attempt = prepareHtsAttemptWithSelector( - BURN_TOKEN_V2, subject, enhancement, addressIdConverter, verificationStrategies, gasCalculator); - assertFalse(subject.matches(attempt)); + BURN_TOKEN_V2, + subject, + enhancement, + addressIdConverter, + verificationStrategies, + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isEmpty(); } @Test diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/tokentype/TokenTypeTranslatorTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/tokentype/TokenTypeTranslatorTest.java index f32ca405fa27..87c5b82fac98 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/tokentype/TokenTypeTranslatorTest.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/tokentype/TokenTypeTranslatorTest.java @@ -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. @@ -21,17 +21,17 @@ import static com.hedera.node.app.service.contract.impl.test.TestHelpers.FUNGIBLE_TOKEN_HEADLONG_ADDRESS; import static com.hedera.node.app.service.contract.impl.test.exec.systemcontracts.CallAttemptHelpers.prepareHtsAttemptWithSelector; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.BDDMockito.given; import com.esaulpaugh.headlong.abi.Tuple; import com.hedera.node.app.service.contract.impl.exec.gas.SystemContractGasCalculator; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.scope.VerificationStrategies; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.AddressIdConverter; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.tokentype.TokenTypeCall; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.tokentype.TokenTypeTranslator; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.hevm.HederaWorldUpdater.Enhancement; import org.apache.tuweni.bytes.Bytes; import org.junit.jupiter.api.BeforeEach; @@ -57,25 +57,42 @@ class TokenTypeTranslatorTest { @Mock private VerificationStrategies verificationStrategies; + @Mock + private ContractMetrics contractMetrics; + + private final SystemContractMethodRegistry systemContractMethodRegistry = new SystemContractMethodRegistry(); + private TokenTypeTranslator subject; @BeforeEach void setUp() { - subject = new TokenTypeTranslator(); + subject = new TokenTypeTranslator(systemContractMethodRegistry, contractMetrics); } @Test void matchesTokenTypeTest() { attempt = prepareHtsAttemptWithSelector( - TOKEN_TYPE, subject, enhancement, addressIdConverter, verificationStrategies, gasCalculator); - assertTrue(subject.matches(attempt)); + TOKEN_TYPE, + subject, + enhancement, + addressIdConverter, + verificationStrategies, + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test void matchesFailsIfIncorrectSelectorTest() { attempt = prepareHtsAttemptWithSelector( - BURN_TOKEN_V2, subject, enhancement, addressIdConverter, verificationStrategies, gasCalculator); - assertFalse(subject.matches(attempt)); + BURN_TOKEN_V2, + subject, + enhancement, + addressIdConverter, + verificationStrategies, + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isEmpty(); } @Test diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/transfer/ClassicTransfersTranslatorTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/transfer/ClassicTransfersTranslatorTest.java index 5686a0a12588..b63b55387c33 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/transfer/ClassicTransfersTranslatorTest.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/transfer/ClassicTransfersTranslatorTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2024 Hedera Hashgraph, LLC + * Copyright (C) 2024-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. @@ -26,6 +26,7 @@ import static org.mockito.BDDMockito.given; import com.hedera.hapi.node.base.AccountID; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.scope.VerificationStrategies; import com.hedera.node.app.service.contract.impl.exec.scope.VerificationStrategy; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.common.CallTranslator; @@ -34,6 +35,7 @@ import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.transfer.ClassicTransfersCall; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.transfer.ClassicTransfersDecoder; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.transfer.ClassicTransfersTranslator; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.test.exec.systemcontracts.common.CallTestBase; import com.swirlds.common.utility.CommonUtils; import java.lang.reflect.Field; @@ -63,13 +65,19 @@ class ClassicTransfersTranslatorTest extends CallTestBase { @Mock private VerificationStrategy strategy; + @Mock + private ContractMetrics contractMetrics; + + private final SystemContractMethodRegistry systemContractMethodRegistry = new SystemContractMethodRegistry(); + private ClassicTransfersTranslator subject; private List> callTranslators; @BeforeEach void setUp() { - callTranslators = List.of(new ClassicTransfersTranslator(classicTransfersDecoder)); + callTranslators = List.of( + new ClassicTransfersTranslator(classicTransfersDecoder, systemContractMethodRegistry, contractMetrics)); } @Test @@ -81,7 +89,8 @@ void returnsAttemptWithAuthorizingId() throws NoSuchFieldException, IllegalAcces NON_SYSTEM_LONG_ZERO_ADDRESS, true, nativeOperations)) .willReturn(strategy); - subject = new ClassicTransfersTranslator(classicTransfersDecoder); + subject = + new ClassicTransfersTranslator(classicTransfersDecoder, systemContractMethodRegistry, contractMetrics); final var call = subject.callFrom(givenV2SubjectWithV2Enabled(ABI_ID_TRANSFER_TOKEN)); Field senderIdField = ClassicTransfersCall.class.getDeclaredField("senderId"); senderIdField.setAccessible(true); @@ -97,7 +106,8 @@ void returnsAttemptWithSenderId() throws NoSuchFieldException, IllegalAccessExce NON_SYSTEM_LONG_ZERO_ADDRESS, true, nativeOperations)) .willReturn(strategy); - subject = new ClassicTransfersTranslator(classicTransfersDecoder); + subject = + new ClassicTransfersTranslator(classicTransfersDecoder, systemContractMethodRegistry, contractMetrics); final var call = subject.callFrom(givenV2SubjectWithV2Enabled(ABI_ID_CRYPTO_TRANSFER_V2)); Field senderIdField = ClassicTransfersCall.class.getDeclaredField("senderId"); senderIdField.setAccessible(true); @@ -119,6 +129,7 @@ private HtsCallAttempt givenV2SubjectWithV2Enabled(final String functionSelector verificationStrategies, gasCalculator, callTranslators, + systemContractMethodRegistry, false); } } diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/update/UpdateExpiryTranslatorTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/update/UpdateExpiryTranslatorTest.java index 0221387dd9c0..61e1ca9cebcb 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/update/UpdateExpiryTranslatorTest.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/update/UpdateExpiryTranslatorTest.java @@ -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. @@ -24,13 +24,12 @@ import static com.hedera.node.app.service.contract.impl.test.TestHelpers.OWNER_HEADLONG_ADDRESS; import static com.hedera.node.app.service.contract.impl.test.exec.systemcontracts.CallAttemptHelpers.prepareHtsAttemptWithSelector; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.BDDMockito.given; import com.esaulpaugh.headlong.abi.Tuple; import com.hedera.node.app.service.contract.impl.exec.gas.SystemContractGasCalculator; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.scope.VerificationStrategies; import com.hedera.node.app.service.contract.impl.exec.scope.VerificationStrategy; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.AddressIdConverter; @@ -38,6 +37,7 @@ import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.update.UpdateDecoder; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.update.UpdateExpiryTranslator; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.hevm.HederaWorldUpdater; import java.time.Instant; import org.apache.tuweni.bytes.Bytes; @@ -67,6 +67,11 @@ class UpdateExpiryTranslatorTest { @Mock private VerificationStrategies verificationStrategies; + @Mock + private ContractMetrics contractMetrics; + + private final SystemContractMethodRegistry systemContractMethodRegistry = new SystemContractMethodRegistry(); + private UpdateExpiryTranslator subject; private final UpdateDecoder decoder = new UpdateDecoder(); @@ -77,7 +82,7 @@ class UpdateExpiryTranslatorTest { @BeforeEach void setUp() { - subject = new UpdateExpiryTranslator(decoder); + subject = new UpdateExpiryTranslator(decoder, systemContractMethodRegistry, contractMetrics); } @Test @@ -88,8 +93,9 @@ void matchesUpdateExpiryV1Test() { enhancement, addressIdConverter, verificationStrategies, - gasCalculator); - assertTrue(subject.matches(attempt)); + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test @@ -100,8 +106,9 @@ void matchesUpdateExpiryV2Test() { enhancement, addressIdConverter, verificationStrategies, - gasCalculator); - assertTrue(subject.matches(attempt)); + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test @@ -112,8 +119,9 @@ void matchesFailsIfIncorrectSelectorTest() { enhancement, addressIdConverter, verificationStrategies, - gasCalculator); - assertFalse(subject.matches(attempt)); + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isEmpty(); } @Test diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/update/UpdateKeysTranslatorTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/update/UpdateKeysTranslatorTest.java index ec187f0ae306..5b84c87f3d73 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/update/UpdateKeysTranslatorTest.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/update/UpdateKeysTranslatorTest.java @@ -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. @@ -17,16 +17,17 @@ package com.hedera.node.app.service.contract.impl.test.exec.systemcontracts.hts.update; import static com.hedera.node.app.service.contract.impl.test.exec.systemcontracts.CallAttemptHelpers.prepareHtsAttemptWithSelector; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; import com.hedera.node.app.service.contract.impl.exec.gas.SystemContractGasCalculator; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.scope.VerificationStrategies; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.AddressIdConverter; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.freeze.FreezeUnfreezeTranslator; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.update.UpdateDecoder; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.update.UpdateKeysTranslator; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.hevm.HederaWorldUpdater; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -51,13 +52,18 @@ class UpdateKeysTranslatorTest { @Mock private VerificationStrategies verificationStrategies; + @Mock + private ContractMetrics contractMetrics; + + private final SystemContractMethodRegistry systemContractMethodRegistry = new SystemContractMethodRegistry(); + private UpdateKeysTranslator subject; private final UpdateDecoder decoder = new UpdateDecoder(); @BeforeEach void setUp() { - subject = new UpdateKeysTranslator(decoder); + subject = new UpdateKeysTranslator(decoder, systemContractMethodRegistry, contractMetrics); } @Test @@ -68,8 +74,9 @@ void matchesUpdateKeysTest() { enhancement, addressIdConverter, verificationStrategies, - gasCalculator); - assertTrue(subject.matches(attempt)); + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test @@ -80,7 +87,8 @@ void matchesIncorrectSelectorFailsTest() { enhancement, addressIdConverter, verificationStrategies, - gasCalculator); - assertFalse(subject.matches(attempt)); + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isEmpty(); } } diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/update/UpdateNFTsMetadataTranslatorTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/update/UpdateNFTsMetadataTranslatorTest.java index f14f58436c71..2964cf4fe4f1 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/update/UpdateNFTsMetadataTranslatorTest.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/update/UpdateNFTsMetadataTranslatorTest.java @@ -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. @@ -19,22 +19,24 @@ import static com.hedera.node.app.service.contract.impl.test.TestHelpers.NON_FUNGIBLE_TOKEN_HEADLONG_ADDRESS; import static com.hedera.node.app.service.contract.impl.test.TestHelpers.NON_SYSTEM_ACCOUNT_ID; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertFalse; import static org.mockito.ArgumentMatchers.any; import static org.mockito.BDDMockito.given; import com.esaulpaugh.headlong.abi.Tuple; import com.hedera.node.app.service.contract.impl.exec.gas.SystemContractGasCalculator; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; 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.systemcontracts.hts.DispatchForResponseCodeHtsCall; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.update.UpdateDecoder; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.update.UpdateNFTsMetadataTranslator; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.hevm.HederaWorldUpdater; import com.hedera.node.config.testfixtures.HederaTestConfigBuilder; import com.swirlds.config.api.Configuration; import edu.umd.cs.findbugs.annotations.NonNull; +import java.util.Optional; import org.apache.tuweni.bytes.Bytes; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -60,29 +62,30 @@ class UpdateNFTsMetadataTranslatorTest { @Mock private VerificationStrategy verificationStrategy; + @Mock + private ContractMetrics contractMetrics; + private UpdateNFTsMetadataTranslator subject; private final UpdateDecoder decoder = new UpdateDecoder(); @BeforeEach void setUp() { - subject = new UpdateNFTsMetadataTranslator(decoder); + subject = new UpdateNFTsMetadataTranslator(decoder, new SystemContractMethodRegistry(), contractMetrics); } @Test void matchesUpdateNFTsMetadataTest() { given(attempt.configuration()).willReturn(getTestConfiguration(true)); - given(attempt.isSelector(UpdateNFTsMetadataTranslator.UPDATE_NFTs_METADATA)) - .willReturn(true); - final var matches = subject.matches(attempt); - assertThat(matches).isTrue(); + given(attempt.isMethod(UpdateNFTsMetadataTranslator.UPDATE_NFTs_METADATA)) + .willReturn(Optional.of(UpdateNFTsMetadataTranslator.UPDATE_NFTs_METADATA)); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test void doesNotMatchUpdateNFTsMetadataWhenDisabled() { given(attempt.configuration()).willReturn(getTestConfiguration(false)); - var matches = subject.matches(attempt); - assertFalse(matches); + assertThat(subject.identifyMethod(attempt)).isEmpty(); } @Test diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/update/UpdateTranslatorTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/update/UpdateTranslatorTest.java index 13d92969da66..0dfdb168fd89 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/update/UpdateTranslatorTest.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/update/UpdateTranslatorTest.java @@ -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. @@ -36,8 +36,6 @@ import static com.hedera.node.app.service.contract.impl.test.exec.systemcontracts.CallAttemptHelpers.prepareHtsAttemptWithSelectorAndCustomConfig; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.lenient; @@ -46,6 +44,7 @@ import com.esaulpaugh.headlong.abi.Tuple; import com.hedera.hapi.node.token.TokenUpdateTransactionBody; import com.hedera.hapi.node.transaction.TransactionBody; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.scope.VerificationStrategies; import com.hedera.node.app.service.contract.impl.exec.scope.VerificationStrategy; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.AddressIdConverter; @@ -54,6 +53,7 @@ import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.freeze.FreezeUnfreezeTranslator; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.update.UpdateDecoder; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.update.UpdateTranslator; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.hevm.HederaWorldUpdater; import com.hedera.node.app.service.contract.impl.test.exec.systemcontracts.common.CallTestBase; import com.hedera.node.app.service.token.ReadableAccountStore; @@ -96,6 +96,11 @@ class UpdateTranslatorTest extends CallTestBase { @Mock Configuration configuration; + @Mock + private ContractMetrics contractMetrics; + + private final SystemContractMethodRegistry systemContractMethodRegistry = new SystemContractMethodRegistry(); + private UpdateTranslator subject; private final UpdateDecoder decoder = new UpdateDecoder(); @@ -115,7 +120,7 @@ class UpdateTranslatorTest extends CallTestBase { @BeforeEach void setUp() { - subject = new UpdateTranslator(decoder); + subject = new UpdateTranslator(decoder, systemContractMethodRegistry, contractMetrics); } @Test @@ -187,8 +192,9 @@ void matchesUpdateV1Test() { enhancement, addressIdConverter, verificationStrategies, - gasCalculator); - assertTrue(subject.matches(attempt)); + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test @@ -199,8 +205,9 @@ void matchesUpdateV2Test() { enhancement, addressIdConverter, verificationStrategies, - gasCalculator); - assertTrue(subject.matches(attempt)); + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test @@ -211,8 +218,9 @@ void matchesUpdateV3Test() { enhancement, addressIdConverter, verificationStrategies, - gasCalculator); - assertTrue(subject.matches(attempt)); + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test @@ -226,8 +234,9 @@ void matchesUpdateMetadataTest() { addressIdConverter, verificationStrategies, gasCalculator, + systemContractMethodRegistry, configuration); - assertTrue(subject.matches(attempt)); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test @@ -238,8 +247,9 @@ void matchesFailsOnIncorrectSelector() { enhancement, addressIdConverter, verificationStrategies, - gasCalculator); - assertFalse(subject.matches(attempt)); + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isEmpty(); } @Test diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/updatetokencustomfees/UpdateTokenCustomFeesTranslatorTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/updatetokencustomfees/UpdateTokenCustomFeesTranslatorTest.java index d658d3081494..a5c318c62c1b 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/updatetokencustomfees/UpdateTokenCustomFeesTranslatorTest.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/updatetokencustomfees/UpdateTokenCustomFeesTranslatorTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2024 Hedera Hashgraph, LLC + * Copyright (C) 2024-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. @@ -26,14 +26,13 @@ import static com.hedera.node.app.service.contract.impl.test.TestHelpers.SENDER_ID; import static com.hedera.node.app.service.contract.impl.test.exec.systemcontracts.CallAttemptHelpers.prepareHtsAttemptWithSelectorAndCustomConfig; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.lenient; import com.esaulpaugh.headlong.abi.Address; import com.esaulpaugh.headlong.abi.Tuple; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.scope.VerificationStrategies; import com.hedera.node.app.service.contract.impl.exec.scope.VerificationStrategy; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.AddressIdConverter; @@ -41,6 +40,7 @@ import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.updatetokencustomfees.UpdateTokenCustomFeesDecoder; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.updatetokencustomfees.UpdateTokenCustomFeesTranslator; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.hevm.HederaWorldUpdater; import com.hedera.node.app.service.contract.impl.test.exec.systemcontracts.common.CallTestBase; import com.hedera.node.config.data.ContractsConfig; @@ -80,13 +80,18 @@ class UpdateTokenCustomFeesTranslatorTest extends CallTestBase { @Mock private VerificationStrategies verificationStrategies; + @Mock + private ContractMetrics contractMetrics; + + private final SystemContractMethodRegistry systemContractMethodRegistry = new SystemContractMethodRegistry(); + private final UpdateTokenCustomFeesDecoder decoder = new UpdateTokenCustomFeesDecoder(); private UpdateTokenCustomFeesTranslator subject; @BeforeEach void setUp() { - subject = new UpdateTokenCustomFeesTranslator(decoder); + subject = new UpdateTokenCustomFeesTranslator(decoder, systemContractMethodRegistry, contractMetrics); } @Test @@ -100,8 +105,9 @@ void matchesIsTrueWhenSelectorForFungibleIsCorrect() { addressIdConverter, verificationStrategies, gasCalculator, + systemContractMethodRegistry, configuration); - assertTrue(subject.matches(attempt)); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test @@ -115,8 +121,9 @@ void matchesIsTrueWhenSelectorForNFTIsCorrect() { addressIdConverter, verificationStrategies, gasCalculator, + systemContractMethodRegistry, configuration); - assertTrue(subject.matches(attempt)); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test @@ -124,7 +131,7 @@ void matchesFailsIfFeatureFlagDisabled() { // given: setConfiguration(false); // expect: - assertFalse(subject.matches(attempt)); + assertThat(subject.identifyMethod(attempt)).isEmpty(); } @Test @@ -138,8 +145,9 @@ void matchesIsFalseWhenSelectorsAreIncorrect() { addressIdConverter, verificationStrategies, gasCalculator, + systemContractMethodRegistry, configuration); - assertFalse(subject.matches(attempt)); + assertThat(subject.identifyMethod(attempt)).isEmpty(); } @Test diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/wipe/WipeTranslatorTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/wipe/WipeTranslatorTest.java index fa616351155a..cf17d0d34b91 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/wipe/WipeTranslatorTest.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/systemcontracts/hts/wipe/WipeTranslatorTest.java @@ -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. @@ -19,15 +19,16 @@ import static com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.burn.BurnTranslator.BURN_TOKEN_V2; import static com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.wipe.WipeTranslator.WIPE_FUNGIBLE_V1; import static com.hedera.node.app.service.contract.impl.test.exec.systemcontracts.CallAttemptHelpers.prepareHtsAttemptWithSelector; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; import com.hedera.node.app.service.contract.impl.exec.gas.SystemContractGasCalculator; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.scope.VerificationStrategies; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.AddressIdConverter; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.HtsCallAttempt; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.wipe.WipeDecoder; import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.wipe.WipeTranslator; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.hevm.HederaWorldUpdater.Enhancement; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -53,40 +54,69 @@ public class WipeTranslatorTest { @Mock private VerificationStrategies verificationStrategies; + private final SystemContractMethodRegistry systemContractMethodRegistry = new SystemContractMethodRegistry(); + + @Mock + private ContractMetrics contractMetrics; + private final WipeDecoder decoder = new WipeDecoder(); private WipeTranslator subject; @BeforeEach void setup() { - subject = new WipeTranslator(decoder); + subject = new WipeTranslator(decoder, systemContractMethodRegistry, contractMetrics); } @Test void matchesWipeFungibleV1Test() { attempt = prepareHtsAttemptWithSelector( - WIPE_FUNGIBLE_V1, subject, enhancement, addressIdConverter, verificationStrategies, gasCalculator); - assertTrue(subject.matches(attempt)); + WIPE_FUNGIBLE_V1, + subject, + enhancement, + addressIdConverter, + verificationStrategies, + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test void matchesWipeFungibleV2Test() { attempt = prepareHtsAttemptWithSelector( - WIPE_FUNGIBLE_V1, subject, enhancement, addressIdConverter, verificationStrategies, gasCalculator); - assertTrue(subject.matches(attempt)); + WIPE_FUNGIBLE_V1, + subject, + enhancement, + addressIdConverter, + verificationStrategies, + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test void matchesWipeNftTest() { attempt = prepareHtsAttemptWithSelector( - WIPE_FUNGIBLE_V1, subject, enhancement, addressIdConverter, verificationStrategies, gasCalculator); - assertTrue(subject.matches(attempt)); + WIPE_FUNGIBLE_V1, + subject, + enhancement, + addressIdConverter, + verificationStrategies, + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isPresent(); } @Test void matchFailsOnIncorrectSelectorTest() { attempt = prepareHtsAttemptWithSelector( - BURN_TOKEN_V2, subject, enhancement, addressIdConverter, verificationStrategies, gasCalculator); - assertFalse(subject.matches(attempt)); + BURN_TOKEN_V2, + subject, + enhancement, + addressIdConverter, + verificationStrategies, + gasCalculator, + systemContractMethodRegistry); + assertThat(subject.identifyMethod(attempt)).isEmpty(); } } diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/utils/SystemContractMethodRegistryTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/utils/SystemContractMethodRegistryTest.java new file mode 100644 index 000000000000..6efb397991c2 --- /dev/null +++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/exec/utils/SystemContractMethodRegistryTest.java @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2024-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.test.exec.utils; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.esaulpaugh.headlong.abi.Function; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; +import com.hedera.node.app.service.contract.impl.exec.systemcontracts.has.getevmaddressalias.EvmAddressAliasTranslator; +import com.hedera.node.app.service.contract.impl.exec.systemcontracts.has.hbarapprove.HbarApproveTranslator; +import com.hedera.node.app.service.contract.impl.exec.systemcontracts.has.isvalidalias.IsValidAliasTranslator; +import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.ReturnTypes; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.CallVia; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.SystemContract; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethod.Variant; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +public class SystemContractMethodRegistryTest { + + @Mock + ContractMetrics contractMetrics; + + @Test + void testMethodCreationHappyPath() { + + final var signature = new Function("collectReward(string)", ReturnTypes.ADDRESS); + final var subject = SystemContractMethod.declare( + signature.getCanonicalSignature(), + signature.getOutputs().toString()) + .withContract(SystemContract.EXCHANGE) + .withVia(CallVia.DIRECT); + + assertThat(subject.methodName()).isEqualTo("collectReward"); + assertThat(subject.qualifiedMethodName()).isEqualTo("EXCHANGE.collectReward"); + assertThat(subject.signature()).isEqualTo("collectReward(string)"); + assertThat(subject.signatureWithReturn()).isEqualTo("collectReward(string):(address)"); + assertThat(subject.selectorLong()).isEqualTo(0x3cbf0049L); + assertThat(subject.selectorHex()).isEqualTo("3cbf0049"); + } + + @Test + void testMethodCreationVariations() { + + final var signature = new Function("collectReward(string)", ReturnTypes.ADDRESS); + + // Proxy + final var subjectProxy = SystemContractMethod.declare( + signature.getCanonicalSignature(), + signature.getOutputs().toString()) + .withContract(SystemContract.EXCHANGE) + .withVia(CallVia.PROXY); + assertThat(subjectProxy.qualifiedMethodName()).isEqualTo("EXCHANGE(PROXY).collectReward"); + + // Variant method name + final var subjectOverrideName = SystemContractMethod.declare( + signature.getCanonicalSignature(), + signature.getOutputs().toString()) + .withContract(SystemContract.EXCHANGE) + .withVariant(Variant.NFT); + assertThat(subjectOverrideName.qualifiedMethodName()).isEqualTo("EXCHANGE.collectReward_NFT"); + assertThat(subjectOverrideName.signature()).isEqualTo("collectReward(string)"); + assertThat(subjectOverrideName.selectorLong()).isEqualTo(0x3cbf0049L); + } + + @Test + void testHappyMethodRegistrations() { + + final var subject = new SystemContractMethodRegistry(); + + // Add some registrations by simply creating instances of classes known to register methods + + final var t1 = new IsValidAliasTranslator(subject, contractMetrics); + final var t2 = new HbarApproveTranslator(subject, contractMetrics); + final var t3 = new EvmAddressAliasTranslator(subject, contractMetrics); + + // Test expected methods are registered (test data is known from looking at the classes involved) + + // HAS(PROXY).hbarApprove: 0x86aff07c - hbarApprove(address,int256):(int64) + // HAS.getEvmAddressAlias: 0xdea3d081 - getEvmAddressAlias(address):(int64,address) + // HAS.hbarApprove: 0xa0918464 - hbarApprove(address,address,int256):(int64) + // HAS.isValidAlias: 0x308ef301 - isValidAlias(address):(bool) + + final var actualAllQualifiedMethods = subject.allQualifiedMethods(); + assertThat(actualAllQualifiedMethods) + .hasSize(4) + .containsExactlyInAnyOrder( + "HAS.isValidAlias", "HAS.getEvmAddressAlias", "HAS.hbarApprove", "HAS(PROXY).hbarApprove"); + + final var actualAllSignatures = subject.allSignatures(); + assertThat(actualAllSignatures) + .hasSize(4) + .containsExactlyInAnyOrder( + "getEvmAddressAlias(address)", + "hbarApprove(address,address,int256)", + "hbarApprove(address,int256)", + "isValidAlias(address)"); + + final var actualAllSignaturesWithReturns = subject.allSignaturesWithReturns(); + assertThat(actualAllSignaturesWithReturns) + .hasSize(4) + .containsExactlyInAnyOrder( + "getEvmAddressAlias(address):(int64,address)", + "hbarApprove(address,address,int256):(int64)", + "hbarApprove(address,int256):(int64)", + "isValidAlias(address):(bool)"); + } + + @Test + void testDuplicateMethodRegistrationRegistersOnlyOneCopy() { + + final var subject = new SystemContractMethodRegistry(); + + // Add some registrations twice - this might happen if a `FooTranslator` isn't marked `@Singleton` + final var t1 = new IsValidAliasTranslator(subject, contractMetrics); + final var t2 = new IsValidAliasTranslator(subject, contractMetrics); + + // Test only one method is registered + + final var actualAllQualifiedMethods = subject.allQualifiedMethods(); + assertThat(actualAllQualifiedMethods).hasSize(1).containsExactly("HAS.isValidAlias"); + + final var actualAllSignatures = subject.allSignatures(); + assertThat(actualAllSignatures).hasSize(1).containsExactly("isValidAlias(address)"); + + final var actualAllSignaturesWithReturns = subject.allSignaturesWithReturns(); + assertThat(actualAllSignaturesWithReturns).hasSize(1).containsExactly("isValidAlias(address):(bool)"); + } +} diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/handlers/ContractCallHandlerTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/handlers/ContractCallHandlerTest.java index 5d22d1890543..38159bcb4cca 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/handlers/ContractCallHandlerTest.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/handlers/ContractCallHandlerTest.java @@ -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. @@ -37,6 +37,7 @@ import com.hedera.node.app.service.contract.impl.exec.ContextTransactionProcessor; import com.hedera.node.app.service.contract.impl.exec.TransactionComponent; import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.handlers.ContractCallHandler; import com.hedera.node.app.service.contract.impl.records.ContractCallStreamBuilder; import com.hedera.node.app.service.contract.impl.state.RootProxyWorldUpdater; @@ -92,14 +93,17 @@ class ContractCallHandlerTest extends ContractHandlerTestBase { @Mock private ContractsConfig contractsConfig; + private final SystemContractMethodRegistry systemContractMethodRegistry = new SystemContractMethodRegistry(); + private final Metrics metrics = new NoOpMetrics(); - private final ContractMetrics contractMetrics = new ContractMetrics(() -> metrics, () -> contractsConfig); + private final ContractMetrics contractMetrics = + new ContractMetrics(() -> metrics, () -> contractsConfig, systemContractMethodRegistry); private ContractCallHandler subject; @BeforeEach void setUp() { - contractMetrics.createContractMetrics(); + contractMetrics.createContractPrimaryMetrics(); given(contractServiceComponent.contractMetrics()).willReturn(contractMetrics); subject = new ContractCallHandler(() -> factory, gasCalculator, contractServiceComponent); } diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/handlers/ContractCallLocalHandlerTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/handlers/ContractCallLocalHandlerTest.java index 84d6d535d7ae..8e06128ac609 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/handlers/ContractCallLocalHandlerTest.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/handlers/ContractCallLocalHandlerTest.java @@ -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. @@ -40,9 +40,11 @@ import com.hedera.hapi.node.transaction.Query; import com.hedera.node.app.hapi.utils.fee.FeeBuilder; import com.hedera.node.app.hapi.utils.fee.SigValueObj; +import com.hedera.node.app.service.contract.impl.ContractServiceComponent; import com.hedera.node.app.service.contract.impl.exec.CallOutcome; import com.hedera.node.app.service.contract.impl.exec.ContextQueryProcessor; import com.hedera.node.app.service.contract.impl.exec.QueryComponent; +import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.handlers.ContractCallLocalHandler; import com.hedera.node.app.service.token.ReadableAccountStore; import com.hedera.node.app.service.token.ReadableTokenStore; @@ -61,6 +63,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; +import org.mockito.Mock.Strictness; import org.mockito.junit.jupiter.MockitoExtension; @ExtendWith(MockitoExtension.class) @@ -120,9 +123,16 @@ class ContractCallLocalHandlerTest { private ContractCallLocalHandler subject; + @Mock(strictness = Strictness.LENIENT) + private ContractServiceComponent contractServiceComponent; + + @Mock + private ContractMetrics contractMetrics; + @BeforeEach void setUp() { - subject = new ContractCallLocalHandler(() -> factory, gasCalculator, instantSource); + given(contractServiceComponent.contractMetrics()).willReturn(contractMetrics); + subject = new ContractCallLocalHandler(() -> factory, gasCalculator, instantSource, contractServiceComponent); } @Test diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/handlers/ContractCreateHandlerTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/handlers/ContractCreateHandlerTest.java index 75b78bdc1136..1d3daade18f0 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/handlers/ContractCreateHandlerTest.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/handlers/ContractCreateHandlerTest.java @@ -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. @@ -41,6 +41,7 @@ import com.hedera.node.app.service.contract.impl.exec.ContextTransactionProcessor; import com.hedera.node.app.service.contract.impl.exec.TransactionComponent; import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.handlers.ContractCreateHandler; import com.hedera.node.app.service.contract.impl.records.ContractCreateStreamBuilder; import com.hedera.node.app.service.contract.impl.state.RootProxyWorldUpdater; @@ -98,14 +99,17 @@ class ContractCreateHandlerTest extends ContractHandlerTestBase { @Mock private ContractsConfig contractsConfig; + private final SystemContractMethodRegistry systemContractMethodRegistry = new SystemContractMethodRegistry(); + private final Metrics metrics = new NoOpMetrics(); - private final ContractMetrics contractMetrics = new ContractMetrics(() -> metrics, () -> contractsConfig); + private final ContractMetrics contractMetrics = + new ContractMetrics(() -> metrics, () -> contractsConfig, systemContractMethodRegistry); private ContractCreateHandler subject; @BeforeEach void setUp() { - contractMetrics.createContractMetrics(); + contractMetrics.createContractPrimaryMetrics(); given(contractServiceComponent.contractMetrics()).willReturn(contractMetrics); subject = new ContractCreateHandler(() -> factory, gasCalculator, contractServiceComponent); } diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/handlers/EthereumTransactionHandlerTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/handlers/EthereumTransactionHandlerTest.java index c87e79f5ed42..cbc0a3cb984a 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/handlers/EthereumTransactionHandlerTest.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/handlers/EthereumTransactionHandlerTest.java @@ -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. @@ -50,6 +50,7 @@ import com.hedera.node.app.service.contract.impl.exec.gas.CustomGasCharging; import com.hedera.node.app.service.contract.impl.exec.metrics.ContractMetrics; import com.hedera.node.app.service.contract.impl.exec.tracers.EvmActionTracer; +import com.hedera.node.app.service.contract.impl.exec.utils.SystemContractMethodRegistry; import com.hedera.node.app.service.contract.impl.handlers.EthereumTransactionHandler; import com.hedera.node.app.service.contract.impl.hevm.HederaEvmContext; import com.hedera.node.app.service.contract.impl.hevm.HederaWorldUpdater; @@ -165,12 +166,15 @@ class EthereumTransactionHandlerTest { @Mock private ContractsConfig contractsConfig; + private final SystemContractMethodRegistry systemContractMethodRegistry = new SystemContractMethodRegistry(); + private final Metrics metrics = new NoOpMetrics(); - private final ContractMetrics contractMetrics = new ContractMetrics(() -> metrics, () -> contractsConfig); + private final ContractMetrics contractMetrics = + new ContractMetrics(() -> metrics, () -> contractsConfig, systemContractMethodRegistry); @BeforeEach void setUp() { - contractMetrics.createContractMetrics(); + contractMetrics.createContractPrimaryMetrics(); given(contractServiceComponent.contractMetrics()).willReturn(contractMetrics); subject = new EthereumTransactionHandler( ethereumSignatures, callDataHydration, () -> factory, gasCalculator, contractServiceComponent);