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

[Spike] Electra attetations renewal #8644

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
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 @@ -44,7 +44,7 @@
import tech.pegasys.teku.spec.TestSpecContext;
import tech.pegasys.teku.spec.TestSpecInvocationContextProvider;
import tech.pegasys.teku.spec.datastructures.operations.SignedAggregateAndProof;
import tech.pegasys.teku.spec.datastructures.operations.versions.electra.AttestationElectra;
import tech.pegasys.teku.spec.datastructures.operations.versions.electra.OnchainAttestation;
import tech.pegasys.teku.spec.datastructures.operations.versions.phase0.AttestationPhase0;
import tech.pegasys.teku.spec.schemas.SchemaDefinitionCache;
import tech.pegasys.teku.spec.util.DataStructureUtil;
Expand Down Expand Up @@ -111,7 +111,7 @@ void shouldReadRequestBody() throws IOException {
((SignedAggregateAndProof) ((List<?>) requestBody).get(0))
.getMessage()
.getAggregate())
.isInstanceOf(AttestationElectra.class);
.isInstanceOf(OnchainAttestation.class);
} else {
assertThat(
((SignedAggregateAndProof) ((List<?>) requestBody).get(0))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,18 @@
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Supplier;
import org.apache.tuweni.bytes.Bytes32;
import tech.pegasys.teku.infrastructure.ssz.collections.SszBitlist;
import tech.pegasys.teku.infrastructure.unsigned.UInt64;
import tech.pegasys.teku.spec.Spec;
import tech.pegasys.teku.spec.constants.Domain;
import tech.pegasys.teku.spec.datastructures.operations.Attestation;
import tech.pegasys.teku.spec.datastructures.operations.AttestationData;
import tech.pegasys.teku.spec.datastructures.operations.IndexedAttestation;
import tech.pegasys.teku.spec.datastructures.operations.SignedAggregateAndProof;
import tech.pegasys.teku.spec.datastructures.operations.versions.electra.OnchainAttestation;
import tech.pegasys.teku.spec.datastructures.operations.versions.electra.OnchainAttestationSchema;
import tech.pegasys.teku.spec.datastructures.state.beaconstate.BeaconState;
import tech.pegasys.teku.spec.schemas.SchemaDefinitionsElectra;

public class ValidatableAttestation {
private final Spec spec;
Expand All @@ -49,6 +53,69 @@ public class ValidatableAttestation {
private volatile Optional<Bytes32> committeeShufflingSeed = Optional.empty();
private volatile Optional<Int2IntMap> committeesSize = Optional.empty();

private volatile Optional<SszBitlist> singleAttestationAggregationBits = Optional.empty();

public ValidatableAttestation convertToOnchainAttestationIfRequired() {

if (attestation.isOnchainAttestation()) {
return this;
}

final Optional<OnchainAttestationSchema> attestationElectraSchema =
spec.atSlot(attestation.getData().getSlot())
.getSchemaDefinitions()
.toVersionElectra()
.map(SchemaDefinitionsElectra::getOnchainAttestationAttestationSchema);

if (attestation.isSingleAttestation()) {

final OnchainAttestation convertedAttestation =
attestationElectraSchema
.orElseThrow()
.create(
singleAttestationAggregationBits.orElseThrow(),
attestation.getData(),
attestation.getAggregateSignature(),
attestationElectraSchema
.orElseThrow()
.getCommitteeBitsSchema()
.orElseThrow()
.ofBits(attestation.getFirstCommitteeIndex().intValue()));

return from(spec, convertedAttestation);
}

if (attestationElectraSchema.isPresent()) {
// this is a good old Attestation (single committee aggregation)
final OnchainAttestation convertedAttestation =
attestationElectraSchema
.get()
.create(
attestation.getAggregationBits(),
attestation.getData(),
attestation.getAggregateSignature(),
attestationElectraSchema
.get()
.getCommitteeBitsSchema()
.orElseThrow()
.ofBits(attestation.getFirstCommitteeIndex().intValue()));

return from(spec, convertedAttestation);
}

return this;
}

public ValidatableAttestation convertToAttestationIfRequired() {
if (!attestation.isOnchainAttestation()) {
// we are at phase0
return this;
}

// TODO convert onchain attestation to Attestation (committee aggregation)
throw new UnsupportedOperationException("not yet implemented");
}

public static ValidatableAttestation from(final Spec spec, final Attestation attestation) {
return new ValidatableAttestation(
spec, attestation, Optional.empty(), OptionalInt.empty(), false);
Expand Down Expand Up @@ -204,6 +271,15 @@ private void saveCommitteesSize(final BeaconState state) {
this.committeesSize = Optional.of(committeesSize);
}

public Optional<SszBitlist> getSingleAttestationAggregationBits() {
return singleAttestationAggregationBits;
}

public void setSingleAttestationAggregationBits(
final SszBitlist singleAttestationAggregationBits) {
this.singleAttestationAggregationBits = Optional.of(singleAttestationAggregationBits);
}

public boolean isGossiped() {
return gossiped.get();
}
Expand Down Expand Up @@ -273,6 +349,7 @@ public String toString() {
.add("committeeShufflingSeed", committeeShufflingSeed)
.add("committeesSize", committeesSize)
.add("receivedSubnetId", receivedSubnetId)
.add("singleAttestationAggregationBits", singleAttestationAggregationBits)
.toString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
import tech.pegasys.teku.spec.datastructures.operations.SignedBlsToExecutionChange;
import tech.pegasys.teku.spec.datastructures.operations.SignedBlsToExecutionChangeSchema;
import tech.pegasys.teku.spec.datastructures.operations.SignedVoluntaryExit;
import tech.pegasys.teku.spec.datastructures.operations.versions.electra.AttestationElectraSchema;
import tech.pegasys.teku.spec.datastructures.operations.versions.electra.OnchainAttestationSchema;
import tech.pegasys.teku.spec.datastructures.type.SszKZGCommitment;
import tech.pegasys.teku.spec.datastructures.type.SszSignature;
import tech.pegasys.teku.spec.datastructures.type.SszSignatureSchema;
Expand Down Expand Up @@ -118,7 +118,7 @@ public static BeaconBlockBodySchemaElectraImpl create(
namedSchema(
BlockBodyFields.ATTESTATIONS,
SszListSchema.create(
new AttestationElectraSchema(
new OnchainAttestationSchema(
maxValidatorsPerAttestation, specConfig.getMaxCommitteesPerSlot())
.castTypeToAttestationSchema(),
specConfig.getMaxAttestationsElectra())),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
import tech.pegasys.teku.spec.datastructures.operations.SignedBlsToExecutionChange;
import tech.pegasys.teku.spec.datastructures.operations.SignedBlsToExecutionChangeSchema;
import tech.pegasys.teku.spec.datastructures.operations.SignedVoluntaryExit;
import tech.pegasys.teku.spec.datastructures.operations.versions.electra.AttestationElectraSchema;
import tech.pegasys.teku.spec.datastructures.operations.versions.electra.OnchainAttestationSchema;
import tech.pegasys.teku.spec.datastructures.type.SszKZGCommitment;
import tech.pegasys.teku.spec.datastructures.type.SszSignature;
import tech.pegasys.teku.spec.datastructures.type.SszSignatureSchema;
Expand Down Expand Up @@ -117,7 +117,7 @@ public static BlindedBeaconBlockBodySchemaElectraImpl create(
namedSchema(
BlockBodyFields.ATTESTATIONS,
SszListSchema.create(
new AttestationElectraSchema(
new OnchainAttestationSchema(
maxValidatorsPerAttestation, specConfig.getMaxCommitteesPerSlot())
.castTypeToAttestationSchema(),
specConfig.getMaxAttestationsElectra())),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

package tech.pegasys.teku.spec.datastructures.operations;

import com.google.common.collect.Sets;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
Expand All @@ -34,9 +35,13 @@ public interface Attestation extends SszContainer {
@Override
AttestationSchema<? extends Attestation> getSchema();

UInt64 getEarliestSlotForForkChoiceProcessing(final Spec spec);
default UInt64 getEarliestSlotForForkChoiceProcessing(final Spec spec) {
return getData().getEarliestSlotForForkChoice(spec);
}

Collection<Bytes32> getDependentBlockRoots();
default Collection<Bytes32> getDependentBlockRoots() {
return Sets.newHashSet(getData().getTarget().getRoot(), getData().getBeaconBlockRoot());
}

AttestationData getData();

Expand Down Expand Up @@ -65,4 +70,16 @@ default List<UInt64> getCommitteeIndicesRequired() {
}

boolean requiresCommitteeBits();

default boolean isSingleAttestation() {
return false;
}

default boolean isOnchainAttestation() {
return false;
}

default Optional<UInt64> getValidatorIndex() {
return Optional.empty();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
import tech.pegasys.teku.infrastructure.ssz.schema.SszContainerSchema;
import tech.pegasys.teku.infrastructure.ssz.schema.collections.SszBitlistSchema;
import tech.pegasys.teku.infrastructure.ssz.schema.collections.SszBitvectorSchema;
import tech.pegasys.teku.spec.datastructures.operations.versions.electra.AttestationElectraSchema;
import tech.pegasys.teku.spec.datastructures.operations.versions.electra.OnchainAttestationSchema;

public interface AttestationSchema<T extends Attestation> extends SszContainerSchema<T> {

Expand All @@ -41,6 +41,11 @@ default SszBitlist createEmptyAggregationBits() {
return bitsSchema.ofBits(Math.toIntExact(bitsSchema.getMaxLength()));
}

default SszBitlist createAggregationBitsOf(final int... indices) {
final SszBitlistSchema<?> bitsSchema = getAggregationBitsSchema();
return bitsSchema.ofBits(Math.toIntExact(bitsSchema.getMaxLength()), indices);
}

default Optional<SszBitvector> createEmptyCommitteeBits() {
return getCommitteeBitsSchema().map(SszBitvectorSchema::ofBits);
}
Expand All @@ -50,7 +55,7 @@ default AttestationSchema<Attestation> castTypeToAttestationSchema() {
return (AttestationSchema<Attestation>) this;
}

default Optional<AttestationElectraSchema> toVersionElectra() {
default Optional<OnchainAttestationSchema> toVersionElectra() {
return Optional.empty();
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
* Copyright Consensys Software Inc., 2024
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/

package tech.pegasys.teku.spec.datastructures.operations;

import tech.pegasys.teku.bls.BLSSignature;
import tech.pegasys.teku.infrastructure.ssz.collections.SszBitlist;
import tech.pegasys.teku.infrastructure.ssz.containers.Container4;
import tech.pegasys.teku.infrastructure.ssz.primitive.SszUInt64;
import tech.pegasys.teku.infrastructure.ssz.tree.TreeNode;
import tech.pegasys.teku.infrastructure.unsigned.UInt64;
import tech.pegasys.teku.spec.datastructures.type.SszSignature;

public class SingleAttestation
extends Container4<SingleAttestation, SszUInt64, SszUInt64, AttestationData, SszSignature>
implements Attestation {
public SingleAttestation(final SingleAttestationSchema type, final TreeNode backingNode) {
super(type, backingNode);
}

public SingleAttestation(
final SingleAttestationSchema schema,
final UInt64 committeeIndex,
final UInt64 validatorIndex,
final AttestationData data,
final BLSSignature signature) {
super(
schema,
SszUInt64.of(committeeIndex),
SszUInt64.of(validatorIndex),
data,
new SszSignature(signature));
}

@Override
public SingleAttestationSchema getSchema() {
return (SingleAttestationSchema) super.getSchema();
}

@Override
public AttestationData getData() {
return getField2();
}

@Override
public SszBitlist getAggregationBits() {
throw new UnsupportedOperationException("Not supported in SingleAttestation");
}

@Override
public UInt64 getFirstCommitteeIndex() {
return getField0().get();
}

@Override
public BLSSignature getAggregateSignature() {
return getField3().getSignature();
}

@Override
public boolean requiresCommitteeBits() {
// we signal that to process this attestation committeeBits handling is required
return true;
}

@Override
public boolean isSingleAttestation() {
return true;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
* Copyright Consensys Software Inc., 2024
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/

package tech.pegasys.teku.spec.datastructures.operations;

import java.util.Optional;
import java.util.function.Supplier;
import tech.pegasys.teku.bls.BLSSignature;
import tech.pegasys.teku.infrastructure.ssz.collections.SszBitlist;
import tech.pegasys.teku.infrastructure.ssz.collections.SszBitvector;
import tech.pegasys.teku.infrastructure.ssz.containers.ContainerSchema4;
import tech.pegasys.teku.infrastructure.ssz.primitive.SszUInt64;
import tech.pegasys.teku.infrastructure.ssz.schema.SszPrimitiveSchemas;
import tech.pegasys.teku.infrastructure.ssz.schema.collections.SszBitlistSchema;
import tech.pegasys.teku.infrastructure.ssz.schema.collections.SszBitvectorSchema;
import tech.pegasys.teku.infrastructure.ssz.tree.TreeNode;
import tech.pegasys.teku.spec.datastructures.type.SszSignature;
import tech.pegasys.teku.spec.datastructures.type.SszSignatureSchema;

public class SingleAttestationSchema
extends ContainerSchema4<SingleAttestation, SszUInt64, SszUInt64, AttestationData, SszSignature>
implements AttestationSchema<SingleAttestation> {
public SingleAttestationSchema() {
super(
"SingleAttestation",
namedSchema("committee_index", SszPrimitiveSchemas.UINT64_SCHEMA),
namedSchema("attester_index", SszPrimitiveSchemas.UINT64_SCHEMA),
namedSchema("data", AttestationData.SSZ_SCHEMA),
namedSchema("signature", SszSignatureSchema.INSTANCE));
}

@Override
public SingleAttestation createFromBackingNode(final TreeNode node) {
return new SingleAttestation(this, node);
}

@Override
public Attestation create(
final SszBitlist aggregationBits,
final AttestationData data,
final BLSSignature signature,
final Supplier<SszBitvector> committeeBits) {
throw new UnsupportedOperationException("Not supported in SingleAttestation");
}

@Override
public SszBitlistSchema<?> getAggregationBitsSchema() {
throw new UnsupportedOperationException("Not supported in SingleAttestation");
}

@Override
public Optional<SszBitvectorSchema<?>> getCommitteeBitsSchema() {
return Optional.empty();
}

@Override
public boolean requiresCommitteeBits() {
return false;
}
}
Loading
Loading