From bd487b50c091aa2b4e23595cfe4095107e637d3d Mon Sep 17 00:00:00 2001 From: Stefan Bratanov Date: Mon, 19 Feb 2024 10:21:24 +0200 Subject: [PATCH 01/10] Make checkpoint sync work when finalized state is transitioned with empty slot --- .../datastructures/blocks/StateAndBlockSummary.java | 8 ++++++-- .../teku/spec/datastructures/state/AnchorPoint.java | 9 +++++++++ .../teku/infrastructure/logging/StatusLogger.java | 13 ++----------- .../services/beaconchain/BeaconChainController.java | 6 +++--- .../beaconchain/WeakSubjectivityInitializer.java | 5 ----- 5 files changed, 20 insertions(+), 21 deletions(-) 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..30bc8842476 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 @@ -33,11 +33,15 @@ public class StateAndBlockSummary implements BeaconBlockSummary { protected StateAndBlockSummary(final BeaconBlockSummary blockSummary, final BeaconState state) { checkNotNull(blockSummary); checkNotNull(state); + verifyStateAndBlockConsistency(); + this.blockSummary = blockSummary; + this.state = state; + } + + protected void verifyStateAndBlockConsistency() { checkArgument( blockSummary.getStateRoot().equals(state.hashTreeRoot()), "Block state root must match the supplied state"); - this.blockSummary = blockSummary; - this.state = state; } public static StateAndBlockSummary create(final BeaconState state) { 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 69046334b66..c4a7dcfd0bc 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 @@ -56,6 +56,15 @@ private AnchorPoint( this.isGenesis = checkpoint.getEpoch().equals(SpecConfig.GENESIS_EPOCH); } + @Override + protected void verifyStateAndBlockConsistency() { + if (state.getSlot().isGreaterThan(blockSummary.getSlot())) { + // skip verification when state is transitioned with empty slot(s) + return; + } + super.verifyStateAndBlockConsistency(); + } + public static AnchorPoint create( final Spec spec, Checkpoint checkpoint, diff --git a/infrastructure/logging/src/main/java/tech/pegasys/teku/infrastructure/logging/StatusLogger.java b/infrastructure/logging/src/main/java/tech/pegasys/teku/infrastructure/logging/StatusLogger.java index 26fd1c87a9c..aaad3325d08 100644 --- a/infrastructure/logging/src/main/java/tech/pegasys/teku/infrastructure/logging/StatusLogger.java +++ b/infrastructure/logging/src/main/java/tech/pegasys/teku/infrastructure/logging/StatusLogger.java @@ -322,21 +322,12 @@ public void loadedInitialStateResource( } } - public void errorIncompatibleInitialState(final UInt64 epoch) { - log.error( - "Cannot start with provided initial state for the epoch {}, " - + "checkpoint occurred on the empty slot, which is not yet supported.\n" - + "If you are using remote checkpoint source, " - + "please wait for the next epoch to finalize and retry.", - epoch); - } - public void warnInitialStateIgnored() { log.warn("Not loading specified initial state as chain data already exists."); } - public void warnFailedToLoadInitialState(final String message) { - log.warn(message); + public void warnFailedToLoadInitialState(final Throwable throwable) { + log.warn("Failed to load initial state", throwable); } public void warnOnInitialStateWithSkippedSlots( 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 18de49d5a2f..83247f22862 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 @@ -1384,14 +1384,14 @@ private Optional tryLoadingAnchorPointFromInitialState( initialAnchor = attemptToLoadAnchorPoint( networkConfiguration.getNetworkBoostrapConfig().getInitialState()); - } catch (final InvalidConfigurationException e) { + } catch (final InvalidConfigurationException ex) { final StateBoostrapConfig stateBoostrapConfig = networkConfiguration.getNetworkBoostrapConfig(); if (stateBoostrapConfig.isUsingCustomInitialState() && !stateBoostrapConfig.isUsingCheckpointSync()) { - throw e; + throw ex; } - STATUS_LOG.warnFailedToLoadInitialState(e.getMessage()); + STATUS_LOG.warnFailedToLoadInitialState(ex); } return initialAnchor; diff --git a/services/beaconchain/src/main/java/tech/pegasys/teku/services/beaconchain/WeakSubjectivityInitializer.java b/services/beaconchain/src/main/java/tech/pegasys/teku/services/beaconchain/WeakSubjectivityInitializer.java index e1d0c9d35a7..564e23d7eec 100644 --- a/services/beaconchain/src/main/java/tech/pegasys/teku/services/beaconchain/WeakSubjectivityInitializer.java +++ b/services/beaconchain/src/main/java/tech/pegasys/teku/services/beaconchain/WeakSubjectivityInitializer.java @@ -13,7 +13,6 @@ package tech.pegasys.teku.services.beaconchain; -import static tech.pegasys.teku.infrastructure.exceptions.ExitConstants.ERROR_EXIT_CODE; import static tech.pegasys.teku.infrastructure.logging.StatusLogger.STATUS_LOG; import static tech.pegasys.teku.networks.Eth2NetworkConfiguration.FINALIZED_STATE_URL_PATH; @@ -86,10 +85,6 @@ private AnchorPoint getAnchorPoint(Spec spec, String stateResource, String sanit throws IOException { STATUS_LOG.loadingInitialStateResource(sanitizedResource); final BeaconState state = ChainDataLoader.loadState(spec, stateResource); - if (state.getSlot().isGreaterThan(state.getLatestBlockHeader().getSlot())) { - STATUS_LOG.errorIncompatibleInitialState(spec.computeEpochAtSlot(state.getSlot())); - System.exit(ERROR_EXIT_CODE); - } final AnchorPoint anchor = AnchorPoint.fromInitialState(spec, state); STATUS_LOG.loadedInitialStateResource( state.hashTreeRoot(), From 052620595b2d62871a084ee25b98ec26903d8e4e Mon Sep 17 00:00:00 2001 From: Stefan Bratanov Date: Mon, 19 Feb 2024 10:34:40 +0200 Subject: [PATCH 02/10] fix --- .../teku/spec/datastructures/blocks/StateAndBlockSummary.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 30bc8842476..6a40e3058f6 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 @@ -33,9 +33,9 @@ public class StateAndBlockSummary implements BeaconBlockSummary { protected StateAndBlockSummary(final BeaconBlockSummary blockSummary, final BeaconState state) { checkNotNull(blockSummary); checkNotNull(state); - verifyStateAndBlockConsistency(); this.blockSummary = blockSummary; this.state = state; + verifyStateAndBlockConsistency(); } protected void verifyStateAndBlockConsistency() { From f157063d5fbcac7a62128c8aafe0e56aeea63a6e Mon Sep 17 00:00:00 2001 From: Stefan Bratanov Date: Mon, 19 Feb 2024 10:39:57 +0200 Subject: [PATCH 03/10] Add actual verification --- .../pegasys/teku/spec/datastructures/state/AnchorPoint.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) 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 c4a7dcfd0bc..fc39ef917b1 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 @@ -59,7 +59,10 @@ private AnchorPoint( @Override protected void verifyStateAndBlockConsistency() { if (state.getSlot().isGreaterThan(blockSummary.getSlot())) { - // skip verification when state is transitioned with empty slot(s) + // state is transitioned with empty slot(s) + checkArgument( + blockSummary.getStateRoot().equals(state.getLatestBlockHeader().getStateRoot()), + "Block state root must match the latest block header state root in the state"); return; } super.verifyStateAndBlockConsistency(); From e076e5decafc429bf0d5d3cbd5c7c9dd8c8a5871 Mon Sep 17 00:00:00 2001 From: Stefan Bratanov Date: Mon, 19 Feb 2024 10:43:08 +0200 Subject: [PATCH 04/10] change comment a bit --- .../pegasys/teku/spec/datastructures/state/AnchorPoint.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 fc39ef917b1..2026887f243 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 @@ -59,7 +59,7 @@ private AnchorPoint( @Override protected void verifyStateAndBlockConsistency() { if (state.getSlot().isGreaterThan(blockSummary.getSlot())) { - // state is transitioned with empty slot(s) + // the finalized state is transitioned with empty slot(s) checkArgument( blockSummary.getStateRoot().equals(state.getLatestBlockHeader().getStateRoot()), "Block state root must match the latest block header state root in the state"); From 9e786006838d7f45f4dfc7724e699e60afccf051 Mon Sep 17 00:00:00 2001 From: Stefan Bratanov Date: Mon, 19 Feb 2024 11:41:52 +0200 Subject: [PATCH 05/10] changes --- .../datastructures/state/AnchorPoint.java | 24 +++++++++---------- .../pegasys/teku/storage/store/Store.java | 7 ++---- 2 files changed, 14 insertions(+), 17 deletions(-) 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 2026887f243..0a6890d804a 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 @@ -56,18 +56,6 @@ private AnchorPoint( this.isGenesis = checkpoint.getEpoch().equals(SpecConfig.GENESIS_EPOCH); } - @Override - protected void verifyStateAndBlockConsistency() { - if (state.getSlot().isGreaterThan(blockSummary.getSlot())) { - // the finalized state is transitioned with empty slot(s) - checkArgument( - blockSummary.getStateRoot().equals(state.getLatestBlockHeader().getStateRoot()), - "Block state root must match the latest block header state root in the state"); - return; - } - super.verifyStateAndBlockConsistency(); - } - public static AnchorPoint create( final Spec spec, Checkpoint checkpoint, @@ -138,6 +126,18 @@ public static AnchorPoint fromInitialBlockAndState( return new AnchorPoint(spec, checkpoint, state, block); } + @Override + protected void verifyStateAndBlockConsistency() { + if (state.getSlot().isGreaterThan(blockSummary.getSlot())) { + // the finalized state is transitioned with empty slot(s) + checkArgument( + blockSummary.getStateRoot().equals(state.getLatestBlockHeader().getStateRoot()), + "Block state root must match the latest block header state root in the state"); + return; + } + super.verifyStateAndBlockConsistency(); + } + public boolean isGenesis() { return isGenesis; } 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 fd69c162f1b..d6478bd571d 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 @@ -858,13 +858,10 @@ private SafeFuture> getOrRegenerateBlockAndState( return SafeFuture.completedFuture(maybeEpochState); } - // if finalized is gone from cache we can still reconstruct that without regenerating + // if finalized is gone from cache we can use the finalized anchor without regenerating if (finalizedAnchor.getRoot().equals(blockRoot)) { LOG.trace("epochCache GET finalizedAnchor {}", finalizedAnchor::getSlot); - return SafeFuture.completedFuture( - Optional.of( - StateAndBlockSummary.create( - finalizedAnchor.getBlockSummary(), finalizedAnchor.getState()))); + return SafeFuture.completedFuture(Optional.of(finalizedAnchor)); } maybeEpochStates.ifPresent( From b201ce38696040c56a4a03912e233065865b75c9 Mon Sep 17 00:00:00 2001 From: Stefan Bratanov Date: Mon, 19 Feb 2024 11:51:30 +0200 Subject: [PATCH 06/10] Add to changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e831c22511f..26dcd43098d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,3 +16,5 @@ the [releases page](https://github.com/Consensys/teku/releases). - Updated Javalin to v.6 (used by rest-api and keymanager-api). ### Bug Fixes + +- Fixed a checkpoint sync issue where Teku couldn't start when the finalized state has been transitioned with empty slot(s) From 872953bab3b2def872101249cca611af14db240c Mon Sep 17 00:00:00 2001 From: Stefan Bratanov Date: Mon, 19 Feb 2024 12:59:43 +0200 Subject: [PATCH 07/10] Add test --- .../java/tech/pegasys/teku/spec/Spec.java | 4 +++ .../datastructures/state/AnchorPointTest.java | 35 +++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/Spec.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/Spec.java index 896a1e42729..0a3ba95951c 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/Spec.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/Spec.java @@ -426,6 +426,10 @@ public UInt64 computeStartSlotAtEpoch(final UInt64 epoch) { return atEpoch(epoch).miscHelpers().computeStartSlotAtEpoch(epoch); } + public UInt64 computeEndSlotAtEpoch(final UInt64 epoch) { + return atEpoch(epoch).miscHelpers().computeEndSlotAtEpoch(epoch); + } + public UInt64 computeEpochAtSlot(final UInt64 slot) { return atSlot(slot).miscHelpers().computeEpochAtSlot(slot); } diff --git a/ethereum/spec/src/test/java/tech/pegasys/teku/spec/datastructures/state/AnchorPointTest.java b/ethereum/spec/src/test/java/tech/pegasys/teku/spec/datastructures/state/AnchorPointTest.java index e7b5dd7c6f6..ecf7340265e 100644 --- a/ethereum/spec/src/test/java/tech/pegasys/teku/spec/datastructures/state/AnchorPointTest.java +++ b/ethereum/spec/src/test/java/tech/pegasys/teku/spec/datastructures/state/AnchorPointTest.java @@ -13,6 +13,7 @@ package tech.pegasys.teku.spec.datastructures.state; +import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; import java.util.Optional; @@ -21,11 +22,19 @@ import tech.pegasys.teku.spec.Spec; import tech.pegasys.teku.spec.TestSpecFactory; import tech.pegasys.teku.spec.datastructures.blocks.BeaconBlockAndState; +import tech.pegasys.teku.spec.datastructures.blocks.SignedBlockAndState; +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.spec.util.DataStructureUtil; +import tech.pegasys.teku.storage.storageSystem.InMemoryStorageSystemBuilder; +import tech.pegasys.teku.storage.storageSystem.StorageSystem; public class AnchorPointTest { private final Spec spec = TestSpecFactory.createDefault(); private final DataStructureUtil dataStructureUtil = new DataStructureUtil(spec); + private final StorageSystem storageSystem = + InMemoryStorageSystemBuilder.create().specProvider(spec).build(); @Test public void create_withCheckpointPriorToState() { @@ -41,4 +50,30 @@ public void create_withCheckpointPriorToState() { .isInstanceOf(IllegalArgumentException.class) .hasMessageContaining("Block must be at or prior to the start of the checkpoint epoch"); } + + @Test + public void createFromInitialState_WithEmptySlotOnCheckpointEpochTransition() + throws SlotProcessingException, EpochProcessingException { + storageSystem.chainUpdater().initializeGenesis(); + + final UInt64 latestBlockHeaderEpoch = UInt64.valueOf(4); + final UInt64 latestBlockHeaderSlot = spec.computeEndSlotAtEpoch(latestBlockHeaderEpoch); + final SignedBlockAndState blockAndState = + storageSystem.chainUpdater().advanceChainUntil(latestBlockHeaderSlot); + + // process empty slot on checkpoint epoch transition + final BeaconState postState = + spec.processSlots(blockAndState.getState(), latestBlockHeaderSlot.increment()); + + final AnchorPoint anchor = AnchorPoint.fromInitialState(spec, postState); + + // verify finalized anchor + assertThat(anchor.getBlockSlot()).isEqualTo(latestBlockHeaderSlot); + assertThat(anchor.getStateRoot()).isEqualTo(blockAndState.getBlock().getStateRoot()); + final Checkpoint expectedCheckpoint = + new Checkpoint( + latestBlockHeaderEpoch.plus(1), + blockAndState.getBlock().asHeader().getMessage().hashTreeRoot()); + assertThat(anchor.getCheckpoint()).isEqualTo(expectedCheckpoint); + } } From c05a1f2a494007ac5a08106d75376852029a383e Mon Sep 17 00:00:00 2001 From: Stefan Bratanov Date: Mon, 19 Feb 2024 13:02:10 +0200 Subject: [PATCH 08/10] change test name --- .../teku/spec/datastructures/state/AnchorPointTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ethereum/spec/src/test/java/tech/pegasys/teku/spec/datastructures/state/AnchorPointTest.java b/ethereum/spec/src/test/java/tech/pegasys/teku/spec/datastructures/state/AnchorPointTest.java index ecf7340265e..aed77ec2d19 100644 --- a/ethereum/spec/src/test/java/tech/pegasys/teku/spec/datastructures/state/AnchorPointTest.java +++ b/ethereum/spec/src/test/java/tech/pegasys/teku/spec/datastructures/state/AnchorPointTest.java @@ -52,7 +52,7 @@ public void create_withCheckpointPriorToState() { } @Test - public void createFromInitialState_WithEmptySlotOnCheckpointEpochTransition() + public void createFromInitialState_WhenFinalizedStateTransitionedWithAnEmptySlot() throws SlotProcessingException, EpochProcessingException { storageSystem.chainUpdater().initializeGenesis(); @@ -61,7 +61,7 @@ public void createFromInitialState_WithEmptySlotOnCheckpointEpochTransition() final SignedBlockAndState blockAndState = storageSystem.chainUpdater().advanceChainUntil(latestBlockHeaderSlot); - // process empty slot on checkpoint epoch transition + // empty slot transition final BeaconState postState = spec.processSlots(blockAndState.getState(), latestBlockHeaderSlot.increment()); From 6199a4a14d1cdfb882bd1cef8895426bbb735a0e Mon Sep 17 00:00:00 2001 From: Stefan Bratanov Date: Mon, 19 Feb 2024 17:18:21 +0200 Subject: [PATCH 09/10] add additional checks --- .../datastructures/state/AnchorPoint.java | 36 +++++++++++++------ 1 file changed, 26 insertions(+), 10 deletions(-) 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 0a6890d804a..347e7436fbf 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 @@ -45,15 +45,10 @@ private AnchorPoint( final BeaconState state, final BeaconBlockSummary blockSummary) { super(blockSummary, state); - checkArgument( - checkpoint.getRoot().equals(blockSummary.getRoot()), "Checkpoint and block must match"); - checkArgument( - checkpoint.getEpochStartSlot(spec).isGreaterThanOrEqualTo(blockSummary.getSlot()), - "Block must be at or prior to the start of the checkpoint epoch"); - this.spec = spec; this.checkpoint = checkpoint; this.isGenesis = checkpoint.getEpoch().equals(SpecConfig.GENESIS_EPOCH); + verifyAnchor(); } public static AnchorPoint create( @@ -126,16 +121,37 @@ public static AnchorPoint fromInitialBlockAndState( return new AnchorPoint(spec, checkpoint, state, block); } + /** Skipping verification in the super class. All checks are made in {@link #verifyAnchor()} */ @Override - protected void verifyStateAndBlockConsistency() { - if (state.getSlot().isGreaterThan(blockSummary.getSlot())) { + protected void verifyStateAndBlockConsistency() {} + + private void verifyAnchor() { + final UInt64 blockSlot = blockSummary.getSlot(); + if (state.getSlot().isGreaterThan(blockSlot)) { // the finalized state is transitioned with empty slot(s) checkArgument( blockSummary.getStateRoot().equals(state.getLatestBlockHeader().getStateRoot()), "Block state root must match the latest block header state root in the state"); - return; + final int stateAndBlockRootsIndex = + blockSlot.mod(spec.getSlotsPerHistoricalRoot(blockSlot)).intValue(); + checkArgument( + blockSummary + .getStateRoot() + .equals(state.getStateRoots().get(stateAndBlockRootsIndex).get()), + "Block state root must match the state root for the block slot %s in the state roots", + blockSlot); + checkArgument( + blockSummary.getRoot().equals(state.getBlockRoots().get(stateAndBlockRootsIndex).get()), + "Block root must match the root for the block slot %s in the block roots in the state", + blockSlot); + } else { + super.verifyStateAndBlockConsistency(); } - super.verifyStateAndBlockConsistency(); + checkArgument( + checkpoint.getRoot().equals(blockSummary.getRoot()), "Checkpoint and block must match"); + checkArgument( + checkpoint.getEpochStartSlot(spec).isGreaterThanOrEqualTo(blockSlot), + "Block must be at or prior to the start of the checkpoint epoch"); } public boolean isGenesis() { From e05a5d73d5e38d2fc62b360439ed15ece161aad7 Mon Sep 17 00:00:00 2001 From: Stefan Bratanov Date: Mon, 19 Feb 2024 17:26:20 +0200 Subject: [PATCH 10/10] change comment --- .../pegasys/teku/spec/datastructures/state/AnchorPoint.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) 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 347e7436fbf..214c84f51d0 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 @@ -121,7 +121,10 @@ public static AnchorPoint fromInitialBlockAndState( return new AnchorPoint(spec, checkpoint, state, block); } - /** Skipping verification in the super class. All checks are made in {@link #verifyAnchor()} */ + /** + * Skipping verification in the super class. All checks are made in {@link #verifyAnchor()} + * instead + */ @Override protected void verifyStateAndBlockConsistency() {}