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 2 - GET/Attestation Pool API - Retrieve attestations and metadata #8437

Merged
merged 3 commits into from
Jul 22, 2024
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 @@ -233,7 +233,9 @@ public DataProvider build() {
isLivenessTrackingEnabled,
activeValidatorChannel,
proposersDataManager,
forkChoiceNotifier);
forkChoiceNotifier,
recentChainData,
spec);
final ChainDataProvider chainDataProvider =
new ChainDataProvider(spec, recentChainData, combinedChainDataClient, rewardCalculator);
final SyncDataProvider syncDataProvider =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@
import tech.pegasys.teku.api.migrated.ValidatorLivenessAtEpoch;
import tech.pegasys.teku.infrastructure.async.SafeFuture;
import tech.pegasys.teku.infrastructure.unsigned.UInt64;
import tech.pegasys.teku.spec.Spec;
import tech.pegasys.teku.spec.datastructures.attestation.ProcessedAttestationListener;
import tech.pegasys.teku.spec.datastructures.metadata.ObjectAndMetaData;
import tech.pegasys.teku.spec.datastructures.operations.Attestation;
import tech.pegasys.teku.spec.datastructures.operations.AttesterSlashing;
import tech.pegasys.teku.spec.datastructures.operations.ProposerSlashing;
Expand All @@ -47,6 +49,7 @@
import tech.pegasys.teku.statetransition.synccommittee.SyncCommitteeContributionPool;
import tech.pegasys.teku.statetransition.validation.InternalValidationResult;
import tech.pegasys.teku.statetransition.validatorcache.ActiveValidatorChannel;
import tech.pegasys.teku.storage.client.RecentChainData;
import tech.pegasys.teku.validator.api.SubmitDataError;

public class NodeDataProvider {
Expand All @@ -63,6 +66,8 @@ public class NodeDataProvider {
private final boolean isLivenessTrackingEnabled;
private final ProposersDataManager proposersDataManager;
private final ForkChoiceNotifier forkChoiceNotifier;
private final RecentChainData recentChainData;
private final Spec spec;

public NodeDataProvider(
final AggregatingAttestationPool attestationPool,
Expand All @@ -76,7 +81,9 @@ public NodeDataProvider(
final boolean isLivenessTrackingEnabled,
final ActiveValidatorChannel activeValidatorChannel,
final ProposersDataManager proposersDataManager,
final ForkChoiceNotifier forkChoiceNotifier) {
final ForkChoiceNotifier forkChoiceNotifier,
final RecentChainData recentChainData,
final Spec spec) {
this.attestationPool = attestationPool;
this.attesterSlashingPool = attesterSlashingsPool;
this.proposerSlashingPool = proposerSlashingPool;
Expand All @@ -89,13 +96,37 @@ public NodeDataProvider(
this.isLivenessTrackingEnabled = isLivenessTrackingEnabled;
this.proposersDataManager = proposersDataManager;
this.forkChoiceNotifier = forkChoiceNotifier;
this.recentChainData = recentChainData;
this.spec = spec;
}

public List<Attestation> getAttestations(
final Optional<UInt64> maybeSlot, final Optional<UInt64> maybeCommitteeIndex) {
return attestationPool.getAttestations(maybeSlot, maybeCommitteeIndex);
}

public ObjectAndMetaData<List<Attestation>> getAttestationsAndMetaData(
final Optional<UInt64> maybeSlot, final Optional<UInt64> maybeCommitteeIndex) {
return lookupMetaData(
attestationPool.getAttestations(maybeSlot, maybeCommitteeIndex), maybeSlot);
}

private ObjectAndMetaData<List<Attestation>> lookupMetaData(
final List<Attestation> attestations, final Optional<UInt64> maybeSlot) {
final UInt64 slot = getSlot(attestations, maybeSlot);
return new ObjectAndMetaData<>(
attestations, spec.atSlot(slot).getMilestone(), false, false, false);
}

private UInt64 getSlot(final List<Attestation> attestations, final Optional<UInt64> maybeSlot) {
return maybeSlot.orElseGet(
() ->
attestations.stream()
.findFirst()
.map(attestation -> attestation.getData().getSlot())
.orElseGet(() -> recentChainData.getCurrentSlot().orElse(UInt64.ZERO)));
}

public List<AttesterSlashing> getAttesterSlashings() {
return new ArrayList<>(attesterSlashingPool.getAll());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,22 @@

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.ExecutionException;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import tech.pegasys.teku.infrastructure.async.SafeFuture;
import tech.pegasys.teku.infrastructure.unsigned.UInt64;
import tech.pegasys.teku.spec.Spec;
import tech.pegasys.teku.spec.SpecMilestone;
import tech.pegasys.teku.spec.SpecVersion;
import tech.pegasys.teku.spec.TestSpecFactory;
import tech.pegasys.teku.spec.datastructures.operations.AttesterSlashing;
import tech.pegasys.teku.spec.datastructures.operations.ProposerSlashing;
Expand All @@ -40,6 +46,7 @@
import tech.pegasys.teku.statetransition.synccommittee.SyncCommitteeContributionPool;
import tech.pegasys.teku.statetransition.validation.InternalValidationResult;
import tech.pegasys.teku.statetransition.validatorcache.ActiveValidatorChannel;
import tech.pegasys.teku.storage.client.RecentChainData;
import tech.pegasys.teku.validator.api.SubmitDataError;

@SuppressWarnings("unchecked")
Expand All @@ -53,6 +60,7 @@ public class NodeDataProviderTest {
private final ActiveValidatorChannel validatorChannel = mock(ActiveValidatorChannel.class);
private final ProposersDataManager proposersDataManager = mock(ProposersDataManager.class);
private final ForkChoiceNotifier forkChoiceNotifier = mock(ForkChoiceNotifier.class);
private final RecentChainData recentChainData = mock(RecentChainData.class);

private final OperationPool<AttesterSlashing> attesterSlashingPool = mock(OperationPool.class);

Expand Down Expand Up @@ -82,7 +90,9 @@ public void setup() {
false,
validatorChannel,
proposersDataManager,
forkChoiceNotifier);
forkChoiceNotifier,
recentChainData,
spec);
}

@Test
Expand Down Expand Up @@ -113,4 +123,70 @@ void blsToExecutionChanges_ReturnsListOfErrors() throws ExecutionException, Inte
assertThat(future.get())
.isEqualTo(List.of(new SubmitDataError(UInt64.ONE, "Computer says no")));
}

@Test
void attestationsMetaDataLookUp_UseFirstAttestationSlot_WhenSlotParamNotProvided() {
final Spec specMock = setUpMockedSpec();
when(attestationPool.getAttestations(any(), any()))
.thenReturn(
List.of(
dataStructureUtil.randomAttestation(5), dataStructureUtil.randomAttestation(10)));
provider.getAttestationsAndMetaData(Optional.empty(), Optional.empty());
verify(specMock).atSlot(eq(UInt64.valueOf(5)));
}

@Test
void attestationsMetaDataLookUp_UseSlot_WhenSlotParamProvided() {
final Spec specMock = setUpMockedSpec();
when(attestationPool.getAttestations(any(), any()))
.thenReturn(
List.of(
dataStructureUtil.randomAttestation(5), dataStructureUtil.randomAttestation(10)));
provider.getAttestationsAndMetaData(Optional.of(UInt64.valueOf(8)), Optional.empty());
verify(specMock).atSlot(eq(UInt64.valueOf(8)));
}

@Test
void attestationsMetaDataLookUp_UseCurrentSlot_WhenSlotParamNotProvided_EmptyList() {
final Spec specMock = setUpMockedSpec();
when(attestationPool.getAttestations(any(), any())).thenReturn(Collections.emptyList());
final UInt64 currentSlot = UInt64.valueOf(8);
when(recentChainData.getCurrentSlot()).thenReturn(Optional.of(currentSlot));
provider.getAttestationsAndMetaData(Optional.empty(), Optional.empty());
verify(specMock).atSlot(eq(currentSlot));
}

@Test
void attestationsMetaDataLookUp_UseSlotZero_WhenSlotParamNotProvided_EmptyList_NoCurrentSlot() {
final Spec specMock = setUpMockedSpec();
when(attestationPool.getAttestations(any(), any())).thenReturn(Collections.emptyList());
when(recentChainData.getCurrentSlot()).thenReturn(Optional.empty());
provider.getAttestationsAndMetaData(Optional.empty(), Optional.empty());
verify(specMock).atSlot(eq(UInt64.ZERO));
}

private Spec setUpMockedSpec() {
final Spec specMock = mock(Spec.class);
final SpecVersion specVersionMock = mock(SpecVersion.class);
final SpecMilestone specMilestone = mock(SpecMilestone.class);
when(specVersionMock.getMilestone()).thenReturn(specMilestone);
when(specMock.atSlot(any())).thenReturn(specVersionMock);
provider =
new NodeDataProvider(
attestationPool,
attesterSlashingPool,
proposerSlashingPool,
voluntaryExitPool,
blsToExecutionChangePool,
syncCommitteeContributionPool,
blockBlobSidecarsTrackersPool,
attestationManager,
false,
validatorChannel,
proposersDataManager,
forkChoiceNotifier,
recentChainData,
specMock);
return specMock;
}
}