Skip to content

Commit 49a6665

Browse files
authored
Fix capella signed voluntary exit was not published on Deneb (Consensys#8205)
1 parent b549a70 commit 49a6665

File tree

2 files changed

+75
-4
lines changed

2 files changed

+75
-4
lines changed

networking/eth2/src/main/java/tech/pegasys/teku/networking/eth2/gossip/forks/GossipForkManager.java

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import org.apache.logging.log4j.Logger;
3232
import tech.pegasys.teku.infrastructure.unsigned.UInt64;
3333
import tech.pegasys.teku.spec.Spec;
34+
import tech.pegasys.teku.spec.SpecMilestone;
3435
import tech.pegasys.teku.spec.datastructures.attestation.ValidatableAttestation;
3536
import tech.pegasys.teku.spec.datastructures.blobs.versions.deneb.BlobSidecar;
3637
import tech.pegasys.teku.spec.datastructures.blocks.SignedBeaconBlock;
@@ -205,11 +206,17 @@ public void publishAttesterSlashing(final AttesterSlashing message) {
205206
}
206207

207208
public void publishVoluntaryExit(final SignedVoluntaryExit message) {
209+
final SpecMilestone currentMilestone =
210+
spec.atEpoch(spec.getCurrentEpoch(recentChainData.getStore())).getMilestone();
211+
final UInt64 publishingSlot;
212+
if (currentMilestone.isGreaterThanOrEqualTo(SpecMilestone.CAPELLA)) {
213+
publishingSlot =
214+
spec.computeStartSlotAtEpoch(spec.getCurrentEpoch(recentChainData.getStore()));
215+
} else {
216+
publishingSlot = spec.computeStartSlotAtEpoch(message.getMessage().getEpoch());
217+
}
208218
publishMessage(
209-
spec.computeStartSlotAtEpoch(message.getMessage().getEpoch()),
210-
message,
211-
"voluntary exit",
212-
GossipForkSubscriptions::publishVoluntaryExit);
219+
publishingSlot, message, "voluntary exit", GossipForkSubscriptions::publishVoluntaryExit);
213220
}
214221

215222
public void publishSignedBlsToExecutionChanges(final SignedBlsToExecutionChange message) {

networking/eth2/src/test/java/tech/pegasys/teku/networking/eth2/gossip/forks/GossipForkManagerTest.java

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,14 @@
1313

1414
package tech.pegasys.teku.networking.eth2.gossip.forks;
1515

16+
import static org.assertj.core.api.Assertions.assertThat;
1617
import static org.assertj.core.api.Assertions.assertThatThrownBy;
18+
import static org.junit.jupiter.api.Assertions.assertEquals;
1719
import static org.mockito.ArgumentMatchers.any;
1820
import static org.mockito.ArgumentMatchers.anyBoolean;
1921
import static org.mockito.Mockito.mock;
2022
import static org.mockito.Mockito.never;
23+
import static org.mockito.Mockito.reset;
2124
import static org.mockito.Mockito.times;
2225
import static org.mockito.Mockito.verify;
2326
import static org.mockito.Mockito.when;
@@ -32,13 +35,17 @@
3235
import org.junit.jupiter.params.provider.MethodSource;
3336
import tech.pegasys.teku.infrastructure.unsigned.UInt64;
3437
import tech.pegasys.teku.spec.Spec;
38+
import tech.pegasys.teku.spec.SpecMilestone;
3539
import tech.pegasys.teku.spec.TestSpecFactory;
3640
import tech.pegasys.teku.spec.datastructures.attestation.ValidatableAttestation;
3741
import tech.pegasys.teku.spec.datastructures.blocks.SignedBeaconBlock;
3842
import tech.pegasys.teku.spec.datastructures.genesis.GenesisData;
43+
import tech.pegasys.teku.spec.datastructures.operations.SignedVoluntaryExit;
44+
import tech.pegasys.teku.spec.datastructures.operations.VoluntaryExit;
3945
import tech.pegasys.teku.spec.datastructures.operations.versions.altair.ValidatableSyncCommitteeMessage;
4046
import tech.pegasys.teku.spec.util.DataStructureUtil;
4147
import tech.pegasys.teku.storage.client.RecentChainData;
48+
import tech.pegasys.teku.storage.store.UpdatableStore;
4249

4350
class GossipForkManagerTest {
4451
private static final Bytes32 GENESIS_VALIDATORS_ROOT = Bytes32.fromHexString("0x12345678446687");
@@ -49,6 +56,7 @@ class GossipForkManagerTest {
4956

5057
@BeforeEach
5158
void setUp() {
59+
reset(recentChainData);
5260
when(recentChainData.getGenesisData())
5361
.thenReturn(
5462
Optional.of(new GenesisData(UInt64.valueOf(134234134L), GENESIS_VALIDATORS_ROOT)));
@@ -348,6 +356,62 @@ void shouldNotPublishSyncCommitteeMessagesToForksThatAreNotActive() {
348356
verify(secondFork, never()).publishSyncCommitteeMessage(message);
349357
}
350358

359+
@Test
360+
void shouldPublishVoluntaryExitOnCapella() {
361+
final Spec specCapella = TestSpecFactory.createMinimalCapella();
362+
final GossipForkSubscriptions capellaFork = forkAtEpoch(0);
363+
final GossipForkManager.Builder builder =
364+
GossipForkManager.builder().recentChainData(recentChainData).spec(specCapella);
365+
Stream.of(capellaFork).forEach(builder::fork);
366+
final GossipForkManager manager = builder.build();
367+
368+
final UpdatableStore store = mock(UpdatableStore.class);
369+
when(recentChainData.getStore()).thenReturn(store);
370+
when(store.getGenesisTime()).thenReturn(UInt64.ZERO);
371+
when(store.getTimeSeconds()).thenReturn(UInt64.ONE);
372+
373+
final VoluntaryExit voluntaryExit = new VoluntaryExit(UInt64.ZERO, UInt64.ONE);
374+
final SignedVoluntaryExit capellaVoluntaryExit =
375+
new SignedVoluntaryExit(voluntaryExit, dataStructureUtil.randomSignature());
376+
377+
manager.configureGossipForEpoch(UInt64.ZERO);
378+
379+
manager.publishVoluntaryExit(capellaVoluntaryExit);
380+
verify(capellaFork).publishVoluntaryExit(capellaVoluntaryExit);
381+
}
382+
383+
@Test
384+
void shouldPublishCapellaVoluntaryExitAfterCapella() {
385+
final Spec specDeneb = TestSpecFactory.createMinimalWithDenebForkEpoch(UInt64.ONE);
386+
final GossipForkSubscriptions capellaFork = forkAtEpoch(0);
387+
final GossipForkSubscriptions denebFork = forkAtEpoch(1);
388+
final GossipForkManager.Builder builder =
389+
GossipForkManager.builder().recentChainData(recentChainData).spec(specDeneb);
390+
Stream.of(capellaFork, denebFork).forEach(builder::fork);
391+
final GossipForkManager manager = builder.build();
392+
393+
final UpdatableStore store = mock(UpdatableStore.class);
394+
when(recentChainData.getStore()).thenReturn(store);
395+
when(store.getGenesisTime()).thenReturn(UInt64.ZERO);
396+
when(store.getTimeSeconds()).thenReturn(UInt64.valueOf(9000));
397+
assertThat(specDeneb.getCurrentEpoch(store)).isGreaterThanOrEqualTo(UInt64.valueOf(3));
398+
399+
final VoluntaryExit voluntaryExit = new VoluntaryExit(UInt64.ZERO, UInt64.ONE);
400+
final SignedVoluntaryExit capellaVoluntaryExit =
401+
new SignedVoluntaryExit(voluntaryExit, dataStructureUtil.randomSignature());
402+
assertEquals(
403+
SpecMilestone.CAPELLA,
404+
specDeneb.atEpoch(capellaVoluntaryExit.getMessage().getEpoch()).getMilestone());
405+
406+
// Deneb
407+
// Previous subscriptions are stopped in 2 epochs after fork transition
408+
manager.configureGossipForEpoch(UInt64.valueOf(3));
409+
410+
manager.publishVoluntaryExit(capellaVoluntaryExit);
411+
verify(capellaFork, never()).publishVoluntaryExit(capellaVoluntaryExit);
412+
verify(denebFork).publishVoluntaryExit(capellaVoluntaryExit);
413+
}
414+
351415
@ParameterizedTest
352416
@MethodSource("subnetSubscriptionTypes")
353417
void shouldSubscribeToAttestationSubnetsPriorToStarting(final SubscriptionType subscriptionType) {

0 commit comments

Comments
 (0)