Skip to content

Commit

Permalink
attestation production logic (Consensys#8269)
Browse files Browse the repository at this point in the history
  • Loading branch information
tbenr authored Apr 30, 2024
1 parent 404bb71 commit 8ddce8b
Show file tree
Hide file tree
Showing 5 changed files with 163 additions and 92 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@
import tech.pegasys.teku.infrastructure.ssz.collections.SszBitlist;
import tech.pegasys.teku.infrastructure.unsigned.UInt64;
import tech.pegasys.teku.spec.config.SpecConfig;
import tech.pegasys.teku.spec.datastructures.blocks.BeaconBlockSummary;
import tech.pegasys.teku.spec.datastructures.operations.Attestation;
import tech.pegasys.teku.spec.datastructures.operations.AttestationData;
import tech.pegasys.teku.spec.datastructures.state.beaconstate.BeaconState;
import tech.pegasys.teku.spec.logic.common.helpers.BeaconStateAccessors;
import tech.pegasys.teku.spec.logic.common.helpers.MiscHelpers;
Expand Down Expand Up @@ -76,4 +78,19 @@ public IntStream streamCommitteeAttesters(
.filter(aggregationBits::isSet)
.map(attesterIndex -> committee.getInt(attesterIndex - committeeOffset));
}

/**
* In electra, attestationData must have committee index set to 0
*
* @see
* <a>https://github.com/ethereum/consensus-specs/blob/dev/specs/electra/validator.md#construct-attestation</a>
*/
@Override
public AttestationData getGenericAttestationData(
final UInt64 slot,
final BeaconState state,
final BeaconBlockSummary block,
final UInt64 committeeIndex) {
return super.getGenericAttestationData(slot, state, block, UInt64.ZERO);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import java.util.List;
import java.util.Optional;
import java.util.function.Supplier;
import java.util.stream.Stream;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
Expand All @@ -28,6 +29,7 @@
import tech.pegasys.teku.infrastructure.metrics.Validator.DutyType;
import tech.pegasys.teku.infrastructure.metrics.Validator.ValidatorDutyMetricsSteps;
import tech.pegasys.teku.infrastructure.ssz.collections.SszBitlist;
import tech.pegasys.teku.infrastructure.ssz.collections.SszBitvector;
import tech.pegasys.teku.infrastructure.unsigned.UInt64;
import tech.pegasys.teku.spec.Spec;
import tech.pegasys.teku.spec.datastructures.operations.Attestation;
Expand Down Expand Up @@ -92,7 +94,8 @@ public SafeFuture<Optional<AttestationData>> addValidator(
final ScheduledCommittee committee =
validatorsByCommitteeIndex.computeIfAbsent(
attestationCommitteeIndex, key -> new ScheduledCommittee());
committee.addValidator(validator, committeePosition, validatorIndex, committeeSize);
committee.addValidator(
validator, attestationCommitteeIndex, committeePosition, validatorIndex, committeeSize);
return committee.getAttestationDataFuture();
}

Expand Down Expand Up @@ -145,7 +148,7 @@ private SafeFuture<ProductionResult<Attestation>> signAttestationForValidatorInC
final UInt64 slot,
final ForkInfo forkInfo,
final int committeeIndex,
final ValidatorWithCommitteePositionAndIndex validator,
final ValidatorWithAttestationDutyInfo validator,
final SafeFuture<Optional<AttestationData>> attestationDataFuture) {
return attestationDataFuture
.thenCompose(
Expand All @@ -164,14 +167,14 @@ private SafeFuture<ProductionResult<Attestation>> signAttestationForValidatorInC
() ->
SafeFuture.completedFuture(
ProductionResult.failure(
validator.getPublicKey(),
validator.publicKey(),
new IllegalStateException(
"Unable to produce attestation for slot "
+ slot
+ " with committee "
+ committeeIndex
+ " because chain data was unavailable")))))
.exceptionally(error -> ProductionResult.failure(validator.getPublicKey(), error));
.exceptionally(error -> ProductionResult.failure(validator.publicKey(), error));
}

private static void validateAttestationData(
Expand All @@ -186,27 +189,37 @@ private static void validateAttestationData(
private SafeFuture<ProductionResult<Attestation>> signAttestationForValidator(
final ForkInfo forkInfo,
final AttestationData attestationData,
final ValidatorWithCommitteePositionAndIndex validator) {
final ValidatorWithAttestationDutyInfo validator) {
return validator
.getSigner()
.signer()
.signAttestationData(attestationData, forkInfo)
.thenApply(signature -> createSignedAttestation(attestationData, validator, signature))
.thenApply(
attestation ->
ProductionResult.success(
validator.getPublicKey(), attestationData.getBeaconBlockRoot(), attestation));
validator.publicKey(), attestationData.getBeaconBlockRoot(), attestation));
}

private Attestation createSignedAttestation(
final AttestationData attestationData,
final ValidatorWithCommitteePositionAndIndex validator,
final ValidatorWithAttestationDutyInfo validator,
final BLSSignature signature) {
final AttestationSchema<?> attestationSchema =
spec.atSlot(attestationData.getSlot()).getSchemaDefinitions().getAttestationSchema();
final SszBitlist aggregationBits =
attestationSchema
.getAggregationBitsSchema()
.ofBits(validator.getCommitteeSize(), validator.getCommitteePosition());
return attestationSchema.create(aggregationBits, attestationData, signature);
.ofBits(validator.committeeSize(), validator.committeePosition());

final Supplier<SszBitvector> committeeBitsSupplier =
attestationSchema
.getCommitteeBitsSchema()
.map(
committeeBitsSchema ->
(Supplier<SszBitvector>)
() -> committeeBitsSchema.ofBits(validator.committeeIndex()))
.orElse(() -> null);
return attestationSchema.create(
aggregationBits, attestationData, committeeBitsSupplier, signature);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,32 +27,31 @@

class ScheduledCommittee {

private final List<ValidatorWithCommitteePositionAndIndex> validators = new ArrayList<>();
private final List<ValidatorWithAttestationDutyInfo> validators = new ArrayList<>();
private final SafeFuture<Optional<AttestationData>> attestationDataFuture = new SafeFuture<>();

public synchronized void addValidator(
final Validator validator,
final int committeeIndex,
final int committeePosition,
final int validatorIndex,
final int committeeSize) {
validators.add(
new ValidatorWithCommitteePositionAndIndex(
validator, committeePosition, validatorIndex, committeeSize));
new ValidatorWithAttestationDutyInfo(
validator, committeeIndex, committeePosition, validatorIndex, committeeSize));
}

public synchronized <T> List<SafeFuture<T>> forEach(
final Function<ValidatorWithCommitteePositionAndIndex, SafeFuture<T>> action) {
final Function<ValidatorWithAttestationDutyInfo, SafeFuture<T>> action) {
return validators.stream().map(action).toList();
}

public List<ValidatorWithCommitteePositionAndIndex> getValidators() {
public List<ValidatorWithAttestationDutyInfo> getValidators() {
return validators;
}

public Set<BLSPublicKey> getValidatorPublicKeys() {
return validators.stream()
.map(ValidatorWithCommitteePositionAndIndex::getPublicKey)
.collect(toSet());
return validators.stream().map(ValidatorWithAttestationDutyInfo::publicKey).collect(toSet());
}

public SafeFuture<Optional<AttestationData>> getAttestationDataFuture() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,47 +17,24 @@
import tech.pegasys.teku.spec.signatures.Signer;
import tech.pegasys.teku.validator.client.Validator;

class ValidatorWithCommitteePositionAndIndex {

private final Validator validator;
private final int committeePosition;
private final int validatorIndex;
private final int committeeSize;

ValidatorWithCommitteePositionAndIndex(
final Validator validator,
final int committeePosition,
final int validatorIndex,
final int committeeSize) {
this.validator = validator;
this.committeePosition = committeePosition;
this.validatorIndex = validatorIndex;
this.committeeSize = committeeSize;
}

public Signer getSigner() {
record ValidatorWithAttestationDutyInfo(
Validator validator,
int committeeIndex,
int committeePosition,
int validatorIndex,
int committeeSize) {

public Signer signer() {
return validator.getSigner();
}

public int getCommitteePosition() {
return committeePosition;
}

public int getValidatorIndex() {
return validatorIndex;
}

public int getCommitteeSize() {
return committeeSize;
}

public BLSPublicKey getPublicKey() {
public BLSPublicKey publicKey() {
return validator.getPublicKey();
}

@Override
public String toString() {
return "ValidatorWithCommitteePositionAndIndex{"
return "ValidatorWithAttestationDutyInfo{"
+ "validator="
+ validator
+ ", committeePosition="
Expand Down
Loading

0 comments on commit 8ddce8b

Please sign in to comment.