diff --git a/beacon/validator/src/main/java/tech/pegasys/teku/validator/coordinator/ValidatorApiHandler.java b/beacon/validator/src/main/java/tech/pegasys/teku/validator/coordinator/ValidatorApiHandler.java index 47da2a51fa7..901b3835edf 100644 --- a/beacon/validator/src/main/java/tech/pegasys/teku/validator/coordinator/ValidatorApiHandler.java +++ b/beacon/validator/src/main/java/tech/pegasys/teku/validator/coordinator/ValidatorApiHandler.java @@ -69,6 +69,7 @@ import tech.pegasys.teku.networking.eth2.gossip.subnets.AttestationTopicSubscriber; import tech.pegasys.teku.networking.eth2.gossip.subnets.SyncCommitteeSubscriptionManager; import tech.pegasys.teku.spec.Spec; +import tech.pegasys.teku.spec.SpecMilestone; import tech.pegasys.teku.spec.SpecVersion; import tech.pegasys.teku.spec.datastructures.attestation.ValidatableAttestation; import tech.pegasys.teku.spec.datastructures.blocks.BeaconBlock; @@ -302,6 +303,10 @@ public SafeFuture> getPayloadAttestationDuties( if (isSyncActive()) { return NodeSyncingException.failedFuture(); } + // post ePBS + if (!spec.atEpoch(epoch).getMilestone().isGreaterThanOrEqualTo(SpecMilestone.EIP7732)) { + return SafeFuture.completedFuture(Optional.empty()); + } if (epoch.isGreaterThan( combinedChainDataClient .getCurrentEpoch() diff --git a/ethereum/dataproviders/src/main/java/tech/pegasys/teku/dataproviders/lookup/ExecutionPayloadEnvelopeProvider.java b/ethereum/dataproviders/src/main/java/tech/pegasys/teku/dataproviders/lookup/ExecutionPayloadEnvelopeProvider.java new file mode 100644 index 00000000000..9ace9414784 --- /dev/null +++ b/ethereum/dataproviders/src/main/java/tech/pegasys/teku/dataproviders/lookup/ExecutionPayloadEnvelopeProvider.java @@ -0,0 +1,39 @@ +/* + * Copyright Consensys Software Inc., 2025 + * + * 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.dataproviders.lookup; + +import java.util.Collections; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import org.apache.tuweni.bytes.Bytes32; +import tech.pegasys.teku.infrastructure.async.SafeFuture; +import tech.pegasys.teku.spec.datastructures.execution.SignedExecutionPayloadEnvelope; + +public interface ExecutionPayloadEnvelopeProvider { + + ExecutionPayloadEnvelopeProvider NOOP = + (roots) -> SafeFuture.completedFuture(Collections.emptyMap()); + + SafeFuture> getExecutionPayloadEnvelopes( + final Set blockRoots); + + default SafeFuture> getExecutionPayloadEnvelope( + final Bytes32 blockRoot) { + return getExecutionPayloadEnvelopes(Set.of(blockRoot)) + .thenApply( + executionPayloadEnvelopes -> + Optional.ofNullable(executionPayloadEnvelopes.get(blockRoot))); + } +} diff --git a/ethereum/dataproviders/src/main/java/tech/pegasys/teku/dataproviders/lookup/SingleExecutionPayloadEnvelopeProvider.java b/ethereum/dataproviders/src/main/java/tech/pegasys/teku/dataproviders/lookup/SingleExecutionPayloadEnvelopeProvider.java new file mode 100644 index 00000000000..05cce5fe0f1 --- /dev/null +++ b/ethereum/dataproviders/src/main/java/tech/pegasys/teku/dataproviders/lookup/SingleExecutionPayloadEnvelopeProvider.java @@ -0,0 +1,24 @@ +/* + * Copyright Consensys Software Inc., 2023 + * + * 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.dataproviders.lookup; + +import java.util.Optional; +import org.apache.tuweni.bytes.Bytes32; +import tech.pegasys.teku.spec.datastructures.execution.SignedExecutionPayloadEnvelope; + +public interface SingleExecutionPayloadEnvelopeProvider { + SingleExecutionPayloadEnvelopeProvider NOOP = (blockRoot) -> Optional.empty(); + + Optional getExecutionPayloadEnvelope(Bytes32 blockRoot); +} diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/forkchoice/MutableStore.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/forkchoice/MutableStore.java index 90ad4d96e3f..575053d3d2a 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/forkchoice/MutableStore.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/forkchoice/MutableStore.java @@ -23,6 +23,7 @@ import tech.pegasys.teku.spec.datastructures.blocks.SignedBlockAndState; import tech.pegasys.teku.spec.datastructures.blocks.SignedExecutionPayloadEnvelopeAndState; import tech.pegasys.teku.spec.datastructures.blocks.SlotAndBlockRoot; +import tech.pegasys.teku.spec.datastructures.execution.SignedExecutionPayloadEnvelope; import tech.pegasys.teku.spec.datastructures.state.Checkpoint; import tech.pegasys.teku.spec.datastructures.state.beaconstate.BeaconState; @@ -68,8 +69,35 @@ default void putBlockAndState( Optional.empty()); } + default void putExecutionPayloadEnvelopeAndState( + final SignedExecutionPayloadEnvelopeAndState executionPayloadEnvelopeAndState, + final List blobSidecars, + final BlockCheckpoints checkpoints) { + putExecutionPayloadEnvelopeAndState( + executionPayloadEnvelopeAndState.getExecutionPayloadEnvelope(), + executionPayloadEnvelopeAndState.getState(), + checkpoints, + Optional.of(blobSidecars), + Optional.empty()); + } + + default void putExecutionPayloadEnvelopeAndState( + final SignedExecutionPayloadEnvelopeAndState executionPayloadEnvelopeAndState, + final BlockCheckpoints checkpoints) { + putExecutionPayloadEnvelopeAndState( + executionPayloadEnvelopeAndState.getExecutionPayloadEnvelope(), + executionPayloadEnvelopeAndState.getState(), + checkpoints, + Optional.empty(), + Optional.empty()); + } + void putExecutionPayloadEnvelopeAndState( - final SignedExecutionPayloadEnvelopeAndState executionPayloadEnvelopeAndState); + SignedExecutionPayloadEnvelope executionPayloadEnvelope, + BeaconState state, + BlockCheckpoints blockCheckpoints, + Optional> blobSidecars, + Optional earliestBlobSidecarSlot); void putStateRoot(Bytes32 stateRoot, SlotAndBlockRoot slotAndBlockRoot); diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/forkchoice/ReadOnlyStore.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/forkchoice/ReadOnlyStore.java index 64c526d7b84..4fb62c8d5c5 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/forkchoice/ReadOnlyStore.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/forkchoice/ReadOnlyStore.java @@ -83,6 +83,8 @@ default UInt64 getGenesisTimeMillis() { boolean containsBlock(Bytes32 blockRoot); + boolean containsExecutionPayloadEnvelope(Bytes32 blockRoot); + /** * @return A collection of block roots ordered to guarantee that parent roots will be sorted * earlier than child roots diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/common/util/ForkChoiceUtil.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/common/util/ForkChoiceUtil.java index 70783045716..92ed165f1f8 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/common/util/ForkChoiceUtil.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/common/util/ForkChoiceUtil.java @@ -31,6 +31,7 @@ import tech.pegasys.teku.spec.datastructures.blocks.SignedBeaconBlock; import tech.pegasys.teku.spec.datastructures.blocks.blockbody.BeaconBlockBody; import tech.pegasys.teku.spec.datastructures.blocks.blockbody.versions.eip7732.BeaconBlockBodyEip7732; +import tech.pegasys.teku.spec.datastructures.execution.SignedExecutionPayloadEnvelope; import tech.pegasys.teku.spec.datastructures.execution.versions.eip7732.ExecutionPayloadHeaderEip7732; import tech.pegasys.teku.spec.datastructures.forkchoice.ChildNode; import tech.pegasys.teku.spec.datastructures.forkchoice.MutableStore; @@ -433,6 +434,40 @@ public void applyBlockToStore( signedBlock, postState, blockCheckpoints, blobSidecars, earliestBlobSidecarsSlot); } + public void applyExecutionPayloadToStore( + final MutableStore store, + final UInt64 slot, + final SignedExecutionPayloadEnvelope executionPayloadEnvelope, + final BeaconState postState, + final boolean isBlockOptimistic, + final Optional> blobSidecars, + final Optional earliestBlobSidecarsSlot) { + BlockCheckpoints blockCheckpoints = epochProcessor.calculateBlockCheckpoints(postState); + + // If executionPayloadEnvelope is from a prior epoch, pull up the post-state to next epoch to + // realize new finality + // info + if (miscHelpers + .computeEpochAtSlot(slot) + .isLessThan(miscHelpers.computeEpochAtSlot(getCurrentSlot(store)))) { + blockCheckpoints = blockCheckpoints.realizeNextEpoch(); + } + + updateCheckpoints( + store, + blockCheckpoints.getJustifiedCheckpoint(), + blockCheckpoints.getFinalizedCheckpoint(), + isBlockOptimistic); + + // Add new execution payload to store + store.putExecutionPayloadEnvelopeAndState( + executionPayloadEnvelope, + postState, + blockCheckpoints, + blobSidecars, + earliestBlobSidecarsSlot); + } + private UInt64 getFinalizedCheckpointStartSlot(final ReadOnlyStore store) { final UInt64 finalizedEpoch = store.getFinalizedCheckpoint().getEpoch(); return miscHelpers.computeStartSlotAtEpoch(finalizedEpoch); diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/common/util/ValidatorsUtil.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/common/util/ValidatorsUtil.java index 6b1fe1c59a8..be1250ce8ed 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/common/util/ValidatorsUtil.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/common/util/ValidatorsUtil.java @@ -26,6 +26,7 @@ import tech.pegasys.teku.infrastructure.crypto.Hash; import tech.pegasys.teku.infrastructure.unsigned.UInt64; import tech.pegasys.teku.spec.config.SpecConfig; +import tech.pegasys.teku.spec.config.SpecConfigEip7732; import tech.pegasys.teku.spec.constants.ValidatorConstants; import tech.pegasys.teku.spec.datastructures.state.CommitteeAssignment; import tech.pegasys.teku.spec.datastructures.state.Validator; @@ -134,14 +135,13 @@ public Int2ObjectMap getValidatorIndexToPtcAssignmentMap( final int slotsPerEpoch = specConfig.getSlotsPerEpoch(); final int committeeCountPerSlot = getPtCommitteesPerSlot(state, epoch).intValue(); - final BeaconStateAccessorsEip7732 beaconStateAccessorsEip7732 = - BeaconStateAccessorsEip7732.required(beaconStateAccessors); final UInt64 startSlot = miscHelpers.computeStartSlotAtEpoch(epoch); for (int slotOffset = 0; slotOffset < slotsPerEpoch; slotOffset++) { final UInt64 slot = startSlot.plus(slotOffset); for (int i = 0; i < committeeCountPerSlot; i++) { - final IntList committee = beaconStateAccessorsEip7732.getPtc(state, slot); + final IntList committee = + BeaconStateAccessorsEip7732.required(beaconStateAccessors).getPtc(state, slot); committee.forEach(j -> assignmentMap.put(j, slot)); } } @@ -152,7 +152,7 @@ private UInt64 getPtCommitteesPerSlot(final BeaconState state, final UInt64 epoc return MathHelpers.bitFloor( BeaconStateAccessorsEip7732.required(beaconStateAccessors) .getCommitteeCountPerSlot(state, epoch) - .min(specConfig.toVersionEip7732().orElseThrow().getPtcSize())); + .min(SpecConfigEip7732.required(specConfig).getPtcSize())); } /** diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/eip7732/SpecLogicEip7732.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/eip7732/SpecLogicEip7732.java index 608d34c5c27..5b8fad7135d 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/eip7732/SpecLogicEip7732.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/eip7732/SpecLogicEip7732.java @@ -192,7 +192,7 @@ public static SpecLogicEip7732 create( config, schemaDefinitions, beaconStateAccessors, beaconStateMutators); // Execution payload processing - // EIP7732 TODO: dirty way to leverage Electra operations + // EIP-7732 TODO: dirty way to leverage Electra operations final BlockProcessorElectra blockProcessorElectra = new BlockProcessorElectra( config, diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/block/BlockProcessorElectra.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/block/BlockProcessorElectra.java index 3b2ed876e1b..a5029b98dc1 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/block/BlockProcessorElectra.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/block/BlockProcessorElectra.java @@ -166,7 +166,8 @@ protected void processOperationsNoValidation( protected void processExecutionRequests( final MutableBeaconState state, final BeaconBlockBody body, - final Supplier validatorExitContextSupplier) { + final Supplier validatorExitContextSupplier) + throws BlockProcessingException { final ExecutionRequests executionRequests = body.getOptionalExecutionRequests() .orElseThrow(() -> new BlockProcessingException("Execution requests expected")); diff --git a/ethereum/spec/src/testFixtures/java/tech/pegasys/teku/spec/datastructures/forkchoice/TestStoreImpl.java b/ethereum/spec/src/testFixtures/java/tech/pegasys/teku/spec/datastructures/forkchoice/TestStoreImpl.java index 66c45385a7f..39511dd0883 100644 --- a/ethereum/spec/src/testFixtures/java/tech/pegasys/teku/spec/datastructures/forkchoice/TestStoreImpl.java +++ b/ethereum/spec/src/testFixtures/java/tech/pegasys/teku/spec/datastructures/forkchoice/TestStoreImpl.java @@ -30,7 +30,6 @@ import tech.pegasys.teku.spec.datastructures.blocks.BlockCheckpoints; import tech.pegasys.teku.spec.datastructures.blocks.SignedBeaconBlock; import tech.pegasys.teku.spec.datastructures.blocks.SignedBlockAndState; -import tech.pegasys.teku.spec.datastructures.blocks.SignedExecutionPayloadEnvelopeAndState; import tech.pegasys.teku.spec.datastructures.blocks.SlotAndBlockRoot; import tech.pegasys.teku.spec.datastructures.blocks.StateAndBlockSummary; import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayload; @@ -167,6 +166,12 @@ public boolean containsBlock(final Bytes32 blockRoot) { return blocks.containsKey(blockRoot); } + // EIP-7732 TODO: implement + @Override + public boolean containsExecutionPayloadEnvelope(final Bytes32 blockRoot) { + return false; + } + @Override public List getOrderedBlockRoots() { return blocks.values().stream() @@ -204,11 +209,11 @@ public SafeFuture> retrieveSignedBlock(final Bytes32 return SafeFuture.completedFuture(getBlockIfAvailable(blockRoot)); } - // EIP7732 TODO: implement + // EIP-7732 TODO: implement @Override public SafeFuture> retrieveExecutionPayloadEnvelope( final Bytes32 blockRoot) { - return null; + return SafeFuture.completedFuture(Optional.empty()); } @Override @@ -309,7 +314,11 @@ public void putBlockAndState( @Override public void putExecutionPayloadEnvelopeAndState( - final SignedExecutionPayloadEnvelopeAndState executionPayloadEnvelopeAndState) { + final SignedExecutionPayloadEnvelope executionPayloadEnvelope, + final BeaconState state, + final BlockCheckpoints blockCheckpoints, + final Optional> blobSidecars, + final Optional earliestBlobSidecarSlot) { // EIP-7732 TODO: implement } diff --git a/ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/blobs/BlockBlobSidecarsTracker.java b/ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/blobs/BlockBlobSidecarsTracker.java index 16f61e13205..2bdf4852d4d 100644 --- a/ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/blobs/BlockBlobSidecarsTracker.java +++ b/ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/blobs/BlockBlobSidecarsTracker.java @@ -120,7 +120,7 @@ public Optional getBlobSidecar(final UInt64 index) { } public Stream getMissingBlobSidecars() { - final Optional blockCommitmentsCount = getBlockKzgCommitmentsCount(); + final Optional blockCommitmentsCount = getBlobKzgCommitmentsCount(); checkState(blockCommitmentsCount.isPresent(), "Block must be known to call this method"); return UInt64.range(UInt64.ZERO, UInt64.valueOf(blockCommitmentsCount.get())) diff --git a/ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/execution/ExecutionPayloadManager.java b/ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/execution/ExecutionPayloadManager.java index 348ecf00777..0c108ace61e 100644 --- a/ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/execution/ExecutionPayloadManager.java +++ b/ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/execution/ExecutionPayloadManager.java @@ -13,21 +13,29 @@ package tech.pegasys.teku.statetransition.execution; +import java.util.Map; import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.apache.tuweni.bytes.Bytes32; import tech.pegasys.teku.infrastructure.async.SafeFuture; import tech.pegasys.teku.infrastructure.unsigned.UInt64; +import tech.pegasys.teku.spec.datastructures.blocks.SignedBeaconBlock; import tech.pegasys.teku.spec.datastructures.execution.SignedExecutionPayloadEnvelope; import tech.pegasys.teku.spec.executionlayer.ExecutionLayerChannel; +import tech.pegasys.teku.statetransition.block.ReceivedBlockEventsChannel; import tech.pegasys.teku.statetransition.forkchoice.ForkChoice; import tech.pegasys.teku.statetransition.validation.ExecutionPayloadValidator; import tech.pegasys.teku.statetransition.validation.InternalValidationResult; import tech.pegasys.teku.storage.client.RecentChainData; -public class ExecutionPayloadManager { +public class ExecutionPayloadManager implements ReceivedBlockEventsChannel { private static final Logger LOG = LogManager.getLogger(); + private final Map validatedExecutionPayloadEnvelopes = + new ConcurrentHashMap<>(); + private final ExecutionPayloadValidator executionPayloadValidator; private final ForkChoice forkChoice; private final RecentChainData recentChainData; @@ -59,6 +67,9 @@ public SafeFuture validateAndImportExecutionPayload( timestamp -> recentChainData.onExecutionPayload(signedExecutionPayloadEnvelope, timestamp), () -> LOG.error("arrivalTimestamp tracking must be enabled to support Eip7732")); + validatedExecutionPayloadEnvelopes.put( + signedExecutionPayloadEnvelope.getMessage().getBeaconBlockRoot(), + signedExecutionPayloadEnvelope); forkChoice .onExecutionPayload(signedExecutionPayloadEnvelope, executionLayerChannel) .finish(err -> LOG.error("Failed to process received execution payload.", err)); @@ -68,4 +79,17 @@ public SafeFuture validateAndImportExecutionPayload( }); return validationResult; } + + public Optional getValidatedExecutionPayloadEnvelope( + final Bytes32 blockRoot) { + return Optional.ofNullable(validatedExecutionPayloadEnvelopes.get(blockRoot)); + } + + @Override + public void onBlockValidated(final SignedBeaconBlock block) {} + + @Override + public void onBlockImported(final SignedBeaconBlock block, final boolean executionOptimistic) { + validatedExecutionPayloadEnvelopes.remove(block.getRoot()); + } } diff --git a/ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/forkchoice/ForkChoice.java b/ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/forkchoice/ForkChoice.java index b4ee6989f02..977c88d7382 100644 --- a/ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/forkchoice/ForkChoice.java +++ b/ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/forkchoice/ForkChoice.java @@ -308,14 +308,14 @@ public void applyIndexedAttestations(final List attestat .ifExceptionGetsHereRaiseABug(); } - // EIP7732 TODO: implement + // EIP-7732 TODO: implement @SuppressWarnings("unused") public SafeFuture onPayloadAttestationMessage( final PayloadAttestationMessage payloadAttestationMessage) { return SafeFuture.completedFuture(AttestationProcessingResult.SUCCESSFUL); } - // EIP7732 TODO: implement + // EIP-7732 TODO: implement @SuppressWarnings("unused") public void applyPayloadAttestationMessages( final List payloadAttestationMessages) {} @@ -544,8 +544,6 @@ private SafeFuture onBlock( }); } - // EIP7732 TODO: implement proper fork choice - @SuppressWarnings({"UnusedDeclaration", "unused"}) private SafeFuture onExecutionPayload( final BeaconState blockSlotState, final SignedBeaconBlock block, @@ -556,6 +554,9 @@ private SafeFuture onExecutionPayload( final BlobSidecarsAvailabilityChecker blobSidecarsAvailabilityChecker = blobSidecarManager.createAvailabilityChecker(block, signedEnvelope.getMessage()); + final SpecVersion specVersion = spec.atSlot(block.getSlot()); + final ForkChoiceUtil forkChoiceUtil = specVersion.getForkChoiceUtil(); + blobSidecarsAvailabilityChecker.initiateDataAvailabilityCheck(); final BeaconState postState; @@ -578,6 +579,7 @@ private SafeFuture onExecutionPayload( blockSlotState, block, postState, + forkChoiceUtil, payloadResult, blobSidecarsAndValidationResult); return null; @@ -714,15 +716,98 @@ private BlockImportResult importBlockAndState( return result; } - // EIP7732 TODO: implement proper fork choice - @SuppressWarnings("unused") private void importExecutionPayloadAndState( final SignedExecutionPayloadEnvelope executionPayloadEnvelope, final BeaconState blockSlotState, final SignedBeaconBlock block, final BeaconState postState, + final ForkChoiceUtil forkChoiceUtil, final PayloadValidationResult payloadValidationResult, - final BlobSidecarsAndValidationResult blobSidecarsAndValidationResult) {} + final BlobSidecarsAndValidationResult blobSidecarsAndValidationResult) { + final PayloadStatus payloadResult = payloadValidationResult.getStatus(); + if (payloadResult.hasInvalidStatus()) { + final BlockImportResult result = + BlockImportResult.failedStateTransition( + new IllegalStateException( + "Invalid ExecutionPayload: " + + payloadResult.getValidationError().orElse("No reason provided"))); + reportInvalidBlock(block, result); + payloadValidationResult + .getInvalidTransitionBlockRoot() + .ifPresentOrElse( + invalidTransitionBlockRoot -> + getForkChoiceStrategy() + .onExecutionPayloadResult(invalidTransitionBlockRoot, payloadResult, true), + () -> + getForkChoiceStrategy() + .onExecutionPayloadResult(block.getParentRoot(), payloadResult, false)); + } + + if (payloadResult.hasNotValidatedStatus() || payloadResult.hasFailedExecution()) { + return; + } + + LOG.debug("blobSidecars validation result: {}", blobSidecarsAndValidationResult::toLogString); + + switch (blobSidecarsAndValidationResult.getValidationResult()) { + case NOT_AVAILABLE -> { + return; + } + case INVALID -> { + debugDataDumper.saveInvalidBlobSidecars( + blobSidecarsAndValidationResult.getBlobSidecars(), block); + return; + } + default -> {} + } + + final ForkChoiceStrategy forkChoiceStrategy = getForkChoiceStrategy(); + + // Now that we're on the fork choice thread, make sure the block still descends from finalized + // (which may have changed while we were processing the block) + if (!forkChoiceUtil.blockDescendsFromLatestFinalizedBlock( + block.getSlot(), block.getParentRoot(), recentChainData.getStore(), forkChoiceStrategy)) { + return; + } + + final StoreTransaction transaction = recentChainData.startStoreTransaction(); + addParentStateRoots(spec, blockSlotState, transaction); + + final Optional> blobSidecars; + if (blobSidecarsAndValidationResult.isNotRequired()) { + // Outside availability window or pre-Deneb + blobSidecars = Optional.empty(); + } else if (blobSidecarsAndValidationResult.isValid()) { + blobSidecars = Optional.of(blobSidecarsAndValidationResult.getBlobSidecars()); + } else { + throw new IllegalStateException( + String.format( + "Unexpected attempt to store invalid blob sidecars (%s) for block: %s", + blobSidecarsAndValidationResult.getBlobSidecars().size(), block.toLogString())); + } + final Optional earliestBlobSidecarsSlot = + computeEarliestBlobSidecarsSlot( + recentChainData.getStore(), blobSidecarsAndValidationResult, block.getMessage()); + + forkChoiceUtil.applyExecutionPayloadToStore( + transaction, + block.getSlot(), + executionPayloadEnvelope, + postState, + payloadResult.hasNotValidatedStatus(), + blobSidecars, + earliestBlobSidecarsSlot); + + if (shouldApplyProposerBoost(block, transaction)) { + transaction.setProposerBoostRoot(block.getRoot()); + } + + // Note: not using thenRun here because we want to ensure each step is on the event thread + transaction.commit().join(); + forkChoiceStrategy.onExecutionPayloadResult(block.getRoot(), payloadResult, true); + + notifyForkChoiceUpdatedAndOptimisticSyncingChanged(Optional.empty()); + } // from consensus-specs/fork-choice: private boolean shouldApplyProposerBoost( diff --git a/ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/util/BlockBlobSidecarsTrackersPoolImpl.java b/ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/util/BlockBlobSidecarsTrackersPoolImpl.java index 97bb614bddd..0fc75df007b 100644 --- a/ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/util/BlockBlobSidecarsTrackersPoolImpl.java +++ b/ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/util/BlockBlobSidecarsTrackersPoolImpl.java @@ -558,25 +558,24 @@ private BlockBlobSidecarsTracker internalOnNewBlockAndExecutionPayloadEnvelope( countBlock(remoteOrigin); - if (existingTracker.isRpcFetchTriggered()) { - // block has been set for the first time and we previously triggered fetching of - // missing blobSidecars. So we may have requested to fetch more sidecars - // than the block actually requires. Let's drop them. - existingTracker - .getUnusedBlobSidecarsForBlock() - .forEach( - blobIdentifier -> - requiredBlobSidecarDroppedSubscribers.deliver( - RequiredBlobSidecarDroppedSubscriber::onRequiredBlobSidecarDropped, - blobIdentifier)); - - // if we attempted to fetch via RPC, we missed the opportunity to complete the - // tracker via local EL (local El fetch requires the block to be known) - // Let's try now - if (!existingTracker.isLocalElFetchTriggered() && !existingTracker.isComplete()) { - fetchMissingContentFromLocalEL(slotAndBlockRoot) - .finish(this::logLocalElBlobsLookupFailure); - } + if (!existingTracker.isComplete()) { + // we missed the opportunity to complete the blob sidecars via local EL and RPC + // (since the block is required to be known) Let's try now + asyncRunner + .runAsync( + () -> + fetchMissingBlobsFromLocalEL(slotAndBlockRoot) + .handleException(this::logLocalElBlobsLookupFailure) + .thenRun( + () -> { + // only run if RPC block fetch has happened + // (no blobs RPC fetch has occurred) + if (existingTracker.isRpcBlockFetchTriggered()) { + fetchMissingBlockOrBlobsFromRPC(slotAndBlockRoot); + } + }) + .handleException(this::logBlockOrBlobsRPCFailure)) + .ifExceptionGetsHereRaiseABug(); } }); diff --git a/ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/validation/ExecutionPayloadHeaderValidator.java b/ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/validation/ExecutionPayloadHeaderValidator.java index 70f52de84b8..35517f185c2 100644 --- a/ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/validation/ExecutionPayloadHeaderValidator.java +++ b/ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/validation/ExecutionPayloadHeaderValidator.java @@ -125,7 +125,7 @@ public SafeFuture validateForGossip( .getValue() .plus(spec.atSlot(header.getSlot()).getConfig().getEjectionBalance()) .isGreaterThan(state.getBalances().get(builderIndex.intValue()).get())) { - return InternalValidationResult.IGNORE; + return InternalValidationResult.ignore("insufficient builder's balance"); } /* * [IGNORE] header.parent_block_hash is the block hash of a known execution payload in fork choice. @@ -134,7 +134,7 @@ public SafeFuture validateForGossip( recentChainData.getExecutionBlockHashForBlockRoot(header.getParentBlockRoot()); if (parentBlockHash.isEmpty() || !header.getParentBlockHash().equals(parentBlockHash.get())) { - return InternalValidationResult.IGNORE; + return InternalValidationResult.ignore("parent block hash is unknown"); } /* * [IGNORE] header.parent_block_root is the hash tree root of a known beacon block in fork choice. @@ -144,7 +144,7 @@ public SafeFuture validateForGossip( .getForkChoiceStrategy() .map(forkChoice -> forkChoice.contains(header.getParentBlockRoot())); if (parentBlockRootIsKnown.isEmpty() || !parentBlockRootIsKnown.get()) { - return InternalValidationResult.IGNORE; + return InternalValidationResult.ignore("parent block root is unknown"); } /* * [IGNORE] header.slot is the current slot or the next slot. @@ -153,7 +153,7 @@ public SafeFuture validateForGossip( if (currentSlot.isEmpty() || (!header.getSlot().equals(currentSlot.get()) && !header.getSlot().equals(currentSlot.get().increment()))) { - return InternalValidationResult.IGNORE; + return InternalValidationResult.ignore("header slot is current or next slot"); } /* * [REJECT] The builder signature, signed_execution_payload_header_envelope.signature, is valid with respect to the header_envelope.builder_index. diff --git a/networking/eth2/src/main/java/tech/pegasys/teku/networking/eth2/peers/Eth2PeerFactory.java b/networking/eth2/src/main/java/tech/pegasys/teku/networking/eth2/peers/Eth2PeerFactory.java index 61cd06311a8..02f0aa8f30d 100644 --- a/networking/eth2/src/main/java/tech/pegasys/teku/networking/eth2/peers/Eth2PeerFactory.java +++ b/networking/eth2/src/main/java/tech/pegasys/teku/networking/eth2/peers/Eth2PeerFactory.java @@ -78,8 +78,8 @@ public Eth2Peer create(final Peer peer, final BeaconChainMethods rpcMethods) { metadataMessagesFactory, PeerChainValidator.create(spec, metricsSystem, chainDataClient, requiredCheckpoint), RateTracker.create(peerBlocksRateLimit, TIME_OUT, timeProvider), - RateTracker.create(peerBlocksRateLimit, TIME_OUT, timeProvider), RateTracker.create(peerBlobSidecarsRateLimit, TIME_OUT, timeProvider), + RateTracker.create(peerBlocksRateLimit, TIME_OUT, timeProvider), RateTracker.create(peerRequestLimit, TIME_OUT, timeProvider), kzg); } diff --git a/networking/eth2/src/testFixtures/java/tech/pegasys/teku/networking/eth2/peers/RespondingEth2Peer.java b/networking/eth2/src/testFixtures/java/tech/pegasys/teku/networking/eth2/peers/RespondingEth2Peer.java index c7f2a325194..31836ca69b5 100644 --- a/networking/eth2/src/testFixtures/java/tech/pegasys/teku/networking/eth2/peers/RespondingEth2Peer.java +++ b/networking/eth2/src/testFixtures/java/tech/pegasys/teku/networking/eth2/peers/RespondingEth2Peer.java @@ -263,7 +263,7 @@ public SafeFuture requestBlobSidecarsByRoot( public SafeFuture requestExecutionPayloadEnvelopesByRoot( final List blockRoots, final RpcResponseListener listener) { - throw new UnsupportedOperationException("EIP7732 TODO"); + throw new UnsupportedOperationException("EIP-7732 TODO"); } @Override @@ -296,7 +296,7 @@ public SafeFuture> requestBlobSidecarByRoot( @Override public SafeFuture> requestExecutionPayloadEnvelopeByRoot( final Bytes32 blockRoot) { - throw new UnsupportedOperationException("EIP7732 TODO"); + throw new UnsupportedOperationException("EIP-7732 TODO"); } private SafeFuture createPendingBlockRequest( diff --git a/services/beaconchain/src/main/java/tech/pegasys/teku/services/beaconchain/BeaconChainController.java b/services/beaconchain/src/main/java/tech/pegasys/teku/services/beaconchain/BeaconChainController.java index 2052c2bc250..f469928cac5 100644 --- a/services/beaconchain/src/main/java/tech/pegasys/teku/services/beaconchain/BeaconChainController.java +++ b/services/beaconchain/src/main/java/tech/pegasys/teku/services/beaconchain/BeaconChainController.java @@ -463,6 +463,8 @@ protected SafeFuture initialize() { (blockRoot) -> blockBlobSidecarsTrackersPool.getBlock(blockRoot), (blockRoot, index) -> blockBlobSidecarsTrackersPool.getBlobSidecar(blockRoot, index), + (blockRoot) -> + executionPayloadManager.getValidatedExecutionPayloadEnvelope(blockRoot), storageQueryChannel, storageUpdateChannel, voteUpdateChannel, @@ -1385,6 +1387,7 @@ public void initExecutionPayloadManager() { executionPayloadManager = new ExecutionPayloadManager( executionPayloadValidator, forkChoice, recentChainData, executionLayer); + eventChannels.subscribe(ReceivedBlockEventsChannel.class, executionPayloadManager); } public void initPayloadAttestationManager() { diff --git a/storage/api/src/main/java/tech/pegasys/teku/storage/api/StorageQueryChannel.java b/storage/api/src/main/java/tech/pegasys/teku/storage/api/StorageQueryChannel.java index 9678099eba5..6463ab2ccaf 100644 --- a/storage/api/src/main/java/tech/pegasys/teku/storage/api/StorageQueryChannel.java +++ b/storage/api/src/main/java/tech/pegasys/teku/storage/api/StorageQueryChannel.java @@ -27,6 +27,7 @@ import tech.pegasys.teku.spec.datastructures.blocks.SignedBlockAndState; import tech.pegasys.teku.spec.datastructures.blocks.SlotAndBlockRoot; import tech.pegasys.teku.spec.datastructures.blocks.StateAndBlockSummary; +import tech.pegasys.teku.spec.datastructures.execution.SignedExecutionPayloadEnvelope; import tech.pegasys.teku.spec.datastructures.state.Checkpoint; import tech.pegasys.teku.spec.datastructures.state.beaconstate.BeaconState; import tech.pegasys.teku.spec.datastructures.util.SlotAndBlockRootAndBlobIndex; @@ -70,6 +71,9 @@ SafeFuture> getHotStateAndBlockSummaryByBlockRoot SafeFuture> getBlobSidecarsBySlotAndBlockRoot( SlotAndBlockRoot slotAndBlockRoot); + SafeFuture> getHotExecutionPayloadEnvelopesByRoot( + Set blockRoots); + SafeFuture> getSlotAndBlockRootByStateRoot(Bytes32 stateRoot); SafeFuture> getLatestFinalizedStateAtSlot(UInt64 slot); diff --git a/storage/src/integration-test/java/tech/pegasys/teku/storage/server/kvstore/DatabaseTest.java b/storage/src/integration-test/java/tech/pegasys/teku/storage/server/kvstore/DatabaseTest.java index d0bbffdfb61..b5529ab38da 100644 --- a/storage/src/integration-test/java/tech/pegasys/teku/storage/server/kvstore/DatabaseTest.java +++ b/storage/src/integration-test/java/tech/pegasys/teku/storage/server/kvstore/DatabaseTest.java @@ -56,6 +56,7 @@ import tech.pegasys.teku.bls.BLSKeyGenerator; import tech.pegasys.teku.bls.BLSKeyPair; import tech.pegasys.teku.dataproviders.lookup.BlockProvider; +import tech.pegasys.teku.dataproviders.lookup.ExecutionPayloadEnvelopeProvider; import tech.pegasys.teku.dataproviders.lookup.StateAndBlockSummaryProvider; import tech.pegasys.teku.ethereum.pow.api.DepositTreeSnapshot; import tech.pegasys.teku.ethereum.pow.api.MinGenesisTimeBlockEvent; @@ -1635,10 +1636,11 @@ public void createMemoryStore_priorToGenesisTime(final DatabaseContext context) .bestJustifiedCheckpoint(data.getBestJustifiedCheckpoint()) .blockInformation(data.getBlockInformation()) .votes(data.getVotes()) - // EIP7732 TODO: figure out this + // EIP-7732 TODO: figure out this .ptcVote(new HashMap<>()) .asyncRunner(mock(AsyncRunner.class)) .blockProvider(mock(BlockProvider.class)) + .executionPayloadEnvelopeProvider(mock(ExecutionPayloadEnvelopeProvider.class)) .stateProvider(mock(StateAndBlockSummaryProvider.class)) .build(); diff --git a/storage/src/main/java/tech/pegasys/teku/storage/client/RecentChainData.java b/storage/src/main/java/tech/pegasys/teku/storage/client/RecentChainData.java index df70582424a..f750ff3e9de 100644 --- a/storage/src/main/java/tech/pegasys/teku/storage/client/RecentChainData.java +++ b/storage/src/main/java/tech/pegasys/teku/storage/client/RecentChainData.java @@ -31,8 +31,10 @@ import org.hyperledger.besu.plugin.services.metrics.Counter; import tech.pegasys.teku.dataproviders.lookup.BlockProvider; import tech.pegasys.teku.dataproviders.lookup.EarliestBlobSidecarSlotProvider; +import tech.pegasys.teku.dataproviders.lookup.ExecutionPayloadEnvelopeProvider; import tech.pegasys.teku.dataproviders.lookup.SingleBlobSidecarProvider; import tech.pegasys.teku.dataproviders.lookup.SingleBlockProvider; +import tech.pegasys.teku.dataproviders.lookup.SingleExecutionPayloadEnvelopeProvider; import tech.pegasys.teku.dataproviders.lookup.StateAndBlockSummaryProvider; import tech.pegasys.teku.infrastructure.async.AsyncRunner; import tech.pegasys.teku.infrastructure.async.SafeFuture; @@ -83,6 +85,7 @@ public abstract class RecentChainData implements StoreUpdateHandler { private static final Logger LOG = LogManager.getLogger(); private final BlockProvider blockProvider; + private final ExecutionPayloadEnvelopeProvider executionPayloadEnvelopeProvider; private final StateAndBlockSummaryProvider stateProvider; private final EarliestBlobSidecarSlotProvider earliestBlobSidecarSlotProvider; protected final FinalizedCheckpointChannel finalizedCheckpointChannel; @@ -108,6 +111,7 @@ public abstract class RecentChainData implements StoreUpdateHandler { private final SingleBlockProvider validatedBlockProvider; private final SingleBlobSidecarProvider validatedBlobSidecarProvider; + private final SingleExecutionPayloadEnvelopeProvider validatedExecutionPayloadEnvelopeProvider; private final LateBlockReorgLogic lateBlockReorgLogic; private final PayloadTimelinessProvider payloadTimelinessProvider; @@ -119,8 +123,10 @@ public abstract class RecentChainData implements StoreUpdateHandler { final MetricsSystem metricsSystem, final StoreConfig storeConfig, final BlockProvider blockProvider, + final ExecutionPayloadEnvelopeProvider executionPayloadEnvelopeProvider, final SingleBlockProvider validatedBlockProvider, final SingleBlobSidecarProvider validatedBlobSidecarProvider, + final SingleExecutionPayloadEnvelopeProvider validatedExecutionPayloadEnvelopeProvider, final StateAndBlockSummaryProvider stateProvider, final EarliestBlobSidecarSlotProvider earliestBlobSidecarSlotProvider, final StorageUpdateChannel storageUpdateChannel, @@ -133,9 +139,11 @@ public abstract class RecentChainData implements StoreUpdateHandler { this.metricsSystem = metricsSystem; this.storeConfig = storeConfig; this.blockProvider = blockProvider; + this.executionPayloadEnvelopeProvider = executionPayloadEnvelopeProvider; this.stateProvider = stateProvider; this.validatedBlockProvider = validatedBlockProvider; this.validatedBlobSidecarProvider = validatedBlobSidecarProvider; + this.validatedExecutionPayloadEnvelopeProvider = validatedExecutionPayloadEnvelopeProvider; this.earliestBlobSidecarSlotProvider = earliestBlobSidecarSlotProvider; this.voteUpdateChannel = voteUpdateChannel; this.chainHeadChannel = chainHeadChannel; @@ -173,6 +181,7 @@ public void initializeFromAnchorPoint(final AnchorPoint anchorPoint, final UInt6 .metricsSystem(metricsSystem) .specProvider(spec) .blockProvider(blockProvider) + .executionPayloadEnvelopeProvider(executionPayloadEnvelopeProvider) .stateProvider(stateProvider) .earliestBlobSidecarSlotProvider(earliestBlobSidecarSlotProvider) .storeConfig(storeConfig) @@ -587,10 +596,9 @@ public Optional getRecentlyValidatedSignedBlockByRoot(final B return store.retrieveExecutionPayloadEnvelope(blockRoot); } - // EIP7732 TODO: implement public Optional getRecentlyValidatedExecutionPayloadEnvelopeByRoot(final Bytes32 blockRoot) { - return Optional.empty(); + return validatedExecutionPayloadEnvelopeProvider.getExecutionPayloadEnvelope(blockRoot); } public SafeFuture> retrieveBlockState(final Bytes32 blockRoot) { diff --git a/storage/src/main/java/tech/pegasys/teku/storage/client/StorageBackedRecentChainData.java b/storage/src/main/java/tech/pegasys/teku/storage/client/StorageBackedRecentChainData.java index 5ffa9a7e22e..5dab0f79fcf 100644 --- a/storage/src/main/java/tech/pegasys/teku/storage/client/StorageBackedRecentChainData.java +++ b/storage/src/main/java/tech/pegasys/teku/storage/client/StorageBackedRecentChainData.java @@ -23,8 +23,10 @@ import org.apache.logging.log4j.Logger; import org.hyperledger.besu.plugin.services.MetricsSystem; import tech.pegasys.teku.dataproviders.lookup.BlockProvider; +import tech.pegasys.teku.dataproviders.lookup.ExecutionPayloadEnvelopeProvider; import tech.pegasys.teku.dataproviders.lookup.SingleBlobSidecarProvider; import tech.pegasys.teku.dataproviders.lookup.SingleBlockProvider; +import tech.pegasys.teku.dataproviders.lookup.SingleExecutionPayloadEnvelopeProvider; import tech.pegasys.teku.dataproviders.lookup.StateAndBlockSummaryProvider; import tech.pegasys.teku.infrastructure.async.AsyncRunner; import tech.pegasys.teku.infrastructure.async.SafeFuture; @@ -44,6 +46,7 @@ public class StorageBackedRecentChainData extends RecentChainData { private static final Logger LOG = LogManager.getLogger(); private final BlockProvider blockProvider; + private final ExecutionPayloadEnvelopeProvider executionPayloadEnvelopeProvider; private final StateAndBlockSummaryProvider stateProvider; private final StorageQueryChannel storageQueryChannel; private final StoreConfig storeConfig; @@ -55,6 +58,7 @@ public StorageBackedRecentChainData( final TimeProvider timeProvider, final SingleBlockProvider validatedBlockProvider, final SingleBlobSidecarProvider validatedBlobSidecarProvider, + final SingleExecutionPayloadEnvelopeProvider validatedExecutionPayloadEnvelopeProvider, final StorageQueryChannel storageQueryChannel, final StorageUpdateChannel storageUpdateChannel, final VoteUpdateChannel voteUpdateChannel, @@ -67,8 +71,10 @@ public StorageBackedRecentChainData( metricsSystem, storeConfig, storageQueryChannel::getHotBlocksByRoot, + storageQueryChannel::getHotExecutionPayloadEnvelopesByRoot, validatedBlockProvider, validatedBlobSidecarProvider, + validatedExecutionPayloadEnvelopeProvider, storageQueryChannel::getHotStateAndBlockSummaryByBlockRoot, storageQueryChannel::getEarliestAvailableBlobSidecarSlot, storageUpdateChannel, @@ -80,6 +86,8 @@ public StorageBackedRecentChainData( this.storeConfig = storeConfig; this.storageQueryChannel = storageQueryChannel; this.blockProvider = storageQueryChannel::getHotBlocksByRoot; + this.executionPayloadEnvelopeProvider = + storageQueryChannel::getHotExecutionPayloadEnvelopesByRoot; this.stateProvider = storageQueryChannel::getHotStateAndBlockSummaryByBlockRoot; } @@ -90,6 +98,7 @@ public static SafeFuture create( final TimeProvider timeProvider, final SingleBlockProvider validatedBlockProvider, final SingleBlobSidecarProvider validatedBlobSidecarProvider, + final SingleExecutionPayloadEnvelopeProvider validatedExecutionPayloadEnvelopeProvider, final StorageQueryChannel storageQueryChannel, final StorageUpdateChannel storageUpdateChannel, final VoteUpdateChannel voteUpdateChannel, @@ -105,6 +114,7 @@ public static SafeFuture create( timeProvider, validatedBlockProvider, validatedBlobSidecarProvider, + validatedExecutionPayloadEnvelopeProvider, storageQueryChannel, storageUpdateChannel, voteUpdateChannel, @@ -124,6 +134,7 @@ public static RecentChainData createImmediately( final TimeProvider timeProvider, final SingleBlockProvider validatedBlockProvider, final SingleBlobSidecarProvider validatedBlobSidecarProvider, + final SingleExecutionPayloadEnvelopeProvider validatedExecutionPayloadEnvelopeProvider, final StorageQueryChannel storageQueryChannel, final StorageUpdateChannel storageUpdateChannel, final VoteUpdateChannel voteUpdateChannel, @@ -139,6 +150,7 @@ public static RecentChainData createImmediately( timeProvider, validatedBlockProvider, validatedBlobSidecarProvider, + validatedExecutionPayloadEnvelopeProvider, storageQueryChannel, storageUpdateChannel, voteUpdateChannel, @@ -179,6 +191,7 @@ private SafeFuture processStoreFuture( .onDiskStoreData(data) .asyncRunner(asyncRunner) .blockProvider(blockProvider) + .executionPayloadEnvelopeProvider(executionPayloadEnvelopeProvider) .stateProvider(stateProvider) .storeConfig(storeConfig) .build(); diff --git a/storage/src/main/java/tech/pegasys/teku/storage/server/ChainStorage.java b/storage/src/main/java/tech/pegasys/teku/storage/server/ChainStorage.java index 5abfe7a53cb..d9a8173bfb0 100644 --- a/storage/src/main/java/tech/pegasys/teku/storage/server/ChainStorage.java +++ b/storage/src/main/java/tech/pegasys/teku/storage/server/ChainStorage.java @@ -34,6 +34,7 @@ import tech.pegasys.teku.spec.datastructures.blocks.SignedBlockAndState; import tech.pegasys.teku.spec.datastructures.blocks.SlotAndBlockRoot; import tech.pegasys.teku.spec.datastructures.blocks.StateAndBlockSummary; +import tech.pegasys.teku.spec.datastructures.execution.SignedExecutionPayloadEnvelope; import tech.pegasys.teku.spec.datastructures.forkchoice.VoteTracker; import tech.pegasys.teku.spec.datastructures.state.AnchorPoint; import tech.pegasys.teku.spec.datastructures.state.Checkpoint; @@ -227,6 +228,13 @@ public SafeFuture> getBlobSidecarsBySlotAndBlockRoot( }); } + // EIP-7732 TODO: implement + @Override + public SafeFuture> + getHotExecutionPayloadEnvelopesByRoot(final Set blockRoots) { + return SafeFuture.failedFuture(new UnsupportedOperationException("Not yet implemented")); + } + @Override public SafeFuture> getSlotAndBlockRootByStateRoot( final Bytes32 stateRoot) { diff --git a/storage/src/main/java/tech/pegasys/teku/storage/server/CombinedStorageChannelSplitter.java b/storage/src/main/java/tech/pegasys/teku/storage/server/CombinedStorageChannelSplitter.java index 83bf303c513..7cdda46f9b9 100644 --- a/storage/src/main/java/tech/pegasys/teku/storage/server/CombinedStorageChannelSplitter.java +++ b/storage/src/main/java/tech/pegasys/teku/storage/server/CombinedStorageChannelSplitter.java @@ -28,6 +28,7 @@ import tech.pegasys.teku.spec.datastructures.blocks.SignedBlockAndState; import tech.pegasys.teku.spec.datastructures.blocks.SlotAndBlockRoot; import tech.pegasys.teku.spec.datastructures.blocks.StateAndBlockSummary; +import tech.pegasys.teku.spec.datastructures.execution.SignedExecutionPayloadEnvelope; import tech.pegasys.teku.spec.datastructures.state.AnchorPoint; import tech.pegasys.teku.spec.datastructures.state.Checkpoint; import tech.pegasys.teku.spec.datastructures.state.beaconstate.BeaconState; @@ -161,6 +162,13 @@ public SafeFuture> getBlobSidecarsBySlotAndBlockRoot( () -> queryDelegate.getBlobSidecarsBySlotAndBlockRoot(slotAndBlockRoot)); } + @Override + public SafeFuture> + getHotExecutionPayloadEnvelopesByRoot(final Set blockRoots) { + return asyncRunner.runAsync( + () -> queryDelegate.getHotExecutionPayloadEnvelopesByRoot(blockRoots)); + } + @Override public SafeFuture> getSlotAndBlockRootByStateRoot( final Bytes32 stateRoot) { diff --git a/storage/src/main/java/tech/pegasys/teku/storage/store/Store.java b/storage/src/main/java/tech/pegasys/teku/storage/store/Store.java index 800c4b97b58..77d41bdc1f9 100644 --- a/storage/src/main/java/tech/pegasys/teku/storage/store/Store.java +++ b/storage/src/main/java/tech/pegasys/teku/storage/store/Store.java @@ -45,6 +45,7 @@ import tech.pegasys.teku.dataproviders.generators.StateRegenerationBaseSelector; import tech.pegasys.teku.dataproviders.lookup.BlockProvider; import tech.pegasys.teku.dataproviders.lookup.EarliestBlobSidecarSlotProvider; +import tech.pegasys.teku.dataproviders.lookup.ExecutionPayloadEnvelopeProvider; import tech.pegasys.teku.dataproviders.lookup.StateAndBlockSummaryProvider; import tech.pegasys.teku.infrastructure.async.AsyncRunner; import tech.pegasys.teku.infrastructure.async.SafeFuture; @@ -102,6 +103,7 @@ class Store extends CacheableStore { private final Spec spec; private final StateAndBlockSummaryProvider stateProvider; private final BlockProvider blockProvider; + private final ExecutionPayloadEnvelopeProvider executionPayloadEnvelopeProvider; private final EarliestBlobSidecarSlotProvider earliestBlobSidecarSlotProvider; private final ForkChoiceStrategy forkChoiceStrategy; @@ -132,6 +134,7 @@ private Store( final Spec spec, final int hotStatePersistenceFrequencyInEpochs, final BlockProvider blockProvider, + final ExecutionPayloadEnvelopeProvider executionPayloadEnvelopeProvider, final StateAndBlockSummaryProvider stateProvider, final EarliestBlobSidecarSlotProvider earliestBlobSidecarSlotProvider, final CachingTaskQueue states, @@ -197,6 +200,8 @@ private Store( .orElseGet(Collections::emptyMap)), createBlockProviderFromMapWhileLocked(this.blocks), blockProvider); + // EIP-7732 TODO: implement as above + this.executionPayloadEnvelopeProvider = executionPayloadEnvelopeProvider; this.earliestBlobSidecarSlotProvider = earliestBlobSidecarSlotProvider; @@ -227,6 +232,7 @@ static UpdatableStore create( final MetricsSystem metricsSystem, final Spec spec, final BlockProvider blockProvider, + final ExecutionPayloadEnvelopeProvider executionPayloadEnvelopeProvider, final StateAndBlockSummaryProvider stateAndBlockProvider, final EarliestBlobSidecarSlotProvider earliestBlobSidecarSlotProvider, final Optional initialCheckpoint, @@ -271,6 +277,7 @@ static UpdatableStore create( spec, config.getHotStatePersistenceFrequencyInEpochs(), blockProvider, + executionPayloadEnvelopeProvider, stateAndBlockProvider, earliestBlobSidecarSlotProvider, stateTaskQueue, @@ -296,6 +303,7 @@ public static UpdatableStore create( final MetricsSystem metricsSystem, final Spec spec, final BlockProvider blockProvider, + final ExecutionPayloadEnvelopeProvider executionPayloadEnvelopeProvider, final StateAndBlockSummaryProvider stateAndBlockProvider, final EarliestBlobSidecarSlotProvider earliestBlobSidecarSlotProvider, final Optional initialCheckpoint, @@ -325,6 +333,7 @@ public static UpdatableStore create( metricsSystem, spec, blockProvider, + executionPayloadEnvelopeProvider, stateAndBlockProvider, earliestBlobSidecarSlotProvider, initialCheckpoint, @@ -553,6 +562,16 @@ public boolean containsBlock(final Bytes32 blockRoot) { } } + @Override + public boolean containsExecutionPayloadEnvelope(final Bytes32 blockRoot) { + readLock.lock(); + try { + return forkChoiceStrategy.executionBlockHash(blockRoot).isPresent(); + } finally { + readLock.unlock(); + } + } + @Override public Collection getOrderedBlockRoots() { readLock.lock(); @@ -652,7 +671,7 @@ public Optional isFfgCompetitive(final Bytes32 headRoot, final Bytes32 headUnrealizedJustifiedCheckpoint.equals(parentUnrealizedJustifiedCheckpoint)); } - // EIP7732 TODO: Turn 256 into constant PAYLOAD_TIMELY_THRESHOLD + // EIP-7732 TODO: Turn 256 into constant PAYLOAD_TIMELY_THRESHOLD @Override public boolean isPayloadPresent(final Bytes32 root) { return ptcVote.getOrDefault(root, Collections.emptyList()).stream() @@ -678,11 +697,13 @@ public SafeFuture> retrieveSignedBlock(final Bytes32 return blockProvider.getBlock(blockRoot); } - // EIP7732 TODO: implement @Override public SafeFuture> retrieveExecutionPayloadEnvelope( final Bytes32 blockRoot) { - return null; + if (!containsExecutionPayloadEnvelope(blockRoot)) { + return EmptyStoreResults.EMPTY_EXECUTION_PAYLOAD_ENVELOPE_FUTURE; + } + return executionPayloadEnvelopeProvider.getExecutionPayloadEnvelope(blockRoot); } @Override diff --git a/storage/src/main/java/tech/pegasys/teku/storage/store/StoreBuilder.java b/storage/src/main/java/tech/pegasys/teku/storage/store/StoreBuilder.java index fd1665879cb..c3d6b9903fa 100644 --- a/storage/src/main/java/tech/pegasys/teku/storage/store/StoreBuilder.java +++ b/storage/src/main/java/tech/pegasys/teku/storage/store/StoreBuilder.java @@ -25,6 +25,7 @@ import org.hyperledger.besu.plugin.services.MetricsSystem; import tech.pegasys.teku.dataproviders.lookup.BlockProvider; import tech.pegasys.teku.dataproviders.lookup.EarliestBlobSidecarSlotProvider; +import tech.pegasys.teku.dataproviders.lookup.ExecutionPayloadEnvelopeProvider; import tech.pegasys.teku.dataproviders.lookup.StateAndBlockSummaryProvider; import tech.pegasys.teku.infrastructure.async.AsyncRunner; import tech.pegasys.teku.infrastructure.unsigned.UInt64; @@ -42,6 +43,7 @@ public class StoreBuilder { private MetricsSystem metricsSystem; private Spec spec; private BlockProvider blockProvider; + private ExecutionPayloadEnvelopeProvider executionPayloadEnvelopeProvider; private StateAndBlockSummaryProvider stateAndBlockProvider; private EarliestBlobSidecarSlotProvider earliestBlobSidecarSlotProvider; private StoreConfig storeConfig = StoreConfig.createDefault(); @@ -105,7 +107,7 @@ public StoreBuilder onDiskStoreData(final OnDiskStoreData data) { .bestJustifiedCheckpoint(data.getBestJustifiedCheckpoint()) .blockInformation(data.getBlockInformation()) .votes(data.getVotes()) - // EIP7732 TODO: figure out this + // EIP-7732 TODO: figure out this .ptcVote(new HashMap<>()); } @@ -118,6 +120,7 @@ public UpdatableStore build() { metricsSystem, spec, blockProvider, + executionPayloadEnvelopeProvider, stateAndBlockProvider, earliestBlobSidecarSlotProvider, anchor, @@ -137,6 +140,7 @@ public UpdatableStore build() { metricsSystem, spec, blockProvider, + executionPayloadEnvelopeProvider, stateAndBlockProvider, earliestBlobSidecarSlotProvider, anchor, @@ -157,6 +161,9 @@ private void assertValid() { checkState(metricsSystem != null, "Metrics system must be defined"); checkState(spec != null, "SpecProvider must be defined"); checkState(blockProvider != null, "Block provider must be defined"); + checkState( + executionPayloadEnvelopeProvider != null, + "Execution payload envelope provider must be defined"); checkState(stateAndBlockProvider != null, "StateAndBlockProvider must be defined"); checkState(time != null, "Time must be defined"); checkState(genesisTime != null, "Genesis time must be defined"); @@ -197,6 +204,13 @@ public StoreBuilder blockProvider(final BlockProvider blockProvider) { return this; } + public StoreBuilder executionPayloadEnvelopeProvider( + final ExecutionPayloadEnvelopeProvider executionPayloadEnvelopeProvider) { + checkNotNull(executionPayloadEnvelopeProvider); + this.executionPayloadEnvelopeProvider = executionPayloadEnvelopeProvider; + return this; + } + public StoreBuilder stateProvider(final StateAndBlockSummaryProvider stateProvider) { checkNotNull(stateProvider); this.stateAndBlockProvider = stateProvider; diff --git a/storage/src/main/java/tech/pegasys/teku/storage/store/StoreTransaction.java b/storage/src/main/java/tech/pegasys/teku/storage/store/StoreTransaction.java index b341b544a89..59b4e218c8d 100644 --- a/storage/src/main/java/tech/pegasys/teku/storage/store/StoreTransaction.java +++ b/storage/src/main/java/tech/pegasys/teku/storage/store/StoreTransaction.java @@ -78,6 +78,8 @@ class StoreTransaction implements UpdatableStore.StoreTransaction { private final UpdatableStore.StoreUpdateHandler updateHandler; // ePBS + Map executionPayloadEnvelopeData = + new HashMap<>(); StoreTransaction( final Spec spec, @@ -110,8 +112,23 @@ public void putBlockAndState( @Override public void putExecutionPayloadEnvelopeAndState( - final SignedExecutionPayloadEnvelopeAndState executionPayloadEnvelopeAndState) { - // EIP-7732 TODO: implement + final SignedExecutionPayloadEnvelope executionPayloadEnvelope, + final BeaconState state, + final BlockCheckpoints blockCheckpoints, + final Optional> blobSidecars, + final Optional maybeEarliestBlobSidecarSlot) { + executionPayloadEnvelopeData.put( + executionPayloadEnvelope.getMessage().getBeaconBlockRoot(), + new TransactionExecutionPayloadEnvelopeData( + executionPayloadEnvelope, state, blockCheckpoints)); + final SlotAndBlockRoot slotAndBlockRoot = + new SlotAndBlockRoot( + state.getSlot(), executionPayloadEnvelope.getMessage().getBeaconBlockRoot()); + blobSidecars.ifPresent(sidecars -> this.blobSidecars.put(slotAndBlockRoot, sidecars)); + if (needToUpdateEarliestBlobSidecarSlot(maybeEarliestBlobSidecarSlot)) { + this.maybeEarliestBlobSidecarTransactionSlot = maybeEarliestBlobSidecarSlot; + } + putStateRoot(state.hashTreeRoot(), slotAndBlockRoot); } private boolean needToUpdateEarliestBlobSidecarSlot( @@ -333,6 +350,12 @@ public boolean containsBlock(final Bytes32 blockRoot) { return blockData.containsKey(blockRoot) || store.containsBlock(blockRoot); } + @Override + public boolean containsExecutionPayloadEnvelope(final Bytes32 blockRoot) { + return executionPayloadEnvelopeData.containsKey(blockRoot) + || store.containsExecutionPayloadEnvelope(blockRoot); + } + @Override public Collection getOrderedBlockRoots() { if (this.blockData.isEmpty()) { @@ -372,11 +395,15 @@ public SafeFuture> retrieveSignedBlock(final Bytes32 return store.retrieveSignedBlock(blockRoot); } - // EIP7732 TODO: implement @Override public SafeFuture> retrieveExecutionPayloadEnvelope( final Bytes32 blockRoot) { - return null; + if (executionPayloadEnvelopeData.containsKey(blockRoot)) { + return SafeFuture.completedFuture( + Optional.of(executionPayloadEnvelopeData.get(blockRoot)) + .map(SignedExecutionPayloadEnvelopeAndState::getExecutionPayloadEnvelope)); + } + return store.retrieveExecutionPayloadEnvelope(blockRoot); } @Override diff --git a/storage/src/main/java/tech/pegasys/teku/storage/store/TransactionExecutionPayloadEnvelopeData.java b/storage/src/main/java/tech/pegasys/teku/storage/store/TransactionExecutionPayloadEnvelopeData.java new file mode 100644 index 00000000000..1ab2f152fb1 --- /dev/null +++ b/storage/src/main/java/tech/pegasys/teku/storage/store/TransactionExecutionPayloadEnvelopeData.java @@ -0,0 +1,71 @@ +/* + * Copyright Consensys Software Inc., 2022 + * + * 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.storage.store; + +import com.google.common.base.MoreObjects; +import java.util.Objects; +import tech.pegasys.teku.spec.datastructures.blocks.BlockCheckpoints; +import tech.pegasys.teku.spec.datastructures.blocks.SignedExecutionPayloadEnvelopeAndState; +import tech.pegasys.teku.spec.datastructures.execution.SignedExecutionPayloadEnvelope; +import tech.pegasys.teku.spec.datastructures.state.beaconstate.BeaconState; + +public class TransactionExecutionPayloadEnvelopeData + extends SignedExecutionPayloadEnvelopeAndState { + private final BlockCheckpoints checkpoints; + + public TransactionExecutionPayloadEnvelopeData( + final SignedExecutionPayloadEnvelope executionPayloadEnvelope, + final BeaconState state, + final BlockCheckpoints checkpoints) { + super(executionPayloadEnvelope, state); + this.checkpoints = checkpoints; + } + + public BlockCheckpoints getCheckpoints() { + return checkpoints; + } + + public SignedExecutionPayloadEnvelopeAndState toSignedBlockAndState() { + return new SignedExecutionPayloadEnvelopeAndState(getExecutionPayloadEnvelope(), getState()); + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + final TransactionExecutionPayloadEnvelopeData that = + (TransactionExecutionPayloadEnvelopeData) o; + return Objects.equals(getExecutionPayloadEnvelope(), that.getExecutionPayloadEnvelope()) + && Objects.equals(getState(), that.getState()) + && Objects.equals(checkpoints, that.checkpoints); + } + + @Override + public int hashCode() { + return Objects.hash(getExecutionPayloadEnvelope(), getState(), checkpoints); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("executionPayloadEnvelope", getExecutionPayloadEnvelope()) + .add("state", getState()) + .add("checkpoints", checkpoints) + .toString(); + } +} diff --git a/storage/src/test/java/tech/pegasys/teku/storage/client/StorageBackedRecentChainDataTest.java b/storage/src/test/java/tech/pegasys/teku/storage/client/StorageBackedRecentChainDataTest.java index 779f7524e87..fe952023255 100644 --- a/storage/src/test/java/tech/pegasys/teku/storage/client/StorageBackedRecentChainDataTest.java +++ b/storage/src/test/java/tech/pegasys/teku/storage/client/StorageBackedRecentChainDataTest.java @@ -27,8 +27,10 @@ import java.util.concurrent.atomic.AtomicBoolean; import org.junit.jupiter.api.Test; import tech.pegasys.teku.dataproviders.lookup.BlockProvider; +import tech.pegasys.teku.dataproviders.lookup.ExecutionPayloadEnvelopeProvider; import tech.pegasys.teku.dataproviders.lookup.SingleBlobSidecarProvider; import tech.pegasys.teku.dataproviders.lookup.SingleBlockProvider; +import tech.pegasys.teku.dataproviders.lookup.SingleExecutionPayloadEnvelopeProvider; import tech.pegasys.teku.dataproviders.lookup.StateAndBlockSummaryProvider; import tech.pegasys.teku.infrastructure.async.SafeFuture; import tech.pegasys.teku.infrastructure.async.StubAsyncRunner; @@ -85,6 +87,7 @@ public void storageBackedClient_storeInitializeViaGetStoreRequest() new SystemTimeProvider(), SingleBlockProvider.NOOP, SingleBlobSidecarProvider.NOOP, + SingleExecutionPayloadEnvelopeProvider.NOOP, storageQueryChannel, storageUpdateChannel, voteUpdateChannel, @@ -114,6 +117,7 @@ public void storageBackedClient_storeInitializeViaGetStoreRequest() .metricsSystem(new StubMetricsSystem()) .specProvider(spec) .blockProvider(BlockProvider.NOOP) + .executionPayloadEnvelopeProvider(ExecutionPayloadEnvelopeProvider.NOOP) .stateProvider(StateAndBlockSummaryProvider.NOOP) .storeConfig(storeConfig) .build(); @@ -136,6 +140,7 @@ public void storageBackedClient_storeInitializeViaNewGenesisState() new SystemTimeProvider(), SingleBlockProvider.NOOP, SingleBlobSidecarProvider.NOOP, + SingleExecutionPayloadEnvelopeProvider.NOOP, storageQueryChannel, storageUpdateChannel, voteUpdateChannel, @@ -165,6 +170,7 @@ public void storageBackedClient_storeInitializeViaNewGenesisState() .metricsSystem(new StubMetricsSystem()) .specProvider(spec) .blockProvider(BlockProvider.NOOP) + .executionPayloadEnvelopeProvider(ExecutionPayloadEnvelopeProvider.NOOP) .stateProvider(StateAndBlockSummaryProvider.NOOP) .storeConfig(storeConfig) .build(); @@ -190,6 +196,7 @@ public void storageBackedClient_storeInitializeViaGetStoreRequestAfterTimeout() new SystemTimeProvider(), SingleBlockProvider.NOOP, SingleBlobSidecarProvider.NOOP, + SingleExecutionPayloadEnvelopeProvider.NOOP, storageQueryChannel, storageUpdateChannel, voteUpdateChannel, @@ -217,6 +224,7 @@ public void storageBackedClient_storeInitializeViaGetStoreRequestAfterTimeout() .metricsSystem(new StubMetricsSystem()) .specProvider(spec) .blockProvider(BlockProvider.NOOP) + .executionPayloadEnvelopeProvider(ExecutionPayloadEnvelopeProvider.NOOP) .stateProvider(StateAndBlockSummaryProvider.NOOP); storeRequestFuture.complete(Optional.of(storeData)); assertThat(client).isCompleted(); @@ -240,6 +248,7 @@ public void storageBackedClient_storeInitializeViaGetStoreRequestAfterIOExceptio new SystemTimeProvider(), SingleBlockProvider.NOOP, SingleBlobSidecarProvider.NOOP, + SingleExecutionPayloadEnvelopeProvider.NOOP, storageQueryChannel, storageUpdateChannel, voteUpdateChannel, diff --git a/storage/src/test/java/tech/pegasys/teku/storage/store/AbstractStoreTest.java b/storage/src/test/java/tech/pegasys/teku/storage/store/AbstractStoreTest.java index 4a142566fc0..3d78e3ff88a 100644 --- a/storage/src/test/java/tech/pegasys/teku/storage/store/AbstractStoreTest.java +++ b/storage/src/test/java/tech/pegasys/teku/storage/store/AbstractStoreTest.java @@ -28,6 +28,7 @@ import java.util.stream.Collectors; import tech.pegasys.teku.dataproviders.lookup.BlockProvider; import tech.pegasys.teku.dataproviders.lookup.EarliestBlobSidecarSlotProvider; +import tech.pegasys.teku.dataproviders.lookup.ExecutionPayloadEnvelopeProvider; import tech.pegasys.teku.dataproviders.lookup.StateAndBlockSummaryProvider; import tech.pegasys.teku.infrastructure.async.SafeFuture; import tech.pegasys.teku.infrastructure.metrics.StubMetricsSystem; @@ -197,6 +198,7 @@ private StoreBuilder createStoreBuilder( .metricsSystem(new StubMetricsSystem()) .specProvider(spec) .blockProvider(blockProviderFromChainBuilder()) + .executionPayloadEnvelopeProvider(ExecutionPayloadEnvelopeProvider.NOOP) .earliestBlobSidecarSlotProvider(earliestBlobSidecarSlotProvider) .stateProvider(StateAndBlockSummaryProvider.NOOP) .anchor(Optional.empty()) diff --git a/storage/src/test/java/tech/pegasys/teku/storage/store/StoreTest.java b/storage/src/test/java/tech/pegasys/teku/storage/store/StoreTest.java index 008bd0ced0f..64182b0a589 100644 --- a/storage/src/test/java/tech/pegasys/teku/storage/store/StoreTest.java +++ b/storage/src/test/java/tech/pegasys/teku/storage/store/StoreTest.java @@ -29,6 +29,7 @@ import org.apache.tuweni.bytes.Bytes32; import org.junit.jupiter.api.Test; import tech.pegasys.teku.dataproviders.lookup.EarliestBlobSidecarSlotProvider; +import tech.pegasys.teku.dataproviders.lookup.ExecutionPayloadEnvelopeProvider; import tech.pegasys.teku.dataproviders.lookup.StateAndBlockSummaryProvider; import tech.pegasys.teku.infrastructure.async.SafeFuture; import tech.pegasys.teku.infrastructure.metrics.StubMetricsSystem; @@ -70,6 +71,7 @@ public void create_timeLessThanGenesisTime() { new StubMetricsSystem(), spec, blockProviderFromChainBuilder(), + ExecutionPayloadEnvelopeProvider.NOOP, StateAndBlockSummaryProvider.NOOP, EarliestBlobSidecarSlotProvider.NOOP, Optional.empty(), diff --git a/storage/src/testFixtures/java/tech/pegasys/teku/storage/api/StubStorageQueryChannel.java b/storage/src/testFixtures/java/tech/pegasys/teku/storage/api/StubStorageQueryChannel.java index c909d238ad9..84acde3cc7c 100644 --- a/storage/src/testFixtures/java/tech/pegasys/teku/storage/api/StubStorageQueryChannel.java +++ b/storage/src/testFixtures/java/tech/pegasys/teku/storage/api/StubStorageQueryChannel.java @@ -28,6 +28,7 @@ import tech.pegasys.teku.spec.datastructures.blocks.SignedBlockAndState; import tech.pegasys.teku.spec.datastructures.blocks.SlotAndBlockRoot; import tech.pegasys.teku.spec.datastructures.blocks.StateAndBlockSummary; +import tech.pegasys.teku.spec.datastructures.execution.SignedExecutionPayloadEnvelope; import tech.pegasys.teku.spec.datastructures.state.Checkpoint; import tech.pegasys.teku.spec.datastructures.state.beaconstate.BeaconState; import tech.pegasys.teku.spec.datastructures.util.SlotAndBlockRootAndBlobIndex; @@ -176,4 +177,10 @@ public SafeFuture> getBlobSidecarsBySlotAndBlockRoot( final SlotAndBlockRoot slotAndBlockRoot) { return SafeFuture.completedFuture(Collections.emptyList()); } + + @Override + public SafeFuture> + getHotExecutionPayloadEnvelopesByRoot(final Set blockRoots) { + return SafeFuture.completedFuture(Collections.emptyMap()); + } } diff --git a/storage/src/testFixtures/java/tech/pegasys/teku/storage/client/MemoryOnlyRecentChainData.java b/storage/src/testFixtures/java/tech/pegasys/teku/storage/client/MemoryOnlyRecentChainData.java index 0f429961b94..e00d6dfe144 100644 --- a/storage/src/testFixtures/java/tech/pegasys/teku/storage/client/MemoryOnlyRecentChainData.java +++ b/storage/src/testFixtures/java/tech/pegasys/teku/storage/client/MemoryOnlyRecentChainData.java @@ -20,8 +20,10 @@ import org.hyperledger.besu.plugin.services.MetricsSystem; import tech.pegasys.teku.dataproviders.lookup.BlockProvider; import tech.pegasys.teku.dataproviders.lookup.EarliestBlobSidecarSlotProvider; +import tech.pegasys.teku.dataproviders.lookup.ExecutionPayloadEnvelopeProvider; import tech.pegasys.teku.dataproviders.lookup.SingleBlobSidecarProvider; import tech.pegasys.teku.dataproviders.lookup.SingleBlockProvider; +import tech.pegasys.teku.dataproviders.lookup.SingleExecutionPayloadEnvelopeProvider; import tech.pegasys.teku.dataproviders.lookup.StateAndBlockSummaryProvider; import tech.pegasys.teku.infrastructure.async.AsyncRunner; import tech.pegasys.teku.spec.Spec; @@ -52,8 +54,10 @@ private MemoryOnlyRecentChainData( metricsSystem, storeConfig, BlockProvider.NOOP, + ExecutionPayloadEnvelopeProvider.NOOP, SingleBlockProvider.NOOP, SingleBlobSidecarProvider.NOOP, + SingleExecutionPayloadEnvelopeProvider.NOOP, StateAndBlockSummaryProvider.NOOP, EarliestBlobSidecarSlotProvider.NOOP, storageUpdateChannel, diff --git a/storage/src/testFixtures/java/tech/pegasys/teku/storage/storageSystem/StorageSystem.java b/storage/src/testFixtures/java/tech/pegasys/teku/storage/storageSystem/StorageSystem.java index c71959bfb9a..f793fc9b898 100644 --- a/storage/src/testFixtures/java/tech/pegasys/teku/storage/storageSystem/StorageSystem.java +++ b/storage/src/testFixtures/java/tech/pegasys/teku/storage/storageSystem/StorageSystem.java @@ -19,6 +19,7 @@ import tech.pegasys.teku.beacon.pow.api.TrackingEth1EventsChannel; import tech.pegasys.teku.dataproviders.lookup.SingleBlobSidecarProvider; import tech.pegasys.teku.dataproviders.lookup.SingleBlockProvider; +import tech.pegasys.teku.dataproviders.lookup.SingleExecutionPayloadEnvelopeProvider; import tech.pegasys.teku.infrastructure.metrics.StubMetricsSystem; import tech.pegasys.teku.infrastructure.time.SystemTimeProvider; import tech.pegasys.teku.infrastructure.time.TimeProvider; @@ -111,6 +112,7 @@ static StorageSystem create( timeProvider, SingleBlockProvider.NOOP, SingleBlobSidecarProvider.NOOP, + SingleExecutionPayloadEnvelopeProvider.NOOP, chainStorageServer, chainStorageServer, chainStorageServer, diff --git a/teku/src/main/java/tech/pegasys/teku/cli/subcommand/debug/DebugDbCommand.java b/teku/src/main/java/tech/pegasys/teku/cli/subcommand/debug/DebugDbCommand.java index aa32be3ba42..d9d0611dc3b 100644 --- a/teku/src/main/java/tech/pegasys/teku/cli/subcommand/debug/DebugDbCommand.java +++ b/teku/src/main/java/tech/pegasys/teku/cli/subcommand/debug/DebugDbCommand.java @@ -38,6 +38,7 @@ import tech.pegasys.teku.cli.options.BeaconNodeDataOptions; import tech.pegasys.teku.cli.options.Eth2NetworkOptions; import tech.pegasys.teku.dataproviders.lookup.BlockProvider; +import tech.pegasys.teku.dataproviders.lookup.ExecutionPayloadEnvelopeProvider; import tech.pegasys.teku.dataproviders.lookup.StateAndBlockSummaryProvider; import tech.pegasys.teku.infrastructure.async.AsyncRunner; import tech.pegasys.teku.infrastructure.async.AsyncRunnerFactory; @@ -264,6 +265,7 @@ public int getLatestFinalizedState( .metricsSystem(new NoOpMetricsSystem()) .specProvider(eth2NetworkOptions.getNetworkConfiguration().getSpec()) .blockProvider(BlockProvider.NOOP) + .executionPayloadEnvelopeProvider(ExecutionPayloadEnvelopeProvider.NOOP) .stateProvider(StateAndBlockSummaryProvider.NOOP) .build()) .map(UpdatableStore::getLatestFinalized); diff --git a/validator/client/src/main/java/tech/pegasys/teku/validator/client/duties/BlockProductionDuty.java b/validator/client/src/main/java/tech/pegasys/teku/validator/client/duties/BlockProductionDuty.java index ff78e99f1fd..3d637d316f1 100644 --- a/validator/client/src/main/java/tech/pegasys/teku/validator/client/duties/BlockProductionDuty.java +++ b/validator/client/src/main/java/tech/pegasys/teku/validator/client/duties/BlockProductionDuty.java @@ -88,7 +88,7 @@ public SafeFuture performDuty() { return forkProvider.getForkInfo(slot).thenCompose(this::produceBlock); } - // EIP7732 TODO: "naive" ePBS block production, need to think about a proper builder flow duty + // EIP-7732 TODO: "naive" ePBS block production, need to think about a proper builder flow duty // abstraction private SafeFuture produceBlock(final ForkInfo forkInfo) { final SpecMilestone milestone = spec.atSlot(slot).getMilestone(); @@ -210,7 +210,7 @@ private SafeFuture sendBlock( return validatorApiChannel .sendSignedBlock( signedBlockContainer, - // EIP7732 TODO: need to make sure block is imported for ePBS (at least for the "naive" + // EIP-7732 TODO: need to make sure block is imported for ePBS (at least for the "naive" // flow) milestone.isGreaterThanOrEqualTo(SpecMilestone.EIP7732) ? BroadcastValidationLevel.CONSENSUS