diff --git a/data/provider/src/main/java/tech/pegasys/teku/api/stateselector/StateSelectorFactory.java b/data/provider/src/main/java/tech/pegasys/teku/api/stateselector/StateSelectorFactory.java index d72b4993993..51e39806b58 100644 --- a/data/provider/src/main/java/tech/pegasys/teku/api/stateselector/StateSelectorFactory.java +++ b/data/provider/src/main/java/tech/pegasys/teku/api/stateselector/StateSelectorFactory.java @@ -16,6 +16,8 @@ import static tech.pegasys.teku.spec.config.SpecConfig.GENESIS_SLOT; import java.util.Optional; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import org.apache.tuweni.bytes.Bytes32; import tech.pegasys.teku.api.AbstractSelectorFactory; import tech.pegasys.teku.infrastructure.async.SafeFuture; @@ -23,13 +25,17 @@ import tech.pegasys.teku.spec.Spec; import tech.pegasys.teku.spec.datastructures.blocks.BeaconBlockHeader; import tech.pegasys.teku.spec.datastructures.metadata.StateAndMetaData; +import tech.pegasys.teku.spec.datastructures.state.AnchorPoint; import tech.pegasys.teku.spec.datastructures.state.beaconstate.BeaconState; +import tech.pegasys.teku.spec.logic.common.statetransition.exceptions.EpochProcessingException; +import tech.pegasys.teku.spec.logic.common.statetransition.exceptions.SlotProcessingException; import tech.pegasys.teku.storage.client.ChainHead; import tech.pegasys.teku.storage.client.CombinedChainDataClient; public class StateSelectorFactory extends AbstractSelectorFactory { private final Spec spec; + private static final Logger LOG = LogManager.getLogger(); public StateSelectorFactory(final Spec spec, final CombinedChainDataClient client) { super(client); @@ -79,20 +85,45 @@ public StateSelector genesisSelector() { @Override public StateSelector finalizedSelector() { + return () -> SafeFuture.completedFuture( client .getLatestFinalized() .map( - finalized -> - addMetaData( - finalized.getState(), - // The finalized checkpoint may change because of optimistically - // imported blocks at the head and if the head isn't optimistic, the - // finalized block can't be optimistic. - client.isChainHeadOptimistic(), - true, - true))); + finalized -> { + final UInt64 slot = finalized.getSlot(); + final Spec spec = finalized.getSpec(); + final BeaconState finalizedState; + //if this isn't the first slot after the finalized epoch than + // we'll compute empty slots until we get there + if (!slot.dividedBy(spec.getSlotsPerEpoch(slot)).isZero()) { + finalizedState = processEmptySlots(finalized, spec); + } else { + finalizedState = finalized.getState(); + } + return addMetaData( + finalizedState, + // The finalized checkpoint may change because of optimistically + // imported blocks at the head and if the head isn't optimistic, the + // finalized block can't be optimistic. + client.isChainHeadOptimistic(), + true, + true); + })); + } + + private BeaconState processEmptySlots(final AnchorPoint finalized, final Spec spec) { + final BeaconState finalizedState; + try { + UInt64 slotToBeReached = + spec.computeStartSlotAtEpoch(finalized.getEpoch()); + finalizedState = + spec.processSlots(finalized.getState(), slotToBeReached); + } catch (SlotProcessingException | EpochProcessingException e) { + throw new RuntimeException(e); + } + return finalizedState; } @Override diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/StateAndBlockSummary.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/StateAndBlockSummary.java index 5dbeabc20a8..3051ef0f898 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/StateAndBlockSummary.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/StateAndBlockSummary.java @@ -128,7 +128,10 @@ public int hashCode() { @Override public String toString() { - return MoreObjects.toStringHelper(this).add("blockSummary", blockSummary).toString(); + return MoreObjects.toStringHelper(this) + .add("blockSummary", blockSummary) + .add("state", state) + .toString(); } private Optional getLatestExecutionPayloadHeader() { diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/state/AnchorPoint.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/state/AnchorPoint.java index 97ab43e0244..b45ba8d8930 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/state/AnchorPoint.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/state/AnchorPoint.java @@ -137,6 +137,10 @@ public Checkpoint getCheckpoint() { return checkpoint; } + public Spec getSpec() { + return spec; + } + public UInt64 getBlockSlot() { return blockSummary.getSlot(); }