Skip to content

Commit

Permalink
Merge branch 'develop' into 09567-fix-token-update-expiry-e2e
Browse files Browse the repository at this point in the history
  • Loading branch information
petreze committed Nov 8, 2023
2 parents 94d965f + 527b92a commit de2caa0
Show file tree
Hide file tree
Showing 23 changed files with 214 additions and 109 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package com.hedera.node.app.spi.validation;

import com.hedera.hapi.node.base.HederaFunctionality;
import com.hedera.hapi.node.base.ResponseCodeEnum;
import com.hedera.node.app.spi.workflows.HandleException;
import com.hedera.node.app.spi.workflows.TransactionHandler;
Expand All @@ -31,16 +32,18 @@ public interface ExpiryValidator {
* Validates the expiry metadata for an attempt to create an entity.
* @param entityCanSelfFundRenewal whether the entity can self-fund its own auto-renewal
* @param creationMetadata the expiry metadata for the attempted creation
* @param isForTopicCreation if the expiry metadata is for topic creation.
* @param functionality the HederaFunctionality that is being attempted
* This is only needed until differential testing is completed to comply with
* mono-service respoinse codes.
* mono-service response codes.
*
* @return the expiry metadata that will result from the creation
* @throws HandleException if the metadata is invalid
*/
@NonNull
ExpiryMeta resolveCreationAttempt(
boolean entityCanSelfFundRenewal, @NonNull ExpiryMeta creationMetadata, final boolean isForTopicCreation);
boolean entityCanSelfFundRenewal,
@NonNull final ExpiryMeta creationMetadata,
@NonNull final HederaFunctionality functionality);

/**
* Validates the expiry metadata for an attempt to update an entity, and returns the
Expand All @@ -49,11 +52,13 @@ ExpiryMeta resolveCreationAttempt(
*
* @param currentMetadata the current expiry metadata for the entity
* @param updateMetadata the expiry metadata for the attempted update
* @param isForTokenUpdate if the expiry metadata is for token update
* @return the expiry metadata that will result from the update
* @throws HandleException if the metadata is invalid
*/
@NonNull
ExpiryMeta resolveUpdateAttempt(@NonNull ExpiryMeta currentMetadata, @NonNull ExpiryMeta updateMetadata);
ExpiryMeta resolveUpdateAttempt(
@NonNull ExpiryMeta currentMetadata, @NonNull ExpiryMeta updateMetadata, boolean isForTokenUpdate);

/**
* Gets the expiration status of an entity based on the {@link EntityType}.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package com.hedera.node.app.workflows.handle.validation;

import static com.hedera.hapi.node.base.ResponseCodeEnum.AUTORENEW_DURATION_NOT_IN_RANGE;
import static com.hedera.hapi.node.base.ResponseCodeEnum.BAD_ENCODING;
import static com.hedera.hapi.node.base.ResponseCodeEnum.INVALID_EXPIRATION_TIME;
import static com.hedera.hapi.node.base.ResponseCodeEnum.INVALID_RENEWAL_PERIOD;
Expand Down Expand Up @@ -100,10 +101,11 @@ public void validateExpiry(long expiry) {
@Override
public void validateAutoRenewPeriod(long autoRenewPeriod) {
final var ledgerConfig = context.configuration().getConfigData(LedgerConfig.class);
validateTrue(autoRenewPeriod > 0, INVALID_RENEWAL_PERIOD);
validateTrue(
autoRenewPeriod >= ledgerConfig.autoRenewPeriodMinDuration()
&& autoRenewPeriod <= ledgerConfig.autoRenewPeriodMaxDuration(),
INVALID_RENEWAL_PERIOD);
AUTORENEW_DURATION_NOT_IN_RANGE);
}

private void validateKeyAtLevel(@NonNull final Key key, final int level) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,19 @@
package com.hedera.node.app.workflows.handle.validation;

import static com.hedera.hapi.node.base.ResponseCodeEnum.ACCOUNT_EXPIRED_AND_PENDING_REMOVAL;
import static com.hedera.hapi.node.base.ResponseCodeEnum.AUTORENEW_DURATION_NOT_IN_RANGE;
import static com.hedera.hapi.node.base.ResponseCodeEnum.CONTRACT_EXPIRED_AND_PENDING_REMOVAL;
import static com.hedera.hapi.node.base.ResponseCodeEnum.EXPIRATION_REDUCTION_NOT_ALLOWED;
import static com.hedera.hapi.node.base.ResponseCodeEnum.INVALID_AUTORENEW_ACCOUNT;
import static com.hedera.hapi.node.base.ResponseCodeEnum.INVALID_RENEWAL_PERIOD;
import static com.hedera.hapi.node.base.ResponseCodeEnum.OK;
import static com.hedera.node.app.service.mono.fees.calculation.FeeCalcUtils.clampedAdd;
import static com.hedera.node.app.spi.workflows.HandleException.validateFalse;
import static com.hedera.node.app.spi.workflows.HandleException.validateTrue;
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.ResponseCodeEnum;
import com.hedera.node.app.service.evm.exceptions.InvalidTransactionException;
import com.hedera.node.app.service.mono.pbj.PbjConverter;
Expand Down Expand Up @@ -62,7 +65,7 @@ public ExpiryValidatorImpl(@NonNull final HandleContext context) {
public ExpiryMeta resolveCreationAttempt(
final boolean entityCanSelfFundRenewal,
@NonNull final ExpiryMeta creationMeta,
final boolean isForTopicCreate) {
@NonNull final HederaFunctionality functionality) {
if (creationMeta.hasAutoRenewAccountId()) {
validateAutoRenewAccount(creationMeta.autoRenewAccountId());
}
Expand All @@ -74,33 +77,52 @@ public ExpiryMeta resolveCreationAttempt(
if (hasCompleteAutoRenewSpec(entityCanSelfFundRenewal, creationMeta)) {
effectiveExpiry = clampedAdd(context.consensusNow().getEpochSecond(), creationMeta.autoRenewPeriod());
}
// In mono-service this check is done first for topic creation.
// To maintain same behaviour for differential testing this condition is needed.
// FUTURE: This condition should be removed after differential testing is done
if (isForTopicCreate) {
if (functionality == HederaFunctionality.CONSENSUS_CREATE_TOPIC) {
// In mono-service this check is done first for topic creation.
context.attributeValidator().validateExpiry(effectiveExpiry);
// Even if the effective expiry is valid, we still also require any explicit auto-renew period to be valid
if (creationMeta.hasAutoRenewPeriod()) {
context.attributeValidator().validateAutoRenewPeriod(creationMeta.autoRenewPeriod());
validateAutoRenew(creationMeta);

Check warning on line 86 in hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/validation/ExpiryValidatorImpl.java

View check run for this annotation

Codecov / codecov/patch

hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/validation/ExpiryValidatorImpl.java#L86

Added line #L86 was not covered by tests
} else if (functionality == HederaFunctionality.TOKEN_CREATE) {
// In mono-service, INVALID_RENEWAL_PERIOD is thrown for token creation and update
// if the autoRenewPeriod is not in range.
// It would be more correct to throw AUTO_RENEW_DURATION_NOT_IN_RANGE like the other services do,
// but this would break differential testing. So for now, we replicate the mono-service behaviour.
try {
validateAutoRenew(creationMeta);
} catch (HandleException e) {

Check warning on line 94 in hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/validation/ExpiryValidatorImpl.java

View check run for this annotation

Codecov / codecov/patch

hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/validation/ExpiryValidatorImpl.java#L93-L94

Added lines #L93 - L94 were not covered by tests
if (e.getStatus() == AUTORENEW_DURATION_NOT_IN_RANGE) {
throw new HandleException(INVALID_RENEWAL_PERIOD);

Check warning on line 96 in hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/validation/ExpiryValidatorImpl.java

View check run for this annotation

Codecov / codecov/patch

hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/validation/ExpiryValidatorImpl.java#L96

Added line #L96 was not covered by tests
} else {
throw e;

Check warning on line 98 in hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/validation/ExpiryValidatorImpl.java

View check run for this annotation

Codecov / codecov/patch

hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/validation/ExpiryValidatorImpl.java#L98

Added line #L98 was not covered by tests
}
}
context.attributeValidator().validateExpiry(effectiveExpiry);

Check warning on line 101 in hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/validation/ExpiryValidatorImpl.java

View check run for this annotation

Codecov / codecov/patch

hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/validation/ExpiryValidatorImpl.java#L101

Added line #L101 was not covered by tests
} else {
// Even if the effective expiry is valid, we still also require any explicit auto-renew period to be valid
if (creationMeta.hasAutoRenewPeriod()) {
context.attributeValidator().validateAutoRenewPeriod(creationMeta.autoRenewPeriod());
}
validateAutoRenew(creationMeta);
context.attributeValidator().validateExpiry(effectiveExpiry);
}

return new ExpiryMeta(effectiveExpiry, creationMeta.autoRenewPeriod(), creationMeta.autoRenewAccountId());
}

private void validateAutoRenew(final ExpiryMeta creationMeta) {
if (creationMeta.hasAutoRenewPeriod()) {
context.attributeValidator().validateAutoRenewPeriod(creationMeta.autoRenewPeriod());
}
}

/**
* {@inheritDoc}
*/
@NonNull
@Override
public ExpiryMeta resolveUpdateAttempt(
@NonNull final ExpiryMeta currentMeta, @NonNull final ExpiryMeta updateMeta) {
@NonNull final ExpiryMeta currentMeta,
@NonNull final ExpiryMeta updateMeta,
final boolean isForTokenUpdate) {
if (updateMeta.hasAutoRenewAccountId()) {
validateAutoRenewAccount(updateMeta.autoRenewAccountId());
}
Expand All @@ -114,8 +136,21 @@ public ExpiryMeta resolveUpdateAttempt(

var resolvedAutoRenewPeriod = currentMeta.autoRenewPeriod();
if (updateMeta.hasAutoRenewPeriod()) {
context.attributeValidator().validateAutoRenewPeriod(updateMeta.autoRenewPeriod());
resolvedAutoRenewPeriod = updateMeta.autoRenewPeriod();
try {
context.attributeValidator().validateAutoRenewPeriod(updateMeta.autoRenewPeriod());
resolvedAutoRenewPeriod = updateMeta.autoRenewPeriod();
} catch (HandleException e) {
// In mono-service, INVALID_RENEWAL_PERIOD is thrown for token creation and update
// if the autoRenewPeriod is not in range.
// It would be more correct to throw AUTO_RENEW_DURATION_NOT_IN_RANGE like the other services do,
// but this would break differential testing. So for now, we replicate the mono-service behaviour.
// FUTURE: This condition should be removed after differential testing is done
if (isForTokenUpdate && e.getStatus() == AUTORENEW_DURATION_NOT_IN_RANGE) {
throw new HandleException(INVALID_RENEWAL_PERIOD);

Check warning on line 149 in hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/validation/ExpiryValidatorImpl.java

View check run for this annotation

Codecov / codecov/patch

hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/validation/ExpiryValidatorImpl.java#L149

Added line #L149 was not covered by tests
} else {
throw e;
}
}
}

var resolvedAutoRenewAccountId = currentMeta.autoRenewAccountId();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,17 @@
package com.hedera.node.app.workflows.handle.validation;

import static com.hedera.hapi.node.base.ResponseCodeEnum.ACCOUNT_EXPIRED_AND_PENDING_REMOVAL;
import static com.hedera.hapi.node.base.ResponseCodeEnum.AUTORENEW_DURATION_NOT_IN_RANGE;
import static com.hedera.hapi.node.base.ResponseCodeEnum.CONTRACT_EXPIRED_AND_PENDING_REMOVAL;
import static com.hedera.hapi.node.base.ResponseCodeEnum.EXPIRATION_REDUCTION_NOT_ALLOWED;
import static com.hedera.hapi.node.base.ResponseCodeEnum.INVALID_AUTORENEW_ACCOUNT;
import static com.hedera.hapi.node.base.ResponseCodeEnum.INVALID_RENEWAL_PERIOD;
import static com.hedera.hapi.node.base.ResponseCodeEnum.OK;
import static com.hedera.node.app.spi.workflows.HandleException.validateFalse;
import static com.hedera.node.app.spi.workflows.HandleException.validateTrue;

import com.hedera.hapi.node.base.AccountID;
import com.hedera.hapi.node.base.HederaFunctionality;
import com.hedera.hapi.node.base.ResponseCodeEnum;
import com.hedera.node.app.service.mono.config.HederaNumbers;
import com.hedera.node.app.service.mono.store.models.Id;
Expand Down Expand Up @@ -78,7 +81,7 @@ public StandardizedExpiryValidator(
public ExpiryMeta resolveCreationAttempt(
final boolean entityCanSelfFundRenewal,
@NonNull final ExpiryMeta creationMeta,
final boolean isForTopicCreate) {
@NonNull final HederaFunctionality functionality) {
if (creationMeta.hasAutoRenewAccountId()) {
validateAutoRenewAccount(creationMeta.autoRenewAccountId());
}
Expand All @@ -94,13 +97,30 @@ public ExpiryMeta resolveCreationAttempt(
// In mono-service this check is done first for topic creation.
// To maintain same behaviour for differential testing this condition is needed.
// FUTURE: This condition should be removed after differential testing is done
if (isForTopicCreate) {
if (functionality == HederaFunctionality.CONSENSUS_CREATE_TOPIC) {
attributeValidator.validateExpiry(effectiveExpiry);

// Even if the effective expiry is valid, we still also require any explicit auto-renew period to be valid
if (creationMeta.hasAutoRenewPeriod()) {
attributeValidator.validateAutoRenewPeriod(creationMeta.autoRenewPeriod());
}
} else if (functionality == HederaFunctionality.TOKEN_CREATE) {
// In mono-service, INVALID_RENEWAL_PERIOD is thrown for token creation and update
// if the autoRenewPeriod is not in range.
// It would be more correct to throw AUTO_RENEW_DURATION_NOT_IN_RANGE like the other services do,
// but this would break differential testing. So for now, we replicate the mono-service behaviour.
try {
if (creationMeta.hasAutoRenewPeriod()) {
attributeValidator.validateAutoRenewPeriod(creationMeta.autoRenewPeriod());

Check warning on line 114 in hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/validation/StandardizedExpiryValidator.java

View check run for this annotation

Codecov / codecov/patch

hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/validation/StandardizedExpiryValidator.java#L114

Added line #L114 was not covered by tests
}
} catch (HandleException e) {

Check warning on line 116 in hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/validation/StandardizedExpiryValidator.java

View check run for this annotation

Codecov / codecov/patch

hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/validation/StandardizedExpiryValidator.java#L116

Added line #L116 was not covered by tests
if (e.getStatus() == AUTORENEW_DURATION_NOT_IN_RANGE) {
throw new HandleException(INVALID_RENEWAL_PERIOD);

Check warning on line 118 in hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/validation/StandardizedExpiryValidator.java

View check run for this annotation

Codecov / codecov/patch

hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/validation/StandardizedExpiryValidator.java#L118

Added line #L118 was not covered by tests
} else {
throw e;

Check warning on line 120 in hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/validation/StandardizedExpiryValidator.java

View check run for this annotation

Codecov / codecov/patch

hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/validation/StandardizedExpiryValidator.java#L120

Added line #L120 was not covered by tests
}
}
attributeValidator.validateExpiry(effectiveExpiry);

Check warning on line 123 in hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/validation/StandardizedExpiryValidator.java

View check run for this annotation

Codecov / codecov/patch

hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/validation/StandardizedExpiryValidator.java#L122-L123

Added lines #L122 - L123 were not covered by tests
} else {
// Even if the effective expiry is valid, we still also require any explicit auto-renew period to be valid
if (creationMeta.hasAutoRenewPeriod()) {
Expand All @@ -117,7 +137,9 @@ public ExpiryMeta resolveCreationAttempt(
@NonNull
@Override
public ExpiryMeta resolveUpdateAttempt(
@NonNull final ExpiryMeta currentMeta, @NonNull final ExpiryMeta updateMeta) {
@NonNull final ExpiryMeta currentMeta,
@NonNull final ExpiryMeta updateMeta,
final boolean isForTokenUpdate) {
if (updateMeta.hasAutoRenewAccountId()) {
validateAutoRenewAccount(updateMeta.autoRenewAccountId());
}
Expand All @@ -131,8 +153,21 @@ public ExpiryMeta resolveUpdateAttempt(

var resolvedAutoRenewPeriod = currentMeta.autoRenewPeriod();
if (updateMeta.hasAutoRenewPeriod()) {
attributeValidator.validateAutoRenewPeriod(updateMeta.autoRenewPeriod());
resolvedAutoRenewPeriod = updateMeta.autoRenewPeriod();
try {
attributeValidator.validateAutoRenewPeriod(updateMeta.autoRenewPeriod());
resolvedAutoRenewPeriod = updateMeta.autoRenewPeriod();
} catch (HandleException e) {
// In mono-service, INVALID_RENEWAL_PERIOD is thrown for token creation and update
// if the autoRenewPeriod is not in range.
// It would be more correct to throw AUTO_RENEW_DURATION_NOT_IN_RANGE like the other services do,
// but this would break differential testing. So for now, we replicate the mono-service behaviour.
// FUTURE: This condition should be removed after differential testing is done
if (isForTokenUpdate && e.getStatus() == AUTORENEW_DURATION_NOT_IN_RANGE) {
throw new HandleException(INVALID_RENEWAL_PERIOD);

Check warning on line 166 in hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/validation/StandardizedExpiryValidator.java

View check run for this annotation

Codecov / codecov/patch

hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/validation/StandardizedExpiryValidator.java#L166

Added line #L166 was not covered by tests
} else {
throw e;
}
}
}

var resolvedAutoRenewId = currentMeta.autoRenewAccountId();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@

package com.hedera.node.app.workflows.handle.validation;

import static com.hedera.hapi.node.base.ResponseCodeEnum.AUTORENEW_DURATION_NOT_IN_RANGE;
import static com.hedera.hapi.node.base.ResponseCodeEnum.BAD_ENCODING;
import static com.hedera.hapi.node.base.ResponseCodeEnum.INVALID_EXPIRATION_TIME;
import static com.hedera.hapi.node.base.ResponseCodeEnum.INVALID_RENEWAL_PERIOD;
import static com.hedera.hapi.node.base.ResponseCodeEnum.INVALID_ZERO_BYTE_IN_STRING;
import static com.hedera.hapi.node.base.ResponseCodeEnum.MEMO_TOO_LONG;
import static com.hedera.node.app.spi.fixtures.workflows.ExceptionConditions.responseCode;
Expand Down Expand Up @@ -117,7 +117,7 @@ void rejectsBriefAutoRenewPeriod() {

assertThatThrownBy(() -> subject.validateAutoRenewPeriod(55L))
.isInstanceOf(HandleException.class)
.has(responseCode(INVALID_RENEWAL_PERIOD));
.has(responseCode(AUTORENEW_DURATION_NOT_IN_RANGE));
}

@Test
Expand All @@ -130,7 +130,7 @@ void rejectsOverLongAutoRenewPeriod() {

assertThatThrownBy(() -> subject.validateAutoRenewPeriod(10_001L))
.isInstanceOf(HandleException.class)
.has(responseCode(INVALID_RENEWAL_PERIOD));
.has(responseCode(AUTORENEW_DURATION_NOT_IN_RANGE));
}

@Test
Expand Down

0 comments on commit de2caa0

Please sign in to comment.