Skip to content

Commit

Permalink
Updated BlockOperationSelectorFactory to include execution requests p…
Browse files Browse the repository at this point in the history
…ost-Electra (#8717)
  • Loading branch information
lucassaldanha authored Oct 14, 2024
1 parent b35d70a commit dfd7f9d
Show file tree
Hide file tree
Showing 4 changed files with 167 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadContext;
import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadHeader;
import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadResult;
import tech.pegasys.teku.spec.datastructures.execution.versions.electra.ExecutionRequestsBuilderElectra;
import tech.pegasys.teku.spec.datastructures.execution.versions.electra.ExecutionRequests;
import tech.pegasys.teku.spec.datastructures.operations.Attestation;
import tech.pegasys.teku.spec.datastructures.operations.AttesterSlashing;
import tech.pegasys.teku.spec.datastructures.operations.ProposerSlashing;
Expand All @@ -64,7 +64,6 @@
import tech.pegasys.teku.spec.schemas.SchemaDefinitions;
import tech.pegasys.teku.spec.schemas.SchemaDefinitionsBellatrix;
import tech.pegasys.teku.spec.schemas.SchemaDefinitionsDeneb;
import tech.pegasys.teku.spec.schemas.SchemaDefinitionsElectra;
import tech.pegasys.teku.statetransition.OperationPool;
import tech.pegasys.teku.statetransition.attestation.AggregatingAttestationPool;
import tech.pegasys.teku.statetransition.attestation.AttestationForkChecker;
Expand Down Expand Up @@ -240,19 +239,11 @@ private SafeFuture<Void> setExecutionData(
requestedBuilderBoostFactor,
blockProductionPerformance);

// TODO Update as part of Electra Engine API updates
// (https://github.com/Consensys/teku/issues/8620)
if (bodyBuilder.supportsExecutionRequests()) {
bodyBuilder.executionRequests(
new ExecutionRequestsBuilderElectra(
SchemaDefinitionsElectra.required(schemaDefinitions).getExecutionRequestsSchema())
.build());
}

return SafeFuture.allOf(
cacheExecutionPayloadValue(executionPayloadResult, blockSlotState),
setPayloadOrPayloadHeader(bodyBuilder, executionPayloadResult),
setKzgCommitments(bodyBuilder, schemaDefinitions, executionPayloadResult));
setKzgCommitments(bodyBuilder, schemaDefinitions, executionPayloadResult),
setExecutionRequests(bodyBuilder, executionPayloadResult));
}

private SafeFuture<Void> cacheExecutionPayloadValue(
Expand Down Expand Up @@ -350,6 +341,29 @@ private SszList<SszKZGCommitment> getBlobKzgCommitmentsFromBuilderFlow(
.orElseThrow();
}

private SafeFuture<Void> setExecutionRequests(
final BeaconBlockBodyBuilder bodyBuilder,
final ExecutionPayloadResult executionPayloadResult) {
if (!bodyBuilder.supportsExecutionRequests()) {
return SafeFuture.COMPLETE;
}

final SafeFuture<ExecutionRequests> executionRequestsFuture;
if (executionPayloadResult.isFromLocalFlow()) {
executionRequestsFuture =
executionPayloadResult
.getExecutionRequestsFromLocalFlow()
.orElseThrow()
.thenApply(Optional::orElseThrow);
} else {
// TODO Add support for builder flow in Electra
// (https://github.com/Consensys/teku/issues/8624)
executionRequestsFuture = SafeFuture.completedFuture(null);
}

return executionRequestsFuture.thenAccept(bodyBuilder::executionRequests);
}

public Consumer<SignedBeaconBlockUnblinder> createBlockUnblinderSelector(
final BlockPublishingPerformance blockPublishingPerformance) {
return bodyUnblinder -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@
import tech.pegasys.teku.validator.api.ClientGraffitiAppendFormat;

class BlockOperationSelectorFactoryTest {
private final Spec spec = TestSpecFactory.createMinimalDeneb();
private final Spec spec = TestSpecFactory.createMinimalElectra();
private final Spec specBellatrix = TestSpecFactory.createMinimalBellatrix();
private final DataStructureUtil dataStructureUtil = new DataStructureUtil(spec);

Expand Down Expand Up @@ -177,7 +177,7 @@ class BlockOperationSelectorFactoryTest {
.getDefault();

private final CapturingBeaconBlockBodyBuilder bodyBuilder =
new CapturingBeaconBlockBodyBuilder(false);
new CapturingBeaconBlockBodyBuilder(false, false);

private final GraffitiBuilder graffitiBuilder =
new GraffitiBuilder(ClientGraffitiAppendFormat.DISABLED);
Expand Down Expand Up @@ -963,6 +963,63 @@ void shouldThrowWhenExecutionPayloadContextNotProvided() {
"ExecutionPayloadContext is not provided for production of post-merge block at slot 1");
}

@Test
void shouldGetExecutionRequestsForLocallyProducedBlocks() {
final UInt64 slot = UInt64.valueOf(2);
final BeaconState blockSlotState = dataStructureUtil.randomBeaconState(slot);
final SignedVoluntaryExit voluntaryExit = dataStructureUtil.randomSignedVoluntaryExit();
final ProposerSlashing proposerSlashing = dataStructureUtil.randomProposerSlashing();
final AttesterSlashing attesterSlashing = dataStructureUtil.randomAttesterSlashing();
final SignedContributionAndProof contribution =
dataStructureUtil.randomSignedContributionAndProof(1, parentRoot);
final SignedBlsToExecutionChange blsToExecutionChange =
dataStructureUtil.randomSignedBlsToExecutionChange();
addToPool(voluntaryExitPool, voluntaryExit);
addToPool(proposerSlashingPool, proposerSlashing);
addToPool(attesterSlashingPool, attesterSlashing);
assertThat(contributionPool.addLocal(contribution)).isCompletedWithValue(ACCEPT);
addToPool(blsToExecutionChangePool, blsToExecutionChange);

final CapturingBeaconBlockBodyBuilder bodyBuilder =
new CapturingBeaconBlockBodyBuilder(true, true);

final ExecutionPayload randomExecutionPayload = dataStructureUtil.randomExecutionPayload();
final UInt256 blockExecutionValue = dataStructureUtil.randomUInt256();

final ExecutionRequests expectedExecutionRequests = dataStructureUtil.randomExecutionRequests();

prepareBlockWithBlobsAndExecutionRequestsProduction(
randomExecutionPayload,
executionPayloadContext,
blockSlotState,
dataStructureUtil.randomBlobsBundle(),
expectedExecutionRequests,
blockExecutionValue);

safeJoin(
factory
.createSelector(
parentRoot,
blockSlotState,
randaoReveal,
Optional.of(defaultGraffiti),
Optional.empty(),
BlockProductionPerformance.NOOP)
.apply(bodyBuilder));

assertThat(bodyBuilder.randaoReveal).isEqualTo(randaoReveal);
assertThat(bodyBuilder.graffiti).isEqualTo(defaultGraffiti);
assertThat(bodyBuilder.proposerSlashings).containsOnly(proposerSlashing);
assertThat(bodyBuilder.attesterSlashings).containsOnly(attesterSlashing);
assertThat(bodyBuilder.voluntaryExits).containsOnly(voluntaryExit);
assertThat(bodyBuilder.syncAggregate)
.isEqualTo(
spec.getSyncCommitteeUtilRequired(slot)
.createSyncAggregate(List.of(contribution.getMessage().getContribution())));
assertThat(bodyBuilder.blsToExecutionChanges).containsOnly(blsToExecutionChange);
assertThat(bodyBuilder.executionRequests).isEqualTo(expectedExecutionRequests);
}

private void prepareBlockProductionWithPayload(
final ExecutionPayload executionPayload,
final ExecutionPayloadContext executionPayloadContext,
Expand Down Expand Up @@ -1044,7 +1101,36 @@ private void prepareBlockAndBlobsProduction(
executionPayloadContext,
SafeFuture.completedFuture(
new GetPayloadResponse(
executionPayload, executionPayloadValue, blobsBundle, false))));
executionPayload,
executionPayloadValue,
blobsBundle,
false,
dataStructureUtil.randomExecutionRequests()))));
}

private void prepareBlockWithBlobsAndExecutionRequestsProduction(
final ExecutionPayload executionPayload,
final ExecutionPayloadContext executionPayloadContext,
final BeaconState blockSlotState,
final BlobsBundle blobsBundle,
final ExecutionRequests executionRequests,
final UInt256 executionPayloadValue) {
when(executionLayer.initiateBlockProduction(
executionPayloadContext,
blockSlotState,
false,
Optional.empty(),
BlockProductionPerformance.NOOP))
.thenReturn(
ExecutionPayloadResult.createForLocalFlow(
executionPayloadContext,
SafeFuture.completedFuture(
new GetPayloadResponse(
executionPayload,
executionPayloadValue,
blobsBundle,
false,
executionRequests))));
}

private void prepareBlindedBlockAndBlobsProduction(
Expand Down Expand Up @@ -1154,6 +1240,7 @@ private void prepareCachedFallbackData(
private static class CapturingBeaconBlockBodyBuilder implements BeaconBlockBodyBuilder {

private final boolean supportsKzgCommitments;
private final boolean supportExecutionRequests;

protected BLSSignature randaoReveal;
protected Bytes32 graffiti;
Expand All @@ -1165,14 +1252,17 @@ private static class CapturingBeaconBlockBodyBuilder implements BeaconBlockBodyB
protected ExecutionPayload executionPayload;
protected ExecutionPayloadHeader executionPayloadHeader;
protected SszList<SszKZGCommitment> blobKzgCommitments;

// TODO Update as part of Electra Engine API updates
// (https://github.com/Consensys/teku/issues/8620)
@SuppressWarnings("unused")
protected ExecutionRequests executionRequests;

public CapturingBeaconBlockBodyBuilder(final boolean supportsKzgCommitments) {
this.supportsKzgCommitments = supportsKzgCommitments;
this.supportExecutionRequests = false;
}

public CapturingBeaconBlockBodyBuilder(
final boolean supportsKzgCommitments, final boolean supportExecutionRequests) {
this.supportsKzgCommitments = supportsKzgCommitments;
this.supportExecutionRequests = supportExecutionRequests;
}

@Override
Expand Down Expand Up @@ -1275,6 +1365,11 @@ public Boolean supportsKzgCommitments() {
return supportsKzgCommitments;
}

@Override
public boolean supportsExecutionRequests() {
return supportExecutionRequests;
}

@Override
public BeaconBlockBodyBuilder blobKzgCommitments(
final SszList<SszKZGCommitment> blobKzgCommitments) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import org.apache.tuweni.units.bigints.UInt256;
import tech.pegasys.teku.infrastructure.async.SafeFuture;
import tech.pegasys.teku.spec.datastructures.builder.BuilderBid;
import tech.pegasys.teku.spec.datastructures.execution.versions.electra.ExecutionRequests;

/**
* In non-blinded flow, {@link #getPayloadResponseFuture} will be present.
Expand Down Expand Up @@ -73,6 +74,12 @@ public Optional<SafeFuture<BuilderBidOrFallbackData>> getBuilderBidOrFallbackDat
return builderBidOrFallbackDataFuture;
}

public Optional<SafeFuture<Optional<ExecutionRequests>>> getExecutionRequestsFromLocalFlow() {
return getPayloadResponseFuture.map(
getPayloadResponse ->
getPayloadResponse.thenApply(GetPayloadResponse::getExecutionRequests));
}

/**
* @return the value from the local payload, the builder bid or the local fallback payload
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,15 +65,20 @@
import tech.pegasys.teku.spec.datastructures.execution.GetPayloadResponse;
import tech.pegasys.teku.spec.datastructures.execution.NewPayloadRequest;
import tech.pegasys.teku.spec.datastructures.execution.PowBlock;
import tech.pegasys.teku.spec.datastructures.execution.versions.electra.ExecutionRequests;
import tech.pegasys.teku.spec.datastructures.execution.versions.electra.ExecutionRequestsBuilderElectra;
import tech.pegasys.teku.spec.datastructures.execution.versions.electra.ExecutionRequestsSchema;
import tech.pegasys.teku.spec.datastructures.state.beaconstate.BeaconState;
import tech.pegasys.teku.spec.datastructures.type.SszKZGCommitment;
import tech.pegasys.teku.spec.datastructures.util.BlobsUtil;
import tech.pegasys.teku.spec.logic.versions.deneb.types.VersionedHash;
import tech.pegasys.teku.spec.schemas.SchemaDefinitions;
import tech.pegasys.teku.spec.schemas.SchemaDefinitionsBellatrix;
import tech.pegasys.teku.spec.schemas.SchemaDefinitionsDeneb;
import tech.pegasys.teku.spec.schemas.SchemaDefinitionsElectra;

public class ExecutionLayerChannelStub implements ExecutionLayerChannel {

private static final Logger LOG = LogManager.getLogger();
private static final ClientVersion STUB_CLIENT_VERSION =
new ClientVersion("SB", ExecutionLayerChannel.STUB_ENDPOINT_PREFIX, "0.0.0", Bytes4.ZERO);
Expand Down Expand Up @@ -303,20 +308,43 @@ public SafeFuture<GetPayloadResponse> engineGetPayload(
state.getSlot(),
executionPayload.getBlockHash());

final Optional<ExecutionRequests> maybeExecutionRequests = getExecutionRequests(slot);

final GetPayloadResponse getPayloadResponse =
headAndAttrs
.currentBlobsBundle
.map(
blobsBundle -> {
LOG.info("getPayload: blobsBundle: {}", blobsBundle.toBriefString());
return new GetPayloadResponse(
executionPayload, UInt256.valueOf(424242424242424242L), blobsBundle, false);
if (maybeExecutionRequests.isPresent()) {
return new GetPayloadResponse(
executionPayload,
UInt256.valueOf(424242424242424242L),
blobsBundle,
false,
maybeExecutionRequests.get());
} else {
return new GetPayloadResponse(
executionPayload, UInt256.valueOf(424242424242424242L), blobsBundle, false);
}
})
.orElse(new GetPayloadResponse(executionPayload, UInt256.valueOf(434242424242424242L)));

return SafeFuture.completedFuture(getPayloadResponse);
}

private Optional<ExecutionRequests> getExecutionRequests(final UInt64 slot) {
if (spec.atSlot(slot).getMilestone().isGreaterThanOrEqualTo(SpecMilestone.ELECTRA)) {
final ExecutionRequestsSchema executionRequestsSchema =
SchemaDefinitionsElectra.required(
spec.forMilestone(SpecMilestone.ELECTRA).getSchemaDefinitions())
.getExecutionRequestsSchema();
return Optional.of(new ExecutionRequestsBuilderElectra(executionRequestsSchema).build());
} else {
return Optional.empty();
}
}

@Override
public SafeFuture<PayloadStatus> engineNewPayload(
final NewPayloadRequest newPayloadRequest, final UInt64 slot) {
Expand Down Expand Up @@ -450,7 +478,8 @@ public SafeFuture<BuilderPayloadOrFallbackData> builderGetPayload(
executionPayloadHeader
.hashTreeRoot()
.equals(lastBuilderPayloadToBeUnblinded.get().hashTreeRoot()),
"provided signed blinded block contains an execution payload header not matching the previously retrieved execution payload via getPayloadHeader");
"provided signed blinded block contains an execution payload header not matching the previously retrieved "
+ "execution payload via getPayloadHeader");

LOG.info(
"proposeBlindedBlock: slot: {} block: {} -> unblinded executionPayload blockHash: {}",
Expand Down

0 comments on commit dfd7f9d

Please sign in to comment.