Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 8385359

Browse files
committedFeb 11, 2025·
Update Store to handle Inclusion Lists
1 parent 614d7e7 commit 8385359

File tree

8 files changed

+138
-14
lines changed

8 files changed

+138
-14
lines changed
 

‎ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/forkchoice/ReadOnlyStore.java

+5
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import tech.pegasys.teku.spec.datastructures.blocks.SlotAndBlockRoot;
3131
import tech.pegasys.teku.spec.datastructures.blocks.StateAndBlockSummary;
3232
import tech.pegasys.teku.spec.datastructures.execution.SlotAndExecutionPayloadSummary;
33+
import tech.pegasys.teku.spec.datastructures.operations.InclusionList;
3334
import tech.pegasys.teku.spec.datastructures.state.AnchorPoint;
3435
import tech.pegasys.teku.spec.datastructures.state.Checkpoint;
3536
import tech.pegasys.teku.spec.datastructures.state.CheckpointState;
@@ -139,4 +140,8 @@ SafeFuture<Optional<BeaconState>> retrieveCheckpointState(
139140

140141
// implements is_ffg_competitive from Consensus Spec
141142
Optional<Boolean> isFfgCompetitive(Bytes32 headRoot, Bytes32 parentRoot);
143+
144+
boolean satisfiesInclusionList(Bytes32 blockRoot);
145+
146+
Optional<List<InclusionList>> getInclusionList(SlotAndBlockRoot slotAndBlockRoot);
142147
}

‎ethereum/spec/src/testFixtures/java/tech/pegasys/teku/spec/datastructures/forkchoice/TestStoreImpl.java

+11
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import tech.pegasys.teku.spec.datastructures.blocks.StateAndBlockSummary;
3535
import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayload;
3636
import tech.pegasys.teku.spec.datastructures.execution.SlotAndExecutionPayloadSummary;
37+
import tech.pegasys.teku.spec.datastructures.operations.InclusionList;
3738
import tech.pegasys.teku.spec.datastructures.state.AnchorPoint;
3839
import tech.pegasys.teku.spec.datastructures.state.Checkpoint;
3940
import tech.pegasys.teku.spec.datastructures.state.CheckpointState;
@@ -264,6 +265,16 @@ public Optional<Boolean> isFfgCompetitive(final Bytes32 headRoot, final Bytes32
264265
return Optional.empty();
265266
}
266267

268+
@Override
269+
public boolean satisfiesInclusionList(final Bytes32 blockRoot) {
270+
return false;
271+
}
272+
273+
@Override
274+
public Optional<List<InclusionList>> getInclusionList(final SlotAndBlockRoot slotAndBlockRoot) {
275+
return Optional.empty();
276+
}
277+
267278
@Override
268279
public Optional<List<BlobSidecar>> getBlobSidecarsIfAvailable(
269280
final SlotAndBlockRoot slotAndBlockRoot) {

‎ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/inclusionlist/InclusionListManager.java

+15-12
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313

1414
package tech.pegasys.teku.statetransition.inclusionlist;
1515

16+
import java.util.ArrayList;
17+
import java.util.HashMap;
1618
import java.util.List;
1719
import java.util.Map;
1820
import java.util.NavigableMap;
@@ -47,18 +49,19 @@ public synchronized void onSlot(final UInt64 slot) {
4749
public void add(final SignedInclusionList signedInclusionList) {
4850
final UInt64 validatorIndex = signedInclusionList.getMessage().getValidatorIndex();
4951
final UInt64 slot = signedInclusionList.getMessage().getSlot();
50-
if (slotToInclusionListsByValidatorIndex.containsKey(slot)) {
51-
if (slotToInclusionListsByValidatorIndex.get(slot).containsKey(validatorIndex)) {
52-
slotToInclusionListsByValidatorIndex.get(slot).get(validatorIndex).add(signedInclusionList);
53-
} else {
54-
slotToInclusionListsByValidatorIndex
55-
.get(slot)
56-
.put(validatorIndex, List.of(signedInclusionList));
57-
}
58-
} else {
59-
slotToInclusionListsByValidatorIndex.put(
60-
slot, Map.of(validatorIndex, List.of(signedInclusionList)));
61-
}
52+
slotToInclusionListsByValidatorIndex
53+
.computeIfAbsent(slot, index -> new HashMap<>())
54+
.compute(
55+
validatorIndex,
56+
(index, inclusionLists) -> {
57+
if (inclusionLists == null) {
58+
return List.of(signedInclusionList);
59+
} else {
60+
List<SignedInclusionList> updatedList = new ArrayList<>(inclusionLists);
61+
updatedList.add(signedInclusionList);
62+
return updatedList;
63+
}
64+
});
6265
}
6366

6467
public SafeFuture<InternalValidationResult> addSignedInclusionList(

‎storage/src/main/java/tech/pegasys/teku/storage/store/CacheableStore.java

+8
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import tech.pegasys.teku.spec.datastructures.blocks.StateAndBlockSummary;
2727
import tech.pegasys.teku.spec.datastructures.execution.SlotAndExecutionPayloadSummary;
2828
import tech.pegasys.teku.spec.datastructures.forkchoice.VoteTracker;
29+
import tech.pegasys.teku.spec.datastructures.operations.InclusionList;
2930

3031
/** Store extension dedicated to keep unsafe updates package-private */
3132
public abstract class CacheableStore implements UpdatableStore {
@@ -38,6 +39,13 @@ public abstract class CacheableStore implements UpdatableStore {
3839

3940
abstract void cacheBlocks(Collection<BlockAndCheckpoints> blockAndCheckpoints);
4041

42+
abstract void cacheUnsatisfiedInclusionListBlock(Bytes32 blockRoot);
43+
44+
abstract void cacheInclusionListEquivocator(
45+
SlotAndBlockRoot slotAndBlockRoot, UInt64 validatorIndex);
46+
47+
abstract void cacheInclusionList(SlotAndBlockRoot slotAndBlockRoot, InclusionList inclusionList);
48+
4149
abstract void cacheStates(Map<Bytes32, StateAndBlockSummary> stateAndBlockSummaries);
4250

4351
abstract void cacheBlobSidecars(Map<SlotAndBlockRoot, List<BlobSidecar>> blobSidecarsMap);

‎storage/src/main/java/tech/pegasys/teku/storage/store/Store.java

+63-2
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,11 @@
2424
import java.util.Collection;
2525
import java.util.Collections;
2626
import java.util.Comparator;
27+
import java.util.HashSet;
2728
import java.util.List;
2829
import java.util.Map;
2930
import java.util.Optional;
31+
import java.util.Set;
3032
import java.util.concurrent.atomic.AtomicReference;
3133
import java.util.concurrent.locks.Lock;
3234
import java.util.concurrent.locks.ReadWriteLock;
@@ -48,6 +50,7 @@
4850
import tech.pegasys.teku.infrastructure.async.AsyncRunner;
4951
import tech.pegasys.teku.infrastructure.async.SafeFuture;
5052
import tech.pegasys.teku.infrastructure.collections.LimitedMap;
53+
import tech.pegasys.teku.infrastructure.collections.LimitedSet;
5154
import tech.pegasys.teku.infrastructure.metrics.SettableGauge;
5255
import tech.pegasys.teku.infrastructure.metrics.TekuMetricCategory;
5356
import tech.pegasys.teku.infrastructure.unsigned.UInt64;
@@ -64,6 +67,7 @@
6467
import tech.pegasys.teku.spec.datastructures.forkchoice.VoteTracker;
6568
import tech.pegasys.teku.spec.datastructures.forkchoice.VoteUpdater;
6669
import tech.pegasys.teku.spec.datastructures.hashtree.HashTree;
70+
import tech.pegasys.teku.spec.datastructures.operations.InclusionList;
6771
import tech.pegasys.teku.spec.datastructures.state.AnchorPoint;
6872
import tech.pegasys.teku.spec.datastructures.state.BlockRootAndState;
6973
import tech.pegasys.teku.spec.datastructures.state.Checkpoint;
@@ -106,6 +110,10 @@ class Store extends CacheableStore {
106110
private final Map<Bytes32, SignedBeaconBlock> blocks;
107111
private final CachingTaskQueue<SlotAndBlockRoot, BeaconState> checkpointStates;
108112
private final Map<SlotAndBlockRoot, List<BlobSidecar>> blobSidecars;
113+
private final Map<SlotAndBlockRoot, List<InclusionList>> inclusionLists;
114+
private final Map<SlotAndBlockRoot, Set<UInt64>> inclusionListEquivocators;
115+
private final Set<Bytes32> unsatisfiedInclusionListBlocks;
116+
109117
private UInt64 timeMillis;
110118
private UInt64 genesisTime;
111119
private AnchorPoint finalizedAnchor;
@@ -139,7 +147,10 @@ private Store(
139147
final Map<Bytes32, SignedBeaconBlock> blocks,
140148
final CachingTaskQueue<SlotAndBlockRoot, BeaconState> checkpointStates,
141149
final Optional<Map<Bytes32, StateAndBlockSummary>> maybeEpochStates,
142-
final Map<SlotAndBlockRoot, List<BlobSidecar>> blobSidecars) {
150+
final Map<SlotAndBlockRoot, List<BlobSidecar>> blobSidecars,
151+
final Map<SlotAndBlockRoot, List<InclusionList>> inclusionLists,
152+
final Map<SlotAndBlockRoot, Set<UInt64>> inclusionListEquivocators,
153+
final Set<Bytes32> unsatisfiedInclusionListBlocks) {
143154
checkArgument(
144155
time.isGreaterThanOrEqualTo(genesisTime),
145156
"Time must be greater than or equal to genesisTime");
@@ -164,6 +175,9 @@ private Store(
164175
this.bestJustifiedCheckpoint = bestJustifiedCheckpoint;
165176
this.blocks = blocks;
166177
this.blobSidecars = blobSidecars;
178+
this.inclusionLists = inclusionLists;
179+
this.inclusionListEquivocators = inclusionListEquivocators;
180+
this.unsatisfiedInclusionListBlocks = unsatisfiedInclusionListBlocks;
167181
this.highestVotedValidatorIndex =
168182
votes.keySet().stream().max(Comparator.naturalOrder()).orElse(UInt64.ZERO);
169183
this.votes =
@@ -242,6 +256,13 @@ static UpdatableStore create(
242256
final Map<SlotAndBlockRoot, List<BlobSidecar>> blobSidecars =
243257
LimitedMap.createSynchronizedNatural(config.getBlockCacheSize());
244258

259+
final Map<SlotAndBlockRoot, List<InclusionList>> inclusionLists =
260+
LimitedMap.createSynchronizedNatural(config.getInclusionListCacheSize());
261+
final Map<SlotAndBlockRoot, Set<UInt64>> inclusionListEquivocators =
262+
LimitedMap.createSynchronizedNatural(config.getInclusionListCacheSize());
263+
final Set<Bytes32> unsatisfiedInclusionListBlocks =
264+
LimitedSet.createSynchronized(config.getInclusionListCacheSize());
265+
245266
return new Store(
246267
metricsSystem,
247268
spec,
@@ -262,7 +283,10 @@ static UpdatableStore create(
262283
blocks,
263284
checkpointStateTaskQueue,
264285
maybeEpochStates,
265-
blobSidecars);
286+
blobSidecars,
287+
inclusionLists,
288+
inclusionListEquivocators,
289+
unsatisfiedInclusionListBlocks);
266290
}
267291

268292
public static UpdatableStore create(
@@ -625,6 +649,21 @@ public Optional<Boolean> isFfgCompetitive(final Bytes32 headRoot, final Bytes32
625649
headUnrealizedJustifiedCheckpoint.equals(parentUnrealizedJustifiedCheckpoint));
626650
}
627651

652+
@Override
653+
public boolean satisfiesInclusionList(final Bytes32 blockRoot) {
654+
return unsatisfiedInclusionListBlocks.contains(blockRoot);
655+
}
656+
657+
@Override
658+
public Optional<List<InclusionList>> getInclusionList(final SlotAndBlockRoot slotAndBlockRoot) {
659+
readLock.lock();
660+
try {
661+
return Optional.ofNullable(inclusionLists.get(slotAndBlockRoot));
662+
} finally {
663+
readLock.unlock();
664+
}
665+
}
666+
628667
private Optional<ProtoNodeData> getBlockDataFromForkChoiceStrategy(final Bytes32 root) {
629668
readLock.lock();
630669
try {
@@ -734,6 +773,28 @@ void cacheBlocks(final Collection<BlockAndCheckpoints> blockAndCheckpoints) {
734773
blockCountGauge.ifPresent(gauge -> gauge.set(blocks.size()));
735774
}
736775

776+
/** Non-synchronized, no lock, unsafe if Store is not locked externally */
777+
@Override
778+
void cacheUnsatisfiedInclusionListBlock(final Bytes32 blockRoot) {
779+
unsatisfiedInclusionListBlocks.add(blockRoot);
780+
}
781+
782+
/** Non-synchronized, no lock, unsafe if Store is not locked externally */
783+
@Override
784+
void cacheInclusionListEquivocator(
785+
final SlotAndBlockRoot slotAndBlockRoot, final UInt64 validatorIndex) {
786+
inclusionListEquivocators
787+
.computeIfAbsent(slotAndBlockRoot, key -> new HashSet<>())
788+
.add(validatorIndex);
789+
}
790+
791+
/** Non-synchronized, no lock, unsafe if Store is not locked externally */
792+
@Override
793+
void cacheInclusionList(
794+
final SlotAndBlockRoot slotAndBlockRoot, final InclusionList inclusionList) {
795+
inclusionLists.computeIfAbsent(slotAndBlockRoot, key -> new ArrayList<>()).add(inclusionList);
796+
}
797+
737798
/** Non-synchronized, no lock, unsafe if Store is not locked externally */
738799
@Override
739800
void cacheTimeMillis(final UInt64 timeMillis) {

‎storage/src/main/java/tech/pegasys/teku/storage/store/StoreConfig.java

+16
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ public class StoreConfig {
2525

2626
public static final int DEFAULT_EPOCH_STATE_CACHE_SIZE = 6;
2727
public static final int DEFAULT_BLOCK_CACHE_SIZE = 32;
28+
public static final int DEFAULT_INCLUSION_LIST_CACHE_SIZE = 32;
2829
public static final int DEFAULT_CHECKPOINT_STATE_CACHE_SIZE = 20;
2930
public static final int DEFAULT_HOT_STATE_PERSISTENCE_FREQUENCY_IN_EPOCHS = 2;
3031

@@ -34,19 +35,22 @@ public class StoreConfig {
3435

3536
private final int epochStateCacheSize;
3637
private final int blockCacheSize;
38+
private final int inclusionListCacheSize;
3739
private final int checkpointStateCacheSize;
3840
private final int hotStatePersistenceFrequencyInEpochs;
3941
private final int earliestAvailableBlockSlotFrequency;
4042

4143
private StoreConfig(
4244
final int stateCacheSize,
4345
final int blockCacheSize,
46+
final int inclusionListCacheSize,
4447
final int checkpointStateCacheSize,
4548
final int hotStatePersistenceFrequencyInEpochs,
4649
final int earliestAvailableBlockSlotFrequency,
4750
final int epochStateCacheSize) {
4851
this.stateCacheSize = stateCacheSize;
4952
this.blockCacheSize = blockCacheSize;
53+
this.inclusionListCacheSize = inclusionListCacheSize;
5054
this.checkpointStateCacheSize = checkpointStateCacheSize;
5155
this.hotStatePersistenceFrequencyInEpochs = hotStatePersistenceFrequencyInEpochs;
5256
this.earliestAvailableBlockSlotFrequency = earliestAvailableBlockSlotFrequency;
@@ -73,6 +77,10 @@ public int getBlockCacheSize() {
7377
return blockCacheSize;
7478
}
7579

80+
public int getInclusionListCacheSize() {
81+
return inclusionListCacheSize;
82+
}
83+
7684
public int getCheckpointStateCacheSize() {
7785
return checkpointStateCacheSize;
7886
}
@@ -116,6 +124,7 @@ public static class Builder {
116124

117125
private int epochStateCacheSize = DEFAULT_EPOCH_STATE_CACHE_SIZE;
118126
private int blockCacheSize = DEFAULT_BLOCK_CACHE_SIZE;
127+
private int inclusionListCacheSize = DEFAULT_BLOCK_CACHE_SIZE;
119128
private int checkpointStateCacheSize = DEFAULT_CHECKPOINT_STATE_CACHE_SIZE;
120129
private int hotStatePersistenceFrequencyInEpochs =
121130
DEFAULT_HOT_STATE_PERSISTENCE_FREQUENCY_IN_EPOCHS;
@@ -127,6 +136,7 @@ public StoreConfig build() {
127136
return new StoreConfig(
128137
stateCacheSize,
129138
blockCacheSize,
139+
inclusionListCacheSize,
130140
checkpointStateCacheSize,
131141
hotStatePersistenceFrequencyInEpochs,
132142
earliestAvailableBlockSlotFrequency,
@@ -151,6 +161,12 @@ public Builder blockCacheSize(final int blockCacheSize) {
151161
return this;
152162
}
153163

164+
public Builder inclusionListCacheSize(final int inclusionListCacheSize) {
165+
validateCacheSize(inclusionListCacheSize);
166+
this.inclusionListCacheSize = inclusionListCacheSize;
167+
return this;
168+
}
169+
154170
public Builder checkpointStateCacheSize(final int checkpointStateCacheSize) {
155171
validateCacheSize(checkpointStateCacheSize);
156172
this.checkpointStateCacheSize = checkpointStateCacheSize;

‎storage/src/main/java/tech/pegasys/teku/storage/store/StoreTransaction.java

+11
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import tech.pegasys.teku.spec.datastructures.blocks.StateAndBlockSummary;
4444
import tech.pegasys.teku.spec.datastructures.execution.SlotAndExecutionPayloadSummary;
4545
import tech.pegasys.teku.spec.datastructures.forkchoice.ReadOnlyForkChoiceStrategy;
46+
import tech.pegasys.teku.spec.datastructures.operations.InclusionList;
4647
import tech.pegasys.teku.spec.datastructures.state.AnchorPoint;
4748
import tech.pegasys.teku.spec.datastructures.state.Checkpoint;
4849
import tech.pegasys.teku.spec.datastructures.state.CheckpointState;
@@ -472,6 +473,16 @@ public Optional<Boolean> isFfgCompetitive(final Bytes32 headRoot, final Bytes32
472473
return store.isFfgCompetitive(headRoot, parentRoot);
473474
}
474475

476+
@Override
477+
public boolean satisfiesInclusionList(final Bytes32 blockRoot) {
478+
return store.satisfiesInclusionList(blockRoot);
479+
}
480+
481+
@Override
482+
public Optional<List<InclusionList>> getInclusionList(final SlotAndBlockRoot slotAndBlockRoot) {
483+
return store.getInclusionList(slotAndBlockRoot);
484+
}
485+
475486
@Override
476487
public Optional<SignedBeaconBlock> getBlockIfAvailable(final Bytes32 blockRoot) {
477488
return Optional.ofNullable(blockData.get(blockRoot))

‎teku/src/main/java/tech/pegasys/teku/cli/options/StoreOptions.java

+9
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,14 @@ public class StoreOptions {
3838
arity = "1")
3939
private int blockCacheSize = StoreConfig.DEFAULT_BLOCK_CACHE_SIZE;
4040

41+
@Option(
42+
hidden = true,
43+
names = {"--Xstore-inclusion-list-cache-size"},
44+
paramLabel = "<INTEGER>",
45+
description = "Number of inclusion lists to cache in memory",
46+
arity = "1")
47+
private int inclusionListCacheSize = StoreConfig.DEFAULT_INCLUSION_LIST_CACHE_SIZE;
48+
4149
@Option(
4250
hidden = true,
4351
names = {"--Xstore-state-cache-size"},
@@ -77,6 +85,7 @@ public void configure(final TekuConfiguration.Builder builder) {
7785
b ->
7886
b.hotStatePersistenceFrequencyInEpochs(hotStatePersistenceFrequencyInEpochs)
7987
.blockCacheSize(blockCacheSize)
88+
.inclusionListCacheSize(inclusionListCacheSize)
8089
.stateCacheSize(stateCacheSize)
8190
.epochStateCacheSize(epochStateCacheSize)
8291
.earliestAvailableBlockSlotFrequency(earliestAvailableBlockSlotQueryFrequency)

0 commit comments

Comments
 (0)
Please sign in to comment.