Skip to content

Commit

Permalink
Fix capella signed voluntary exit was not published on Deneb (#8205)
Browse files Browse the repository at this point in the history
  • Loading branch information
zilm13 authored Apr 15, 2024
1 parent b549a70 commit 49a6665
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import org.apache.logging.log4j.Logger;
import tech.pegasys.teku.infrastructure.unsigned.UInt64;
import tech.pegasys.teku.spec.Spec;
import tech.pegasys.teku.spec.SpecMilestone;
import tech.pegasys.teku.spec.datastructures.attestation.ValidatableAttestation;
import tech.pegasys.teku.spec.datastructures.blobs.versions.deneb.BlobSidecar;
import tech.pegasys.teku.spec.datastructures.blocks.SignedBeaconBlock;
Expand Down Expand Up @@ -205,11 +206,17 @@ public void publishAttesterSlashing(final AttesterSlashing message) {
}

public void publishVoluntaryExit(final SignedVoluntaryExit message) {
final SpecMilestone currentMilestone =
spec.atEpoch(spec.getCurrentEpoch(recentChainData.getStore())).getMilestone();
final UInt64 publishingSlot;
if (currentMilestone.isGreaterThanOrEqualTo(SpecMilestone.CAPELLA)) {
publishingSlot =
spec.computeStartSlotAtEpoch(spec.getCurrentEpoch(recentChainData.getStore()));
} else {
publishingSlot = spec.computeStartSlotAtEpoch(message.getMessage().getEpoch());
}
publishMessage(
spec.computeStartSlotAtEpoch(message.getMessage().getEpoch()),
message,
"voluntary exit",
GossipForkSubscriptions::publishVoluntaryExit);
publishingSlot, message, "voluntary exit", GossipForkSubscriptions::publishVoluntaryExit);
}

public void publishSignedBlsToExecutionChanges(final SignedBlsToExecutionChange message) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,14 @@

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

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
Expand All @@ -32,13 +35,17 @@
import org.junit.jupiter.params.provider.MethodSource;
import tech.pegasys.teku.infrastructure.unsigned.UInt64;
import tech.pegasys.teku.spec.Spec;
import tech.pegasys.teku.spec.SpecMilestone;
import tech.pegasys.teku.spec.TestSpecFactory;
import tech.pegasys.teku.spec.datastructures.attestation.ValidatableAttestation;
import tech.pegasys.teku.spec.datastructures.blocks.SignedBeaconBlock;
import tech.pegasys.teku.spec.datastructures.genesis.GenesisData;
import tech.pegasys.teku.spec.datastructures.operations.SignedVoluntaryExit;
import tech.pegasys.teku.spec.datastructures.operations.VoluntaryExit;
import tech.pegasys.teku.spec.datastructures.operations.versions.altair.ValidatableSyncCommitteeMessage;
import tech.pegasys.teku.spec.util.DataStructureUtil;
import tech.pegasys.teku.storage.client.RecentChainData;
import tech.pegasys.teku.storage.store.UpdatableStore;

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

@BeforeEach
void setUp() {
reset(recentChainData);
when(recentChainData.getGenesisData())
.thenReturn(
Optional.of(new GenesisData(UInt64.valueOf(134234134L), GENESIS_VALIDATORS_ROOT)));
Expand Down Expand Up @@ -348,6 +356,62 @@ void shouldNotPublishSyncCommitteeMessagesToForksThatAreNotActive() {
verify(secondFork, never()).publishSyncCommitteeMessage(message);
}

@Test
void shouldPublishVoluntaryExitOnCapella() {
final Spec specCapella = TestSpecFactory.createMinimalCapella();
final GossipForkSubscriptions capellaFork = forkAtEpoch(0);
final GossipForkManager.Builder builder =
GossipForkManager.builder().recentChainData(recentChainData).spec(specCapella);
Stream.of(capellaFork).forEach(builder::fork);
final GossipForkManager manager = builder.build();

final UpdatableStore store = mock(UpdatableStore.class);
when(recentChainData.getStore()).thenReturn(store);
when(store.getGenesisTime()).thenReturn(UInt64.ZERO);
when(store.getTimeSeconds()).thenReturn(UInt64.ONE);

final VoluntaryExit voluntaryExit = new VoluntaryExit(UInt64.ZERO, UInt64.ONE);
final SignedVoluntaryExit capellaVoluntaryExit =
new SignedVoluntaryExit(voluntaryExit, dataStructureUtil.randomSignature());

manager.configureGossipForEpoch(UInt64.ZERO);

manager.publishVoluntaryExit(capellaVoluntaryExit);
verify(capellaFork).publishVoluntaryExit(capellaVoluntaryExit);
}

@Test
void shouldPublishCapellaVoluntaryExitAfterCapella() {
final Spec specDeneb = TestSpecFactory.createMinimalWithDenebForkEpoch(UInt64.ONE);
final GossipForkSubscriptions capellaFork = forkAtEpoch(0);
final GossipForkSubscriptions denebFork = forkAtEpoch(1);
final GossipForkManager.Builder builder =
GossipForkManager.builder().recentChainData(recentChainData).spec(specDeneb);
Stream.of(capellaFork, denebFork).forEach(builder::fork);
final GossipForkManager manager = builder.build();

final UpdatableStore store = mock(UpdatableStore.class);
when(recentChainData.getStore()).thenReturn(store);
when(store.getGenesisTime()).thenReturn(UInt64.ZERO);
when(store.getTimeSeconds()).thenReturn(UInt64.valueOf(9000));
assertThat(specDeneb.getCurrentEpoch(store)).isGreaterThanOrEqualTo(UInt64.valueOf(3));

final VoluntaryExit voluntaryExit = new VoluntaryExit(UInt64.ZERO, UInt64.ONE);
final SignedVoluntaryExit capellaVoluntaryExit =
new SignedVoluntaryExit(voluntaryExit, dataStructureUtil.randomSignature());
assertEquals(
SpecMilestone.CAPELLA,
specDeneb.atEpoch(capellaVoluntaryExit.getMessage().getEpoch()).getMilestone());

// Deneb
// Previous subscriptions are stopped in 2 epochs after fork transition
manager.configureGossipForEpoch(UInt64.valueOf(3));

manager.publishVoluntaryExit(capellaVoluntaryExit);
verify(capellaFork, never()).publishVoluntaryExit(capellaVoluntaryExit);
verify(denebFork).publishVoluntaryExit(capellaVoluntaryExit);
}

@ParameterizedTest
@MethodSource("subnetSubscriptionTypes")
void shouldSubscribeToAttestationSubnetsPriorToStarting(final SubscriptionType subscriptionType) {
Expand Down

0 comments on commit 49a6665

Please sign in to comment.