From 6f78534a72b7d2a339f8fc43cac856095e943698 Mon Sep 17 00:00:00 2001 From: Enrico Del Fante Date: Mon, 2 Dec 2024 12:55:42 +0100 Subject: [PATCH] Provide `SingleAttestation` datastructure (#8867) --- .../operations/Attestation.java | 21 ++++- .../operations/AttestationSchema.java | 9 ++ .../operations/SingleAttestation.java | 93 +++++++++++++++++++ .../operations/SingleAttestationSchema.java | 84 +++++++++++++++++ .../versions/electra/AttestationElectra.java | 14 --- .../versions/phase0/AttestationPhase0.java | 14 --- .../schemas/SchemaDefinitionsElectra.java | 10 ++ .../registry/SchemaRegistryBuilder.java | 11 ++- .../spec/schemas/registry/SchemaTypes.java | 3 + .../SingleAttestationPropertyTest.java | 37 ++++++++ .../operations/SingleAttestationSupplier.java | 25 +++++ .../teku/spec/util/DataStructureUtil.java | 9 ++ 12 files changed, 299 insertions(+), 31 deletions(-) create mode 100644 ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/operations/SingleAttestation.java create mode 100644 ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/operations/SingleAttestationSchema.java create mode 100644 ethereum/spec/src/property-test/java/tech/pegasys/teku/spec/datastructures/operations/SingleAttestationPropertyTest.java create mode 100644 ethereum/spec/src/testFixtures/java/tech/pegasys/teku/spec/propertytest/suppliers/operations/SingleAttestationSupplier.java diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/operations/Attestation.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/operations/Attestation.java index 57f0ff3f234..06cef12df1d 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/operations/Attestation.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/operations/Attestation.java @@ -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; @@ -34,9 +35,13 @@ public interface Attestation extends SszContainer { @Override AttestationSchema getSchema(); - UInt64 getEarliestSlotForForkChoiceProcessing(final Spec spec); + default UInt64 getEarliestSlotForForkChoiceProcessing(final Spec spec) { + return getData().getEarliestSlotForForkChoice(spec); + } - Collection getDependentBlockRoots(); + default Collection getDependentBlockRoots() { + return Sets.newHashSet(getData().getTarget().getRoot(), getData().getBeaconBlockRoot()); + } AttestationData getData(); @@ -65,4 +70,16 @@ default List getCommitteeIndicesRequired() { } boolean requiresCommitteeBits(); + + default boolean isSingleAttestation() { + return false; + } + + default SingleAttestation toSingleAttestationRequired() { + throw new UnsupportedOperationException("Not a SingleAttestation"); + } + + default UInt64 getValidatorIndexRequired() { + throw new UnsupportedOperationException("Not a SingleAttestation"); + } } diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/operations/AttestationSchema.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/operations/AttestationSchema.java index 3b0b0f880ec..f3b45e20c0f 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/operations/AttestationSchema.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/operations/AttestationSchema.java @@ -41,6 +41,11 @@ default SszBitlist createEmptyAggregationBits() { return bitsSchema.ofBits(Math.toIntExact(bitsSchema.getMaxLength())); } + default SszBitlist createAggregationBitsOf(final int size, final int... indices) { + final SszBitlistSchema bitsSchema = getAggregationBitsSchema(); + return bitsSchema.ofBits(size, indices); + } + default Optional createEmptyCommitteeBits() { return getCommitteeBitsSchema().map(SszBitvectorSchema::ofBits); } @@ -54,6 +59,10 @@ default Optional toVersionElectra() { return Optional.empty(); } + default SingleAttestationSchema toSingleAttestationSchemaRequired() { + throw new UnsupportedOperationException("Not a SingleAttestationSchema"); + } + SszBitlistSchema getAggregationBitsSchema(); Optional> getCommitteeBitsSchema(); diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/operations/SingleAttestation.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/operations/SingleAttestation.java new file mode 100644 index 00000000000..5aaaa1c73ac --- /dev/null +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/operations/SingleAttestation.java @@ -0,0 +1,93 @@ +/* + * 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 + 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(); + } + + public BLSSignature getSignature() { + return getField3().getSignature(); + } + + @Override + public boolean requiresCommitteeBits() { + return false; + } + + @Override + public boolean isSingleAttestation() { + return true; + } + + @Override + public SingleAttestation toSingleAttestationRequired() { + return this; + } + + @Override + public UInt64 getValidatorIndexRequired() { + return getField1().get(); + } +} diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/operations/SingleAttestationSchema.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/operations/SingleAttestationSchema.java new file mode 100644 index 00000000000..0993ec88e7f --- /dev/null +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/operations/SingleAttestationSchema.java @@ -0,0 +1,84 @@ +/* + * 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.infrastructure.unsigned.UInt64; +import tech.pegasys.teku.spec.datastructures.type.SszSignature; +import tech.pegasys.teku.spec.datastructures.type.SszSignatureSchema; + +public class SingleAttestationSchema + extends ContainerSchema4 + implements AttestationSchema { + 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); + } + + public SingleAttestation create( + final UInt64 committeeIndex, + final UInt64 attesterIndex, + final AttestationData data, + final BLSSignature signature) { + return new SingleAttestation(this, committeeIndex, attesterIndex, data, signature); + } + + @Override + public Attestation create( + final SszBitlist aggregationBits, + final AttestationData data, + final BLSSignature signature, + final Supplier committeeBits) { + throw new UnsupportedOperationException("Not supported in SingleAttestation"); + } + + @Override + public SszBitlistSchema getAggregationBitsSchema() { + throw new UnsupportedOperationException("Not supported in SingleAttestation"); + } + + @Override + public Optional> getCommitteeBitsSchema() { + return Optional.empty(); + } + + @Override + public SingleAttestationSchema toSingleAttestationSchemaRequired() { + return this; + } + + @Override + public boolean requiresCommitteeBits() { + return false; + } +} diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/operations/versions/electra/AttestationElectra.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/operations/versions/electra/AttestationElectra.java index 1842c46e897..cebb76f5cb3 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/operations/versions/electra/AttestationElectra.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/operations/versions/electra/AttestationElectra.java @@ -13,18 +13,14 @@ package tech.pegasys.teku.spec.datastructures.operations.versions.electra; -import com.google.common.collect.Sets; -import java.util.Collection; import java.util.List; import java.util.Optional; -import org.apache.tuweni.bytes.Bytes32; 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.Container4; import tech.pegasys.teku.infrastructure.ssz.tree.TreeNode; import tech.pegasys.teku.infrastructure.unsigned.UInt64; -import tech.pegasys.teku.spec.Spec; import tech.pegasys.teku.spec.datastructures.operations.Attestation; import tech.pegasys.teku.spec.datastructures.operations.AttestationData; import tech.pegasys.teku.spec.datastructures.type.SszSignature; @@ -51,16 +47,6 @@ public AttestationElectraSchema getSchema() { return (AttestationElectraSchema) super.getSchema(); } - @Override - public UInt64 getEarliestSlotForForkChoiceProcessing(final Spec spec) { - return getData().getEarliestSlotForForkChoice(spec); - } - - @Override - public Collection getDependentBlockRoots() { - return Sets.newHashSet(getData().getTarget().getRoot(), getData().getBeaconBlockRoot()); - } - @Override public SszBitlist getAggregationBits() { return getField0(); diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/operations/versions/phase0/AttestationPhase0.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/operations/versions/phase0/AttestationPhase0.java index dd343f37361..e7d464a43aa 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/operations/versions/phase0/AttestationPhase0.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/operations/versions/phase0/AttestationPhase0.java @@ -13,15 +13,11 @@ package tech.pegasys.teku.spec.datastructures.operations.versions.phase0; -import com.google.common.collect.Sets; -import java.util.Collection; -import org.apache.tuweni.bytes.Bytes32; import tech.pegasys.teku.bls.BLSSignature; import tech.pegasys.teku.infrastructure.ssz.collections.SszBitlist; import tech.pegasys.teku.infrastructure.ssz.containers.Container3; import tech.pegasys.teku.infrastructure.ssz.tree.TreeNode; import tech.pegasys.teku.infrastructure.unsigned.UInt64; -import tech.pegasys.teku.spec.Spec; import tech.pegasys.teku.spec.datastructures.operations.Attestation; import tech.pegasys.teku.spec.datastructures.operations.AttestationData; import tech.pegasys.teku.spec.datastructures.type.SszSignature; @@ -47,16 +43,6 @@ public AttestationPhase0Schema getSchema() { return (AttestationPhase0Schema) super.getSchema(); } - @Override - public UInt64 getEarliestSlotForForkChoiceProcessing(final Spec spec) { - return getData().getEarliestSlotForForkChoice(spec); - } - - @Override - public Collection getDependentBlockRoots() { - return Sets.newHashSet(getData().getTarget().getRoot(), getData().getBeaconBlockRoot()); - } - @Override public SszBitlist getAggregationBits() { return getField0(); diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/schemas/SchemaDefinitionsElectra.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/schemas/SchemaDefinitionsElectra.java index 46ef4ecd760..2888b00b1ff 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/schemas/SchemaDefinitionsElectra.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/schemas/SchemaDefinitionsElectra.java @@ -20,6 +20,7 @@ import static tech.pegasys.teku.spec.schemas.registry.SchemaTypes.PENDING_CONSOLIDATIONS_SCHEMA; import static tech.pegasys.teku.spec.schemas.registry.SchemaTypes.PENDING_DEPOSITS_SCHEMA; import static tech.pegasys.teku.spec.schemas.registry.SchemaTypes.PENDING_PARTIAL_WITHDRAWALS_SCHEMA; +import static tech.pegasys.teku.spec.schemas.registry.SchemaTypes.SINGLE_ATTESTATION_SCHEMA; import static tech.pegasys.teku.spec.schemas.registry.SchemaTypes.WITHDRAWAL_REQUEST_SCHEMA; import java.util.Optional; @@ -31,6 +32,7 @@ import tech.pegasys.teku.spec.datastructures.execution.versions.electra.DepositRequestSchema; import tech.pegasys.teku.spec.datastructures.execution.versions.electra.ExecutionRequestsSchema; import tech.pegasys.teku.spec.datastructures.execution.versions.electra.WithdrawalRequestSchema; +import tech.pegasys.teku.spec.datastructures.operations.SingleAttestationSchema; import tech.pegasys.teku.spec.datastructures.state.versions.electra.PendingConsolidation; import tech.pegasys.teku.spec.datastructures.state.versions.electra.PendingConsolidation.PendingConsolidationSchema; import tech.pegasys.teku.spec.datastructures.state.versions.electra.PendingDeposit; @@ -53,6 +55,8 @@ public class SchemaDefinitionsElectra extends SchemaDefinitionsDeneb { private final PendingPartialWithdrawalSchema pendingPartialWithdrawalSchema; private final PendingConsolidationSchema pendingConsolidationSchema; + private final SingleAttestationSchema singleAttestationSchema; + public SchemaDefinitionsElectra(final SchemaRegistry schemaRegistry) { super(schemaRegistry); this.executionRequestsSchema = schemaRegistry.get(EXECUTION_REQUESTS_SCHEMA); @@ -60,6 +64,8 @@ public SchemaDefinitionsElectra(final SchemaRegistry schemaRegistry) { this.pendingPartialWithdrawalsSchema = schemaRegistry.get(PENDING_PARTIAL_WITHDRAWALS_SCHEMA); this.pendingConsolidationsSchema = schemaRegistry.get(PENDING_CONSOLIDATIONS_SCHEMA); + this.singleAttestationSchema = schemaRegistry.get(SINGLE_ATTESTATION_SCHEMA); + this.depositRequestSchema = schemaRegistry.get(DEPOSIT_REQUEST_SCHEMA); this.withdrawalRequestSchema = schemaRegistry.get(WITHDRAWAL_REQUEST_SCHEMA); this.consolidationRequestSchema = schemaRegistry.get(CONSOLIDATION_REQUEST_SCHEMA); @@ -126,6 +132,10 @@ public PendingConsolidation.PendingConsolidationSchema getPendingConsolidationSc return pendingPartialWithdrawalsSchema; } + public SingleAttestationSchema getSingleAttestationSchema() { + return singleAttestationSchema; + } + public SszListSchema getPendingConsolidationsSchema() { return pendingConsolidationsSchema; } diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/schemas/registry/SchemaRegistryBuilder.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/schemas/registry/SchemaRegistryBuilder.java index 0f459fb0d4b..16ac090a73a 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/schemas/registry/SchemaRegistryBuilder.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/schemas/registry/SchemaRegistryBuilder.java @@ -58,6 +58,7 @@ import static tech.pegasys.teku.spec.schemas.registry.SchemaTypes.SIGNED_BLOCK_CONTENTS_SCHEMA; import static tech.pegasys.teku.spec.schemas.registry.SchemaTypes.SIGNED_BLS_TO_EXECUTION_CHANGE_SCHEMA; import static tech.pegasys.teku.spec.schemas.registry.SchemaTypes.SIGNED_BUILDER_BID_SCHEMA; +import static tech.pegasys.teku.spec.schemas.registry.SchemaTypes.SINGLE_ATTESTATION_SCHEMA; import static tech.pegasys.teku.spec.schemas.registry.SchemaTypes.SYNCNETS_ENR_FIELD_SCHEMA; import static tech.pegasys.teku.spec.schemas.registry.SchemaTypes.WITHDRAWAL_REQUEST_SCHEMA; import static tech.pegasys.teku.spec.schemas.registry.SchemaTypes.WITHDRAWAL_SCHEMA; @@ -117,6 +118,7 @@ import tech.pegasys.teku.spec.datastructures.operations.IndexedAttestationSchema; import tech.pegasys.teku.spec.datastructures.operations.SignedAggregateAndProof.SignedAggregateAndProofSchema; import tech.pegasys.teku.spec.datastructures.operations.SignedBlsToExecutionChangeSchema; +import tech.pegasys.teku.spec.datastructures.operations.SingleAttestationSchema; import tech.pegasys.teku.spec.datastructures.operations.versions.electra.AttestationElectraSchema; import tech.pegasys.teku.spec.datastructures.operations.versions.phase0.AttestationPhase0Schema; import tech.pegasys.teku.spec.datastructures.state.HistoricalBatch.HistoricalBatchSchema; @@ -188,7 +190,14 @@ public static SchemaRegistryBuilder create() { .addProvider(createDepositRequestSchemaProvider()) .addProvider(createWithdrawalRequestSchemaProvider()) .addProvider(createConsolidationRequestSchemaProvider()) - .addProvider(createExecutionRequestsSchemaProvider()); + .addProvider(createExecutionRequestsSchemaProvider()) + .addProvider(createSingleAttestationSchemaProvider()); + } + + private static SchemaProvider createSingleAttestationSchemaProvider() { + return providerBuilder(SINGLE_ATTESTATION_SCHEMA) + .withCreator(ELECTRA, (registry, specConfig, schemaName) -> new SingleAttestationSchema()) + .build(); } private static SchemaProvider createDepositRequestSchemaProvider() { diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/schemas/registry/SchemaTypes.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/schemas/registry/SchemaTypes.java index 4a8356d373a..1c6b3756672 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/schemas/registry/SchemaTypes.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/schemas/registry/SchemaTypes.java @@ -59,6 +59,7 @@ import tech.pegasys.teku.spec.datastructures.operations.IndexedAttestationSchema; import tech.pegasys.teku.spec.datastructures.operations.SignedAggregateAndProof.SignedAggregateAndProofSchema; import tech.pegasys.teku.spec.datastructures.operations.SignedBlsToExecutionChangeSchema; +import tech.pegasys.teku.spec.datastructures.operations.SingleAttestationSchema; import tech.pegasys.teku.spec.datastructures.state.HistoricalBatch.HistoricalBatchSchema; import tech.pegasys.teku.spec.datastructures.state.beaconstate.BeaconState; import tech.pegasys.teku.spec.datastructures.state.beaconstate.BeaconStateSchema; @@ -169,6 +170,8 @@ public class SchemaTypes { create("WITHDRAWAL_REQUEST_SCHEMA"); public static final SchemaId CONSOLIDATION_REQUEST_SCHEMA = create("CONSOLIDATION_REQUEST_SCHEMA"); + public static final SchemaId SINGLE_ATTESTATION_SCHEMA = + create("SINGLE_ATTESTATION_SCHEMA"); private SchemaTypes() { // Prevent instantiation diff --git a/ethereum/spec/src/property-test/java/tech/pegasys/teku/spec/datastructures/operations/SingleAttestationPropertyTest.java b/ethereum/spec/src/property-test/java/tech/pegasys/teku/spec/datastructures/operations/SingleAttestationPropertyTest.java new file mode 100644 index 00000000000..ea0c7f944ce --- /dev/null +++ b/ethereum/spec/src/property-test/java/tech/pegasys/teku/spec/datastructures/operations/SingleAttestationPropertyTest.java @@ -0,0 +1,37 @@ +/* + * Copyright Consensys Software Inc., 2022 + * + * 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 static tech.pegasys.teku.spec.propertytest.util.PropertyTestHelper.assertDeserializeMutatedThrowsExpected; +import static tech.pegasys.teku.spec.propertytest.util.PropertyTestHelper.assertRoundTrip; + +import com.fasterxml.jackson.core.JsonProcessingException; +import net.jqwik.api.ForAll; +import net.jqwik.api.Property; +import tech.pegasys.teku.spec.propertytest.suppliers.operations.SingleAttestationSupplier; + +public class SingleAttestationPropertyTest { + @Property + void roundTrip(@ForAll(supplier = SingleAttestationSupplier.class) final Attestation attestation) + throws JsonProcessingException { + assertRoundTrip(attestation); + } + + @Property + void deserializeMutated( + @ForAll(supplier = SingleAttestationSupplier.class) final Attestation attestation, + @ForAll final int seed) { + assertDeserializeMutatedThrowsExpected(attestation, seed); + } +} diff --git a/ethereum/spec/src/testFixtures/java/tech/pegasys/teku/spec/propertytest/suppliers/operations/SingleAttestationSupplier.java b/ethereum/spec/src/testFixtures/java/tech/pegasys/teku/spec/propertytest/suppliers/operations/SingleAttestationSupplier.java new file mode 100644 index 00000000000..de6215d748e --- /dev/null +++ b/ethereum/spec/src/testFixtures/java/tech/pegasys/teku/spec/propertytest/suppliers/operations/SingleAttestationSupplier.java @@ -0,0 +1,25 @@ +/* + * Copyright Consensys Software Inc., 2022 + * + * 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.propertytest.suppliers.operations; + +import tech.pegasys.teku.spec.SpecMilestone; +import tech.pegasys.teku.spec.datastructures.operations.SingleAttestation; +import tech.pegasys.teku.spec.propertytest.suppliers.DataStructureUtilSupplier; +import tech.pegasys.teku.spec.util.DataStructureUtil; + +public class SingleAttestationSupplier extends DataStructureUtilSupplier { + public SingleAttestationSupplier() { + super(DataStructureUtil::randomSingleAttestation, SpecMilestone.ELECTRA); + } +} diff --git a/ethereum/spec/src/testFixtures/java/tech/pegasys/teku/spec/util/DataStructureUtil.java b/ethereum/spec/src/testFixtures/java/tech/pegasys/teku/spec/util/DataStructureUtil.java index c89c94d15aa..b1f39032a9a 100644 --- a/ethereum/spec/src/testFixtures/java/tech/pegasys/teku/spec/util/DataStructureUtil.java +++ b/ethereum/spec/src/testFixtures/java/tech/pegasys/teku/spec/util/DataStructureUtil.java @@ -160,6 +160,7 @@ import tech.pegasys.teku.spec.datastructures.operations.SignedAggregateAndProof; import tech.pegasys.teku.spec.datastructures.operations.SignedBlsToExecutionChange; import tech.pegasys.teku.spec.datastructures.operations.SignedVoluntaryExit; +import tech.pegasys.teku.spec.datastructures.operations.SingleAttestation; import tech.pegasys.teku.spec.datastructures.operations.VoluntaryExit; import tech.pegasys.teku.spec.datastructures.operations.versions.altair.ContributionAndProof; import tech.pegasys.teku.spec.datastructures.operations.versions.altair.SignedContributionAndProof; @@ -819,6 +820,14 @@ public Attestation randomAttestation() { this::randomCommitteeBitvector); } + public SingleAttestation randomSingleAttestation() { + return spec.getGenesisSchemaDefinitions() + .toVersionElectra() + .orElseThrow() + .getSingleAttestationSchema() + .create(randomUInt64(), randomUInt64(), randomAttestationData(), randomSignature()); + } + public Attestation randomAttestation(final long slot) { return randomAttestation(UInt64.valueOf(slot)); }