use of tech.pegasys.teku.spec.datastructures.util.SyncSubcommitteeAssignments in project teku by ConsenSys.
the class SyncCommitteeUtil method getSyncSubcommittees.
public Map<UInt64, SyncSubcommitteeAssignments> getSyncSubcommittees(final BeaconState state, final UInt64 epoch) {
final UInt64 syncCommitteePeriod = computeSyncCommitteePeriod(epoch);
final UInt64 currentEpoch = beaconStateAccessors.getCurrentEpoch(state);
final UInt64 currentSyncCommitteePeriod = computeSyncCommitteePeriod(currentEpoch);
checkArgument(isStateUsableForCommitteeCalculationAtEpoch(state, epoch), "State must be in the same or previous sync committee period. Cannot calculate epoch %s from state at slot %s", epoch, state.getSlot());
final BeaconStateAltair altairState = BeaconStateAltair.required(state);
return BeaconStateCache.getTransitionCaches(altairState).getSyncCommitteeCache().get(syncCommitteePeriod, period -> {
final SyncCommittee syncCommittee;
if (syncCommitteePeriod.equals(currentSyncCommitteePeriod)) {
syncCommittee = altairState.getCurrentSyncCommittee();
} else {
syncCommittee = altairState.getNextSyncCommittee();
}
final int subcommitteeSize = getSubcommitteeSize();
final SszVector<SszPublicKey> pubkeys = syncCommittee.getPubkeys();
final Map<UInt64, SyncSubcommitteeAssignments.Builder> subcommitteeAssignments = new HashMap<>();
for (int index = 0; index < pubkeys.size(); index++) {
final BLSPublicKey pubkey = pubkeys.get(index).getBLSPublicKey();
final UInt64 validatorIndex = UInt64.valueOf(validatorsUtil.getValidatorIndex(altairState, pubkey).orElseThrow(() -> new IllegalStateException("Unknown validator assigned to sync committee: " + pubkey)));
final int subcommitteeIndex = index / subcommitteeSize;
final int subcommitteeParticipationIndex = index - (subcommitteeIndex * subcommitteeSize);
// Note we're using plain HashMap here instead of a concurrent alternative as they
// are created once here and then never modified so safe to access from multiple
// threads.
subcommitteeAssignments.computeIfAbsent(validatorIndex, __ -> SyncSubcommitteeAssignments.builder()).addAssignment(subcommitteeIndex, subcommitteeParticipationIndex).addCommitteeIndex(index);
}
return subcommitteeAssignments.entrySet().stream().collect(toUnmodifiableMap(Map.Entry::getKey, entry -> entry.getValue().build()));
});
}
use of tech.pegasys.teku.spec.datastructures.util.SyncSubcommitteeAssignments in project teku by ConsenSys.
the class SyncCommitteeUtilTest method getSyncSubCommittees_shouldSupportValidatorsInTheSameSubCommitteeMultipleTimes.
@Test
void getSyncSubCommittees_shouldSupportValidatorsInTheSameSubCommitteeMultipleTimes() {
final List<SszPublicKey> syncCommittee = new ArrayList<>(validatorPublicKeys);
final SszPublicKey validator0 = syncCommittee.get(0);
syncCommittee.set(2, validator0);
syncCommittee.set(3, validator0);
final BeaconState state = createStateWithCurrentSyncCommittee(syncCommittee);
final Map<UInt64, SyncSubcommitteeAssignments> syncSubcommittees = syncCommitteeUtil.getSyncSubcommittees(state, spec.getCurrentEpoch(state));
final SyncSubcommitteeAssignments assignments = syncSubcommittees.get(UInt64.ZERO);
assertThat(assignments.getAssignedSubcommittees()).containsExactly(0);
assertThat(assignments.getParticipationBitIndices(0)).containsExactlyInAnyOrder(0, 2, 3);
}
use of tech.pegasys.teku.spec.datastructures.util.SyncSubcommitteeAssignments in project teku by ConsenSys.
the class SignedContributionAndProofTestBuilder method aggregatorNotInSyncSubcommittee.
public SignedContributionAndProofTestBuilder aggregatorNotInSyncSubcommittee() {
final Map<UInt64, SyncSubcommitteeAssignments> subcommittees = syncCommitteeUtil.getSyncSubcommittees(state, spec.computeEpochAtSlot(slot));
for (int validatorIndex = 0; validatorIndex < 10_000; validatorIndex++) {
final SyncSubcommitteeAssignments assignments = subcommittees.get(UInt64.valueOf(validatorIndex));
if (assignments == null || !assignments.getAssignedSubcommittees().contains(subcommitteeIndex)) {
this.aggregatorIndex = UInt64.valueOf(validatorIndex);
this.aggregatorSigner = signerProvider.apply(validatorIndex);
return this;
} else {
for (int candidateSubcommitteeIndex = 0; candidateSubcommitteeIndex < NetworkConstants.SYNC_COMMITTEE_SUBNET_COUNT; candidateSubcommitteeIndex++) {
if (!assignments.getAssignedSubcommittees().contains(candidateSubcommitteeIndex)) {
this.aggregatorIndex = UInt64.valueOf(validatorIndex);
this.aggregatorSigner = signerProvider.apply(validatorIndex);
this.subcommitteeIndex = candidateSubcommitteeIndex;
return this;
}
}
}
}
throw new IllegalStateException("Could not find validator not in the sync committee");
}
use of tech.pegasys.teku.spec.datastructures.util.SyncSubcommitteeAssignments in project teku by ConsenSys.
the class SyncCommitteeMessageValidator method validateWithState.
private SafeFuture<InternalValidationResult> validateWithState(final ValidateableSyncCommitteeMessage validateableMessage, final SyncCommitteeMessage message, final SyncCommitteeUtil syncCommitteeUtil, final BeaconStateAltair state, final Optional<UniquenessKey> maybeUniquenessKey) {
final UInt64 messageEpoch = spec.computeEpochAtSlot(message.getSlot());
// Always calculate the applicable subcommittees to ensure they are cached and can be used to
// send the gossip.
final SyncSubcommitteeAssignments assignedSubcommittees = validateableMessage.calculateAssignments(spec, state);
// state.current_sync_committee.pubkeys.
if (assignedSubcommittees.isEmpty()) {
return SafeFuture.completedFuture(reject("Rejecting sync committee message because validator is not in the sync committee"));
}
// For messages received via gossip, it has to be unique based on the subnet it was on
// For locally produced messages we should accept it if it hasn't been seen on any subnet
final List<UniquenessKey> uniquenessKeys = maybeUniquenessKey.map(List::of).orElseGet(() -> assignedSubcommittees.getAssignedSubcommittees().stream().map(subnetId -> getUniquenessKey(message, subnetId)).collect(toList()));
// validator referenced by sync_committee_message.validator_index.
if (seenIndices.containsAll(uniquenessKeys)) {
return SafeFuture.completedFuture(IGNORE);
}
// compute_subnets_for_sync_committee(state, sync_committee_message.validator_index).
if (validateableMessage.getReceivedSubnetId().isPresent() && !assignedSubcommittees.getAssignedSubcommittees().contains(validateableMessage.getReceivedSubnetId().getAsInt())) {
return SafeFuture.completedFuture(reject("Rejecting sync committee message because subnet id is incorrect"));
}
final Optional<BLSPublicKey> maybeValidatorPublicKey = spec.getValidatorPubKey(state, message.getValidatorIndex());
if (maybeValidatorPublicKey.isEmpty()) {
return SafeFuture.completedFuture(reject("Rejecting sync committee message because the validator index is unknown"));
}
// [REJECT] The message is valid for the message beacon_block_root for the validator
// referenced by validator_index.
final Bytes32 signingRoot = syncCommitteeUtil.getSyncCommitteeMessageSigningRoot(message.getBeaconBlockRoot(), messageEpoch, state.getForkInfo());
return signatureVerifier.verify(maybeValidatorPublicKey.get(), signingRoot, message.getSignature()).thenApply(signatureValid -> {
if (!signatureValid) {
return reject("Rejecting sync committee message because the signature is invalid");
}
if (!seenIndices.addAll(uniquenessKeys)) {
return ignore("Ignoring sync committee message as a duplicate was processed during validation");
}
return ACCEPT;
});
}
use of tech.pegasys.teku.spec.datastructures.util.SyncSubcommitteeAssignments in project teku by ConsenSys.
the class ChainBuilder method createValidSignedContributionAndProofBuilder.
public SignedContributionAndProofTestBuilder createValidSignedContributionAndProofBuilder(final UInt64 slot, final Bytes32 beaconBlockRoot) {
final SyncCommitteeUtil syncCommitteeUtil = spec.getSyncCommitteeUtilRequired(slot);
final SignedBlockAndState latestBlockAndState = getLatestBlockAndState();
final UInt64 epoch = syncCommitteeUtil.getEpochForDutiesAtSlot(slot);
final Map<UInt64, SyncSubcommitteeAssignments> subcommitteeAssignments = syncCommitteeUtil.getSyncSubcommittees(latestBlockAndState.getState(), epoch);
for (Map.Entry<UInt64, SyncSubcommitteeAssignments> entry : subcommitteeAssignments.entrySet()) {
final UInt64 validatorIndex = entry.getKey();
final Signer signer = getSigner(validatorIndex.intValue());
final SyncSubcommitteeAssignments assignments = entry.getValue();
for (int subcommitteeIndex : assignments.getAssignedSubcommittees()) {
final SyncAggregatorSelectionData syncAggregatorSelectionData = syncCommitteeUtil.createSyncAggregatorSelectionData(slot, UInt64.valueOf(subcommitteeIndex));
final BLSSignature proof = signer.signSyncCommitteeSelectionProof(syncAggregatorSelectionData, latestBlockAndState.getState().getForkInfo()).join();
if (syncCommitteeUtil.isSyncCommitteeAggregator(proof)) {
return new SignedContributionAndProofTestBuilder().signerProvider(this::getSigner).syncCommitteeUtil(syncCommitteeUtil).spec(spec).state(latestBlockAndState.getState()).subcommitteeIndex(subcommitteeIndex).slot(slot).selectionProof(proof).beaconBlockRoot(beaconBlockRoot).aggregator(validatorIndex, signer);
}
}
}
throw new IllegalStateException("No valid sync subcommittee aggregators found");
}
Aggregations