From 6b25463a8b1fa9e6b786a71c5197f90df7562b82 Mon Sep 17 00:00:00 2001 From: Petar Tonev Date: Fri, 12 Jan 2024 11:28:35 +0200 Subject: [PATCH 01/34] fix: reclaim throttle usage for failed auto-creations --- .../node/app/spi/workflows/HandleContext.java | 8 +++ .../throttle/NetworkUtilizationManager.java | 9 ++++ .../impl/NetworkUtilizationManagerImpl.java | 27 ++++++---- .../workflows/handle/HandleContextImpl.java | 16 +++++- .../app/workflows/handle/HandleWorkflow.java | 3 +- .../handle/HandleContextImplTest.java | 13 +++-- .../java/common/BaseScaffoldingModule.java | 53 +++++++++++++++---- .../impl/handlers/CryptoTransferHandler.java | 13 ++++- 8 files changed, 116 insertions(+), 26 deletions(-) diff --git a/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/workflows/HandleContext.java b/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/workflows/HandleContext.java index de13a29aba50..7c3a340dbce9 100644 --- a/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/workflows/HandleContext.java +++ b/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/workflows/HandleContext.java @@ -660,6 +660,14 @@ default T dispatchRemovableChildTransaction( */ void revertRecordsFrom(@NonNull RecordListCheckPoint recordListCheckPoint); + /** + * Reclaim the capacity for a number of transactions of the same functionality. + * + * @param n the number of transactions to consider + * @param function the functionality type of the transactions + */ + void reclaimPreviouslyReservedThrottle(int n, HederaFunctionality function); + /** * Create a checkpoint for the current childRecords. * diff --git a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/NetworkUtilizationManager.java b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/NetworkUtilizationManager.java index 3fa444516686..c74ebb9560df 100644 --- a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/NetworkUtilizationManager.java +++ b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/NetworkUtilizationManager.java @@ -17,6 +17,7 @@ package com.hedera.node.app.throttle; import com.hedera.hapi.node.base.AccountID; +import com.hedera.hapi.node.base.HederaFunctionality; import com.hedera.node.app.state.HederaState; import com.hedera.node.app.workflows.TransactionInfo; import edu.umd.cs.findbugs.annotations.NonNull; @@ -65,6 +66,14 @@ void trackFeePayments( */ void leakUnusedGasPreviouslyReserved(@NonNull final TransactionInfo txnInfo, final long value); + /* + * Leaks the claimed capacity for a number of transactions of the same functionality. + * + * @param n the number of transactions to consider + * @param function the functionality type of the transactions + */ + void leakUnusedThrottlePreviouslyReserved(int n, HederaFunctionality function); + /* * Resets the throttle usage and congestion multiplier from the given state. * diff --git a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/impl/NetworkUtilizationManagerImpl.java b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/impl/NetworkUtilizationManagerImpl.java index 36610c63031d..120a46531f55 100644 --- a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/impl/NetworkUtilizationManagerImpl.java +++ b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/impl/NetworkUtilizationManagerImpl.java @@ -16,14 +16,8 @@ package com.hedera.node.app.throttle.impl; -import static com.hedera.hapi.node.base.HederaFunctionality.CRYPTO_TRANSFER; -import static com.hedera.node.app.records.BlockRecordService.EPOCH; -import static com.hedera.node.app.service.mono.pbj.PbjConverter.fromPbj; -import static com.hedera.node.app.service.mono.pbj.PbjConverter.toPbj; -import static com.hedera.node.app.service.mono.utils.MiscUtils.safeResetThrottles; -import static java.util.Objects.requireNonNull; - import com.hedera.hapi.node.base.AccountID; +import com.hedera.hapi.node.base.HederaFunctionality; import com.hedera.hapi.node.base.SignatureMap; import com.hedera.hapi.node.base.Timestamp; import com.hedera.hapi.node.base.Transaction; @@ -42,12 +36,20 @@ import com.hedera.node.app.workflows.TransactionInfo; import com.hedera.pbj.runtime.io.buffer.Bytes; import edu.umd.cs.findbugs.annotations.NonNull; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import javax.inject.Inject; import java.time.Instant; import java.util.ArrayList; import java.util.List; -import javax.inject.Inject; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; + +import static com.hedera.hapi.node.base.HederaFunctionality.CRYPTO_TRANSFER; +import static com.hedera.node.app.records.BlockRecordService.EPOCH; +import static com.hedera.node.app.service.mono.pbj.PbjConverter.fromPbj; +import static com.hedera.node.app.service.mono.pbj.PbjConverter.toPbj; +import static com.hedera.node.app.service.mono.utils.MiscUtils.safeResetThrottles; +import static java.util.Objects.requireNonNull; /** * Implementation of {@link NetworkUtilizationManager} that delegates to injected {@link ThrottleAccumulator} and {@link @@ -201,4 +203,9 @@ public boolean wasLastTxnGasThrottled() { public void leakUnusedGasPreviouslyReserved(@NonNull final TransactionInfo txnInfo, long value) { backendThrottle.leakUnusedGasPreviouslyReserved(txnInfo, value); } + + @Override + public void leakUnusedThrottlePreviouslyReserved(int n, HederaFunctionality function) { + backendThrottle.leakCapacityForNOfUnscaled(n, function); + } } diff --git a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleContextImpl.java b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleContextImpl.java index cf2ca273e955..7fe9a69dfb22 100644 --- a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleContextImpl.java +++ b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleContextImpl.java @@ -75,6 +75,7 @@ import com.hedera.node.app.spi.workflows.record.SingleTransactionRecordBuilder; import com.hedera.node.app.state.HederaRecordCache; import com.hedera.node.app.state.WrappedHederaState; +import com.hedera.node.app.throttle.NetworkUtilizationManager; import com.hedera.node.app.workflows.SolvencyPreCheck; import com.hedera.node.app.workflows.TransactionChecker; import com.hedera.node.app.workflows.dispatcher.ReadableStoreFactory; @@ -131,6 +132,7 @@ public class HandleContextImpl implements HandleContext, FeeContext { private final Authorizer authorizer; private final SolvencyPreCheck solvencyPreCheck; private final ChildRecordFinalizer childRecordFinalizer; + private final NetworkUtilizationManager networkUtilizationManager; private ReadableStoreFactory readableStoreFactory; private AttributeValidator attributeValidator; @@ -161,6 +163,7 @@ public class HandleContextImpl implements HandleContext, FeeContext { * @param authorizer The {@link Authorizer} used to authorize the transaction * @param solvencyPreCheck The {@link SolvencyPreCheck} used to validate if the account is able to pay the fees * @param childRecordFinalizer The {@link ChildRecordFinalizer} used to finalize child records + * @param networkUtilizationManager The {@link NetworkUtilizationManager} used to manage tracking of network utilization */ public HandleContextImpl( @NonNull final TransactionBody txBody, @@ -185,7 +188,8 @@ public HandleContextImpl( @NonNull final Instant userTransactionConsensusTime, @NonNull final Authorizer authorizer, @NonNull final SolvencyPreCheck solvencyPreCheck, - @NonNull final ChildRecordFinalizer childRecordFinalizer) { + @NonNull final ChildRecordFinalizer childRecordFinalizer, + @NonNull final NetworkUtilizationManager networkUtilizationManager) { this.txBody = requireNonNull(txBody, "txBody must not be null"); this.functionality = requireNonNull(functionality, "functionality must not be null"); this.payer = requireNonNull(payer, "payer must not be null"); @@ -207,6 +211,8 @@ public HandleContextImpl( requireNonNull(userTransactionConsensusTime, "userTransactionConsensusTime must not be null"); this.authorizer = requireNonNull(authorizer, "authorizer must not be null"); this.childRecordFinalizer = requireNonNull(childRecordFinalizer, "childRecordFinalizer must not be null"); + this.networkUtilizationManager = + requireNonNull(networkUtilizationManager, "networkUtilizationManager must not be null"); final var serviceScope = serviceScopeLookup.getServiceName(txBody); this.writableStoreFactory = new WritableStoreFactory(stack, serviceScope); @@ -690,7 +696,8 @@ private void dispatchSyntheticTxn( userTransactionConsensusTime, authorizer, solvencyPreCheck, - childRecordFinalizer); + childRecordFinalizer, + networkUtilizationManager); if (dispatchValidationResult != null) { childContext.feeAccumulator.chargeFees( @@ -883,6 +890,11 @@ public RecordListCheckPoint createRecordListCheckPoint() { return new RecordListCheckPoint(firstPreceding, lastFollowing); } + @Override + public void reclaimPreviouslyReservedThrottle(int n, HederaFunctionality function) { + networkUtilizationManager.leakUnusedThrottlePreviouslyReserved(n, function); + } + public enum PrecedingTransactionCategory { UNLIMITED_CHILD_RECORDS, LIMITED_CHILD_RECORDS diff --git a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleWorkflow.java b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleWorkflow.java index 83285d74c635..16c91e0014f4 100644 --- a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleWorkflow.java +++ b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleWorkflow.java @@ -389,7 +389,8 @@ private void handleUserTransaction( consensusNow, authorizer, solvencyPreCheck, - childRecordFinalizer); + childRecordFinalizer, + networkUtilizationManager); // Calculate the fee fees = dispatcher.dispatchComputeFees(context); diff --git a/hedera-node/hedera-app/src/test/java/com/hedera/node/app/workflows/handle/HandleContextImplTest.java b/hedera-node/hedera-app/src/test/java/com/hedera/node/app/workflows/handle/HandleContextImplTest.java index 3c775077b18e..d43e4ed0144e 100644 --- a/hedera-node/hedera-app/src/test/java/com/hedera/node/app/workflows/handle/HandleContextImplTest.java +++ b/hedera-node/hedera-app/src/test/java/com/hedera/node/app/workflows/handle/HandleContextImplTest.java @@ -89,6 +89,7 @@ import com.hedera.node.app.spi.workflows.record.SingleTransactionRecordBuilder; import com.hedera.node.app.state.HederaRecordCache; import com.hedera.node.app.state.HederaState; +import com.hedera.node.app.throttle.NetworkUtilizationManager; import com.hedera.node.app.workflows.SolvencyPreCheck; import com.hedera.node.app.workflows.TransactionChecker; import com.hedera.node.app.workflows.dispatcher.TransactionDispatcher; @@ -178,6 +179,9 @@ class HandleContextImplTest extends StateTestBase implements Scenarios { @Mock private ChildRecordFinalizer childRecordFinalizer; + @Mock + private NetworkUtilizationManager networkUtilizationManager; + @Mock private SelfNodeInfo selfNodeInfo; @@ -230,7 +234,8 @@ private HandleContextImpl createContext(final TransactionBody txBody) { DEFAULT_CONSENSUS_NOW, authorizer, solvencyPreCheck, - childRecordFinalizer); + childRecordFinalizer, + networkUtilizationManager); } @SuppressWarnings("ConstantConditions") @@ -387,7 +392,8 @@ void setUp() { DEFAULT_CONSENSUS_NOW, authorizer, solvencyPreCheck, - childRecordFinalizer); + childRecordFinalizer, + networkUtilizationManager); } @Test @@ -918,7 +924,8 @@ private HandleContextImpl createContext(final TransactionBody txBody, final Tran DEFAULT_CONSENSUS_NOW, authorizer, solvencyPreCheck, - childRecordFinalizer); + childRecordFinalizer, + networkUtilizationManager); } @SuppressWarnings("ConstantConditions") diff --git a/hedera-node/hedera-app/src/xtest/java/common/BaseScaffoldingModule.java b/hedera-node/hedera-app/src/xtest/java/common/BaseScaffoldingModule.java index 04e0a2caaf45..623ff2056061 100644 --- a/hedera-node/hedera-app/src/xtest/java/common/BaseScaffoldingModule.java +++ b/hedera-node/hedera-app/src/xtest/java/common/BaseScaffoldingModule.java @@ -16,11 +16,6 @@ package common; -import static com.hedera.hapi.node.base.HederaFunctionality.CRYPTO_TRANSFER; -import static com.hedera.node.app.spi.HapiUtils.functionOf; -import static com.hedera.node.app.spi.workflows.HandleContext.TransactionCategory.USER; -import static com.hedera.node.app.throttle.ThrottleAccumulator.ThrottleType.BACKEND_THROTTLE; - import com.hedera.hapi.node.base.AccountID; import com.hedera.hapi.node.base.HederaFunctionality; import com.hedera.hapi.node.base.Key; @@ -66,7 +61,9 @@ import com.hedera.node.app.state.HederaState; import com.hedera.node.app.state.recordcache.DeduplicationCacheImpl; import com.hedera.node.app.state.recordcache.RecordCacheImpl; +import com.hedera.node.app.throttle.NetworkUtilizationManager; import com.hedera.node.app.throttle.ThrottleAccumulator; +import com.hedera.node.app.throttle.impl.NetworkUtilizationManagerImpl; import com.hedera.node.app.validation.ExpiryValidation; import com.hedera.node.app.workflows.SolvencyPreCheck; import com.hedera.node.app.workflows.TransactionChecker; @@ -91,6 +88,9 @@ import dagger.Module; import dagger.Provides; import edu.umd.cs.findbugs.annotations.NonNull; +import org.jetbrains.annotations.NotNull; + +import javax.inject.Singleton; import java.nio.file.FileSystem; import java.nio.file.FileSystems; import java.time.Instant; @@ -98,7 +98,11 @@ import java.util.Map; import java.util.function.BiFunction; import java.util.function.Function; -import javax.inject.Singleton; + +import static com.hedera.hapi.node.base.HederaFunctionality.CRYPTO_TRANSFER; +import static com.hedera.node.app.spi.HapiUtils.functionOf; +import static com.hedera.node.app.spi.workflows.HandleContext.TransactionCategory.USER; +import static com.hedera.node.app.throttle.ThrottleAccumulator.ThrottleType.BACKEND_THROTTLE; /** * A helper module for Dagger2 to instantiate an {@link ContractScaffoldingComponent}; provides @@ -201,6 +205,10 @@ static ConfigProvider provideConfigProvider(@NonNull final Configuration configu @Binds @Singleton ChildRecordFinalizer provideChildRecordFinalizer(@NonNull FinalizeChildRecordHandler childRecordFinalizer); + /* + @Binds + @Singleton + NetworkUtilizationManager provideNetworkUtilizationManager(@NonNull NetworkUtilizationManager networkUtilizationManager);*/ @Provides @Singleton @@ -235,7 +243,8 @@ static Function provideHandleContextCreator( @NonNull final ExchangeRateManager exchangeRateManager, @NonNull final FeeManager feeManager, @NonNull final Authorizer authorizer, - @NonNull final ChildRecordFinalizer childRecordFinalizer) { + @NonNull final ChildRecordFinalizer childRecordFinalizer, + @NonNull final NetworkUtilizationManager networkUtilizationManager) { final var consensusTime = Instant.now(); final var recordListBuilder = new RecordListBuilder(consensusTime); final var parentRecordBuilder = recordListBuilder.userTransactionRecordBuilder(); @@ -273,7 +282,8 @@ static Function provideHandleContextCreator( consensusTime, authorizer, solvencyPreCheck, - childRecordFinalizer); + childRecordFinalizer, + networkUtilizationManager); }; } @@ -281,7 +291,26 @@ static Function provideHandleContextCreator( @Singleton static CongestionMultipliers createCongestionMultipliers(@NonNull ConfigProvider configProvider) { var backendThrottle = new ThrottleAccumulator(() -> 1, configProvider, BACKEND_THROTTLE); - final var genericFeeMultiplier = new ThrottleMultiplier( + final var genericFeeMultiplier = getThrottleMultiplier(configProvider, backendThrottle); + + return getCongestionMultipliers(configProvider, genericFeeMultiplier, backendThrottle); + } + + @Provides + @Singleton + static NetworkUtilizationManager createNetworkUtilizationManager(@NonNull ConfigProvider configProvider) { + var backendThrottle = new ThrottleAccumulator(() -> 1, configProvider, BACKEND_THROTTLE); + final var genericFeeMultiplier = getThrottleMultiplier(configProvider, backendThrottle); + + final var congestionMultipliers = + getCongestionMultipliers(configProvider, genericFeeMultiplier, backendThrottle); + return new NetworkUtilizationManagerImpl(backendThrottle, congestionMultipliers); + } + + @NotNull + private static ThrottleMultiplier getThrottleMultiplier( + @NotNull ConfigProvider configProvider, ThrottleAccumulator backendThrottle) { + return new ThrottleMultiplier( "logical TPS", "TPS", "CryptoTransfer throughput", @@ -294,7 +323,13 @@ static CongestionMultipliers createCongestionMultipliers(@NonNull ConfigProvider .getConfigData(FeesConfig.class) .percentCongestionMultipliers(), () -> backendThrottle.activeThrottlesFor(CRYPTO_TRANSFER)); + } + @NotNull + private static CongestionMultipliers getCongestionMultipliers( + @NotNull ConfigProvider configProvider, + ThrottleMultiplier genericFeeMultiplier, + ThrottleAccumulator backendThrottle) { final var txnRateMultiplier = new EntityUtilizationMultiplier(genericFeeMultiplier, configProvider); final var gasFeeMultiplier = new ThrottleMultiplier( diff --git a/hedera-node/hedera-token-service-impl/src/main/java/com/hedera/node/app/service/token/impl/handlers/CryptoTransferHandler.java b/hedera-node/hedera-token-service-impl/src/main/java/com/hedera/node/app/service/token/impl/handlers/CryptoTransferHandler.java index 136b8f91161a..46965d36c827 100644 --- a/hedera-node/hedera-token-service-impl/src/main/java/com/hedera/node/app/service/token/impl/handlers/CryptoTransferHandler.java +++ b/hedera-node/hedera-token-service-impl/src/main/java/com/hedera/node/app/service/token/impl/handlers/CryptoTransferHandler.java @@ -16,6 +16,7 @@ package com.hedera.node.app.service.token.impl.handlers; +import static com.hedera.hapi.node.base.HederaFunctionality.CRYPTO_CREATE; import static com.hedera.hapi.node.base.ResponseCodeEnum.INSUFFICIENT_PAYER_BALANCE_FOR_CUSTOM_FEE; import static com.hedera.hapi.node.base.ResponseCodeEnum.INSUFFICIENT_SENDER_ACCOUNT_BALANCE_FOR_CUSTOM_FEE; import static com.hedera.hapi.node.base.ResponseCodeEnum.INVALID_ACCOUNT_ID; @@ -177,7 +178,17 @@ private CryptoTransferTransactionBody ensureAndReplaceAliasesInOp( final var op = txn.cryptoTransferOrThrow(); // ensure all aliases exist, if not create then if receivers - ensureExistenceOfAliasesOrCreate(op, transferContext); + try { + ensureExistenceOfAliasesOrCreate(op, transferContext); + } catch (HandleException e) { + final int autoCreationsNumber = transferContext.numOfAutoCreations() + transferContext.numOfLazyCreations(); + context.reclaimPreviouslyReservedThrottle(autoCreationsNumber, CRYPTO_CREATE); + // we only want to reclaim the previously reserved throttle for `CRYPTO_CREATE` transaction + // if there is a failed auto-creation triggered from CryptoTransfer + // this is why we re-throw the HandleException, so that it will be still tackled the same in HandleWorkflow + throw e; + } + if (transferContext.numOfLazyCreations() > 0) { final var config = context.configuration().getConfigData(LazyCreationConfig.class); validateTrue(config.enabled(), NOT_SUPPORTED); From ff569ff8aab6bfdfd93085348b3043b4e1db12ad Mon Sep 17 00:00:00 2001 From: Petar Tonev Date: Fri, 12 Jan 2024 11:42:45 +0200 Subject: [PATCH 02/34] chore: remove comment --- .../src/xtest/java/common/BaseScaffoldingModule.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/hedera-node/hedera-app/src/xtest/java/common/BaseScaffoldingModule.java b/hedera-node/hedera-app/src/xtest/java/common/BaseScaffoldingModule.java index 623ff2056061..08a2b2d56c2a 100644 --- a/hedera-node/hedera-app/src/xtest/java/common/BaseScaffoldingModule.java +++ b/hedera-node/hedera-app/src/xtest/java/common/BaseScaffoldingModule.java @@ -205,10 +205,6 @@ static ConfigProvider provideConfigProvider(@NonNull final Configuration configu @Binds @Singleton ChildRecordFinalizer provideChildRecordFinalizer(@NonNull FinalizeChildRecordHandler childRecordFinalizer); - /* - @Binds - @Singleton - NetworkUtilizationManager provideNetworkUtilizationManager(@NonNull NetworkUtilizationManager networkUtilizationManager);*/ @Provides @Singleton From 2eaac487560c6e027c076b573d9e27864bd7e9d4 Mon Sep 17 00:00:00 2001 From: Petar Tonev Date: Fri, 12 Jan 2024 13:09:41 +0200 Subject: [PATCH 03/34] fix: move throttle reclaiming in inner class when AutoAccountCreator is called --- .../impl/NetworkUtilizationManagerImpl.java | 21 +++--- .../java/common/BaseScaffoldingModule.java | 15 ++-- .../impl/handlers/CryptoTransferHandler.java | 72 ++++++++----------- .../transfer/TransferContextImpl.java | 26 +++++-- 4 files changed, 67 insertions(+), 67 deletions(-) diff --git a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/impl/NetworkUtilizationManagerImpl.java b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/impl/NetworkUtilizationManagerImpl.java index 120a46531f55..b2b1b741652a 100644 --- a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/impl/NetworkUtilizationManagerImpl.java +++ b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/impl/NetworkUtilizationManagerImpl.java @@ -16,6 +16,13 @@ package com.hedera.node.app.throttle.impl; +import static com.hedera.hapi.node.base.HederaFunctionality.CRYPTO_TRANSFER; +import static com.hedera.node.app.records.BlockRecordService.EPOCH; +import static com.hedera.node.app.service.mono.pbj.PbjConverter.fromPbj; +import static com.hedera.node.app.service.mono.pbj.PbjConverter.toPbj; +import static com.hedera.node.app.service.mono.utils.MiscUtils.safeResetThrottles; +import static java.util.Objects.requireNonNull; + import com.hedera.hapi.node.base.AccountID; import com.hedera.hapi.node.base.HederaFunctionality; import com.hedera.hapi.node.base.SignatureMap; @@ -36,20 +43,12 @@ import com.hedera.node.app.workflows.TransactionInfo; import com.hedera.pbj.runtime.io.buffer.Bytes; import edu.umd.cs.findbugs.annotations.NonNull; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import javax.inject.Inject; import java.time.Instant; import java.util.ArrayList; import java.util.List; - -import static com.hedera.hapi.node.base.HederaFunctionality.CRYPTO_TRANSFER; -import static com.hedera.node.app.records.BlockRecordService.EPOCH; -import static com.hedera.node.app.service.mono.pbj.PbjConverter.fromPbj; -import static com.hedera.node.app.service.mono.pbj.PbjConverter.toPbj; -import static com.hedera.node.app.service.mono.utils.MiscUtils.safeResetThrottles; -import static java.util.Objects.requireNonNull; +import javax.inject.Inject; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; /** * Implementation of {@link NetworkUtilizationManager} that delegates to injected {@link ThrottleAccumulator} and {@link diff --git a/hedera-node/hedera-app/src/xtest/java/common/BaseScaffoldingModule.java b/hedera-node/hedera-app/src/xtest/java/common/BaseScaffoldingModule.java index 08a2b2d56c2a..6298add0ea6f 100644 --- a/hedera-node/hedera-app/src/xtest/java/common/BaseScaffoldingModule.java +++ b/hedera-node/hedera-app/src/xtest/java/common/BaseScaffoldingModule.java @@ -16,6 +16,11 @@ package common; +import static com.hedera.hapi.node.base.HederaFunctionality.CRYPTO_TRANSFER; +import static com.hedera.node.app.spi.HapiUtils.functionOf; +import static com.hedera.node.app.spi.workflows.HandleContext.TransactionCategory.USER; +import static com.hedera.node.app.throttle.ThrottleAccumulator.ThrottleType.BACKEND_THROTTLE; + import com.hedera.hapi.node.base.AccountID; import com.hedera.hapi.node.base.HederaFunctionality; import com.hedera.hapi.node.base.Key; @@ -88,9 +93,6 @@ import dagger.Module; import dagger.Provides; import edu.umd.cs.findbugs.annotations.NonNull; -import org.jetbrains.annotations.NotNull; - -import javax.inject.Singleton; import java.nio.file.FileSystem; import java.nio.file.FileSystems; import java.time.Instant; @@ -98,11 +100,8 @@ import java.util.Map; import java.util.function.BiFunction; import java.util.function.Function; - -import static com.hedera.hapi.node.base.HederaFunctionality.CRYPTO_TRANSFER; -import static com.hedera.node.app.spi.HapiUtils.functionOf; -import static com.hedera.node.app.spi.workflows.HandleContext.TransactionCategory.USER; -import static com.hedera.node.app.throttle.ThrottleAccumulator.ThrottleType.BACKEND_THROTTLE; +import javax.inject.Singleton; +import org.jetbrains.annotations.NotNull; /** * A helper module for Dagger2 to instantiate an {@link ContractScaffoldingComponent}; provides diff --git a/hedera-node/hedera-token-service-impl/src/main/java/com/hedera/node/app/service/token/impl/handlers/CryptoTransferHandler.java b/hedera-node/hedera-token-service-impl/src/main/java/com/hedera/node/app/service/token/impl/handlers/CryptoTransferHandler.java index 46965d36c827..4d5b6d5f9024 100644 --- a/hedera-node/hedera-token-service-impl/src/main/java/com/hedera/node/app/service/token/impl/handlers/CryptoTransferHandler.java +++ b/hedera-node/hedera-token-service-impl/src/main/java/com/hedera/node/app/service/token/impl/handlers/CryptoTransferHandler.java @@ -16,34 +16,6 @@ package com.hedera.node.app.service.token.impl.handlers; -import static com.hedera.hapi.node.base.HederaFunctionality.CRYPTO_CREATE; -import static com.hedera.hapi.node.base.ResponseCodeEnum.INSUFFICIENT_PAYER_BALANCE_FOR_CUSTOM_FEE; -import static com.hedera.hapi.node.base.ResponseCodeEnum.INSUFFICIENT_SENDER_ACCOUNT_BALANCE_FOR_CUSTOM_FEE; -import static com.hedera.hapi.node.base.ResponseCodeEnum.INVALID_ACCOUNT_ID; -import static com.hedera.hapi.node.base.ResponseCodeEnum.INVALID_TOKEN_ID; -import static com.hedera.hapi.node.base.ResponseCodeEnum.INVALID_TRANSACTION_BODY; -import static com.hedera.hapi.node.base.ResponseCodeEnum.INVALID_TRANSFER_ACCOUNT_ID; -import static com.hedera.hapi.node.base.ResponseCodeEnum.INVALID_TREASURY_ACCOUNT_FOR_TOKEN; -import static com.hedera.hapi.node.base.ResponseCodeEnum.NOT_SUPPORTED; -import static com.hedera.hapi.node.base.SubType.DEFAULT; -import static com.hedera.hapi.node.base.SubType.TOKEN_FUNGIBLE_COMMON; -import static com.hedera.hapi.node.base.SubType.TOKEN_FUNGIBLE_COMMON_WITH_CUSTOM_FEES; -import static com.hedera.hapi.node.base.SubType.TOKEN_NON_FUNGIBLE_UNIQUE; -import static com.hedera.hapi.node.base.SubType.TOKEN_NON_FUNGIBLE_UNIQUE_WITH_CUSTOM_FEES; -import static com.hedera.node.app.hapi.fees.usage.SingletonUsageProperties.USAGE_PROPERTIES; -import static com.hedera.node.app.hapi.fees.usage.crypto.CryptoOpsUsage.LONG_ACCOUNT_AMOUNT_BYTES; -import static com.hedera.node.app.hapi.fees.usage.token.TokenOpsUsage.LONG_BASIC_ENTITY_ID_SIZE; -import static com.hedera.node.app.hapi.fees.usage.token.entities.TokenEntitySizes.TOKEN_ENTITY_SIZES; -import static com.hedera.node.app.service.token.AliasUtils.isAlias; -import static com.hedera.node.app.service.token.impl.handlers.BaseCryptoHandler.isStakingAccount; -import static com.hedera.node.app.spi.HapiUtils.isHollow; -import static com.hedera.node.app.spi.key.KeyUtils.isValid; -import static com.hedera.node.app.spi.validation.Validations.validateAccountID; -import static com.hedera.node.app.spi.workflows.HandleException.validateTrue; -import static com.hedera.node.app.spi.workflows.PreCheckException.validateTruePreCheck; -import static java.util.Collections.emptyList; -import static java.util.Objects.requireNonNull; - import com.hedera.hapi.node.base.AccountAmount; import com.hedera.hapi.node.base.AccountID; import com.hedera.hapi.node.base.HederaFunctionality; @@ -81,10 +53,38 @@ import com.hedera.node.config.data.LedgerConfig; import com.hedera.node.config.data.TokensConfig; import edu.umd.cs.findbugs.annotations.NonNull; -import java.util.ArrayList; -import java.util.List; + import javax.inject.Inject; import javax.inject.Singleton; +import java.util.ArrayList; +import java.util.List; + +import static com.hedera.hapi.node.base.ResponseCodeEnum.INSUFFICIENT_PAYER_BALANCE_FOR_CUSTOM_FEE; +import static com.hedera.hapi.node.base.ResponseCodeEnum.INSUFFICIENT_SENDER_ACCOUNT_BALANCE_FOR_CUSTOM_FEE; +import static com.hedera.hapi.node.base.ResponseCodeEnum.INVALID_ACCOUNT_ID; +import static com.hedera.hapi.node.base.ResponseCodeEnum.INVALID_TOKEN_ID; +import static com.hedera.hapi.node.base.ResponseCodeEnum.INVALID_TRANSACTION_BODY; +import static com.hedera.hapi.node.base.ResponseCodeEnum.INVALID_TRANSFER_ACCOUNT_ID; +import static com.hedera.hapi.node.base.ResponseCodeEnum.INVALID_TREASURY_ACCOUNT_FOR_TOKEN; +import static com.hedera.hapi.node.base.ResponseCodeEnum.NOT_SUPPORTED; +import static com.hedera.hapi.node.base.SubType.DEFAULT; +import static com.hedera.hapi.node.base.SubType.TOKEN_FUNGIBLE_COMMON; +import static com.hedera.hapi.node.base.SubType.TOKEN_FUNGIBLE_COMMON_WITH_CUSTOM_FEES; +import static com.hedera.hapi.node.base.SubType.TOKEN_NON_FUNGIBLE_UNIQUE; +import static com.hedera.hapi.node.base.SubType.TOKEN_NON_FUNGIBLE_UNIQUE_WITH_CUSTOM_FEES; +import static com.hedera.node.app.hapi.fees.usage.SingletonUsageProperties.USAGE_PROPERTIES; +import static com.hedera.node.app.hapi.fees.usage.crypto.CryptoOpsUsage.LONG_ACCOUNT_AMOUNT_BYTES; +import static com.hedera.node.app.hapi.fees.usage.token.TokenOpsUsage.LONG_BASIC_ENTITY_ID_SIZE; +import static com.hedera.node.app.hapi.fees.usage.token.entities.TokenEntitySizes.TOKEN_ENTITY_SIZES; +import static com.hedera.node.app.service.token.AliasUtils.isAlias; +import static com.hedera.node.app.service.token.impl.handlers.BaseCryptoHandler.isStakingAccount; +import static com.hedera.node.app.spi.HapiUtils.isHollow; +import static com.hedera.node.app.spi.key.KeyUtils.isValid; +import static com.hedera.node.app.spi.validation.Validations.validateAccountID; +import static com.hedera.node.app.spi.workflows.HandleException.validateTrue; +import static com.hedera.node.app.spi.workflows.PreCheckException.validateTruePreCheck; +import static java.util.Collections.emptyList; +import static java.util.Objects.requireNonNull; /** * This class contains all workflow-related functionality regarding {@link @@ -178,17 +178,7 @@ private CryptoTransferTransactionBody ensureAndReplaceAliasesInOp( final var op = txn.cryptoTransferOrThrow(); // ensure all aliases exist, if not create then if receivers - try { - ensureExistenceOfAliasesOrCreate(op, transferContext); - } catch (HandleException e) { - final int autoCreationsNumber = transferContext.numOfAutoCreations() + transferContext.numOfLazyCreations(); - context.reclaimPreviouslyReservedThrottle(autoCreationsNumber, CRYPTO_CREATE); - // we only want to reclaim the previously reserved throttle for `CRYPTO_CREATE` transaction - // if there is a failed auto-creation triggered from CryptoTransfer - // this is why we re-throw the HandleException, so that it will be still tackled the same in HandleWorkflow - throw e; - } - + ensureExistenceOfAliasesOrCreate(op, transferContext); if (transferContext.numOfLazyCreations() > 0) { final var config = context.configuration().getConfigData(LazyCreationConfig.class); validateTrue(config.enabled(), NOT_SUPPORTED); diff --git a/hedera-node/hedera-token-service-impl/src/main/java/com/hedera/node/app/service/token/impl/handlers/transfer/TransferContextImpl.java b/hedera-node/hedera-token-service-impl/src/main/java/com/hedera/node/app/service/token/impl/handlers/transfer/TransferContextImpl.java index a6a1f3a7191d..dd946230e93e 100644 --- a/hedera-node/hedera-token-service-impl/src/main/java/com/hedera/node/app/service/token/impl/handlers/transfer/TransferContextImpl.java +++ b/hedera-node/hedera-token-service-impl/src/main/java/com/hedera/node/app/service/token/impl/handlers/transfer/TransferContextImpl.java @@ -16,12 +16,6 @@ package com.hedera.node.app.service.token.impl.handlers.transfer; -import static com.hedera.hapi.node.base.ResponseCodeEnum.INVALID_ALIAS_KEY; -import static com.hedera.hapi.node.base.ResponseCodeEnum.NOT_SUPPORTED; -import static com.hedera.node.app.service.mono.utils.EntityIdUtils.EVM_ADDRESS_SIZE; -import static com.hedera.node.app.service.token.AliasUtils.isSerializedProtoKey; -import static com.hedera.node.app.spi.workflows.HandleException.validateTrue; - import com.hedera.hapi.node.base.AccountID; import com.hedera.hapi.node.base.TokenAssociation; import com.hedera.hapi.node.transaction.AssessedCustomFee; @@ -32,11 +26,19 @@ import com.hedera.node.config.data.LazyCreationConfig; import com.hedera.node.config.data.TokensConfig; import com.hedera.pbj.runtime.io.buffer.Bytes; + import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import static com.hedera.hapi.node.base.HederaFunctionality.CRYPTO_CREATE; +import static com.hedera.hapi.node.base.ResponseCodeEnum.INVALID_ALIAS_KEY; +import static com.hedera.hapi.node.base.ResponseCodeEnum.NOT_SUPPORTED; +import static com.hedera.node.app.service.mono.utils.EntityIdUtils.EVM_ADDRESS_SIZE; +import static com.hedera.node.app.service.token.AliasUtils.isSerializedProtoKey; +import static com.hedera.node.app.spi.workflows.HandleException.validateTrue; + /** * The context of a token transfer. This is used to pass information between the steps of the transfer. */ @@ -93,7 +95,17 @@ public void createFromAlias(final Bytes alias, final int reqMaxAutoAssociations) validateTrue(tokensConfig.autoCreationsIsEnabled(), NOT_SUPPORTED); } // Keep the created account in the resolutions map - final var createdAccount = autoAccountCreator.create(alias, reqMaxAutoAssociations); + AccountID createdAccount; + try { + createdAccount = autoAccountCreator.create(alias, reqMaxAutoAssociations); + } catch (HandleException e) { + final int autoCreationsNumber = numOfAutoCreations() + numOfLazyCreations(); + context.reclaimPreviouslyReservedThrottle(autoCreationsNumber, CRYPTO_CREATE); + // we only want to reclaim the previously reserved throttle for `CRYPTO_CREATE` transaction + // if there is a failed auto-creation triggered from CryptoTransfer + // this is why we re-throw the HandleException, so that it will be still tackled the same in HandleWorkflow + throw e; + } resolutions.put(alias, createdAccount); } From 83b64de22e45fcc17917f6d0f1cbafe00738305b Mon Sep 17 00:00:00 2001 From: Petar Tonev Date: Fri, 12 Jan 2024 13:46:46 +0200 Subject: [PATCH 04/34] chore: apply spotless --- .../impl/handlers/CryptoTransferHandler.java | 59 +++++++++---------- .../transfer/TransferContextImpl.java | 15 +++-- 2 files changed, 36 insertions(+), 38 deletions(-) diff --git a/hedera-node/hedera-token-service-impl/src/main/java/com/hedera/node/app/service/token/impl/handlers/CryptoTransferHandler.java b/hedera-node/hedera-token-service-impl/src/main/java/com/hedera/node/app/service/token/impl/handlers/CryptoTransferHandler.java index 4d5b6d5f9024..136b8f91161a 100644 --- a/hedera-node/hedera-token-service-impl/src/main/java/com/hedera/node/app/service/token/impl/handlers/CryptoTransferHandler.java +++ b/hedera-node/hedera-token-service-impl/src/main/java/com/hedera/node/app/service/token/impl/handlers/CryptoTransferHandler.java @@ -16,6 +16,33 @@ package com.hedera.node.app.service.token.impl.handlers; +import static com.hedera.hapi.node.base.ResponseCodeEnum.INSUFFICIENT_PAYER_BALANCE_FOR_CUSTOM_FEE; +import static com.hedera.hapi.node.base.ResponseCodeEnum.INSUFFICIENT_SENDER_ACCOUNT_BALANCE_FOR_CUSTOM_FEE; +import static com.hedera.hapi.node.base.ResponseCodeEnum.INVALID_ACCOUNT_ID; +import static com.hedera.hapi.node.base.ResponseCodeEnum.INVALID_TOKEN_ID; +import static com.hedera.hapi.node.base.ResponseCodeEnum.INVALID_TRANSACTION_BODY; +import static com.hedera.hapi.node.base.ResponseCodeEnum.INVALID_TRANSFER_ACCOUNT_ID; +import static com.hedera.hapi.node.base.ResponseCodeEnum.INVALID_TREASURY_ACCOUNT_FOR_TOKEN; +import static com.hedera.hapi.node.base.ResponseCodeEnum.NOT_SUPPORTED; +import static com.hedera.hapi.node.base.SubType.DEFAULT; +import static com.hedera.hapi.node.base.SubType.TOKEN_FUNGIBLE_COMMON; +import static com.hedera.hapi.node.base.SubType.TOKEN_FUNGIBLE_COMMON_WITH_CUSTOM_FEES; +import static com.hedera.hapi.node.base.SubType.TOKEN_NON_FUNGIBLE_UNIQUE; +import static com.hedera.hapi.node.base.SubType.TOKEN_NON_FUNGIBLE_UNIQUE_WITH_CUSTOM_FEES; +import static com.hedera.node.app.hapi.fees.usage.SingletonUsageProperties.USAGE_PROPERTIES; +import static com.hedera.node.app.hapi.fees.usage.crypto.CryptoOpsUsage.LONG_ACCOUNT_AMOUNT_BYTES; +import static com.hedera.node.app.hapi.fees.usage.token.TokenOpsUsage.LONG_BASIC_ENTITY_ID_SIZE; +import static com.hedera.node.app.hapi.fees.usage.token.entities.TokenEntitySizes.TOKEN_ENTITY_SIZES; +import static com.hedera.node.app.service.token.AliasUtils.isAlias; +import static com.hedera.node.app.service.token.impl.handlers.BaseCryptoHandler.isStakingAccount; +import static com.hedera.node.app.spi.HapiUtils.isHollow; +import static com.hedera.node.app.spi.key.KeyUtils.isValid; +import static com.hedera.node.app.spi.validation.Validations.validateAccountID; +import static com.hedera.node.app.spi.workflows.HandleException.validateTrue; +import static com.hedera.node.app.spi.workflows.PreCheckException.validateTruePreCheck; +import static java.util.Collections.emptyList; +import static java.util.Objects.requireNonNull; + import com.hedera.hapi.node.base.AccountAmount; import com.hedera.hapi.node.base.AccountID; import com.hedera.hapi.node.base.HederaFunctionality; @@ -53,38 +80,10 @@ import com.hedera.node.config.data.LedgerConfig; import com.hedera.node.config.data.TokensConfig; import edu.umd.cs.findbugs.annotations.NonNull; - -import javax.inject.Inject; -import javax.inject.Singleton; import java.util.ArrayList; import java.util.List; - -import static com.hedera.hapi.node.base.ResponseCodeEnum.INSUFFICIENT_PAYER_BALANCE_FOR_CUSTOM_FEE; -import static com.hedera.hapi.node.base.ResponseCodeEnum.INSUFFICIENT_SENDER_ACCOUNT_BALANCE_FOR_CUSTOM_FEE; -import static com.hedera.hapi.node.base.ResponseCodeEnum.INVALID_ACCOUNT_ID; -import static com.hedera.hapi.node.base.ResponseCodeEnum.INVALID_TOKEN_ID; -import static com.hedera.hapi.node.base.ResponseCodeEnum.INVALID_TRANSACTION_BODY; -import static com.hedera.hapi.node.base.ResponseCodeEnum.INVALID_TRANSFER_ACCOUNT_ID; -import static com.hedera.hapi.node.base.ResponseCodeEnum.INVALID_TREASURY_ACCOUNT_FOR_TOKEN; -import static com.hedera.hapi.node.base.ResponseCodeEnum.NOT_SUPPORTED; -import static com.hedera.hapi.node.base.SubType.DEFAULT; -import static com.hedera.hapi.node.base.SubType.TOKEN_FUNGIBLE_COMMON; -import static com.hedera.hapi.node.base.SubType.TOKEN_FUNGIBLE_COMMON_WITH_CUSTOM_FEES; -import static com.hedera.hapi.node.base.SubType.TOKEN_NON_FUNGIBLE_UNIQUE; -import static com.hedera.hapi.node.base.SubType.TOKEN_NON_FUNGIBLE_UNIQUE_WITH_CUSTOM_FEES; -import static com.hedera.node.app.hapi.fees.usage.SingletonUsageProperties.USAGE_PROPERTIES; -import static com.hedera.node.app.hapi.fees.usage.crypto.CryptoOpsUsage.LONG_ACCOUNT_AMOUNT_BYTES; -import static com.hedera.node.app.hapi.fees.usage.token.TokenOpsUsage.LONG_BASIC_ENTITY_ID_SIZE; -import static com.hedera.node.app.hapi.fees.usage.token.entities.TokenEntitySizes.TOKEN_ENTITY_SIZES; -import static com.hedera.node.app.service.token.AliasUtils.isAlias; -import static com.hedera.node.app.service.token.impl.handlers.BaseCryptoHandler.isStakingAccount; -import static com.hedera.node.app.spi.HapiUtils.isHollow; -import static com.hedera.node.app.spi.key.KeyUtils.isValid; -import static com.hedera.node.app.spi.validation.Validations.validateAccountID; -import static com.hedera.node.app.spi.workflows.HandleException.validateTrue; -import static com.hedera.node.app.spi.workflows.PreCheckException.validateTruePreCheck; -import static java.util.Collections.emptyList; -import static java.util.Objects.requireNonNull; +import javax.inject.Inject; +import javax.inject.Singleton; /** * This class contains all workflow-related functionality regarding {@link diff --git a/hedera-node/hedera-token-service-impl/src/main/java/com/hedera/node/app/service/token/impl/handlers/transfer/TransferContextImpl.java b/hedera-node/hedera-token-service-impl/src/main/java/com/hedera/node/app/service/token/impl/handlers/transfer/TransferContextImpl.java index dd946230e93e..a5b1e568a76b 100644 --- a/hedera-node/hedera-token-service-impl/src/main/java/com/hedera/node/app/service/token/impl/handlers/transfer/TransferContextImpl.java +++ b/hedera-node/hedera-token-service-impl/src/main/java/com/hedera/node/app/service/token/impl/handlers/transfer/TransferContextImpl.java @@ -16,6 +16,13 @@ package com.hedera.node.app.service.token.impl.handlers.transfer; +import static com.hedera.hapi.node.base.HederaFunctionality.CRYPTO_CREATE; +import static com.hedera.hapi.node.base.ResponseCodeEnum.INVALID_ALIAS_KEY; +import static com.hedera.hapi.node.base.ResponseCodeEnum.NOT_SUPPORTED; +import static com.hedera.node.app.service.mono.utils.EntityIdUtils.EVM_ADDRESS_SIZE; +import static com.hedera.node.app.service.token.AliasUtils.isSerializedProtoKey; +import static com.hedera.node.app.spi.workflows.HandleException.validateTrue; + import com.hedera.hapi.node.base.AccountID; import com.hedera.hapi.node.base.TokenAssociation; import com.hedera.hapi.node.transaction.AssessedCustomFee; @@ -26,19 +33,11 @@ import com.hedera.node.config.data.LazyCreationConfig; import com.hedera.node.config.data.TokensConfig; import com.hedera.pbj.runtime.io.buffer.Bytes; - import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import static com.hedera.hapi.node.base.HederaFunctionality.CRYPTO_CREATE; -import static com.hedera.hapi.node.base.ResponseCodeEnum.INVALID_ALIAS_KEY; -import static com.hedera.hapi.node.base.ResponseCodeEnum.NOT_SUPPORTED; -import static com.hedera.node.app.service.mono.utils.EntityIdUtils.EVM_ADDRESS_SIZE; -import static com.hedera.node.app.service.token.AliasUtils.isSerializedProtoKey; -import static com.hedera.node.app.spi.workflows.HandleException.validateTrue; - /** * The context of a token transfer. This is used to pass information between the steps of the transfer. */ From eb803d76022ead64ea964923a7260cf9a898c8b3 Mon Sep 17 00:00:00 2001 From: Petar Tonev Date: Fri, 12 Jan 2024 17:15:16 +0200 Subject: [PATCH 05/34] fix: unit test in HandleContextImplTest --- .../node/app/workflows/handle/HandleContextImplTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hedera-node/hedera-app/src/test/java/com/hedera/node/app/workflows/handle/HandleContextImplTest.java b/hedera-node/hedera-app/src/test/java/com/hedera/node/app/workflows/handle/HandleContextImplTest.java index d43e4ed0144e..7c4cf4f2a0e1 100644 --- a/hedera-node/hedera-app/src/test/java/com/hedera/node/app/workflows/handle/HandleContextImplTest.java +++ b/hedera-node/hedera-app/src/test/java/com/hedera/node/app/workflows/handle/HandleContextImplTest.java @@ -264,7 +264,8 @@ void testConstructorWithInvalidArguments() { DEFAULT_CONSENSUS_NOW, authorizer, solvencyPreCheck, - childRecordFinalizer + childRecordFinalizer, + networkUtilizationManager }; final var constructor = HandleContextImpl.class.getConstructors()[0]; From 312f1b712a09f2a4052536d240dba3fcbea1ff80 Mon Sep 17 00:00:00 2001 From: Petar Tonev Date: Wed, 17 Jan 2024 21:19:09 +0200 Subject: [PATCH 06/34] fix: use frontend instead of backend throttle and add checks to handle the properly the correct cases --- .../node/app/spi/workflows/HandleContext.java | 21 ++++++ .../throttle/NetworkUtilizationManager.java | 9 --- .../SynchronizedThrottleAccumulator.java | 4 ++ .../impl/NetworkUtilizationManagerImpl.java | 6 -- .../workflows/handle/HandleContextImpl.java | 33 ++++++--- .../app/workflows/handle/HandleWorkflow.java | 8 ++- .../handle/HandleContextImplTest.java | 12 ++-- .../workflows/handle/HandleWorkflowTest.java | 69 +++++++++++++++++++ .../java/common/BaseScaffoldingModule.java | 19 +++-- .../transfer/TransferContextImpl.java | 10 ++- 10 files changed, 148 insertions(+), 43 deletions(-) diff --git a/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/workflows/HandleContext.java b/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/workflows/HandleContext.java index 7c3a340dbce9..b3f1cc255878 100644 --- a/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/workflows/HandleContext.java +++ b/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/workflows/HandleContext.java @@ -677,6 +677,27 @@ default T dispatchRemovableChildTransaction( @NonNull RecordListCheckPoint createRecordListCheckPoint(); + /** + * Returns the current {@link HederaFunctionality} + * + * @return the Hedera functionality in the context + */ + HederaFunctionality getHederaFunctionality(); + + /** + * Returns the current {@link TransactionCategory} of the transaction + * + * @return the current transaction category + */ + TransactionCategory getTransactionCategory(); + + /** + * Returns whether the current transaction being processed was submitted by this node. + * + * @return true if the current transaction was submitted by this node + */ + boolean isSelfSubmitted(); + /** * A stack of savepoints. * diff --git a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/NetworkUtilizationManager.java b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/NetworkUtilizationManager.java index c74ebb9560df..3fa444516686 100644 --- a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/NetworkUtilizationManager.java +++ b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/NetworkUtilizationManager.java @@ -17,7 +17,6 @@ package com.hedera.node.app.throttle; import com.hedera.hapi.node.base.AccountID; -import com.hedera.hapi.node.base.HederaFunctionality; import com.hedera.node.app.state.HederaState; import com.hedera.node.app.workflows.TransactionInfo; import edu.umd.cs.findbugs.annotations.NonNull; @@ -66,14 +65,6 @@ void trackFeePayments( */ void leakUnusedGasPreviouslyReserved(@NonNull final TransactionInfo txnInfo, final long value); - /* - * Leaks the claimed capacity for a number of transactions of the same functionality. - * - * @param n the number of transactions to consider - * @param function the functionality type of the transactions - */ - void leakUnusedThrottlePreviouslyReserved(int n, HederaFunctionality function); - /* * Resets the throttle usage and congestion multiplier from the given state. * diff --git a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/SynchronizedThrottleAccumulator.java b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/SynchronizedThrottleAccumulator.java index cd44a677e808..efe77035164b 100644 --- a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/SynchronizedThrottleAccumulator.java +++ b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/SynchronizedThrottleAccumulator.java @@ -75,4 +75,8 @@ private void setDecisionTime() { final var now = Instant.now(); lastDecisionTime = now.isBefore(lastDecisionTime) ? lastDecisionTime : now; } + + public void leakUnusedThrottlePreviouslyReserved(int n, HederaFunctionality function) { + frontendThrottle.leakCapacityForNOfUnscaled(n, function); + } } diff --git a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/impl/NetworkUtilizationManagerImpl.java b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/impl/NetworkUtilizationManagerImpl.java index b2b1b741652a..36610c63031d 100644 --- a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/impl/NetworkUtilizationManagerImpl.java +++ b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/impl/NetworkUtilizationManagerImpl.java @@ -24,7 +24,6 @@ import static java.util.Objects.requireNonNull; import com.hedera.hapi.node.base.AccountID; -import com.hedera.hapi.node.base.HederaFunctionality; import com.hedera.hapi.node.base.SignatureMap; import com.hedera.hapi.node.base.Timestamp; import com.hedera.hapi.node.base.Transaction; @@ -202,9 +201,4 @@ public boolean wasLastTxnGasThrottled() { public void leakUnusedGasPreviouslyReserved(@NonNull final TransactionInfo txnInfo, long value) { backendThrottle.leakUnusedGasPreviouslyReserved(txnInfo, value); } - - @Override - public void leakUnusedThrottlePreviouslyReserved(int n, HederaFunctionality function) { - backendThrottle.leakCapacityForNOfUnscaled(n, function); - } } diff --git a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleContextImpl.java b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleContextImpl.java index 7fe9a69dfb22..ec6c60aa855c 100644 --- a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleContextImpl.java +++ b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleContextImpl.java @@ -75,7 +75,7 @@ import com.hedera.node.app.spi.workflows.record.SingleTransactionRecordBuilder; import com.hedera.node.app.state.HederaRecordCache; import com.hedera.node.app.state.WrappedHederaState; -import com.hedera.node.app.throttle.NetworkUtilizationManager; +import com.hedera.node.app.throttle.SynchronizedThrottleAccumulator; import com.hedera.node.app.workflows.SolvencyPreCheck; import com.hedera.node.app.workflows.TransactionChecker; import com.hedera.node.app.workflows.dispatcher.ReadableStoreFactory; @@ -93,6 +93,7 @@ import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; import java.time.Instant; +import java.util.Objects; import java.util.function.Function; import java.util.function.Predicate; import java.util.function.Supplier; @@ -132,7 +133,7 @@ public class HandleContextImpl implements HandleContext, FeeContext { private final Authorizer authorizer; private final SolvencyPreCheck solvencyPreCheck; private final ChildRecordFinalizer childRecordFinalizer; - private final NetworkUtilizationManager networkUtilizationManager; + private final SynchronizedThrottleAccumulator synchronizedThrottleAccumulator; private ReadableStoreFactory readableStoreFactory; private AttributeValidator attributeValidator; @@ -163,7 +164,7 @@ public class HandleContextImpl implements HandleContext, FeeContext { * @param authorizer The {@link Authorizer} used to authorize the transaction * @param solvencyPreCheck The {@link SolvencyPreCheck} used to validate if the account is able to pay the fees * @param childRecordFinalizer The {@link ChildRecordFinalizer} used to finalize child records - * @param networkUtilizationManager The {@link NetworkUtilizationManager} used to manage tracking of network utilization + * @param synchronizedThrottleAccumulator The {@link SynchronizedThrottleAccumulator} used to manage tracking of network utilization */ public HandleContextImpl( @NonNull final TransactionBody txBody, @@ -189,7 +190,7 @@ public HandleContextImpl( @NonNull final Authorizer authorizer, @NonNull final SolvencyPreCheck solvencyPreCheck, @NonNull final ChildRecordFinalizer childRecordFinalizer, - @NonNull final NetworkUtilizationManager networkUtilizationManager) { + @NonNull final SynchronizedThrottleAccumulator synchronizedThrottleAccumulator) { this.txBody = requireNonNull(txBody, "txBody must not be null"); this.functionality = requireNonNull(functionality, "functionality must not be null"); this.payer = requireNonNull(payer, "payer must not be null"); @@ -211,8 +212,8 @@ public HandleContextImpl( requireNonNull(userTransactionConsensusTime, "userTransactionConsensusTime must not be null"); this.authorizer = requireNonNull(authorizer, "authorizer must not be null"); this.childRecordFinalizer = requireNonNull(childRecordFinalizer, "childRecordFinalizer must not be null"); - this.networkUtilizationManager = - requireNonNull(networkUtilizationManager, "networkUtilizationManager must not be null"); + this.synchronizedThrottleAccumulator = + requireNonNull(synchronizedThrottleAccumulator, "synchronizedThrottleAccumulator must not be null"); final var serviceScope = serviceScopeLookup.getServiceName(txBody); this.writableStoreFactory = new WritableStoreFactory(stack, serviceScope); @@ -697,7 +698,7 @@ private void dispatchSyntheticTxn( authorizer, solvencyPreCheck, childRecordFinalizer, - networkUtilizationManager); + synchronizedThrottleAccumulator); if (dispatchValidationResult != null) { childContext.feeAccumulator.chargeFees( @@ -892,7 +893,23 @@ public RecordListCheckPoint createRecordListCheckPoint() { @Override public void reclaimPreviouslyReservedThrottle(int n, HederaFunctionality function) { - networkUtilizationManager.leakUnusedThrottlePreviouslyReserved(n, function); + synchronizedThrottleAccumulator.leakUnusedThrottlePreviouslyReserved(n, function); + } + + @Override + public HederaFunctionality getHederaFunctionality() { + return functionality; + } + + @Override + public TransactionCategory getTransactionCategory() { + return category; + } + + @Override + public boolean isSelfSubmitted() { + return Objects.equals( + body().nodeAccountID(), networkInfo().selfNodeInfo().accountId()); } public enum PrecedingTransactionCategory { diff --git a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleWorkflow.java b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleWorkflow.java index 16c91e0014f4..2e8c4017f812 100644 --- a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleWorkflow.java +++ b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleWorkflow.java @@ -85,6 +85,7 @@ import com.hedera.node.app.state.HederaRecordCache; import com.hedera.node.app.state.HederaState; import com.hedera.node.app.throttle.NetworkUtilizationManager; +import com.hedera.node.app.throttle.SynchronizedThrottleAccumulator; import com.hedera.node.app.workflows.SolvencyPreCheck; import com.hedera.node.app.workflows.TransactionChecker; import com.hedera.node.app.workflows.dispatcher.ReadableStoreFactory; @@ -147,6 +148,7 @@ public class HandleWorkflow { private final SolvencyPreCheck solvencyPreCheck; private final Authorizer authorizer; private final NetworkUtilizationManager networkUtilizationManager; + private final SynchronizedThrottleAccumulator synchronizedThrottleAccumulator; @Inject public HandleWorkflow( @@ -169,6 +171,7 @@ public HandleWorkflow( @NonNull final SolvencyPreCheck solvencyPreCheck, @NonNull final Authorizer authorizer, @NonNull final NetworkUtilizationManager networkUtilizationManager, + @NonNull final SynchronizedThrottleAccumulator synchronizedThrottleAccumulator, @NonNull final ScheduleExpirationHook scheduleExpirationHook) { this.networkInfo = requireNonNull(networkInfo, "networkInfo must not be null"); this.preHandleWorkflow = requireNonNull(preHandleWorkflow, "preHandleWorkflow must not be null"); @@ -192,6 +195,9 @@ public HandleWorkflow( this.authorizer = requireNonNull(authorizer, "authorizer must not be null"); this.networkUtilizationManager = requireNonNull(networkUtilizationManager, "networkUtilizationManager must not be null"); + this.synchronizedThrottleAccumulator = + requireNonNull(synchronizedThrottleAccumulator, "synchronizedThrottleAccumulator must not be null"); + ; this.scheduleExpirationHook = requireNonNull(scheduleExpirationHook, "scheduleExpirationHook must not be null"); } @@ -390,7 +396,7 @@ private void handleUserTransaction( authorizer, solvencyPreCheck, childRecordFinalizer, - networkUtilizationManager); + synchronizedThrottleAccumulator); // Calculate the fee fees = dispatcher.dispatchComputeFees(context); diff --git a/hedera-node/hedera-app/src/test/java/com/hedera/node/app/workflows/handle/HandleContextImplTest.java b/hedera-node/hedera-app/src/test/java/com/hedera/node/app/workflows/handle/HandleContextImplTest.java index 7c4cf4f2a0e1..4f958f480cda 100644 --- a/hedera-node/hedera-app/src/test/java/com/hedera/node/app/workflows/handle/HandleContextImplTest.java +++ b/hedera-node/hedera-app/src/test/java/com/hedera/node/app/workflows/handle/HandleContextImplTest.java @@ -89,7 +89,7 @@ import com.hedera.node.app.spi.workflows.record.SingleTransactionRecordBuilder; import com.hedera.node.app.state.HederaRecordCache; import com.hedera.node.app.state.HederaState; -import com.hedera.node.app.throttle.NetworkUtilizationManager; +import com.hedera.node.app.throttle.SynchronizedThrottleAccumulator; import com.hedera.node.app.workflows.SolvencyPreCheck; import com.hedera.node.app.workflows.TransactionChecker; import com.hedera.node.app.workflows.dispatcher.TransactionDispatcher; @@ -180,7 +180,7 @@ class HandleContextImplTest extends StateTestBase implements Scenarios { private ChildRecordFinalizer childRecordFinalizer; @Mock - private NetworkUtilizationManager networkUtilizationManager; + private SynchronizedThrottleAccumulator synchronizedThrottleAccumulator; @Mock private SelfNodeInfo selfNodeInfo; @@ -235,7 +235,7 @@ private HandleContextImpl createContext(final TransactionBody txBody) { authorizer, solvencyPreCheck, childRecordFinalizer, - networkUtilizationManager); + synchronizedThrottleAccumulator); } @SuppressWarnings("ConstantConditions") @@ -265,7 +265,7 @@ void testConstructorWithInvalidArguments() { authorizer, solvencyPreCheck, childRecordFinalizer, - networkUtilizationManager + synchronizedThrottleAccumulator }; final var constructor = HandleContextImpl.class.getConstructors()[0]; @@ -394,7 +394,7 @@ void setUp() { authorizer, solvencyPreCheck, childRecordFinalizer, - networkUtilizationManager); + synchronizedThrottleAccumulator); } @Test @@ -926,7 +926,7 @@ private HandleContextImpl createContext(final TransactionBody txBody, final Tran authorizer, solvencyPreCheck, childRecordFinalizer, - networkUtilizationManager); + synchronizedThrottleAccumulator); } @SuppressWarnings("ConstantConditions") diff --git a/hedera-node/hedera-app/src/test/java/com/hedera/node/app/workflows/handle/HandleWorkflowTest.java b/hedera-node/hedera-app/src/test/java/com/hedera/node/app/workflows/handle/HandleWorkflowTest.java index 23f07dcaa4a8..17ba08365704 100644 --- a/hedera-node/hedera-app/src/test/java/com/hedera/node/app/workflows/handle/HandleWorkflowTest.java +++ b/hedera-node/hedera-app/src/test/java/com/hedera/node/app/workflows/handle/HandleWorkflowTest.java @@ -62,6 +62,7 @@ import com.hedera.node.app.state.HederaRecordCache.DuplicateCheckResult; import com.hedera.node.app.state.SingleTransactionRecord; import com.hedera.node.app.throttle.NetworkUtilizationManager; +import com.hedera.node.app.throttle.SynchronizedThrottleAccumulator; import com.hedera.node.app.workflows.SolvencyPreCheck; import com.hedera.node.app.workflows.TransactionChecker; import com.hedera.node.app.workflows.TransactionScenarioBuilder; @@ -198,6 +199,9 @@ private static PreHandleResult createPreHandleResult(@NonNull Status status, @No @Mock private NetworkUtilizationManager networkUtilizationManager; + @Mock + private SynchronizedThrottleAccumulator synchronizedThrottleAccumulator; + @Mock private PlatformStateUpdateFacility platformStateUpdateFacility; @@ -283,6 +287,7 @@ void setup() throws PreCheckException { solvencyPreCheck, authorizer, networkUtilizationManager, + synchronizedThrottleAccumulator, scheduleExpirationHook); } @@ -309,6 +314,7 @@ void testContructorWithInvalidArguments() { solvencyPreCheck, authorizer, networkUtilizationManager, + synchronizedThrottleAccumulator, scheduleExpirationHook)) .isInstanceOf(NullPointerException.class); assertThatThrownBy(() -> new HandleWorkflow( @@ -331,6 +337,7 @@ void testContructorWithInvalidArguments() { solvencyPreCheck, authorizer, networkUtilizationManager, + synchronizedThrottleAccumulator, scheduleExpirationHook)) .isInstanceOf(NullPointerException.class); assertThatThrownBy(() -> new HandleWorkflow( @@ -353,6 +360,7 @@ void testContructorWithInvalidArguments() { solvencyPreCheck, authorizer, networkUtilizationManager, + synchronizedThrottleAccumulator, scheduleExpirationHook)) .isInstanceOf(NullPointerException.class); assertThatThrownBy(() -> new HandleWorkflow( @@ -375,6 +383,7 @@ void testContructorWithInvalidArguments() { solvencyPreCheck, authorizer, networkUtilizationManager, + synchronizedThrottleAccumulator, scheduleExpirationHook)) .isInstanceOf(NullPointerException.class); assertThatThrownBy(() -> new HandleWorkflow( @@ -397,6 +406,7 @@ void testContructorWithInvalidArguments() { solvencyPreCheck, authorizer, networkUtilizationManager, + synchronizedThrottleAccumulator, scheduleExpirationHook)) .isInstanceOf(NullPointerException.class); assertThatThrownBy(() -> new HandleWorkflow( @@ -419,6 +429,7 @@ void testContructorWithInvalidArguments() { solvencyPreCheck, authorizer, networkUtilizationManager, + synchronizedThrottleAccumulator, scheduleExpirationHook)) .isInstanceOf(NullPointerException.class); assertThatThrownBy(() -> new HandleWorkflow( @@ -441,6 +452,7 @@ void testContructorWithInvalidArguments() { solvencyPreCheck, authorizer, networkUtilizationManager, + synchronizedThrottleAccumulator, scheduleExpirationHook)) .isInstanceOf(NullPointerException.class); assertThatThrownBy(() -> new HandleWorkflow( @@ -463,6 +475,7 @@ void testContructorWithInvalidArguments() { solvencyPreCheck, authorizer, networkUtilizationManager, + synchronizedThrottleAccumulator, scheduleExpirationHook)) .isInstanceOf(NullPointerException.class); assertThatThrownBy(() -> new HandleWorkflow( @@ -485,6 +498,7 @@ void testContructorWithInvalidArguments() { solvencyPreCheck, authorizer, networkUtilizationManager, + synchronizedThrottleAccumulator, scheduleExpirationHook)) .isInstanceOf(NullPointerException.class); assertThatThrownBy(() -> new HandleWorkflow( @@ -507,6 +521,7 @@ void testContructorWithInvalidArguments() { solvencyPreCheck, authorizer, networkUtilizationManager, + synchronizedThrottleAccumulator, scheduleExpirationHook)) .isInstanceOf(NullPointerException.class); assertThatThrownBy(() -> new HandleWorkflow( @@ -529,6 +544,7 @@ void testContructorWithInvalidArguments() { solvencyPreCheck, authorizer, networkUtilizationManager, + synchronizedThrottleAccumulator, scheduleExpirationHook)) .isInstanceOf(NullPointerException.class); assertThatThrownBy(() -> new HandleWorkflow( @@ -551,6 +567,7 @@ void testContructorWithInvalidArguments() { solvencyPreCheck, authorizer, networkUtilizationManager, + synchronizedThrottleAccumulator, scheduleExpirationHook)) .isInstanceOf(NullPointerException.class); assertThatThrownBy(() -> new HandleWorkflow( @@ -573,6 +590,7 @@ void testContructorWithInvalidArguments() { solvencyPreCheck, authorizer, networkUtilizationManager, + synchronizedThrottleAccumulator, scheduleExpirationHook)) .isInstanceOf(NullPointerException.class); assertThatThrownBy(() -> new HandleWorkflow( @@ -595,6 +613,7 @@ void testContructorWithInvalidArguments() { solvencyPreCheck, authorizer, networkUtilizationManager, + synchronizedThrottleAccumulator, scheduleExpirationHook)) .isInstanceOf(NullPointerException.class); assertThatThrownBy(() -> new HandleWorkflow( @@ -617,6 +636,7 @@ void testContructorWithInvalidArguments() { solvencyPreCheck, authorizer, networkUtilizationManager, + synchronizedThrottleAccumulator, scheduleExpirationHook)) .isInstanceOf(NullPointerException.class); assertThatThrownBy(() -> new HandleWorkflow( @@ -639,6 +659,7 @@ void testContructorWithInvalidArguments() { null, authorizer, networkUtilizationManager, + synchronizedThrottleAccumulator, scheduleExpirationHook)) .isInstanceOf(NullPointerException.class); assertThatThrownBy(() -> new HandleWorkflow( @@ -661,6 +682,30 @@ void testContructorWithInvalidArguments() { solvencyPreCheck, null, networkUtilizationManager, + synchronizedThrottleAccumulator, + scheduleExpirationHook)) + .isInstanceOf(NullPointerException.class); + assertThatThrownBy(() -> new HandleWorkflow( + networkInfo, + preHandleWorkflow, + dispatcher, + blockRecordManager, + checker, + serviceLookup, + configProvider, + recordCache, + genesisRecordsTimeHook, + stakingPeriodTimeHook, + feeManager, + exchangeRateManager, + childRecordFinalizer, + finalizer, + systemFileUpdateFacility, + platformStateUpdateFacility, + solvencyPreCheck, + authorizer, + null, + synchronizedThrottleAccumulator, scheduleExpirationHook)) .isInstanceOf(NullPointerException.class); assertThatThrownBy(() -> new HandleWorkflow( @@ -682,9 +727,33 @@ void testContructorWithInvalidArguments() { platformStateUpdateFacility, solvencyPreCheck, authorizer, + networkUtilizationManager, null, scheduleExpirationHook)) .isInstanceOf(NullPointerException.class); + assertThatThrownBy(() -> new HandleWorkflow( + networkInfo, + preHandleWorkflow, + dispatcher, + blockRecordManager, + checker, + serviceLookup, + configProvider, + recordCache, + genesisRecordsTimeHook, + stakingPeriodTimeHook, + feeManager, + exchangeRateManager, + childRecordFinalizer, + finalizer, + systemFileUpdateFacility, + platformStateUpdateFacility, + solvencyPreCheck, + authorizer, + networkUtilizationManager, + synchronizedThrottleAccumulator, + null)) + .isInstanceOf(NullPointerException.class); } @Test diff --git a/hedera-node/hedera-app/src/xtest/java/common/BaseScaffoldingModule.java b/hedera-node/hedera-app/src/xtest/java/common/BaseScaffoldingModule.java index 6298add0ea6f..979feaf3578f 100644 --- a/hedera-node/hedera-app/src/xtest/java/common/BaseScaffoldingModule.java +++ b/hedera-node/hedera-app/src/xtest/java/common/BaseScaffoldingModule.java @@ -20,6 +20,7 @@ import static com.hedera.node.app.spi.HapiUtils.functionOf; import static com.hedera.node.app.spi.workflows.HandleContext.TransactionCategory.USER; import static com.hedera.node.app.throttle.ThrottleAccumulator.ThrottleType.BACKEND_THROTTLE; +import static com.hedera.node.app.throttle.ThrottleAccumulator.ThrottleType.FRONTEND_THROTTLE; import com.hedera.hapi.node.base.AccountID; import com.hedera.hapi.node.base.HederaFunctionality; @@ -66,9 +67,8 @@ import com.hedera.node.app.state.HederaState; import com.hedera.node.app.state.recordcache.DeduplicationCacheImpl; import com.hedera.node.app.state.recordcache.RecordCacheImpl; -import com.hedera.node.app.throttle.NetworkUtilizationManager; +import com.hedera.node.app.throttle.SynchronizedThrottleAccumulator; import com.hedera.node.app.throttle.ThrottleAccumulator; -import com.hedera.node.app.throttle.impl.NetworkUtilizationManagerImpl; import com.hedera.node.app.validation.ExpiryValidation; import com.hedera.node.app.workflows.SolvencyPreCheck; import com.hedera.node.app.workflows.TransactionChecker; @@ -239,7 +239,7 @@ static Function provideHandleContextCreator( @NonNull final FeeManager feeManager, @NonNull final Authorizer authorizer, @NonNull final ChildRecordFinalizer childRecordFinalizer, - @NonNull final NetworkUtilizationManager networkUtilizationManager) { + @NonNull final SynchronizedThrottleAccumulator synchronizedThrottleAccumulator) { final var consensusTime = Instant.now(); final var recordListBuilder = new RecordListBuilder(consensusTime); final var parentRecordBuilder = recordListBuilder.userTransactionRecordBuilder(); @@ -278,7 +278,7 @@ static Function provideHandleContextCreator( authorizer, solvencyPreCheck, childRecordFinalizer, - networkUtilizationManager); + synchronizedThrottleAccumulator); }; } @@ -293,13 +293,10 @@ static CongestionMultipliers createCongestionMultipliers(@NonNull ConfigProvider @Provides @Singleton - static NetworkUtilizationManager createNetworkUtilizationManager(@NonNull ConfigProvider configProvider) { - var backendThrottle = new ThrottleAccumulator(() -> 1, configProvider, BACKEND_THROTTLE); - final var genericFeeMultiplier = getThrottleMultiplier(configProvider, backendThrottle); - - final var congestionMultipliers = - getCongestionMultipliers(configProvider, genericFeeMultiplier, backendThrottle); - return new NetworkUtilizationManagerImpl(backendThrottle, congestionMultipliers); + static SynchronizedThrottleAccumulator createSynchronizedThrottleAccumulator( + @NonNull ConfigProvider configProvider) { + var frontendThrottle = new ThrottleAccumulator(() -> 1, configProvider, FRONTEND_THROTTLE); + return new SynchronizedThrottleAccumulator(frontendThrottle); } @NotNull diff --git a/hedera-node/hedera-token-service-impl/src/main/java/com/hedera/node/app/service/token/impl/handlers/transfer/TransferContextImpl.java b/hedera-node/hedera-token-service-impl/src/main/java/com/hedera/node/app/service/token/impl/handlers/transfer/TransferContextImpl.java index a5b1e568a76b..4246988424dc 100644 --- a/hedera-node/hedera-token-service-impl/src/main/java/com/hedera/node/app/service/token/impl/handlers/transfer/TransferContextImpl.java +++ b/hedera-node/hedera-token-service-impl/src/main/java/com/hedera/node/app/service/token/impl/handlers/transfer/TransferContextImpl.java @@ -17,10 +17,12 @@ package com.hedera.node.app.service.token.impl.handlers.transfer; import static com.hedera.hapi.node.base.HederaFunctionality.CRYPTO_CREATE; +import static com.hedera.hapi.node.base.HederaFunctionality.CRYPTO_TRANSFER; import static com.hedera.hapi.node.base.ResponseCodeEnum.INVALID_ALIAS_KEY; import static com.hedera.hapi.node.base.ResponseCodeEnum.NOT_SUPPORTED; import static com.hedera.node.app.service.mono.utils.EntityIdUtils.EVM_ADDRESS_SIZE; import static com.hedera.node.app.service.token.AliasUtils.isSerializedProtoKey; +import static com.hedera.node.app.spi.workflows.HandleContext.TransactionCategory.PRECEDING; import static com.hedera.node.app.spi.workflows.HandleException.validateTrue; import com.hedera.hapi.node.base.AccountID; @@ -98,8 +100,12 @@ public void createFromAlias(final Bytes alias, final int reqMaxAutoAssociations) try { createdAccount = autoAccountCreator.create(alias, reqMaxAutoAssociations); } catch (HandleException e) { - final int autoCreationsNumber = numOfAutoCreations() + numOfLazyCreations(); - context.reclaimPreviouslyReservedThrottle(autoCreationsNumber, CRYPTO_CREATE); + if (getHandleContext().getHederaFunctionality() == CRYPTO_TRANSFER + && getHandleContext().getTransactionCategory() == PRECEDING + && getHandleContext().isSelfSubmitted()) { + final int autoCreationsNumber = numOfAutoCreations() + numOfLazyCreations(); + getHandleContext().reclaimPreviouslyReservedThrottle(autoCreationsNumber, CRYPTO_CREATE); + } // we only want to reclaim the previously reserved throttle for `CRYPTO_CREATE` transaction // if there is a failed auto-creation triggered from CryptoTransfer // this is why we re-throw the HandleException, so that it will be still tackled the same in HandleWorkflow From 3cc2d18bdd0981fbb3c176bb1ed8b93625af5abb Mon Sep 17 00:00:00 2001 From: Petar Tonev Date: Thu, 18 Jan 2024 10:58:37 +0200 Subject: [PATCH 07/34] fix: simplify conditions on auto-account creation throttle reclaim --- .../node/app/spi/workflows/HandleContext.java | 14 -------------- .../app/workflows/handle/HandleContextImpl.java | 10 ---------- .../handlers/transfer/TransferContextImpl.java | 6 +----- 3 files changed, 1 insertion(+), 29 deletions(-) diff --git a/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/workflows/HandleContext.java b/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/workflows/HandleContext.java index b3f1cc255878..f1110117c8bf 100644 --- a/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/workflows/HandleContext.java +++ b/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/workflows/HandleContext.java @@ -677,20 +677,6 @@ default T dispatchRemovableChildTransaction( @NonNull RecordListCheckPoint createRecordListCheckPoint(); - /** - * Returns the current {@link HederaFunctionality} - * - * @return the Hedera functionality in the context - */ - HederaFunctionality getHederaFunctionality(); - - /** - * Returns the current {@link TransactionCategory} of the transaction - * - * @return the current transaction category - */ - TransactionCategory getTransactionCategory(); - /** * Returns whether the current transaction being processed was submitted by this node. * diff --git a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleContextImpl.java b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleContextImpl.java index ec6c60aa855c..4d5191aec046 100644 --- a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleContextImpl.java +++ b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleContextImpl.java @@ -896,16 +896,6 @@ public void reclaimPreviouslyReservedThrottle(int n, HederaFunctionality functio synchronizedThrottleAccumulator.leakUnusedThrottlePreviouslyReserved(n, function); } - @Override - public HederaFunctionality getHederaFunctionality() { - return functionality; - } - - @Override - public TransactionCategory getTransactionCategory() { - return category; - } - @Override public boolean isSelfSubmitted() { return Objects.equals( diff --git a/hedera-node/hedera-token-service-impl/src/main/java/com/hedera/node/app/service/token/impl/handlers/transfer/TransferContextImpl.java b/hedera-node/hedera-token-service-impl/src/main/java/com/hedera/node/app/service/token/impl/handlers/transfer/TransferContextImpl.java index 4246988424dc..ce8760bfee36 100644 --- a/hedera-node/hedera-token-service-impl/src/main/java/com/hedera/node/app/service/token/impl/handlers/transfer/TransferContextImpl.java +++ b/hedera-node/hedera-token-service-impl/src/main/java/com/hedera/node/app/service/token/impl/handlers/transfer/TransferContextImpl.java @@ -17,12 +17,10 @@ package com.hedera.node.app.service.token.impl.handlers.transfer; import static com.hedera.hapi.node.base.HederaFunctionality.CRYPTO_CREATE; -import static com.hedera.hapi.node.base.HederaFunctionality.CRYPTO_TRANSFER; import static com.hedera.hapi.node.base.ResponseCodeEnum.INVALID_ALIAS_KEY; import static com.hedera.hapi.node.base.ResponseCodeEnum.NOT_SUPPORTED; import static com.hedera.node.app.service.mono.utils.EntityIdUtils.EVM_ADDRESS_SIZE; import static com.hedera.node.app.service.token.AliasUtils.isSerializedProtoKey; -import static com.hedera.node.app.spi.workflows.HandleContext.TransactionCategory.PRECEDING; import static com.hedera.node.app.spi.workflows.HandleException.validateTrue; import com.hedera.hapi.node.base.AccountID; @@ -100,9 +98,7 @@ public void createFromAlias(final Bytes alias, final int reqMaxAutoAssociations) try { createdAccount = autoAccountCreator.create(alias, reqMaxAutoAssociations); } catch (HandleException e) { - if (getHandleContext().getHederaFunctionality() == CRYPTO_TRANSFER - && getHandleContext().getTransactionCategory() == PRECEDING - && getHandleContext().isSelfSubmitted()) { + if (getHandleContext().isSelfSubmitted()) { final int autoCreationsNumber = numOfAutoCreations() + numOfLazyCreations(); getHandleContext().reclaimPreviouslyReservedThrottle(autoCreationsNumber, CRYPTO_CREATE); } From 733e56590ccca3bd2cd1ae23cf38dfa1fded990f Mon Sep 17 00:00:00 2001 From: Petar Tonev Date: Fri, 19 Jan 2024 12:06:53 +0200 Subject: [PATCH 08/34] fix: implement capacity check if should throttle auto-creations --- .../node/app/spi/workflows/Context.java | 23 +++++++++++++++++++ .../node/app/spi/workflows/HandleContext.java | 14 ++++++++++- .../node/app/spi/workflows/QueryContext.java | 5 +++- .../SynchronizedThrottleAccumulator.java | 5 ++++ .../workflows/handle/HandleContextImpl.java | 7 +++++- .../app/workflows/query/QueryContextImpl.java | 19 +++++++++++++++ .../workflows/query/QueryWorkflowImpl.java | 4 ++++ .../java/common/BaseScaffoldingModule.java | 6 ++++- .../impl/exec/ContextQueryProcessor.java | 1 + .../exec/ContextTransactionProcessor.java | 1 + .../impl/hevm/HederaWorldUpdater.java | 6 +++++ .../impl/state/ProxyWorldUpdater.java | 23 +++++++++++++++++++ .../impl/state/RootProxyWorldUpdater.java | 9 ++++++++ .../test/state/RootProxyWorldUpdaterTest.java | 4 ++++ 14 files changed, 123 insertions(+), 4 deletions(-) create mode 100644 hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/workflows/Context.java diff --git a/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/workflows/Context.java b/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/workflows/Context.java new file mode 100644 index 000000000000..b8185dc31532 --- /dev/null +++ b/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/workflows/Context.java @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2024 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.spi.workflows; + +import com.hedera.hapi.node.base.HederaFunctionality; + +public interface Context { + boolean shouldThrottleNOfUnscaled(int n, HederaFunctionality function); +} diff --git a/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/workflows/HandleContext.java b/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/workflows/HandleContext.java index f1110117c8bf..5d98ab136bd5 100644 --- a/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/workflows/HandleContext.java +++ b/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/workflows/HandleContext.java @@ -60,7 +60,7 @@ * */ @SuppressWarnings("UnusedReturnValue") -public interface HandleContext { +public interface HandleContext extends Context { /** * Category of the current transaction. */ @@ -668,6 +668,18 @@ default T dispatchRemovableChildTransaction( */ void reclaimPreviouslyReservedThrottle(int n, HederaFunctionality function); + /** + * Verifies if the frontend throttle has enough capacity to handle the given number of the + * given function at the given time. (The time matters because we want to consider how much + * will have leaked between now and that time.) + * + * @param n the number of the given function + * @param function the function + * @return true if the system should throttle the given number of the given function + * at the instant for which throttling should be calculated + */ + boolean shouldThrottleNOfUnscaled(int n, HederaFunctionality function); + /** * Create a checkpoint for the current childRecords. * diff --git a/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/workflows/QueryContext.java b/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/workflows/QueryContext.java index fad6562054de..63750fb8d01e 100644 --- a/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/workflows/QueryContext.java +++ b/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/workflows/QueryContext.java @@ -17,6 +17,7 @@ package com.hedera.node.app.spi.workflows; import com.hedera.hapi.node.base.AccountID; +import com.hedera.hapi.node.base.HederaFunctionality; import com.hedera.hapi.node.transaction.Query; import com.hedera.node.app.spi.fees.ExchangeRateInfo; import com.hedera.node.app.spi.fees.FeeCalculator; @@ -29,7 +30,7 @@ /** * Context of a single query. Contains all query specific information. */ -public interface QueryContext { +public interface QueryContext extends Context { /** * Returns the {@link Query} that is currently being processed. @@ -88,4 +89,6 @@ public interface QueryContext { */ @NonNull FeeCalculator feeCalculator(); + + boolean shouldThrottleNOfUnscaled(int n, HederaFunctionality function); } diff --git a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/SynchronizedThrottleAccumulator.java b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/SynchronizedThrottleAccumulator.java index efe77035164b..bce71e0e7366 100644 --- a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/SynchronizedThrottleAccumulator.java +++ b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/SynchronizedThrottleAccumulator.java @@ -79,4 +79,9 @@ private void setDecisionTime() { public void leakUnusedThrottlePreviouslyReserved(int n, HederaFunctionality function) { frontendThrottle.leakCapacityForNOfUnscaled(n, function); } + + public boolean shouldThrottleNOfUnscaled( + final int n, @NonNull final HederaFunctionality function, @NonNull final Instant consensusTime) { + return frontendThrottle.shouldThrottleNOfUnscaled(n, function, consensusTime); + } } diff --git a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleContextImpl.java b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleContextImpl.java index 4d5191aec046..e2b8761113c7 100644 --- a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleContextImpl.java +++ b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleContextImpl.java @@ -164,7 +164,7 @@ public class HandleContextImpl implements HandleContext, FeeContext { * @param authorizer The {@link Authorizer} used to authorize the transaction * @param solvencyPreCheck The {@link SolvencyPreCheck} used to validate if the account is able to pay the fees * @param childRecordFinalizer The {@link ChildRecordFinalizer} used to finalize child records - * @param synchronizedThrottleAccumulator The {@link SynchronizedThrottleAccumulator} used to manage tracking of network utilization + * @param synchronizedThrottleAccumulator The {@link SynchronizedThrottleAccumulator} used to manage the tracking of network throttling */ public HandleContextImpl( @NonNull final TransactionBody txBody, @@ -896,6 +896,11 @@ public void reclaimPreviouslyReservedThrottle(int n, HederaFunctionality functio synchronizedThrottleAccumulator.leakUnusedThrottlePreviouslyReserved(n, function); } + @Override + public boolean shouldThrottleNOfUnscaled(int n, HederaFunctionality function) { + return synchronizedThrottleAccumulator.shouldThrottleNOfUnscaled(n, function, userTransactionConsensusTime); + } + @Override public boolean isSelfSubmitted() { return Objects.equals( diff --git a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/query/QueryContextImpl.java b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/query/QueryContextImpl.java index c34f39a8f098..3ed61ca1f973 100644 --- a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/query/QueryContextImpl.java +++ b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/query/QueryContextImpl.java @@ -19,6 +19,7 @@ import static java.util.Objects.requireNonNull; import com.hedera.hapi.node.base.AccountID; +import com.hedera.hapi.node.base.HederaFunctionality; import com.hedera.hapi.node.state.blockrecords.BlockInfo; import com.hedera.hapi.node.state.blockrecords.RunningHashes; import com.hedera.hapi.node.transaction.Query; @@ -31,10 +32,12 @@ import com.hedera.node.app.spi.records.RecordCache; import com.hedera.node.app.spi.workflows.QueryContext; import com.hedera.node.app.state.HederaState; +import com.hedera.node.app.throttle.SynchronizedThrottleAccumulator; import com.hedera.node.app.workflows.dispatcher.ReadableStoreFactory; import com.swirlds.config.api.Configuration; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; +import java.time.Instant; /** * Simple implementation of {@link QueryContext}. @@ -49,6 +52,8 @@ public class QueryContextImpl implements QueryContext { private final ExchangeRateManager exchangeRateManager; private final AccountID payer; private final FeeCalculator feeCalculator; + private final Instant userQueryConsensusTime; + private final SynchronizedThrottleAccumulator synchronizedThrottleAccumulator; private BlockRecordInfo blockRecordInfo; // lazily created private ExchangeRateInfo exchangeRateInfo; // lazily created @@ -62,6 +67,8 @@ public class QueryContextImpl implements QueryContext { * @param recordCache the {@link RecordCache} used to cache records * @param exchangeRateManager the {@link ExchangeRateManager} used to get the current exchange rate * @param feeCalculator the {@link FeeCalculator} used to calculate fees + * @param userQueryConsensusTime the query time + * @param synchronizedThrottleAccumulator The {@link SynchronizedThrottleAccumulator} used to manage the tracking of network throttling * @param payer the {@link AccountID} of the payer, if present * @throws NullPointerException if {@code query} is {@code null} */ @@ -73,6 +80,8 @@ public QueryContextImpl( @NonNull final RecordCache recordCache, @NonNull final ExchangeRateManager exchangeRateManager, @NonNull final FeeCalculator feeCalculator, + @NonNull final Instant userQueryConsensusTime, + @NonNull final SynchronizedThrottleAccumulator synchronizedThrottleAccumulator, @Nullable final AccountID payer) { this.state = requireNonNull(state, "state must not be null"); this.storeFactory = requireNonNull(storeFactory, "storeFactory must not be null"); @@ -81,6 +90,11 @@ public QueryContextImpl( this.recordCache = requireNonNull(recordCache, "recordCache must not be null"); this.exchangeRateManager = requireNonNull(exchangeRateManager, "exchangeRateManager must not be null"); this.feeCalculator = requireNonNull(feeCalculator, "feeCalculator must not be null"); + this.userQueryConsensusTime = requireNonNull(userQueryConsensusTime, "userQueryConsensusTime must not be null"); + ; + this.synchronizedThrottleAccumulator = + requireNonNull(synchronizedThrottleAccumulator, "synchronizedThrottleAccumulator must not be null"); + ; this.payer = payer; } @@ -144,4 +158,9 @@ public ExchangeRateInfo exchangeRateInfo() { public FeeCalculator feeCalculator() { return feeCalculator; } + + @Override + public boolean shouldThrottleNOfUnscaled(int n, HederaFunctionality function) { + return synchronizedThrottleAccumulator.shouldThrottleNOfUnscaled(n, function, userQueryConsensusTime); + } } diff --git a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/query/QueryWorkflowImpl.java b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/query/QueryWorkflowImpl.java index 5672c9e657ab..a2d206f7eff8 100644 --- a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/query/QueryWorkflowImpl.java +++ b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/query/QueryWorkflowImpl.java @@ -207,6 +207,8 @@ public void handleQuery(@NonNull final Bytes requestBuffer, @NonNull final Buffe recordCache, exchangeRateManager, feeCalculator, + consensusTime, + synchronizedThrottleAccumulator, payerID); // A super-user does not have to pay for a query and has all permissions @@ -250,6 +252,8 @@ public void handleQuery(@NonNull final Bytes requestBuffer, @NonNull final Buffe recordCache, exchangeRateManager, feeCalculator, + consensusTime, + synchronizedThrottleAccumulator, null); } diff --git a/hedera-node/hedera-app/src/xtest/java/common/BaseScaffoldingModule.java b/hedera-node/hedera-app/src/xtest/java/common/BaseScaffoldingModule.java index 979feaf3578f..995c44535baa 100644 --- a/hedera-node/hedera-app/src/xtest/java/common/BaseScaffoldingModule.java +++ b/hedera-node/hedera-app/src/xtest/java/common/BaseScaffoldingModule.java @@ -211,7 +211,9 @@ static BiFunction provideQueryContextFactory( @NonNull final HederaState state, @NonNull final RecordCache recordCache, @NonNull final Configuration configuration, - @NonNull final ExchangeRateManager exchangeRateManager) { + @NonNull final ExchangeRateManager exchangeRateManager, + @NonNull final SynchronizedThrottleAccumulator synchronizedThrottleAccumulator) { + final var consensusTime = Instant.now(); return (query, payerId) -> new QueryContextImpl( state, new ReadableStoreFactory(state), @@ -220,6 +222,8 @@ static BiFunction provideQueryContextFactory( recordCache, exchangeRateManager, NoOpFeeCalculator.INSTANCE, + consensusTime, + synchronizedThrottleAccumulator, payerId); } diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/ContextQueryProcessor.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/ContextQueryProcessor.java index 9abe841fa725..ae031172de5f 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/ContextQueryProcessor.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/ContextQueryProcessor.java @@ -68,6 +68,7 @@ public ContextQueryProcessor( this.worldUpdater = Objects.requireNonNull(worldUpdater); this.hederaEvmContext = Objects.requireNonNull(hederaEvmContext); this.hevmStaticTransactionFactory = Objects.requireNonNull(hevmStaticTransactionFactory); + this.worldUpdater.setupContext(context); } @Override diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/ContextTransactionProcessor.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/ContextTransactionProcessor.java index 28eb95b071e2..a2dd22d9b426 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/ContextTransactionProcessor.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/ContextTransactionProcessor.java @@ -87,6 +87,7 @@ public ContextTransactionProcessor( this.contractsConfig = Objects.requireNonNull(contractsConfig); this.hederaEvmContext = Objects.requireNonNull(hederaEvmContext); this.hevmTransactionFactory = Objects.requireNonNull(hevmTransactionFactory); + this.rootProxyWorldUpdater.setupContext(context); } @Override diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/hevm/HederaWorldUpdater.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/hevm/HederaWorldUpdater.java index 86952eba6686..4647ef5877bc 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/hevm/HederaWorldUpdater.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/hevm/HederaWorldUpdater.java @@ -31,6 +31,7 @@ import com.hedera.node.app.service.contract.impl.state.PendingCreation; import com.hedera.node.app.service.contract.impl.state.ProxyWorldUpdater; import com.hedera.node.app.service.contract.impl.state.StorageAccesses; +import com.hedera.node.app.spi.workflows.Context; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; import java.util.List; @@ -273,6 +274,11 @@ Optional tryTrackingSelfDestructBeneficiary( @NonNull List pendingStorageUpdates(); + void setupContext(@NonNull Context context); + + @NonNull + Optional context(); + /** * Externalizes the results of a system contract call into a record * @param result The result of the system contract call diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/state/ProxyWorldUpdater.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/state/ProxyWorldUpdater.java index fc8f83880a5b..f984b889d5fb 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/state/ProxyWorldUpdater.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/state/ProxyWorldUpdater.java @@ -37,6 +37,7 @@ import com.hedera.hapi.node.transaction.ExchangeRate; import com.hedera.node.app.service.contract.impl.exec.scope.HandleHederaOperations; import com.hedera.node.app.service.contract.impl.hevm.HederaWorldUpdater; +import com.hedera.node.app.spi.workflows.Context; import com.hedera.node.app.spi.workflows.ResourceExhaustedException; import com.hedera.node.app.spi.workflows.record.RecordListCheckPoint; import edu.umd.cs.findbugs.annotations.NonNull; @@ -80,6 +81,12 @@ public class ProxyWorldUpdater implements HederaWorldUpdater { @Nullable private final WorldUpdater parent; + /** + * Context + */ + @Nullable + private Context context; + /** * The current checkpoint of the child records for this ProxyWorldUpdater. */ @@ -445,6 +452,22 @@ public void commit() { } } + /** + * {@inheritDoc} + */ + @Override + public void setupContext(@NonNull final Context context) { + this.context = context; + } + + /** + * {@inheritDoc} + */ + @Override + public @NonNull Optional context() { + return Optional.ofNullable(context); + } + /** * {@inheritDoc} */ diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/state/RootProxyWorldUpdater.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/state/RootProxyWorldUpdater.java index 4cfa72513ffc..585681727b81 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/state/RootProxyWorldUpdater.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/state/RootProxyWorldUpdater.java @@ -16,6 +16,10 @@ package com.hedera.node.app.service.contract.impl.state; +import static com.hedera.hapi.node.base.HederaFunctionality.CRYPTO_CREATE; +import static com.hedera.hapi.node.base.ResponseCodeEnum.CONSENSUS_GAS_EXHAUSTED; +import static com.hedera.node.app.spi.workflows.HandleException.validateTrue; + import com.hedera.hapi.node.base.ContractID; import com.hedera.hapi.node.contract.ContractNonceInfo; import com.hedera.node.app.service.contract.impl.annotations.TransactionScope; @@ -96,6 +100,11 @@ public void commit() { final var contractChangeSummary = enhancement.operations().summarizeContractChanges(); createdContractIds = contractChangeSummary.newContractIds(); + context().ifPresent(context -> { + final var creationCapacity = context.shouldThrottleNOfUnscaled(createdContractIds.size(), CRYPTO_CREATE); + validateTrue(creationCapacity, CONSENSUS_GAS_EXHAUSTED); + }); + // If nonces externalization is enabled, we need to capture the updated nonces if (contractsConfig.noncesExternalizationEnabled()) { updatedContractNonces = contractChangeSummary.updatedContractNonces(); diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/state/RootProxyWorldUpdaterTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/state/RootProxyWorldUpdaterTest.java index 8fc29778be0b..72a445e8617d 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/state/RootProxyWorldUpdaterTest.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/state/RootProxyWorldUpdaterTest.java @@ -38,6 +38,7 @@ import com.hedera.node.app.service.contract.impl.state.StorageAccesses; import com.hedera.node.app.service.contract.impl.state.StorageSizeChange; import com.hedera.node.app.service.token.api.ContractChangeSummary; +import com.hedera.node.app.spi.workflows.Context; import com.hedera.node.config.data.ContractsConfig; import com.hedera.node.config.testfixtures.HederaTestConfigBuilder; import com.swirlds.config.api.Configuration; @@ -90,6 +91,9 @@ class RootProxyWorldUpdaterTest { @Mock private ContractStateStore store; + @Mock + private Context context; + private Enhancement enhancement; private RootProxyWorldUpdater subject; From 0378cad32decd80575164e79028e6cac434f7d58 Mon Sep 17 00:00:00 2001 From: Petar Tonev Date: Fri, 19 Jan 2024 17:39:39 +0200 Subject: [PATCH 09/34] fix: implement capacity check if should throttle child records --- .../node/app/spi/workflows/Context.java | 18 ++++++++ .../node/app/spi/workflows/HandleContext.java | 12 ------ .../node/app/spi/workflows/QueryContext.java | 3 -- .../throttle/NetworkUtilizationManager.java | 10 +++++ .../impl/NetworkUtilizationManagerImpl.java | 5 +++ .../workflows/handle/HandleContextImpl.java | 42 ++++++++++++++++++- .../app/workflows/handle/HandleWorkflow.java | 1 + .../app/workflows/query/QueryContextImpl.java | 5 +++ .../handle/HandleContextImplTest.java | 8 ++++ .../java/common/BaseScaffoldingModule.java | 15 +++++++ .../impl/state/RootProxyWorldUpdater.java | 10 ++++- 11 files changed, 111 insertions(+), 18 deletions(-) diff --git a/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/workflows/Context.java b/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/workflows/Context.java index b8185dc31532..1668649b6af0 100644 --- a/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/workflows/Context.java +++ b/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/workflows/Context.java @@ -19,5 +19,23 @@ import com.hedera.hapi.node.base.HederaFunctionality; public interface Context { + /** + * Verifies if the frontend throttle has enough capacity to handle the given number of the + * given function at the given time. (The time matters because we want to consider how much + * will have leaked between now and that time.) + * + * @param n the number of the given function + * @param function the function + * @return true if the system should throttle the given number of the given function + * at the instant for which throttling should be calculated + */ boolean shouldThrottleNOfUnscaled(int n, HederaFunctionality function); + + /** + * For each following child transaction consumes the capacity + * required for that child transaction in the consensus throttle buckets. + * + * @return true if all the child transactions were allowed through the throttle consideration, false otherwise. + */ + boolean hasThrottleCapacityForChildTransactions(); } diff --git a/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/workflows/HandleContext.java b/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/workflows/HandleContext.java index 5d98ab136bd5..5404c2f8caa5 100644 --- a/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/workflows/HandleContext.java +++ b/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/workflows/HandleContext.java @@ -668,18 +668,6 @@ default T dispatchRemovableChildTransaction( */ void reclaimPreviouslyReservedThrottle(int n, HederaFunctionality function); - /** - * Verifies if the frontend throttle has enough capacity to handle the given number of the - * given function at the given time. (The time matters because we want to consider how much - * will have leaked between now and that time.) - * - * @param n the number of the given function - * @param function the function - * @return true if the system should throttle the given number of the given function - * at the instant for which throttling should be calculated - */ - boolean shouldThrottleNOfUnscaled(int n, HederaFunctionality function); - /** * Create a checkpoint for the current childRecords. * diff --git a/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/workflows/QueryContext.java b/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/workflows/QueryContext.java index 63750fb8d01e..c628ba038eac 100644 --- a/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/workflows/QueryContext.java +++ b/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/workflows/QueryContext.java @@ -17,7 +17,6 @@ package com.hedera.node.app.spi.workflows; import com.hedera.hapi.node.base.AccountID; -import com.hedera.hapi.node.base.HederaFunctionality; import com.hedera.hapi.node.transaction.Query; import com.hedera.node.app.spi.fees.ExchangeRateInfo; import com.hedera.node.app.spi.fees.FeeCalculator; @@ -89,6 +88,4 @@ public interface QueryContext extends Context { */ @NonNull FeeCalculator feeCalculator(); - - boolean shouldThrottleNOfUnscaled(int n, HederaFunctionality function); } diff --git a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/NetworkUtilizationManager.java b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/NetworkUtilizationManager.java index 3fa444516686..5d6e33498da5 100644 --- a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/NetworkUtilizationManager.java +++ b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/NetworkUtilizationManager.java @@ -78,4 +78,14 @@ void trackFeePayments( * @param state the state of the node */ void saveTo(@NonNull final HederaState state); + + /* + * Updates the throttle requirements for the given transaction and returns whether the transaction + * should be throttled for the current time(Instant.now). + * + * @param txnInfo the transaction to update the throttle requirements for + * @param state the current state of the node + * @return whether the transaction should be throttled + */ + boolean shouldThrottle(@NonNull TransactionInfo txnInfo, HederaState state); } diff --git a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/impl/NetworkUtilizationManagerImpl.java b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/impl/NetworkUtilizationManagerImpl.java index 36610c63031d..c0c5f36ddf2f 100644 --- a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/impl/NetworkUtilizationManagerImpl.java +++ b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/impl/NetworkUtilizationManagerImpl.java @@ -201,4 +201,9 @@ public boolean wasLastTxnGasThrottled() { public void leakUnusedGasPreviouslyReserved(@NonNull final TransactionInfo txnInfo, long value) { backendThrottle.leakUnusedGasPreviouslyReserved(txnInfo, value); } + + public boolean shouldThrottle(@NonNull TransactionInfo txnInfo, HederaState state) { + final var now = Instant.now(); + return backendThrottle.shouldThrottle(txnInfo, now, state); + } } diff --git a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleContextImpl.java b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleContextImpl.java index e2b8761113c7..d6d9ce38dab7 100644 --- a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleContextImpl.java +++ b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleContextImpl.java @@ -16,8 +16,11 @@ package com.hedera.node.app.workflows.handle; +import static com.hedera.hapi.node.base.HederaFunctionality.CONTRACT_CALL; +import static com.hedera.hapi.node.base.HederaFunctionality.CONTRACT_CREATE; import static com.hedera.hapi.node.base.ResponseCodeEnum.DUPLICATE_TRANSACTION; import static com.hedera.hapi.node.base.ResponseCodeEnum.INVALID_SIGNATURE; +import static com.hedera.hapi.node.base.ResponseCodeEnum.SUCCESS; import static com.hedera.node.app.spi.HapiUtils.functionOf; import static com.hedera.node.app.spi.workflows.HandleContext.TransactionCategory.CHILD; import static com.hedera.node.app.spi.workflows.HandleContext.TransactionCategory.PRECEDING; @@ -75,9 +78,11 @@ import com.hedera.node.app.spi.workflows.record.SingleTransactionRecordBuilder; import com.hedera.node.app.state.HederaRecordCache; import com.hedera.node.app.state.WrappedHederaState; +import com.hedera.node.app.throttle.NetworkUtilizationManager; import com.hedera.node.app.throttle.SynchronizedThrottleAccumulator; import com.hedera.node.app.workflows.SolvencyPreCheck; import com.hedera.node.app.workflows.TransactionChecker; +import com.hedera.node.app.workflows.TransactionInfo; import com.hedera.node.app.workflows.dispatcher.ReadableStoreFactory; import com.hedera.node.app.workflows.dispatcher.ServiceApiFactory; import com.hedera.node.app.workflows.dispatcher.TransactionDispatcher; @@ -133,6 +138,7 @@ public class HandleContextImpl implements HandleContext, FeeContext { private final Authorizer authorizer; private final SolvencyPreCheck solvencyPreCheck; private final ChildRecordFinalizer childRecordFinalizer; + private final NetworkUtilizationManager networkUtilizationManager; private final SynchronizedThrottleAccumulator synchronizedThrottleAccumulator; private ReadableStoreFactory readableStoreFactory; @@ -164,7 +170,8 @@ public class HandleContextImpl implements HandleContext, FeeContext { * @param authorizer The {@link Authorizer} used to authorize the transaction * @param solvencyPreCheck The {@link SolvencyPreCheck} used to validate if the account is able to pay the fees * @param childRecordFinalizer The {@link ChildRecordFinalizer} used to finalize child records - * @param synchronizedThrottleAccumulator The {@link SynchronizedThrottleAccumulator} used to manage the tracking of network throttling + * @param networkUtilizationManager The {@link NetworkUtilizationManager} used to manage the tracking of backend network throttling + * @param synchronizedThrottleAccumulator The {@link SynchronizedThrottleAccumulator} used to manage the tracking of frontend network throttling */ public HandleContextImpl( @NonNull final TransactionBody txBody, @@ -190,6 +197,7 @@ public HandleContextImpl( @NonNull final Authorizer authorizer, @NonNull final SolvencyPreCheck solvencyPreCheck, @NonNull final ChildRecordFinalizer childRecordFinalizer, + @NonNull final NetworkUtilizationManager networkUtilizationManager, @NonNull final SynchronizedThrottleAccumulator synchronizedThrottleAccumulator) { this.txBody = requireNonNull(txBody, "txBody must not be null"); this.functionality = requireNonNull(functionality, "functionality must not be null"); @@ -212,6 +220,8 @@ public HandleContextImpl( requireNonNull(userTransactionConsensusTime, "userTransactionConsensusTime must not be null"); this.authorizer = requireNonNull(authorizer, "authorizer must not be null"); this.childRecordFinalizer = requireNonNull(childRecordFinalizer, "childRecordFinalizer must not be null"); + this.networkUtilizationManager = + requireNonNull(networkUtilizationManager, "networkUtilization must not be null"); this.synchronizedThrottleAccumulator = requireNonNull(synchronizedThrottleAccumulator, "synchronizedThrottleAccumulator must not be null"); @@ -698,6 +708,7 @@ private void dispatchSyntheticTxn( authorizer, solvencyPreCheck, childRecordFinalizer, + networkUtilizationManager, synchronizedThrottleAccumulator); if (dispatchValidationResult != null) { @@ -901,6 +912,35 @@ public boolean shouldThrottleNOfUnscaled(int n, HederaFunctionality function) { return synchronizedThrottleAccumulator.shouldThrottleNOfUnscaled(n, function, userTransactionConsensusTime); } + public boolean shouldThrottleTxn(TransactionInfo txInfo) { + return networkUtilizationManager.shouldThrottle(txInfo, current()); + } + + @Override + public boolean hasThrottleCapacityForChildTransactions() { + var isAllowed = true; + final var childRecords = recordListBuilder.childRecordBuilders(); + + for (int i = 0, n = childRecords.size(); i < n && isAllowed; i++) { + final var childRecord = childRecords.get(i); + if (Objects.equals(childRecord.status(), SUCCESS)) { + final var tx = childRecord.build().transaction(); + final var txInfo = new TransactionInfo( + tx, childRecord.transactionBody(), tx.sigMap(), tx.signedTransactionBytes(), functionality); + + if (txInfo.functionality() == CONTRACT_CREATE || txInfo.functionality() == CONTRACT_CALL) { + continue; + } + + if (shouldThrottleTxn(txInfo)) { + isAllowed = false; + } + } + } + + return isAllowed; + } + @Override public boolean isSelfSubmitted() { return Objects.equals( diff --git a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleWorkflow.java b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleWorkflow.java index 2e8c4017f812..9ebb8b2ea26c 100644 --- a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleWorkflow.java +++ b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleWorkflow.java @@ -396,6 +396,7 @@ private void handleUserTransaction( authorizer, solvencyPreCheck, childRecordFinalizer, + networkUtilizationManager, synchronizedThrottleAccumulator); // Calculate the fee diff --git a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/query/QueryContextImpl.java b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/query/QueryContextImpl.java index 3ed61ca1f973..ab29e9bedb1d 100644 --- a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/query/QueryContextImpl.java +++ b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/query/QueryContextImpl.java @@ -163,4 +163,9 @@ public FeeCalculator feeCalculator() { public boolean shouldThrottleNOfUnscaled(int n, HederaFunctionality function) { return synchronizedThrottleAccumulator.shouldThrottleNOfUnscaled(n, function, userQueryConsensusTime); } + + @Override + public boolean hasThrottleCapacityForChildTransactions() { + return true; + } } diff --git a/hedera-node/hedera-app/src/test/java/com/hedera/node/app/workflows/handle/HandleContextImplTest.java b/hedera-node/hedera-app/src/test/java/com/hedera/node/app/workflows/handle/HandleContextImplTest.java index 4f958f480cda..fcf40caefd99 100644 --- a/hedera-node/hedera-app/src/test/java/com/hedera/node/app/workflows/handle/HandleContextImplTest.java +++ b/hedera-node/hedera-app/src/test/java/com/hedera/node/app/workflows/handle/HandleContextImplTest.java @@ -89,6 +89,7 @@ import com.hedera.node.app.spi.workflows.record.SingleTransactionRecordBuilder; import com.hedera.node.app.state.HederaRecordCache; import com.hedera.node.app.state.HederaState; +import com.hedera.node.app.throttle.NetworkUtilizationManager; import com.hedera.node.app.throttle.SynchronizedThrottleAccumulator; import com.hedera.node.app.workflows.SolvencyPreCheck; import com.hedera.node.app.workflows.TransactionChecker; @@ -182,6 +183,9 @@ class HandleContextImplTest extends StateTestBase implements Scenarios { @Mock private SynchronizedThrottleAccumulator synchronizedThrottleAccumulator; + @Mock + private NetworkUtilizationManager networkUtilizationManager; + @Mock private SelfNodeInfo selfNodeInfo; @@ -235,6 +239,7 @@ private HandleContextImpl createContext(final TransactionBody txBody) { authorizer, solvencyPreCheck, childRecordFinalizer, + networkUtilizationManager, synchronizedThrottleAccumulator); } @@ -265,6 +270,7 @@ void testConstructorWithInvalidArguments() { authorizer, solvencyPreCheck, childRecordFinalizer, + networkUtilizationManager, synchronizedThrottleAccumulator }; @@ -394,6 +400,7 @@ void setUp() { authorizer, solvencyPreCheck, childRecordFinalizer, + networkUtilizationManager, synchronizedThrottleAccumulator); } @@ -926,6 +933,7 @@ private HandleContextImpl createContext(final TransactionBody txBody, final Tran authorizer, solvencyPreCheck, childRecordFinalizer, + networkUtilizationManager, synchronizedThrottleAccumulator); } diff --git a/hedera-node/hedera-app/src/xtest/java/common/BaseScaffoldingModule.java b/hedera-node/hedera-app/src/xtest/java/common/BaseScaffoldingModule.java index 995c44535baa..fc0dbb8a665b 100644 --- a/hedera-node/hedera-app/src/xtest/java/common/BaseScaffoldingModule.java +++ b/hedera-node/hedera-app/src/xtest/java/common/BaseScaffoldingModule.java @@ -67,8 +67,10 @@ import com.hedera.node.app.state.HederaState; import com.hedera.node.app.state.recordcache.DeduplicationCacheImpl; import com.hedera.node.app.state.recordcache.RecordCacheImpl; +import com.hedera.node.app.throttle.NetworkUtilizationManager; import com.hedera.node.app.throttle.SynchronizedThrottleAccumulator; import com.hedera.node.app.throttle.ThrottleAccumulator; +import com.hedera.node.app.throttle.impl.NetworkUtilizationManagerImpl; import com.hedera.node.app.validation.ExpiryValidation; import com.hedera.node.app.workflows.SolvencyPreCheck; import com.hedera.node.app.workflows.TransactionChecker; @@ -243,6 +245,7 @@ static Function provideHandleContextCreator( @NonNull final FeeManager feeManager, @NonNull final Authorizer authorizer, @NonNull final ChildRecordFinalizer childRecordFinalizer, + @NonNull final NetworkUtilizationManager networkUtilizationManager, @NonNull final SynchronizedThrottleAccumulator synchronizedThrottleAccumulator) { final var consensusTime = Instant.now(); final var recordListBuilder = new RecordListBuilder(consensusTime); @@ -282,6 +285,7 @@ static Function provideHandleContextCreator( authorizer, solvencyPreCheck, childRecordFinalizer, + networkUtilizationManager, synchronizedThrottleAccumulator); }; } @@ -344,4 +348,15 @@ private static CongestionMultipliers getCongestionMultipliers( return new CongestionMultipliers(txnRateMultiplier, gasFeeMultiplier); } + + @Provides + @Singleton + static NetworkUtilizationManager createNetworkUtilizationManager(@NonNull ConfigProvider configProvider) { + var backendThrottle = new ThrottleAccumulator(() -> 1, configProvider, BACKEND_THROTTLE); + final var genericFeeMultiplier = getThrottleMultiplier(configProvider, backendThrottle); + + final var congestionMultipliers = + getCongestionMultipliers(configProvider, genericFeeMultiplier, backendThrottle); + return new NetworkUtilizationManagerImpl(backendThrottle, congestionMultipliers); + } } diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/state/RootProxyWorldUpdater.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/state/RootProxyWorldUpdater.java index 585681727b81..cdf792dd88af 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/state/RootProxyWorldUpdater.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/state/RootProxyWorldUpdater.java @@ -101,8 +101,14 @@ public void commit() { createdContractIds = contractChangeSummary.newContractIds(); context().ifPresent(context -> { - final var creationCapacity = context.shouldThrottleNOfUnscaled(createdContractIds.size(), CRYPTO_CREATE); - validateTrue(creationCapacity, CONSENSUS_GAS_EXHAUSTED); + final var creationCapacityIsAvailable = + context.shouldThrottleNOfUnscaled(createdContractIds.size(), CRYPTO_CREATE); + validateTrue(creationCapacityIsAvailable, CONSENSUS_GAS_EXHAUSTED); + }); + + context().ifPresent(context -> { + final var childThrottleIsAvailable = context.hasThrottleCapacityForChildTransactions(); + validateTrue(childThrottleIsAvailable, CONSENSUS_GAS_EXHAUSTED); }); // If nonces externalization is enabled, we need to capture the updated nonces From 41a0c8fece8ef36e1daa15d13578282c1135b76e Mon Sep 17 00:00:00 2001 From: Petar Tonev Date: Fri, 19 Jan 2024 22:42:44 +0200 Subject: [PATCH 10/34] chore: rename to OperationContext and clarify description --- .../com/hedera/node/app/spi/workflows/HandleContext.java | 2 +- .../spi/workflows/{Context.java => OperationContext.java} | 4 ++-- .../com/hedera/node/app/spi/workflows/QueryContext.java | 2 +- .../service/contract/impl/hevm/HederaWorldUpdater.java | 6 +++--- .../service/contract/impl/state/ProxyWorldUpdater.java | 8 ++++---- .../impl/test/state/RootProxyWorldUpdaterTest.java | 4 ---- 6 files changed, 11 insertions(+), 15 deletions(-) rename hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/workflows/{Context.java => OperationContext.java} (91%) diff --git a/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/workflows/HandleContext.java b/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/workflows/HandleContext.java index 5404c2f8caa5..c73314276758 100644 --- a/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/workflows/HandleContext.java +++ b/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/workflows/HandleContext.java @@ -60,7 +60,7 @@ * */ @SuppressWarnings("UnusedReturnValue") -public interface HandleContext extends Context { +public interface HandleContext extends OperationContext { /** * Category of the current transaction. */ diff --git a/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/workflows/Context.java b/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/workflows/OperationContext.java similarity index 91% rename from hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/workflows/Context.java rename to hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/workflows/OperationContext.java index 1668649b6af0..af33ec719d8d 100644 --- a/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/workflows/Context.java +++ b/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/workflows/OperationContext.java @@ -18,9 +18,9 @@ import com.hedera.hapi.node.base.HederaFunctionality; -public interface Context { +public interface OperationContext { /** - * Verifies if the frontend throttle has enough capacity to handle the given number of the + * Verifies if the throttle in this operation context has enough capacity to handle the given number of the * given function at the given time. (The time matters because we want to consider how much * will have leaked between now and that time.) * diff --git a/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/workflows/QueryContext.java b/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/workflows/QueryContext.java index c628ba038eac..c499b1755b9a 100644 --- a/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/workflows/QueryContext.java +++ b/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/workflows/QueryContext.java @@ -29,7 +29,7 @@ /** * Context of a single query. Contains all query specific information. */ -public interface QueryContext extends Context { +public interface QueryContext extends OperationContext { /** * Returns the {@link Query} that is currently being processed. diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/hevm/HederaWorldUpdater.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/hevm/HederaWorldUpdater.java index 4647ef5877bc..3ac0866bd357 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/hevm/HederaWorldUpdater.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/hevm/HederaWorldUpdater.java @@ -31,7 +31,7 @@ import com.hedera.node.app.service.contract.impl.state.PendingCreation; import com.hedera.node.app.service.contract.impl.state.ProxyWorldUpdater; import com.hedera.node.app.service.contract.impl.state.StorageAccesses; -import com.hedera.node.app.spi.workflows.Context; +import com.hedera.node.app.spi.workflows.OperationContext; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; import java.util.List; @@ -274,10 +274,10 @@ Optional tryTrackingSelfDestructBeneficiary( @NonNull List pendingStorageUpdates(); - void setupContext(@NonNull Context context); + void setupContext(@NonNull OperationContext context); @NonNull - Optional context(); + Optional context(); /** * Externalizes the results of a system contract call into a record diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/state/ProxyWorldUpdater.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/state/ProxyWorldUpdater.java index f984b889d5fb..3e454d8bf8de 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/state/ProxyWorldUpdater.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/state/ProxyWorldUpdater.java @@ -37,7 +37,7 @@ import com.hedera.hapi.node.transaction.ExchangeRate; import com.hedera.node.app.service.contract.impl.exec.scope.HandleHederaOperations; import com.hedera.node.app.service.contract.impl.hevm.HederaWorldUpdater; -import com.hedera.node.app.spi.workflows.Context; +import com.hedera.node.app.spi.workflows.OperationContext; import com.hedera.node.app.spi.workflows.ResourceExhaustedException; import com.hedera.node.app.spi.workflows.record.RecordListCheckPoint; import edu.umd.cs.findbugs.annotations.NonNull; @@ -85,7 +85,7 @@ public class ProxyWorldUpdater implements HederaWorldUpdater { * Context */ @Nullable - private Context context; + private OperationContext context; /** * The current checkpoint of the child records for this ProxyWorldUpdater. @@ -456,7 +456,7 @@ public void commit() { * {@inheritDoc} */ @Override - public void setupContext(@NonNull final Context context) { + public void setupContext(@NonNull final OperationContext context) { this.context = context; } @@ -464,7 +464,7 @@ public void setupContext(@NonNull final Context context) { * {@inheritDoc} */ @Override - public @NonNull Optional context() { + public @NonNull Optional context() { return Optional.ofNullable(context); } diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/state/RootProxyWorldUpdaterTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/state/RootProxyWorldUpdaterTest.java index 72a445e8617d..8fc29778be0b 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/state/RootProxyWorldUpdaterTest.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/state/RootProxyWorldUpdaterTest.java @@ -38,7 +38,6 @@ import com.hedera.node.app.service.contract.impl.state.StorageAccesses; import com.hedera.node.app.service.contract.impl.state.StorageSizeChange; import com.hedera.node.app.service.token.api.ContractChangeSummary; -import com.hedera.node.app.spi.workflows.Context; import com.hedera.node.config.data.ContractsConfig; import com.hedera.node.config.testfixtures.HederaTestConfigBuilder; import com.swirlds.config.api.Configuration; @@ -91,9 +90,6 @@ class RootProxyWorldUpdaterTest { @Mock private ContractStateStore store; - @Mock - private Context context; - private Enhancement enhancement; private RootProxyWorldUpdater subject; From c903b9452a091a905915d02c85496cd5356cb818 Mon Sep 17 00:00:00 2001 From: Petar Tonev Date: Fri, 19 Jan 2024 22:49:06 +0200 Subject: [PATCH 11/34] chore: add interface description to OperationContext --- .../node/app/spi/workflows/OperationContext.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/workflows/OperationContext.java b/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/workflows/OperationContext.java index af33ec719d8d..d4ac9eb5ffb2 100644 --- a/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/workflows/OperationContext.java +++ b/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/workflows/OperationContext.java @@ -18,6 +18,17 @@ import com.hedera.hapi.node.base.HederaFunctionality; +/** + * Represents a generalized operation context (HandleContext or QueryContext) of a single {@code handle()}-call. + *
    + *
  • Information about the transaction being handled, such as its consensus time, its body, and its category
  • + *
  • Configuration data and objects that depend on the current configuration
  • + *
  • Verification data, that has been assembled during pre-handle
  • + *
  • State related data and the possibility to rollback changes
  • + *
  • Data related to the record stream
  • + *
  • Functionality to dispatch preceding and child transactions
  • + *
+ */ public interface OperationContext { /** * Verifies if the throttle in this operation context has enough capacity to handle the given number of the From 262e388bd0918fe3a5e016010b02bfd8c6924f7e Mon Sep 17 00:00:00 2001 From: Petar Tonev Date: Mon, 22 Jan 2024 17:28:54 +0200 Subject: [PATCH 12/34] fix: address PR comments with several conceptual changes --- .../spi/throttle/HandleThrottleParser.java | 2 + .../node/app/spi/workflows/HandleContext.java | 15 ++++ .../throttle/FakeHandleThrottleParser.java | 5 ++ .../throttle/NetworkUtilizationManager.java | 18 ++++- .../app/throttle/ThrottleAccumulator.java | 51 +++++++------ .../impl/NetworkUtilizationManagerImpl.java | 37 ++++++---- .../workflows/handle/HandleContextImpl.java | 71 +++++++++++++------ .../SingleTransactionRecordBuilderImpl.java | 9 +-- .../ContractOperationRecordBuilderTest.java | 8 ++- 9 files changed, 152 insertions(+), 64 deletions(-) diff --git a/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/throttle/HandleThrottleParser.java b/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/throttle/HandleThrottleParser.java index 98d9ca86a4a3..47153a32c9c5 100644 --- a/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/throttle/HandleThrottleParser.java +++ b/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/throttle/HandleThrottleParser.java @@ -31,6 +31,8 @@ public interface HandleThrottleParser { @NonNull List allActiveThrottles(); + void resetUsageThrottlesTo(List snapshots); + @Nullable public GasLimitDeterministicThrottle gasLimitThrottle(); } diff --git a/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/workflows/HandleContext.java b/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/workflows/HandleContext.java index c73314276758..0846efa9db47 100644 --- a/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/workflows/HandleContext.java +++ b/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/workflows/HandleContext.java @@ -24,6 +24,7 @@ import com.hedera.hapi.node.base.Key; import com.hedera.hapi.node.base.SubType; import com.hedera.hapi.node.transaction.TransactionBody; +import com.hedera.node.app.hapi.utils.throttles.DeterministicThrottle; import com.hedera.node.app.spi.authorization.SystemPrivilege; import com.hedera.node.app.spi.fees.ExchangeRateInfo; import com.hedera.node.app.spi.fees.FeeAccumulator; @@ -43,6 +44,7 @@ import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; import java.time.Instant; +import java.util.List; import java.util.function.Predicate; /** @@ -677,6 +679,19 @@ default T dispatchRemovableChildTransaction( @NonNull RecordListCheckPoint createRecordListCheckPoint(); + /** + * Returns a list of snapshots of the current usage of all active throttles. + * @return the active snapshots + */ + List getUsageSnapshots(); + + /** + * Resets the current usage of all active throttles to the given snapshots. + * + * @param snapshots the snapshots to reset to + */ + void resetUsageThrottlesTo(List snapshots); + /** * Returns whether the current transaction being processed was submitted by this node. * diff --git a/hedera-node/hedera-app-spi/src/testFixtures/java/com/hedera/node/app/spi/fixtures/throttle/FakeHandleThrottleParser.java b/hedera-node/hedera-app-spi/src/testFixtures/java/com/hedera/node/app/spi/fixtures/throttle/FakeHandleThrottleParser.java index 033692916e4b..31c0ced1ae64 100644 --- a/hedera-node/hedera-app-spi/src/testFixtures/java/com/hedera/node/app/spi/fixtures/throttle/FakeHandleThrottleParser.java +++ b/hedera-node/hedera-app-spi/src/testFixtures/java/com/hedera/node/app/spi/fixtures/throttle/FakeHandleThrottleParser.java @@ -42,6 +42,11 @@ public List allActiveThrottles() { return Collections.emptyList(); } + @Override + public void resetUsageThrottlesTo(List snapshots) { + + } + @Nullable @Override public GasLimitDeterministicThrottle gasLimitThrottle() { diff --git a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/NetworkUtilizationManager.java b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/NetworkUtilizationManager.java index 5d6e33498da5..2288be032238 100644 --- a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/NetworkUtilizationManager.java +++ b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/NetworkUtilizationManager.java @@ -17,10 +17,12 @@ package com.hedera.node.app.throttle; import com.hedera.hapi.node.base.AccountID; +import com.hedera.node.app.hapi.utils.throttles.DeterministicThrottle; import com.hedera.node.app.state.HederaState; import com.hedera.node.app.workflows.TransactionInfo; import edu.umd.cs.findbugs.annotations.NonNull; import java.time.Instant; +import java.util.List; /** * Interface which purpose is to do the work of tracking network utilization (and its impact on @@ -85,7 +87,21 @@ void trackFeePayments( * * @param txnInfo the transaction to update the throttle requirements for * @param state the current state of the node + * @param consensusTime the consensus time * @return whether the transaction should be throttled */ - boolean shouldThrottle(@NonNull TransactionInfo txnInfo, HederaState state); + boolean shouldThrottle(@NonNull final TransactionInfo txnInfo, @NonNull final HederaState state, @NonNull final Instant consensusTime); + + /** + * Returns a list of snapshots of the current usage of all active throttles. + * @return the active snapshots + */ + List getUsageSnapshots(); + + /** + * Resets the current usage of all active throttles to the given snapshots. + * + * @param snapshots the snapshots to reset to + */ + void resetUsageThrottlesTo(List snapshots); } diff --git a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/ThrottleAccumulator.java b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/ThrottleAccumulator.java index 2f1bb59b4938..1bc254df6c15 100644 --- a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/ThrottleAccumulator.java +++ b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/ThrottleAccumulator.java @@ -16,23 +16,6 @@ package com.hedera.node.app.throttle; -import static com.hedera.hapi.node.base.HederaFunctionality.CONTRACT_CALL; -import static com.hedera.hapi.node.base.HederaFunctionality.CONTRACT_CALL_LOCAL; -import static com.hedera.hapi.node.base.HederaFunctionality.CONTRACT_CREATE; -import static com.hedera.hapi.node.base.HederaFunctionality.CRYPTO_CREATE; -import static com.hedera.hapi.node.base.HederaFunctionality.CRYPTO_TRANSFER; -import static com.hedera.hapi.node.base.HederaFunctionality.ETHEREUM_TRANSACTION; -import static com.hedera.node.app.hapi.utils.ethereum.EthTxData.populateEthTxData; -import static com.hedera.node.app.hapi.utils.sysfiles.domain.throttling.ScaleFactor.ONE_TO_ONE; -import static com.hedera.node.app.service.evm.accounts.HederaEvmContractAliases.isMirror; -import static com.hedera.node.app.service.mono.utils.EntityIdUtils.isOfEvmAddressSize; -import static com.hedera.node.app.service.schedule.impl.handlers.HandlerUtility.childAsOrdinary; -import static com.hedera.node.app.service.token.AliasUtils.isAlias; -import static com.hedera.node.app.service.token.AliasUtils.isSerializedProtoKey; -import static com.hedera.node.app.spi.HapiUtils.functionOf; -import static com.hedera.node.app.throttle.ThrottleAccumulator.ThrottleType.FRONTEND_THROTTLE; -import static java.util.Objects.requireNonNull; - import com.hedera.hapi.node.base.AccountAmount; import com.hedera.hapi.node.base.AccountID; import com.hedera.hapi.node.base.HederaFunctionality; @@ -71,6 +54,10 @@ import com.swirlds.config.api.Configuration; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; +import org.apache.commons.lang3.tuple.Pair; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + import java.math.BigInteger; import java.time.Instant; import java.util.ArrayList; @@ -83,9 +70,23 @@ import java.util.Optional; import java.util.Set; import java.util.function.IntSupplier; -import org.apache.commons.lang3.tuple.Pair; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; + +import static com.hedera.hapi.node.base.HederaFunctionality.CONTRACT_CALL; +import static com.hedera.hapi.node.base.HederaFunctionality.CONTRACT_CALL_LOCAL; +import static com.hedera.hapi.node.base.HederaFunctionality.CONTRACT_CREATE; +import static com.hedera.hapi.node.base.HederaFunctionality.CRYPTO_CREATE; +import static com.hedera.hapi.node.base.HederaFunctionality.CRYPTO_TRANSFER; +import static com.hedera.hapi.node.base.HederaFunctionality.ETHEREUM_TRANSACTION; +import static com.hedera.node.app.hapi.utils.ethereum.EthTxData.populateEthTxData; +import static com.hedera.node.app.hapi.utils.sysfiles.domain.throttling.ScaleFactor.ONE_TO_ONE; +import static com.hedera.node.app.service.evm.accounts.HederaEvmContractAliases.isMirror; +import static com.hedera.node.app.service.mono.utils.EntityIdUtils.isOfEvmAddressSize; +import static com.hedera.node.app.service.schedule.impl.handlers.HandlerUtility.childAsOrdinary; +import static com.hedera.node.app.service.token.AliasUtils.isAlias; +import static com.hedera.node.app.service.token.AliasUtils.isSerializedProtoKey; +import static com.hedera.node.app.spi.HapiUtils.functionOf; +import static com.hedera.node.app.throttle.ThrottleAccumulator.ThrottleType.FRONTEND_THROTTLE; +import static java.util.Objects.requireNonNull; /** * Keeps track of the amount of usage of different TPS throttle categories and gas, and returns whether a given @@ -288,6 +289,16 @@ public void resetUsage() { } } + /* + * Resets the usage for all snapshots. + */ + @Override + public void resetUsageThrottlesTo(final List snapshots) { + for (int i = 0, n = activeThrottles.size(); i < n; i++) { + activeThrottles.get(i).resetUsageTo(snapshots.get(i)); + } + } + private boolean shouldThrottleTxn( final boolean isScheduled, @NonNull final TransactionInfo txnInfo, diff --git a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/impl/NetworkUtilizationManagerImpl.java b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/impl/NetworkUtilizationManagerImpl.java index c0c5f36ddf2f..3c1d8c8531ea 100644 --- a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/impl/NetworkUtilizationManagerImpl.java +++ b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/impl/NetworkUtilizationManagerImpl.java @@ -16,13 +16,6 @@ package com.hedera.node.app.throttle.impl; -import static com.hedera.hapi.node.base.HederaFunctionality.CRYPTO_TRANSFER; -import static com.hedera.node.app.records.BlockRecordService.EPOCH; -import static com.hedera.node.app.service.mono.pbj.PbjConverter.fromPbj; -import static com.hedera.node.app.service.mono.pbj.PbjConverter.toPbj; -import static com.hedera.node.app.service.mono.utils.MiscUtils.safeResetThrottles; -import static java.util.Objects.requireNonNull; - import com.hedera.hapi.node.base.AccountID; import com.hedera.hapi.node.base.SignatureMap; import com.hedera.hapi.node.base.Timestamp; @@ -42,12 +35,20 @@ import com.hedera.node.app.workflows.TransactionInfo; import com.hedera.pbj.runtime.io.buffer.Bytes; import edu.umd.cs.findbugs.annotations.NonNull; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import javax.inject.Inject; import java.time.Instant; import java.util.ArrayList; import java.util.List; -import javax.inject.Inject; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; + +import static com.hedera.hapi.node.base.HederaFunctionality.CRYPTO_TRANSFER; +import static com.hedera.node.app.records.BlockRecordService.EPOCH; +import static com.hedera.node.app.service.mono.pbj.PbjConverter.fromPbj; +import static com.hedera.node.app.service.mono.pbj.PbjConverter.toPbj; +import static com.hedera.node.app.service.mono.utils.MiscUtils.safeResetThrottles; +import static java.util.Objects.requireNonNull; /** * Implementation of {@link NetworkUtilizationManager} that delegates to injected {@link ThrottleAccumulator} and {@link @@ -202,8 +203,18 @@ public void leakUnusedGasPreviouslyReserved(@NonNull final TransactionInfo txnIn backendThrottle.leakUnusedGasPreviouslyReserved(txnInfo, value); } - public boolean shouldThrottle(@NonNull TransactionInfo txnInfo, HederaState state) { - final var now = Instant.now(); - return backendThrottle.shouldThrottle(txnInfo, now, state); + @Override + public boolean shouldThrottle(@NonNull final TransactionInfo txnInfo, @NonNull final HederaState state, @NonNull final Instant consensusTime) { + return backendThrottle.shouldThrottle(txnInfo, consensusTime, state); + } + + @Override + public List getUsageSnapshots() { + return backendThrottle.allActiveThrottles().stream().map(DeterministicThrottle::usageSnapshot).toList(); + } + + @Override + public void resetUsageThrottlesTo(List snapshots) { + backendThrottle.resetUsageThrottlesTo(snapshots); } } diff --git a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleContextImpl.java b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleContextImpl.java index d6d9ce38dab7..863e11a317b5 100644 --- a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleContextImpl.java +++ b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleContextImpl.java @@ -16,19 +16,6 @@ package com.hedera.node.app.workflows.handle; -import static com.hedera.hapi.node.base.HederaFunctionality.CONTRACT_CALL; -import static com.hedera.hapi.node.base.HederaFunctionality.CONTRACT_CREATE; -import static com.hedera.hapi.node.base.ResponseCodeEnum.DUPLICATE_TRANSACTION; -import static com.hedera.hapi.node.base.ResponseCodeEnum.INVALID_SIGNATURE; -import static com.hedera.hapi.node.base.ResponseCodeEnum.SUCCESS; -import static com.hedera.node.app.spi.HapiUtils.functionOf; -import static com.hedera.node.app.spi.workflows.HandleContext.TransactionCategory.CHILD; -import static com.hedera.node.app.spi.workflows.HandleContext.TransactionCategory.PRECEDING; -import static com.hedera.node.app.spi.workflows.HandleContext.TransactionCategory.SCHEDULED; -import static com.hedera.node.app.state.HederaRecordCache.DuplicateCheckResult.NO_DUPLICATE; -import static com.hedera.node.app.workflows.handle.HandleContextImpl.PrecedingTransactionCategory.LIMITED_CHILD_RECORDS; -import static java.util.Objects.requireNonNull; - import com.hedera.hapi.node.base.AccountID; import com.hedera.hapi.node.base.HederaFunctionality; import com.hedera.hapi.node.base.Key; @@ -45,6 +32,7 @@ import com.hedera.node.app.fees.FeeManager; import com.hedera.node.app.fees.NoOpFeeAccumulator; import com.hedera.node.app.fees.NoOpFeeCalculator; +import com.hedera.node.app.hapi.utils.throttles.DeterministicThrottle; import com.hedera.node.app.ids.EntityIdService; import com.hedera.node.app.ids.WritableEntityIdStore; import com.hedera.node.app.service.token.TokenService; @@ -97,13 +85,28 @@ import com.swirlds.config.api.Configuration; 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; + import java.time.Instant; +import java.util.List; import java.util.Objects; import java.util.function.Function; import java.util.function.Predicate; import java.util.function.Supplier; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; + +import static com.hedera.hapi.node.base.HederaFunctionality.CONTRACT_CALL; +import static com.hedera.hapi.node.base.HederaFunctionality.CONTRACT_CREATE; +import static com.hedera.hapi.node.base.ResponseCodeEnum.DUPLICATE_TRANSACTION; +import static com.hedera.hapi.node.base.ResponseCodeEnum.INVALID_SIGNATURE; +import static com.hedera.hapi.node.base.ResponseCodeEnum.SUCCESS; +import static com.hedera.node.app.spi.HapiUtils.functionOf; +import static com.hedera.node.app.spi.workflows.HandleContext.TransactionCategory.CHILD; +import static com.hedera.node.app.spi.workflows.HandleContext.TransactionCategory.PRECEDING; +import static com.hedera.node.app.spi.workflows.HandleContext.TransactionCategory.SCHEDULED; +import static com.hedera.node.app.state.HederaRecordCache.DuplicateCheckResult.NO_DUPLICATE; +import static com.hedera.node.app.workflows.handle.HandleContextImpl.PrecedingTransactionCategory.LIMITED_CHILD_RECORDS; +import static java.util.Objects.requireNonNull; /** * The default implementation of {@link HandleContext}. @@ -913,31 +916,53 @@ public boolean shouldThrottleNOfUnscaled(int n, HederaFunctionality function) { } public boolean shouldThrottleTxn(TransactionInfo txInfo) { - return networkUtilizationManager.shouldThrottle(txInfo, current()); + return networkUtilizationManager.shouldThrottle(txInfo, current(), userTransactionConsensusTime); + } + + @Override + public List getUsageSnapshots() { + return networkUtilizationManager.getUsageSnapshots(); + } + + @Override + public void resetUsageThrottlesTo(List snapshots) { + networkUtilizationManager.resetUsageThrottlesTo(snapshots); } @Override public boolean hasThrottleCapacityForChildTransactions() { var isAllowed = true; final var childRecords = recordListBuilder.childRecordBuilders(); + @Nullable List snapshotsIfNeeded = null; for (int i = 0, n = childRecords.size(); i < n && isAllowed; i++) { final var childRecord = childRecords.get(i); if (Objects.equals(childRecord.status(), SUCCESS)) { - final var tx = childRecord.build().transaction(); - final var txInfo = new TransactionInfo( - tx, childRecord.transactionBody(), tx.sigMap(), tx.signedTransactionBytes(), functionality); + final var childTx = childRecord.build().transaction(); + final var childTxBody = childRecord.transactionBody(); + HederaFunctionality childTxFunctionality; + try { + childTxFunctionality = functionOf(childTxBody); + } catch (UnknownHederaFunctionality e) { + throw new IllegalStateException("Invalid transaction body " + childTxBody, e); + } - if (txInfo.functionality() == CONTRACT_CREATE || txInfo.functionality() == CONTRACT_CALL) { + final var childTxInfo = new TransactionInfo( + childTx, childTxBody, childTx.sigMap(), childTx.signedTransactionBytes(), childTxFunctionality); + if (childTxFunctionality == CONTRACT_CREATE || childTxFunctionality == CONTRACT_CALL) { continue; } - - if (shouldThrottleTxn(txInfo)) { + if (snapshotsIfNeeded == null) { + snapshotsIfNeeded = getUsageSnapshots(); + } + if (shouldThrottleTxn(childTxInfo)) { isAllowed = false; } } } - + if (!isAllowed) { + resetUsageThrottlesTo(snapshotsIfNeeded); + } return isAllowed; } diff --git a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/record/SingleTransactionRecordBuilderImpl.java b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/record/SingleTransactionRecordBuilderImpl.java index e0f8040f9fd3..d267e791d7f0 100644 --- a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/record/SingleTransactionRecordBuilderImpl.java +++ b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/record/SingleTransactionRecordBuilderImpl.java @@ -16,10 +16,6 @@ package com.hedera.node.app.workflows.handle.record; -import static com.hedera.node.app.spi.workflows.record.ExternalizedRecordCustomizer.NOOP_EXTERNALIZED_RECORD_CUSTOMIZER; -import static com.hedera.node.app.state.logging.TransactionStateLogger.logEndTransactionRecord; -import static java.util.Objects.requireNonNull; - import com.hedera.hapi.node.base.AccountAmount; import com.hedera.hapi.node.base.AccountID; import com.hedera.hapi.node.base.ContractID; @@ -80,6 +76,7 @@ import com.swirlds.common.crypto.DigestType; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; + import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.time.Instant; @@ -91,6 +88,10 @@ import java.util.List; import java.util.Map; +import static com.hedera.node.app.spi.workflows.record.ExternalizedRecordCustomizer.NOOP_EXTERNALIZED_RECORD_CUSTOMIZER; +import static com.hedera.node.app.state.logging.TransactionStateLogger.logEndTransactionRecord; +import static java.util.Objects.requireNonNull; + /** * A custom builder for create a {@link SingleTransactionRecord}. * diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/records/ContractOperationRecordBuilderTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/records/ContractOperationRecordBuilderTest.java index 50cc3603dfc0..252f2868fbd3 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/records/ContractOperationRecordBuilderTest.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/records/ContractOperationRecordBuilderTest.java @@ -16,8 +16,6 @@ package com.hedera.node.app.service.contract.impl.test.records; -import static org.junit.jupiter.api.Assertions.*; - import com.hedera.hapi.node.base.AccountID; import com.hedera.hapi.node.base.ContractID; import com.hedera.hapi.node.base.ResponseCodeEnum; @@ -33,10 +31,14 @@ import com.hedera.node.app.spi.workflows.record.SingleTransactionRecordBuilder; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; -import java.util.List; import org.jetbrains.annotations.NotNull; import org.junit.jupiter.api.Test; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertSame; + class ContractOperationRecordBuilderTest { @Test void withGasFeeWorksAsExpected() { From b07a52720df0451b81e8ef3841d96a4fad5e50ce Mon Sep 17 00:00:00 2001 From: Petar Tonev Date: Mon, 22 Jan 2024 20:03:00 +0200 Subject: [PATCH 13/34] chore: apply spotless --- .../throttle/FakeHandleThrottleParser.java | 4 +- .../throttle/NetworkUtilizationManager.java | 5 ++- .../app/throttle/ThrottleAccumulator.java | 41 +++++++++---------- .../impl/NetworkUtilizationManagerImpl.java | 30 ++++++++------ .../workflows/handle/HandleContextImpl.java | 31 +++++++------- .../SingleTransactionRecordBuilderImpl.java | 9 ++-- .../ContractOperationRecordBuilderTest.java | 9 ++-- 7 files changed, 65 insertions(+), 64 deletions(-) diff --git a/hedera-node/hedera-app-spi/src/testFixtures/java/com/hedera/node/app/spi/fixtures/throttle/FakeHandleThrottleParser.java b/hedera-node/hedera-app-spi/src/testFixtures/java/com/hedera/node/app/spi/fixtures/throttle/FakeHandleThrottleParser.java index 31c0ced1ae64..f04644740301 100644 --- a/hedera-node/hedera-app-spi/src/testFixtures/java/com/hedera/node/app/spi/fixtures/throttle/FakeHandleThrottleParser.java +++ b/hedera-node/hedera-app-spi/src/testFixtures/java/com/hedera/node/app/spi/fixtures/throttle/FakeHandleThrottleParser.java @@ -43,9 +43,7 @@ public List allActiveThrottles() { } @Override - public void resetUsageThrottlesTo(List snapshots) { - - } + public void resetUsageThrottlesTo(List snapshots) {} @Nullable @Override diff --git a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/NetworkUtilizationManager.java b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/NetworkUtilizationManager.java index 2288be032238..8ef5345844d3 100644 --- a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/NetworkUtilizationManager.java +++ b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/NetworkUtilizationManager.java @@ -90,7 +90,10 @@ void trackFeePayments( * @param consensusTime the consensus time * @return whether the transaction should be throttled */ - boolean shouldThrottle(@NonNull final TransactionInfo txnInfo, @NonNull final HederaState state, @NonNull final Instant consensusTime); + boolean shouldThrottle( + @NonNull final TransactionInfo txnInfo, + @NonNull final HederaState state, + @NonNull final Instant consensusTime); /** * Returns a list of snapshots of the current usage of all active throttles. diff --git a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/ThrottleAccumulator.java b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/ThrottleAccumulator.java index 1bc254df6c15..9d5bc7852c54 100644 --- a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/ThrottleAccumulator.java +++ b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/ThrottleAccumulator.java @@ -16,6 +16,23 @@ package com.hedera.node.app.throttle; +import static com.hedera.hapi.node.base.HederaFunctionality.CONTRACT_CALL; +import static com.hedera.hapi.node.base.HederaFunctionality.CONTRACT_CALL_LOCAL; +import static com.hedera.hapi.node.base.HederaFunctionality.CONTRACT_CREATE; +import static com.hedera.hapi.node.base.HederaFunctionality.CRYPTO_CREATE; +import static com.hedera.hapi.node.base.HederaFunctionality.CRYPTO_TRANSFER; +import static com.hedera.hapi.node.base.HederaFunctionality.ETHEREUM_TRANSACTION; +import static com.hedera.node.app.hapi.utils.ethereum.EthTxData.populateEthTxData; +import static com.hedera.node.app.hapi.utils.sysfiles.domain.throttling.ScaleFactor.ONE_TO_ONE; +import static com.hedera.node.app.service.evm.accounts.HederaEvmContractAliases.isMirror; +import static com.hedera.node.app.service.mono.utils.EntityIdUtils.isOfEvmAddressSize; +import static com.hedera.node.app.service.schedule.impl.handlers.HandlerUtility.childAsOrdinary; +import static com.hedera.node.app.service.token.AliasUtils.isAlias; +import static com.hedera.node.app.service.token.AliasUtils.isSerializedProtoKey; +import static com.hedera.node.app.spi.HapiUtils.functionOf; +import static com.hedera.node.app.throttle.ThrottleAccumulator.ThrottleType.FRONTEND_THROTTLE; +import static java.util.Objects.requireNonNull; + import com.hedera.hapi.node.base.AccountAmount; import com.hedera.hapi.node.base.AccountID; import com.hedera.hapi.node.base.HederaFunctionality; @@ -54,10 +71,6 @@ import com.swirlds.config.api.Configuration; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; -import org.apache.commons.lang3.tuple.Pair; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - import java.math.BigInteger; import java.time.Instant; import java.util.ArrayList; @@ -70,23 +83,9 @@ import java.util.Optional; import java.util.Set; import java.util.function.IntSupplier; - -import static com.hedera.hapi.node.base.HederaFunctionality.CONTRACT_CALL; -import static com.hedera.hapi.node.base.HederaFunctionality.CONTRACT_CALL_LOCAL; -import static com.hedera.hapi.node.base.HederaFunctionality.CONTRACT_CREATE; -import static com.hedera.hapi.node.base.HederaFunctionality.CRYPTO_CREATE; -import static com.hedera.hapi.node.base.HederaFunctionality.CRYPTO_TRANSFER; -import static com.hedera.hapi.node.base.HederaFunctionality.ETHEREUM_TRANSACTION; -import static com.hedera.node.app.hapi.utils.ethereum.EthTxData.populateEthTxData; -import static com.hedera.node.app.hapi.utils.sysfiles.domain.throttling.ScaleFactor.ONE_TO_ONE; -import static com.hedera.node.app.service.evm.accounts.HederaEvmContractAliases.isMirror; -import static com.hedera.node.app.service.mono.utils.EntityIdUtils.isOfEvmAddressSize; -import static com.hedera.node.app.service.schedule.impl.handlers.HandlerUtility.childAsOrdinary; -import static com.hedera.node.app.service.token.AliasUtils.isAlias; -import static com.hedera.node.app.service.token.AliasUtils.isSerializedProtoKey; -import static com.hedera.node.app.spi.HapiUtils.functionOf; -import static com.hedera.node.app.throttle.ThrottleAccumulator.ThrottleType.FRONTEND_THROTTLE; -import static java.util.Objects.requireNonNull; +import org.apache.commons.lang3.tuple.Pair; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; /** * Keeps track of the amount of usage of different TPS throttle categories and gas, and returns whether a given diff --git a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/impl/NetworkUtilizationManagerImpl.java b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/impl/NetworkUtilizationManagerImpl.java index 3c1d8c8531ea..e66bf93230d5 100644 --- a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/impl/NetworkUtilizationManagerImpl.java +++ b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/impl/NetworkUtilizationManagerImpl.java @@ -16,6 +16,13 @@ package com.hedera.node.app.throttle.impl; +import static com.hedera.hapi.node.base.HederaFunctionality.CRYPTO_TRANSFER; +import static com.hedera.node.app.records.BlockRecordService.EPOCH; +import static com.hedera.node.app.service.mono.pbj.PbjConverter.fromPbj; +import static com.hedera.node.app.service.mono.pbj.PbjConverter.toPbj; +import static com.hedera.node.app.service.mono.utils.MiscUtils.safeResetThrottles; +import static java.util.Objects.requireNonNull; + import com.hedera.hapi.node.base.AccountID; import com.hedera.hapi.node.base.SignatureMap; import com.hedera.hapi.node.base.Timestamp; @@ -35,20 +42,12 @@ import com.hedera.node.app.workflows.TransactionInfo; import com.hedera.pbj.runtime.io.buffer.Bytes; import edu.umd.cs.findbugs.annotations.NonNull; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import javax.inject.Inject; import java.time.Instant; import java.util.ArrayList; import java.util.List; - -import static com.hedera.hapi.node.base.HederaFunctionality.CRYPTO_TRANSFER; -import static com.hedera.node.app.records.BlockRecordService.EPOCH; -import static com.hedera.node.app.service.mono.pbj.PbjConverter.fromPbj; -import static com.hedera.node.app.service.mono.pbj.PbjConverter.toPbj; -import static com.hedera.node.app.service.mono.utils.MiscUtils.safeResetThrottles; -import static java.util.Objects.requireNonNull; +import javax.inject.Inject; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; /** * Implementation of {@link NetworkUtilizationManager} that delegates to injected {@link ThrottleAccumulator} and {@link @@ -204,13 +203,18 @@ public void leakUnusedGasPreviouslyReserved(@NonNull final TransactionInfo txnIn } @Override - public boolean shouldThrottle(@NonNull final TransactionInfo txnInfo, @NonNull final HederaState state, @NonNull final Instant consensusTime) { + public boolean shouldThrottle( + @NonNull final TransactionInfo txnInfo, + @NonNull final HederaState state, + @NonNull final Instant consensusTime) { return backendThrottle.shouldThrottle(txnInfo, consensusTime, state); } @Override public List getUsageSnapshots() { - return backendThrottle.allActiveThrottles().stream().map(DeterministicThrottle::usageSnapshot).toList(); + return backendThrottle.allActiveThrottles().stream() + .map(DeterministicThrottle::usageSnapshot) + .toList(); } @Override diff --git a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleContextImpl.java b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleContextImpl.java index 863e11a317b5..6c4b9e39d146 100644 --- a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleContextImpl.java +++ b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleContextImpl.java @@ -16,6 +16,19 @@ package com.hedera.node.app.workflows.handle; +import static com.hedera.hapi.node.base.HederaFunctionality.CONTRACT_CALL; +import static com.hedera.hapi.node.base.HederaFunctionality.CONTRACT_CREATE; +import static com.hedera.hapi.node.base.ResponseCodeEnum.DUPLICATE_TRANSACTION; +import static com.hedera.hapi.node.base.ResponseCodeEnum.INVALID_SIGNATURE; +import static com.hedera.hapi.node.base.ResponseCodeEnum.SUCCESS; +import static com.hedera.node.app.spi.HapiUtils.functionOf; +import static com.hedera.node.app.spi.workflows.HandleContext.TransactionCategory.CHILD; +import static com.hedera.node.app.spi.workflows.HandleContext.TransactionCategory.PRECEDING; +import static com.hedera.node.app.spi.workflows.HandleContext.TransactionCategory.SCHEDULED; +import static com.hedera.node.app.state.HederaRecordCache.DuplicateCheckResult.NO_DUPLICATE; +import static com.hedera.node.app.workflows.handle.HandleContextImpl.PrecedingTransactionCategory.LIMITED_CHILD_RECORDS; +import static java.util.Objects.requireNonNull; + import com.hedera.hapi.node.base.AccountID; import com.hedera.hapi.node.base.HederaFunctionality; import com.hedera.hapi.node.base.Key; @@ -85,28 +98,14 @@ import com.swirlds.config.api.Configuration; 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; - import java.time.Instant; import java.util.List; import java.util.Objects; import java.util.function.Function; import java.util.function.Predicate; import java.util.function.Supplier; - -import static com.hedera.hapi.node.base.HederaFunctionality.CONTRACT_CALL; -import static com.hedera.hapi.node.base.HederaFunctionality.CONTRACT_CREATE; -import static com.hedera.hapi.node.base.ResponseCodeEnum.DUPLICATE_TRANSACTION; -import static com.hedera.hapi.node.base.ResponseCodeEnum.INVALID_SIGNATURE; -import static com.hedera.hapi.node.base.ResponseCodeEnum.SUCCESS; -import static com.hedera.node.app.spi.HapiUtils.functionOf; -import static com.hedera.node.app.spi.workflows.HandleContext.TransactionCategory.CHILD; -import static com.hedera.node.app.spi.workflows.HandleContext.TransactionCategory.PRECEDING; -import static com.hedera.node.app.spi.workflows.HandleContext.TransactionCategory.SCHEDULED; -import static com.hedera.node.app.state.HederaRecordCache.DuplicateCheckResult.NO_DUPLICATE; -import static com.hedera.node.app.workflows.handle.HandleContextImpl.PrecedingTransactionCategory.LIMITED_CHILD_RECORDS; -import static java.util.Objects.requireNonNull; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; /** * The default implementation of {@link HandleContext}. diff --git a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/record/SingleTransactionRecordBuilderImpl.java b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/record/SingleTransactionRecordBuilderImpl.java index d267e791d7f0..e0f8040f9fd3 100644 --- a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/record/SingleTransactionRecordBuilderImpl.java +++ b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/record/SingleTransactionRecordBuilderImpl.java @@ -16,6 +16,10 @@ package com.hedera.node.app.workflows.handle.record; +import static com.hedera.node.app.spi.workflows.record.ExternalizedRecordCustomizer.NOOP_EXTERNALIZED_RECORD_CUSTOMIZER; +import static com.hedera.node.app.state.logging.TransactionStateLogger.logEndTransactionRecord; +import static java.util.Objects.requireNonNull; + import com.hedera.hapi.node.base.AccountAmount; import com.hedera.hapi.node.base.AccountID; import com.hedera.hapi.node.base.ContractID; @@ -76,7 +80,6 @@ import com.swirlds.common.crypto.DigestType; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; - import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.time.Instant; @@ -88,10 +91,6 @@ import java.util.List; import java.util.Map; -import static com.hedera.node.app.spi.workflows.record.ExternalizedRecordCustomizer.NOOP_EXTERNALIZED_RECORD_CUSTOMIZER; -import static com.hedera.node.app.state.logging.TransactionStateLogger.logEndTransactionRecord; -import static java.util.Objects.requireNonNull; - /** * A custom builder for create a {@link SingleTransactionRecord}. * diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/records/ContractOperationRecordBuilderTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/records/ContractOperationRecordBuilderTest.java index 252f2868fbd3..25da8a219ce4 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/records/ContractOperationRecordBuilderTest.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/records/ContractOperationRecordBuilderTest.java @@ -16,6 +16,9 @@ package com.hedera.node.app.service.contract.impl.test.records; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertSame; + import com.hedera.hapi.node.base.AccountID; import com.hedera.hapi.node.base.ContractID; import com.hedera.hapi.node.base.ResponseCodeEnum; @@ -31,14 +34,10 @@ import com.hedera.node.app.spi.workflows.record.SingleTransactionRecordBuilder; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; +import java.util.List; import org.jetbrains.annotations.NotNull; import org.junit.jupiter.api.Test; -import java.util.List; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertSame; - class ContractOperationRecordBuilderTest { @Test void withGasFeeWorksAsExpected() { From d11de6c96253ec388bd14ac770343658eb752b71 Mon Sep 17 00:00:00 2001 From: Petar Tonev Date: Tue, 23 Jan 2024 11:21:46 +0200 Subject: [PATCH 14/34] fix: potential fix with reverse condition --- .../node/app/workflows/handle/HandleContextImpl.java | 2 +- .../record/SingleTransactionRecordBuilderImpl.java | 9 +++++++++ .../contract/impl/state/RootProxyWorldUpdater.java | 2 +- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleContextImpl.java b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleContextImpl.java index 6c4b9e39d146..75635d1e9a52 100644 --- a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleContextImpl.java +++ b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleContextImpl.java @@ -937,7 +937,7 @@ public boolean hasThrottleCapacityForChildTransactions() { for (int i = 0, n = childRecords.size(); i < n && isAllowed; i++) { final var childRecord = childRecords.get(i); if (Objects.equals(childRecord.status(), SUCCESS)) { - final var childTx = childRecord.build().transaction(); + final var childTx = childRecord.transaction(); final var childTxBody = childRecord.transactionBody(); HederaFunctionality childTxFunctionality; try { diff --git a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/record/SingleTransactionRecordBuilderImpl.java b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/record/SingleTransactionRecordBuilderImpl.java index e0f8040f9fd3..bc9e2f7133b4 100644 --- a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/record/SingleTransactionRecordBuilderImpl.java +++ b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/record/SingleTransactionRecordBuilderImpl.java @@ -439,6 +439,15 @@ public SingleTransactionRecordBuilderImpl memo(@NonNull final String memo) { // ------------------------------------------------------------------------------------------------------------------------ // fields needed for TransactionRecord + /** + * Gets the transaction object. + * + * @return the transaction object + */ + @NonNull + public Transaction transaction() { + return transaction; + } /** * Gets the consensus instant. * diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/state/RootProxyWorldUpdater.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/state/RootProxyWorldUpdater.java index cdf792dd88af..061ca6320c33 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/state/RootProxyWorldUpdater.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/state/RootProxyWorldUpdater.java @@ -102,7 +102,7 @@ public void commit() { context().ifPresent(context -> { final var creationCapacityIsAvailable = - context.shouldThrottleNOfUnscaled(createdContractIds.size(), CRYPTO_CREATE); + !context.shouldThrottleNOfUnscaled(createdContractIds.size(), CRYPTO_CREATE); validateTrue(creationCapacityIsAvailable, CONSENSUS_GAS_EXHAUSTED); }); From 841a22bc3208d15e85a56260ed5de47d3ada4539 Mon Sep 17 00:00:00 2001 From: Petar Tonev Date: Tue, 23 Jan 2024 16:53:01 +0200 Subject: [PATCH 15/34] fix: NullPointerException for some TXs yielding FAIL_INVALID --- .../hedera/node/app/workflows/handle/HandleContextImpl.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleContextImpl.java b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleContextImpl.java index 75635d1e9a52..144d8993665b 100644 --- a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleContextImpl.java +++ b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleContextImpl.java @@ -946,14 +946,15 @@ public boolean hasThrottleCapacityForChildTransactions() { throw new IllegalStateException("Invalid transaction body " + childTxBody, e); } - final var childTxInfo = new TransactionInfo( - childTx, childTxBody, childTx.sigMap(), childTx.signedTransactionBytes(), childTxFunctionality); if (childTxFunctionality == CONTRACT_CREATE || childTxFunctionality == CONTRACT_CALL) { continue; } if (snapshotsIfNeeded == null) { snapshotsIfNeeded = getUsageSnapshots(); } + + final var childTxInfo = new TransactionInfo( + childTx, childTxBody, childTx.sigMap(), childTx.signedTransactionBytes(), childTxFunctionality); if (shouldThrottleTxn(childTxInfo)) { isAllowed = false; } From 8830e255ac6c18360460c9da996802d91546885f Mon Sep 17 00:00:00 2001 From: Petar Tonev Date: Wed, 24 Jan 2024 10:48:33 +0200 Subject: [PATCH 16/34] fix: use context functionality instead of the one from child records --- .../com/hedera/node/app/workflows/handle/HandleContextImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleContextImpl.java b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleContextImpl.java index 144d8993665b..856ae9750c7f 100644 --- a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleContextImpl.java +++ b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleContextImpl.java @@ -946,7 +946,7 @@ public boolean hasThrottleCapacityForChildTransactions() { throw new IllegalStateException("Invalid transaction body " + childTxBody, e); } - if (childTxFunctionality == CONTRACT_CREATE || childTxFunctionality == CONTRACT_CALL) { + if (functionality == CONTRACT_CREATE || functionality == CONTRACT_CALL) { continue; } if (snapshotsIfNeeded == null) { From 5d1c362b7756be1ae10d1af184f06ab98e1e0082 Mon Sep 17 00:00:00 2001 From: Petar Tonev Date: Wed, 24 Jan 2024 12:01:08 +0200 Subject: [PATCH 17/34] fix: try adding both functionalities --- .../hedera/node/app/workflows/handle/HandleContextImpl.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleContextImpl.java b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleContextImpl.java index 856ae9750c7f..44b53f83c4e9 100644 --- a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleContextImpl.java +++ b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleContextImpl.java @@ -946,7 +946,10 @@ public boolean hasThrottleCapacityForChildTransactions() { throw new IllegalStateException("Invalid transaction body " + childTxBody, e); } - if (functionality == CONTRACT_CREATE || functionality == CONTRACT_CALL) { + if (functionality == CONTRACT_CREATE + || functionality == CONTRACT_CALL + || childTxFunctionality == CONTRACT_CREATE + || childTxFunctionality == CONTRACT_CALL) { continue; } if (snapshotsIfNeeded == null) { From c881553adf525accd01115f8270391df6e1a8815 Mon Sep 17 00:00:00 2001 From: Petar Tonev Date: Wed, 24 Jan 2024 13:25:45 +0200 Subject: [PATCH 18/34] fix: return to child functionalities --- .../hedera/node/app/workflows/handle/HandleContextImpl.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleContextImpl.java b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleContextImpl.java index 44b53f83c4e9..144d8993665b 100644 --- a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleContextImpl.java +++ b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleContextImpl.java @@ -946,10 +946,7 @@ public boolean hasThrottleCapacityForChildTransactions() { throw new IllegalStateException("Invalid transaction body " + childTxBody, e); } - if (functionality == CONTRACT_CREATE - || functionality == CONTRACT_CALL - || childTxFunctionality == CONTRACT_CREATE - || childTxFunctionality == CONTRACT_CALL) { + if (childTxFunctionality == CONTRACT_CREATE || childTxFunctionality == CONTRACT_CALL) { continue; } if (snapshotsIfNeeded == null) { From 90ecac37949bce0a685959eaa790890c3df5ae7d Mon Sep 17 00:00:00 2001 From: Petar Tonev Date: Mon, 29 Jan 2024 15:37:25 +0200 Subject: [PATCH 19/34] fix: mimic mono behaviour and return false if null is encountered --- .../app/throttle/ThrottleAccumulator.java | 52 ++++++++++--------- .../node/app/workflows/TransactionInfo.java | 27 +++++++++- .../workflows/handle/HandleContextImpl.java | 33 ++++++------ 3 files changed, 70 insertions(+), 42 deletions(-) diff --git a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/ThrottleAccumulator.java b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/ThrottleAccumulator.java index 9d5bc7852c54..efe56a38fa2d 100644 --- a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/ThrottleAccumulator.java +++ b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/ThrottleAccumulator.java @@ -16,23 +16,6 @@ package com.hedera.node.app.throttle; -import static com.hedera.hapi.node.base.HederaFunctionality.CONTRACT_CALL; -import static com.hedera.hapi.node.base.HederaFunctionality.CONTRACT_CALL_LOCAL; -import static com.hedera.hapi.node.base.HederaFunctionality.CONTRACT_CREATE; -import static com.hedera.hapi.node.base.HederaFunctionality.CRYPTO_CREATE; -import static com.hedera.hapi.node.base.HederaFunctionality.CRYPTO_TRANSFER; -import static com.hedera.hapi.node.base.HederaFunctionality.ETHEREUM_TRANSACTION; -import static com.hedera.node.app.hapi.utils.ethereum.EthTxData.populateEthTxData; -import static com.hedera.node.app.hapi.utils.sysfiles.domain.throttling.ScaleFactor.ONE_TO_ONE; -import static com.hedera.node.app.service.evm.accounts.HederaEvmContractAliases.isMirror; -import static com.hedera.node.app.service.mono.utils.EntityIdUtils.isOfEvmAddressSize; -import static com.hedera.node.app.service.schedule.impl.handlers.HandlerUtility.childAsOrdinary; -import static com.hedera.node.app.service.token.AliasUtils.isAlias; -import static com.hedera.node.app.service.token.AliasUtils.isSerializedProtoKey; -import static com.hedera.node.app.spi.HapiUtils.functionOf; -import static com.hedera.node.app.throttle.ThrottleAccumulator.ThrottleType.FRONTEND_THROTTLE; -import static java.util.Objects.requireNonNull; - import com.hedera.hapi.node.base.AccountAmount; import com.hedera.hapi.node.base.AccountID; import com.hedera.hapi.node.base.HederaFunctionality; @@ -71,6 +54,10 @@ import com.swirlds.config.api.Configuration; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; +import org.apache.commons.lang3.tuple.Pair; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + import java.math.BigInteger; import java.time.Instant; import java.util.ArrayList; @@ -83,9 +70,23 @@ import java.util.Optional; import java.util.Set; import java.util.function.IntSupplier; -import org.apache.commons.lang3.tuple.Pair; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; + +import static com.hedera.hapi.node.base.HederaFunctionality.CONTRACT_CALL; +import static com.hedera.hapi.node.base.HederaFunctionality.CONTRACT_CALL_LOCAL; +import static com.hedera.hapi.node.base.HederaFunctionality.CONTRACT_CREATE; +import static com.hedera.hapi.node.base.HederaFunctionality.CRYPTO_CREATE; +import static com.hedera.hapi.node.base.HederaFunctionality.CRYPTO_TRANSFER; +import static com.hedera.hapi.node.base.HederaFunctionality.ETHEREUM_TRANSACTION; +import static com.hedera.node.app.hapi.utils.ethereum.EthTxData.populateEthTxData; +import static com.hedera.node.app.hapi.utils.sysfiles.domain.throttling.ScaleFactor.ONE_TO_ONE; +import static com.hedera.node.app.service.evm.accounts.HederaEvmContractAliases.isMirror; +import static com.hedera.node.app.service.mono.utils.EntityIdUtils.isOfEvmAddressSize; +import static com.hedera.node.app.service.schedule.impl.handlers.HandlerUtility.childAsOrdinary; +import static com.hedera.node.app.service.token.AliasUtils.isAlias; +import static com.hedera.node.app.service.token.AliasUtils.isSerializedProtoKey; +import static com.hedera.node.app.spi.HapiUtils.functionOf; +import static com.hedera.node.app.throttle.ThrottleAccumulator.ThrottleType.FRONTEND_THROTTLE; +import static java.util.Objects.requireNonNull; /** * Keeps track of the amount of usage of different TPS throttle categories and gas, and returns whether a given @@ -497,13 +498,16 @@ private boolean shouldThrottleScheduleSign( } public static boolean throttleExempt( - @NonNull final AccountID accountID, @NonNull final Configuration configuration) { + @Nullable final AccountID accountID, @NonNull final Configuration configuration) { final long maxThrottleExemptNum = configuration.getConfigData(AccountsConfig.class).lastThrottleExempt(); - final long accountNum = accountID.accountNum().longValue(); - return 1L <= accountNum && accountNum <= maxThrottleExemptNum; + try { + final long accountNum = accountID.accountNum().longValue(); + return 1L <= accountNum && accountNum <= maxThrottleExemptNum; + } catch (NullPointerException e) { + return false; + } } - private void reclaimLastAllowedUse() { activeThrottles.forEach(DeterministicThrottle::reclaimLastAllowedUse); if (gasThrottle != null) { diff --git a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/TransactionInfo.java b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/TransactionInfo.java index 6ec2115b39d2..0420a0c89894 100644 --- a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/TransactionInfo.java +++ b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/TransactionInfo.java @@ -25,6 +25,7 @@ import com.hedera.hapi.node.transaction.TransactionBody; import com.hedera.pbj.runtime.io.buffer.Bytes; import edu.umd.cs.findbugs.annotations.NonNull; +import edu.umd.cs.findbugs.annotations.Nullable; /** * Contains information related to a parsed transaction. @@ -49,8 +50,8 @@ public record TransactionInfo( @NonNull Transaction transaction, @NonNull TransactionBody txBody, - @NonNull TransactionID transactionID, - @NonNull AccountID payerID, + @Nullable TransactionID transactionID, + @Nullable AccountID payerID, @NonNull SignatureMap signatureMap, @NonNull Bytes signedBytes, @NonNull HederaFunctionality functionality) { @@ -70,4 +71,26 @@ public TransactionInfo( signedBytes, functionality); } + + static public TransactionInfo from(@NonNull Transaction transaction, + @NonNull TransactionBody txBody, + @NonNull SignatureMap signatureMap, + @NonNull Bytes signedBytes, + @NonNull HederaFunctionality functionality) { + TransactionID transactionId = null; + AccountID payerId = null; + if (txBody.transactionID() != null) { + transactionId = txBody.transactionID(); + if (transactionId.accountID() != null) { + payerId = txBody.transactionID().accountID(); + } + } + return new TransactionInfo(transaction, + txBody, + transactionId, + payerId, + signatureMap, + signedBytes, + functionality); + } } diff --git a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleContextImpl.java b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleContextImpl.java index 144d8993665b..2542055d922d 100644 --- a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleContextImpl.java +++ b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleContextImpl.java @@ -16,19 +16,6 @@ package com.hedera.node.app.workflows.handle; -import static com.hedera.hapi.node.base.HederaFunctionality.CONTRACT_CALL; -import static com.hedera.hapi.node.base.HederaFunctionality.CONTRACT_CREATE; -import static com.hedera.hapi.node.base.ResponseCodeEnum.DUPLICATE_TRANSACTION; -import static com.hedera.hapi.node.base.ResponseCodeEnum.INVALID_SIGNATURE; -import static com.hedera.hapi.node.base.ResponseCodeEnum.SUCCESS; -import static com.hedera.node.app.spi.HapiUtils.functionOf; -import static com.hedera.node.app.spi.workflows.HandleContext.TransactionCategory.CHILD; -import static com.hedera.node.app.spi.workflows.HandleContext.TransactionCategory.PRECEDING; -import static com.hedera.node.app.spi.workflows.HandleContext.TransactionCategory.SCHEDULED; -import static com.hedera.node.app.state.HederaRecordCache.DuplicateCheckResult.NO_DUPLICATE; -import static com.hedera.node.app.workflows.handle.HandleContextImpl.PrecedingTransactionCategory.LIMITED_CHILD_RECORDS; -import static java.util.Objects.requireNonNull; - import com.hedera.hapi.node.base.AccountID; import com.hedera.hapi.node.base.HederaFunctionality; import com.hedera.hapi.node.base.Key; @@ -98,14 +85,28 @@ import com.swirlds.config.api.Configuration; 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; + import java.time.Instant; import java.util.List; import java.util.Objects; import java.util.function.Function; import java.util.function.Predicate; import java.util.function.Supplier; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; + +import static com.hedera.hapi.node.base.HederaFunctionality.CONTRACT_CALL; +import static com.hedera.hapi.node.base.HederaFunctionality.CONTRACT_CREATE; +import static com.hedera.hapi.node.base.ResponseCodeEnum.DUPLICATE_TRANSACTION; +import static com.hedera.hapi.node.base.ResponseCodeEnum.INVALID_SIGNATURE; +import static com.hedera.hapi.node.base.ResponseCodeEnum.SUCCESS; +import static com.hedera.node.app.spi.HapiUtils.functionOf; +import static com.hedera.node.app.spi.workflows.HandleContext.TransactionCategory.CHILD; +import static com.hedera.node.app.spi.workflows.HandleContext.TransactionCategory.PRECEDING; +import static com.hedera.node.app.spi.workflows.HandleContext.TransactionCategory.SCHEDULED; +import static com.hedera.node.app.state.HederaRecordCache.DuplicateCheckResult.NO_DUPLICATE; +import static com.hedera.node.app.workflows.handle.HandleContextImpl.PrecedingTransactionCategory.LIMITED_CHILD_RECORDS; +import static java.util.Objects.requireNonNull; /** * The default implementation of {@link HandleContext}. @@ -953,7 +954,7 @@ public boolean hasThrottleCapacityForChildTransactions() { snapshotsIfNeeded = getUsageSnapshots(); } - final var childTxInfo = new TransactionInfo( + final var childTxInfo = TransactionInfo.from( childTx, childTxBody, childTx.sigMap(), childTx.signedTransactionBytes(), childTxFunctionality); if (shouldThrottleTxn(childTxInfo)) { isAllowed = false; From e7722994e6261866f3fd3580686671e563b1674a Mon Sep 17 00:00:00 2001 From: Petar Tonev Date: Mon, 29 Jan 2024 15:41:46 +0200 Subject: [PATCH 20/34] fix: apply spotless --- .../app/throttle/ThrottleAccumulator.java | 42 +++++++++---------- .../node/app/workflows/TransactionInfo.java | 20 ++++----- .../workflows/handle/HandleContextImpl.java | 31 +++++++------- 3 files changed, 44 insertions(+), 49 deletions(-) diff --git a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/ThrottleAccumulator.java b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/ThrottleAccumulator.java index efe56a38fa2d..9af9e1f49c9d 100644 --- a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/ThrottleAccumulator.java +++ b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/ThrottleAccumulator.java @@ -16,6 +16,23 @@ package com.hedera.node.app.throttle; +import static com.hedera.hapi.node.base.HederaFunctionality.CONTRACT_CALL; +import static com.hedera.hapi.node.base.HederaFunctionality.CONTRACT_CALL_LOCAL; +import static com.hedera.hapi.node.base.HederaFunctionality.CONTRACT_CREATE; +import static com.hedera.hapi.node.base.HederaFunctionality.CRYPTO_CREATE; +import static com.hedera.hapi.node.base.HederaFunctionality.CRYPTO_TRANSFER; +import static com.hedera.hapi.node.base.HederaFunctionality.ETHEREUM_TRANSACTION; +import static com.hedera.node.app.hapi.utils.ethereum.EthTxData.populateEthTxData; +import static com.hedera.node.app.hapi.utils.sysfiles.domain.throttling.ScaleFactor.ONE_TO_ONE; +import static com.hedera.node.app.service.evm.accounts.HederaEvmContractAliases.isMirror; +import static com.hedera.node.app.service.mono.utils.EntityIdUtils.isOfEvmAddressSize; +import static com.hedera.node.app.service.schedule.impl.handlers.HandlerUtility.childAsOrdinary; +import static com.hedera.node.app.service.token.AliasUtils.isAlias; +import static com.hedera.node.app.service.token.AliasUtils.isSerializedProtoKey; +import static com.hedera.node.app.spi.HapiUtils.functionOf; +import static com.hedera.node.app.throttle.ThrottleAccumulator.ThrottleType.FRONTEND_THROTTLE; +import static java.util.Objects.requireNonNull; + import com.hedera.hapi.node.base.AccountAmount; import com.hedera.hapi.node.base.AccountID; import com.hedera.hapi.node.base.HederaFunctionality; @@ -54,10 +71,6 @@ import com.swirlds.config.api.Configuration; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; -import org.apache.commons.lang3.tuple.Pair; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - import java.math.BigInteger; import java.time.Instant; import java.util.ArrayList; @@ -70,23 +83,9 @@ import java.util.Optional; import java.util.Set; import java.util.function.IntSupplier; - -import static com.hedera.hapi.node.base.HederaFunctionality.CONTRACT_CALL; -import static com.hedera.hapi.node.base.HederaFunctionality.CONTRACT_CALL_LOCAL; -import static com.hedera.hapi.node.base.HederaFunctionality.CONTRACT_CREATE; -import static com.hedera.hapi.node.base.HederaFunctionality.CRYPTO_CREATE; -import static com.hedera.hapi.node.base.HederaFunctionality.CRYPTO_TRANSFER; -import static com.hedera.hapi.node.base.HederaFunctionality.ETHEREUM_TRANSACTION; -import static com.hedera.node.app.hapi.utils.ethereum.EthTxData.populateEthTxData; -import static com.hedera.node.app.hapi.utils.sysfiles.domain.throttling.ScaleFactor.ONE_TO_ONE; -import static com.hedera.node.app.service.evm.accounts.HederaEvmContractAliases.isMirror; -import static com.hedera.node.app.service.mono.utils.EntityIdUtils.isOfEvmAddressSize; -import static com.hedera.node.app.service.schedule.impl.handlers.HandlerUtility.childAsOrdinary; -import static com.hedera.node.app.service.token.AliasUtils.isAlias; -import static com.hedera.node.app.service.token.AliasUtils.isSerializedProtoKey; -import static com.hedera.node.app.spi.HapiUtils.functionOf; -import static com.hedera.node.app.throttle.ThrottleAccumulator.ThrottleType.FRONTEND_THROTTLE; -import static java.util.Objects.requireNonNull; +import org.apache.commons.lang3.tuple.Pair; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; /** * Keeps track of the amount of usage of different TPS throttle categories and gas, and returns whether a given @@ -508,6 +507,7 @@ public static boolean throttleExempt( return false; } } + private void reclaimLastAllowedUse() { activeThrottles.forEach(DeterministicThrottle::reclaimLastAllowedUse); if (gasThrottle != null) { diff --git a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/TransactionInfo.java b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/TransactionInfo.java index 0420a0c89894..9464b216328a 100644 --- a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/TransactionInfo.java +++ b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/TransactionInfo.java @@ -72,11 +72,12 @@ public TransactionInfo( functionality); } - static public TransactionInfo from(@NonNull Transaction transaction, - @NonNull TransactionBody txBody, - @NonNull SignatureMap signatureMap, - @NonNull Bytes signedBytes, - @NonNull HederaFunctionality functionality) { + public static TransactionInfo from( + @NonNull Transaction transaction, + @NonNull TransactionBody txBody, + @NonNull SignatureMap signatureMap, + @NonNull Bytes signedBytes, + @NonNull HederaFunctionality functionality) { TransactionID transactionId = null; AccountID payerId = null; if (txBody.transactionID() != null) { @@ -85,12 +86,7 @@ static public TransactionInfo from(@NonNull Transaction transaction, payerId = txBody.transactionID().accountID(); } } - return new TransactionInfo(transaction, - txBody, - transactionId, - payerId, - signatureMap, - signedBytes, - functionality); + return new TransactionInfo( + transaction, txBody, transactionId, payerId, signatureMap, signedBytes, functionality); } } diff --git a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleContextImpl.java b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleContextImpl.java index 2542055d922d..f9851c74e1bc 100644 --- a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleContextImpl.java +++ b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleContextImpl.java @@ -16,6 +16,19 @@ package com.hedera.node.app.workflows.handle; +import static com.hedera.hapi.node.base.HederaFunctionality.CONTRACT_CALL; +import static com.hedera.hapi.node.base.HederaFunctionality.CONTRACT_CREATE; +import static com.hedera.hapi.node.base.ResponseCodeEnum.DUPLICATE_TRANSACTION; +import static com.hedera.hapi.node.base.ResponseCodeEnum.INVALID_SIGNATURE; +import static com.hedera.hapi.node.base.ResponseCodeEnum.SUCCESS; +import static com.hedera.node.app.spi.HapiUtils.functionOf; +import static com.hedera.node.app.spi.workflows.HandleContext.TransactionCategory.CHILD; +import static com.hedera.node.app.spi.workflows.HandleContext.TransactionCategory.PRECEDING; +import static com.hedera.node.app.spi.workflows.HandleContext.TransactionCategory.SCHEDULED; +import static com.hedera.node.app.state.HederaRecordCache.DuplicateCheckResult.NO_DUPLICATE; +import static com.hedera.node.app.workflows.handle.HandleContextImpl.PrecedingTransactionCategory.LIMITED_CHILD_RECORDS; +import static java.util.Objects.requireNonNull; + import com.hedera.hapi.node.base.AccountID; import com.hedera.hapi.node.base.HederaFunctionality; import com.hedera.hapi.node.base.Key; @@ -85,28 +98,14 @@ import com.swirlds.config.api.Configuration; 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; - import java.time.Instant; import java.util.List; import java.util.Objects; import java.util.function.Function; import java.util.function.Predicate; import java.util.function.Supplier; - -import static com.hedera.hapi.node.base.HederaFunctionality.CONTRACT_CALL; -import static com.hedera.hapi.node.base.HederaFunctionality.CONTRACT_CREATE; -import static com.hedera.hapi.node.base.ResponseCodeEnum.DUPLICATE_TRANSACTION; -import static com.hedera.hapi.node.base.ResponseCodeEnum.INVALID_SIGNATURE; -import static com.hedera.hapi.node.base.ResponseCodeEnum.SUCCESS; -import static com.hedera.node.app.spi.HapiUtils.functionOf; -import static com.hedera.node.app.spi.workflows.HandleContext.TransactionCategory.CHILD; -import static com.hedera.node.app.spi.workflows.HandleContext.TransactionCategory.PRECEDING; -import static com.hedera.node.app.spi.workflows.HandleContext.TransactionCategory.SCHEDULED; -import static com.hedera.node.app.state.HederaRecordCache.DuplicateCheckResult.NO_DUPLICATE; -import static com.hedera.node.app.workflows.handle.HandleContextImpl.PrecedingTransactionCategory.LIMITED_CHILD_RECORDS; -import static java.util.Objects.requireNonNull; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; /** * The default implementation of {@link HandleContext}. From c3eadf8661edc7866b8a89effefbdb4bb71ff553 Mon Sep 17 00:00:00 2001 From: Petar Tonev Date: Tue, 30 Jan 2024 12:08:28 +0200 Subject: [PATCH 21/34] fix: refactor after changing the approach --- .../com/hedera/node/app/throttle/ThrottleAccumulator.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/ThrottleAccumulator.java b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/ThrottleAccumulator.java index 9af9e1f49c9d..1d0cddbfd6ab 100644 --- a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/ThrottleAccumulator.java +++ b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/ThrottleAccumulator.java @@ -500,12 +500,11 @@ public static boolean throttleExempt( @Nullable final AccountID accountID, @NonNull final Configuration configuration) { final long maxThrottleExemptNum = configuration.getConfigData(AccountsConfig.class).lastThrottleExempt(); - try { + if (accountID != null) { final long accountNum = accountID.accountNum().longValue(); return 1L <= accountNum && accountNum <= maxThrottleExemptNum; - } catch (NullPointerException e) { - return false; } + return false; } private void reclaimLastAllowedUse() { From 1da1cd7dee23472cb8539493652b66fcd59c23cd Mon Sep 17 00:00:00 2001 From: Petar Tonev Date: Thu, 1 Feb 2024 16:33:04 +0200 Subject: [PATCH 22/34] fix: update decision time before using it in frontend throttle --- .../SynchronizedThrottleAccumulator.java | 16 ++++++++-------- .../app/workflows/handle/HandleContextImpl.java | 2 +- .../app/workflows/query/QueryContextImpl.java | 7 +------ .../app/workflows/query/QueryWorkflowImpl.java | 2 -- 4 files changed, 10 insertions(+), 17 deletions(-) diff --git a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/SynchronizedThrottleAccumulator.java b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/SynchronizedThrottleAccumulator.java index bce71e0e7366..55c87dfc368c 100644 --- a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/SynchronizedThrottleAccumulator.java +++ b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/SynchronizedThrottleAccumulator.java @@ -71,17 +71,17 @@ public synchronized boolean shouldThrottle(HederaFunctionality queryFunction, Qu return frontendThrottle.shouldThrottle(queryFunction, lastDecisionTime, query, queryPayerId); } - private void setDecisionTime() { - final var now = Instant.now(); - lastDecisionTime = now.isBefore(lastDecisionTime) ? lastDecisionTime : now; - } - public void leakUnusedThrottlePreviouslyReserved(int n, HederaFunctionality function) { frontendThrottle.leakCapacityForNOfUnscaled(n, function); } - public boolean shouldThrottleNOfUnscaled( - final int n, @NonNull final HederaFunctionality function, @NonNull final Instant consensusTime) { - return frontendThrottle.shouldThrottleNOfUnscaled(n, function, consensusTime); + public boolean shouldThrottleNOfUnscaled(final int n, @NonNull final HederaFunctionality function) { + setDecisionTime(); + return frontendThrottle.shouldThrottleNOfUnscaled(n, function, lastDecisionTime); + } + + private void setDecisionTime() { + final var now = Instant.now(); + lastDecisionTime = now.isBefore(lastDecisionTime) ? lastDecisionTime : now; } } diff --git a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleContextImpl.java b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleContextImpl.java index f9851c74e1bc..f356a5cb881e 100644 --- a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleContextImpl.java +++ b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleContextImpl.java @@ -911,7 +911,7 @@ public void reclaimPreviouslyReservedThrottle(int n, HederaFunctionality functio @Override public boolean shouldThrottleNOfUnscaled(int n, HederaFunctionality function) { - return synchronizedThrottleAccumulator.shouldThrottleNOfUnscaled(n, function, userTransactionConsensusTime); + return synchronizedThrottleAccumulator.shouldThrottleNOfUnscaled(n, function); } public boolean shouldThrottleTxn(TransactionInfo txInfo) { diff --git a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/query/QueryContextImpl.java b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/query/QueryContextImpl.java index ab29e9bedb1d..5035f4c45ecc 100644 --- a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/query/QueryContextImpl.java +++ b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/query/QueryContextImpl.java @@ -37,7 +37,6 @@ import com.swirlds.config.api.Configuration; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; -import java.time.Instant; /** * Simple implementation of {@link QueryContext}. @@ -52,7 +51,6 @@ public class QueryContextImpl implements QueryContext { private final ExchangeRateManager exchangeRateManager; private final AccountID payer; private final FeeCalculator feeCalculator; - private final Instant userQueryConsensusTime; private final SynchronizedThrottleAccumulator synchronizedThrottleAccumulator; private BlockRecordInfo blockRecordInfo; // lazily created private ExchangeRateInfo exchangeRateInfo; // lazily created @@ -67,7 +65,6 @@ public class QueryContextImpl implements QueryContext { * @param recordCache the {@link RecordCache} used to cache records * @param exchangeRateManager the {@link ExchangeRateManager} used to get the current exchange rate * @param feeCalculator the {@link FeeCalculator} used to calculate fees - * @param userQueryConsensusTime the query time * @param synchronizedThrottleAccumulator The {@link SynchronizedThrottleAccumulator} used to manage the tracking of network throttling * @param payer the {@link AccountID} of the payer, if present * @throws NullPointerException if {@code query} is {@code null} @@ -80,7 +77,6 @@ public QueryContextImpl( @NonNull final RecordCache recordCache, @NonNull final ExchangeRateManager exchangeRateManager, @NonNull final FeeCalculator feeCalculator, - @NonNull final Instant userQueryConsensusTime, @NonNull final SynchronizedThrottleAccumulator synchronizedThrottleAccumulator, @Nullable final AccountID payer) { this.state = requireNonNull(state, "state must not be null"); @@ -90,7 +86,6 @@ public QueryContextImpl( this.recordCache = requireNonNull(recordCache, "recordCache must not be null"); this.exchangeRateManager = requireNonNull(exchangeRateManager, "exchangeRateManager must not be null"); this.feeCalculator = requireNonNull(feeCalculator, "feeCalculator must not be null"); - this.userQueryConsensusTime = requireNonNull(userQueryConsensusTime, "userQueryConsensusTime must not be null"); ; this.synchronizedThrottleAccumulator = requireNonNull(synchronizedThrottleAccumulator, "synchronizedThrottleAccumulator must not be null"); @@ -161,7 +156,7 @@ public FeeCalculator feeCalculator() { @Override public boolean shouldThrottleNOfUnscaled(int n, HederaFunctionality function) { - return synchronizedThrottleAccumulator.shouldThrottleNOfUnscaled(n, function, userQueryConsensusTime); + return synchronizedThrottleAccumulator.shouldThrottleNOfUnscaled(n, function); } @Override diff --git a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/query/QueryWorkflowImpl.java b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/query/QueryWorkflowImpl.java index 851736d795ec..fe6c0f1e41bc 100644 --- a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/query/QueryWorkflowImpl.java +++ b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/query/QueryWorkflowImpl.java @@ -211,7 +211,6 @@ public void handleQuery(@NonNull final Bytes requestBuffer, @NonNull final Buffe recordCache, exchangeRateManager, feeCalculator, - consensusTime, synchronizedThrottleAccumulator, payerID); @@ -256,7 +255,6 @@ public void handleQuery(@NonNull final Bytes requestBuffer, @NonNull final Buffe recordCache, exchangeRateManager, feeCalculator, - consensusTime, synchronizedThrottleAccumulator, null); } From a8219b10bd2b61822a32597f78cb6c45d04afa2c Mon Sep 17 00:00:00 2001 From: Petar Tonev Date: Thu, 1 Feb 2024 16:39:07 +0200 Subject: [PATCH 23/34] fix: fix constructor issue --- .../hedera-app/src/xtest/java/common/BaseScaffoldingModule.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/hedera-node/hedera-app/src/xtest/java/common/BaseScaffoldingModule.java b/hedera-node/hedera-app/src/xtest/java/common/BaseScaffoldingModule.java index 3865929dafcc..d19b568bf855 100644 --- a/hedera-node/hedera-app/src/xtest/java/common/BaseScaffoldingModule.java +++ b/hedera-node/hedera-app/src/xtest/java/common/BaseScaffoldingModule.java @@ -221,7 +221,6 @@ static BiFunction provideQueryContextFactory( @NonNull final Configuration configuration, @NonNull final ExchangeRateManager exchangeRateManager, @NonNull final SynchronizedThrottleAccumulator synchronizedThrottleAccumulator) { - final var consensusTime = Instant.now(); return (query, payerId) -> new QueryContextImpl( state, new ReadableStoreFactory(state), @@ -230,7 +229,6 @@ static BiFunction provideQueryContextFactory( recordCache, exchangeRateManager, NoOpFeeCalculator.INSTANCE, - consensusTime, synchronizedThrottleAccumulator, payerId); } From ad4cebfe95dfc73722bf08da8d7fe0c813282851 Mon Sep 17 00:00:00 2001 From: Petar Tonev Date: Mon, 5 Feb 2024 13:49:09 +0200 Subject: [PATCH 24/34] fix: update decision time after checks --- .../node/app/throttle/SynchronizedThrottleAccumulator.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/SynchronizedThrottleAccumulator.java b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/SynchronizedThrottleAccumulator.java index 55c87dfc368c..e4e935b8b407 100644 --- a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/SynchronizedThrottleAccumulator.java +++ b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/SynchronizedThrottleAccumulator.java @@ -77,7 +77,9 @@ public void leakUnusedThrottlePreviouslyReserved(int n, HederaFunctionality func public boolean shouldThrottleNOfUnscaled(final int n, @NonNull final HederaFunctionality function) { setDecisionTime(); - return frontendThrottle.shouldThrottleNOfUnscaled(n, function, lastDecisionTime); + final var decision = frontendThrottle.shouldThrottleNOfUnscaled(n, function, lastDecisionTime); + setDecisionTime(); + return decision; } private void setDecisionTime() { From b8818f7ce59bd9f85e90103bd3e9aa1e77955203 Mon Sep 17 00:00:00 2001 From: Petar Tonev Date: Mon, 5 Feb 2024 17:43:47 +0200 Subject: [PATCH 25/34] fix: try with userTransactionConsensusTime --- .../SynchronizedThrottleAccumulator.java | 18 ++++++++---------- .../workflows/handle/HandleContextImpl.java | 2 +- .../app/workflows/query/QueryContextImpl.java | 7 ++++++- .../app/workflows/query/QueryWorkflowImpl.java | 2 ++ .../java/common/BaseScaffoldingModule.java | 2 ++ 5 files changed, 19 insertions(+), 12 deletions(-) diff --git a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/SynchronizedThrottleAccumulator.java b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/SynchronizedThrottleAccumulator.java index e4e935b8b407..b07c4cc1225d 100644 --- a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/SynchronizedThrottleAccumulator.java +++ b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/SynchronizedThrottleAccumulator.java @@ -53,7 +53,7 @@ public SynchronizedThrottleAccumulator(ThrottleAccumulator frontendThrottle) { * @return whether the transaction should be throttled */ public synchronized boolean shouldThrottle(@NonNull TransactionInfo txnInfo, HederaState state) { - setDecisionTime(); + setDecisionTime(Instant.now()); return frontendThrottle.shouldThrottle(txnInfo, lastDecisionTime, state); } @@ -67,7 +67,7 @@ public synchronized boolean shouldThrottle(@NonNull TransactionInfo txnInfo, Hed * @return whether the query should be throttled */ public synchronized boolean shouldThrottle(HederaFunctionality queryFunction, Query query, AccountID queryPayerId) { - setDecisionTime(); + setDecisionTime(Instant.now()); return frontendThrottle.shouldThrottle(queryFunction, lastDecisionTime, query, queryPayerId); } @@ -75,15 +75,13 @@ public void leakUnusedThrottlePreviouslyReserved(int n, HederaFunctionality func frontendThrottle.leakCapacityForNOfUnscaled(n, function); } - public boolean shouldThrottleNOfUnscaled(final int n, @NonNull final HederaFunctionality function) { - setDecisionTime(); - final var decision = frontendThrottle.shouldThrottleNOfUnscaled(n, function, lastDecisionTime); - setDecisionTime(); - return decision; + public boolean shouldThrottleNOfUnscaled( + final int n, @NonNull final HederaFunctionality function, @NonNull final Instant consensusTime) { + setDecisionTime(consensusTime); + return frontendThrottle.shouldThrottleNOfUnscaled(n, function, lastDecisionTime); } - private void setDecisionTime() { - final var now = Instant.now(); - lastDecisionTime = now.isBefore(lastDecisionTime) ? lastDecisionTime : now; + private void setDecisionTime(@NonNull final Instant time) { + lastDecisionTime = time.isBefore(lastDecisionTime) ? lastDecisionTime : time; } } diff --git a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleContextImpl.java b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleContextImpl.java index 45b8105100f0..e9ef0f4eb13a 100644 --- a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleContextImpl.java +++ b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleContextImpl.java @@ -916,7 +916,7 @@ public void reclaimPreviouslyReservedThrottle(int n, HederaFunctionality functio @Override public boolean shouldThrottleNOfUnscaled(int n, HederaFunctionality function) { - return synchronizedThrottleAccumulator.shouldThrottleNOfUnscaled(n, function); + return synchronizedThrottleAccumulator.shouldThrottleNOfUnscaled(n, function, userTransactionConsensusTime); } public boolean shouldThrottleTxn(TransactionInfo txInfo) { diff --git a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/query/QueryContextImpl.java b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/query/QueryContextImpl.java index 5035f4c45ecc..ab29e9bedb1d 100644 --- a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/query/QueryContextImpl.java +++ b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/query/QueryContextImpl.java @@ -37,6 +37,7 @@ import com.swirlds.config.api.Configuration; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; +import java.time.Instant; /** * Simple implementation of {@link QueryContext}. @@ -51,6 +52,7 @@ public class QueryContextImpl implements QueryContext { private final ExchangeRateManager exchangeRateManager; private final AccountID payer; private final FeeCalculator feeCalculator; + private final Instant userQueryConsensusTime; private final SynchronizedThrottleAccumulator synchronizedThrottleAccumulator; private BlockRecordInfo blockRecordInfo; // lazily created private ExchangeRateInfo exchangeRateInfo; // lazily created @@ -65,6 +67,7 @@ public class QueryContextImpl implements QueryContext { * @param recordCache the {@link RecordCache} used to cache records * @param exchangeRateManager the {@link ExchangeRateManager} used to get the current exchange rate * @param feeCalculator the {@link FeeCalculator} used to calculate fees + * @param userQueryConsensusTime the query time * @param synchronizedThrottleAccumulator The {@link SynchronizedThrottleAccumulator} used to manage the tracking of network throttling * @param payer the {@link AccountID} of the payer, if present * @throws NullPointerException if {@code query} is {@code null} @@ -77,6 +80,7 @@ public QueryContextImpl( @NonNull final RecordCache recordCache, @NonNull final ExchangeRateManager exchangeRateManager, @NonNull final FeeCalculator feeCalculator, + @NonNull final Instant userQueryConsensusTime, @NonNull final SynchronizedThrottleAccumulator synchronizedThrottleAccumulator, @Nullable final AccountID payer) { this.state = requireNonNull(state, "state must not be null"); @@ -86,6 +90,7 @@ public QueryContextImpl( this.recordCache = requireNonNull(recordCache, "recordCache must not be null"); this.exchangeRateManager = requireNonNull(exchangeRateManager, "exchangeRateManager must not be null"); this.feeCalculator = requireNonNull(feeCalculator, "feeCalculator must not be null"); + this.userQueryConsensusTime = requireNonNull(userQueryConsensusTime, "userQueryConsensusTime must not be null"); ; this.synchronizedThrottleAccumulator = requireNonNull(synchronizedThrottleAccumulator, "synchronizedThrottleAccumulator must not be null"); @@ -156,7 +161,7 @@ public FeeCalculator feeCalculator() { @Override public boolean shouldThrottleNOfUnscaled(int n, HederaFunctionality function) { - return synchronizedThrottleAccumulator.shouldThrottleNOfUnscaled(n, function); + return synchronizedThrottleAccumulator.shouldThrottleNOfUnscaled(n, function, userQueryConsensusTime); } @Override diff --git a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/query/QueryWorkflowImpl.java b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/query/QueryWorkflowImpl.java index fe6c0f1e41bc..851736d795ec 100644 --- a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/query/QueryWorkflowImpl.java +++ b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/query/QueryWorkflowImpl.java @@ -211,6 +211,7 @@ public void handleQuery(@NonNull final Bytes requestBuffer, @NonNull final Buffe recordCache, exchangeRateManager, feeCalculator, + consensusTime, synchronizedThrottleAccumulator, payerID); @@ -255,6 +256,7 @@ public void handleQuery(@NonNull final Bytes requestBuffer, @NonNull final Buffe recordCache, exchangeRateManager, feeCalculator, + consensusTime, synchronizedThrottleAccumulator, null); } diff --git a/hedera-node/hedera-app/src/xtest/java/common/BaseScaffoldingModule.java b/hedera-node/hedera-app/src/xtest/java/common/BaseScaffoldingModule.java index d19b568bf855..3865929dafcc 100644 --- a/hedera-node/hedera-app/src/xtest/java/common/BaseScaffoldingModule.java +++ b/hedera-node/hedera-app/src/xtest/java/common/BaseScaffoldingModule.java @@ -221,6 +221,7 @@ static BiFunction provideQueryContextFactory( @NonNull final Configuration configuration, @NonNull final ExchangeRateManager exchangeRateManager, @NonNull final SynchronizedThrottleAccumulator synchronizedThrottleAccumulator) { + final var consensusTime = Instant.now(); return (query, payerId) -> new QueryContextImpl( state, new ReadableStoreFactory(state), @@ -229,6 +230,7 @@ static BiFunction provideQueryContextFactory( recordCache, exchangeRateManager, NoOpFeeCalculator.INSTANCE, + consensusTime, synchronizedThrottleAccumulator, payerId); } From 0d18a80ad6241e1764e3677346d7fbf44c57c333 Mon Sep 17 00:00:00 2001 From: Petar Tonev Date: Mon, 5 Feb 2024 23:56:17 +0200 Subject: [PATCH 26/34] fix: test cli workflow --- .../com/hedera/node/app/workflows/handle/HandleWorkflow.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleWorkflow.java b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleWorkflow.java index 3a9e4b1c28db..1bea02478393 100644 --- a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleWorkflow.java +++ b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleWorkflow.java @@ -276,7 +276,7 @@ private void handlePlatformTransaction( @NonNull final ConsensusTransaction platformTxn) { // Get the consensus timestamp. FUTURE We want this to exactly match the consensus timestamp from the hashgraph, // but for compatibility with the current implementation, we adjust it as follows. - final Instant consensusNow = platformTxn.getConsensusTimestamp().minusNanos(1000 - 3L); + final Instant consensusNow = platformTxn.getConsensusTimestamp().minusNanos(1000); // handle user transaction handleUserTransaction(consensusNow, state, platformState, platformEvent, creator, platformTxn); From 80ce68552ff1f3e9b17577d126223cb169a3403d Mon Sep 17 00:00:00 2001 From: Petar Tonev Date: Tue, 6 Feb 2024 10:07:39 +0200 Subject: [PATCH 27/34] fix: test cli workflow --- .../node/app/throttle/SynchronizedThrottleAccumulator.java | 4 +++- .../com/hedera/node/app/workflows/handle/HandleWorkflow.java | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/SynchronizedThrottleAccumulator.java b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/SynchronizedThrottleAccumulator.java index b07c4cc1225d..eca2dd9741c5 100644 --- a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/SynchronizedThrottleAccumulator.java +++ b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/SynchronizedThrottleAccumulator.java @@ -78,7 +78,9 @@ public void leakUnusedThrottlePreviouslyReserved(int n, HederaFunctionality func public boolean shouldThrottleNOfUnscaled( final int n, @NonNull final HederaFunctionality function, @NonNull final Instant consensusTime) { setDecisionTime(consensusTime); - return frontendThrottle.shouldThrottleNOfUnscaled(n, function, lastDecisionTime); + final var decision = frontendThrottle.shouldThrottleNOfUnscaled(n, function, lastDecisionTime); + setDecisionTime(consensusTime); + return decision; } private void setDecisionTime(@NonNull final Instant time) { diff --git a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleWorkflow.java b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleWorkflow.java index 1bea02478393..3a9e4b1c28db 100644 --- a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleWorkflow.java +++ b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleWorkflow.java @@ -276,7 +276,7 @@ private void handlePlatformTransaction( @NonNull final ConsensusTransaction platformTxn) { // Get the consensus timestamp. FUTURE We want this to exactly match the consensus timestamp from the hashgraph, // but for compatibility with the current implementation, we adjust it as follows. - final Instant consensusNow = platformTxn.getConsensusTimestamp().minusNanos(1000); + final Instant consensusNow = platformTxn.getConsensusTimestamp().minusNanos(1000 - 3L); // handle user transaction handleUserTransaction(consensusNow, state, platformState, platformEvent, creator, platformTxn); From 77f847018266b63ccfff3839bc927b5bf3d6736c Mon Sep 17 00:00:00 2001 From: Petar Tonev Date: Tue, 6 Feb 2024 12:48:09 +0200 Subject: [PATCH 28/34] fix: use the backend throttle instead --- .../app/throttle/NetworkUtilizationManager.java | 13 +++++++++++++ .../impl/NetworkUtilizationManagerImpl.java | 7 +++++++ .../app/workflows/handle/HandleContextImpl.java | 2 +- .../app/workflows/query/QueryContextImpl.java | 15 +-------------- .../app/workflows/query/QueryWorkflowImpl.java | 4 ---- .../xtest/java/common/BaseScaffoldingModule.java | 2 -- 6 files changed, 22 insertions(+), 21 deletions(-) diff --git a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/NetworkUtilizationManager.java b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/NetworkUtilizationManager.java index 8ef5345844d3..9536645b44a5 100644 --- a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/NetworkUtilizationManager.java +++ b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/NetworkUtilizationManager.java @@ -17,6 +17,7 @@ package com.hedera.node.app.throttle; import com.hedera.hapi.node.base.AccountID; +import com.hedera.hapi.node.base.HederaFunctionality; import com.hedera.node.app.hapi.utils.throttles.DeterministicThrottle; import com.hedera.node.app.state.HederaState; import com.hedera.node.app.workflows.TransactionInfo; @@ -95,6 +96,18 @@ boolean shouldThrottle( @NonNull final HederaState state, @NonNull final Instant consensusTime); + /** + * Verifies if the throttle in this operation context has enough capacity to handle the given number of the + * given function at the given time. (The time matters because we want to consider how much + * will have leaked between now and that time.) + * + * @param n the number of the given function + * @param function the function + * @return true if the system should throttle the given number of the given function + * at the instant for which throttling should be calculated + */ + boolean shouldThrottleNOfUnscaled(int n, @NonNull HederaFunctionality function, @NonNull Instant consensusTime); + /** * Returns a list of snapshots of the current usage of all active throttles. * @return the active snapshots diff --git a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/impl/NetworkUtilizationManagerImpl.java b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/impl/NetworkUtilizationManagerImpl.java index e66bf93230d5..d290682858f6 100644 --- a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/impl/NetworkUtilizationManagerImpl.java +++ b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/impl/NetworkUtilizationManagerImpl.java @@ -24,6 +24,7 @@ import static java.util.Objects.requireNonNull; import com.hedera.hapi.node.base.AccountID; +import com.hedera.hapi.node.base.HederaFunctionality; import com.hedera.hapi.node.base.SignatureMap; import com.hedera.hapi.node.base.Timestamp; import com.hedera.hapi.node.base.Transaction; @@ -210,6 +211,12 @@ public boolean shouldThrottle( return backendThrottle.shouldThrottle(txnInfo, consensusTime, state); } + @Override + public boolean shouldThrottleNOfUnscaled( + final int n, @NonNull final HederaFunctionality function, @NonNull final Instant consensusTime) { + return backendThrottle.shouldThrottleNOfUnscaled(n, function, consensusTime); + } + @Override public List getUsageSnapshots() { return backendThrottle.allActiveThrottles().stream() diff --git a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleContextImpl.java b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleContextImpl.java index e9ef0f4eb13a..f6cf70c68001 100644 --- a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleContextImpl.java +++ b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleContextImpl.java @@ -916,7 +916,7 @@ public void reclaimPreviouslyReservedThrottle(int n, HederaFunctionality functio @Override public boolean shouldThrottleNOfUnscaled(int n, HederaFunctionality function) { - return synchronizedThrottleAccumulator.shouldThrottleNOfUnscaled(n, function, userTransactionConsensusTime); + return networkUtilizationManager.shouldThrottleNOfUnscaled(n, function, userTransactionConsensusTime); } public boolean shouldThrottleTxn(TransactionInfo txInfo) { diff --git a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/query/QueryContextImpl.java b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/query/QueryContextImpl.java index ab29e9bedb1d..e319c38f26d0 100644 --- a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/query/QueryContextImpl.java +++ b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/query/QueryContextImpl.java @@ -32,12 +32,10 @@ import com.hedera.node.app.spi.records.RecordCache; import com.hedera.node.app.spi.workflows.QueryContext; import com.hedera.node.app.state.HederaState; -import com.hedera.node.app.throttle.SynchronizedThrottleAccumulator; import com.hedera.node.app.workflows.dispatcher.ReadableStoreFactory; import com.swirlds.config.api.Configuration; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; -import java.time.Instant; /** * Simple implementation of {@link QueryContext}. @@ -52,8 +50,6 @@ public class QueryContextImpl implements QueryContext { private final ExchangeRateManager exchangeRateManager; private final AccountID payer; private final FeeCalculator feeCalculator; - private final Instant userQueryConsensusTime; - private final SynchronizedThrottleAccumulator synchronizedThrottleAccumulator; private BlockRecordInfo blockRecordInfo; // lazily created private ExchangeRateInfo exchangeRateInfo; // lazily created @@ -67,8 +63,6 @@ public class QueryContextImpl implements QueryContext { * @param recordCache the {@link RecordCache} used to cache records * @param exchangeRateManager the {@link ExchangeRateManager} used to get the current exchange rate * @param feeCalculator the {@link FeeCalculator} used to calculate fees - * @param userQueryConsensusTime the query time - * @param synchronizedThrottleAccumulator The {@link SynchronizedThrottleAccumulator} used to manage the tracking of network throttling * @param payer the {@link AccountID} of the payer, if present * @throws NullPointerException if {@code query} is {@code null} */ @@ -80,8 +74,6 @@ public QueryContextImpl( @NonNull final RecordCache recordCache, @NonNull final ExchangeRateManager exchangeRateManager, @NonNull final FeeCalculator feeCalculator, - @NonNull final Instant userQueryConsensusTime, - @NonNull final SynchronizedThrottleAccumulator synchronizedThrottleAccumulator, @Nullable final AccountID payer) { this.state = requireNonNull(state, "state must not be null"); this.storeFactory = requireNonNull(storeFactory, "storeFactory must not be null"); @@ -90,11 +82,6 @@ public QueryContextImpl( this.recordCache = requireNonNull(recordCache, "recordCache must not be null"); this.exchangeRateManager = requireNonNull(exchangeRateManager, "exchangeRateManager must not be null"); this.feeCalculator = requireNonNull(feeCalculator, "feeCalculator must not be null"); - this.userQueryConsensusTime = requireNonNull(userQueryConsensusTime, "userQueryConsensusTime must not be null"); - ; - this.synchronizedThrottleAccumulator = - requireNonNull(synchronizedThrottleAccumulator, "synchronizedThrottleAccumulator must not be null"); - ; this.payer = payer; } @@ -161,7 +148,7 @@ public FeeCalculator feeCalculator() { @Override public boolean shouldThrottleNOfUnscaled(int n, HederaFunctionality function) { - return synchronizedThrottleAccumulator.shouldThrottleNOfUnscaled(n, function, userQueryConsensusTime); + return false; } @Override diff --git a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/query/QueryWorkflowImpl.java b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/query/QueryWorkflowImpl.java index 851736d795ec..f2f0a58c8801 100644 --- a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/query/QueryWorkflowImpl.java +++ b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/query/QueryWorkflowImpl.java @@ -211,8 +211,6 @@ public void handleQuery(@NonNull final Bytes requestBuffer, @NonNull final Buffe recordCache, exchangeRateManager, feeCalculator, - consensusTime, - synchronizedThrottleAccumulator, payerID); // A super-user does not have to pay for a query and has all permissions @@ -256,8 +254,6 @@ public void handleQuery(@NonNull final Bytes requestBuffer, @NonNull final Buffe recordCache, exchangeRateManager, feeCalculator, - consensusTime, - synchronizedThrottleAccumulator, null); } diff --git a/hedera-node/hedera-app/src/xtest/java/common/BaseScaffoldingModule.java b/hedera-node/hedera-app/src/xtest/java/common/BaseScaffoldingModule.java index 3865929dafcc..a0202f29071b 100644 --- a/hedera-node/hedera-app/src/xtest/java/common/BaseScaffoldingModule.java +++ b/hedera-node/hedera-app/src/xtest/java/common/BaseScaffoldingModule.java @@ -230,8 +230,6 @@ static BiFunction provideQueryContextFactory( recordCache, exchangeRateManager, NoOpFeeCalculator.INSTANCE, - consensusTime, - synchronizedThrottleAccumulator, payerId); } From 65e08820ef7400a7681fa4c8d56564752dfb23d8 Mon Sep 17 00:00:00 2001 From: Petar Tonev Date: Tue, 6 Feb 2024 16:19:48 +0200 Subject: [PATCH 29/34] fix: remove unnecessary method --- .../app/throttle/SynchronizedThrottleAccumulator.java | 8 -------- 1 file changed, 8 deletions(-) diff --git a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/SynchronizedThrottleAccumulator.java b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/SynchronizedThrottleAccumulator.java index eca2dd9741c5..4e9815a62f07 100644 --- a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/SynchronizedThrottleAccumulator.java +++ b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/throttle/SynchronizedThrottleAccumulator.java @@ -75,14 +75,6 @@ public void leakUnusedThrottlePreviouslyReserved(int n, HederaFunctionality func frontendThrottle.leakCapacityForNOfUnscaled(n, function); } - public boolean shouldThrottleNOfUnscaled( - final int n, @NonNull final HederaFunctionality function, @NonNull final Instant consensusTime) { - setDecisionTime(consensusTime); - final var decision = frontendThrottle.shouldThrottleNOfUnscaled(n, function, lastDecisionTime); - setDecisionTime(consensusTime); - return decision; - } - private void setDecisionTime(@NonNull final Instant time) { lastDecisionTime = time.isBefore(lastDecisionTime) ? lastDecisionTime : time; } From 5ac2bc48ebe2138ee5c5db24da1e31959a6513cc Mon Sep 17 00:00:00 2001 From: Petar Tonev Date: Tue, 6 Feb 2024 23:22:43 +0200 Subject: [PATCH 30/34] fix: add check if property enforceCreationThrottle is true --- .../contract/impl/state/RootProxyWorldUpdater.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/state/RootProxyWorldUpdater.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/state/RootProxyWorldUpdater.java index 44fedffcaee2..bde0d25360f0 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/state/RootProxyWorldUpdater.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/state/RootProxyWorldUpdater.java @@ -100,11 +100,13 @@ public void commit() { final var contractChangeSummary = enhancement.operations().summarizeContractChanges(); createdContractIds = contractChangeSummary.newContractIds(); - context().ifPresent(context -> { - final var creationCapacityIsAvailable = - !context.shouldThrottleNOfUnscaled(createdContractIds.size(), CRYPTO_CREATE); - validateTrue(creationCapacityIsAvailable, CONSENSUS_GAS_EXHAUSTED); - }); + if (contractsConfig.enforceCreationThrottle()) { + context().ifPresent(context -> { + final var creationCapacityIsAvailable = + !context.shouldThrottleNOfUnscaled(createdContractIds.size(), CRYPTO_CREATE); + validateTrue(creationCapacityIsAvailable, CONSENSUS_GAS_EXHAUSTED); + }); + } context().ifPresent(context -> { final var childThrottleIsAvailable = context.hasThrottleCapacityForChildTransactions(); From 0044e33bd289e5135bae24b44444881b5c323118 Mon Sep 17 00:00:00 2001 From: Petar Tonev Date: Wed, 7 Feb 2024 17:27:05 +0200 Subject: [PATCH 31/34] fix: refactor to simplify implementation and add method comments --- .../spi/throttle/HandleThrottleParser.java | 21 +++++++- .../node/app/spi/workflows/HandleContext.java | 22 +++++++- .../app/spi/workflows/OperationContext.java | 52 ------------------- .../node/app/spi/workflows/QueryContext.java | 2 +- .../app/workflows/query/QueryContextImpl.java | 11 ---- .../impl/exec/ContextQueryProcessor.java | 1 - .../impl/hevm/HederaWorldUpdater.java | 6 +-- .../impl/state/ProxyWorldUpdater.java | 8 +-- 8 files changed, 49 insertions(+), 74 deletions(-) delete mode 100644 hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/workflows/OperationContext.java diff --git a/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/throttle/HandleThrottleParser.java b/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/throttle/HandleThrottleParser.java index 47153a32c9c5..86bb3855cce3 100644 --- a/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/throttle/HandleThrottleParser.java +++ b/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/throttle/HandleThrottleParser.java @@ -24,15 +24,34 @@ import java.util.List; public interface HandleThrottleParser { + /* + * Rebuilds the throttle requirements based on the given throttle definitions. + * + * @param defs the throttle definitions to rebuild the throttle requirements based on + */ void rebuildFor(@NonNull final ThrottleDefinitions defs); + /* + * Rebuilds the gas throttle based on the current configuration. + */ void applyGasConfig(); + /* + * Gets the current list of active throttles. + * + * @return the current list of active throttles + */ @NonNull List allActiveThrottles(); + /* + * Resets the usage for all snapshots. + */ void resetUsageThrottlesTo(List snapshots); + /* + * Gets the gas throttle. + */ @Nullable - public GasLimitDeterministicThrottle gasLimitThrottle(); + GasLimitDeterministicThrottle gasLimitThrottle(); } diff --git a/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/workflows/HandleContext.java b/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/workflows/HandleContext.java index 0846efa9db47..6cd3b6e5c201 100644 --- a/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/workflows/HandleContext.java +++ b/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/workflows/HandleContext.java @@ -62,7 +62,7 @@ * */ @SuppressWarnings("UnusedReturnValue") -public interface HandleContext extends OperationContext { +public interface HandleContext { /** * Category of the current transaction. */ @@ -670,6 +670,26 @@ default T dispatchRemovableChildTransaction( */ void reclaimPreviouslyReservedThrottle(int n, HederaFunctionality function); + /** + * Verifies if the throttle in this operation context has enough capacity to handle the given number of the + * given function at the given time. (The time matters because we want to consider how much + * will have leaked between now and that time.) + * + * @param n the number of the given function + * @param function the function + * @return true if the system should throttle the given number of the given function + * at the instant for which throttling should be calculated + */ + boolean shouldThrottleNOfUnscaled(int n, HederaFunctionality function); + + /** + * For each following child transaction consumes the capacity + * required for that child transaction in the consensus throttle buckets. + * + * @return true if all the child transactions were allowed through the throttle consideration, false otherwise. + */ + boolean hasThrottleCapacityForChildTransactions(); + /** * Create a checkpoint for the current childRecords. * diff --git a/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/workflows/OperationContext.java b/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/workflows/OperationContext.java deleted file mode 100644 index d4ac9eb5ffb2..000000000000 --- a/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/workflows/OperationContext.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (C) 2024 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.spi.workflows; - -import com.hedera.hapi.node.base.HederaFunctionality; - -/** - * Represents a generalized operation context (HandleContext or QueryContext) of a single {@code handle()}-call. - *
    - *
  • Information about the transaction being handled, such as its consensus time, its body, and its category
  • - *
  • Configuration data and objects that depend on the current configuration
  • - *
  • Verification data, that has been assembled during pre-handle
  • - *
  • State related data and the possibility to rollback changes
  • - *
  • Data related to the record stream
  • - *
  • Functionality to dispatch preceding and child transactions
  • - *
- */ -public interface OperationContext { - /** - * Verifies if the throttle in this operation context has enough capacity to handle the given number of the - * given function at the given time. (The time matters because we want to consider how much - * will have leaked between now and that time.) - * - * @param n the number of the given function - * @param function the function - * @return true if the system should throttle the given number of the given function - * at the instant for which throttling should be calculated - */ - boolean shouldThrottleNOfUnscaled(int n, HederaFunctionality function); - - /** - * For each following child transaction consumes the capacity - * required for that child transaction in the consensus throttle buckets. - * - * @return true if all the child transactions were allowed through the throttle consideration, false otherwise. - */ - boolean hasThrottleCapacityForChildTransactions(); -} diff --git a/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/workflows/QueryContext.java b/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/workflows/QueryContext.java index c499b1755b9a..fad6562054de 100644 --- a/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/workflows/QueryContext.java +++ b/hedera-node/hedera-app-spi/src/main/java/com/hedera/node/app/spi/workflows/QueryContext.java @@ -29,7 +29,7 @@ /** * Context of a single query. Contains all query specific information. */ -public interface QueryContext extends OperationContext { +public interface QueryContext { /** * Returns the {@link Query} that is currently being processed. diff --git a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/query/QueryContextImpl.java b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/query/QueryContextImpl.java index e319c38f26d0..c34f39a8f098 100644 --- a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/query/QueryContextImpl.java +++ b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/query/QueryContextImpl.java @@ -19,7 +19,6 @@ import static java.util.Objects.requireNonNull; import com.hedera.hapi.node.base.AccountID; -import com.hedera.hapi.node.base.HederaFunctionality; import com.hedera.hapi.node.state.blockrecords.BlockInfo; import com.hedera.hapi.node.state.blockrecords.RunningHashes; import com.hedera.hapi.node.transaction.Query; @@ -145,14 +144,4 @@ public ExchangeRateInfo exchangeRateInfo() { public FeeCalculator feeCalculator() { return feeCalculator; } - - @Override - public boolean shouldThrottleNOfUnscaled(int n, HederaFunctionality function) { - return false; - } - - @Override - public boolean hasThrottleCapacityForChildTransactions() { - return true; - } } diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/ContextQueryProcessor.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/ContextQueryProcessor.java index ae031172de5f..9abe841fa725 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/ContextQueryProcessor.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/ContextQueryProcessor.java @@ -68,7 +68,6 @@ public ContextQueryProcessor( this.worldUpdater = Objects.requireNonNull(worldUpdater); this.hederaEvmContext = Objects.requireNonNull(hederaEvmContext); this.hevmStaticTransactionFactory = Objects.requireNonNull(hevmStaticTransactionFactory); - this.worldUpdater.setupContext(context); } @Override diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/hevm/HederaWorldUpdater.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/hevm/HederaWorldUpdater.java index 7fcd13615a88..4bb9109868e8 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/hevm/HederaWorldUpdater.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/hevm/HederaWorldUpdater.java @@ -31,7 +31,7 @@ import com.hedera.node.app.service.contract.impl.state.PendingCreation; import com.hedera.node.app.service.contract.impl.state.ProxyWorldUpdater; import com.hedera.node.app.service.contract.impl.state.StorageAccesses; -import com.hedera.node.app.spi.workflows.OperationContext; +import com.hedera.node.app.spi.workflows.HandleContext; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; import java.util.List; @@ -274,10 +274,10 @@ Optional tryTrackingSelfDestructBeneficiary( @NonNull List pendingStorageUpdates(); - void setupContext(@NonNull OperationContext context); + void setupContext(@NonNull HandleContext context); @NonNull - Optional context(); + Optional context(); /** * Externalizes the results of a system contract call into a record diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/state/ProxyWorldUpdater.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/state/ProxyWorldUpdater.java index a0cde800352f..9797853e2550 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/state/ProxyWorldUpdater.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/state/ProxyWorldUpdater.java @@ -37,7 +37,7 @@ import com.hedera.hapi.node.transaction.ExchangeRate; import com.hedera.node.app.service.contract.impl.exec.scope.HandleHederaOperations; import com.hedera.node.app.service.contract.impl.hevm.HederaWorldUpdater; -import com.hedera.node.app.spi.workflows.OperationContext; +import com.hedera.node.app.spi.workflows.HandleContext; import com.hedera.node.app.spi.workflows.ResourceExhaustedException; import com.hedera.node.app.spi.workflows.record.RecordListCheckPoint; import edu.umd.cs.findbugs.annotations.NonNull; @@ -85,7 +85,7 @@ public class ProxyWorldUpdater implements HederaWorldUpdater { * Context */ @Nullable - private OperationContext context; + private HandleContext context; /** * The current checkpoint of the child records for this ProxyWorldUpdater. @@ -452,7 +452,7 @@ public void commit() { * {@inheritDoc} */ @Override - public void setupContext(@NonNull final OperationContext context) { + public void setupContext(@NonNull final HandleContext context) { this.context = context; } @@ -460,7 +460,7 @@ public void setupContext(@NonNull final OperationContext context) { * {@inheritDoc} */ @Override - public @NonNull Optional context() { + public @NonNull Optional context() { return Optional.ofNullable(context); } From 4aff875082146d77d391ea4fe816457d228d1273 Mon Sep 17 00:00:00 2001 From: Petar Tonev Date: Thu, 8 Feb 2024 18:35:44 +0200 Subject: [PATCH 32/34] fix: inject HandleContext into the constructor --- .../exec/ContextTransactionProcessor.java | 1 - .../impl/hevm/HederaWorldUpdater.java | 6 ----- .../impl/state/ProxyWorldUpdater.java | 23 ------------------- .../impl/state/RootProxyWorldUpdater.java | 20 ++++++++-------- .../test/state/RootProxyWorldUpdaterTest.java | 7 +++++- 5 files changed, 16 insertions(+), 41 deletions(-) diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/ContextTransactionProcessor.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/ContextTransactionProcessor.java index dba1d3a374df..a404d13ebc2e 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/ContextTransactionProcessor.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/ContextTransactionProcessor.java @@ -91,7 +91,6 @@ public ContextTransactionProcessor( this.hederaEvmContext = Objects.requireNonNull(hederaEvmContext); this.hevmTransactionFactory = Objects.requireNonNull(hevmTransactionFactory); this.gasCharging = Objects.requireNonNull(customGasCharging); - this.rootProxyWorldUpdater.setupContext(context); } @Override diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/hevm/HederaWorldUpdater.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/hevm/HederaWorldUpdater.java index 4bb9109868e8..b4f0dba255b6 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/hevm/HederaWorldUpdater.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/hevm/HederaWorldUpdater.java @@ -31,7 +31,6 @@ import com.hedera.node.app.service.contract.impl.state.PendingCreation; import com.hedera.node.app.service.contract.impl.state.ProxyWorldUpdater; import com.hedera.node.app.service.contract.impl.state.StorageAccesses; -import com.hedera.node.app.spi.workflows.HandleContext; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; import java.util.List; @@ -274,11 +273,6 @@ Optional tryTrackingSelfDestructBeneficiary( @NonNull List pendingStorageUpdates(); - void setupContext(@NonNull HandleContext context); - - @NonNull - Optional context(); - /** * Externalizes the results of a system contract call into a record * @param result The result of the system contract call diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/state/ProxyWorldUpdater.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/state/ProxyWorldUpdater.java index 9797853e2550..9b0e0b60787e 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/state/ProxyWorldUpdater.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/state/ProxyWorldUpdater.java @@ -37,7 +37,6 @@ import com.hedera.hapi.node.transaction.ExchangeRate; import com.hedera.node.app.service.contract.impl.exec.scope.HandleHederaOperations; import com.hedera.node.app.service.contract.impl.hevm.HederaWorldUpdater; -import com.hedera.node.app.spi.workflows.HandleContext; import com.hedera.node.app.spi.workflows.ResourceExhaustedException; import com.hedera.node.app.spi.workflows.record.RecordListCheckPoint; import edu.umd.cs.findbugs.annotations.NonNull; @@ -81,12 +80,6 @@ public class ProxyWorldUpdater implements HederaWorldUpdater { @Nullable private final WorldUpdater parent; - /** - * Context - */ - @Nullable - private HandleContext context; - /** * The current checkpoint of the child records for this ProxyWorldUpdater. */ @@ -448,22 +441,6 @@ public void commit() { } } - /** - * {@inheritDoc} - */ - @Override - public void setupContext(@NonNull final HandleContext context) { - this.context = context; - } - - /** - * {@inheritDoc} - */ - @Override - public @NonNull Optional context() { - return Optional.ofNullable(context); - } - /** * {@inheritDoc} */ diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/state/RootProxyWorldUpdater.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/state/RootProxyWorldUpdater.java index bde0d25360f0..094bfbb6da50 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/state/RootProxyWorldUpdater.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/state/RootProxyWorldUpdater.java @@ -27,6 +27,7 @@ import com.hedera.node.app.service.contract.impl.infra.IterableStorageManager; import com.hedera.node.app.service.contract.impl.infra.RentCalculator; import com.hedera.node.app.service.contract.impl.infra.StorageSizeValidator; +import com.hedera.node.app.spi.workflows.HandleContext; import com.hedera.node.app.spi.workflows.ResourceExhaustedException; import com.hedera.node.config.data.ContractsConfig; import edu.umd.cs.findbugs.annotations.NonNull; @@ -48,6 +49,7 @@ public class RootProxyWorldUpdater extends ProxyWorldUpdater { private final ContractsConfig contractsConfig; private final IterableStorageManager storageManager; private final StorageSizeValidator storageSizeValidator; + private final HandleContext context; private boolean committed = false; private List createdContractIds; @@ -60,12 +62,14 @@ public RootProxyWorldUpdater( @NonNull final EvmFrameStateFactory evmFrameStateFactory, @NonNull final RentCalculator rentCalculator, @NonNull final IterableStorageManager storageManager, - @NonNull final StorageSizeValidator storageSizeValidator) { + @NonNull final StorageSizeValidator storageSizeValidator, + @NonNull final HandleContext context) { super(enhancement, evmFrameStateFactory, null); this.contractsConfig = Objects.requireNonNull(contractsConfig); this.storageManager = Objects.requireNonNull(storageManager); this.rentCalculator = Objects.requireNonNull(rentCalculator); this.storageSizeValidator = Objects.requireNonNull(storageSizeValidator); + this.context = context; } /** @@ -101,17 +105,13 @@ public void commit() { createdContractIds = contractChangeSummary.newContractIds(); if (contractsConfig.enforceCreationThrottle()) { - context().ifPresent(context -> { - final var creationCapacityIsAvailable = - !context.shouldThrottleNOfUnscaled(createdContractIds.size(), CRYPTO_CREATE); - validateTrue(creationCapacityIsAvailable, CONSENSUS_GAS_EXHAUSTED); - }); + final var creationCapacityIsAvailable = + !context.shouldThrottleNOfUnscaled(createdContractIds.size(), CRYPTO_CREATE); + validateTrue(creationCapacityIsAvailable, CONSENSUS_GAS_EXHAUSTED); } - context().ifPresent(context -> { - final var childThrottleIsAvailable = context.hasThrottleCapacityForChildTransactions(); - validateTrue(childThrottleIsAvailable, CONSENSUS_GAS_EXHAUSTED); - }); + final var childThrottleIsAvailable = context.hasThrottleCapacityForChildTransactions(); + validateTrue(childThrottleIsAvailable, CONSENSUS_GAS_EXHAUSTED); // If nonces externalization is enabled, we need to capture the updated nonces if (contractsConfig.noncesExternalizationEnabled()) { diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/state/RootProxyWorldUpdaterTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/state/RootProxyWorldUpdaterTest.java index 95bc03e5ff52..6668227759cf 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/state/RootProxyWorldUpdaterTest.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/state/RootProxyWorldUpdaterTest.java @@ -39,6 +39,7 @@ import com.hedera.node.app.service.contract.impl.state.StorageAccesses; import com.hedera.node.app.service.contract.impl.state.StorageSizeChange; import com.hedera.node.app.service.token.api.ContractChangeSummary; +import com.hedera.node.app.spi.workflows.HandleContext; import com.hedera.node.config.data.ContractsConfig; import com.hedera.node.config.testfixtures.HederaTestConfigBuilder; import com.swirlds.config.api.Configuration; @@ -78,6 +79,9 @@ class RootProxyWorldUpdaterTest { @Mock private StorageSizeValidator storageSizeValidator; + @Mock + private HandleContext context; + @Mock private EvmFrameState evmFrameState; @@ -154,7 +158,8 @@ private void givenSubjectWith(@NonNull final Configuration configuration, @NonNu () -> evmFrameState, rentCalculator, storageManager, - storageSizeValidator); + storageSizeValidator, + context); } private List pendingChanges() { From 2835c3c39b7f09ad193fe2bbe8175ad7ad090fe5 Mon Sep 17 00:00:00 2001 From: Petar Tonev Date: Fri, 9 Feb 2024 08:26:43 +0200 Subject: [PATCH 33/34] fix: unit test in RootProxyWorldUpdaterTest --- .../contract/impl/test/state/RootProxyWorldUpdaterTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/state/RootProxyWorldUpdaterTest.java b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/state/RootProxyWorldUpdaterTest.java index 6668227759cf..4b06ccbad836 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/state/RootProxyWorldUpdaterTest.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/test/java/com/hedera/node/app/service/contract/impl/test/state/RootProxyWorldUpdaterTest.java @@ -138,6 +138,7 @@ void performsAdditionalCommitActionsInOrder() { final var updatedNonces = new ArrayList<>(List.of(new ContractNonceInfo(CALLED_CONTRACT_ID, 1L))); given(hederaOperations.summarizeContractChanges()) .willReturn(new ContractChangeSummary(createdIds, updatedNonces)); + given(context.hasThrottleCapacityForChildTransactions()).willReturn(true); subject.commit(); From 3743eac9650a2d40f266736a1d9174118361f9d9 Mon Sep 17 00:00:00 2001 From: Petar Tonev Date: Mon, 12 Feb 2024 23:24:50 +0200 Subject: [PATCH 34/34] fix: throw more specific ResourceExhaustedEx --- .../service/contract/impl/state/RootProxyWorldUpdater.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/state/RootProxyWorldUpdater.java b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/state/RootProxyWorldUpdater.java index 094bfbb6da50..998f20165a72 100644 --- a/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/state/RootProxyWorldUpdater.java +++ b/hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/state/RootProxyWorldUpdater.java @@ -18,7 +18,7 @@ import static com.hedera.hapi.node.base.HederaFunctionality.CRYPTO_CREATE; import static com.hedera.hapi.node.base.ResponseCodeEnum.CONSENSUS_GAS_EXHAUSTED; -import static com.hedera.node.app.spi.workflows.HandleException.validateTrue; +import static com.hedera.node.app.spi.workflows.ResourceExhaustedException.validateResource; import com.hedera.hapi.node.base.ContractID; import com.hedera.hapi.node.contract.ContractNonceInfo; @@ -107,11 +107,11 @@ public void commit() { if (contractsConfig.enforceCreationThrottle()) { final var creationCapacityIsAvailable = !context.shouldThrottleNOfUnscaled(createdContractIds.size(), CRYPTO_CREATE); - validateTrue(creationCapacityIsAvailable, CONSENSUS_GAS_EXHAUSTED); + validateResource(creationCapacityIsAvailable, CONSENSUS_GAS_EXHAUSTED); } final var childThrottleIsAvailable = context.hasThrottleCapacityForChildTransactions(); - validateTrue(childThrottleIsAvailable, CONSENSUS_GAS_EXHAUSTED); + validateResource(childThrottleIsAvailable, CONSENSUS_GAS_EXHAUSTED); // If nonces externalization is enabled, we need to capture the updated nonces if (contractsConfig.noncesExternalizationEnabled()) {