Skip to content

Commit e4d2587

Browse files
author
Cody Littley
committed
Merge branch 'develop' into 12526-automate-deduplicator
Signed-off-by: Cody Littley <[email protected]>
2 parents 250323c + 488d80c commit e4d2587

File tree

15 files changed

+225
-119
lines changed

15 files changed

+225
-119
lines changed

.github/CODEOWNERS

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
# Hedera Node Deployments - Configuration & Grafana Dashboards
1616
/hedera-node/configuration/** @rbair23 @dalvizu @poulok @netopyr @Nana-EC @SimiHunjan @steven-sheehy @nathanklick
17+
/hedera-node/configuration/dev/** @hashgraph/hedera-base @hashgraph/hedera-services
1718
/hedera-node/infrastructure/** @hashgraph/release-engineering @hashgraph/devops @hashgraph/hedera-base @hashgraph/hedera-services
1819

1920
# Hedera Node Docker Definitions

hedera-node/configuration/dev/application.properties

+1
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ staking.fees.nodeRewardPercentage=10
99
staking.fees.stakingRewardPercentage=10
1010
# Needed for Restart and Reconnect HapiTests that run many transactions of each type
1111
bootstrap.throttleDefsJson.resource=genesis/throttles-dev.json
12+
ledger.id=0x03

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

+11-2
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import com.hedera.node.app.state.DeduplicationCache;
2727
import com.hedera.node.config.ConfigProvider;
2828
import com.hedera.node.config.data.HederaConfig;
29+
import com.hedera.node.config.data.LedgerConfig;
2930
import com.hedera.node.config.data.StatsConfig;
3031
import com.hedera.node.config.types.Profile;
3132
import com.hedera.pbj.runtime.io.buffer.Bytes;
@@ -70,6 +71,9 @@ public class SubmissionManager {
7071

7172
private static final String PLATFORM_TXN_REJECTIONS_DESC = "number of platform transactions not created per second";
7273
private static final String SPEEDOMETER_FORMAT = "%,13.2f";
74+
private static final Bytes MAIN_NET_LEDGER_ID = Bytes.fromHex("00");
75+
private static final Bytes TEST_NET_LEDGER_ID = Bytes.fromHex("01");
76+
private static final Bytes PREVIEW_NET_LEDGER_ID = Bytes.fromHex("02");
7377

7478
// FUTURE Consider adding a metric to keep track of the number of duplicate transactions submitted by users.
7579

@@ -130,8 +134,13 @@ public void submit(@NonNull final TransactionBody txBody, @NonNull final Bytes t
130134
if (txBody.hasUncheckedSubmit()) {
131135
// We do NOT allow this call in production!
132136
// check profile dynamically, this way we allow profile overriding in Hapi tests
133-
final var hederaConfig = configProvider.getConfiguration().getConfigData(HederaConfig.class);
134-
if (hederaConfig.activeProfile() == Profile.PROD) {
137+
final var configuration = configProvider.getConfiguration();
138+
final var hederaConfig = configuration.getConfigData(HederaConfig.class);
139+
final var ledgerConfig = configuration.getConfigData(LedgerConfig.class);
140+
if (hederaConfig.activeProfile() == Profile.PROD
141+
|| MAIN_NET_LEDGER_ID.equals(ledgerConfig.id())
142+
|| TEST_NET_LEDGER_ID.equals(ledgerConfig.id())
143+
|| PREVIEW_NET_LEDGER_ID.equals(ledgerConfig.id())) {
135144
throw new PreCheckException(PLATFORM_TRANSACTION_NOT_CREATED);
136145
}
137146

hedera-node/hedera-app/src/test/java/com/hedera/node/app/workflows/ingest/SubmissionManagerTest.java

+80
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,7 @@ void setup() {
202202
config = () -> new VersionedConfigImpl(
203203
HederaTestConfigBuilder.create()
204204
.withValue("hedera.profiles.active", Profile.TEST.toString())
205+
.withValue("ledger.id", "0x03")
205206
.getOrCreateConfig(),
206207
1);
207208
when(mockedMetrics.getOrCreate(any())).thenReturn(platformTxnRejections);
@@ -245,6 +246,85 @@ void testUncheckedSubmitInProdFails() {
245246
config = () -> new VersionedConfigImpl(
246247
HederaTestConfigBuilder.create()
247248
.withValue("hedera.profiles.active", Profile.PROD.toString())
249+
.withValue("ledger.id", "0x03")
250+
.getOrCreateConfig(),
251+
1);
252+
submissionManager = new SubmissionManager(platform, deduplicationCache, config, mockedMetrics);
253+
254+
// When we submit an unchecked transaction, and separate bytes, then the
255+
// submission FAILS because we are in PROD mode
256+
assertThatThrownBy(() -> submissionManager.submit(txBody, bytes))
257+
.isInstanceOf(PreCheckException.class)
258+
.hasFieldOrPropertyWithValue("responseCode", PLATFORM_TRANSACTION_NOT_CREATED);
259+
260+
// Then the platform NEVER sees the unchecked bytes
261+
verify(platform, never()).createTransaction(uncheckedBytes);
262+
// We never attempted to submit this tx to the platform, so we don't increase the metric
263+
verify(platformTxnRejections, never()).cycle();
264+
// And the deduplication cache is not updated
265+
verify(deduplicationCache, never()).add(any());
266+
}
267+
268+
@Test
269+
@DisplayName("An unchecked transaction on MainNet WILL FAIL")
270+
void testUncheckedSubmitOnMainNetFails() {
271+
// Given we are in PROD mode
272+
config = () -> new VersionedConfigImpl(
273+
HederaTestConfigBuilder.create()
274+
.withValue("hedera.profiles.active", Profile.TEST.toString())
275+
.withValue("ledger.id", "0x00")
276+
.getOrCreateConfig(),
277+
1);
278+
submissionManager = new SubmissionManager(platform, deduplicationCache, config, mockedMetrics);
279+
280+
// When we submit an unchecked transaction, and separate bytes, then the
281+
// submission FAILS because we are in PROD mode
282+
assertThatThrownBy(() -> submissionManager.submit(txBody, bytes))
283+
.isInstanceOf(PreCheckException.class)
284+
.hasFieldOrPropertyWithValue("responseCode", PLATFORM_TRANSACTION_NOT_CREATED);
285+
286+
// Then the platform NEVER sees the unchecked bytes
287+
verify(platform, never()).createTransaction(uncheckedBytes);
288+
// We never attempted to submit this tx to the platform, so we don't increase the metric
289+
verify(platformTxnRejections, never()).cycle();
290+
// And the deduplication cache is not updated
291+
verify(deduplicationCache, never()).add(any());
292+
}
293+
294+
@Test
295+
@DisplayName("An unchecked transaction on TestNet WILL FAIL")
296+
void testUncheckedSubmitOnTestNetFails() {
297+
// Given we are in PROD mode
298+
config = () -> new VersionedConfigImpl(
299+
HederaTestConfigBuilder.create()
300+
.withValue("hedera.profiles.active", Profile.TEST.toString())
301+
.withValue("ledger.id", "0x01")
302+
.getOrCreateConfig(),
303+
1);
304+
submissionManager = new SubmissionManager(platform, deduplicationCache, config, mockedMetrics);
305+
306+
// When we submit an unchecked transaction, and separate bytes, then the
307+
// submission FAILS because we are in PROD mode
308+
assertThatThrownBy(() -> submissionManager.submit(txBody, bytes))
309+
.isInstanceOf(PreCheckException.class)
310+
.hasFieldOrPropertyWithValue("responseCode", PLATFORM_TRANSACTION_NOT_CREATED);
311+
312+
// Then the platform NEVER sees the unchecked bytes
313+
verify(platform, never()).createTransaction(uncheckedBytes);
314+
// We never attempted to submit this tx to the platform, so we don't increase the metric
315+
verify(platformTxnRejections, never()).cycle();
316+
// And the deduplication cache is not updated
317+
verify(deduplicationCache, never()).add(any());
318+
}
319+
320+
@Test
321+
@DisplayName("An unchecked transaction on PreviewNet WILL FAIL")
322+
void testUncheckedSubmitOnPreviewNetFails() {
323+
// Given we are in PROD mode
324+
config = () -> new VersionedConfigImpl(
325+
HederaTestConfigBuilder.create()
326+
.withValue("hedera.profiles.active", Profile.TEST.toString())
327+
.withValue("ledger.id", "0x02")
248328
.getOrCreateConfig(),
249329
1);
250330
submissionManager = new SubmissionManager(platform, deduplicationCache, config, mockedMetrics);

hedera-node/hedera-smart-contract-service-impl/src/main/java/module-info.java

+1
Original file line numberDiff line numberDiff line change
@@ -69,4 +69,5 @@
6969
com.hedera.node.app.service.contract.impl.test;
7070

7171
exports com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.mint;
72+
exports com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.associations;
7273
}

hedera-node/test-clients/src/main/java/com/hedera/services/bdd/suites/contract/precompile/AssociatePrecompileV2SecurityModelSuite.java

+43-3
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package com.hedera.services.bdd.suites.contract.precompile;
1818

19+
import static com.hedera.services.bdd.junit.TestTags.SMART_CONTRACT;
1920
import static com.hedera.services.bdd.spec.HapiSpec.defaultHapiSpec;
2021
import static com.hedera.services.bdd.spec.assertions.ContractFnResultAsserts.resultWith;
2122
import static com.hedera.services.bdd.spec.assertions.TransactionRecordAsserts.recordWith;
@@ -56,6 +57,7 @@
5657
import static com.hederahashgraph.api.proto.java.TokenType.NON_FUNGIBLE_UNIQUE;
5758

5859
import com.esaulpaugh.headlong.abi.Address;
60+
import com.hedera.node.app.service.contract.impl.exec.systemcontracts.hts.associations.AssociationsTranslator;
5961
import com.hedera.services.bdd.junit.HapiTest;
6062
import com.hedera.services.bdd.junit.HapiTestSuite;
6163
import com.hedera.services.bdd.spec.HapiSpec;
@@ -66,8 +68,11 @@
6668
import java.util.List;
6769
import org.apache.logging.log4j.LogManager;
6870
import org.apache.logging.log4j.Logger;
71+
import org.apache.tuweni.bytes.Bytes;
72+
import org.junit.jupiter.api.Tag;
6973

7074
@HapiTestSuite
75+
@Tag(SMART_CONTRACT)
7176
public class AssociatePrecompileV2SecurityModelSuite extends HapiSuite {
7277

7378
private static final Logger log = LogManager.getLogger(AssociatePrecompileV1SecurityModelSuite.class);
@@ -91,6 +96,7 @@ public class AssociatePrecompileV2SecurityModelSuite extends HapiSuite {
9196
private static final String ADMIN_KEY = "Admin key";
9297
private static final String CONTRACT_KEY = "ContractKey";
9398
private static final String MINT_TOKEN_CONTRACT = "MixedMintToken";
99+
private static final String CALLCODE_CONTRACT = "MixedMintToken";
94100

95101
public static void main(String... args) {
96102
new AssociatePrecompileV2SecurityModelSuite().runSuiteAsync();
@@ -623,7 +629,7 @@ final HapiSpec V2Security041TokenAssociateFromStaticcallAndCallcode() {
623629
return defaultHapiSpec("V2Security041TokenAssociateFromStaticcallAndCallcode")
624630
.given(
625631
cryptoCreate(ACCOUNT).balance(ONE_HUNDRED_HBARS),
626-
cryptoCreate(TOKEN_TREASURY),
632+
cryptoCreate(TOKEN_TREASURY).balance(THOUSAND_HBAR),
627633
tokenCreate(FUNGIBLE_TOKEN)
628634
.tokenType(FUNGIBLE_COMMON)
629635
.supplyKey(TOKEN_TREASURY)
@@ -635,8 +641,9 @@ final HapiSpec V2Security041TokenAssociateFromStaticcallAndCallcode() {
635641
.initialSupply(0)
636642
.adminKey(TOKEN_TREASURY)
637643
.treasury(TOKEN_TREASURY),
638-
uploadInitCode(ASSOCIATE_CONTRACT, NESTED_ASSOCIATE_CONTRACT),
639-
contractCreate(ASSOCIATE_CONTRACT))
644+
uploadInitCode(ASSOCIATE_CONTRACT, NESTED_ASSOCIATE_CONTRACT, CALLCODE_CONTRACT),
645+
contractCreate(ASSOCIATE_CONTRACT),
646+
contractCreate(CALLCODE_CONTRACT))
640647
.when(withOpContext((spec, opLog) -> allRunFor(
641648
spec,
642649
contractCreate(
@@ -646,6 +653,9 @@ final HapiSpec V2Security041TokenAssociateFromStaticcallAndCallcode() {
646653
newKeyNamed(CONTRACT_KEY)
647654
.shape(THRESHOLD_KEY_SHAPE.signedWith(sigs(ON, NESTED_ASSOCIATE_CONTRACT))),
648655
cryptoUpdate(ACCOUNT).key(CONTRACT_KEY),
656+
// Test Case 1: Account paying and signing a nested fungible TOKEN ASSOCIATE TRANSACTION,
657+
// when we associate the token to the signer
658+
// via STATICCALL
649659
contractCall(
650660
NESTED_ASSOCIATE_CONTRACT,
651661
"associateStaticCall",
@@ -660,10 +670,40 @@ final HapiSpec V2Security041TokenAssociateFromStaticcallAndCallcode() {
660670
.gas(GAS_TO_OFFER)
661671
.hasKnownStatus(CONTRACT_REVERT_EXECUTED),
662672
getTxnRecord("associateStaticcallFungibleTxn")
673+
.andAllChildRecords()
674+
.logged(),
675+
// Test Case 2: Account paying and signing a nested fungible TOKEN ASSOCIATE TRANSACTION,
676+
// when we associate the token to the signer
677+
// via CALLCODE
678+
// SIGNER → call → CONTRACT A → callcode → CONTRACT B → call → PRECOMPILE(HTS)
679+
contractCall(
680+
CALLCODE_CONTRACT,
681+
"callCodeToContractWithoutAmount",
682+
asHeadlongAddress(getNestedContractAddress(ASSOCIATE_CONTRACT, spec)),
683+
Bytes.wrap(AssociationsTranslator.ASSOCIATE_ONE
684+
.encodeCallWithArgs(
685+
HapiParserUtil.asHeadlongAddress(asAddress(
686+
spec.registry()
687+
.getAccountID(ACCOUNT))),
688+
HapiParserUtil.asHeadlongAddress(asAddress(
689+
spec.registry()
690+
.getTokenID(FUNGIBLE_TOKEN))))
691+
.array())
692+
.toArray())
693+
.via("associateCallcodeFungibleTxn")
694+
.gas(GAS_TO_OFFER)
695+
.sending(ONE_HUNDRED_HBARS)
696+
.signedBy(TOKEN_TREASURY)
697+
.payingWith(TOKEN_TREASURY)
698+
.hasRetryPrecheckFrom(BUSY)
699+
// Verify that the top level status of the transaction is CONTRACT_REVERT_EXECUTED
700+
.hasKnownStatus(CONTRACT_REVERT_EXECUTED),
701+
getTxnRecord("associateCallcodeFungibleTxn")
663702
.andAllChildRecords()
664703
.logged())))
665704
.then(
666705
emptyChildRecordsCheck("associateStaticcallFungibleTxn", CONTRACT_REVERT_EXECUTED),
706+
emptyChildRecordsCheck("associateCallcodeFungibleTxn", CONTRACT_REVERT_EXECUTED),
667707
getAccountInfo(ACCOUNT).hasNoTokenRelationship(FUNGIBLE_TOKEN));
668708
}
669709

hedera-node/test-clients/src/main/java/com/hedera/services/bdd/suites/contract/precompile/ContractMintHTSV2SecurityModelSuite.java

+3
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package com.hedera.services.bdd.suites.contract.precompile;
1818

19+
import static com.hedera.services.bdd.junit.TestTags.SMART_CONTRACT;
1920
import static com.hedera.services.bdd.spec.HapiPropertySource.asToken;
2021
import static com.hedera.services.bdd.spec.HapiSpec.defaultHapiSpec;
2122
import static com.hedera.services.bdd.spec.assertions.TransactionRecordAsserts.recordWith;
@@ -65,8 +66,10 @@
6566
import org.apache.logging.log4j.LogManager;
6667
import org.apache.logging.log4j.Logger;
6768
import org.apache.tuweni.bytes.Bytes;
69+
import org.junit.jupiter.api.Tag;
6870

6971
@HapiTestSuite
72+
@Tag(SMART_CONTRACT)
7073
@SuppressWarnings("java:S1192") // "string literal should not be duplicated" - this rule makes test suites worse
7174
public class ContractMintHTSV2SecurityModelSuite extends HapiSuite {
7275

platform-sdk/docs/core/wiring-diagram.svg

+1-1
Loading

platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/wiring/PlatformSchedulersConfig.java

-5
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,6 @@
3737
* scheduler
3838
* @param internalEventValidator configuration for the internal event validator scheduler
3939
* @param eventDeduplicator configuration for the event deduplicator scheduler
40-
* @param eventDeduplicatorSchedulerType the event deduplicator scheduler type
41-
* @param eventDeduplicatorUnhandledCapacity number of unhandled tasks allowed in the event deduplicator
42-
* scheduler
4340
* @param eventSignatureValidatorSchedulerType the event signature validator scheduler type
4441
* @param eventSignatureValidatorUnhandledCapacity number of unhandled tasks allowed in the event signature
4542
* validator scheduler
@@ -100,8 +97,6 @@ public record PlatformSchedulersConfig(
10097
TaskSchedulerConfiguration internalEventValidator,
10198
@ConfigProperty(defaultValue = "SEQUENTIAL CAPACITY(500) FLUSHABLE UNHANDLED_TASK_METRIC")
10299
TaskSchedulerConfiguration eventDeduplicator,
103-
@ConfigProperty(defaultValue = "SEQUENTIAL") TaskSchedulerType eventDeduplicatorSchedulerType,
104-
@ConfigProperty(defaultValue = "500") int eventDeduplicatorUnhandledCapacity,
105100
@ConfigProperty(defaultValue = "SEQUENTIAL") TaskSchedulerType eventSignatureValidatorSchedulerType,
106101
@ConfigProperty(defaultValue = "500") int eventSignatureValidatorUnhandledCapacity,
107102
@ConfigProperty(defaultValue = "SEQUENTIAL") TaskSchedulerType orphanBufferSchedulerType,

platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/wiring/components/StateSignatureCollectorWiring.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ private StateSignatureCollectorWiring(
7575
preConsensusTransformer = new WireTransformer<>(
7676
model,
7777
"extractPreconsensusSignatureTransactions",
78-
"preconsensus events",
78+
"preconsensus signatures",
7979
event -> SystemTransactionExtractionUtils.extractFromEvent(
8080
event, StateSignatureTransaction.class));
8181
preConsensusEventInput = preConsensusTransformer.getInputWire();

platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/wiring/generate-platform-diagram.sh

+6-2
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,12 @@ pcli diagram \
2121
-s 'getKeystoneEventSequenceNumber:flush request:🚽' \
2222
-s 'extractOldestMinimumGenerationOnDisk:minimum identifier to store:📀' \
2323
-s 'eventCreationManager:non-validated events:🍎' \
24-
-s 'Mystery Input:mystery data:X' \
24+
-s 'Mystery Input:mystery data:' \
2525
-s 'stateSigner:signature transactions:🖋️' \
26+
-s 'issNotificationSplitter:IssNotification:💥' \
27+
-s 'toNotification:StateWriteToDiskCompleteNotification:📦' \
28+
-s 'latestCompleteStateNotifier:CompleteStateNotificationWithCleanup:💢' \
29+
-s 'orphanBufferSplitter:preconsensus signatures:🔰' \
2630
-g 'Event Validation:InternalEventValidator,EventDeduplicator,eventSignatureValidator' \
2731
-g 'Event Hashing:eventHasher,postHashCollector' \
2832
-g 'Orphan Buffer:orphanBuffer,orphanBufferSplitter' \
@@ -38,10 +42,10 @@ pcli diagram \
3842
-g 'Heartbeat:heartbeat,❤️' \
3943
-g 'PCES Replay:pcesReplayer,✅' \
4044
-g 'Transaction Prehandling:applicationTransactionPrehandler,🔮' \
41-
-g 'Signature Management:State Signature Collection,stateSigner,🖋️' \
4245
-g 'Consensus Round Handler:consensusRoundHandler,postHandler_stateAndRoundReserver,postHandler_getRoundNumber,postHandler_stateReserver' \
4346
-g 'State Hasher:stateHasher,postHasher_stateAndRoundReserver,postHasher_getConsensusRound,postHasher_stateReserver' \
4447
-g 'State Modification:Consensus Round Handler,runningHashUpdate' \
48+
-g 'State Verification:stateSigner,hashLogger,ISS Detector,🖋️,💥' \
4549
-c 'Consensus Event Stream' \
4650
-c 'Orphan Buffer' \
4751
-c 'Consensus Engine' \

0 commit comments

Comments
 (0)