Skip to content
Draft
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 @@ -44,14 +44,6 @@ static BlockProvider fromMap(final Map<Bytes32, SignedBeaconBlock> blockMap) {
.collect(Collectors.toMap(Function.identity(), blockMap::get)));
}

static BlockProvider fromList(final List<SignedBeaconBlock> blockAndStates) {
final Map<Bytes32, SignedBeaconBlock> blocks =
blockAndStates.stream()
.collect(Collectors.toMap(SignedBeaconBlock::getRoot, Function.identity()));

return fromMap(blocks);
}

static BlockProvider withKnownBlocks(
final BlockProvider blockProvider, final Map<Bytes32, SignedBeaconBlock> knownBlocks) {
return combined(fromMap(knownBlocks), blockProvider);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* 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.Optional;
import org.apache.tuweni.bytes.Bytes32;
import tech.pegasys.teku.infrastructure.async.SafeFuture;
import tech.pegasys.teku.spec.datastructures.epbs.versions.gloas.SignedExecutionPayloadEnvelope;

@FunctionalInterface
public interface ExecutionPayloadProvider {

ExecutionPayloadProvider NOOP = beaconBlockRoot -> SafeFuture.completedFuture(Optional.empty());

SafeFuture<Optional<SignedExecutionPayloadEnvelope>> getExecutionPayload(Bytes32 beaconBlockRoot);

static ExecutionPayloadProvider combined(
final ExecutionPayloadProvider primaryProvider,
final ExecutionPayloadProvider secondaryProvider) {
return beaconBlockRoot ->
primaryProvider
.getExecutionPayload(beaconBlockRoot)
.thenCompose(
executionPayload -> {
if (executionPayload.isPresent()) {
return SafeFuture.completedFuture(executionPayload);
}
return secondaryProvider.getExecutionPayload(beaconBlockRoot);
});
}
}
13 changes: 13 additions & 0 deletions ethereum/spec/src/main/java/tech/pegasys/teku/spec/Spec.java
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@
import tech.pegasys.teku.spec.datastructures.blocks.SignedBlockContainer;
import tech.pegasys.teku.spec.datastructures.blocks.blockbody.BeaconBlockBodyBuilder;
import tech.pegasys.teku.spec.datastructures.epbs.ExecutionPayloadAndState;
import tech.pegasys.teku.spec.datastructures.epbs.versions.gloas.SignedExecutionPayloadEnvelope;
import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadHeader;
import tech.pegasys.teku.spec.datastructures.execution.versions.capella.Withdrawal;
import tech.pegasys.teku.spec.datastructures.forkchoice.MutableStore;
Expand Down Expand Up @@ -125,6 +126,7 @@
import tech.pegasys.teku.spec.logic.versions.fulu.util.ForkChoiceUtilFulu;
import tech.pegasys.teku.spec.logic.versions.gloas.helpers.BeaconStateAccessorsGloas;
import tech.pegasys.teku.spec.schemas.SchemaDefinitions;
import tech.pegasys.teku.spec.schemas.SchemaDefinitionsGloas;
import tech.pegasys.teku.spec.schemas.registry.SchemaRegistryBuilder;

public class Spec {
Expand Down Expand Up @@ -472,6 +474,17 @@ public SignedBlockContainer deserializeSignedBlindedBlockContainer(
.sszDeserialize(serializedSignedBlindedBlockContainer);
}

/**
* TODO-GLOAS: https://github.com/Consensys/teku/issues/10098 this works for devnet-0 but we need
* a generic solution similar to {@link BeaconBlockInvariants}
*/
public SignedExecutionPayloadEnvelope deserializeSignedExecutionPayload(
final Bytes serializedSignedExecutionPayload) {
return SchemaDefinitionsGloas.required(forMilestone(GLOAS).getSchemaDefinitions())
.getSignedExecutionPayloadEnvelopeSchema()
.sszDeserialize(serializedSignedExecutionPayload);
}

private Optional<SchemaDefinitions> getSchemaDefinitionsForMilestone(
final Optional<String> milestone) {
return milestone
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

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

import org.apache.tuweni.bytes.Bytes32;
import tech.pegasys.teku.infrastructure.unsigned.UInt64;
import tech.pegasys.teku.spec.datastructures.epbs.versions.gloas.SignedExecutionPayloadEnvelope;
import tech.pegasys.teku.spec.datastructures.state.beaconstate.BeaconState;
Expand All @@ -25,4 +26,8 @@ public record SignedExecutionPayloadAndState(
public UInt64 getSlot() {
return executionPayload.getMessage().getSlot();
}

public Bytes32 getBeaconBlockRoot() {
return executionPayload.getMessage().getBeaconBlockRoot();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

package tech.pegasys.teku.spec.datastructures.epbs.versions.gloas;

import org.apache.tuweni.bytes.Bytes32;
import tech.pegasys.teku.bls.BLSSignature;
import tech.pegasys.teku.infrastructure.logging.LogFormatter;
import tech.pegasys.teku.infrastructure.ssz.containers.Container2;
Expand Down Expand Up @@ -53,6 +54,10 @@ public UInt64 getSlot() {
return getMessage().getSlot();
}

public Bytes32 getBeaconBlockRoot() {
return getMessage().getBeaconBlockRoot();
}

public SlotAndBlockRoot getSlotAndBlockRoot() {
return getMessage().getSlotAndBlockRoot();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import tech.pegasys.teku.spec.datastructures.blocks.SignedBeaconBlock;
import tech.pegasys.teku.spec.datastructures.blocks.SignedBlockAndState;
import tech.pegasys.teku.spec.datastructures.blocks.SlotAndBlockRoot;
import tech.pegasys.teku.spec.datastructures.epbs.versions.gloas.SignedExecutionPayloadEnvelope;
import tech.pegasys.teku.spec.datastructures.state.Checkpoint;
import tech.pegasys.teku.spec.datastructures.state.beaconstate.BeaconState;

Expand Down Expand Up @@ -67,6 +68,15 @@ default void putBlockAndState(
Optional.empty());
}

/**
* Stores the corresponding data for this execution payload
*
* @param executionPayload Execution payload
* @param state Corresponding state
*/
void putExecutionPayloadAndState(
SignedExecutionPayloadEnvelope executionPayload, BeaconState state);

void putStateRoot(Bytes32 stateRoot, SlotAndBlockRoot slotAndBlockRoot);

void pullUpBlockCheckpoints(Bytes32 blockRoot);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,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.epbs.versions.gloas.SignedExecutionPayloadEnvelope;
import tech.pegasys.teku.spec.datastructures.execution.SlotAndExecutionPayloadSummary;
import tech.pegasys.teku.spec.datastructures.state.AnchorPoint;
import tech.pegasys.teku.spec.datastructures.state.Checkpoint;
Expand Down Expand Up @@ -139,6 +140,17 @@ SafeFuture<Optional<BeaconState>> retrieveCheckpointState(

void computeBalanceThresholds(BeaconState justifiedState);

// implements is_ffg_competitive from Consensus Spec
// implements is_ffg_competitive from consensus-specs
Optional<Boolean> isFfgCompetitive(Bytes32 headRoot, Bytes32 parentRoot);

/**
* Returns an execution payload only if it is immediately available (not pruned).
*
* @param beaconBlockRoot The beacon block root of the execution payload to retrieve
* @return The execution payload if available.
*/
Optional<SignedExecutionPayloadEnvelope> getExecutionPayloadIfAvailable(Bytes32 beaconBlockRoot);

SafeFuture<Optional<SignedExecutionPayloadEnvelope>> retrieveSignedExecutionPayloadEnvelope(
Bytes32 beaconBlockRoot);
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import tech.pegasys.teku.spec.datastructures.blocks.BlockCheckpoints;
import tech.pegasys.teku.spec.datastructures.blocks.SignedBeaconBlock;
import tech.pegasys.teku.spec.datastructures.blocks.SlotAndBlockRoot;
import tech.pegasys.teku.spec.datastructures.epbs.versions.gloas.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;
Expand Down Expand Up @@ -77,7 +78,9 @@ public TestStoreImpl createEmptyStore() {
new HashMap<>(),
Optional.empty(),
Optional.empty(),
Optional.empty());
Optional.empty(),
new HashMap<>(),
new HashMap<>());
}

private AnchorPoint createAnchorForGenesis() {
Expand All @@ -99,6 +102,8 @@ private TestStoreImpl getForkChoiceStore(final AnchorPoint anchor) {
Map<Checkpoint, BeaconState> checkpointStates = new HashMap<>();
Map<UInt64, VoteTracker> votes = new HashMap<>();
Map<SlotAndBlockRoot, List<BlobSidecar>> blobSidecars = new HashMap<>();
Map<Bytes32, SignedExecutionPayloadEnvelope> executionPayloads = new HashMap<>();
Map<Bytes32, BeaconState> executionPayloadStates = new HashMap<>();

blocks.put(anchorRoot, anchor.getSignedBeaconBlock().orElseThrow());
blockStates.put(anchorRoot, anchorState);
Expand All @@ -124,7 +129,9 @@ private TestStoreImpl getForkChoiceStore(final AnchorPoint anchor) {
blobSidecars,
Optional.empty(),
Optional.empty(),
Optional.empty());
Optional.empty(),
executionPayloads,
executionPayloadStates);
}

private BeaconState createRandomGenesisState() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,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.epbs.versions.gloas.SignedExecutionPayloadEnvelope;
import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayload;
import tech.pegasys.teku.spec.datastructures.execution.SlotAndExecutionPayloadSummary;
import tech.pegasys.teku.spec.datastructures.state.AnchorPoint;
Expand All @@ -56,7 +57,10 @@ public class TestStoreImpl implements MutableStore, VoteUpdater {
protected Optional<UInt64> earliestBlobSidecarSlot;
protected Optional<Bytes32> latestCanonicalBlockRoot;
protected Optional<UInt64> custodyGroupCount;
protected Map<Bytes32, SignedExecutionPayloadEnvelope> executionPayloads;
protected Map<Bytes32, BeaconState> executionPayloadStates;
protected Optional<Bytes32> proposerBoostRoot = Optional.empty();

protected final TestReadOnlyForkChoiceStrategy forkChoiceStrategy =
new TestReadOnlyForkChoiceStrategy();

Expand All @@ -76,7 +80,9 @@ public class TestStoreImpl implements MutableStore, VoteUpdater {
final Map<SlotAndBlockRoot, List<BlobSidecar>> blobSidecars,
final Optional<UInt64> maybeEarliestBlobSidecarSlot,
final Optional<Bytes32> maybeLatestCanonicalBlockRoot,
final Optional<UInt64> maybeCustodyGroupCount) {
final Optional<UInt64> maybeCustodyGroupCount,
final Map<Bytes32, SignedExecutionPayloadEnvelope> executionPayloads,
final Map<Bytes32, BeaconState> executionPayloadStates) {
this.spec = spec;
this.timeMillis = secondsToMillis(time);
this.genesisTime = genesisTime;
Expand All @@ -93,6 +99,8 @@ public class TestStoreImpl implements MutableStore, VoteUpdater {
this.earliestBlobSidecarSlot = maybeEarliestBlobSidecarSlot;
this.latestCanonicalBlockRoot = maybeLatestCanonicalBlockRoot;
this.custodyGroupCount = maybeCustodyGroupCount;
this.executionPayloads = executionPayloads;
this.executionPayloadStates = executionPayloadStates;
}

// Readonly methods
Expand Down Expand Up @@ -162,6 +170,10 @@ private SignedBeaconBlock getSignedBlock(final Bytes32 blockRoot) {
return blocks.get(blockRoot);
}

private SignedExecutionPayloadEnvelope getSignedExecutionPayload(final Bytes32 beaconBlockRoot) {
return executionPayloads.get(beaconBlockRoot);
}

private Optional<SignedBlockAndState> getBlockAndState(final Bytes32 blockRoot) {
final SignedBeaconBlock block = getSignedBlock(blockRoot);
final BeaconState state = getBlockState(blockRoot);
Expand Down Expand Up @@ -275,6 +287,18 @@ public Optional<Boolean> isFfgCompetitive(final Bytes32 headRoot, final Bytes32
return Optional.empty();
}

@Override
public Optional<SignedExecutionPayloadEnvelope> getExecutionPayloadIfAvailable(
final Bytes32 beaconBlockRoot) {
return Optional.ofNullable(getSignedExecutionPayload(beaconBlockRoot));
}

@Override
public SafeFuture<Optional<SignedExecutionPayloadEnvelope>>
retrieveSignedExecutionPayloadEnvelope(final Bytes32 beaconBlockRoot) {
return SafeFuture.completedFuture(getExecutionPayloadIfAvailable(beaconBlockRoot));
}

@Override
public Optional<List<BlobSidecar>> getBlobSidecarsIfAvailable(
final SlotAndBlockRoot slotAndBlockRoot) {
Expand Down Expand Up @@ -304,6 +328,14 @@ public void putBlockAndState(
}
}

@Override
public void putExecutionPayloadAndState(
final SignedExecutionPayloadEnvelope executionPayload, final BeaconState state) {
final Bytes32 beaconBlockRoot = executionPayload.getBeaconBlockRoot();
executionPayloads.put(beaconBlockRoot, executionPayload);
executionPayloadStates.put(beaconBlockRoot, state);
}

@Override
public void putStateRoot(final Bytes32 stateRoot, final SlotAndBlockRoot slotAndBlockRoot) {
// NO-OP
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,10 +163,7 @@ private ChainBuilder(
executionPayloads.putAll(existingExecutionPayloads);
existingExecutionPayloads
.values()
.forEach(
e ->
executionPayloadsByHash.put(
e.executionPayload().getMessage().getBeaconBlockRoot(), e));
.forEach(e -> executionPayloadsByHash.put(e.executionPayload().getBeaconBlockRoot(), e));
}

public static ChainBuilder create(final Spec spec) {
Expand All @@ -192,8 +189,18 @@ public Optional<SignedBlockAndState> getBlockAndState(final Bytes32 blockRoot) {
return Optional.ofNullable(blocksByHash.get(blockRoot));
}

public Optional<SignedExecutionPayloadEnvelope> getExecutionPayload(final Bytes32 blockRoot) {
return Optional.ofNullable(executionPayloadsByHash.get(blockRoot))
public Optional<SignedExecutionPayloadAndState> getExecutionPayloadAndState(
final Bytes32 beaconBlockRoot) {
return Optional.ofNullable(executionPayloadsByHash.get(beaconBlockRoot));
}

public Optional<BeaconState> getExecutionPayloadState(final Bytes32 beaconBlockRoot) {
return getExecutionPayloadAndState(beaconBlockRoot).map(SignedExecutionPayloadAndState::state);
}

public Optional<SignedExecutionPayloadEnvelope> getExecutionPayload(
final Bytes32 beaconBlockRoot) {
return getExecutionPayloadAndState(beaconBlockRoot)
.map(SignedExecutionPayloadAndState::executionPayload);
}

Expand Down Expand Up @@ -303,6 +310,10 @@ public Stream<Map.Entry<SlotAndBlockRoot, List<DataColumnSidecar>>> streamDataCo
return streamDataColumnSidecars(UInt64.valueOf(fromSlot), UInt64.valueOf(toSlot), columns);
}

public Stream<SignedExecutionPayloadAndState> streamExecutionPayloadsAndStates() {
return executionPayloads.values().stream();
}

public Stream<SignedExecutionPayloadAndState> streamExecutionPayloadsAndStates(
final long fromSlot, final long toSlot) {
return streamExecutionPayloadsAndStates(UInt64.valueOf(fromSlot), UInt64.valueOf(toSlot));
Expand Down Expand Up @@ -367,10 +378,6 @@ public SignedExecutionPayloadAndState getExecutionPayloadAndStateAtSlot(final UI
return executionPayloads.get(slot);
}

public BeaconState getExecutionPayloadStateAtSlot(final UInt64 slot) {
return resultToState(getExecutionPayloadAndStateAtSlot(slot));
}

public SignedBlockAndState getLatestBlockAndStateAtSlot(final long slot) {
return getLatestBlockAndStateAtSlot(UInt64.valueOf(slot));
}
Expand Down Expand Up @@ -670,19 +677,17 @@ private void trackDataColumnSidecars(
}

private void trackExecutionPayload(final SignedExecutionPayloadAndState executionPayload) {
executionPayloads.put(
executionPayload.executionPayload().getMessage().getSlot(), executionPayload);
executionPayloads.put(executionPayload.executionPayload().getSlot(), executionPayload);
executionPayloadsByHash.put(
executionPayload.executionPayload().getMessage().getBeaconBlockRoot(), executionPayload);
executionPayload.executionPayload().getBeaconBlockRoot(), executionPayload);
}

private SignedBlockAndState appendNewBlockToChain(final UInt64 slot, final BlockOptions options) {
final SignedBlockAndState latestBlockAndState = getLatestBlockAndState();
final Bytes32 parentRoot = latestBlockAndState.getBlock().getRoot();
final BeaconState preState =
// build on top of the execution payload state if an execution payload has been processed
Optional.ofNullable(getExecutionPayloadStateAtSlot(latestBlockAndState.getSlot()))
.orElse(latestBlockAndState.getState());
final Bytes32 parentRoot = latestBlockAndState.getBlock().getMessage().hashTreeRoot();
getExecutionPayloadState(parentRoot).orElse(latestBlockAndState.getState());

int proposerIndex = blockProposalTestUtil.getProposerIndexForSlot(preState, slot);
if (options.isWrongProposerEnabled()) {
Expand Down Expand Up @@ -1017,10 +1022,6 @@ private SignedBeaconBlock resultToBlock(final SignedBlockAndState result) {
return Optional.ofNullable(result).map(SignedBlockAndState::getBlock).orElse(null);
}

private BeaconState resultToState(final SignedExecutionPayloadAndState result) {
return Optional.ofNullable(result).map(SignedExecutionPayloadAndState::state).orElse(null);
}

public SignedContributionAndProofTestBuilder createValidSignedContributionAndProofBuilder() {
return createValidSignedContributionAndProofBuilder(getLatestSlot());
}
Expand Down
Loading
Loading