Skip to content

Commit 0f87ff2

Browse files
authored
chore: 21153 tss block signing threshold (#21629)
Signed-off-by: artemderevets <[email protected]>
1 parent 0e8238e commit 0f87ff2

File tree

11 files changed

+38
-70
lines changed

11 files changed

+38
-70
lines changed

hedera-node/hedera-app/src/main/java/com/hedera/node/app/ServicesMain.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@
4141
import com.hedera.node.app.state.ConsensusStateEventHandlerImpl;
4242
import com.hedera.node.app.tss.TssBlockHashSigner;
4343
import com.hedera.node.config.data.BlockStreamConfig;
44-
import com.hedera.node.config.data.TssConfig;
4544
import com.hedera.node.internal.network.Network;
4645
import com.hedera.node.internal.network.NodeMetadata;
4746
import com.hedera.pbj.runtime.io.buffer.Bytes;
@@ -465,8 +464,7 @@ public static Hedera newHedera(
465464
ForkJoinPool.commonPool(),
466465
appContext,
467466
new HintsLibraryImpl(),
468-
bootstrapConfig.getConfigData(BlockStreamConfig.class).blockPeriod(),
469-
bootstrapConfig.getConfigData(TssConfig.class)),
467+
bootstrapConfig.getConfigData(BlockStreamConfig.class).blockPeriod()),
470468
(appContext, bootstrapConfig) -> new HistoryServiceImpl(
471469
metrics, ForkJoinPool.commonPool(), appContext, new HistoryLibraryImpl(), bootstrapConfig),
472470
TssBlockHashSigner::new,

hedera-node/hedera-app/src/main/java/com/hedera/node/app/hints/impl/HintsContext.java

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import com.hedera.node.app.hints.HintsLibrary;
1212
import com.hedera.node.config.data.TssConfig;
1313
import com.hedera.pbj.runtime.io.buffer.Bytes;
14+
import com.swirlds.config.api.Configuration;
1415
import edu.umd.cs.findbugs.annotations.NonNull;
1516
import edu.umd.cs.findbugs.annotations.Nullable;
1617
import java.time.Duration;
@@ -24,6 +25,7 @@
2425
import java.util.concurrent.ScheduledExecutorService;
2526
import java.util.concurrent.atomic.AtomicBoolean;
2627
import java.util.concurrent.atomic.AtomicLong;
28+
import java.util.function.Supplier;
2729
import javax.inject.Inject;
2830
import javax.inject.Singleton;
2931
import org.apache.logging.log4j.LogManager;
@@ -43,7 +45,7 @@ public class HintsContext {
4345
private final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
4446

4547
private final HintsLibrary library;
46-
private final TssConfig tssConfig;
48+
private final Supplier<Configuration> configProvider;
4749

4850
@Nullable
4951
private Bytes crs;
@@ -57,9 +59,9 @@ public class HintsContext {
5759
private long schemeId;
5860

5961
@Inject
60-
public HintsContext(@NonNull final HintsLibrary library, @NonNull final TssConfig tssConfig) {
62+
public HintsContext(@NonNull final HintsLibrary library, @NonNull final Supplier<Configuration> configProvider) {
6163
this.library = requireNonNull(library);
62-
this.tssConfig = requireNonNull(tssConfig);
64+
this.configProvider = requireNonNull(configProvider);
6365
}
6466

6567
/**
@@ -177,6 +179,7 @@ public boolean validate(
177179
totalWeight += nodePartyId.partyWeight();
178180
nodeWeights.put(nodePartyId.nodeId(), nodePartyId.partyWeight());
179181
}
182+
final var tssConfig = configProvider.get().getConfigData(TssConfig.class);
180183
final int divisor = tssConfig.signingThresholdDivisor();
181184
if (divisor <= 0) {
182185
throw new IllegalArgumentException("signingThresholdDivisor must be > 0");
@@ -284,9 +287,8 @@ public void incorporateValid(@NonNull final Bytes crs, final long nodeId, @NonNu
284287
signatures.put(partyId, signature);
285288
final var weight = nodeWeights.getOrDefault(nodeId, 0L);
286289
final var totalWeight = weightOfSignatures.addAndGet(weight);
287-
final boolean reachedThreshold = tssConfig.strictSigningThreshold()
288-
? (totalWeight > thresholdWeight)
289-
: (totalWeight >= thresholdWeight);
290+
// For block hash signing, always require strictly greater than threshold
291+
final boolean reachedThreshold = totalWeight > thresholdWeight;
290292
if (reachedThreshold && completed.compareAndSet(false, true)) {
291293
final var aggregatedSignature =
292294
library.aggregateSignatures(crs, aggregationKey, verificationKey, signatures);

hedera-node/hedera-app/src/main/java/com/hedera/node/app/hints/impl/HintsServiceComponent.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import com.hedera.node.app.hints.HintsLibrary;
66
import com.hedera.node.app.hints.handlers.HintsHandlers;
77
import com.hedera.node.app.spi.AppContext;
8-
import com.hedera.node.config.data.TssConfig;
98
import com.hedera.pbj.runtime.io.buffer.Bytes;
109
import com.swirlds.config.api.Configuration;
1110
import com.swirlds.metrics.api.Metrics;
@@ -30,8 +29,7 @@ HintsServiceComponent create(
3029
@BindsInstance Metrics metrics,
3130
@BindsInstance AtomicReference<Roster> currentRoster,
3231
@BindsInstance Duration blockPeriod,
33-
@BindsInstance OnHintsFinished onHintsFinished,
34-
@BindsInstance TssConfig tssConfig);
32+
@BindsInstance OnHintsFinished onHintsFinished);
3533
}
3634

3735
HintsHandlers handlers();

hedera-node/hedera-app/src/main/java/com/hedera/node/app/hints/impl/HintsServiceImpl.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,11 @@ public HintsServiceImpl(
5050
@NonNull final Executor executor,
5151
@NonNull final AppContext appContext,
5252
@NonNull final HintsLibrary library,
53-
@NonNull final Duration blockPeriod,
54-
@NonNull final TssConfig tssConfig) {
53+
@NonNull final Duration blockPeriod) {
5554
this.library = requireNonNull(library);
5655
// Fully qualified for benefit of javadoc
5756
this.component = com.hedera.node.app.hints.impl.DaggerHintsServiceComponent.factory()
58-
.create(library, appContext, executor, metrics, currentRoster, blockPeriod, this, tssConfig);
57+
.create(library, appContext, executor, metrics, currentRoster, blockPeriod, this);
5958
}
6059

6160
@VisibleForTesting

hedera-node/hedera-app/src/main/java/com/hedera/node/app/workflows/standalone/TransactionExecutors.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
import com.hedera.node.app.throttle.ThrottleAccumulator;
2929
import com.hedera.node.config.data.BlockStreamConfig;
3030
import com.hedera.node.config.data.HederaConfig;
31-
import com.hedera.node.config.data.TssConfig;
3231
import com.hedera.node.config.types.StreamMode;
3332
import com.hedera.pbj.runtime.io.buffer.Bytes;
3433
import com.swirlds.common.metrics.noop.NoOpMetrics;
@@ -291,8 +290,7 @@ private ExecutorComponent newExecutorComponent(
291290
ForkJoinPool.commonPool(),
292291
appContext,
293292
new HintsLibraryImpl(),
294-
bootstrapConfig.getConfigData(BlockStreamConfig.class).blockPeriod(),
295-
bootstrapConfig.getConfigData(TssConfig.class));
293+
bootstrapConfig.getConfigData(BlockStreamConfig.class).blockPeriod());
296294
final var historyService = new HistoryServiceImpl(
297295
NO_OP_METRICS, ForkJoinPool.commonPool(), appContext, new HistoryLibraryImpl(), bootstrapConfig);
298296
final var component = DaggerExecutorComponent.builder()

hedera-node/hedera-app/src/test/java/com/hedera/node/app/components/IngestComponentTest.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@
4545
import com.hedera.node.app.state.recordcache.RecordCacheService;
4646
import com.hedera.node.config.data.BlockStreamConfig;
4747
import com.hedera.node.config.data.HederaConfig;
48-
import com.hedera.node.config.data.TssConfig;
4948
import com.hedera.node.config.testfixtures.HederaTestConfigBuilder;
5049
import com.hedera.pbj.runtime.io.buffer.Bytes;
5150
import com.swirlds.common.context.PlatformContext;
@@ -133,8 +132,7 @@ void setUp() {
133132
ForkJoinPool.commonPool(),
134133
appContext,
135134
new HintsLibraryImpl(),
136-
DEFAULT_CONFIG.getConfigData(BlockStreamConfig.class).blockPeriod(),
137-
DEFAULT_CONFIG.getConfigData(TssConfig.class));
135+
DEFAULT_CONFIG.getConfigData(BlockStreamConfig.class).blockPeriod());
138136
final var historyService = new HistoryServiceImpl(
139137
NO_OP_METRICS, ForkJoinPool.commonPool(), appContext, new HistoryLibraryImpl(), DEFAULT_CONFIG);
140138
app = DaggerHederaInjectionComponent.builder()

hedera-node/hedera-app/src/test/java/com/hedera/node/app/hints/impl/HintsContextTest.java

Lines changed: 18 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
import static org.junit.jupiter.api.Assertions.*;
55
import static org.mockito.BDDMockito.given;
6+
import static org.mockito.Mockito.lenient;
67

78
import com.hedera.hapi.node.state.hints.HintsConstruction;
89
import com.hedera.hapi.node.state.hints.HintsScheme;
@@ -11,9 +12,11 @@
1112
import com.hedera.node.app.hints.HintsLibrary;
1213
import com.hedera.node.config.data.TssConfig;
1314
import com.hedera.pbj.runtime.io.buffer.Bytes;
15+
import com.swirlds.config.api.Configuration;
1416
import java.time.Duration;
1517
import java.util.List;
1618
import java.util.Map;
19+
import java.util.function.Supplier;
1720
import org.junit.jupiter.api.BeforeEach;
1821
import org.junit.jupiter.api.Test;
1922
import org.junit.jupiter.api.extension.ExtendWith;
@@ -43,18 +46,22 @@ class HintsContextTest {
4346
@Mock
4447
private Bytes signature;
4548

46-
private HintsContext subject;
49+
@Mock
50+
private Supplier<Configuration> configProvider;
4751

4852
@Mock
49-
private TssConfig strictHalfConfig;
53+
private Configuration configuration;
54+
55+
private HintsContext subject;
5056

5157
@BeforeEach
5258
void setUp() {
53-
strictHalfConfig = defaultConfig(2, true);
54-
subject = new HintsContext(library, strictHalfConfig);
59+
lenient().when(configProvider.get()).thenReturn(configuration);
60+
lenient().when(configuration.getConfigData(TssConfig.class)).thenReturn(defaultConfig(2));
61+
subject = new HintsContext(library, configProvider);
5562
}
5663

57-
private static TssConfig defaultConfig(final int divisor, final boolean strict) {
64+
private static TssConfig defaultConfig(final int divisor) {
5865
return new TssConfig(
5966
Duration.ofSeconds(60),
6067
Duration.ofSeconds(300),
@@ -67,8 +74,7 @@ private static TssConfig defaultConfig(final int divisor, final boolean strict)
6774
false,
6875
false,
6976
false,
70-
divisor,
71-
strict);
77+
divisor);
7278
}
7379

7480
@Test
@@ -113,33 +119,7 @@ void incorporatingValidWorksAsExpected() {
113119
}
114120

115121
@Test
116-
void greaterOrEqualComparisonAllowsExactThreshold() {
117-
final var equalWeightA = new NodePartyId(11L, 1, 5L);
118-
final var equalWeightB = new NodePartyId(12L, 2, 5L);
119-
final var equalConstruction = HintsConstruction.newBuilder()
120-
.constructionId(2L)
121-
.hintsScheme(new HintsScheme(PREPROCESSED_KEYS, List.of(equalWeightA, equalWeightB)))
122-
.build();
123-
124-
final Map<Integer, Bytes> expectedSignatures = Map.of(equalWeightA.partyId(), signature);
125-
final var aggregateSignature = Bytes.wrap("AS2");
126-
given(library.aggregateSignatures(CRS, AGGREGATION_KEY, VERIFICATION_KEY, expectedSignatures))
127-
.willReturn(aggregateSignature);
128-
129-
final var geConfig = defaultConfig(2, false);
130-
final var geSubject = new HintsContext(library, geConfig);
131-
geSubject.setConstruction(equalConstruction);
132-
133-
final var signing = geSubject.newSigning(BLOCK_HASH, () -> {});
134-
final var future = signing.future();
135-
136-
signing.incorporateValid(CRS, equalWeightA.nodeId(), signature);
137-
assertTrue(future.isDone());
138-
assertEquals(aggregateSignature, future.join());
139-
}
140-
141-
@Test
142-
void strictComparisonRequiresGreaterThanThreshold() {
122+
void alwaysRequiresGreaterThanThreshold() {
143123
final var a = new NodePartyId(21L, 1, 5L);
144124
final var b = new NodePartyId(22L, 2, 5L);
145125
final var construction = HintsConstruction.newBuilder()
@@ -152,18 +132,16 @@ void strictComparisonRequiresGreaterThanThreshold() {
152132
given(library.aggregateSignatures(CRS, AGGREGATION_KEY, VERIFICATION_KEY, expectedSignatures))
153133
.willReturn(aggregateSignature);
154134

155-
final var strictConfig = defaultConfig(2, true);
156-
final var s = new HintsContext(library, strictConfig);
157-
s.setConstruction(construction);
135+
subject.setConstruction(construction);
158136

159-
final var signing = s.newSigning(BLOCK_HASH, () -> {});
137+
final var signing = subject.newSigning(BLOCK_HASH, () -> {});
160138
final var future = signing.future();
161139

162-
// Exactly half: should NOT complete when strict
140+
// Exactly half (5 out of 10 total weight): should NOT complete, need strictly > 1/2
163141
signing.incorporateValid(CRS, a.nodeId(), signature);
164142
assertFalse(future.isDone());
165143

166-
// One more: now it should complete
144+
// One more signature gives us 10 out of 10: now it should complete
167145
signing.incorporateValid(CRS, b.nodeId(), signature);
168146
assertTrue(future.isDone());
169147
assertEquals(aggregateSignature, future.join());

hedera-node/hedera-app/src/test/java/com/hedera/node/app/hints/impl/WritableHintsStoreImplTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ class WritableHintsStoreImplTest {
124124

125125
@BeforeEach
126126
void setUp() {
127+
given(appContext.configSupplier()).willReturn(() -> DEFAULT_CONFIG);
127128
state = emptyState();
128129
entityCounters = new WritableEntityIdStore(new MapWritableStates(Map.of(
129130
ENTITY_ID_STATE_ID,
@@ -472,8 +473,7 @@ private State emptyState() {
472473
library,
473474
DEFAULT_CONFIG
474475
.getConfigData(BlockStreamConfig.class)
475-
.blockPeriod(),
476-
DEFAULT_CONFIG.getConfigData(TssConfig.class)))
476+
.blockPeriod()))
477477
.forEach(servicesRegistry::register);
478478
final var migrator = new FakeServiceMigrator();
479479
final var bootstrapConfig = new BootstrapConfigProviderImpl().getConfiguration();

hedera-node/hedera-config/src/main/java/com/hedera/node/config/data/TssConfig.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,5 @@ public record TssConfig(
2727
// to give express consent for breaking the address book chain of trust
2828
@ConfigProperty(defaultValue = "false") @NetworkProperty boolean forceHandoffs,
2929
// Denominator used to compute signing threshold: totalWeight / signingThresholdDivisor
30-
@ConfigProperty(defaultValue = "2") @Min(1) @NetworkProperty int signingThresholdDivisor,
31-
// If true, require strictly greater than threshold; if false, allow greater-than-or-equal
32-
@ConfigProperty(defaultValue = "true") @NetworkProperty boolean strictSigningThreshold) {}
30+
// For block hash signing, this must always be 2 to ensure > 1/2 consensus
31+
@ConfigProperty(defaultValue = "2") @Min(1) @NetworkProperty int signingThresholdDivisor) {}

hedera-node/test-clients/src/main/java/com/hedera/services/bdd/junit/hedera/embedded/fakes/FakeHintsService.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,7 @@ public FakeHintsService(@NonNull final AppContext appContext, @NonNull final Con
3333
pendingHintsSubmissions::offer,
3434
appContext,
3535
new HintsLibraryImpl(),
36-
bootstrapConfig.getConfigData(BlockStreamConfig.class).blockPeriod(),
37-
bootstrapConfig.getConfigData(TssConfig.class));
36+
bootstrapConfig.getConfigData(BlockStreamConfig.class).blockPeriod());
3837
}
3938

4039
@Override

0 commit comments

Comments
 (0)