Skip to content

Commit

Permalink
use the new target and max blob sidecars parameters
Browse files Browse the repository at this point in the history
  • Loading branch information
mehdi-aouadi committed Nov 6, 2024
1 parent d9e0d6e commit 7ca6e4c
Show file tree
Hide file tree
Showing 9 changed files with 137 additions and 46 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ void engineNewPayload_shouldCallNewPayloadV4() {
}

@Test
void engineForkChoiceUpdated_shouldCallEngineForkChoiceUpdatedV3() {
void engineForkChoiceUpdated_shouldCallEngineForkChoiceUpdatedV4() {
final ExecutionClientHandler handler = getHandler();
final ForkChoiceState forkChoiceState = dataStructureUtil.randomForkChoiceState(false);
final ForkChoiceStateV1 forkChoiceStateV1 =
Expand All @@ -142,7 +142,7 @@ void engineForkChoiceUpdated_shouldCallEngineForkChoiceUpdatedV3() {
Optional.empty(),
Optional.of(List.of()),
dataStructureUtil.randomBytes32(),
spec.getMaxBlobsPerBlock().map(max -> UInt64.valueOf(max / 2)),
spec.getTargetBlobsPerBlock(dataStructureUtil.randomSlot()).map(UInt64::valueOf),
spec.getMaxBlobsPerBlock().map(UInt64::valueOf));
final Optional<PayloadAttributesV4> payloadAttributes =
PayloadAttributesV4.fromInternalPayloadBuildingAttributesV4(Optional.of(attributes));
Expand Down
14 changes: 8 additions & 6 deletions ethereum/spec/src/main/java/tech/pegasys/teku/spec/Spec.java
Original file line number Diff line number Diff line change
Expand Up @@ -950,11 +950,17 @@ public boolean isAvailabilityOfBlobSidecarsRequiredAtEpoch(
}

public Optional<Integer> getMaxBlobsPerBlock() {
return getSpecConfigDeneb().map(SpecConfigDeneb::getMaxBlobsPerBlock);
final SpecMilestone highestSupportedMilestone =
getForkSchedule().getHighestSupportedMilestone();
return forMilestone(highestSupportedMilestone).miscHelpers().getMaxBlobsPerBlock();
}

public Optional<Integer> getMaxBlobsPerBlock(final UInt64 slot) {
return getSpecConfigDeneb(slot).map(SpecConfigDeneb::getMaxBlobsPerBlock);
return atSlot(slot).miscHelpers().getMaxBlobsPerBlock();
}

public Optional<Integer> getTargetBlobsPerBlock(final UInt64 slot) {
return atSlot(slot).miscHelpers().getTargetBlobsPerBlock();
}

public UInt64 computeSubnetForBlobSidecar(final BlobSidecar blobSidecar) {
Expand Down Expand Up @@ -983,10 +989,6 @@ private Optional<SpecConfigDeneb> getSpecConfigDeneb() {
.flatMap(SpecConfig::toVersionDeneb);
}

private Optional<SpecConfigDeneb> getSpecConfigDeneb(final UInt64 slot) {
return atSlot(slot).getConfig().toVersionDeneb();
}

// Private helpers
private SpecVersion atState(final BeaconState state) {
return atSlot(state.getSlot());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -392,8 +392,12 @@ public int getMaxRequestBlobSidecars() {
throw new UnsupportedOperationException("No Blob Sidecars before Deneb");
}

public int getMaxBlobsPerBlock() {
throw new UnsupportedOperationException("No Blob Sidecars before Deneb");
public Optional<Integer> getMaxBlobsPerBlock() {
return Optional.empty();
}

public Optional<Integer> getTargetBlobsPerBlock() {
return Optional.empty();
}

public Optional<Integer> getBlobSidecarSubnetCount() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -217,8 +217,8 @@ public int getMaxRequestBlobSidecars() {
}

@Override
public int getMaxBlobsPerBlock() {
return SpecConfigDeneb.required(specConfig).getMaxBlobsPerBlock();
public Optional<Integer> getMaxBlobsPerBlock() {
return Optional.of(SpecConfigDeneb.required(specConfig).getMaxBlobsPerBlock());
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,12 @@ public int getMaxRequestBlobSidecars() {
}

@Override
public int getMaxBlobsPerBlock() {
return SpecConfigElectra.required(specConfig).getMaxBlobsPerBlockElectra();
public Optional<Integer> getMaxBlobsPerBlock() {
return Optional.of(SpecConfigElectra.required(specConfig).getMaxBlobsPerBlockElectra());
}

public Optional<Integer> getTargetBlobsPerBlock() {
return Optional.of(SpecConfigElectra.required(specConfig).getTargetBlobsPerBlockElectra());
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -195,11 +195,10 @@ public SafeFuture<Optional<PayloadBuildingAttributes>> calculatePayloadBuildingA
final ForkChoiceState forkChoiceState = forkChoiceUpdateData.getForkChoiceState();
final Bytes32 currentHeadBlockRoot = forkChoiceState.getHeadBlockRoot();
return getStateInEpoch(epoch)
.thenApplyAsync(
.thenApply(
maybeState ->
calculatePayloadBuildingAttributes(
currentHeadBlockRoot, blockSlot, epoch, maybeState, mandatory),
eventThread);
currentHeadBlockRoot, blockSlot, epoch, maybeState, mandatory));
}

/**
Expand Down Expand Up @@ -237,7 +236,10 @@ private Optional<PayloadBuildingAttributes> calculatePayloadBuildingAttributes(
.map(RegisteredValidatorInfo::getSignedValidatorRegistration);

final Eth1Address feeRecipient = getFeeRecipient(proposerInfo, blockSlot);
final Optional<UInt64> maxBlobsPerBlock = spec.getMaxBlobsPerBlock().map(UInt64::valueOf);
final Optional<UInt64> maxBlobsPerBlock =
spec.getMaxBlobsPerBlock(blockSlot).map(UInt64::valueOf);
final Optional<UInt64> targetBlobsPerBlock =
spec.getTargetBlobsPerBlock(blockSlot).map(UInt64::valueOf);

return Optional.of(
new PayloadBuildingAttributes(
Expand All @@ -249,7 +251,7 @@ private Optional<PayloadBuildingAttributes> calculatePayloadBuildingAttributes(
validatorRegistration,
spec.getExpectedWithdrawals(state),
currentHeadBlockRoot,
maxBlobsPerBlock.map(maxBlobs -> maxBlobs.dividedBy(2)),
targetBlobsPerBlock,
maxBlobsPerBlock));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,70 +14,147 @@
package tech.pegasys.teku.statetransition.forkchoice;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import java.util.List;
import java.util.Optional;
import java.util.concurrent.ExecutionException;
import org.apache.tuweni.bytes.Bytes32;
import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem;
import org.hyperledger.besu.plugin.services.MetricsSystem;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.TestTemplate;
import tech.pegasys.teku.ethereum.execution.types.Eth1Address;
import tech.pegasys.teku.infrastructure.async.SafeFuture;
import tech.pegasys.teku.infrastructure.async.eventthread.EventThread;
import tech.pegasys.teku.infrastructure.unsigned.UInt64;
import tech.pegasys.teku.spec.Spec;
import tech.pegasys.teku.spec.SpecMilestone;
import tech.pegasys.teku.spec.TestSpecContext;
import tech.pegasys.teku.spec.TestSpecFactory;
import tech.pegasys.teku.spec.TestSpecInvocationContextProvider;
import tech.pegasys.teku.spec.datastructures.state.beaconstate.BeaconState;
import tech.pegasys.teku.spec.datastructures.validator.BeaconPreparableProposer;
import tech.pegasys.teku.spec.executionlayer.ExecutionLayerChannel;
import tech.pegasys.teku.spec.executionlayer.ForkChoiceState;
import tech.pegasys.teku.spec.executionlayer.PayloadBuildingAttributes;
import tech.pegasys.teku.spec.util.DataStructureUtil;
import tech.pegasys.teku.storage.client.ChainHead;
import tech.pegasys.teku.storage.client.RecentChainData;

@TestSpecContext(allMilestones = true)
class ProposersDataManagerTest {

private final Spec spec = TestSpecFactory.createMinimalCapella();

private final DataStructureUtil dataStructureUtil = new DataStructureUtil(spec);

private final UInt64 currentForkEpoch = UInt64.valueOf(1);
private final RecentChainData recentChainData = mock(RecentChainData.class);

private final ExecutionLayerChannel channel = ExecutionLayerChannel.NOOP;
private final MetricsSystem metricsSystem = new NoOpMetricsSystem();
private List<BeaconPreparableProposer> proposers;

private final Eth1Address defaultAddress = dataStructureUtil.randomEth1Address();
private final ProposersDataManager manager =
new ProposersDataManager(
mock(EventThread.class),
spec,
metricsSystem,
channel,
recentChainData,
Optional.of(defaultAddress),
false);
private Spec spec;
private SpecMilestone specMilestone;
private DataStructureUtil dataStructureUtil;
private ProposersDataManager manager;
private Eth1Address defaultAddress;
private UInt64 currentForkFirstSlot;

final List<BeaconPreparableProposer> proposers =
List.of(
new BeaconPreparableProposer(UInt64.ONE, dataStructureUtil.randomEth1Address()),
new BeaconPreparableProposer(UInt64.ZERO, defaultAddress));
@BeforeEach
public void setUp(final TestSpecInvocationContextProvider.SpecContext specContext) {
specMilestone = specContext.getSpecMilestone();
spec =
switch (specContext.getSpecMilestone()) {
case PHASE0 -> TestSpecFactory.createMinimalPhase0();
case ALTAIR -> TestSpecFactory.createMinimalWithAltairForkEpoch(currentForkEpoch);
case BELLATRIX -> TestSpecFactory.createMinimalWithBellatrixForkEpoch(currentForkEpoch);
case CAPELLA -> TestSpecFactory.createMinimalWithCapellaForkEpoch(currentForkEpoch);
case DENEB -> TestSpecFactory.createMinimalWithDenebForkEpoch(currentForkEpoch);
case ELECTRA -> TestSpecFactory.createMinimalWithElectraForkEpoch(currentForkEpoch);
};
currentForkFirstSlot = spec.computeStartSlotAtEpoch(currentForkEpoch);
dataStructureUtil = specContext.getDataStructureUtil();
defaultAddress = dataStructureUtil.randomEth1Address();
manager =
new ProposersDataManager(
mock(EventThread.class),
spec,
metricsSystem,
channel,
recentChainData,
Optional.of(defaultAddress),
false);
proposers =
List.of(
new BeaconPreparableProposer(UInt64.ONE, dataStructureUtil.randomEth1Address()),
new BeaconPreparableProposer(UInt64.ZERO, defaultAddress));
}

@Test
@TestTemplate
void validatorIsConnected_notFound_withEmptyPreparedList() {
assertThat(manager.validatorIsConnected(UInt64.ZERO, UInt64.ZERO)).isFalse();
}

@Test
@TestTemplate
void validatorIsConnected_found_withPreparedProposer() {
manager.updatePreparedProposers(proposers, UInt64.ONE);
assertThat(manager.validatorIsConnected(UInt64.ONE, UInt64.valueOf(1))).isTrue();
}

@Test
@TestTemplate
void validatorIsConnected_notFound_withDifferentPreparedProposer() {
manager.updatePreparedProposers(proposers, UInt64.ONE);
assertThat(manager.validatorIsConnected(UInt64.valueOf(2), UInt64.valueOf(2))).isFalse();
}

@Test
@TestTemplate
void validatorIsConnected_notFound_withExpiredPreparedProposer() {
manager.updatePreparedProposers(proposers, UInt64.ONE);
assertThat(manager.validatorIsConnected(UInt64.ONE, UInt64.valueOf(26))).isFalse();
}

@TestTemplate
void shouldSetMaxAndTargetBlobCount() throws ExecutionException, InterruptedException {
final Spec specMock = mock(Spec.class);
when(specMock.computeEpochAtSlot(any())).thenReturn(currentForkEpoch);
final UInt64 timestamp = dataStructureUtil.randomUInt64();
when(specMock.computeTimeAtSlot(any(), any())).thenReturn(timestamp);
final Bytes32 random = dataStructureUtil.randomBytes32();
when(specMock.getRandaoMix(any(), any())).thenReturn(random);
when(specMock.getMaxBlobsPerBlock(currentForkFirstSlot)).thenReturn(spec.getMaxBlobsPerBlock());
when(specMock.getTargetBlobsPerBlock(currentForkFirstSlot))
.thenReturn(spec.getTargetBlobsPerBlock(currentForkFirstSlot));
manager =
new ProposersDataManager(
mock(EventThread.class),
specMock,
metricsSystem,
channel,
recentChainData,
Optional.of(defaultAddress),
true);
final ForkChoiceUpdateData forkChoiceUpdateDataMock = mock(ForkChoiceUpdateData.class);
when(forkChoiceUpdateDataMock.hasHeadBlockHash()).thenReturn(true);
final ForkChoiceState forkChoiceStateMock = mock(ForkChoiceState.class);
when(forkChoiceStateMock.getHeadBlockRoot()).thenReturn(dataStructureUtil.randomBytes32());
when(forkChoiceUpdateDataMock.getForkChoiceState()).thenReturn(forkChoiceStateMock);
when(recentChainData.isJustifiedCheckpointFullyValidated()).thenReturn(true);
final ChainHead chainHeadMock = mock(ChainHead.class);
when(chainHeadMock.getSlot()).thenReturn(UInt64.ZERO);
when(chainHeadMock.getRoot()).thenReturn(dataStructureUtil.randomBytes32());
when(recentChainData.getChainHead()).thenReturn(Optional.of(chainHeadMock));
final BeaconState beaconStateMock = mock(BeaconState.class);
when(chainHeadMock.getState()).thenReturn(SafeFuture.completedFuture(beaconStateMock));

final SafeFuture<Optional<PayloadBuildingAttributes>> payloadBuildingAttributesFuture =
manager.calculatePayloadBuildingAttributes(
currentForkFirstSlot, true, forkChoiceUpdateDataMock, false);
final Optional<PayloadBuildingAttributes> maybePayloadBuildingAttributes =
payloadBuildingAttributesFuture.get();
assertThat(maybePayloadBuildingAttributes).isPresent();
assertThat(maybePayloadBuildingAttributes.get().getTargetBlobCount())
.isEqualTo(spec.getTargetBlobsPerBlock(currentForkFirstSlot).map(UInt64::valueOf));
assertThat(maybePayloadBuildingAttributes.get().getMaximumBlobCount())
.isEqualTo(spec.getMaxBlobsPerBlock(currentForkFirstSlot).map(UInt64::valueOf));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ public Optional<RpcException> validateRequest(
final MiscHelpers miscHelpers = spec.forMilestone(latestMilestoneRequested).miscHelpers();

final int maxRequestBlobSidecars = miscHelpers.getMaxRequestBlobSidecars();
final int maxBlobsPerBlock = miscHelpers.getMaxBlobsPerBlock();
final int maxBlobsPerBlock = miscHelpers.getMaxBlobsPerBlock().orElseThrow();

final long requestedCount = calculateRequestedCount(request, maxBlobsPerBlock);

Expand Down Expand Up @@ -126,7 +126,8 @@ public void onIncomingMessage(
final SpecMilestone latestMilestoneRequested =
spec.getForkSchedule().getSpecMilestoneAtSlot(endSlot);
final MiscHelpers miscHelpers = spec.forMilestone(latestMilestoneRequested).miscHelpers();
final long requestedCount = calculateRequestedCount(message, miscHelpers.getMaxBlobsPerBlock());
final long requestedCount =
calculateRequestedCount(message, miscHelpers.getMaxBlobsPerBlock().orElseThrow());

final Optional<RequestApproval> blobSidecarsRequestApproval =
peer.approveBlobSidecarsRequest(callback, requestedCount);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,8 @@ public void setUp(final TestSpecInvocationContextProvider.SpecContext specContex
};

dataStructureUtil = new DataStructureUtil(spec);
maxBlobsPerBlock = spec.forMilestone(specMilestone).miscHelpers().getMaxBlobsPerBlock();
maxBlobsPerBlock =
spec.forMilestone(specMilestone).miscHelpers().getMaxBlobsPerBlock().orElseThrow();
slotsPerEpoch = spec.getSlotsPerEpoch(ZERO);
startSlot = currentForkEpoch.increment().times(slotsPerEpoch);
handler = new BlobSidecarsByRangeMessageHandler(spec, metricsSystem, combinedChainDataClient);
Expand Down

0 comments on commit 7ca6e4c

Please sign in to comment.