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

PART 1 - GET/Attestation Pool API - Handle Electra attestations in the aggregating pool #8431

Merged
Merged
Show file tree
Hide file tree
Changes from all 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 @@ -269,15 +269,20 @@ public synchronized SszList<Attestation> getAttestationsForBlock(

public synchronized List<Attestation> getAttestations(
final Optional<UInt64> maybeSlot, final Optional<UInt64> maybeCommitteeIndex) {

final Predicate<Map.Entry<UInt64, Set<Bytes>>> filterForSlot =
(entry) -> maybeSlot.map(slot -> entry.getKey().equals(slot)).orElse(true);

// TODO fix for electra (only used in Beacon API)
final Predicate<MatchingDataAttestationGroup> filterForCommitteeIndex =
(group) ->
maybeCommitteeIndex
.map(index -> group.getAttestationData().getIndex().equals(index))
.orElse(true);
final UInt64 slot = maybeSlot.orElse(recentChainData.getCurrentSlot().orElse(UInt64.ZERO));
final SchemaDefinitions schemaDefinitions = spec.atSlot(slot).getSchemaDefinitions();

final boolean requestRequiresAttestationWithCommitteeBits =
schemaDefinitions.getAttestationSchema().requiresCommitteeBits();

return dataHashBySlot.descendingMap().entrySet().stream()
.filter(filterForSlot)
Expand All @@ -288,6 +293,9 @@ public synchronized List<Attestation> getAttestations(
.filter(filterForCommitteeIndex)
.flatMap(MatchingDataAttestationGroup::stream)
.map(ValidatableAttestation::getAttestation)
.filter(
attestation ->
attestation.requiresCommitteeBits() == requestRequiresAttestationWithCommitteeBits)
.toList();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assumptions.assumeThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static tech.pegasys.teku.infrastructure.unsigned.UInt64.ONE;
Expand Down Expand Up @@ -44,6 +45,7 @@
import tech.pegasys.teku.spec.Spec;
import tech.pegasys.teku.spec.SpecMilestone;
import tech.pegasys.teku.spec.TestSpecContext;
import tech.pegasys.teku.spec.TestSpecFactory;
import tech.pegasys.teku.spec.TestSpecInvocationContextProvider;
import tech.pegasys.teku.spec.datastructures.attestation.ValidatableAttestation;
import tech.pegasys.teku.spec.datastructures.operations.Attestation;
Expand All @@ -64,7 +66,6 @@ class AggregatingAttestationPoolTest {
private Spec spec;
private SpecMilestone specMilestone;
private DataStructureUtil dataStructureUtil;
private AttestationSchema<?> attestationSchema;
private Optional<UInt64> committeeIndex;
private final Spec mockSpec = mock(Spec.class);
private final RecentChainData mockRecentChainData = mock(RecentChainData.class);
Expand All @@ -84,7 +85,6 @@ class AggregatingAttestationPoolTest {
public void setUp(final TestSpecInvocationContextProvider.SpecContext specContext) {
spec = specContext.getSpec();
specMilestone = specContext.getSpecMilestone();
attestationSchema = spec.getGenesisSchemaDefinitions().getAttestationSchema();
dataStructureUtil = specContext.getDataStructureUtil();

committeeSizes = new Int2IntOpenHashMap();
Expand Down Expand Up @@ -115,6 +115,7 @@ public void setUp(final TestSpecInvocationContextProvider.SpecContext specContex
when(mockSpec.getCurrentEpoch(any(BeaconState.class)))
.thenAnswer(i -> spec.getCurrentEpoch(i.<BeaconState>getArgument(0)));
when(mockSpec.atSlot(any())).thenAnswer(invocation -> spec.atSlot(invocation.getArgument(0)));
when(mockSpec.getGenesisSchemaDefinitions()).thenReturn(spec.getGenesisSchemaDefinitions());
}

@TestTemplate
Expand Down Expand Up @@ -471,18 +472,57 @@ public void getAttestationsForBlock_shouldNotAddAttestationsFromWrongFork() {

@TestTemplate
public void getAttestations_shouldReturnAllAttestations() {
// TODO EIP7549 Handle Electra attestations
final AttestationData firstAttestationData = dataStructureUtil.randomAttestationData();
final Attestation firstAttestation =
addAttestationFromValidators(firstAttestationData, 1, 2, 3);
final AttestationData secondAttestationData = dataStructureUtil.randomAttestationData();
final Attestation secondAttestation =
addAttestationFromValidators(secondAttestationData, 3, 4, 5);
assertThat(aggregatingPool.getAttestations(Optional.empty(), Optional.empty()))
.containsExactlyInAnyOrder(firstAttestation, secondAttestation);
}

@TestTemplate
public void
getAttestations_shouldReturnElectraAttestationsOnly_whenElectraActivatesAndNoSlotProvided() {
// Genesis spec must be before Electra in order to be able to add phase0 attestations
assumeThat(specMilestone).isLessThan(ELECTRA);
final AttestationData attestationData = dataStructureUtil.randomAttestationData();
Attestation attestation = addAttestationFromValidators(attestationData, 1, 2, 3);
final Spec mockedSpec = mock(Spec.class);
final AggregatingAttestationPool aggregatingPool =
new AggregatingAttestationPool(
mockedSpec,
mockRecentChainData,
new NoOpMetricsSystem(),
DEFAULT_MAXIMUM_ATTESTATION_COUNT);
// Adding a phase0 attestation to the aggregation pool
final Spec phase0Spec = TestSpecFactory.createMinimalPhase0();
when(mockedSpec.atSlot(any())).thenReturn(phase0Spec.getGenesisSpec());
final DataStructureUtil phase0DataStructureUtil = new DataStructureUtil(phase0Spec);
final AttestationData phase0AttestationData =
phase0DataStructureUtil.randomAttestationData(SLOT.minus(4));
addAttestationFromValidators(aggregatingPool, phase0AttestationData, phase0Spec, 4, 5);
rolfyone marked this conversation as resolved.
Show resolved Hide resolved

// Adding an Electra attestation to the aggregation pool
final Spec electraSpec = TestSpecFactory.createMinimalElectra();
// Electra activates from SLOT
when(mockedSpec.atSlot(argThat(slot -> slot.isGreaterThanOrEqualTo(SLOT))))
.thenReturn(electraSpec.getGenesisSpec());
final AttestationData electraAttestationData = dataStructureUtil.randomAttestationData(SLOT);
committeeIndex =
Optional.of(
dataStructureUtil.randomUInt64(
electraSpec.getGenesisSpec().getConfig().getMaxCommitteesPerSlot()));
final Attestation electraAttestation =
addAttestationFromValidators(aggregatingPool, electraAttestationData, electraSpec, 1, 2, 3);

when(mockRecentChainData.getCurrentSlot()).thenReturn(Optional.of(SLOT));
// Should get the Electra attestation only
assertThat(aggregatingPool.getAttestations(Optional.empty(), Optional.empty()))
.containsExactly(attestation);
.containsExactly(electraAttestation);
}

@TestTemplate
public void getAttestations_shouldReturnAttestationsForGivenCommitteeIndexOnly() {
// TODO EIP7549 Handle Electra attestations
assumeThat(specMilestone).isLessThan(ELECTRA);
final AttestationData attestationData1 = dataStructureUtil.randomAttestationData();
final AttestationData attestationData2 =
new AttestationData(
Expand Down Expand Up @@ -560,18 +600,41 @@ private Attestation addAttestationFromValidators(final UInt64 slot, final int...

private Attestation addAttestationFromValidators(
final AttestationData data, final int... validators) {
final Attestation attestation = createAttestation(data, validators);
return addAttestationFromValidators(data, spec, validators);
}

private Attestation addAttestationFromValidators(
final AttestationData data, final Spec spec, final int... validators) {
return addAttestationFromValidators(aggregatingPool, data, spec, validators);
}

private Attestation addAttestationFromValidators(
final AggregatingAttestationPool aggregatingAttestationPool,
final AttestationData data,
final Spec spec,
final int... validators) {
final Attestation attestation = createAttestation(data, spec, validators);
ValidatableAttestation validatableAttestation =
ValidatableAttestation.from(spec, attestation, committeeSizes);
validatableAttestation.saveCommitteeShufflingSeedAndCommitteesSize(
dataStructureUtil.randomBeaconState(100, 15, data.getSlot()));
aggregatingPool.add(validatableAttestation);
aggregatingAttestationPool.add(validatableAttestation);
return attestation;
}

private Attestation createAttestation(final AttestationData data, final int... validators) {
return createAttestation(data, spec, validators);
}

private Attestation createAttestation(
final AttestationData data, final Spec spec, final int... validators) {
final AttestationSchema<?> attestationSchema =
spec.getGenesisSchemaDefinitions().getAttestationSchema();
final SszBitlist bitlist =
attestationSchema.getAggregationBitsSchema().ofBits(COMMITTEE_SIZE, validators);
spec.getGenesisSchemaDefinitions()
.getAttestationSchema()
.getAggregationBitsSchema()
.ofBits(COMMITTEE_SIZE, validators);

final Supplier<SszBitvector> committeeBits;

Expand Down