Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Include meta data in BlockSelector result #5067

Merged
merged 3 commits into from
Mar 1, 2022
Merged
Show file tree
Hide file tree
Changes from 2 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 @@ -36,6 +36,7 @@
import org.apache.logging.log4j.Logger;
import org.apache.tuweni.bytes.Bytes32;
import org.apache.tuweni.bytes.Bytes48;
import tech.pegasys.teku.api.blockselector.BlockAndMetaData;
import tech.pegasys.teku.api.blockselector.BlockSelectorFactory;
import tech.pegasys.teku.api.exceptions.BadRequestException;
import tech.pegasys.teku.api.response.SszResponse;
Expand Down Expand Up @@ -88,7 +89,7 @@ public ChainDataProvider(
this.combinedChainDataClient = combinedChainDataClient;
this.recentChainData = recentChainData;
this.schemaObjectProvider = new SchemaObjectProvider(spec);
this.defaultBlockSelectorFactory = new BlockSelectorFactory(combinedChainDataClient);
this.defaultBlockSelectorFactory = new BlockSelectorFactory(spec, combinedChainDataClient);
this.defaultStateSelectorFactory = new StateSelectorFactory(combinedChainDataClient);
}

Expand All @@ -115,27 +116,31 @@ public SafeFuture<Optional<BlockHeader>> getBlockHeader(final String slotParamet
return defaultBlockSelectorFactory
.defaultBlockSelector(slotParameter)
.getSingleBlock()
.thenApply(this::discardBlockMetaData)
.thenApply(maybeBlock -> maybeBlock.map(block -> new BlockHeader(block, true)));
}

public SafeFuture<Optional<SignedBeaconBlock>> getBlock(final String slotParameter) {
return defaultBlockSelectorFactory
.defaultBlockSelector(slotParameter)
.getSingleBlock()
.thenApply(this::discardBlockMetaData)
.thenApply(maybeBlock -> maybeBlock.map(schemaObjectProvider::getSignedBeaconBlock));
}

public SafeFuture<Optional<SignedBeaconBlock>> getBlockV2(final String slotParameter) {
return defaultBlockSelectorFactory
.defaultBlockSelector(slotParameter)
.getSingleBlock()
.thenApply(this::discardBlockMetaData)
.thenApply(maybeBlock -> maybeBlock.map(schemaObjectProvider::getSignedBeaconBlock));
}

public SafeFuture<Optional<SszResponse>> getBlockSsz(final String slotParameter) {
return defaultBlockSelectorFactory
.defaultBlockSelector(slotParameter)
.getSingleBlock()
.thenApply(this::discardBlockMetaData)
.thenApply(
maybeBlock ->
maybeBlock.map(
Expand All @@ -150,13 +155,15 @@ public SafeFuture<Optional<Root>> getBlockRoot(final String slotParameter) {
return defaultBlockSelectorFactory
.defaultBlockSelector(slotParameter)
.getSingleBlock()
.thenApply(this::discardBlockMetaData)
.thenApply(maybeBlock -> maybeBlock.map(block -> new Root(block.getRoot())));
}

public SafeFuture<Optional<List<Attestation>>> getBlockAttestations(final String slotParameter) {
return defaultBlockSelectorFactory
.defaultBlockSelector(slotParameter)
.getSingleBlock()
.thenApply(this::discardBlockMetaData)
.thenApply(
maybeBlock ->
maybeBlock.map(
Expand Down Expand Up @@ -218,6 +225,7 @@ public SafeFuture<GetAllBlocksAtSlotResponse> getAllBlocksAtSlot(final String sl
blockList -> {
final Set<SignedBeaconBlockWithRoot> blocks =
blockList.stream()
.map(this::discardBlockMetaData)
.map(SignedBeaconBlockWithRoot::new)
.collect(Collectors.toSet());

Expand Down Expand Up @@ -344,7 +352,10 @@ public SafeFuture<List<BlockHeader>> getBlockHeaders(
.getBlock()
.thenApply(
blockList ->
blockList.stream().map(block -> new BlockHeader(block, true)).collect(toList()));
blockList.stream()
.map(this::discardBlockMetaData)
.map(block -> new BlockHeader(block, true))
.collect(toList()));
}

public SafeFuture<Optional<List<ValidatorResponse>>> getStateValidators(
Expand Down Expand Up @@ -537,4 +548,22 @@ public SpecMilestone getMilestoneAtSlot(final UInt64 slot) {
public Version getVersionAtSlot(final UInt64 slot) {
return Version.fromMilestone(spec.atSlot(slot).getMilestone());
}

/**
* @deprecated We need to move to using the return metadata instead of recreating it in handlers
*/
@Deprecated
private Optional<tech.pegasys.teku.spec.datastructures.blocks.SignedBeaconBlock>
discardBlockMetaData(final Optional<BlockAndMetaData> maybeBlockAndData) {
return maybeBlockAndData.map(BlockAndMetaData::getData);
}

/**
* @deprecated We need to move to using the return metadata instead of recreating it in handlers
*/
@Deprecated
private tech.pegasys.teku.spec.datastructures.blocks.SignedBeaconBlock discardBlockMetaData(
final BlockAndMetaData blockAndMetaData) {
return blockAndMetaData.getData();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
* Copyright 2022 ConsenSys AG.
*
* 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.api;

import com.google.common.base.MoreObjects;
import java.util.Objects;
import tech.pegasys.teku.spec.SpecMilestone;

public class ObjectAndMetaData<T> {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This class is more generic than we need right now but the next step is to add beacon state with metadata and we don't want to have two separate definitions of the metadata so introducing a class that can be shared now. Little bit of a YAGNI violation but I'm feeling lucky. :)


protected final T data;
private final SpecMilestone milestone;
private final boolean executionOptimistic;

public ObjectAndMetaData(
final T data, final SpecMilestone milestone, final boolean executionOptimistic) {
this.data = data;
this.milestone = milestone;
this.executionOptimistic = executionOptimistic;
}

public T getData() {
return data;
}

public SpecMilestone getMilestone() {
return milestone;
}

public boolean isExecutionOptimistic() {
return executionOptimistic;
}

@Override
public boolean equals(final Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
final ObjectAndMetaData<?> that = (ObjectAndMetaData<?>) o;
return executionOptimistic == that.executionOptimistic
&& Objects.equals(data, that.data)
&& milestone == that.milestone;
}

@Override
public int hashCode() {
return Objects.hash(data, milestone, executionOptimistic);
}

@Override
public String toString() {
return MoreObjects.toStringHelper(this)
.add("data", data)
.add("milestone", milestone)
.add("executionOptimistic", executionOptimistic)
.toString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import tech.pegasys.teku.api.schema.phase0.BeaconStatePhase0;
import tech.pegasys.teku.infrastructure.unsigned.UInt64;
import tech.pegasys.teku.spec.Spec;
import tech.pegasys.teku.spec.SpecMilestone;

/**
* Takes objects from Internal layers and converts to an appropriate schema object.
Expand All @@ -50,8 +51,13 @@ public SignedBeaconBlock getSignedBeaconBlock(

public BeaconBlock getBeaconBlock(
final tech.pegasys.teku.spec.datastructures.blocks.BeaconBlock block) {
final UInt64 slot = block.getSlot();
switch (spec.atSlot(slot).getMilestone()) {
return getBeaconBlock(block, spec.atSlot(block.getSlot()).getMilestone());
}

public BeaconBlock getBeaconBlock(
final tech.pegasys.teku.spec.datastructures.blocks.BeaconBlock block,
final SpecMilestone milestone) {
switch (milestone) {
case PHASE0:
return new BeaconBlockPhase0(
block.getSlot(),
Expand All @@ -74,7 +80,7 @@ public BeaconBlock getBeaconBlock(
block.getStateRoot(),
getBeaconBlockBodyBellatrix(block.getBody()));
default:
throw new IllegalArgumentException("Unsupported milestone for slot " + slot);
throw new IllegalArgumentException("Unsupported milestone for slot " + block.getSlot());
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* Copyright 2022 ConsenSys AG.
*
* 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.api.blockselector;

import tech.pegasys.teku.api.ObjectAndMetaData;
import tech.pegasys.teku.spec.SpecMilestone;
import tech.pegasys.teku.spec.datastructures.blocks.SignedBeaconBlock;

public class BlockAndMetaData extends ObjectAndMetaData<SignedBeaconBlock> {

public BlockAndMetaData(
final SignedBeaconBlock data,
final SpecMilestone milestone,
final boolean executionOptimistic) {
super(data, milestone, executionOptimistic);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,11 @@
import java.util.List;
import java.util.Optional;
import tech.pegasys.teku.infrastructure.async.SafeFuture;
import tech.pegasys.teku.spec.datastructures.blocks.SignedBeaconBlock;

public interface BlockSelector {
SafeFuture<List<SignedBeaconBlock>> getBlock();
SafeFuture<List<BlockAndMetaData>> getBlock();

default SafeFuture<Optional<SignedBeaconBlock>> getSingleBlock() {
default SafeFuture<Optional<BlockAndMetaData>> getSingleBlock() {
return getBlock().thenApply(blockList -> blockList.stream().findFirst());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,27 @@

import static tech.pegasys.teku.spec.config.SpecConfig.GENESIS_SLOT;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import org.apache.tuweni.bytes.Bytes32;
import tech.pegasys.teku.api.exceptions.BadRequestException;
import tech.pegasys.teku.infrastructure.async.SafeFuture;
import tech.pegasys.teku.infrastructure.unsigned.UInt64;
import tech.pegasys.teku.spec.Spec;
import tech.pegasys.teku.spec.datastructures.blocks.SignedBeaconBlock;
import tech.pegasys.teku.storage.client.ChainHead;
import tech.pegasys.teku.storage.client.CombinedChainDataClient;

public class BlockSelectorFactory {

private final Spec spec;
private final CombinedChainDataClient client;

public BlockSelectorFactory(final CombinedChainDataClient combinedChainDataClient) {
public BlockSelectorFactory(
final Spec spec, final CombinedChainDataClient combinedChainDataClient) {
this.spec = spec;
this.client = combinedChainDataClient;
}

Expand All @@ -40,7 +45,7 @@ public BlockSelectorFactory(final CombinedChainDataClient combinedChainDataClien
* the finalized epoch - 0x00 - the block root (bytes32) to return - {UINT64} - a specific slot to
* retrieve a block from
*
* @param selectorMethod
* @param selectorMethod the selector from the rest api call
* @return the selector for the requested string
*/
public BlockSelector defaultBlockSelector(final String selectorMethod) {
Expand Down Expand Up @@ -71,33 +76,78 @@ public BlockSelector headSelector() {
optionalToList(
client
.getChainHead()
.map(ChainHead::getBlock)
.map(this::fromChainHead)
.orElse(SafeFuture.completedFuture(Optional.empty())));
}

private SafeFuture<Optional<BlockAndMetaData>> fromChainHead(final ChainHead head) {
return head.getBlock()
.thenApply(maybeBlock -> lookupBlockData(maybeBlock, head.isOptimistic()));
}

public BlockSelector nonCanonicalBlocksSelector(final UInt64 slot) {
return () -> client.GetAllBlocksAtSlot(slot).thenApply(ArrayList::new);
return () ->
client.GetAllBlocksAtSlot(slot)
.thenApply(
blocks -> blocks.stream().map(this::lookupBlockData).collect(Collectors.toList()));
}

public BlockSelector finalizedSelector() {
return () -> optionalToList(SafeFuture.completedFuture(client.getFinalizedBlock()));
return () ->
optionalToList(SafeFuture.completedFuture(lookupBlockData(client.getFinalizedBlock())));
}

public BlockSelector genesisSelector() {
return () -> optionalToList(client.getBlockAtSlotExact(GENESIS_SLOT));
return () ->
optionalToList(
client
.getBlockAtSlotExact(GENESIS_SLOT)
.thenApply(maybeBlock -> lookupBlockData(maybeBlock, false)));
}

public BlockSelector forSlot(final UInt64 slot) {
return () -> optionalToList(client.getBlockAtSlotExact(slot));
return () -> optionalToList(forSlot(client.getChainHead(), slot));
}

private SafeFuture<Optional<BlockAndMetaData>> forSlot(
final Optional<ChainHead> maybeHead, final UInt64 slot) {
return maybeHead
.map(head -> forSlot(head, slot))
.orElse(SafeFuture.completedFuture(Optional.empty()));
}

private SafeFuture<Optional<BlockAndMetaData>> forSlot(final ChainHead head, final UInt64 slot) {
return client
.getBlockAtSlotExact(slot, head.getRoot())
.thenApply(maybeBlock -> lookupBlockData(maybeBlock, head.isOptimistic()));
}

public BlockSelector forBlockRoot(final Bytes32 blockRoot) {
return () -> optionalToList(client.getBlockByBlockRoot(blockRoot));
return () ->
optionalToList(client.getBlockByBlockRoot(blockRoot).thenApply(this::lookupBlockData));
}

private SafeFuture<List<SignedBeaconBlock>> optionalToList(
final SafeFuture<Optional<SignedBeaconBlock>> future) {
private SafeFuture<List<BlockAndMetaData>> optionalToList(
final SafeFuture<Optional<BlockAndMetaData>> future) {
return future.thenApply(
maybeBlock -> maybeBlock.map(List::of).orElseGet(Collections::emptyList));
}

private Optional<BlockAndMetaData> lookupBlockData(final Optional<SignedBeaconBlock> block) {
return block.map(this::lookupBlockData);
}

private Optional<BlockAndMetaData> lookupBlockData(
final Optional<SignedBeaconBlock> maybeBlock, final boolean isOptimistic) {
return maybeBlock.map(block -> lookupBlockData(block, isOptimistic));
}

private BlockAndMetaData lookupBlockData(final SignedBeaconBlock block) {
return lookupBlockData(block, client.isOptimisticBlock(block.getRoot()));
}

private BlockAndMetaData lookupBlockData(
final SignedBeaconBlock block, final boolean isOptimistic) {
return new BlockAndMetaData(block, spec.atSlot(block.getSlot()).getMilestone(), isOptimistic);
}
}
Loading