Skip to content

Commit a8bc1ae

Browse files
chore: cherry pick 12547 (#12569)
Signed-off-by: Michael Tinker <[email protected]>
1 parent 86668c7 commit a8bc1ae

File tree

6 files changed

+184
-3
lines changed

6 files changed

+184
-3
lines changed

hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/ingest/IngestChecker.java

+34
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,20 @@
1717
package com.hedera.node.app.workflows.ingest;
1818

1919
import static com.hedera.hapi.node.base.HederaFunctionality.CONTRACT_CALL;
20+
import static com.hedera.hapi.node.base.HederaFunctionality.CRYPTO_ADD_LIVE_HASH;
21+
import static com.hedera.hapi.node.base.HederaFunctionality.CRYPTO_DELETE_LIVE_HASH;
2022
import static com.hedera.hapi.node.base.HederaFunctionality.ETHEREUM_TRANSACTION;
23+
import static com.hedera.hapi.node.base.HederaFunctionality.FREEZE;
24+
import static com.hedera.hapi.node.base.HederaFunctionality.SYSTEM_DELETE;
25+
import static com.hedera.hapi.node.base.HederaFunctionality.SYSTEM_UNDELETE;
2126
import static com.hedera.hapi.node.base.ResponseCodeEnum.BUSY;
2227
import static com.hedera.hapi.node.base.ResponseCodeEnum.DUPLICATE_TRANSACTION;
2328
import static com.hedera.hapi.node.base.ResponseCodeEnum.INSUFFICIENT_GAS;
2429
import static com.hedera.hapi.node.base.ResponseCodeEnum.INSUFFICIENT_TX_FEE;
2530
import static com.hedera.hapi.node.base.ResponseCodeEnum.INVALID_ETHEREUM_TRANSACTION;
2631
import static com.hedera.hapi.node.base.ResponseCodeEnum.INVALID_NODE_ACCOUNT;
2732
import static com.hedera.hapi.node.base.ResponseCodeEnum.INVALID_SIGNATURE;
33+
import static com.hedera.hapi.node.base.ResponseCodeEnum.NOT_SUPPORTED;
2834
import static com.hedera.hapi.node.base.ResponseCodeEnum.PLATFORM_NOT_ACTIVE;
2935
import static com.hedera.hapi.node.base.ResponseCodeEnum.UNAUTHORIZED;
3036
import static com.hedera.node.app.hapi.utils.ethereum.EthTxData.populateEthTxData;
@@ -69,8 +75,10 @@
6975
import com.swirlds.config.api.Configuration;
7076
import edu.umd.cs.findbugs.annotations.NonNull;
7177
import java.time.Instant;
78+
import java.util.EnumSet;
7279
import java.util.HashSet;
7380
import java.util.List;
81+
import java.util.Set;
7482
import javax.inject.Inject;
7583
import org.apache.logging.log4j.LogManager;
7684
import org.apache.logging.log4j.Logger;
@@ -80,6 +88,10 @@
8088
*/
8189
public final class IngestChecker {
8290
private static final Logger logger = LogManager.getLogger(IngestChecker.class);
91+
private static final Set<HederaFunctionality> UNSUPPORTED_TRANSACTIONS =
92+
EnumSet.of(CRYPTO_ADD_LIVE_HASH, CRYPTO_DELETE_LIVE_HASH);
93+
private static final Set<HederaFunctionality> PRIVILEGED_TRANSACTIONS =
94+
EnumSet.of(FREEZE, SYSTEM_DELETE, SYSTEM_UNDELETE);
8395

8496
private final CurrentPlatformStatus currentPlatformStatus;
8597
private final TransactionChecker transactionChecker;
@@ -204,6 +216,7 @@ public TransactionInfo runAllChecks(
204216
}
205217

206218
// 4. Check throttles
219+
assertThrottlingPreconditions(txInfo, configuration);
207220
if (synchronizedThrottleAccumulator.shouldThrottle(txInfo, state)) {
208221
throw new PreCheckException(BUSY);
209222
}
@@ -245,6 +258,27 @@ public TransactionInfo runAllChecks(
245258
return txInfo;
246259
}
247260

261+
private void assertThrottlingPreconditions(
262+
@NonNull final TransactionInfo txInfo, @NonNull final Configuration configuration)
263+
throws PreCheckException {
264+
if (UNSUPPORTED_TRANSACTIONS.contains(txInfo.functionality())) {
265+
throw new PreCheckException(NOT_SUPPORTED);
266+
}
267+
if (PRIVILEGED_TRANSACTIONS.contains(txInfo.functionality())) {
268+
final var payerNum =
269+
txInfo.payerID() == null ? Long.MAX_VALUE : txInfo.payerID().accountNumOrElse(Long.MAX_VALUE);
270+
final var hederaConfig = configuration.getConfigData(HederaConfig.class);
271+
// This adds a mild restriction that privileged transactions can only
272+
// be issued by system accounts; (FUTURE) consider giving non-trivial
273+
// minimum fees to privileged transactions that fail with UNAUTHORIZED
274+
// at consensus, and adding them to normal throttle buckets, c.f.
275+
// https://github.com/hashgraph/hedera-services/issues/12559
276+
if (payerNum >= hederaConfig.firstUserEntity()) {
277+
throw new PreCheckException(UNAUTHORIZED);
278+
}
279+
}
280+
}
281+
248282
private void verifyPayerSignature(
249283
@NonNull final TransactionInfo txInfo,
250284
@NonNull final Account payer,

hedera-node/test-clients/src/main/java/com/hedera/services/bdd/spec/utilops/UtilVerbs.java

+10
Original file line numberDiff line numberDiff line change
@@ -94,12 +94,14 @@
9494
import com.hedera.services.bdd.spec.transactions.file.HapiFileUpdate;
9595
import com.hedera.services.bdd.spec.transactions.file.UploadProgress;
9696
import com.hedera.services.bdd.spec.transactions.system.HapiFreeze;
97+
import com.hedera.services.bdd.spec.utilops.checks.VerifyAddLiveHashNotSupported;
9798
import com.hedera.services.bdd.spec.utilops.checks.VerifyGetAccountNftInfosNotSupported;
9899
import com.hedera.services.bdd.spec.utilops.checks.VerifyGetBySolidityIdNotSupported;
99100
import com.hedera.services.bdd.spec.utilops.checks.VerifyGetFastRecordNotSupported;
100101
import com.hedera.services.bdd.spec.utilops.checks.VerifyGetLiveHashNotSupported;
101102
import com.hedera.services.bdd.spec.utilops.checks.VerifyGetStakersNotSupported;
102103
import com.hedera.services.bdd.spec.utilops.checks.VerifyGetTokenNftInfosNotSupported;
104+
import com.hedera.services.bdd.spec.utilops.checks.VerifyUserFreezeNotAuthorized;
103105
import com.hedera.services.bdd.spec.utilops.grouping.InBlockingOrder;
104106
import com.hedera.services.bdd.spec.utilops.grouping.ParallelSpecOps;
105107
import com.hedera.services.bdd.spec.utilops.inventory.NewSpecKey;
@@ -506,6 +508,14 @@ public static VerifyGetTokenNftInfosNotSupported getTokenNftInfosNotSupported()
506508
return new VerifyGetTokenNftInfosNotSupported();
507509
}
508510

511+
public static VerifyAddLiveHashNotSupported verifyAddLiveHashNotSupported() {
512+
return new VerifyAddLiveHashNotSupported();
513+
}
514+
515+
public static VerifyUserFreezeNotAuthorized verifyUserFreezeNotAuthorized() {
516+
return new VerifyUserFreezeNotAuthorized();
517+
}
518+
509519
public static RunLoadTest runLoadTest(Supplier<HapiSpecOperation[]> opSource) {
510520
return new RunLoadTest(opSource);
511521
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/*
2+
* Copyright (C) 2024 Hedera Hashgraph, LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.hedera.services.bdd.spec.utilops.checks;
18+
19+
import static com.hedera.services.bdd.spec.transactions.TxnUtils.getUniqueTimestampPlusSecs;
20+
import static com.hederahashgraph.api.proto.java.ResponseCodeEnum.NOT_SUPPORTED;
21+
import static org.junit.jupiter.api.Assertions.assertEquals;
22+
23+
import com.hedera.services.bdd.spec.HapiSpec;
24+
import com.hedera.services.bdd.spec.utilops.UtilOp;
25+
import com.hederahashgraph.api.proto.java.AccountID;
26+
import com.hederahashgraph.api.proto.java.CryptoAddLiveHashTransactionBody;
27+
import com.hederahashgraph.api.proto.java.Duration;
28+
import com.hederahashgraph.api.proto.java.SignatureMap;
29+
import com.hederahashgraph.api.proto.java.SignedTransaction;
30+
import com.hederahashgraph.api.proto.java.Transaction;
31+
import com.hederahashgraph.api.proto.java.TransactionBody;
32+
import com.hederahashgraph.api.proto.java.TransactionID;
33+
34+
public class VerifyAddLiveHashNotSupported extends UtilOp {
35+
private static final long USER_PAYER_NUM = 1001L;
36+
37+
@Override
38+
protected boolean submitOp(HapiSpec spec) throws Throwable {
39+
final var validStart = getUniqueTimestampPlusSecs(spec.setup().txnStartOffsetSecs());
40+
final var txnId = TransactionID.newBuilder()
41+
.setTransactionValidStart(validStart)
42+
.setAccountID(
43+
AccountID.newBuilder().setAccountNum(USER_PAYER_NUM).build())
44+
.build();
45+
final var body = TransactionBody.newBuilder()
46+
.setTransactionID(txnId)
47+
.setNodeAccountID(AccountID.newBuilder().setAccountNum(3).build())
48+
.setTransactionValidDuration(
49+
Duration.newBuilder().setSeconds(120).build())
50+
.setCryptoAddLiveHash(CryptoAddLiveHashTransactionBody.getDefaultInstance())
51+
.build();
52+
final var txn = Transaction.newBuilder()
53+
.setSignedTransactionBytes(SignedTransaction.newBuilder()
54+
.setBodyBytes(body.toByteString())
55+
.setSigMap(SignatureMap.getDefaultInstance())
56+
.build()
57+
.toByteString())
58+
.build();
59+
final var response =
60+
spec.clients().getCryptoSvcStub(targetNodeFor(spec), useTls).addLiveHash(txn);
61+
assertEquals(NOT_SUPPORTED, response.getNodeTransactionPrecheckCode());
62+
return false;
63+
}
64+
}

hedera-node/test-clients/src/main/java/com/hedera/services/bdd/spec/utilops/checks/VerifyGetTokenNftInfosNotSupported.java

+2-3
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,13 @@
1818

1919
import static com.hedera.services.bdd.spec.HapiPropertySource.asToken;
2020
import static com.hederahashgraph.api.proto.java.ResponseCodeEnum.NOT_SUPPORTED;
21+
import static org.junit.jupiter.api.Assertions.assertEquals;
2122

2223
import com.hedera.services.bdd.spec.HapiSpec;
2324
import com.hedera.services.bdd.spec.utilops.UtilOp;
2425
import com.hederahashgraph.api.proto.java.Query;
2526
import com.hederahashgraph.api.proto.java.Response;
2627
import com.hederahashgraph.api.proto.java.TokenGetNftInfosQuery;
27-
import org.junit.jupiter.api.Assertions;
2828

2929
public class VerifyGetTokenNftInfosNotSupported extends UtilOp {
3030
@Override
@@ -33,8 +33,7 @@ protected boolean submitOp(HapiSpec spec) throws Throwable {
3333
Query query = Query.newBuilder().setTokenGetNftInfos(op).build();
3434
Response response =
3535
spec.clients().getTokenSvcStub(targetNodeFor(spec), useTls).getTokenNftInfos(query);
36-
Assertions.assertEquals(
37-
NOT_SUPPORTED, response.getTokenGetNftInfos().getHeader().getNodeTransactionPrecheckCode());
36+
assertEquals(NOT_SUPPORTED, response.getTokenGetNftInfos().getHeader().getNodeTransactionPrecheckCode());
3837
return false;
3938
}
4039
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/*
2+
* Copyright (C) 2024 Hedera Hashgraph, LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.hedera.services.bdd.spec.utilops.checks;
18+
19+
import static com.hedera.services.bdd.spec.transactions.TxnUtils.getUniqueTimestampPlusSecs;
20+
import static com.hederahashgraph.api.proto.java.ResponseCodeEnum.UNAUTHORIZED;
21+
import static org.junit.jupiter.api.Assertions.assertEquals;
22+
23+
import com.hedera.services.bdd.spec.HapiSpec;
24+
import com.hedera.services.bdd.spec.utilops.UtilOp;
25+
import com.hederahashgraph.api.proto.java.AccountID;
26+
import com.hederahashgraph.api.proto.java.Duration;
27+
import com.hederahashgraph.api.proto.java.FreezeTransactionBody;
28+
import com.hederahashgraph.api.proto.java.SignatureMap;
29+
import com.hederahashgraph.api.proto.java.SignedTransaction;
30+
import com.hederahashgraph.api.proto.java.Transaction;
31+
import com.hederahashgraph.api.proto.java.TransactionBody;
32+
import com.hederahashgraph.api.proto.java.TransactionID;
33+
34+
public class VerifyUserFreezeNotAuthorized extends UtilOp {
35+
private static final long USER_PAYER_NUM = 1001L;
36+
37+
@Override
38+
protected boolean submitOp(HapiSpec spec) throws Throwable {
39+
final var validStart = getUniqueTimestampPlusSecs(spec.setup().txnStartOffsetSecs());
40+
final var txnId = TransactionID.newBuilder()
41+
.setTransactionValidStart(validStart)
42+
.setAccountID(
43+
AccountID.newBuilder().setAccountNum(USER_PAYER_NUM).build())
44+
.build();
45+
final var body = TransactionBody.newBuilder()
46+
.setTransactionID(txnId)
47+
.setNodeAccountID(AccountID.newBuilder().setAccountNum(3).build())
48+
.setTransactionValidDuration(
49+
Duration.newBuilder().setSeconds(120).build())
50+
.setFreeze(FreezeTransactionBody.getDefaultInstance())
51+
.build();
52+
final var txn = Transaction.newBuilder()
53+
.setSignedTransactionBytes(SignedTransaction.newBuilder()
54+
.setBodyBytes(body.toByteString())
55+
.setSigMap(SignatureMap.getDefaultInstance())
56+
.build()
57+
.toByteString())
58+
.build();
59+
final var response =
60+
spec.clients().getCryptoSvcStub(targetNodeFor(spec), useTls).addLiveHash(txn);
61+
assertEquals(UNAUTHORIZED, response.getNodeTransactionPrecheckCode());
62+
return false;
63+
}
64+
}

hedera-node/test-clients/src/main/java/com/hedera/services/bdd/suites/crypto/MiscCryptoSuite.java

+10
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
import static com.hedera.services.bdd.spec.transactions.crypto.HapiCryptoTransfer.tinyBarsFromTo;
2727
import static com.hedera.services.bdd.spec.utilops.UtilVerbs.newKeyNamed;
2828
import static com.hedera.services.bdd.spec.utilops.UtilVerbs.reduceFeeFor;
29+
import static com.hedera.services.bdd.spec.utilops.UtilVerbs.verifyAddLiveHashNotSupported;
30+
import static com.hedera.services.bdd.spec.utilops.UtilVerbs.verifyUserFreezeNotAuthorized;
2931
import static com.hedera.services.bdd.spec.utilops.UtilVerbs.withOpContext;
3032
import static com.hederahashgraph.api.proto.java.HederaFunctionality.CryptoTransfer;
3133
import static com.hederahashgraph.api.proto.java.ResponseCodeEnum.INSUFFICIENT_TX_FEE;
@@ -71,6 +73,14 @@ private List<HapiSpec> negativeTests() {
7173
return List.of(updateWithOutOfDateKeyFails());
7274
}
7375

76+
@HapiTest
77+
final HapiSpec unsupportedAndUnauthorizedTransactionsAreNotThrottled() {
78+
return defaultHapiSpec("unsupportedAndUnauthorizedTransactionsAreNotThrottled")
79+
.given()
80+
.when()
81+
.then(verifyAddLiveHashNotSupported(), verifyUserFreezeNotAuthorized());
82+
}
83+
7484
@HapiTest
7585
final HapiSpec sysAccountKeyUpdateBySpecialWontNeedNewKeyTxnSign() {
7686
String sysAccount = "0.0.977";

0 commit comments

Comments
 (0)