@@ -219,7 +219,6 @@ library ValidatorSelectionLib {
219219 setCachedProposer (_slot, proposer, stack.proposerIndex);
220220 }
221221
222- // Q: Do we still need to cache the proposer?
223222 function setCachedProposer (Slot _slot , address _proposer , uint256 _proposerIndex ) internal {
224223 require (
225224 _proposerIndex <= type (uint96 ).max,
@@ -230,25 +229,24 @@ library ValidatorSelectionLib {
230229 }
231230
232231 function getProposerAt (Slot _slot ) internal returns (address , uint256 ) {
233- (address cachedProposer , uint256 proposerIndex ) = getCachedProposer (_slot);
232+ (address cachedProposer , uint256 cachedProposerIndex ) = getCachedProposer (_slot);
234233 if (cachedProposer != address (0 )) {
235- return (cachedProposer, proposerIndex );
234+ return (cachedProposer, cachedProposerIndex );
236235 }
237236
238- // @note this is deliberately "bad" for the simple reason of code reduction.
239- // it does not need to actually return the full committee and then draw from it
240- // it can just return the proposer directly, but then we duplicate the code
241- // which we just don't have room for right now...
242237 Epoch epochNumber = _slot.epochFromSlot ();
243238
244239 uint224 sampleSeed = getSampleSeed (epochNumber);
245- address [] memory committee = sampleValidators (epochNumber, sampleSeed);
246- if (committee.length == 0 ) {
240+ (uint32 ts , uint256 [] memory indices ) = sampleValidatorsIndices (epochNumber, sampleSeed);
241+ uint256 committeeSize = indices.length ;
242+ if (committeeSize == 0 ) {
247243 return (address (0 ), 0 );
248244 }
249-
250- uint256 index = computeProposerIndex (epochNumber, _slot, sampleSeed, committee.length );
251- return (committee[index], index);
245+ uint256 proposerIndex = computeProposerIndex (epochNumber, _slot, sampleSeed, committeeSize);
246+ return (
247+ StakingLib.getAttesterFromIndexAtTime (indices[proposerIndex], Timestamp.wrap (ts)),
248+ proposerIndex
249+ );
252250 }
253251
254252 /**
@@ -260,24 +258,7 @@ library ValidatorSelectionLib {
260258 * @return The validators for the given epoch
261259 */
262260 function sampleValidators (Epoch _epoch , uint224 _seed ) internal returns (address [] memory ) {
263- ValidatorSelectionStorage storage store = getStorage ();
264- uint32 ts = epochToSampleTime (_epoch);
265- uint256 validatorSetSize = StakingLib.getAttesterCountAtTime (Timestamp.wrap (ts));
266- uint256 targetCommitteeSize = store.targetCommitteeSize;
267-
268- require (
269- validatorSetSize >= targetCommitteeSize,
270- Errors.ValidatorSelection__InsufficientCommitteeSize (validatorSetSize, targetCommitteeSize)
271- );
272-
273- if (targetCommitteeSize == 0 ) {
274- return new address [](0 );
275- }
276-
277- // Sample the larger committee
278- uint256 [] memory indices =
279- SampleLib.computeCommittee (targetCommitteeSize, validatorSetSize, _seed);
280-
261+ (uint32 ts , uint256 [] memory indices ) = sampleValidatorsIndices (_epoch, _seed);
281262 return StakingLib.getAttestersFromIndicesAtTime (Timestamp.wrap (ts), indices);
282263 }
283264
@@ -420,6 +401,35 @@ library ValidatorSelectionLib {
420401 }
421402 }
422403
404+ /**
405+ * @notice Samples a validator set for a specific epoch and returns their indices within the set.
406+ *
407+ * @dev Only used internally, should never be called for anything but the "next" epoch
408+ * Allowing us to always use `lastSeed`.
409+ *
410+ * @return The sample time and the indices of the validators for the given epoch
411+ */
412+ function sampleValidatorsIndices (Epoch _epoch , uint224 _seed )
413+ internal
414+ returns (uint32 , uint256 [] memory )
415+ {
416+ ValidatorSelectionStorage storage store = getStorage ();
417+ uint32 ts = epochToSampleTime (_epoch);
418+ uint256 validatorSetSize = StakingLib.getAttesterCountAtTime (Timestamp.wrap (ts));
419+ uint256 targetCommitteeSize = store.targetCommitteeSize;
420+
421+ require (
422+ validatorSetSize >= targetCommitteeSize,
423+ Errors.ValidatorSelection__InsufficientCommitteeSize (validatorSetSize, targetCommitteeSize)
424+ );
425+
426+ if (targetCommitteeSize == 0 ) {
427+ return (ts, new uint256 [](0 ));
428+ }
429+
430+ return (ts, SampleLib.computeCommittee (targetCommitteeSize, validatorSetSize, _seed));
431+ }
432+
423433 /**
424434 * @notice Computes the nextSeed for an epoch
425435 *
@@ -457,7 +467,7 @@ library ValidatorSelectionLib {
457467 * @return The index of the proposer
458468 */
459469 function computeProposerIndex (Epoch _epoch , Slot _slot , uint256 _seed , uint256 _size )
460- private
470+ internal
461471 pure
462472 returns (uint256 )
463473 {
0 commit comments