Skip to content

Commit 9584555

Browse files
committed
Merge branch 'main' into 18591-prepare-utilities
* main: chore: prepare consensus event creator (#18585) fix: airdrop TCK issues fixes (#18582) feat: Long Term Schedule Transaction Support For DAB transactions (#18539) test: Add Ingest workflow checks HAPI tests (#18382) fix: 18571: Current path range should be respected when path to hash and path to KV indices are restored (#18592) chore: upgrade PBJ to v0.10.3 (#18597) chore: update new git-semver version (#18596) chore: 13214 custom fee assessor v3 (#18503) # Conflicts: # platform-sdk/swirlds-platform-core/src/main/java/module-info.java
2 parents 6c4c9dc + b4c06ec commit 9584555

File tree

6 files changed

+169
-35
lines changed

6 files changed

+169
-35
lines changed

.github/workflows/node-flow-deploy-release-artifact.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ jobs:
209209
run: |
210210
git push --delete origin v${{ needs.prepare-tag-release.outputs.version }} || true
211211
git tag --delete v${{ needs.prepare-tag-release.outputs.version }} || true
212-
rsync -a --delete ../hapi/hedera-protobufs/services/ services/
212+
rsync -a --delete ../hapi/hedera-protobuf-java-api/src/main/proto/services/ services/
213213
214214
- name: Import GPG key for commit signoff
215215
id: gpg_import

hedera-node/hedera-token-service-impl/src/main/java/com/hedera/node/app/service/token/impl/handlers/TokenFeeScheduleUpdateHandler.java

+6-1
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,12 @@ public void handle(@NonNull final HandleContext context) {
123123
}
124124
// validate custom fees before committing
125125
customFeesValidator.validateForFeeScheduleUpdate(
126-
token, readableAccountStore, readableTokenRelsStore, tokenStore, op.customFees());
126+
token,
127+
readableAccountStore,
128+
readableTokenRelsStore,
129+
tokenStore,
130+
op.customFees(),
131+
context.expiryValidator());
127132
// set the custom fees on token
128133
final var copy = token.copyBuilder().customFees(op.customFees());
129134
// add token to the modifications map

hedera-node/hedera-token-service-impl/src/main/java/com/hedera/node/app/service/token/impl/validators/CustomFeesValidator.java

+14-7
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@
1212
import static com.hedera.hapi.node.base.ResponseCodeEnum.INVALID_TOKEN_ID_IN_CUSTOM_FEES;
1313
import static com.hedera.hapi.node.base.ResponseCodeEnum.ROYALTY_FRACTION_CANNOT_EXCEED_ONE;
1414
import static com.hedera.hapi.node.base.ResponseCodeEnum.TOKEN_NOT_ASSOCIATED_TO_FEE_COLLECTOR;
15-
import static com.hedera.node.app.spi.workflows.HandleException.validateFalse;
15+
import static com.hedera.node.app.service.token.impl.util.TokenHandlerHelper.TokenValidations.REQUIRE_NOT_PAUSED;
16+
import static com.hedera.node.app.service.token.impl.util.TokenHandlerHelper.getIfUsable;
1617
import static com.hedera.node.app.spi.workflows.HandleException.validateTrue;
1718
import static java.util.Objects.requireNonNull;
1819

@@ -88,7 +89,7 @@ public List<CustomFee> validateForCreation(
8889
final var createdTokenId = createdToken.tokenId();
8990
for (final var fee : customFees) {
9091
// Validate the fee collector account is in a usable state
91-
TokenHandlerHelper.getIfUsable(
92+
getIfUsable(
9293
fee.feeCollectorAccountIdOrElse(AccountID.DEFAULT),
9394
accountStore,
9495
expiryValidator,
@@ -131,7 +132,8 @@ public void validateForFeeScheduleUpdate(
131132
@NonNull final ReadableAccountStore accountStore,
132133
@NonNull final ReadableTokenRelationStore tokenRelationStore,
133134
@NonNull final WritableTokenStore tokenStore,
134-
@NonNull final List<CustomFee> customFees) {
135+
@NonNull final List<CustomFee> customFees,
136+
@NonNull final ExpiryValidator expiryValidator) {
135137
requireNonNull(token);
136138
requireNonNull(accountStore);
137139
requireNonNull(tokenRelationStore);
@@ -141,7 +143,14 @@ public void validateForFeeScheduleUpdate(
141143
final var tokenType = token.tokenType();
142144
for (final var fee : customFees) {
143145
final var collectorId = fee.feeCollectorAccountIdOrElse(AccountID.DEFAULT);
144-
final var collector = accountStore.getAccountById(collectorId);
146+
// check if collector is usable
147+
final var collector = getIfUsable(
148+
collectorId,
149+
accountStore,
150+
expiryValidator,
151+
INVALID_CUSTOM_FEE_COLLECTOR,
152+
INVALID_CUSTOM_FEE_COLLECTOR,
153+
TokenHandlerHelper.AccountIDType.NOT_ALIASED_ID);
145154
validateTrue(collector != null, INVALID_CUSTOM_FEE_COLLECTOR);
146155

147156
switch (fee.fee().kind()) {
@@ -176,9 +185,7 @@ private void validateExplicitTokenDenomination(
176185
@NonNull final TokenID tokenNum,
177186
@NonNull final ReadableTokenRelationStore tokenRelationStore,
178187
@NonNull final WritableTokenStore tokenStore) {
179-
final var denomToken = tokenStore.get(tokenNum);
180-
validateTrue(denomToken != null, INVALID_TOKEN_ID_IN_CUSTOM_FEES);
181-
validateFalse(denomToken.paused(), INVALID_TOKEN_ID_IN_CUSTOM_FEES);
188+
final var denomToken = getIfUsable(tokenNum, tokenStore, REQUIRE_NOT_PAUSED, INVALID_TOKEN_ID_IN_CUSTOM_FEES);
182189
validateTrue(isFungibleCommon(denomToken.tokenType()), CUSTOM_FEE_DENOMINATION_MUST_BE_FUNGIBLE_COMMON);
183190
validateTrue(tokenRelationStore.get(feeCollectorNum, tokenNum) != null, TOKEN_NOT_ASSOCIATED_TO_FEE_COLLECTOR);
184191
}

hedera-node/hedera-token-service-impl/src/test/java/com/hedera/node/app/service/token/impl/test/handlers/TokenFeeScheduleUpdateHandlerTest.java

+8
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import static org.mockito.Mockito.when;
2121

2222
import com.hedera.hapi.node.base.Key;
23+
import com.hedera.hapi.node.base.ResponseCodeEnum;
2324
import com.hedera.hapi.node.base.SignatureMap;
2425
import com.hedera.hapi.node.base.TokenID;
2526
import com.hedera.hapi.node.base.TransactionID;
@@ -40,6 +41,7 @@
4041
import com.hedera.node.app.spi.fees.FeeCalculator;
4142
import com.hedera.node.app.spi.fees.Fees;
4243
import com.hedera.node.app.spi.store.StoreFactory;
44+
import com.hedera.node.app.spi.validation.ExpiryValidator;
4345
import com.hedera.node.app.spi.workflows.HandleContext;
4446
import com.hedera.node.app.spi.workflows.HandleException;
4547
import com.hedera.node.app.spi.workflows.PreCheckException;
@@ -88,6 +90,9 @@ class TokenFeeScheduleUpdateHandlerTest extends CryptoTokenHandlerTestBase {
8890
@Mock
8991
private PureChecksContext pureChecksContext;
9092

93+
@Mock(strictness = Mock.Strictness.LENIENT)
94+
private ExpiryValidator expiryValidator;
95+
9196
@BeforeEach
9297
void setup() {
9398
super.setUp();
@@ -100,6 +105,9 @@ void setup() {
100105
.getOrCreateConfig();
101106
given(context.configuration()).willReturn(config);
102107
given(context.storeFactory()).willReturn(storeFactory);
108+
given(context.expiryValidator()).willReturn(expiryValidator);
109+
given(expiryValidator.expirationStatus(any(), anyBoolean(), anyLong())).willReturn(ResponseCodeEnum.OK);
110+
103111
given(storeFactory.readableStore(ReadableAccountStore.class)).willReturn(readableAccountStore);
104112
given(storeFactory.readableStore(ReadableTokenRelationStore.class)).willReturn(readableTokenRelStore);
105113
given(storeFactory.writableStore(WritableTokenStore.class)).willReturn(writableTokenStore);

hedera-node/hedera-token-service-impl/src/test/java/com/hedera/node/app/service/token/impl/test/validators/CustomFeesValidatorTest.java

+65-26
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,8 @@ void validateNullFeeCollectorOnFeeScheduleUpdate() {
6666
readableAccountStore,
6767
readableTokenRelStore,
6868
writableTokenStore,
69-
nullCollectorFee))
69+
nullCollectorFee,
70+
expiryValidator))
7071
.isInstanceOf(HandleException.class)
7172
.has(responseCode(INVALID_CUSTOM_FEE_COLLECTOR));
7273
}
@@ -81,7 +82,8 @@ void validateMissingFeeCollectorOnFeeScheduleUpdate() {
8182
readableAccountStore,
8283
readableTokenRelStore,
8384
writableTokenStore,
84-
missingFeeCollectorFee))
85+
missingFeeCollectorFee,
86+
expiryValidator))
8587
.isInstanceOf(HandleException.class)
8688
.has(responseCode(INVALID_CUSTOM_FEE_COLLECTOR));
8789
}
@@ -96,7 +98,8 @@ void validateDefaultInstanceOnFeeScheduleUpdate() {
9698
readableAccountStore,
9799
readableTokenRelStore,
98100
writableTokenStore,
99-
missingFeeCollectorFee))
101+
missingFeeCollectorFee,
102+
expiryValidator))
100103
.isInstanceOf(HandleException.class)
101104
.has(responseCode(INVALID_CUSTOM_FEE_COLLECTOR));
102105
}
@@ -106,7 +109,12 @@ void validateDefaultInstanceOnFeeScheduleUpdate() {
106109
void validateFixedFeeAndFractionalFeesOnFeeScheduleUpdate() {
107110
assertThatNoException()
108111
.isThrownBy(() -> subject.validateForFeeScheduleUpdate(
109-
fungibleToken, readableAccountStore, readableTokenRelStore, writableTokenStore, customFees));
112+
fungibleToken,
113+
readableAccountStore,
114+
readableTokenRelStore,
115+
writableTokenStore,
116+
customFees,
117+
expiryValidator));
110118
}
111119

112120
@Test
@@ -115,7 +123,12 @@ void royaltyFeeForFungibleTokenFailOnFeeScheduleUpdates() {
115123
final List<CustomFee> feeWithRoyalty = new ArrayList<>();
116124
feeWithRoyalty.add(withRoyaltyFee(royaltyFee));
117125
assertThatThrownBy(() -> subject.validateForFeeScheduleUpdate(
118-
fungibleToken, readableAccountStore, readableTokenRelStore, writableTokenStore, feeWithRoyalty))
126+
fungibleToken,
127+
readableAccountStore,
128+
readableTokenRelStore,
129+
writableTokenStore,
130+
feeWithRoyalty,
131+
expiryValidator))
119132
.isInstanceOf(HandleException.class)
120133
.has(responseCode(CUSTOM_ROYALTY_FEE_ONLY_ALLOWED_FOR_NON_FUNGIBLE_UNIQUE));
121134
}
@@ -132,7 +145,8 @@ void royaltyFeeForNonFungibleTokenSucceedsOnFeeScheduleUpdate() {
132145
readableAccountStore,
133146
readableTokenRelStore,
134147
writableTokenStore,
135-
feeWithRoyalty));
148+
feeWithRoyalty,
149+
expiryValidator));
136150
}
137151

138152
@Test
@@ -150,7 +164,8 @@ void royaltyFeeFailsWithMissingTokenOnFeeScheduleUpdate() {
150164
readableAccountStore,
151165
readableTokenRelStore,
152166
writableTokenStore,
153-
feeWithRoyalty))
167+
feeWithRoyalty,
168+
expiryValidator))
154169
.isInstanceOf(HandleException.class)
155170
.has(responseCode(INVALID_TOKEN_ID_IN_CUSTOM_FEES));
156171
}
@@ -174,7 +189,8 @@ void royaltyFeeFailsFungibleDenomOnFeeScheduleUpdate() {
174189
readableAccountStore,
175190
readableTokenRelStore,
176191
writableTokenStore,
177-
feeWithRoyalty))
192+
feeWithRoyalty,
193+
expiryValidator))
178194
.isInstanceOf(HandleException.class)
179195
.has(responseCode(CUSTOM_FEE_DENOMINATION_MUST_BE_FUNGIBLE_COMMON));
180196
}
@@ -194,7 +210,8 @@ void missingTokenAssociationForRoyaltyFeeFailsOnFeeScheduleUpdate() {
194210
List.of(withRoyaltyFee(royaltyFee
195211
.copyBuilder()
196212
.fallbackFee(htsFixedFee)
197-
.build()))))
213+
.build())),
214+
expiryValidator))
198215
.isInstanceOf(HandleException.class)
199216
.has(responseCode(TOKEN_NOT_ASSOCIATED_TO_FEE_COLLECTOR));
200217
}
@@ -209,7 +226,8 @@ void fractionalFeeForNonFungibleTokenFailsOnFeeScheduleUpdate() {
209226
readableAccountStore,
210227
readableTokenRelStore,
211228
writableTokenStore,
212-
feeWithFractional))
229+
feeWithFractional,
230+
expiryValidator))
213231
.isInstanceOf(HandleException.class)
214232
.has(responseCode(CUSTOM_FRACTIONAL_FEE_ONLY_ALLOWED_FOR_FUNGIBLE_COMMON));
215233
}
@@ -226,7 +244,8 @@ void fixedFeeIsAllowedForNonFungibleTokenOnFeeScheduleUpdate() {
226244
readableAccountStore,
227245
readableTokenRelStore,
228246
writableTokenStore,
229-
feeWithFixed));
247+
feeWithFixed,
248+
expiryValidator));
230249
}
231250

232251
@Test
@@ -242,7 +261,8 @@ void failsIfTokenRelationIsMissingInFixedFeeOnFeeScheduleUpdate() {
242261
readableAccountStore,
243262
readableTokenRelStore,
244263
writableTokenStore,
245-
List.of(withFixedFee(hbarFixedFee), withFractionalFee(fractionalFee))))
264+
List.of(withFixedFee(hbarFixedFee), withFractionalFee(fractionalFee)),
265+
expiryValidator))
246266
.isInstanceOf(HandleException.class)
247267
.has(responseCode(TOKEN_NOT_ASSOCIATED_TO_FEE_COLLECTOR));
248268
}
@@ -260,7 +280,8 @@ void failsIfTokenRelationIsMissingForFractionalFeeOnFeeScheduleUpdate() {
260280
readableAccountStore,
261281
readableTokenRelStore,
262282
writableTokenStore,
263-
List.of(withFractionalFee(fractionalFee))))
283+
List.of(withFractionalFee(fractionalFee)),
284+
expiryValidator))
264285
.isInstanceOf(HandleException.class)
265286
.has(responseCode(TOKEN_NOT_ASSOCIATED_TO_FEE_COLLECTOR));
266287
}
@@ -280,27 +301,38 @@ void validateTokenDenominationForFixedFeeOnFeeScheduleUpdate() {
280301
readableAccountStore,
281302
readableTokenRelStore,
282303
writableTokenStore,
283-
List.of(withFixedFee(newFee))))
304+
List.of(withFixedFee(newFee)),
305+
expiryValidator))
284306
.isInstanceOf(HandleException.class)
285307
.has(responseCode(CUSTOM_FEE_DENOMINATION_MUST_BE_FUNGIBLE_COMMON));
286308
}
287309

288310
@Test
289311
void nullParamsThrowOnFeeScheduleUpdate() {
290312
assertThatThrownBy(() -> subject.validateForFeeScheduleUpdate(
291-
null, readableAccountStore, readableTokenRelStore, writableTokenStore, customFees))
313+
null,
314+
readableAccountStore,
315+
readableTokenRelStore,
316+
writableTokenStore,
317+
customFees,
318+
expiryValidator))
292319
.isInstanceOf(NullPointerException.class);
293320
assertThatThrownBy(() -> subject.validateForFeeScheduleUpdate(
294-
fungibleToken, null, readableTokenRelStore, writableTokenStore, customFees))
321+
fungibleToken, null, readableTokenRelStore, writableTokenStore, customFees, expiryValidator))
295322
.isInstanceOf(NullPointerException.class);
296323
assertThatThrownBy(() -> subject.validateForFeeScheduleUpdate(
297-
fungibleToken, readableAccountStore, null, writableTokenStore, customFees))
324+
fungibleToken, readableAccountStore, null, writableTokenStore, customFees, expiryValidator))
298325
.isInstanceOf(NullPointerException.class);
299326
assertThatThrownBy(() -> subject.validateForFeeScheduleUpdate(
300-
fungibleToken, readableAccountStore, readableTokenRelStore, null, customFees))
327+
fungibleToken, readableAccountStore, readableTokenRelStore, null, customFees, expiryValidator))
301328
.isInstanceOf(NullPointerException.class);
302329
assertThatThrownBy(() -> subject.validateForFeeScheduleUpdate(
303-
fungibleToken, readableAccountStore, readableTokenRelStore, writableTokenStore, null))
330+
fungibleToken,
331+
readableAccountStore,
332+
readableTokenRelStore,
333+
writableTokenStore,
334+
null,
335+
expiryValidator))
304336
.isInstanceOf(NullPointerException.class);
305337
}
306338

@@ -319,7 +351,8 @@ void failsIfFractionalFeeDenominatorIsSetToZero() {
319351
readableAccountStore,
320352
readableTokenRelStore,
321353
writableTokenStore,
322-
List.of(withFractionalFee(fractionalFeeWithZeroDenominator))))
354+
List.of(withFractionalFee(fractionalFeeWithZeroDenominator)),
355+
expiryValidator))
323356
.isInstanceOf(HandleException.class)
324357
.hasMessage("FRACTION_DIVIDES_BY_ZERO");
325358
}
@@ -339,7 +372,8 @@ void failsIfFractionalFeeNumeratorIsNegative() {
339372
readableAccountStore,
340373
readableTokenRelStore,
341374
writableTokenStore,
342-
List.of(withFractionalFee(fractionalFeeWithNegativeNumerator))))
375+
List.of(withFractionalFee(fractionalFeeWithNegativeNumerator)),
376+
expiryValidator))
343377
.isInstanceOf(HandleException.class)
344378
.hasMessage("CUSTOM_FEE_MUST_BE_POSITIVE");
345379
}
@@ -359,7 +393,8 @@ void failsIfFractionalFeeMinimumAmountIsNegative() {
359393
readableAccountStore,
360394
readableTokenRelStore,
361395
writableTokenStore,
362-
List.of(withFractionalFee(fractionalFeeWithNegativeMinimumAmount))))
396+
List.of(withFractionalFee(fractionalFeeWithNegativeMinimumAmount)),
397+
expiryValidator))
363398
.isInstanceOf(HandleException.class)
364399
.hasMessage("CUSTOM_FEE_MUST_BE_POSITIVE");
365400
}
@@ -379,7 +414,8 @@ void failsIfFractionalFeeMaximumAmountIsNegative() {
379414
readableAccountStore,
380415
readableTokenRelStore,
381416
writableTokenStore,
382-
List.of(withFractionalFee(fractionalFeeWithNegativeMaximumAmount))))
417+
List.of(withFractionalFee(fractionalFeeWithNegativeMaximumAmount)),
418+
expiryValidator))
383419
.isInstanceOf(HandleException.class)
384420
.hasMessage("CUSTOM_FEE_MUST_BE_POSITIVE");
385421
}
@@ -396,7 +432,8 @@ void failsIfHtsFixedFeeAmountIsNegative() {
396432
readableAccountStore,
397433
readableTokenRelStore,
398434
writableTokenStore,
399-
List.of(withFixedFee(htsFixedFeeWithNegativeAmount))))
435+
List.of(withFixedFee(htsFixedFeeWithNegativeAmount)),
436+
expiryValidator))
400437
.isInstanceOf(HandleException.class)
401438
.hasMessage("CUSTOM_FEE_MUST_BE_POSITIVE");
402439
}
@@ -416,7 +453,8 @@ void failsIfFractionalFeeMaximumAmountIsLessThanMinimumAmount() {
416453
readableAccountStore,
417454
readableTokenRelStore,
418455
writableTokenStore,
419-
List.of(withFractionalFee(fractionalFeeWithWrongMinMaxAmount))))
456+
List.of(withFractionalFee(fractionalFeeWithWrongMinMaxAmount)),
457+
expiryValidator))
420458
.isInstanceOf(HandleException.class)
421459
.hasMessage("FRACTIONAL_FEE_MAX_AMOUNT_LESS_THAN_MIN_AMOUNT");
422460
}
@@ -430,7 +468,8 @@ void failsIfEmptyCustomFeesOnFeeScheduleUpdate() {
430468
writableTokenStore,
431469
List.of(CustomFee.newBuilder()
432470
.feeCollectorAccountId(idFactory.newAccountId(accountNum.longValue()))
433-
.build())))
471+
.build()),
472+
expiryValidator))
434473
.isInstanceOf(HandleException.class)
435474
.hasMessage("CUSTOM_FEE_NOT_FULLY_SPECIFIED");
436475
}

0 commit comments

Comments
 (0)