From 85e774e08acb5dd7858f7cbad95ef7e1eca99364 Mon Sep 17 00:00:00 2001 From: Stefan Bratanov Date: Tue, 10 Sep 2024 09:57:35 +0300 Subject: [PATCH] few more fixes --- ...ergedGenesisInteropModeAcceptanceTest.java | 6 ++ .../acceptance/dsl/TekuNodeConfigBuilder.java | 12 +++ .../BlockOperationSelectorFactory.java | 35 ++++++++ .../v3/validator/GetNewBlockV3Test.java | 9 ++- .../ExecutionPayloadHeaderEip7732.java | 3 +- .../BeaconBlockBodyBuilderEip7732.java | 10 +++ .../eip7732/BeaconBlockBodyEip7732.java | 11 +++ .../execution/ExpectedWithdrawals.java | 5 +- .../eip7732/block/BlockProcessorEip7732.java | 8 ++ .../schemas/SchemaDefinitionsEip7732.java | 6 ++ .../teku/spec/signatures/DeletableSigner.java | 7 ++ .../teku/spec/signatures/LocalSigner.java | 8 ++ .../pegasys/teku/spec/signatures/Signer.java | 4 + .../teku/spec/signatures/SigningRootUtil.java | 15 ++++ .../signatures/SlashingProtectedSigner.java | 7 ++ .../spec/generator/BlockProposalTestUtil.java | 81 +++++++++++++++++++ .../spec/generator/signatures/NoOpSigner.java | 7 ++ .../teku/spec/util/DataStructureUtil.java | 17 +++- .../client/signer/ExternalSigner.java | 7 ++ 19 files changed, 252 insertions(+), 6 deletions(-) diff --git a/acceptance-tests/src/acceptance-test/java/tech/pegasys/teku/test/acceptance/MergedGenesisInteropModeAcceptanceTest.java b/acceptance-tests/src/acceptance-test/java/tech/pegasys/teku/test/acceptance/MergedGenesisInteropModeAcceptanceTest.java index f9176de6494..a671519d6f5 100644 --- a/acceptance-tests/src/acceptance-test/java/tech/pegasys/teku/test/acceptance/MergedGenesisInteropModeAcceptanceTest.java +++ b/acceptance-tests/src/acceptance-test/java/tech/pegasys/teku/test/acceptance/MergedGenesisInteropModeAcceptanceTest.java @@ -91,6 +91,12 @@ private static TekuNodeConfigBuilder createTekuNodeBuilderForMilestone( tekuNodeConfigBuilder.withDenebEpoch(UInt64.ZERO); tekuNodeConfigBuilder.withElectraEpoch(UInt64.ZERO); break; + case EIP7732: + tekuNodeConfigBuilder.withCapellaEpoch(UInt64.ZERO); + tekuNodeConfigBuilder.withDenebEpoch(UInt64.ZERO); + tekuNodeConfigBuilder.withElectraEpoch(UInt64.ZERO); + tekuNodeConfigBuilder.withEip7732Epoch(UInt64.ZERO); + break; default: // Test will reach this whenever a new milestone is added and isn't mapped on the switch. // This is a way to force us to always remember to validate that a new milestone can start diff --git a/acceptance-tests/src/testFixtures/java/tech/pegasys/teku/test/acceptance/dsl/TekuNodeConfigBuilder.java b/acceptance-tests/src/testFixtures/java/tech/pegasys/teku/test/acceptance/dsl/TekuNodeConfigBuilder.java index b1947a653be..7d27007e5a4 100644 --- a/acceptance-tests/src/testFixtures/java/tech/pegasys/teku/test/acceptance/dsl/TekuNodeConfigBuilder.java +++ b/acceptance-tests/src/testFixtures/java/tech/pegasys/teku/test/acceptance/dsl/TekuNodeConfigBuilder.java @@ -170,6 +170,18 @@ public TekuNodeConfigBuilder withElectraEpoch(final UInt64 electraForkEpoch) { return this; } + public TekuNodeConfigBuilder withEip7732Epoch(final UInt64 eip7732ForkEpoch) { + mustBe(NodeType.BEACON_NODE); + LOG.debug("Xnetwork-eip7732-fork-epoch={}", eip7732ForkEpoch); + configMap.put("Xnetwork-eip7732-fork-epoch", eip7732ForkEpoch.toString()); + specConfigModifier = + specConfigModifier.andThen( + specConfigBuilder -> + specConfigBuilder.eip7732Builder( + eip7732Builder -> eip7732Builder.eip7732ForkEpoch(eip7732ForkEpoch))); + return this; + } + public TekuNodeConfigBuilder withTrustedSetupFromClasspath(final String trustedSetup) throws Exception { mustBe(NodeType.BEACON_NODE); diff --git a/beacon/validator/src/main/java/tech/pegasys/teku/validator/coordinator/BlockOperationSelectorFactory.java b/beacon/validator/src/main/java/tech/pegasys/teku/validator/coordinator/BlockOperationSelectorFactory.java index be7cc850166..67eabc09915 100644 --- a/beacon/validator/src/main/java/tech/pegasys/teku/validator/coordinator/BlockOperationSelectorFactory.java +++ b/beacon/validator/src/main/java/tech/pegasys/teku/validator/coordinator/BlockOperationSelectorFactory.java @@ -63,6 +63,7 @@ import tech.pegasys.teku.spec.schemas.SchemaDefinitions; import tech.pegasys.teku.spec.schemas.SchemaDefinitionsBellatrix; import tech.pegasys.teku.spec.schemas.SchemaDefinitionsDeneb; +import tech.pegasys.teku.spec.schemas.SchemaDefinitionsEip7732; import tech.pegasys.teku.statetransition.OperationPool; import tech.pegasys.teku.statetransition.attestation.AggregatingAttestationPool; import tech.pegasys.teku.statetransition.attestation.AttestationForkChecker; @@ -180,6 +181,7 @@ public Function> createSelector( // In `setExecutionData` the following fields are set: // Post-Bellatrix: Execution Payload / Execution Payload Header // Post-Deneb: KZG Commitments + // Post-ePBS: Signed Execution Payload Header if (bodyBuilder.supportsExecutionPayload()) { blockProductionComplete = forkChoiceNotifier @@ -224,6 +226,35 @@ private SafeFuture setExecutionData( return SafeFuture.COMPLETE; } + // ePBS (TODO: placeholder) also the whole flow requires refactor + if (bodyBuilder.supportsSignedExecutionPayloadHeader()) { + final SchemaDefinitionsEip7732 schemaDefinitionsEip7732 = + SchemaDefinitionsEip7732.required(schemaDefinitions); + final ExecutionPayloadHeader emptyHeader = + schemaDefinitions + .getExecutionPayloadHeaderSchema() + .createExecutionPayloadHeader( + builder -> + builder + .parentBlockHash(() -> Bytes32.ZERO) + .parentBlockRoot(() -> Bytes32.ZERO) + .blockHash(Bytes32.ZERO) + .gasLimit(UInt64.ZERO) + .builderIndex(() -> UInt64.ZERO) + .slot(() -> UInt64.ZERO) + .value(() -> UInt64.ZERO) + .blobKzgCommitmentsRoot(() -> Bytes32.ZERO)); + // empty signed header + bodyBuilder.signedExecutionPayloadHeader( + schemaDefinitionsEip7732 + .getSignedExecutionPayloadHeaderSchema() + .create(emptyHeader, BLSSignature.empty())); + // empty list + bodyBuilder.payloadAttestations( + schemaDefinitionsEip7732.getPayloadAttestationsSchema().createFromElements(List.of())); + return SafeFuture.COMPLETE; + } + // We should run Builder flow (blinded) only if we have a validator registration final boolean shouldTryBuilderFlow = executionPayloadContext @@ -296,6 +327,10 @@ private SafeFuture setKzgCommitments( if (!bodyBuilder.supportsKzgCommitments()) { return SafeFuture.COMPLETE; } + // ePBS (no blob kzg commitments in block) + if (bodyBuilder.supportsSignedExecutionPayloadHeader()) { + return SafeFuture.COMPLETE; + } final BlobKzgCommitmentsSchema blobKzgCommitmentsSchema = SchemaDefinitionsDeneb.required(schemaDefinitions).getBlobKzgCommitmentsSchema(); final SafeFuture> blobKzgCommitments; diff --git a/data/beaconrestapi/src/test/java/tech/pegasys/teku/beaconrestapi/handlers/v3/validator/GetNewBlockV3Test.java b/data/beaconrestapi/src/test/java/tech/pegasys/teku/beaconrestapi/handlers/v3/validator/GetNewBlockV3Test.java index 1e422952048..521470b6623 100644 --- a/data/beaconrestapi/src/test/java/tech/pegasys/teku/beaconrestapi/handlers/v3/validator/GetNewBlockV3Test.java +++ b/data/beaconrestapi/src/test/java/tech/pegasys/teku/beaconrestapi/handlers/v3/validator/GetNewBlockV3Test.java @@ -78,8 +78,15 @@ void shouldHandleBlindedBeaconBlocks() throws Exception { assertThat(request.getResponseBody()).isEqualTo(blockContainerAndMetaData); assertThat(request.getResponseHeaders(HEADER_CONSENSUS_VERSION)) .isEqualTo(Version.fromMilestone(blockContainerAndMetaData.specMilestone()).name()); + final boolean expectedHeaderExecutionPayloadBlinded; + if (specMilestone.isGreaterThanOrEqualTo(SpecMilestone.EIP7732)) { + // no blind/unblind concept in ePBS + expectedHeaderExecutionPayloadBlinded = false; + } else { + expectedHeaderExecutionPayloadBlinded = true; + } assertThat(request.getResponseHeaders(HEADER_EXECUTION_PAYLOAD_BLINDED)) - .isEqualTo(Boolean.toString(true)); + .isEqualTo(Boolean.toString(expectedHeaderExecutionPayloadBlinded)); assertThat(request.getResponseHeaders(HEADER_EXECUTION_PAYLOAD_VALUE)) .isEqualTo(blockContainerAndMetaData.executionPayloadValue().toDecimalString()); assertThat(request.getResponseHeaders(HEADER_CONSENSUS_BLOCK_VALUE)) diff --git a/data/serializer/src/main/java/tech/pegasys/teku/api/schema/eip7732/ExecutionPayloadHeaderEip7732.java b/data/serializer/src/main/java/tech/pegasys/teku/api/schema/eip7732/ExecutionPayloadHeaderEip7732.java index fd88d540eb2..b8e9e382571 100644 --- a/data/serializer/src/main/java/tech/pegasys/teku/api/schema/eip7732/ExecutionPayloadHeaderEip7732.java +++ b/data/serializer/src/main/java/tech/pegasys/teku/api/schema/eip7732/ExecutionPayloadHeaderEip7732.java @@ -98,7 +98,8 @@ public ExecutionPayloadHeaderEip7732( } public ExecutionPayloadHeaderEip7732( - tech.pegasys.teku.spec.datastructures.execution.versions.eip7732.ExecutionPayloadHeaderEip7732 + final tech.pegasys.teku.spec.datastructures.execution.versions.eip7732 + .ExecutionPayloadHeaderEip7732 executionPayloadHeader) { this( executionPayloadHeader.getParentBlockHash(), diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/versions/eip7732/BeaconBlockBodyBuilderEip7732.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/versions/eip7732/BeaconBlockBodyBuilderEip7732.java index 29c779fee9f..5b3b4a41064 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/versions/eip7732/BeaconBlockBodyBuilderEip7732.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/versions/eip7732/BeaconBlockBodyBuilderEip7732.java @@ -35,6 +35,16 @@ public BeaconBlockBodyBuilderEip7732( super(schema, null); } + @Override + public Boolean supportsExecutionPayload() { + return false; + } + + @Override + public Boolean supportsKzgCommitments() { + return false; + } + @Override public Boolean supportsSignedExecutionPayloadHeader() { return true; diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/versions/eip7732/BeaconBlockBodyEip7732.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/versions/eip7732/BeaconBlockBodyEip7732.java index be9cfacd611..5a0c9477bb5 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/versions/eip7732/BeaconBlockBodyEip7732.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/versions/eip7732/BeaconBlockBodyEip7732.java @@ -17,6 +17,7 @@ import tech.pegasys.teku.infrastructure.ssz.SszList; import tech.pegasys.teku.spec.datastructures.blocks.blockbody.BeaconBlockBody; import tech.pegasys.teku.spec.datastructures.blocks.blockbody.versions.electra.BeaconBlockBodyElectra; +import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayload; import tech.pegasys.teku.spec.datastructures.execution.SignedExecutionPayloadHeader; import tech.pegasys.teku.spec.datastructures.execution.versions.electra.ExecutionPayloadElectra; import tech.pegasys.teku.spec.datastructures.operations.PayloadAttestation; @@ -38,6 +39,16 @@ static BeaconBlockBodyEip7732 required(final BeaconBlockBody body) { SszList getPayloadAttestations(); + @Override + default Optional getOptionalExecutionPayload() { + return Optional.empty(); + } + + @Override + default Optional> getOptionalBlobKzgCommitments() { + return Optional.empty(); + } + @Override default Optional getOptionalSignedExecutionPayloadHeader() { return Optional.of(getSignedExecutionPayloadHeader()); diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/ExpectedWithdrawals.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/ExpectedWithdrawals.java index 0d70afb7eff..8c46bc6de7a 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/ExpectedWithdrawals.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/ExpectedWithdrawals.java @@ -269,7 +269,10 @@ public void processWithdrawals( final SszList expectedWithdrawals = getExpectedWithdrawalsSszList(schemaDefinitionsCapella); - assertWithdrawalsInExecutionPayloadMatchExpected(payloadSummary, expectedWithdrawals); + // EIP7732 TODO: hacky (requires refactor) + if (genericState.toVersionEip7732().isEmpty()) { + assertWithdrawalsInExecutionPayloadMatchExpected(payloadSummary, expectedWithdrawals); + } processWithdrawalsUnchecked( genericState, schemaDefinitionsCapella, beaconStateMutators, specConfigCapella); diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/eip7732/block/BlockProcessorEip7732.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/eip7732/block/BlockProcessorEip7732.java index a93d8f7a05e..6ccf2933b2d 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/eip7732/block/BlockProcessorEip7732.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/eip7732/block/BlockProcessorEip7732.java @@ -34,6 +34,7 @@ import tech.pegasys.teku.spec.datastructures.blocks.blockbody.BeaconBlockBody; import tech.pegasys.teku.spec.datastructures.blocks.blockbody.versions.eip7732.BeaconBlockBodyEip7732; import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayload; +import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadHeader; import tech.pegasys.teku.spec.datastructures.execution.SignedExecutionPayloadHeader; import tech.pegasys.teku.spec.datastructures.execution.versions.eip7732.ExecutionPayloadHeaderEip7732; import tech.pegasys.teku.spec.datastructures.operations.IndexedPayloadAttestation; @@ -284,6 +285,13 @@ public void processExecutionPayload( // Removed in EIP-7732 } + @Override + public ExecutionPayloadHeader extractExecutionPayloadHeader(final BeaconBlockBody beaconBlockBody) + throws BlockProcessingException { + // Removed in EIP-7732 (only required for withdrawals validation against the state) + return null; + } + @Override protected void processDepositRequests( final MutableBeaconState state, final Optional executionPayload) diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/schemas/SchemaDefinitionsEip7732.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/schemas/SchemaDefinitionsEip7732.java index 4c96b831fe5..372e02d3d52 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/schemas/SchemaDefinitionsEip7732.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/schemas/SchemaDefinitionsEip7732.java @@ -16,6 +16,7 @@ import static com.google.common.base.Preconditions.checkArgument; import java.util.Optional; +import tech.pegasys.teku.infrastructure.ssz.schema.SszListSchema; import tech.pegasys.teku.spec.config.SpecConfigEip7732; import tech.pegasys.teku.spec.datastructures.blobs.versions.deneb.BlobSidecarSchema; import tech.pegasys.teku.spec.datastructures.blocks.BeaconBlockSchema; @@ -48,6 +49,7 @@ import tech.pegasys.teku.spec.datastructures.operations.AggregateAndProof.AggregateAndProofSchema; import tech.pegasys.teku.spec.datastructures.operations.AttestationSchema; import tech.pegasys.teku.spec.datastructures.operations.IndexedPayloadAttestationSchema; +import tech.pegasys.teku.spec.datastructures.operations.PayloadAttestation; import tech.pegasys.teku.spec.datastructures.operations.PayloadAttestationMessageSchema; import tech.pegasys.teku.spec.datastructures.operations.PayloadAttestationSchema; import tech.pegasys.teku.spec.datastructures.operations.SignedAggregateAndProof.SignedAggregateAndProofSchema; @@ -322,6 +324,10 @@ public PayloadAttestationMessageSchema getPayloadAttestationMessageSchema() { return payloadAttestationMessageSchema; } + public SszListSchema getPayloadAttestationsSchema() { + return beaconBlockBodySchema.getPayloadAttestationsSchema(); + } + @Override public Optional toVersionEip7732() { return Optional.of(this); diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/signatures/DeletableSigner.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/signatures/DeletableSigner.java index cc1b6a96764..d6a3a86ceb1 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/signatures/DeletableSigner.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/signatures/DeletableSigner.java @@ -25,6 +25,7 @@ import tech.pegasys.teku.infrastructure.unsigned.UInt64; import tech.pegasys.teku.spec.datastructures.blocks.BeaconBlock; import tech.pegasys.teku.spec.datastructures.builder.ValidatorRegistration; +import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadHeader; import tech.pegasys.teku.spec.datastructures.operations.AggregateAndProof; import tech.pegasys.teku.spec.datastructures.operations.AttestationData; import tech.pegasys.teku.spec.datastructures.operations.PayloadAttestationData; @@ -117,6 +118,12 @@ public SafeFuture signValidatorRegistration( return sign(() -> delegate.signValidatorRegistration(validatorRegistration)); } + @Override + public SafeFuture signExecutionPayloadHeader( + final ExecutionPayloadHeader executionPayloadHeader, final ForkInfo forkInfo) { + return sign(() -> delegate.signExecutionPayloadHeader(executionPayloadHeader, forkInfo)); + } + @Override public Optional getSigningServiceUrl() { return delegate.getSigningServiceUrl(); diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/signatures/LocalSigner.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/signatures/LocalSigner.java index 8958737f5a2..d256c91c577 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/signatures/LocalSigner.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/signatures/LocalSigner.java @@ -27,6 +27,7 @@ import tech.pegasys.teku.spec.Spec; import tech.pegasys.teku.spec.datastructures.blocks.BeaconBlock; import tech.pegasys.teku.spec.datastructures.builder.ValidatorRegistration; +import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadHeader; import tech.pegasys.teku.spec.datastructures.operations.AggregateAndProof; import tech.pegasys.teku.spec.datastructures.operations.AttestationData; import tech.pegasys.teku.spec.datastructures.operations.PayloadAttestationData; @@ -130,6 +131,13 @@ public SafeFuture signValidatorRegistration( return sign(signingRootUtil.signingRootForValidatorRegistration(validatorRegistration)); } + @Override + public SafeFuture signExecutionPayloadHeader( + final ExecutionPayloadHeader executionPayloadHeader, final ForkInfo forkInfo) { + return sign( + signingRootUtil.signingRootForExecutionPayloadHeader(executionPayloadHeader, forkInfo)); + } + private SafeFuture signingRootFromSyncCommitteeUtils( final UInt64 slot, final Function createSigningRoot) { return SafeFuture.of(() -> createSigningRoot.apply(spec.getSyncCommitteeUtilRequired(slot))); diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/signatures/Signer.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/signatures/Signer.java index f892ef90c7a..40f1c519750 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/signatures/Signer.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/signatures/Signer.java @@ -21,6 +21,7 @@ import tech.pegasys.teku.infrastructure.unsigned.UInt64; import tech.pegasys.teku.spec.datastructures.blocks.BeaconBlock; import tech.pegasys.teku.spec.datastructures.builder.ValidatorRegistration; +import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadHeader; import tech.pegasys.teku.spec.datastructures.operations.AggregateAndProof; import tech.pegasys.teku.spec.datastructures.operations.AttestationData; import tech.pegasys.teku.spec.datastructures.operations.PayloadAttestationData; @@ -60,6 +61,9 @@ SafeFuture signContributionAndProof( SafeFuture signValidatorRegistration(ValidatorRegistration validatorRegistration); + SafeFuture signExecutionPayloadHeader( + ExecutionPayloadHeader executionPayloadHeader, ForkInfo forkInfo); + default boolean isLocal() { return getSigningServiceUrl().isEmpty(); } diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/signatures/SigningRootUtil.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/signatures/SigningRootUtil.java index 04e3f5522de..2b69fe2be9a 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/signatures/SigningRootUtil.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/signatures/SigningRootUtil.java @@ -22,6 +22,8 @@ import tech.pegasys.teku.spec.datastructures.blocks.BeaconBlock; import tech.pegasys.teku.spec.datastructures.blocks.BeaconBlockHeader; import tech.pegasys.teku.spec.datastructures.builder.ValidatorRegistration; +import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadHeader; +import tech.pegasys.teku.spec.datastructures.execution.versions.eip7732.ExecutionPayloadHeaderEip7732; import tech.pegasys.teku.spec.datastructures.operations.AggregateAndProof; import tech.pegasys.teku.spec.datastructures.operations.AttestationData; import tech.pegasys.teku.spec.datastructures.operations.PayloadAttestationData; @@ -125,4 +127,17 @@ public Bytes signingRootForValidatorRegistration( final Bytes32 domain = miscHelpers.computeDomain(Domain.APPLICATION_BUILDER); return miscHelpers.computeSigningRoot(validatorRegistration, domain); } + + public Bytes signingRootForExecutionPayloadHeader( + final ExecutionPayloadHeader executionPayloadHeader, final ForkInfo forkInfo) { + final UInt64 slot = ExecutionPayloadHeaderEip7732.required(executionPayloadHeader).getSlot(); + final SpecVersion specVersion = spec.atSlot(slot); + final Bytes32 domain = + spec.getDomain( + Domain.BEACON_BUILDER, + spec.computeEpochAtSlot(slot), + forkInfo.getFork(), + forkInfo.getGenesisValidatorsRoot()); + return specVersion.miscHelpers().computeSigningRoot(executionPayloadHeader, domain); + } } diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/signatures/SlashingProtectedSigner.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/signatures/SlashingProtectedSigner.java index d92a925a34e..3e5c89b102c 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/signatures/SlashingProtectedSigner.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/signatures/SlashingProtectedSigner.java @@ -24,6 +24,7 @@ import tech.pegasys.teku.infrastructure.unsigned.UInt64; import tech.pegasys.teku.spec.datastructures.blocks.BeaconBlock; import tech.pegasys.teku.spec.datastructures.builder.ValidatorRegistration; +import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadHeader; import tech.pegasys.teku.spec.datastructures.operations.AggregateAndProof; import tech.pegasys.teku.spec.datastructures.operations.AttestationData; import tech.pegasys.teku.spec.datastructures.operations.PayloadAttestationData; @@ -155,6 +156,12 @@ public SafeFuture signValidatorRegistration( return delegate.signValidatorRegistration(validatorRegistration); } + @Override + public SafeFuture signExecutionPayloadHeader( + final ExecutionPayloadHeader executionPayloadHeader, final ForkInfo forkInfo) { + return delegate.signExecutionPayloadHeader(executionPayloadHeader, forkInfo); + } + @Override public Optional getSigningServiceUrl() { return delegate.getSigningServiceUrl(); diff --git a/ethereum/spec/src/testFixtures/java/tech/pegasys/teku/spec/generator/BlockProposalTestUtil.java b/ethereum/spec/src/testFixtures/java/tech/pegasys/teku/spec/generator/BlockProposalTestUtil.java index 7d8d262f7be..ef7b1cdd9d2 100644 --- a/ethereum/spec/src/testFixtures/java/tech/pegasys/teku/spec/generator/BlockProposalTestUtil.java +++ b/ethereum/spec/src/testFixtures/java/tech/pegasys/teku/spec/generator/BlockProposalTestUtil.java @@ -40,6 +40,7 @@ import tech.pegasys.teku.spec.datastructures.blocks.blockbody.versions.altair.SyncAggregate; import tech.pegasys.teku.spec.datastructures.blocks.blockbody.versions.deneb.BeaconBlockBodySchemaDeneb; import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayload; +import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadHeader; import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadSchema; import tech.pegasys.teku.spec.datastructures.operations.Attestation; import tech.pegasys.teku.spec.datastructures.operations.AttesterSlashing; @@ -49,12 +50,14 @@ import tech.pegasys.teku.spec.datastructures.operations.SignedVoluntaryExit; import tech.pegasys.teku.spec.datastructures.state.beaconstate.BeaconState; import tech.pegasys.teku.spec.datastructures.state.beaconstate.versions.bellatrix.BeaconStateBellatrix; +import tech.pegasys.teku.spec.datastructures.state.beaconstate.versions.eip7732.BeaconStateEip7732; import tech.pegasys.teku.spec.datastructures.type.SszKZGCommitment; import tech.pegasys.teku.spec.datastructures.util.BeaconBlockBodyLists; import tech.pegasys.teku.spec.datastructures.util.BlobsUtil; import tech.pegasys.teku.spec.logic.common.statetransition.exceptions.EpochProcessingException; import tech.pegasys.teku.spec.logic.common.statetransition.exceptions.SlotProcessingException; import tech.pegasys.teku.spec.schemas.SchemaDefinitionsBellatrix; +import tech.pegasys.teku.spec.schemas.SchemaDefinitionsEip7732; import tech.pegasys.teku.spec.signatures.Signer; import tech.pegasys.teku.spec.util.DataStructureUtil; @@ -128,6 +131,47 @@ public SafeFuture createNewBlock( builder.blobKzgCommitments( kzgCommitments.orElseGet(dataStructureUtil::emptyBlobKzgCommitments)); } + // EIP7732 TODO: + if (builder.supportsSignedExecutionPayloadHeader()) { + final SchemaDefinitionsEip7732 schemaDefinitionsEip7732 = + SchemaDefinitionsEip7732.required(spec.atSlot(newSlot).getSchemaDefinitions()); + final ExecutionPayload payload = + executionPayload.orElseGet( + () -> + createExecutionPayload( + newSlot, blockSlotState, transactions, terminalBlock)); + final ExecutionPayloadHeader message = + schemaDefinitionsEip7732 + .getExecutionPayloadHeaderSchema() + .createExecutionPayloadHeader( + b -> + b.parentBlockHash( + () -> + BeaconStateEip7732.required(blockSlotState) + .getLatestBlockHash()) + .parentBlockRoot(() -> parentBlockSigningRoot) + .blockHash(payload.getBlockHash()) + .gasLimit(payload.getGasLimit()) + .builderIndex( + () -> + UInt64.valueOf( + spec.getBeaconProposerIndex( + blockSlotState, newSlot))) + .slot(() -> newSlot) + .value(() -> UInt64.ZERO) + .blobKzgCommitmentsRoot(() -> Bytes32.ZERO)); + builder.signedExecutionPayloadHeader( + schemaDefinitionsEip7732 + .getSignedExecutionPayloadHeaderSchema() + .create( + message, + signer + .signExecutionPayloadHeader(message, blockSlotState.getForkInfo()) + .join())); + } + if (builder.supportsPayloadAttestations()) { + builder.payloadAttestations(dataStructureUtil.emptyPayloadAttestations()); + } return SafeFuture.COMPLETE; }, BlockProductionPerformance.NOOP) @@ -201,6 +245,43 @@ public SafeFuture createNewBlockSkippingStateTransition( builder.blobKzgCommitments( kzgCommitments.orElseGet(dataStructureUtil::emptyBlobKzgCommitments)); } + // EIP7732 TODO: + if (builder.supportsSignedExecutionPayloadHeader()) { + final SchemaDefinitionsEip7732 schemaDefinitionsEip7732 = + SchemaDefinitionsEip7732.required(spec.atSlot(newSlot).getSchemaDefinitions()); + final ExecutionPayload payload = + executionPayload.orElseGet( + () -> createExecutionPayload(newSlot, state, transactions, terminalBlock)); + final ExecutionPayloadHeader message = + schemaDefinitionsEip7732 + .getExecutionPayloadHeaderSchema() + .createExecutionPayloadHeader( + b -> + b.parentBlockHash( + () -> + BeaconStateEip7732.required(state).getLatestBlockHash()) + .parentBlockRoot(() -> parentBlockSigningRoot) + .blockHash(payload.getBlockHash()) + .gasLimit(payload.getGasLimit()) + .builderIndex( + () -> + UInt64.valueOf( + spec.getBeaconProposerIndex(state, newSlot))) + .slot(() -> newSlot) + .value(() -> UInt64.ZERO) + .blobKzgCommitmentsRoot(() -> Bytes32.ZERO)); + builder.signedExecutionPayloadHeader( + schemaDefinitionsEip7732 + .getSignedExecutionPayloadHeaderSchema() + .create( + message, + signer + .signExecutionPayloadHeader(message, state.getForkInfo()) + .join())); + } + if (builder.supportsPayloadAttestations()) { + builder.payloadAttestations(dataStructureUtil.emptyPayloadAttestations()); + } return SafeFuture.COMPLETE; }) .thenApply( diff --git a/ethereum/spec/src/testFixtures/java/tech/pegasys/teku/spec/generator/signatures/NoOpSigner.java b/ethereum/spec/src/testFixtures/java/tech/pegasys/teku/spec/generator/signatures/NoOpSigner.java index 14bfda4860e..fc7683f005b 100644 --- a/ethereum/spec/src/testFixtures/java/tech/pegasys/teku/spec/generator/signatures/NoOpSigner.java +++ b/ethereum/spec/src/testFixtures/java/tech/pegasys/teku/spec/generator/signatures/NoOpSigner.java @@ -21,6 +21,7 @@ import tech.pegasys.teku.infrastructure.unsigned.UInt64; import tech.pegasys.teku.spec.datastructures.blocks.BeaconBlock; import tech.pegasys.teku.spec.datastructures.builder.ValidatorRegistration; +import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadHeader; import tech.pegasys.teku.spec.datastructures.operations.AggregateAndProof; import tech.pegasys.teku.spec.datastructures.operations.AttestationData; import tech.pegasys.teku.spec.datastructures.operations.PayloadAttestationData; @@ -100,6 +101,12 @@ public SafeFuture signPayloadAttestationData( return new SafeFuture<>(); } + @Override + public SafeFuture signExecutionPayloadHeader( + final ExecutionPayloadHeader executionPayloadHeader, final ForkInfo forkInfo) { + return new SafeFuture<>(); + } + @Override public abstract Optional getSigningServiceUrl(); } diff --git a/ethereum/spec/src/testFixtures/java/tech/pegasys/teku/spec/util/DataStructureUtil.java b/ethereum/spec/src/testFixtures/java/tech/pegasys/teku/spec/util/DataStructureUtil.java index cf08b5865f6..47a52346234 100644 --- a/ethereum/spec/src/testFixtures/java/tech/pegasys/teku/spec/util/DataStructureUtil.java +++ b/ethereum/spec/src/testFixtures/java/tech/pegasys/teku/spec/util/DataStructureUtil.java @@ -2377,8 +2377,8 @@ public SignedBlockContents randomSignedBlockContents(final UInt64 slot) { .getMessage() .getBody() .getOptionalBlobKzgCommitments() - .orElseThrow() - .size(); + .map(SszList::size) + .orElse(randomNumberOfBlobsPerBlock()); final List blobs = randomBlobs(numberOfBlobs, slot); final List kzgProofs = randomKZGProofs(numberOfBlobs); return getDenebSchemaDefinitions(slot) @@ -2406,7 +2406,11 @@ public BlockContents randomBlockContents() { public BlockContents randomBlockContents(final UInt64 slot) { final BeaconBlock beaconBlock = randomBeaconBlock(slot); final int numberOfBlobs = - beaconBlock.getBody().getOptionalBlobKzgCommitments().orElseThrow().size(); + beaconBlock + .getBody() + .getOptionalBlobKzgCommitments() + .map(SszList::size) + .orElse(randomNumberOfBlobsPerBlock()); final List blobs = randomBlobs(numberOfBlobs, slot); final List kzgProofs = randomKZGProofs(numberOfBlobs); return getDenebSchemaDefinitions(slot) @@ -2581,6 +2585,13 @@ public SignedExecutionPayloadHeader randomSignedExecutionPayloadHeader() { randomSignature()); } + public SszList emptyPayloadAttestations() { + return SchemaDefinitionsEip7732.required( + spec.forMilestone(SpecMilestone.EIP7732).getSchemaDefinitions()) + .getPayloadAttestationsSchema() + .of(); + } + public PayloadAttestation randomPayloadAttestation() { return getEip7732SchemaDefinitions(randomSlot()) .getPayloadAttestationSchema() diff --git a/validator/client/src/main/java/tech/pegasys/teku/validator/client/signer/ExternalSigner.java b/validator/client/src/main/java/tech/pegasys/teku/validator/client/signer/ExternalSigner.java index 23c344e0a07..a5b771b7cc9 100644 --- a/validator/client/src/main/java/tech/pegasys/teku/validator/client/signer/ExternalSigner.java +++ b/validator/client/src/main/java/tech/pegasys/teku/validator/client/signer/ExternalSigner.java @@ -48,6 +48,7 @@ import tech.pegasys.teku.spec.Spec; import tech.pegasys.teku.spec.datastructures.blocks.BeaconBlock; import tech.pegasys.teku.spec.datastructures.builder.ValidatorRegistration; +import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadHeader; import tech.pegasys.teku.spec.datastructures.operations.AggregateAndProof; import tech.pegasys.teku.spec.datastructures.operations.AttestationData; import tech.pegasys.teku.spec.datastructures.operations.PayloadAttestationData; @@ -284,6 +285,12 @@ public SafeFuture signValidatorRegistration( slashableGenericMessage("validator registration"))); } + @Override + public SafeFuture signExecutionPayloadHeader( + final ExecutionPayloadHeader executionPayloadHeader, final ForkInfo forkInfo) { + return SafeFuture.failedFuture(new UnsupportedOperationException("Not Yet Implemented")); + } + @Override public Optional getSigningServiceUrl() { return Optional.of(signingServiceUrl);