diff --git a/data/beaconrestapi/src/integration-test/java/tech/pegasys/teku/beaconrestapi/v1/node/GetIdentityIntegrationTest.java b/data/beaconrestapi/src/integration-test/java/tech/pegasys/teku/beaconrestapi/v1/node/GetIdentityIntegrationTest.java index 32b34ba217c..4d0f2e83fc8 100644 --- a/data/beaconrestapi/src/integration-test/java/tech/pegasys/teku/beaconrestapi/v1/node/GetIdentityIntegrationTest.java +++ b/data/beaconrestapi/src/integration-test/java/tech/pegasys/teku/beaconrestapi/v1/node/GetIdentityIntegrationTest.java @@ -56,7 +56,7 @@ public void shouldReturnNetworkIdentity() throws Exception { final MetadataMessage metadataMessage = spec.getGenesisSchemaDefinitions() .getMetadataMessageSchema() - .create(seqnr, List.of(1, 11, 15), Collections.emptyList()); + .create(seqnr, List.of(1, 11, 15), Collections.emptyList(), Optional.empty()); when(eth2P2PNetwork.getMetadata()).thenReturn(metadataMessage); @@ -73,7 +73,7 @@ public void shouldReturnNetworkIdentityAltair() throws Exception { final MetadataMessage metadataMessage = spec.getGenesisSchemaDefinitions() .getMetadataMessageSchema() - .create(seqnr, List.of(1, 11, 15), List.of(0, 1, 2, 3)); + .create(seqnr, List.of(1, 11, 15), List.of(0, 1, 2, 3), Optional.empty()); when(eth2P2PNetwork.getMetadata()).thenReturn(metadataMessage); diff --git a/eth-reference-tests/src/referenceTest/java/tech/pegasys/teku/reference/Eth2ReferenceTestCase.java b/eth-reference-tests/src/referenceTest/java/tech/pegasys/teku/reference/Eth2ReferenceTestCase.java index 0fdc506b0f5..6ef979d43f0 100644 --- a/eth-reference-tests/src/referenceTest/java/tech/pegasys/teku/reference/Eth2ReferenceTestCase.java +++ b/eth-reference-tests/src/referenceTest/java/tech/pegasys/teku/reference/Eth2ReferenceTestCase.java @@ -98,6 +98,18 @@ public abstract class Eth2ReferenceTestCase { .putAll(MerkleProofTests.MERKLE_PROOF_TEST_TYPES) .build(); + private static final ImmutableMap FULU_TEST_TYPES = + ImmutableMap.builder() + .putAll(ForkUpgradeTestExecutor.FORK_UPGRADE_TEST_TYPES) + .putAll(RewardsTestExecutorBellatrix.REWARDS_TEST_TYPES) + .put("merkle_proof/single_merkle_proof", TestExecutor.IGNORE_TESTS) + // TODO-fulu enable merkle proof tests + // .putAll(MerkleProofTests.MERKLE_PROOF_TEST_TYPES) + // TODO-fulu networking test types (networking/compute_columns_for_custody_group) + .put("networking/get_custody_groups", TestExecutor.IGNORE_TESTS) + .put("networking/compute_columns_for_custody_group", TestExecutor.IGNORE_TESTS) + .build(); + protected void runReferenceTest(final TestDefinition testDefinition) throws Throwable { getExecutorFor(testDefinition).runTest(testDefinition); } @@ -112,6 +124,7 @@ private TestExecutor getExecutorFor(final TestDefinition testDefinition) { case TestFork.CAPELLA -> CAPELLA_TEST_TYPES.get(testDefinition.getTestType()); case TestFork.DENEB -> DENEB_TEST_TYPES.get(testDefinition.getTestType()); case TestFork.ELECTRA -> ELECTRA_TEST_TYPES.get(testDefinition.getTestType()); + case TestFork.FULU -> FULU_TEST_TYPES.get(testDefinition.getTestType()); default -> null; }; diff --git a/eth-reference-tests/src/referenceTest/java/tech/pegasys/teku/reference/altair/fork/ForkUpgradeTestExecutor.java b/eth-reference-tests/src/referenceTest/java/tech/pegasys/teku/reference/altair/fork/ForkUpgradeTestExecutor.java index ed28863f639..8b4df02fe57 100644 --- a/eth-reference-tests/src/referenceTest/java/tech/pegasys/teku/reference/altair/fork/ForkUpgradeTestExecutor.java +++ b/eth-reference-tests/src/referenceTest/java/tech/pegasys/teku/reference/altair/fork/ForkUpgradeTestExecutor.java @@ -29,6 +29,7 @@ import tech.pegasys.teku.spec.datastructures.state.beaconstate.versions.bellatrix.BeaconStateSchemaBellatrix; import tech.pegasys.teku.spec.datastructures.state.beaconstate.versions.capella.BeaconStateSchemaCapella; import tech.pegasys.teku.spec.datastructures.state.beaconstate.versions.deneb.BeaconStateSchemaDeneb; +import tech.pegasys.teku.spec.datastructures.state.beaconstate.versions.electra.BeaconStateSchemaElectra; import tech.pegasys.teku.spec.datastructures.state.beaconstate.versions.phase0.BeaconStateSchemaPhase0; import tech.pegasys.teku.spec.logic.common.forktransition.StateUpgrade; @@ -65,6 +66,10 @@ private void processUpgrade(final TestDefinition testDefinition, final SpecMiles BeaconStateSchemaDeneb.create( previousMilestoneSpecVersion.getConfig(), previousMilestoneSpecVersion.getSchemaDefinitions().getSchemaRegistry()); + case FULU -> + BeaconStateSchemaElectra.create( + previousMilestoneSpecVersion.getConfig(), + previousMilestoneSpecVersion.getSchemaDefinitions().getSchemaRegistry()); default -> throw new IllegalStateException( "Unhandled fork upgrade for test " diff --git a/eth-reference-tests/src/referenceTest/java/tech/pegasys/teku/reference/phase0/kzg/KzgComputeCellsAndKzgProofsTestExecutor.java b/eth-reference-tests/src/referenceTest/java/tech/pegasys/teku/reference/phase0/kzg/KzgComputeCellsAndKzgProofsTestExecutor.java new file mode 100644 index 00000000000..648bd0c0b19 --- /dev/null +++ b/eth-reference-tests/src/referenceTest/java/tech/pegasys/teku/reference/phase0/kzg/KzgComputeCellsAndKzgProofsTestExecutor.java @@ -0,0 +1,76 @@ +/* + * 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.reference.phase0.kzg; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.google.common.collect.Streams; +import java.util.List; +import org.apache.tuweni.bytes.Bytes; +import tech.pegasys.teku.ethtests.finder.TestDefinition; +import tech.pegasys.teku.kzg.KZG; +import tech.pegasys.teku.kzg.KZGCell; +import tech.pegasys.teku.kzg.KZGCellAndProof; +import tech.pegasys.teku.kzg.KZGProof; + +public class KzgComputeCellsAndKzgProofsTestExecutor extends KzgTestExecutor { + + @Override + @SuppressWarnings("deprecation") + public void runTest(final TestDefinition testDefinition, final KZG kzg) throws Throwable { + final Data data = loadDataFile(testDefinition, Data.class); + final List expectedKzgCellsAndProofs = data.getOutput(); + List actualKzgCellsAndProofs; + try { + final Bytes blob = data.getInput().getBlob(); + actualKzgCellsAndProofs = kzg.computeCellsAndProofs(blob); + } catch (final RuntimeException ex) { + actualKzgCellsAndProofs = null; + } + assertThat(actualKzgCellsAndProofs).isEqualTo(expectedKzgCellsAndProofs); + } + + private static class Data { + @JsonProperty(value = "input", required = true) + private Input input; + + @JsonProperty(value = "output", required = true) + private List[] output; + + public Input getInput() { + return input; + } + + public List getOutput() { + return output == null + ? null + : Streams.zip( + output[0].stream() + .map(cellString -> new KZGCell(Bytes.fromHexString(cellString))), + output[1].stream().map(KZGProof::fromHexString), + KZGCellAndProof::new) + .toList(); + } + + private static class Input { + @JsonProperty(value = "blob", required = true) + private String blob; + + public Bytes getBlob() { + return Bytes.fromHexString(blob); + } + } + } +} diff --git a/eth-reference-tests/src/referenceTest/java/tech/pegasys/teku/reference/phase0/kzg/KzgComputeCellsTestExecutor.java b/eth-reference-tests/src/referenceTest/java/tech/pegasys/teku/reference/phase0/kzg/KzgComputeCellsTestExecutor.java new file mode 100644 index 00000000000..c7ed5168555 --- /dev/null +++ b/eth-reference-tests/src/referenceTest/java/tech/pegasys/teku/reference/phase0/kzg/KzgComputeCellsTestExecutor.java @@ -0,0 +1,76 @@ +/* + * Copyright Consensys Software Inc., 2025 + * + * 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.reference.phase0.kzg; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import org.apache.tuweni.bytes.Bytes; +import tech.pegasys.teku.ethtests.finder.TestDefinition; +import tech.pegasys.teku.kzg.KZG; +import tech.pegasys.teku.kzg.KZGCell; + +public class KzgComputeCellsTestExecutor extends KzgTestExecutor { + + @Override + public void runTest(final TestDefinition testDefinition, final KZG kzg) throws Throwable { + final Data data = loadDataFile(testDefinition, Data.class); + final List expectedKzgCells = data.getOutput(); + List actualKzgCells; + try { + final Bytes blob = data.getInput().getBlob(); + actualKzgCells = kzg.computeCells(blob); + } catch (final RuntimeException ex) { + actualKzgCells = null; + } + + if (expectedKzgCells == null) { + assertThat(actualKzgCells).isNull(); + } else { + assertThat(actualKzgCells).isEqualTo(expectedKzgCells); + } + } + + private static class Data { + + @JsonProperty(value = "input", required = true) + private Input input; + + @JsonProperty(value = "output", required = true) + private List output; + + public Input getInput() { + return input; + } + + public List getOutput() { + return output == null + ? null + : output.stream() + .map(cellString -> new KZGCell(Bytes.fromHexString(cellString))) + .toList(); + } + + private static class Input { + + @JsonProperty(value = "blob", required = true) + private String blob; + + public Bytes getBlob() { + return Bytes.fromHexString(blob); + } + } + } +} diff --git a/eth-reference-tests/src/referenceTest/java/tech/pegasys/teku/reference/phase0/kzg/KzgRecoverCellsAndKzgProofsTestExecutor.java b/eth-reference-tests/src/referenceTest/java/tech/pegasys/teku/reference/phase0/kzg/KzgRecoverCellsAndKzgProofsTestExecutor.java new file mode 100644 index 00000000000..74b165a8f74 --- /dev/null +++ b/eth-reference-tests/src/referenceTest/java/tech/pegasys/teku/reference/phase0/kzg/KzgRecoverCellsAndKzgProofsTestExecutor.java @@ -0,0 +1,111 @@ +/* + * 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.reference.phase0.kzg; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.google.common.collect.Streams; +import java.util.List; +import java.util.stream.IntStream; +import org.apache.tuweni.bytes.Bytes; +import org.apache.tuweni.bytes.Bytes48; +import tech.pegasys.teku.ethtests.finder.TestDefinition; +import tech.pegasys.teku.kzg.KZG; +import tech.pegasys.teku.kzg.KZGCell; +import tech.pegasys.teku.kzg.KZGCellAndProof; +import tech.pegasys.teku.kzg.KZGCellWithColumnId; +import tech.pegasys.teku.kzg.KZGProof; + +public class KzgRecoverCellsAndKzgProofsTestExecutor extends KzgTestExecutor { + + @Override + public void runTest(final TestDefinition testDefinition, final KZG kzg) throws Throwable { + final Data data = loadDataFile(testDefinition, Data.class); + final List expectedKzgCells = data.getOutput(); + List actualKzgCells; + try { + final List cellIds = data.getInput().getCellIndices(); + final List cells = data.getInput().getCells(); + if (cells.size() != cellIds.size()) { + throw new RuntimeException("Cells doesn't match ids"); + } + final List cellWithIds = + Streams.zip(cells.stream(), cellIds.stream(), KZGCellWithColumnId::fromCellAndColumn) + .toList(); + actualKzgCells = kzg.recoverCellsAndProofs(cellWithIds); + } catch (final RuntimeException ex) { + actualKzgCells = null; + } + assertThat(actualKzgCells).isEqualTo(expectedKzgCells); + } + + private static class Data { + @JsonProperty(value = "input", required = true) + private Input input; + + @JsonProperty(value = "output", required = true) + private List> output; + + public Input getInput() { + return input; + } + + public List getOutput() { + if (output == null) { + return null; + } + final List cellStrings = output.get(0); + final List proofStrings = output.get(1); + if (cellStrings.size() != proofStrings.size()) { + throw new RuntimeException("Number of cells and proofs should be the same"); + } + return IntStream.range(0, cellStrings.size()) + .mapToObj( + index -> + new KZGCellAndProof( + new KZGCell(Bytes.fromHexString(cellStrings.get(index))), + KZGProof.fromHexString(proofStrings.get(index)))) + .toList(); + } + + private static class Input { + @JsonProperty(value = "cell_indices", required = true) + private List cellIndices; + + @JsonProperty(value = "cells", required = true) + private List cells; + + @JsonProperty(value = "proofs", required = true) + private List proofs; + + public List getCellIndices() { + return cellIndices; + } + + public List getCells() { + return cells.stream() + .map(cellString -> new KZGCell(Bytes.fromHexString(cellString))) + .toList(); + } + + @SuppressWarnings("Unused") + public List getProfos() { + return proofs.stream() + .map(proofString -> new KZGProof(Bytes48.fromHexString(proofString))) + .toList(); + } + } + } +} diff --git a/eth-reference-tests/src/referenceTest/java/tech/pegasys/teku/reference/phase0/kzg/KzgTests.java b/eth-reference-tests/src/referenceTest/java/tech/pegasys/teku/reference/phase0/kzg/KzgTests.java index 6b2c9b50bdb..5e465c392d6 100644 --- a/eth-reference-tests/src/referenceTest/java/tech/pegasys/teku/reference/phase0/kzg/KzgTests.java +++ b/eth-reference-tests/src/referenceTest/java/tech/pegasys/teku/reference/phase0/kzg/KzgTests.java @@ -29,5 +29,10 @@ public class KzgTests { .put("kzg/verify_blob_kzg_proof_batch", new KzgVerifyBlobProofBatchTestExecutor()) // no KZG interface on CL side, EL responsibility .put("kzg/verify_kzg_proof", TestExecutor.IGNORE_TESTS) + // DataColumnSidecar PeerDAS Fulu utils + .put("kzg/compute_cells", new KzgComputeCellsTestExecutor()) + .put("kzg/compute_cells_and_kzg_proofs", new KzgComputeCellsAndKzgProofsTestExecutor()) + .put("kzg/recover_cells_and_kzg_proofs", new KzgRecoverCellsAndKzgProofsTestExecutor()) + .put("kzg/verify_cell_kzg_proof_batch", new KzgVerifyCellKzgProofBatchTestExecutor()) .build(); } diff --git a/eth-reference-tests/src/referenceTest/java/tech/pegasys/teku/reference/phase0/kzg/KzgVerifyCellKzgProofBatchTestExecutor.java b/eth-reference-tests/src/referenceTest/java/tech/pegasys/teku/reference/phase0/kzg/KzgVerifyCellKzgProofBatchTestExecutor.java new file mode 100644 index 00000000000..6a72c30b10a --- /dev/null +++ b/eth-reference-tests/src/referenceTest/java/tech/pegasys/teku/reference/phase0/kzg/KzgVerifyCellKzgProofBatchTestExecutor.java @@ -0,0 +1,100 @@ +/* + * 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.reference.phase0.kzg; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.google.common.collect.Streams; +import java.util.List; +import org.apache.tuweni.bytes.Bytes; +import tech.pegasys.teku.ethtests.finder.TestDefinition; +import tech.pegasys.teku.kzg.KZG; +import tech.pegasys.teku.kzg.KZGCell; +import tech.pegasys.teku.kzg.KZGCellWithColumnId; +import tech.pegasys.teku.kzg.KZGCommitment; +import tech.pegasys.teku.kzg.KZGProof; + +public class KzgVerifyCellKzgProofBatchTestExecutor extends KzgTestExecutor { + + @Override + public void runTest(final TestDefinition testDefinition, final KZG kzg) throws Throwable { + final Data data = loadDataFile(testDefinition, Data.class); + final Boolean expectedVerificationResult = data.getOutput(); + Boolean actualVerificationResult; + try { + if (data.getInput().cellIndices.size() != data.getInput().cells.size()) { + throw new RuntimeException("cellIndices and cells sizes don't match!"); + } + actualVerificationResult = + kzg.verifyCellProofBatch( + data.getInput().getCommitments(), + Streams.zip( + data.getInput().getCellIndices().stream(), + data.getInput().getCells().stream(), + (cellIndex, cell) -> KZGCellWithColumnId.fromCellAndColumn(cell, cellIndex)) + .toList(), + data.getInput().getProofs()); + } catch (final RuntimeException ex) { + actualVerificationResult = null; + } + assertThat(actualVerificationResult).isEqualTo(expectedVerificationResult); + } + + private static class Data { + @JsonProperty(value = "input", required = true) + private Input input; + + @JsonProperty(value = "output", required = true) + private Boolean output; + + public Input getInput() { + return input; + } + + public Boolean getOutput() { + return output; + } + + private static class Input { + @JsonProperty(value = "commitments", required = true) + private List commitments; + + @JsonProperty(value = "cell_indices", required = true) + private List cellIndices; + + @JsonProperty(value = "cells", required = true) + private List cells; + + @JsonProperty(value = "proofs", required = true) + private List proofs; + + public List getCommitments() { + return commitments.stream().map(KZGCommitment::fromHexString).toList(); + } + + public List getCellIndices() { + return cellIndices; + } + + public List getCells() { + return cells.stream().map(cell -> new KZGCell(Bytes.fromHexString(cell))).toList(); + } + + public List getProofs() { + return proofs.stream().map(KZGProof::fromHexString).toList(); + } + } + } +} diff --git a/eth-reference-tests/src/referenceTest/java/tech/pegasys/teku/reference/phase0/ssz_static/SszTestExecutor.java b/eth-reference-tests/src/referenceTest/java/tech/pegasys/teku/reference/phase0/ssz_static/SszTestExecutor.java index 811577836b1..bf712c66ab9 100644 --- a/eth-reference-tests/src/referenceTest/java/tech/pegasys/teku/reference/phase0/ssz_static/SszTestExecutor.java +++ b/eth-reference-tests/src/referenceTest/java/tech/pegasys/teku/reference/phase0/ssz_static/SszTestExecutor.java @@ -29,6 +29,7 @@ import tech.pegasys.teku.spec.datastructures.blocks.SignedBeaconBlockHeader; import tech.pegasys.teku.spec.datastructures.blocks.blockbody.versions.altair.BeaconBlockBodySchemaAltair; import tech.pegasys.teku.spec.datastructures.networking.libp2p.rpc.BlobIdentifier; +import tech.pegasys.teku.spec.datastructures.networking.libp2p.rpc.DataColumnIdentifier; import tech.pegasys.teku.spec.datastructures.operations.AttestationData; import tech.pegasys.teku.spec.datastructures.operations.Deposit; import tech.pegasys.teku.spec.datastructures.operations.DepositData; @@ -48,6 +49,7 @@ import tech.pegasys.teku.spec.schemas.SchemaDefinitionsCapella; import tech.pegasys.teku.spec.schemas.SchemaDefinitionsDeneb; import tech.pegasys.teku.spec.schemas.SchemaDefinitionsElectra; +import tech.pegasys.teku.spec.schemas.SchemaDefinitionsFulu; public class SszTestExecutor implements TestExecutor { private final SchemaProvider sszType; @@ -226,6 +228,19 @@ public class SszTestExecutor implements TestExecutor { schemas -> SchemaDefinitionsElectra.required(schemas).getSingleAttestationSchema())) + // Fulu types + .put( + "ssz_static/DataColumnIdentifier", + new SszTestExecutor<>(schemas -> DataColumnIdentifier.SSZ_SCHEMA)) + .put( + "ssz_static/DataColumnSidecar", + new SszTestExecutor<>( + schemas -> SchemaDefinitionsFulu.required(schemas).getDataColumnSidecarSchema())) + .put( + "ssz_static/MatrixEntry", + new SszTestExecutor<>( + schemas -> SchemaDefinitionsFulu.required(schemas).getMatrixEntrySchema())) + // Legacy Schemas (Not yet migrated to SchemaDefinitions) .put( "ssz_static/AttestationData", new SszTestExecutor<>(__ -> AttestationData.SSZ_SCHEMA)) diff --git a/eth-tests/src/main/java/tech/pegasys/teku/ethtests/TestFork.java b/eth-tests/src/main/java/tech/pegasys/teku/ethtests/TestFork.java index 3db1001c903..4b8997901c3 100644 --- a/eth-tests/src/main/java/tech/pegasys/teku/ethtests/TestFork.java +++ b/eth-tests/src/main/java/tech/pegasys/teku/ethtests/TestFork.java @@ -20,4 +20,5 @@ public class TestFork { public static final String CAPELLA = "capella"; public static final String DENEB = "deneb"; public static final String ELECTRA = "electra"; + public static final String FULU = "fulu"; } diff --git a/eth-tests/src/main/java/tech/pegasys/teku/ethtests/finder/ReferenceTestFinder.java b/eth-tests/src/main/java/tech/pegasys/teku/ethtests/finder/ReferenceTestFinder.java index 7836d79f53c..878a7bbe9f5 100644 --- a/eth-tests/src/main/java/tech/pegasys/teku/ethtests/finder/ReferenceTestFinder.java +++ b/eth-tests/src/main/java/tech/pegasys/teku/ethtests/finder/ReferenceTestFinder.java @@ -36,7 +36,8 @@ public class ReferenceTestFinder { TestFork.BELLATRIX, TestFork.CAPELLA, TestFork.DENEB, - TestFork.ELECTRA); + TestFork.ELECTRA, + TestFork.FULU); @MustBeClosed public static Stream findReferenceTests() throws IOException { diff --git a/eth-tests/src/main/java/tech/pegasys/teku/ethtests/finder/TestDefinition.java b/eth-tests/src/main/java/tech/pegasys/teku/ethtests/finder/TestDefinition.java index cdd831d5df3..62d8541b6bf 100644 --- a/eth-tests/src/main/java/tech/pegasys/teku/ethtests/finder/TestDefinition.java +++ b/eth-tests/src/main/java/tech/pegasys/teku/ethtests/finder/TestDefinition.java @@ -73,6 +73,7 @@ private void createSpec() { case TestFork.CAPELLA -> SpecMilestone.CAPELLA; case TestFork.DENEB -> SpecMilestone.DENEB; case TestFork.ELECTRA -> SpecMilestone.ELECTRA; + case TestFork.FULU -> SpecMilestone.FULU; default -> throw new IllegalArgumentException("Unknown fork: " + fork); }; spec = TestSpecFactory.create(milestone, network); diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blobs/versions/fulu/Cell.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blobs/versions/fulu/Cell.java new file mode 100644 index 00000000000..a9b2837f176 --- /dev/null +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blobs/versions/fulu/Cell.java @@ -0,0 +1,33 @@ +/* + * Copyright Consensys Software Inc., 2025 + * + * 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.blobs.versions.fulu; + +import org.apache.tuweni.bytes.Bytes; +import tech.pegasys.teku.infrastructure.ssz.collections.impl.SszByteVectorImpl; +import tech.pegasys.teku.infrastructure.ssz.tree.TreeNode; + +public class Cell extends SszByteVectorImpl { + + Cell(final CellSchema schema, final TreeNode backingNode) { + super(schema, backingNode); + } + + Cell(final CellSchema cellSchema, final Bytes bytes) { + super(cellSchema, bytes); + } + + public String toBriefString() { + return getBytes().slice(0, 7).toUnprefixedHexString(); + } +} diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blobs/versions/fulu/CellSchema.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blobs/versions/fulu/CellSchema.java new file mode 100644 index 00000000000..94e0444c347 --- /dev/null +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blobs/versions/fulu/CellSchema.java @@ -0,0 +1,38 @@ +/* + * Copyright Consensys Software Inc., 2025 + * + * 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.blobs.versions.fulu; + +import org.apache.tuweni.bytes.Bytes; +import tech.pegasys.teku.infrastructure.ssz.schema.collections.impl.SszByteVectorSchemaImpl; +import tech.pegasys.teku.infrastructure.ssz.tree.TreeNode; +import tech.pegasys.teku.spec.config.SpecConfigDeneb; +import tech.pegasys.teku.spec.config.SpecConfigFulu; + +public class CellSchema extends SszByteVectorSchemaImpl { + + public CellSchema(final SpecConfigFulu specConfig) { + super( + SpecConfigDeneb.BYTES_PER_FIELD_ELEMENT.longValue() + * specConfig.getFieldElementsPerCell().longValue()); + } + + public Cell create(final Bytes bytes) { + return new Cell(this, bytes); + } + + @Override + public Cell createFromBackingNode(final TreeNode node) { + return new Cell(this, node); + } +} diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blobs/versions/fulu/DataColumn.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blobs/versions/fulu/DataColumn.java new file mode 100644 index 00000000000..75911124177 --- /dev/null +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blobs/versions/fulu/DataColumn.java @@ -0,0 +1,29 @@ +/* + * Copyright Consensys Software Inc., 2025 + * + * 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.blobs.versions.fulu; + +import tech.pegasys.teku.infrastructure.ssz.SszList; +import tech.pegasys.teku.infrastructure.ssz.impl.SszListImpl; +import tech.pegasys.teku.infrastructure.ssz.tree.TreeNode; + +public class DataColumn extends SszListImpl implements SszList { + + DataColumn(final DataColumnSchema schema, final TreeNode node) { + super(schema, node); + } + + public String toBriefString() { + return isEmpty() ? "" : get(0).toBriefString(); + } +} diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blobs/versions/fulu/DataColumnSchema.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blobs/versions/fulu/DataColumnSchema.java new file mode 100644 index 00000000000..30595c0d5c4 --- /dev/null +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blobs/versions/fulu/DataColumnSchema.java @@ -0,0 +1,39 @@ +/* + * Copyright Consensys Software Inc., 2025 + * + * 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.blobs.versions.fulu; + +import static tech.pegasys.teku.spec.schemas.registry.SchemaTypes.CELL_SCHEMA; + +import java.util.List; +import tech.pegasys.teku.infrastructure.ssz.schema.impl.AbstractSszListSchema; +import tech.pegasys.teku.infrastructure.ssz.tree.TreeNode; +import tech.pegasys.teku.spec.config.SpecConfigDeneb; +import tech.pegasys.teku.spec.schemas.registry.SchemaRegistry; + +public class DataColumnSchema extends AbstractSszListSchema { + + public DataColumnSchema(final SpecConfigDeneb specConfig, final SchemaRegistry registry) { + super(registry.get(CELL_SCHEMA), specConfig.getMaxBlobCommitmentsPerBlock()); + } + + public DataColumn create(final List cells) { + final TreeNode backingNode = this.createTreeFromElements(cells); + return createFromBackingNode(backingNode); + } + + @Override + public DataColumn createFromBackingNode(final TreeNode node) { + return new DataColumn(this, node); + } +} diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blobs/versions/fulu/DataColumnSidecar.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blobs/versions/fulu/DataColumnSidecar.java new file mode 100644 index 00000000000..b63dd88e7a0 --- /dev/null +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blobs/versions/fulu/DataColumnSidecar.java @@ -0,0 +1,143 @@ +/* + * Copyright Consensys Software Inc., 2025 + * + * 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.blobs.versions.fulu; + +import java.util.List; +import org.apache.tuweni.bytes.Bytes32; +import tech.pegasys.teku.infrastructure.logging.LogFormatter; +import tech.pegasys.teku.infrastructure.ssz.SszList; +import tech.pegasys.teku.infrastructure.ssz.collections.SszBytes32Vector; +import tech.pegasys.teku.infrastructure.ssz.containers.Container6; +import tech.pegasys.teku.infrastructure.ssz.primitive.SszBytes32; +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.kzg.KZGCommitment; +import tech.pegasys.teku.kzg.KZGProof; +import tech.pegasys.teku.spec.datastructures.blocks.SignedBeaconBlockHeader; +import tech.pegasys.teku.spec.datastructures.blocks.SlotAndBlockRoot; +import tech.pegasys.teku.spec.datastructures.type.SszKZGCommitment; +import tech.pegasys.teku.spec.datastructures.type.SszKZGProof; + +public class DataColumnSidecar + extends Container6< + DataColumnSidecar, + SszUInt64, + DataColumn, + SszList, + SszList, + SignedBeaconBlockHeader, + SszBytes32Vector> { + + DataColumnSidecar( + final DataColumnSidecarSchema dataColumnSidecarSchema, final TreeNode backingTreeNode) { + super(dataColumnSidecarSchema, backingTreeNode); + } + + public DataColumnSidecar( + final DataColumnSidecarSchema schema, + final UInt64 index, + final DataColumn dataColumn, + final List kzgCommitments, + final List kzgProofs, + final SignedBeaconBlockHeader signedBeaconBlockHeader, + final List kzgCommitmentsInclusionProof) { + super( + schema, + SszUInt64.of(index), + dataColumn, + schema + .getKzgCommitmentsSchema() + .createFromElements(kzgCommitments.stream().map(SszKZGCommitment::new).toList()), + schema + .getKzgProofsSchema() + .createFromElements(kzgProofs.stream().map(SszKZGProof::new).toList()), + signedBeaconBlockHeader, + schema + .getKzgCommitmentsInclusionProofSchema() + .createFromElements( + kzgCommitmentsInclusionProof.stream().map(SszBytes32::of).toList())); + } + + public DataColumnSidecar( + final DataColumnSidecarSchema schema, + final UInt64 index, + final DataColumn dataColumn, + final SszList sszKzgCommitments, + final SszList sszKkzgProofs, + final SignedBeaconBlockHeader signedBeaconBlockHeader, + final List kzgCommitmentsInclusionProof) { + super( + schema, + SszUInt64.of(index), + dataColumn, + sszKzgCommitments, + sszKkzgProofs, + signedBeaconBlockHeader, + schema + .getKzgCommitmentsInclusionProofSchema() + .createFromElements( + kzgCommitmentsInclusionProof.stream().map(SszBytes32::of).toList())); + } + + public UInt64 getIndex() { + return getField0().get(); + } + + public DataColumn getDataColumn() { + return getField1(); + } + + public SszList getSszKZGCommitments() { + return getField2(); + } + + public SszList getSszKZGProofs() { + return getField3(); + } + + public SignedBeaconBlockHeader getSignedBeaconBlockHeader() { + return getField4(); + } + + public SszBytes32Vector getKzgCommitmentsInclusionProof() { + return getField5(); + } + + public UInt64 getSlot() { + return getSignedBeaconBlockHeader().getMessage().getSlot(); + } + + public Bytes32 getBlockBodyRoot() { + return getSignedBeaconBlockHeader().getMessage().getBodyRoot(); + } + + public Bytes32 getBlockRoot() { + return getSignedBeaconBlockHeader().getMessage().getRoot(); + } + + public SlotAndBlockRoot getSlotAndBlockRoot() { + return new SlotAndBlockRoot(getSlot(), getBlockRoot()); + } + + public String toLogString() { + return LogFormatter.formatDataColumnSidecar( + getSlot(), + getBlockRoot(), + getIndex(), + getDataColumn().toBriefString(), + getSszKZGCommitments().size(), + getSszKZGProofs().size()); + } +} diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blobs/versions/fulu/DataColumnSidecarSchema.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blobs/versions/fulu/DataColumnSidecarSchema.java new file mode 100644 index 00000000000..10f5b104af3 --- /dev/null +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blobs/versions/fulu/DataColumnSidecarSchema.java @@ -0,0 +1,164 @@ +/* + * Copyright Consensys Software Inc., 2025 + * + * 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.blobs.versions.fulu; + +import java.util.List; +import org.apache.tuweni.bytes.Bytes32; +import tech.pegasys.teku.infrastructure.ssz.SszList; +import tech.pegasys.teku.infrastructure.ssz.collections.SszBytes32Vector; +import tech.pegasys.teku.infrastructure.ssz.containers.ContainerSchema6; +import tech.pegasys.teku.infrastructure.ssz.primitive.SszUInt64; +import tech.pegasys.teku.infrastructure.ssz.schema.SszFieldName; +import tech.pegasys.teku.infrastructure.ssz.schema.SszListSchema; +import tech.pegasys.teku.infrastructure.ssz.schema.SszPrimitiveSchemas; +import tech.pegasys.teku.infrastructure.ssz.schema.collections.SszBytes32VectorSchema; +import tech.pegasys.teku.infrastructure.ssz.tree.TreeNode; +import tech.pegasys.teku.infrastructure.unsigned.UInt64; +import tech.pegasys.teku.kzg.KZGCommitment; +import tech.pegasys.teku.kzg.KZGProof; +import tech.pegasys.teku.spec.config.SpecConfigFulu; +import tech.pegasys.teku.spec.datastructures.blocks.SignedBeaconBlockHeader; +import tech.pegasys.teku.spec.datastructures.blocks.SignedBeaconBlockHeaderSchema; +import tech.pegasys.teku.spec.datastructures.type.SszKZGCommitment; +import tech.pegasys.teku.spec.datastructures.type.SszKZGCommitmentSchema; +import tech.pegasys.teku.spec.datastructures.type.SszKZGProof; +import tech.pegasys.teku.spec.datastructures.type.SszKZGProofSchema; + +public class DataColumnSidecarSchema + extends ContainerSchema6< + DataColumnSidecar, + SszUInt64, + DataColumn, + SszList, + SszList, + SignedBeaconBlockHeader, + SszBytes32Vector> { + + static final SszFieldName FIELD_BLOB = () -> "column"; + static final SszFieldName FIELD_KZG_COMMITMENTS = () -> "kzg_commitments"; + static final SszFieldName FIELD_KZG_PROOFS = () -> "kzg_proofs"; + static final SszFieldName FIELD_SIGNED_BLOCK_HEADER = () -> "signed_block_header"; + static final SszFieldName FIELD_KZG_COMMITMENTS_INCLUSION_PROOF = + () -> "kzg_commitments_inclusion_proof"; + + DataColumnSidecarSchema( + final SignedBeaconBlockHeaderSchema signedBeaconBlockHeaderSchema, + final DataColumnSchema dataColumnSchema, + final SpecConfigFulu specConfig) { + super( + "DataColumnSidecar", + namedSchema("index", SszPrimitiveSchemas.UINT64_SCHEMA), + namedSchema(FIELD_BLOB, dataColumnSchema), + namedSchema( + FIELD_KZG_COMMITMENTS, + SszListSchema.create( + SszKZGCommitmentSchema.INSTANCE, specConfig.getMaxBlobCommitmentsPerBlock())), + namedSchema( + FIELD_KZG_PROOFS, + SszListSchema.create( + SszKZGProofSchema.INSTANCE, specConfig.getMaxBlobCommitmentsPerBlock())), + namedSchema(FIELD_SIGNED_BLOCK_HEADER, signedBeaconBlockHeaderSchema), + namedSchema( + FIELD_KZG_COMMITMENTS_INCLUSION_PROOF, + SszBytes32VectorSchema.create( + specConfig.getKzgCommitmentsInclusionProofDepth().intValue()))); + } + + @SuppressWarnings("unchecked") + public DataColumnSchema getDataColumnSszSchema() { + return (DataColumnSchema) getChildSchema(getFieldIndex(FIELD_BLOB)); + } + + public SignedBeaconBlockHeaderSchema getSignedBlockHeaderSchema() { + return (SignedBeaconBlockHeaderSchema) getFieldSchema4(); + } + + public SszBytes32VectorSchema getKzgCommitmentsInclusionProofSchema() { + return (SszBytes32VectorSchema) + getChildSchema(getFieldIndex(FIELD_KZG_COMMITMENTS_INCLUSION_PROOF)); + } + + @SuppressWarnings("unchecked") + public SszListSchema getKzgCommitmentsSchema() { + return (SszListSchema) + getChildSchema(getFieldIndex(FIELD_KZG_COMMITMENTS)); + } + + @SuppressWarnings("unchecked") + public SszListSchema getKzgProofsSchema() { + return (SszListSchema) getChildSchema(getFieldIndex(FIELD_KZG_PROOFS)); + } + + public DataColumnSidecar create( + final UInt64 index, + final DataColumn dataColumn, + final SszList sszKzgCommitments, + final SszList sszKkzgProofs, + final SignedBeaconBlockHeader signedBeaconBlockHeader, + final List kzgCommitmentsInclusionProof) { + return new DataColumnSidecar( + this, + index, + dataColumn, + sszKzgCommitments, + sszKkzgProofs, + signedBeaconBlockHeader, + kzgCommitmentsInclusionProof); + } + + // public DataColumnSidecar create( + // final UInt64 index, + // final Bytes blob, + // final Bytes48 kzgCommitment, + // final Bytes48 kzgProof, + // final SignedBeaconBlockHeader signedBeaconBlockHeader, + // final List kzgCommitmentsInclusionProof) { + // return create( + // index, + // new Blob(getBlobSchema(), blob), + // KZGCommitment.fromBytesCompressed(kzgCommitment), + // KZGProof.fromBytesCompressed(kzgProof), + // signedBeaconBlockHeader, + // kzgCommitmentsInclusionProof); + // } + + public DataColumnSidecar create( + final UInt64 index, + final DataColumn dataColumn, + final List kzgCommitments, + final List kzgProofs, + final SignedBeaconBlockHeader signedBeaconBlockHeader, + final List kzgCommitmentsInclusionProof) { + return new DataColumnSidecar( + this, + index, + dataColumn, + kzgCommitments, + kzgProofs, + signedBeaconBlockHeader, + kzgCommitmentsInclusionProof); + } + + public static DataColumnSidecarSchema create( + final SignedBeaconBlockHeaderSchema signedBeaconBlockHeaderSchema, + final DataColumnSchema dataColumnSchema, + final SpecConfigFulu specConfig) { + return new DataColumnSidecarSchema(signedBeaconBlockHeaderSchema, dataColumnSchema, specConfig); + } + + @Override + public DataColumnSidecar createFromBackingNode(final TreeNode node) { + return new DataColumnSidecar(this, node); + } +} diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blobs/versions/fulu/MatrixEntry.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blobs/versions/fulu/MatrixEntry.java new file mode 100644 index 00000000000..7ab049cc6b5 --- /dev/null +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blobs/versions/fulu/MatrixEntry.java @@ -0,0 +1,63 @@ +/* + * Copyright Consensys Software Inc., 2025 + * + * 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.blobs.versions.fulu; + +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.kzg.KZGProof; +import tech.pegasys.teku.spec.datastructures.type.SszKZGProof; + +public class MatrixEntry extends Container4 { + + MatrixEntry(final MatrixEntrySchema matrixEntrySchema, final TreeNode backingTreeNode) { + super(matrixEntrySchema, backingTreeNode); + } + + public MatrixEntry( + final MatrixEntrySchema schema, + final Cell cell, + final KZGProof kzgProof, + final UInt64 columnIndex, + final UInt64 rowIndex) { + super( + schema, cell, new SszKZGProof(kzgProof), SszUInt64.of(columnIndex), SszUInt64.of(rowIndex)); + } + + public MatrixEntry( + final MatrixEntrySchema schema, + final Cell cell, + final SszKZGProof sszKZGProof, + final SszUInt64 sszColumnIndex, + final SszUInt64 sszRowIndex) { + super(schema, cell, sszKZGProof, sszColumnIndex, sszRowIndex); + } + + public Cell getCell() { + return getField0(); + } + + public KZGProof getKzgProof() { + return getField1().getKZGProof(); + } + + public UInt64 getColumnIndex() { + return getField2().get(); + } + + public UInt64 getRowIndex() { + return getField3().get(); + } +} diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blobs/versions/fulu/MatrixEntrySchema.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blobs/versions/fulu/MatrixEntrySchema.java new file mode 100644 index 00000000000..a22c74bfce3 --- /dev/null +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blobs/versions/fulu/MatrixEntrySchema.java @@ -0,0 +1,66 @@ +/* + * Copyright Consensys Software Inc., 2025 + * + * 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.blobs.versions.fulu; + +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.tree.TreeNode; +import tech.pegasys.teku.infrastructure.unsigned.UInt64; +import tech.pegasys.teku.kzg.KZGCell; +import tech.pegasys.teku.kzg.KZGProof; +import tech.pegasys.teku.spec.datastructures.type.SszKZGProof; +import tech.pegasys.teku.spec.datastructures.type.SszKZGProofSchema; + +public class MatrixEntrySchema + extends ContainerSchema4 { + + MatrixEntrySchema(final CellSchema cellSchema) { + super( + "MatrixEntry", + namedSchema("cell", cellSchema), + namedSchema("kzg_proof", SszKZGProofSchema.INSTANCE), + namedSchema("column_index", SszPrimitiveSchemas.UINT64_SCHEMA), + namedSchema("row_index", SszPrimitiveSchemas.UINT64_SCHEMA)); + } + + public CellSchema getCellSchema() { + return (CellSchema) getFieldSchema0(); + } + + public MatrixEntry create( + final Cell cell, final KZGProof kzgProof, final UInt64 columnIndex, final UInt64 rowIndex) { + return new MatrixEntry( + this, cell, new SszKZGProof(kzgProof), SszUInt64.of(columnIndex), SszUInt64.of(rowIndex)); + } + + public MatrixEntry create( + final KZGCell cell, final KZGProof kzgProof, final int columnIndex, final int rowIndex) { + return new MatrixEntry( + this, + getCellSchema().create(cell.bytes()), + new SszKZGProof(kzgProof), + SszUInt64.of(UInt64.valueOf(columnIndex)), + SszUInt64.of(UInt64.valueOf(rowIndex))); + } + + public static MatrixEntrySchema create(final CellSchema cellSchema) { + return new MatrixEntrySchema(cellSchema); + } + + @Override + public MatrixEntry createFromBackingNode(final TreeNode node) { + return new MatrixEntry(this, node); + } +} diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/networking/libp2p/rpc/DataColumnIdentifier.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/networking/libp2p/rpc/DataColumnIdentifier.java new file mode 100644 index 00000000000..826cb6168d7 --- /dev/null +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/networking/libp2p/rpc/DataColumnIdentifier.java @@ -0,0 +1,65 @@ +/* + * Copyright Consensys Software Inc., 2025 + * + * 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.networking.libp2p.rpc; + +import org.apache.tuweni.bytes.Bytes32; +import tech.pegasys.teku.infrastructure.ssz.containers.Container2; +import tech.pegasys.teku.infrastructure.ssz.containers.ContainerSchema2; +import tech.pegasys.teku.infrastructure.ssz.primitive.SszBytes32; +import tech.pegasys.teku.infrastructure.ssz.primitive.SszUInt64; +import tech.pegasys.teku.infrastructure.ssz.schema.SszPrimitiveSchemas; +import tech.pegasys.teku.infrastructure.ssz.tree.TreeNode; +import tech.pegasys.teku.infrastructure.unsigned.UInt64; +import tech.pegasys.teku.spec.datastructures.blobs.versions.fulu.DataColumnSidecar; + +public class DataColumnIdentifier extends Container2 { + + public static class DataColumnIdentifierSchema + extends ContainerSchema2 { + + private DataColumnIdentifierSchema() { + super( + "DataColumnIdentifier", + namedSchema("block_root", SszPrimitiveSchemas.BYTES32_SCHEMA), + namedSchema("index", SszPrimitiveSchemas.UINT64_SCHEMA)); + } + + @Override + public DataColumnIdentifier createFromBackingNode(final TreeNode node) { + return new DataColumnIdentifier(node); + } + } + + public static final DataColumnIdentifierSchema SSZ_SCHEMA = new DataColumnIdentifierSchema(); + + public static DataColumnIdentifier createFromSidecar(final DataColumnSidecar sidecar) { + return new DataColumnIdentifier(sidecar.getBlockRoot(), sidecar.getIndex()); + } + + private DataColumnIdentifier(final TreeNode node) { + super(SSZ_SCHEMA, node); + } + + public DataColumnIdentifier(final Bytes32 root, final UInt64 index) { + super(SSZ_SCHEMA, SszBytes32.of(root), SszUInt64.of(index)); + } + + public Bytes32 getBlockRoot() { + return getField0().get(); + } + + public UInt64 getIndex() { + return getField1().get(); + } +} diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/networking/libp2p/rpc/DataColumnSidecarsByRangeRequestMessage.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/networking/libp2p/rpc/DataColumnSidecarsByRangeRequestMessage.java new file mode 100644 index 00000000000..bc9dbfe80fd --- /dev/null +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/networking/libp2p/rpc/DataColumnSidecarsByRangeRequestMessage.java @@ -0,0 +1,100 @@ +/* + * Copyright Consensys Software Inc., 2025 + * + * 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.networking.libp2p.rpc; + +import java.util.List; +import tech.pegasys.teku.infrastructure.ssz.collections.SszUInt64List; +import tech.pegasys.teku.infrastructure.ssz.containers.Container3; +import tech.pegasys.teku.infrastructure.ssz.containers.ContainerSchema3; +import tech.pegasys.teku.infrastructure.ssz.impl.AbstractSszPrimitive; +import tech.pegasys.teku.infrastructure.ssz.primitive.SszUInt64; +import tech.pegasys.teku.infrastructure.ssz.schema.SszListSchema; +import tech.pegasys.teku.infrastructure.ssz.schema.SszPrimitiveSchemas; +import tech.pegasys.teku.infrastructure.ssz.schema.collections.SszUInt64ListSchema; +import tech.pegasys.teku.infrastructure.ssz.tree.TreeNode; +import tech.pegasys.teku.infrastructure.unsigned.UInt64; +import tech.pegasys.teku.spec.config.SpecConfigFulu; + +public class DataColumnSidecarsByRangeRequestMessage + extends Container3 + implements RpcRequest { + + public static class DataColumnSidecarsByRangeRequestMessageSchema + extends ContainerSchema3< + DataColumnSidecarsByRangeRequestMessage, SszUInt64, SszUInt64, SszUInt64List> { + + public DataColumnSidecarsByRangeRequestMessageSchema(final SpecConfigFulu specConfig) { + super( + "DataColumnSidecarsByRangeRequestMessage", + namedSchema("start_slot", SszPrimitiveSchemas.UINT64_SCHEMA), + namedSchema("count", SszPrimitiveSchemas.UINT64_SCHEMA), + namedSchema("columns", SszUInt64ListSchema.create(specConfig.getNumberOfColumns()))); + } + + @Override + public DataColumnSidecarsByRangeRequestMessage createFromBackingNode(final TreeNode node) { + return new DataColumnSidecarsByRangeRequestMessage(this, node); + } + + @SuppressWarnings("unchecked") + public SszListSchema getColumnsSchema() { + return (SszListSchema) getFieldSchema2(); + } + + public DataColumnSidecarsByRangeRequestMessage create( + final UInt64 startSlot, final UInt64 count, final List columns) { + return new DataColumnSidecarsByRangeRequestMessage( + this, + SszUInt64.of(startSlot), + SszUInt64.of(count), + (SszUInt64List) + this.getColumnsSchema() + .createFromElements(columns.stream().map(SszUInt64::of).toList())); + } + } + + private DataColumnSidecarsByRangeRequestMessage( + final DataColumnSidecarsByRangeRequestMessageSchema type, final TreeNode backingNode) { + super(type, backingNode); + } + + public DataColumnSidecarsByRangeRequestMessage( + final DataColumnSidecarsByRangeRequestMessageSchema type, + final SszUInt64 startSlot, + final SszUInt64 count, + final SszUInt64List columns) { + super(type, startSlot, count, columns); + } + + public UInt64 getStartSlot() { + return getField0().get(); + } + + public UInt64 getCount() { + return getField1().get(); + } + + public UInt64 getMaxSlot() { + return getStartSlot().plus(getCount()).minusMinZero(1); + } + + public List getColumns() { + return getField2().stream().map(AbstractSszPrimitive::get).toList(); + } + + @Override + public int getMaximumResponseChunks() { + return getCount().intValue() * getColumns().size(); + } +} diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/networking/libp2p/rpc/DataColumnSidecarsByRootRequestMessage.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/networking/libp2p/rpc/DataColumnSidecarsByRootRequestMessage.java new file mode 100644 index 00000000000..d8854dd6f35 --- /dev/null +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/networking/libp2p/rpc/DataColumnSidecarsByRootRequestMessage.java @@ -0,0 +1,44 @@ +/* + * Copyright Consensys Software Inc., 2025 + * + * 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.networking.libp2p.rpc; + +import java.util.List; +import tech.pegasys.teku.infrastructure.ssz.SszList; +import tech.pegasys.teku.infrastructure.ssz.impl.SszListImpl; +import tech.pegasys.teku.infrastructure.ssz.tree.TreeNode; + +public class DataColumnSidecarsByRootRequestMessage extends SszListImpl + implements SszList, RpcRequest { + + public DataColumnSidecarsByRootRequestMessage( + final DataColumnSidecarsByRootRequestMessageSchema schema, + final List dataColumnIdentifiers) { + super(schema, schema.createTreeFromElements(dataColumnIdentifiers)); + } + + DataColumnSidecarsByRootRequestMessage( + final DataColumnSidecarsByRootRequestMessageSchema schema, final TreeNode node) { + super(schema, node); + } + + @Override + public int getMaximumResponseChunks() { + return size(); + } + + @Override + public String toString() { + return "DataColumnSidecarsByRootRequestMessage{" + super.toString() + "}"; + } +} diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/networking/libp2p/rpc/DataColumnSidecarsByRootRequestMessageSchema.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/networking/libp2p/rpc/DataColumnSidecarsByRootRequestMessageSchema.java new file mode 100644 index 00000000000..d7aa219b1a7 --- /dev/null +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/networking/libp2p/rpc/DataColumnSidecarsByRootRequestMessageSchema.java @@ -0,0 +1,31 @@ +/* + * Copyright Consensys Software Inc., 2025 + * + * 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.networking.libp2p.rpc; + +import tech.pegasys.teku.infrastructure.ssz.schema.impl.AbstractSszListSchema; +import tech.pegasys.teku.infrastructure.ssz.tree.TreeNode; +import tech.pegasys.teku.spec.config.SpecConfigFulu; + +public class DataColumnSidecarsByRootRequestMessageSchema + extends AbstractSszListSchema { + + public DataColumnSidecarsByRootRequestMessageSchema(final SpecConfigFulu specConfig) { + super(DataColumnIdentifier.SSZ_SCHEMA, specConfig.getMaxRequestDataColumnSidecars()); + } + + @Override + public DataColumnSidecarsByRootRequestMessage createFromBackingNode(final TreeNode node) { + return new DataColumnSidecarsByRootRequestMessage(this, node); + } +} diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/networking/libp2p/rpc/metadata/MetadataMessage.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/networking/libp2p/rpc/metadata/MetadataMessage.java index 6646a1e065c..9f7df796356 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/networking/libp2p/rpc/metadata/MetadataMessage.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/networking/libp2p/rpc/metadata/MetadataMessage.java @@ -32,4 +32,8 @@ default int getMaximumResponseChunks() { default Optional getOptionalSyncnets() { return Optional.empty(); } + + default Optional getOptionalCustodyGroupCount() { + return Optional.empty(); + } } diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/networking/libp2p/rpc/metadata/MetadataMessageSchema.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/networking/libp2p/rpc/metadata/MetadataMessageSchema.java index 3fd0a1d348b..482c27654d8 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/networking/libp2p/rpc/metadata/MetadataMessageSchema.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/networking/libp2p/rpc/metadata/MetadataMessageSchema.java @@ -13,6 +13,7 @@ package tech.pegasys.teku.spec.datastructures.networking.libp2p.rpc.metadata; +import java.util.Optional; import tech.pegasys.teku.infrastructure.ssz.schema.SszContainerSchema; import tech.pegasys.teku.infrastructure.ssz.tree.TreeNode; import tech.pegasys.teku.infrastructure.unsigned.UInt64; @@ -21,7 +22,11 @@ public interface MetadataMessageSchema extends SszCon @Override T createFromBackingNode(TreeNode node); - T create(UInt64 seqNumber, Iterable attnets, final Iterable syncnets); + T create( + UInt64 seqNumber, + Iterable attnets, + final Iterable syncnets, + final Optional custodyGroupCount); T createDefault(); } diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/networking/libp2p/rpc/metadata/versions/altair/MetadataMessageSchemaAltair.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/networking/libp2p/rpc/metadata/versions/altair/MetadataMessageSchemaAltair.java index 2342d7dd027..6de9eb9bdd0 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/networking/libp2p/rpc/metadata/versions/altair/MetadataMessageSchemaAltair.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/networking/libp2p/rpc/metadata/versions/altair/MetadataMessageSchemaAltair.java @@ -13,6 +13,7 @@ package tech.pegasys.teku.spec.datastructures.networking.libp2p.rpc.metadata.versions.altair; +import java.util.Optional; import tech.pegasys.teku.infrastructure.ssz.collections.SszBitvector; import tech.pegasys.teku.infrastructure.ssz.containers.ContainerSchema3; import tech.pegasys.teku.infrastructure.ssz.primitive.SszUInt64; @@ -39,7 +40,10 @@ public MetadataMessageSchemaAltair(final NetworkingSpecConfig networkingSpecConf @Override public MetadataMessageAltair create( - final UInt64 seqNumber, final Iterable attnets, final Iterable syncnets) { + final UInt64 seqNumber, + final Iterable attnets, + final Iterable syncnets, + final Optional custodyGroupCount) { return new MetadataMessageAltair( this, seqNumber, getAttnestSchema().ofBits(attnets), getSyncnetsSchema().ofBits(syncnets)); } diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/networking/libp2p/rpc/metadata/versions/fulu/MetadataMessageFulu.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/networking/libp2p/rpc/metadata/versions/fulu/MetadataMessageFulu.java new file mode 100644 index 00000000000..ae293c379c7 --- /dev/null +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/networking/libp2p/rpc/metadata/versions/fulu/MetadataMessageFulu.java @@ -0,0 +1,72 @@ +/* + * Copyright Consensys Software Inc., 2025 + * + * 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.networking.libp2p.rpc.metadata.versions.fulu; + +import java.util.Optional; +import tech.pegasys.teku.infrastructure.ssz.collections.SszBitvector; +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.networking.libp2p.rpc.metadata.MetadataMessage; + +public class MetadataMessageFulu + extends Container4 + implements MetadataMessage { + + MetadataMessageFulu(final MetadataMessageSchemaFulu schema) { + super(schema); + } + + MetadataMessageFulu(final MetadataMessageSchemaFulu schema, final TreeNode backingNode) { + super(schema, backingNode); + } + + MetadataMessageFulu( + final MetadataMessageSchemaFulu schema, + final UInt64 seqNumber, + final SszBitvector attNets, + final SszBitvector syncNets, + final UInt64 custodyGroupCount) { + super(schema, SszUInt64.of(seqNumber), attNets, syncNets, SszUInt64.of(custodyGroupCount)); + } + + @Override + public UInt64 getSeqNumber() { + return getField0().get(); + } + + @Override + public SszBitvector getAttnets() { + return getField1(); + } + + public SszBitvector getSyncnets() { + return getField2(); + } + + public UInt64 getCustodyGroupCount() { + return getField3().get(); + } + + @Override + public Optional getOptionalSyncnets() { + return Optional.of(getSyncnets()); + } + + @Override + public Optional getOptionalCustodyGroupCount() { + return Optional.of(getCustodyGroupCount()); + } +} diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/networking/libp2p/rpc/metadata/versions/fulu/MetadataMessageSchemaFulu.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/networking/libp2p/rpc/metadata/versions/fulu/MetadataMessageSchemaFulu.java new file mode 100644 index 00000000000..f63c81c140f --- /dev/null +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/networking/libp2p/rpc/metadata/versions/fulu/MetadataMessageSchemaFulu.java @@ -0,0 +1,73 @@ +/* + * Copyright Consensys Software Inc., 2025 + * + * 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.networking.libp2p.rpc.metadata.versions.fulu; + +import java.util.Optional; +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.SszBitvectorSchema; +import tech.pegasys.teku.infrastructure.ssz.tree.TreeNode; +import tech.pegasys.teku.infrastructure.unsigned.UInt64; +import tech.pegasys.teku.spec.config.NetworkingSpecConfig; +import tech.pegasys.teku.spec.constants.NetworkConstants; +import tech.pegasys.teku.spec.datastructures.networking.libp2p.rpc.metadata.MetadataMessageSchema; + +public class MetadataMessageSchemaFulu + extends ContainerSchema4 + implements MetadataMessageSchema { + public MetadataMessageSchemaFulu(final NetworkingSpecConfig networkingSpecConfig) { + super( + "MetadataMessage", + namedSchema("seq_number", SszPrimitiveSchemas.UINT64_SCHEMA), + namedSchema( + "attnets", SszBitvectorSchema.create(networkingSpecConfig.getAttestationSubnetCount())), + namedSchema( + "syncnets", SszBitvectorSchema.create(NetworkConstants.SYNC_COMMITTEE_SUBNET_COUNT)), + namedSchema("custody_group_count", SszPrimitiveSchemas.UINT64_SCHEMA)); + } + + @Override + public MetadataMessageFulu create( + final UInt64 seqNumber, + final Iterable attnets, + final Iterable syncnets, + final Optional custodyGroupCount) { + return new MetadataMessageFulu( + this, + seqNumber, + getAttnestSchema().ofBits(attnets), + getSyncnetsSchema().ofBits(syncnets), + custodyGroupCount.orElse(UInt64.ZERO)); + } + + @Override + public MetadataMessageFulu createDefault() { + return new MetadataMessageFulu(this); + } + + @Override + public MetadataMessageFulu createFromBackingNode(final TreeNode node) { + return new MetadataMessageFulu(this, node); + } + + private SszBitvectorSchema getAttnestSchema() { + return (SszBitvectorSchema) getFieldSchema1(); + } + + private SszBitvectorSchema getSyncnetsSchema() { + return (SszBitvectorSchema) getFieldSchema2(); + } +} diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/networking/libp2p/rpc/metadata/versions/phase0/MetadataMessageSchemaPhase0.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/networking/libp2p/rpc/metadata/versions/phase0/MetadataMessageSchemaPhase0.java index 117f1dad68c..32528cf9b4f 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/networking/libp2p/rpc/metadata/versions/phase0/MetadataMessageSchemaPhase0.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/networking/libp2p/rpc/metadata/versions/phase0/MetadataMessageSchemaPhase0.java @@ -13,6 +13,7 @@ package tech.pegasys.teku.spec.datastructures.networking.libp2p.rpc.metadata.versions.phase0; +import java.util.Optional; import tech.pegasys.teku.infrastructure.ssz.collections.SszBitvector; import tech.pegasys.teku.infrastructure.ssz.containers.ContainerSchema2; import tech.pegasys.teku.infrastructure.ssz.primitive.SszUInt64; @@ -43,7 +44,10 @@ public MetadataMessagePhase0 createFromBackingNode(final TreeNode node) { @Override public MetadataMessagePhase0 create( - final UInt64 seqNumber, final Iterable attnets, final Iterable syncnets) { + final UInt64 seqNumber, + final Iterable attnets, + final Iterable syncnets, + final Optional custodyGroupCount) { return new MetadataMessagePhase0(this, seqNumber, getAttnestSchema().ofBits(attnets)); } diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/util/DataColumnSlotAndIdentifier.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/util/DataColumnSlotAndIdentifier.java new file mode 100644 index 00000000000..c9752652fe7 --- /dev/null +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/util/DataColumnSlotAndIdentifier.java @@ -0,0 +1,59 @@ +/* + * Copyright Consensys Software Inc., 2025 + * + * 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.util; + +import java.util.Comparator; +import org.apache.tuweni.bytes.Bytes32; +import org.jetbrains.annotations.NotNull; +import tech.pegasys.teku.infrastructure.unsigned.UInt64; +import tech.pegasys.teku.spec.datastructures.blobs.versions.fulu.DataColumnSidecar; +import tech.pegasys.teku.spec.datastructures.blocks.SlotAndBlockRoot; +import tech.pegasys.teku.spec.datastructures.networking.libp2p.rpc.DataColumnIdentifier; + +public record DataColumnSlotAndIdentifier(UInt64 slot, Bytes32 blockRoot, UInt64 columnIndex) + implements Comparable { + + public DataColumnSlotAndIdentifier( + final UInt64 slot, final DataColumnIdentifier dataColumnIdentifier) { + this(slot, dataColumnIdentifier.getBlockRoot(), dataColumnIdentifier.getIndex()); + } + + public static DataColumnSlotAndIdentifier fromDataColumn( + final DataColumnSidecar dataColumnSidecar) { + return new DataColumnSlotAndIdentifier( + dataColumnSidecar.getSlot(), + dataColumnSidecar.getBlockRoot(), + dataColumnSidecar.getIndex()); + } + + public static DataColumnSlotAndIdentifier minimalComparableForSlot(final UInt64 slot) { + return new DataColumnSlotAndIdentifier(slot, Bytes32.ZERO, UInt64.ZERO); + } + + public DataColumnIdentifier toDataColumnIdentifier() { + return new DataColumnIdentifier(blockRoot(), columnIndex()); + } + + public SlotAndBlockRoot getSlotAndBlockRoot() { + return new SlotAndBlockRoot(slot, blockRoot()); + } + + @Override + public int compareTo(@NotNull final DataColumnSlotAndIdentifier o) { + return Comparator.comparing(DataColumnSlotAndIdentifier::slot) + .thenComparing(DataColumnSlotAndIdentifier::blockRoot) + .thenComparing(DataColumnSlotAndIdentifier::columnIndex) + .compare(this, o); + } +} diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/schemas/SchemaDefinitionsFulu.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/schemas/SchemaDefinitionsFulu.java index 723fd9fa824..7b9c96e2172 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/schemas/SchemaDefinitionsFulu.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/schemas/SchemaDefinitionsFulu.java @@ -14,14 +14,44 @@ package tech.pegasys.teku.spec.schemas; import static com.google.common.base.Preconditions.checkArgument; +import static tech.pegasys.teku.spec.schemas.registry.SchemaTypes.CELL_SCHEMA; +import static tech.pegasys.teku.spec.schemas.registry.SchemaTypes.DATA_COLUMN_SCHEMA; +import static tech.pegasys.teku.spec.schemas.registry.SchemaTypes.DATA_COLUMN_SIDECARS_BY_RANGE_REQUEST_MESSAGE_SCHEMA; +import static tech.pegasys.teku.spec.schemas.registry.SchemaTypes.DATA_COLUMN_SIDECARS_BY_ROOT_REQUEST_MESSAGE_SCHEMA; +import static tech.pegasys.teku.spec.schemas.registry.SchemaTypes.DATA_COLUMN_SIDECAR_SCHEMA; +import static tech.pegasys.teku.spec.schemas.registry.SchemaTypes.MATRIX_ENTRY_SCHEMA; import java.util.Optional; +import tech.pegasys.teku.spec.datastructures.blobs.versions.fulu.CellSchema; +import tech.pegasys.teku.spec.datastructures.blobs.versions.fulu.DataColumnSchema; +import tech.pegasys.teku.spec.datastructures.blobs.versions.fulu.DataColumnSidecarSchema; +import tech.pegasys.teku.spec.datastructures.blobs.versions.fulu.MatrixEntrySchema; +import tech.pegasys.teku.spec.datastructures.networking.libp2p.rpc.DataColumnSidecarsByRangeRequestMessage; +import tech.pegasys.teku.spec.datastructures.networking.libp2p.rpc.DataColumnSidecarsByRootRequestMessageSchema; import tech.pegasys.teku.spec.schemas.registry.SchemaRegistry; public class SchemaDefinitionsFulu extends SchemaDefinitionsElectra { + private final CellSchema cellSchema; + private final DataColumnSchema dataColumnSchema; + private final DataColumnSidecarSchema dataColumnSidecarSchema; + private final MatrixEntrySchema matrixEntrySchema; + private final DataColumnSidecarsByRootRequestMessageSchema + dataColumnSidecarsByRootRequestMessageSchema; + private final DataColumnSidecarsByRangeRequestMessage + .DataColumnSidecarsByRangeRequestMessageSchema + dataColumnSidecarsByRangeRequestMessageSchema; + public SchemaDefinitionsFulu(final SchemaRegistry schemaRegistry) { super(schemaRegistry); + this.cellSchema = schemaRegistry.get(CELL_SCHEMA); + this.dataColumnSchema = schemaRegistry.get(DATA_COLUMN_SCHEMA); + this.dataColumnSidecarSchema = schemaRegistry.get(DATA_COLUMN_SIDECAR_SCHEMA); + this.matrixEntrySchema = schemaRegistry.get(MATRIX_ENTRY_SCHEMA); + this.dataColumnSidecarsByRootRequestMessageSchema = + schemaRegistry.get(DATA_COLUMN_SIDECARS_BY_ROOT_REQUEST_MESSAGE_SCHEMA); + this.dataColumnSidecarsByRangeRequestMessageSchema = + schemaRegistry.get(DATA_COLUMN_SIDECARS_BY_RANGE_REQUEST_MESSAGE_SCHEMA); } public static SchemaDefinitionsFulu required(final SchemaDefinitions schemaDefinitions) { @@ -33,6 +63,32 @@ public static SchemaDefinitionsFulu required(final SchemaDefinitions schemaDefin return (SchemaDefinitionsFulu) schemaDefinitions; } + public CellSchema getCellSchema() { + return cellSchema; + } + + public DataColumnSchema getDataColumnSchema() { + return dataColumnSchema; + } + + public DataColumnSidecarSchema getDataColumnSidecarSchema() { + return dataColumnSidecarSchema; + } + + public MatrixEntrySchema getMatrixEntrySchema() { + return matrixEntrySchema; + } + + public DataColumnSidecarsByRootRequestMessageSchema + getDataColumnSidecarsByRootRequestMessageSchema() { + return dataColumnSidecarsByRootRequestMessageSchema; + } + + public DataColumnSidecarsByRangeRequestMessage.DataColumnSidecarsByRangeRequestMessageSchema + getDataColumnSidecarsByRangeRequestMessageSchema() { + return dataColumnSidecarsByRangeRequestMessageSchema; + } + @Override public Optional toVersionFulu() { return Optional.of(this); 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 7b73b6e68c4..d848ecef599 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 @@ -19,6 +19,7 @@ import static tech.pegasys.teku.spec.SpecMilestone.CAPELLA; import static tech.pegasys.teku.spec.SpecMilestone.DENEB; import static tech.pegasys.teku.spec.SpecMilestone.ELECTRA; +import static tech.pegasys.teku.spec.SpecMilestone.FULU; import static tech.pegasys.teku.spec.SpecMilestone.PHASE0; import static tech.pegasys.teku.spec.schemas.registry.BaseSchemaProvider.providerBuilder; import static tech.pegasys.teku.spec.schemas.registry.SchemaTypes.AGGREGATE_AND_PROOF_SCHEMA; @@ -40,7 +41,12 @@ import static tech.pegasys.teku.spec.schemas.registry.SchemaTypes.BLOCK_CONTENTS_SCHEMA; import static tech.pegasys.teku.spec.schemas.registry.SchemaTypes.BLS_TO_EXECUTION_CHANGE_SCHEMA; import static tech.pegasys.teku.spec.schemas.registry.SchemaTypes.BUILDER_BID_SCHEMA; +import static tech.pegasys.teku.spec.schemas.registry.SchemaTypes.CELL_SCHEMA; import static tech.pegasys.teku.spec.schemas.registry.SchemaTypes.CONSOLIDATION_REQUEST_SCHEMA; +import static tech.pegasys.teku.spec.schemas.registry.SchemaTypes.DATA_COLUMN_SCHEMA; +import static tech.pegasys.teku.spec.schemas.registry.SchemaTypes.DATA_COLUMN_SIDECARS_BY_RANGE_REQUEST_MESSAGE_SCHEMA; +import static tech.pegasys.teku.spec.schemas.registry.SchemaTypes.DATA_COLUMN_SIDECARS_BY_ROOT_REQUEST_MESSAGE_SCHEMA; +import static tech.pegasys.teku.spec.schemas.registry.SchemaTypes.DATA_COLUMN_SIDECAR_SCHEMA; import static tech.pegasys.teku.spec.schemas.registry.SchemaTypes.DEPOSIT_REQUEST_SCHEMA; import static tech.pegasys.teku.spec.schemas.registry.SchemaTypes.EXECUTION_PAYLOAD_AND_BLOBS_BUNDLE_SCHEMA; import static tech.pegasys.teku.spec.schemas.registry.SchemaTypes.EXECUTION_PAYLOAD_HEADER_SCHEMA; @@ -49,6 +55,8 @@ import static tech.pegasys.teku.spec.schemas.registry.SchemaTypes.HISTORICAL_BATCH_SCHEMA; import static tech.pegasys.teku.spec.schemas.registry.SchemaTypes.HISTORICAL_SUMMARIES_SCHEMA; import static tech.pegasys.teku.spec.schemas.registry.SchemaTypes.INDEXED_ATTESTATION_SCHEMA; +import static tech.pegasys.teku.spec.schemas.registry.SchemaTypes.MATRIX_ENTRY_SCHEMA; +import static tech.pegasys.teku.spec.schemas.registry.SchemaTypes.METADATA_MESSAGE_SCHEMA; 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; @@ -74,10 +82,15 @@ import tech.pegasys.teku.spec.config.SpecConfigCapella; import tech.pegasys.teku.spec.config.SpecConfigDeneb; import tech.pegasys.teku.spec.config.SpecConfigElectra; +import tech.pegasys.teku.spec.config.SpecConfigFulu; import tech.pegasys.teku.spec.constants.NetworkConstants; import tech.pegasys.teku.spec.datastructures.blobs.versions.deneb.BlobKzgCommitmentsSchema; import tech.pegasys.teku.spec.datastructures.blobs.versions.deneb.BlobSchema; import tech.pegasys.teku.spec.datastructures.blobs.versions.deneb.BlobSidecarSchema; +import tech.pegasys.teku.spec.datastructures.blobs.versions.fulu.CellSchema; +import tech.pegasys.teku.spec.datastructures.blobs.versions.fulu.DataColumnSchema; +import tech.pegasys.teku.spec.datastructures.blobs.versions.fulu.DataColumnSidecarSchema; +import tech.pegasys.teku.spec.datastructures.blobs.versions.fulu.MatrixEntrySchema; import tech.pegasys.teku.spec.datastructures.blocks.BeaconBlockSchema; import tech.pegasys.teku.spec.datastructures.blocks.SignedBeaconBlockHeader; import tech.pegasys.teku.spec.datastructures.blocks.SignedBeaconBlockSchema; @@ -112,6 +125,11 @@ import tech.pegasys.teku.spec.datastructures.execution.versions.electra.WithdrawalRequestSchema; import tech.pegasys.teku.spec.datastructures.networking.libp2p.rpc.BeaconBlocksByRootRequestMessage.BeaconBlocksByRootRequestMessageSchema; import tech.pegasys.teku.spec.datastructures.networking.libp2p.rpc.BlobSidecarsByRootRequestMessageSchema; +import tech.pegasys.teku.spec.datastructures.networking.libp2p.rpc.DataColumnSidecarsByRangeRequestMessage; +import tech.pegasys.teku.spec.datastructures.networking.libp2p.rpc.DataColumnSidecarsByRootRequestMessageSchema; +import tech.pegasys.teku.spec.datastructures.networking.libp2p.rpc.metadata.versions.altair.MetadataMessageSchemaAltair; +import tech.pegasys.teku.spec.datastructures.networking.libp2p.rpc.metadata.versions.fulu.MetadataMessageSchemaFulu; +import tech.pegasys.teku.spec.datastructures.networking.libp2p.rpc.metadata.versions.phase0.MetadataMessageSchemaPhase0; import tech.pegasys.teku.spec.datastructures.operations.AggregateAndProof.AggregateAndProofSchema; import tech.pegasys.teku.spec.datastructures.operations.AttesterSlashingSchema; import tech.pegasys.teku.spec.datastructures.operations.BlsToExecutionChangeSchema; @@ -156,6 +174,7 @@ public static SchemaRegistryBuilder create() { .addProvider(createBeaconBlockSchemaProvider()) .addProvider(createSignedBeaconBlockSchemaProvider()) .addProvider(createBeaconStateSchemaProvider()) + .addProvider(createMetadataMessageSchemaProvider()) // BELLATRIX .addProvider(createExecutionPayloadSchemaProvider()) @@ -191,7 +210,15 @@ public static SchemaRegistryBuilder create() { .addProvider(createWithdrawalRequestSchemaProvider()) .addProvider(createConsolidationRequestSchemaProvider()) .addProvider(createExecutionRequestsSchemaProvider()) - .addProvider(createSingleAttestationSchemaProvider()); + .addProvider(createSingleAttestationSchemaProvider()) + + // FULU + .addProvider(createCellSchemaProvider()) + .addProvider(createDataColumnSchemaProvider()) + .addProvider(createDataColumnSidecarSchemaProvider()) + .addProvider(createMatrixEntrySchemaProvider()) + .addProvider(createDataColumnSidecarsByRootRequestMessageSchemaProvider()) + .addProvider(createDataColumnSidecarsByRangeRequestMessageSchemaProvider()); } private static SchemaProvider createSingleAttestationSchemaProvider() { @@ -664,6 +691,81 @@ private static SchemaProvider createSignedAggregateAndProofSchemaProvider() { .build(); } + private static SchemaProvider createCellSchemaProvider() { + return providerBuilder(CELL_SCHEMA) + .withCreator( + FULU, + (registry, specConfig, schemaName) -> + new CellSchema(SpecConfigFulu.required(specConfig))) + .build(); + } + + private static SchemaProvider createDataColumnSchemaProvider() { + return providerBuilder(DATA_COLUMN_SCHEMA) + .withCreator( + FULU, + (registry, specConfig, schemaName) -> + new DataColumnSchema(SpecConfigDeneb.required(specConfig), registry)) + .build(); + } + + private static SchemaProvider createDataColumnSidecarSchemaProvider() { + return providerBuilder(DATA_COLUMN_SIDECAR_SCHEMA) + .withCreator( + FULU, + (registry, specConfig, schemaName) -> + DataColumnSidecarSchema.create( + SignedBeaconBlockHeader.SSZ_SCHEMA, + registry.get(DATA_COLUMN_SCHEMA), + SpecConfigFulu.required(specConfig))) + .build(); + } + + private static SchemaProvider createMatrixEntrySchemaProvider() { + return providerBuilder(MATRIX_ENTRY_SCHEMA) + .withCreator( + FULU, + (registry, specConfig, schemaName) -> + MatrixEntrySchema.create(registry.get(CELL_SCHEMA))) + .build(); + } + + private static SchemaProvider createDataColumnSidecarsByRootRequestMessageSchemaProvider() { + return providerBuilder(DATA_COLUMN_SIDECARS_BY_ROOT_REQUEST_MESSAGE_SCHEMA) + .withCreator( + FULU, + (registry, specConfig, schemaName) -> + new DataColumnSidecarsByRootRequestMessageSchema( + SpecConfigFulu.required(specConfig))) + .build(); + } + + private static SchemaProvider createDataColumnSidecarsByRangeRequestMessageSchemaProvider() { + return providerBuilder(DATA_COLUMN_SIDECARS_BY_RANGE_REQUEST_MESSAGE_SCHEMA) + .withCreator( + FULU, + (registry, specConfig, schemaName) -> + new DataColumnSidecarsByRangeRequestMessage + .DataColumnSidecarsByRangeRequestMessageSchema( + SpecConfigFulu.required(specConfig))) + .build(); + } + + private static SchemaProvider createMetadataMessageSchemaProvider() { + return providerBuilder(METADATA_MESSAGE_SCHEMA) + .withCreator( + PHASE0, + (registry, specConfig, schemaName) -> + new MetadataMessageSchemaPhase0(specConfig.getNetworkingConfig())) + .withCreator( + ALTAIR, + (registry, specConfig, schemaName) -> + new MetadataMessageSchemaAltair(specConfig.getNetworkingConfig())) + .withCreator( + FULU, (registry, specConfig, schemaName) -> new MetadataMessageSchemaFulu(specConfig)) + .build(); + } + private static long getMaxValidatorsPerAttestationPhase0(final SpecConfig specConfig) { return specConfig.getMaxValidatorsPerCommittee(); } 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 e2f5bc23d34..dd080b9bee8 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 @@ -27,6 +27,10 @@ import tech.pegasys.teku.spec.datastructures.blobs.versions.deneb.BlobKzgCommitmentsSchema; import tech.pegasys.teku.spec.datastructures.blobs.versions.deneb.BlobSchema; import tech.pegasys.teku.spec.datastructures.blobs.versions.deneb.BlobSidecarSchema; +import tech.pegasys.teku.spec.datastructures.blobs.versions.fulu.CellSchema; +import tech.pegasys.teku.spec.datastructures.blobs.versions.fulu.DataColumnSchema; +import tech.pegasys.teku.spec.datastructures.blobs.versions.fulu.DataColumnSidecarSchema; +import tech.pegasys.teku.spec.datastructures.blobs.versions.fulu.MatrixEntrySchema; import tech.pegasys.teku.spec.datastructures.blocks.BeaconBlockSchema; import tech.pegasys.teku.spec.datastructures.blocks.SignedBeaconBlockSchema; import tech.pegasys.teku.spec.datastructures.blocks.blockbody.BeaconBlockBody; @@ -51,6 +55,9 @@ import tech.pegasys.teku.spec.datastructures.execution.versions.electra.WithdrawalRequestSchema; import tech.pegasys.teku.spec.datastructures.networking.libp2p.rpc.BeaconBlocksByRootRequestMessage.BeaconBlocksByRootRequestMessageSchema; import tech.pegasys.teku.spec.datastructures.networking.libp2p.rpc.BlobSidecarsByRootRequestMessageSchema; +import tech.pegasys.teku.spec.datastructures.networking.libp2p.rpc.DataColumnSidecarsByRangeRequestMessage; +import tech.pegasys.teku.spec.datastructures.networking.libp2p.rpc.DataColumnSidecarsByRootRequestMessageSchema; +import tech.pegasys.teku.spec.datastructures.networking.libp2p.rpc.metadata.MetadataMessageSchema; import tech.pegasys.teku.spec.datastructures.operations.AggregateAndProof.AggregateAndProofSchema; import tech.pegasys.teku.spec.datastructures.operations.Attestation; import tech.pegasys.teku.spec.datastructures.operations.AttestationSchema; @@ -103,6 +110,8 @@ public class SchemaTypes { public static final SchemaId< BeaconStateSchema> BEACON_STATE_SCHEMA = create("BEACON_STATE_SCHEMA"); + public static final SchemaId> METADATA_MESSAGE_SCHEMA = + create("METADATA_MESSAGE_SCHEMA"); // Altair @@ -173,6 +182,21 @@ public class SchemaTypes { public static final SchemaId SINGLE_ATTESTATION_SCHEMA = create("SINGLE_ATTESTATION_SCHEMA"); + // Fulu + public static final SchemaId CELL_SCHEMA = create("CELL_SCHEMA"); + public static final SchemaId DATA_COLUMN_SCHEMA = create("DATA_COLUMN_SCHEMA"); + public static final SchemaId DATA_COLUMN_SIDECAR_SCHEMA = + create("DATA_COLUMN_SIDECAR_SCHEMA"); + public static final SchemaId MATRIX_ENTRY_SCHEMA = + create("MATRIX_ENTRY_SCHEMA"); + public static final SchemaId + DATA_COLUMN_SIDECARS_BY_ROOT_REQUEST_MESSAGE_SCHEMA = + create("DATA_COLUMN_SIDECARS_BY_ROOT_REQUEST_MESSAGE_SCHEMA"); + public static final SchemaId< + DataColumnSidecarsByRangeRequestMessage.DataColumnSidecarsByRangeRequestMessageSchema> + DATA_COLUMN_SIDECARS_BY_RANGE_REQUEST_MESSAGE_SCHEMA = + create("DATA_COLUMN_SIDECARS_BY_RANGE_REQUEST_MESSAGE_SCHEMA"); + private SchemaTypes() { // Prevent instantiation } diff --git a/ethereum/spec/src/test/java/tech/pegasys/teku/spec/datastructures/networking/libp2p/rpc/MetadataMessageTest.java b/ethereum/spec/src/test/java/tech/pegasys/teku/spec/datastructures/networking/libp2p/rpc/MetadataMessageTest.java index 46fdbce83e9..fa668460e66 100644 --- a/ethereum/spec/src/test/java/tech/pegasys/teku/spec/datastructures/networking/libp2p/rpc/MetadataMessageTest.java +++ b/ethereum/spec/src/test/java/tech/pegasys/teku/spec/datastructures/networking/libp2p/rpc/MetadataMessageTest.java @@ -19,6 +19,7 @@ import it.unimi.dsi.fastutil.ints.IntList; import java.util.Collections; +import java.util.Optional; import org.apache.tuweni.bytes.Bytes; import org.junit.jupiter.api.Test; import tech.pegasys.teku.infrastructure.unsigned.UInt64; @@ -38,7 +39,8 @@ class MetadataMessageTest { new MetadataMessageSchemaAltair(spec.getNetworkingConfig()); private final Bytes expectedSsz = Bytes.fromHexString("0x23000000000000000100000000000080"); private final MetadataMessage message = - phase0Schema.create(UInt64.valueOf(0x23), IntList.of(0, 63), Collections.emptyList()); + phase0Schema.create( + UInt64.valueOf(0x23), IntList.of(0, 63), Collections.emptyList(), Optional.empty()); @Test public void shouldSerializeToSsz() { @@ -59,7 +61,8 @@ public void shouldRejectOutOfBoundsAttnets() { phase0Schema.create( UInt64.valueOf(15), IntList.of(spec.getNetworkingConfig().getAttestationSubnetCount()), - Collections.emptyList())) + Collections.emptyList(), + Optional.empty())) .isInstanceOf(IndexOutOfBoundsException.class); } @@ -70,7 +73,8 @@ public void shouldRejectOutOfBoundsSyncnets() { altairSchema.create( UInt64.valueOf(15), Collections.emptyList(), - IntList.of(NetworkConstants.SYNC_COMMITTEE_SUBNET_COUNT))) + IntList.of(NetworkConstants.SYNC_COMMITTEE_SUBNET_COUNT), + Optional.empty())) .isInstanceOf(IndexOutOfBoundsException.class); } } diff --git a/infrastructure/logging/src/main/java/tech/pegasys/teku/infrastructure/logging/LogFormatter.java b/infrastructure/logging/src/main/java/tech/pegasys/teku/infrastructure/logging/LogFormatter.java index 54bf0f413ed..8a9b535569d 100644 --- a/infrastructure/logging/src/main/java/tech/pegasys/teku/infrastructure/logging/LogFormatter.java +++ b/infrastructure/logging/src/main/java/tech/pegasys/teku/infrastructure/logging/LogFormatter.java @@ -41,4 +41,16 @@ public static String formatBlobSidecar( "block %s (%s), index %s, blob %s, commitment %s, proof %s", formatAbbreviatedHashRoot(blockRoot), slot, index, blob, kzgCommitment, kzgProof); } + + public static String formatDataColumnSidecar( + final UInt64 slot, + final Bytes32 blockRoot, + final UInt64 index, + final String blob, + final int kzgCommitmentsSize, + final int kzgProofsSize) { + return String.format( + "DataColumnSidecar[block %s (%s), index %s, 1st cell %s, commitments %s, proofs %s]", + formatAbbreviatedHashRoot(blockRoot), slot, index, blob, kzgCommitmentsSize, kzgProofsSize); + } } diff --git a/infrastructure/ssz/src/main/java/tech/pegasys/teku/infrastructure/ssz/schema/collections/impl/SszByteVectorSchemaImpl.java b/infrastructure/ssz/src/main/java/tech/pegasys/teku/infrastructure/ssz/schema/collections/impl/SszByteVectorSchemaImpl.java index f6f223dd72c..0e516f7f393 100644 --- a/infrastructure/ssz/src/main/java/tech/pegasys/teku/infrastructure/ssz/schema/collections/impl/SszByteVectorSchemaImpl.java +++ b/infrastructure/ssz/src/main/java/tech/pegasys/teku/infrastructure/ssz/schema/collections/impl/SszByteVectorSchemaImpl.java @@ -38,6 +38,10 @@ public SszByteVectorSchemaImpl( super(elementSchema, vectorLength); } + public SszByteVectorSchemaImpl(final long vectorLength) { + this(SszPrimitiveSchemas.BYTE_SCHEMA, vectorLength); + } + @Override protected DeserializableTypeDefinition createTypeDefinition() { return getElementSchema().equals(SszPrimitiveSchemas.BYTE_SCHEMA) diff --git a/networking/eth2/src/main/java/tech/pegasys/teku/networking/eth2/rpc/beaconchain/methods/MetadataMessagesFactory.java b/networking/eth2/src/main/java/tech/pegasys/teku/networking/eth2/rpc/beaconchain/methods/MetadataMessagesFactory.java index 32169a12065..da80176571a 100644 --- a/networking/eth2/src/main/java/tech/pegasys/teku/networking/eth2/rpc/beaconchain/methods/MetadataMessagesFactory.java +++ b/networking/eth2/src/main/java/tech/pegasys/teku/networking/eth2/rpc/beaconchain/methods/MetadataMessagesFactory.java @@ -14,17 +14,23 @@ package tech.pegasys.teku.networking.eth2.rpc.beaconchain.methods; import java.util.Collections; +import java.util.Optional; import java.util.concurrent.atomic.AtomicLong; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import tech.pegasys.teku.infrastructure.unsigned.UInt64; import tech.pegasys.teku.spec.datastructures.networking.libp2p.rpc.PingMessage; import tech.pegasys.teku.spec.datastructures.networking.libp2p.rpc.metadata.MetadataMessage; import tech.pegasys.teku.spec.datastructures.networking.libp2p.rpc.metadata.MetadataMessageSchema; public class MetadataMessagesFactory { + private static final Logger LOG = LogManager.getLogger(); private final AtomicLong seqNumberGenerator = new AtomicLong(0L); private Iterable attestationSubnetIds = Collections.emptyList(); private Iterable syncCommitteeSubnetIds = Collections.emptyList(); + // TODO-fulu update with Fulu networking-related changes (CustodyGroupCountChannel) + private final Optional custodyGroupCount = Optional.empty(); public synchronized void updateAttestationSubnetIds( final Iterable attestationSubnetIds) { @@ -43,7 +49,11 @@ private void handleUpdate() { } public synchronized MetadataMessage createMetadataMessage(final MetadataMessageSchema schema) { - return schema.create(getCurrentSeqNumber(), attestationSubnetIds, syncCommitteeSubnetIds); + final MetadataMessage metadataMessage = + schema.create( + getCurrentSeqNumber(), attestationSubnetIds, syncCommitteeSubnetIds, custodyGroupCount); + LOG.debug("Created metadata message {}", metadataMessage); + return metadataMessage; } public PingMessage createPingMessage() {