Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updated BlockOperationSelectorFactory to include execution requests post-Electra #8717

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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