Skip to content

Commit

Permalink
Ability to add deposit receipts in the stub (#8139)
Browse files Browse the repository at this point in the history
  • Loading branch information
StefanBratanov authored Mar 25, 2024
1 parent 15f5a84 commit 508459f
Show file tree
Hide file tree
Showing 7 changed files with 114 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ public ExecutionPayloadResult initiateBlockProduction(
if (!isBlind) {
final SafeFuture<GetPayloadResponse> getPayloadResponseFuture =
executionLayerChannel
.engineGetPayload(context, blockSlotState.getSlot())
.engineGetPayload(context, blockSlotState)
.thenPeek(__ -> blockProductionPerformance.engineGetPayload());
final SafeFuture<ExecutionPayload> executionPayloadFuture =
getPayloadResponseFuture.thenApply(GetPayloadResponse::getExecutionPayload);
Expand Down Expand Up @@ -111,7 +111,7 @@ public ExecutionPayloadResult initiateBlockAndBlobsProduction(
if (!isBlind) {
final SafeFuture<GetPayloadResponse> getPayloadResponseFuture =
executionLayerChannel
.engineGetPayload(context, blockSlotState.getSlot())
.engineGetPayload(context, blockSlotState)
.thenPeek(__ -> blockProductionPerformance.engineGetPayload());
final SafeFuture<ExecutionPayload> executionPayloadFuture =
getPayloadResponseFuture.thenApply(GetPayloadResponse::getExecutionPayload);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -195,8 +195,8 @@ public SafeFuture<ForkChoiceUpdatedResult> engineForkChoiceUpdated(

@Override
public SafeFuture<GetPayloadResponse> engineGetPayload(
final ExecutionPayloadContext executionPayloadContext, final UInt64 slot) {
return engineGetPayload(executionPayloadContext, slot, false)
final ExecutionPayloadContext executionPayloadContext, final BeaconState state) {
return engineGetPayload(executionPayloadContext, state.getSlot(), false)
.thenPeek(__ -> recordExecutionPayloadFallbackSource(Source.LOCAL_EL, FallbackReason.NONE));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@ public class ExecutionLayerManagerStub extends ExecutionLayerChannelStub
private final BuilderCircuitBreaker builderCircuitBreaker;

public ExecutionLayerManagerStub(
Spec spec,
TimeProvider timeProvider,
boolean enableTransitionEmulation,
final Spec spec,
final TimeProvider timeProvider,
final boolean enableTransitionEmulation,
final Optional<Bytes32> terminalBlockHashInTTDMode,
final BuilderCircuitBreaker builderCircuitBreaker) {
super(spec, timeProvider, enableTransitionEmulation, terminalBlockHashInTTDMode);
Expand All @@ -58,7 +58,7 @@ public SafeFuture<HeaderWithFallbackData> builderGetHeader(
final SafeFuture<UInt256> payloadValueResult,
final Optional<UInt64> requestedBuilderBoostFactor,
final BlockProductionPerformance blockProductionPerformance) {
boolean builderCircuitBreakerEngaged = builderCircuitBreaker.isEngaged(state);
final boolean builderCircuitBreakerEngaged = builderCircuitBreaker.isEngaged(state);
LOG.info("Builder Circuit Breaker isEngaged: " + builderCircuitBreakerEngaged);

return super.builderGetHeader(
Expand All @@ -70,9 +70,7 @@ public SafeFuture<HeaderWithFallbackData> builderGetHeader(
.thenCompose(
headerWithFallbackData -> {
if (builderCircuitBreakerEngaged) {
return engineGetPayload(
executionPayloadContext,
executionPayloadContext.getPayloadBuildingAttributes().getProposalSlot())
return engineGetPayload(executionPayloadContext, state)
.thenApply(
payload ->
HeaderWithFallbackData.create(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,11 +166,12 @@ public void engineGetPayload_shouldReturnGetPayloadResponseViaEngine() {
final ExecutionPayloadContext executionPayloadContext =
dataStructureUtil.randomPayloadExecutionContext(false, true);
final UInt64 slot = executionPayloadContext.getForkChoiceState().getHeadBlockSlot();
final BeaconState state = dataStructureUtil.randomBeaconState(slot);

final GetPayloadResponse getPayloadResponse =
prepareEngineGetPayloadResponse(executionPayloadContext, localExecutionPayloadValue, slot);

assertThat(executionLayerManager.engineGetPayload(executionPayloadContext, slot))
assertThat(executionLayerManager.engineGetPayload(executionPayloadContext, state))
.isCompletedWithValue(getPayloadResponse);

// we expect no calls to builder
Expand All @@ -187,11 +188,12 @@ public void engineGetPayloadV2_shouldReturnPayloadViaEngine() {
dataStructureUtil.randomPayloadExecutionContext(false, true);
executionLayerManager = createExecutionLayerChannelImpl(false, false);
final UInt64 slot = executionPayloadContext.getForkChoiceState().getHeadBlockSlot();
final BeaconState state = dataStructureUtil.randomBeaconState(slot);

final GetPayloadResponse getPayloadResponse =
prepareEngineGetPayloadResponse(executionPayloadContext, localExecutionPayloadValue, slot);

assertThat(executionLayerManager.engineGetPayload(executionPayloadContext, slot))
assertThat(executionLayerManager.engineGetPayload(executionPayloadContext, state))
.isCompletedWithValue(getPayloadResponse);

// we expect no calls to builder
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/*
* Copyright Consensys Software Inc., 2024
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/

package tech.pegasys.teku.spec.datastructures.util;

import java.security.SecureRandom;
import java.util.List;
import java.util.stream.IntStream;
import org.apache.tuweni.bytes.Bytes32;
import tech.pegasys.teku.bls.BLS;
import tech.pegasys.teku.bls.BLSKeyPair;
import tech.pegasys.teku.bls.BLSPublicKey;
import tech.pegasys.teku.bls.BLSSignature;
import tech.pegasys.teku.infrastructure.unsigned.UInt64;
import tech.pegasys.teku.spec.Spec;
import tech.pegasys.teku.spec.constants.Domain;
import tech.pegasys.teku.spec.datastructures.execution.versions.electra.DepositReceipt;
import tech.pegasys.teku.spec.datastructures.operations.DepositMessage;
import tech.pegasys.teku.spec.datastructures.state.beaconstate.BeaconState;
import tech.pegasys.teku.spec.logic.common.helpers.MiscHelpers;
import tech.pegasys.teku.spec.schemas.SchemaDefinitionsElectra;

public class DepositReceiptsUtil {

private static final int MAX_NUMBER_OF_DEPOSITS_PER_BLOCK = 3;

private final Spec spec;

@SuppressWarnings("DoNotCreateSecureRandomDirectly")
private final SecureRandom random = new SecureRandom();

public DepositReceiptsUtil(final Spec spec) {
this.spec = spec;
}

public List<DepositReceipt> generateDepositReceipts(final BeaconState state) {
final UInt64 nextDepositReceiptIndex = UInt64.valueOf(state.getValidators().size());
return IntStream.range(0, getNumberOfDepositReceiptsToGenerate())
.mapToObj(i -> createDepositReceipt(state.getSlot(), nextDepositReceiptIndex.plus(i)))
.toList();
}

private int getNumberOfDepositReceiptsToGenerate() {
return random.nextInt(MAX_NUMBER_OF_DEPOSITS_PER_BLOCK + 1);
}

private DepositReceipt createDepositReceipt(final UInt64 slot, final UInt64 index) {
final BLSKeyPair validatorKeyPair = BLSKeyPair.random(random);
final BLSPublicKey publicKey = validatorKeyPair.getPublicKey();
final UInt64 depositAmount = UInt64.THIRTY_TWO_ETH;
final DepositMessage depositMessage =
new DepositMessage(publicKey, Bytes32.ZERO, depositAmount);
final MiscHelpers miscHelpers = spec.atSlot(slot).miscHelpers();
final Bytes32 depositDomain = miscHelpers.computeDomain(Domain.DEPOSIT);
final BLSSignature signature =
BLS.sign(
validatorKeyPair.getSecretKey(),
miscHelpers.computeSigningRoot(depositMessage, depositDomain));
return SchemaDefinitionsElectra.required(spec.atSlot(slot).getSchemaDefinitions())
.getDepositReceiptSchema()
.create(publicKey, Bytes32.ZERO, depositAmount, signature, index);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public SafeFuture<ForkChoiceUpdatedResult> engineForkChoiceUpdated(

@Override
public SafeFuture<GetPayloadResponse> engineGetPayload(
final ExecutionPayloadContext executionPayloadContext, final UInt64 slot) {
final ExecutionPayloadContext executionPayloadContext, final BeaconState state) {
return SafeFuture.completedFuture(null);
}

Expand Down Expand Up @@ -123,7 +123,7 @@ SafeFuture<ForkChoiceUpdatedResult> engineForkChoiceUpdated(
* BeaconState, boolean, Optional, BlockProductionPerformance)} instead
*/
SafeFuture<GetPayloadResponse> engineGetPayload(
ExecutionPayloadContext executionPayloadContext, UInt64 slot);
ExecutionPayloadContext executionPayloadContext, BeaconState state);

// builder namespace
SafeFuture<Void> builderRegisterValidators(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,11 @@
import tech.pegasys.teku.spec.datastructures.execution.HeaderWithFallbackData;
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.DepositReceipt;
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.datastructures.util.DepositReceiptsUtil;
import tech.pegasys.teku.spec.schemas.SchemaDefinitions;
import tech.pegasys.teku.spec.schemas.SchemaDefinitionsBellatrix;
import tech.pegasys.teku.spec.schemas.SchemaDefinitionsDeneb;
Expand All @@ -73,6 +75,8 @@ public class ExecutionLayerChannelStub implements ExecutionLayerChannel {
private static final ClientVersion STUB_CLIENT_VERSION =
new ClientVersion("SB", ExecutionLayerChannel.STUB_ENDPOINT_PREFIX, "0.0.0", Bytes4.ZERO);

private static final boolean GENERATE_DEPOSIT_RECEIPTS = false;

private final TimeProvider timeProvider;
private final Map<Bytes32, PowBlock> knownBlocks = new ConcurrentHashMap<>();
private final Map<Bytes32, PayloadStatus> knownPosBlocks = new ConcurrentHashMap<>();
Expand All @@ -81,6 +85,7 @@ public class ExecutionLayerChannelStub implements ExecutionLayerChannel {
private final Set<Bytes32> requestedPowBlocks = new HashSet<>();
private final Spec spec;
private final BlobsUtil blobsUtil;
private final DepositReceiptsUtil depositReceiptsUtil;
private final Random random = new Random();

private PayloadStatus payloadStatus = PayloadStatus.VALID;
Expand Down Expand Up @@ -122,6 +127,7 @@ public ExecutionLayerChannelStub(
kzg = KZG.NOOP;
}
this.blobsUtil = new BlobsUtil(spec, kzg);
this.depositReceiptsUtil = new DepositReceiptsUtil(spec);
}

public ExecutionLayerChannelStub(
Expand Down Expand Up @@ -222,14 +228,15 @@ public SafeFuture<ForkChoiceUpdatedResult> engineForkChoiceUpdated(

@Override
public SafeFuture<GetPayloadResponse> engineGetPayload(
final ExecutionPayloadContext executionPayloadContext, final UInt64 slot) {
final ExecutionPayloadContext executionPayloadContext, final BeaconState state) {
if (!bellatrixActivationDetected) {
LOG.info(
"getPayload received before terminalBlock has been sent. Assuming transition already happened");

// do the activation check to be able to respond to terminal block verification
checkBellatrixActivation();
}
final UInt64 slot = state.getSlot();

final Optional<SchemaDefinitionsBellatrix> schemaDefinitionsBellatrix =
spec.atSlot(slot).getSchemaDefinitions().toVersionBellatrix();
Expand All @@ -246,9 +253,7 @@ public SafeFuture<GetPayloadResponse> engineGetPayload(
final List<Bytes> transactions = generateTransactions(slot, headAndAttrs);

final ExecutionPayload executionPayload =
spec.atSlot(slot)
.getSchemaDefinitions()
.toVersionBellatrix()
schemaDefinitionsBellatrix
.orElseThrow()
.getExecutionPayloadSchema()
.createExecutionPayload(
Expand All @@ -271,7 +276,7 @@ public SafeFuture<GetPayloadResponse> engineGetPayload(
.withdrawals(() -> payloadAttributes.getWithdrawals().orElse(List.of()))
.blobGasUsed(() -> UInt64.ZERO)
.excessBlobGas(() -> UInt64.ZERO)
.depositReceipts(List::of)
.depositReceipts(() -> generateDepositReceipts(state))
.exits(List::of));

// we assume all blocks are produced locally
Expand All @@ -288,7 +293,7 @@ public SafeFuture<GetPayloadResponse> engineGetPayload(
LOG.info(
"getPayload: payloadId: {} slot: {} -> executionPayload blockHash: {}",
executionPayloadContext.getPayloadId(),
slot,
state.getSlot(),
executionPayload.getBlockHash());

final GetPayloadResponse getPayloadResponse =
Expand Down Expand Up @@ -346,7 +351,7 @@ public SafeFuture<HeaderWithFallbackData> builderGetHeader(

final SchemaDefinitions schemaDefinitions = spec.atSlot(slot).getSchemaDefinitions();

return engineGetPayload(executionPayloadContext, slot)
return engineGetPayload(executionPayloadContext, state)
.thenPeek(__ -> blockProductionPerformance.engineGetPayload())
.thenApply(
getPayloadResponse -> {
Expand Down Expand Up @@ -554,4 +559,18 @@ private Bytes generateBlobsAndTransaction(

return blobsUtil.generateRawBlobTransactionFromKzgCommitments(commitments);
}

private List<DepositReceipt> generateDepositReceipts(final BeaconState state) {
return spec.atSlot(state.getSlot())
.getConfig()
.toVersionElectra()
.map(
__ -> {
if (GENERATE_DEPOSIT_RECEIPTS) {
return depositReceiptsUtil.generateDepositReceipts(state);
}
return List.<DepositReceipt>of();
})
.orElse(List.of());
}
}

0 comments on commit 508459f

Please sign in to comment.