Skip to content

Commit f61f7ad

Browse files
author
Cody Littley
committed
Merge branch 'develop' into 12528-no-op-scheduler
Signed-off-by: Cody Littley <[email protected]>
2 parents deb3a38 + adf9713 commit f61f7ad

File tree

52 files changed

+954
-436
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+954
-436
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/ServicesMain.java

+6-5
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,9 @@
1818

1919
import static com.swirlds.common.io.utility.FileUtils.getAbsolutePath;
2020
import static com.swirlds.logging.legacy.LogMarker.EXCEPTION;
21-
import static com.swirlds.platform.PlatformBuilder.DEFAULT_SETTINGS_FILE_NAME;
22-
import static com.swirlds.platform.PlatformBuilder.buildPlatformContext;
21+
import static com.swirlds.platform.builder.PlatformBuildConstants.DEFAULT_CONFIG_FILE_NAME;
22+
import static com.swirlds.platform.builder.PlatformBuildConstants.DEFAULT_SETTINGS_FILE_NAME;
23+
import static com.swirlds.platform.builder.PlatformBuilder.buildPlatformContext;
2324
import static com.swirlds.platform.system.SystemExitCode.CONFIGURATION_ERROR;
2425
import static com.swirlds.platform.system.SystemExitCode.NODE_ADDRESS_MISMATCH;
2526
import static com.swirlds.platform.system.SystemExitUtils.exitSystem;
@@ -37,7 +38,7 @@
3738
import com.swirlds.config.extensions.sources.SystemEnvironmentConfigSource;
3839
import com.swirlds.config.extensions.sources.SystemPropertiesConfigSource;
3940
import com.swirlds.platform.CommandLineArgs;
40-
import com.swirlds.platform.PlatformBuilder;
41+
import com.swirlds.platform.builder.PlatformBuilder;
4142
import com.swirlds.platform.config.legacy.ConfigurationException;
4243
import com.swirlds.platform.config.legacy.LegacyConfigProperties;
4344
import com.swirlds.platform.config.legacy.LegacyConfigPropertiesLoader;
@@ -128,7 +129,7 @@ public static void main(final String... args) throws Exception {
128129

129130
// Determine which node to run locally
130131
// Load config.txt address book file and parse address book
131-
final AddressBook addressBook = loadAddressBook(PlatformBuilder.DEFAULT_CONFIG_FILE_NAME);
132+
final AddressBook addressBook = loadAddressBook(DEFAULT_CONFIG_FILE_NAME);
132133
// parse command line arguments
133134
final CommandLineArgs commandLineArgs = CommandLineArgs.parse(args);
134135

@@ -160,7 +161,7 @@ public static void main(final String... args) throws Exception {
160161
buildPlatformContext(config, getAbsolutePath(DEFAULT_SETTINGS_FILE_NAME), selfId);
161162

162163
final PlatformBuilder builder =
163-
new PlatformBuilder(Hedera.APP_NAME, Hedera.SWIRLD_NAME, version, hedera::newState, selfId);
164+
PlatformBuilder.create(Hedera.APP_NAME, Hedera.SWIRLD_NAME, version, hedera::newState, selfId);
164165

165166
builder.withPreviousSoftwareVersionClassId(0x6f2b1bc2df8cbd0bL /* SerializableSemVers.CLASS_ID */);
166167
builder.withPlatformContext(platformContext);

hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleContextImpl.java

+9-35
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
import static com.hedera.node.app.state.HederaRecordCache.DuplicateCheckResult.NO_DUPLICATE;
2929
import static com.hedera.node.app.workflows.handle.HandleContextImpl.PrecedingTransactionCategory.LIMITED_CHILD_RECORDS;
3030
import static com.hedera.node.app.workflows.handle.HandleWorkflow.extraRewardReceivers;
31-
import static java.util.Collections.emptySet;
31+
import static java.util.Collections.emptyMap;
3232
import static java.util.Objects.requireNonNull;
3333

3434
import com.hedera.hapi.node.base.AccountID;
@@ -104,10 +104,10 @@
104104
import edu.umd.cs.findbugs.annotations.NonNull;
105105
import edu.umd.cs.findbugs.annotations.Nullable;
106106
import java.time.Instant;
107-
import java.util.LinkedHashSet;
107+
import java.util.LinkedHashMap;
108108
import java.util.List;
109+
import java.util.Map;
109110
import java.util.Objects;
110-
import java.util.Set;
111111
import java.util.function.Function;
112112
import java.util.function.Predicate;
113113
import java.util.function.Supplier;
@@ -156,7 +156,7 @@ public class HandleContextImpl implements HandleContext, FeeContext {
156156
private AttributeValidator attributeValidator;
157157
private ExpiryValidator expiryValidator;
158158
private ExchangeRateInfo exchangeRateInfo;
159-
private Set<AccountID> dispatchPaidStakerIds;
159+
private Map<AccountID, Long> dispatchPaidRewards;
160160
private PlatformState platformState;
161161

162162
/**
@@ -644,8 +644,8 @@ private <T> T doDispatchChildTransaction(
644644
return castRecordBuilder(childRecordBuilder, recordBuilderClass);
645645
}
646646

647-
public @NonNull Set<AccountID> dispatchPaidStakerIds() {
648-
return dispatchPaidStakerIds == null ? emptySet() : dispatchPaidStakerIds;
647+
public @NonNull Map<AccountID, Long> dispatchPaidRewards() {
648+
return dispatchPaidRewards == null ? emptyMap() : dispatchPaidRewards;
649649
}
650650

651651
private void dispatchSyntheticTxn(
@@ -783,36 +783,10 @@ private void dispatchSyntheticTxn(
783783
payer, finalizeContext, function, extraRewardReceivers(txBody, function, childRecordBuilder));
784784
final var paidStakingRewards = childRecordBuilder.getPaidStakingRewards();
785785
if (!paidStakingRewards.isEmpty()) {
786-
if (dispatchPaidStakerIds == null) {
787-
dispatchPaidStakerIds = new LinkedHashSet<>();
786+
if (dispatchPaidRewards == null) {
787+
dispatchPaidRewards = new LinkedHashMap<>();
788788
}
789-
paidStakingRewards.forEach(aa -> dispatchPaidStakerIds.add(aa.accountIDOrThrow()));
790-
}
791-
} else {
792-
final var finalizeContext = new ChildFinalizeContextImpl(
793-
new ReadableStoreFactory(childStack),
794-
new WritableStoreFactory(childStack, TokenService.NAME),
795-
childRecordBuilder);
796-
childRecordFinalizer.finalizeChildRecord(finalizeContext, function);
797-
}
798-
// For mono-service fidelity, we need to attach staking rewards for a
799-
// triggered transaction to the record of the child here, and not the
800-
// "parent" ScheduleCreate or ScheduleSign transaction
801-
if (childCategory == SCHEDULED) {
802-
final var finalizeContext = new TriggeredFinalizeContext(
803-
new ReadableStoreFactory(childStack),
804-
new WritableStoreFactory(childStack, TokenService.NAME),
805-
childRecordBuilder,
806-
consensusNow(),
807-
configuration);
808-
parentRecordFinalizer.finalizeParentRecord(
809-
payer, finalizeContext, function, extraRewardReceivers(txBody, function, childRecordBuilder));
810-
final var paidStakingRewards = childRecordBuilder.getPaidStakingRewards();
811-
if (!paidStakingRewards.isEmpty()) {
812-
if (dispatchPaidStakerIds == null) {
813-
dispatchPaidStakerIds = new LinkedHashSet<>();
814-
}
815-
paidStakingRewards.forEach(aa -> dispatchPaidStakerIds.add(aa.accountIDOrThrow()));
789+
paidStakingRewards.forEach(aa -> dispatchPaidRewards.put(aa.accountIDOrThrow(), aa.amount()));
816790
}
817791
} else {
818792
final var finalizeContext = new ChildFinalizeContextImpl(

hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/HandleWorkflow.java

+5-3
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
import static com.hedera.node.app.workflows.prehandle.PreHandleResult.Status.PRE_HANDLE_FAILURE;
4747
import static com.hedera.node.app.workflows.prehandle.PreHandleResult.Status.SO_FAR_SO_GOOD;
4848
import static java.util.Collections.emptyList;
49+
import static java.util.Collections.emptyMap;
4950
import static java.util.Collections.emptySet;
5051
import static java.util.Objects.requireNonNull;
5152

@@ -126,6 +127,7 @@
126127
import java.util.EnumSet;
127128
import java.util.LinkedHashSet;
128129
import java.util.List;
130+
import java.util.Map;
129131
import java.util.Set;
130132
import java.util.concurrent.atomic.AtomicBoolean;
131133
import javax.inject.Inject;
@@ -355,7 +357,7 @@ private void handleUserTransaction(
355357
AccountID payer = null;
356358
Fees fees = null;
357359
TransactionInfo transactionInfo = null;
358-
Set<AccountID> prePaidRewardReceivers = emptySet();
360+
Map<AccountID, Long> prePaidRewards = emptyMap();
359361
try {
360362
final var preHandleResult = getCurrentPreHandleResult(readableStoreFactory, creator, platformTxn);
361363

@@ -549,7 +551,7 @@ private void handleUserTransaction(
549551
recordBuilder.status(SUCCESS);
550552
// Only ScheduleCreate and ScheduleSign can trigger paid staking rewards via
551553
// dispatch; and only if this top-level transaction was successful
552-
prePaidRewardReceivers = context.dispatchPaidStakerIds();
554+
prePaidRewards = context.dispatchPaidRewards();
553555

554556
// Notify responsible facility if system-file was uploaded.
555557
// Returns SUCCESS if no system-file was uploaded
@@ -625,7 +627,7 @@ private void handleUserTransaction(
625627
tokenServiceContext,
626628
function,
627629
extraRewardReceivers(transactionInfo, recordBuilder),
628-
prePaidRewardReceivers);
630+
prePaidRewards);
629631

630632
// Commit all state changes
631633
stack.commitFullStack();

hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/TokenContextImpl.java

+5
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,11 @@ public boolean isFirstTransaction() {
131131
return isFirstTransaction;
132132
}
133133

134+
@Override
135+
public boolean isScheduleDispatch() {
136+
return false;
137+
}
138+
134139
@Override
135140
public void markMigrationRecordsStreamed() {
136141
blockRecordManager.markMigrationRecordsStreamed();

hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/handle/TriggeredFinalizeContext.java

+5
Original file line numberDiff line numberDiff line change
@@ -67,4 +67,9 @@ public boolean hasChildRecords() {
6767
public <T> void forEachChildRecord(@NonNull Class<T> recordBuilderClass, @NonNull Consumer<T> consumer) {
6868
// No-op, as contract operations cannot be scheduled at this time
6969
}
70+
71+
@Override
72+
public boolean isScheduleDispatch() {
73+
return true;
74+
}
7075
}

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/hedera-token-service-impl/src/main/java/com/hedera/node/app/service/token/impl/handlers/FinalizeParentRecordHandler.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ public void finalizeParentRecord(
7777
@NonNull final FinalizeContext context,
7878
@NonNull final HederaFunctionality functionality,
7979
@NonNull final Set<AccountID> explicitRewardReceivers,
80-
@NonNull final Set<AccountID> prePaidRewardReceivers) {
80+
@NonNull final Map<AccountID, Long> prePaidRewards) {
8181
final var recordBuilder = context.userTransactionRecordBuilder(CryptoTransferRecordBuilder.class);
8282

8383
// This handler won't ask the context for its transaction, but instead will determine the net hbar transfers and
@@ -97,7 +97,7 @@ public void finalizeParentRecord(
9797
// Calculate staking rewards and add them also to hbarChanges here, before assessing
9898
// net changes for transaction record
9999
final var rewardsPaid =
100-
stakingRewardsHandler.applyStakingRewards(context, explicitRewardReceivers, prePaidRewardReceivers);
100+
stakingRewardsHandler.applyStakingRewards(context, explicitRewardReceivers, prePaidRewards);
101101
if (requiresExternalization(rewardsPaid)) {
102102
recordBuilder.paidStakingRewards(asAccountAmounts(rewardsPaid));
103103
}

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,13 @@ public interface StakingRewardsHandler {
4949
*
5050
* @param context the context of the transaction
5151
* @param explicitRewardReceivers a set of accounts that must be considered for rewards independent of the context
52-
* @param prePaidRewardReceivers a set of accounts that have already been paid rewards in the current transaction
52+
* @param prePaidRewards a set of accounts that have already been paid rewards in the current transaction
5353
* @return a map of account id to the amount of rewards paid out
5454
*/
5555
Map<AccountID, Long> applyStakingRewards(
5656
FinalizeContext context,
5757
@NonNull Set<AccountID> explicitRewardReceivers,
58-
@NonNull Set<AccountID> prePaidRewardReceivers);
58+
@NonNull Map<AccountID, Long> prePaidRewards);
5959

6060
/**
6161
* Checks if the account has been rewarded since the last staking metadata change.

0 commit comments

Comments
 (0)