From e7f9e40ad0468a6bb9e265bc31ef48f17b115d50 Mon Sep 17 00:00:00 2001 From: Stefan Bratanov Date: Tue, 5 Mar 2024 18:40:10 +0000 Subject: [PATCH 01/13] [EIP-6110] Block processing logic --- .../electra/MutableBeaconStateElectra.java | 9 ++ .../capella/block/BlockProcessorCapella.java | 13 +- .../versions/electra/SpecLogicElectra.java | 6 +- .../electra/block/BlockProcessorElectra.java | 134 ++++++++++++++++++ 4 files changed, 152 insertions(+), 10 deletions(-) create mode 100644 ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/block/BlockProcessorElectra.java diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/state/beaconstate/versions/electra/MutableBeaconStateElectra.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/state/beaconstate/versions/electra/MutableBeaconStateElectra.java index 20155013ae7..7e03486adad 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/state/beaconstate/versions/electra/MutableBeaconStateElectra.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/state/beaconstate/versions/electra/MutableBeaconStateElectra.java @@ -16,10 +16,19 @@ import java.util.Optional; import tech.pegasys.teku.infrastructure.ssz.primitive.SszUInt64; import tech.pegasys.teku.infrastructure.unsigned.UInt64; +import tech.pegasys.teku.spec.datastructures.state.beaconstate.MutableBeaconState; import tech.pegasys.teku.spec.datastructures.state.beaconstate.common.BeaconStateFields; import tech.pegasys.teku.spec.datastructures.state.beaconstate.versions.deneb.MutableBeaconStateDeneb; public interface MutableBeaconStateElectra extends MutableBeaconStateDeneb, BeaconStateElectra { + static MutableBeaconStateElectra required(final MutableBeaconState state) { + return state + .toMutableVersionElectra() + .orElseThrow( + () -> + new IllegalArgumentException( + "Expected an Electra state but got: " + state.getClass().getSimpleName())); + } @Override BeaconStateElectra commitChanges(); diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/capella/block/BlockProcessorCapella.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/capella/block/BlockProcessorCapella.java index c45aeff4e51..b8a375a9bf3 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/capella/block/BlockProcessorCapella.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/capella/block/BlockProcessorCapella.java @@ -33,6 +33,7 @@ import tech.pegasys.teku.spec.config.SpecConfigCapella; import tech.pegasys.teku.spec.datastructures.blocks.SignedBeaconBlock; import tech.pegasys.teku.spec.datastructures.blocks.blockbody.BeaconBlockBody; +import tech.pegasys.teku.spec.datastructures.blocks.blockbody.versions.capella.BeaconBlockBodyCapella; import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadHeader; import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadSummary; import tech.pegasys.teku.spec.datastructures.execution.versions.capella.Withdrawal; @@ -139,13 +140,11 @@ protected void processOperationsNoValidation( throws BlockProcessingException { super.processOperationsNoValidation(state, body, indexedAttestationCache); - processBlsToExecutionChangesNoValidation( - MutableBeaconStateCapella.required(state), - body.getOptionalBlsToExecutionChanges() - .orElseThrow( - () -> - new BlockProcessingException( - "BlsToExecutionChanges was not found during block processing."))); + safelyProcess( + () -> + processBlsToExecutionChangesNoValidation( + MutableBeaconStateCapella.required(state), + BeaconBlockBodyCapella.required(body).getBlsToExecutionChanges())); } @Override diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/SpecLogicElectra.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/SpecLogicElectra.java index eda0f40c05f..12ec358b02b 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/SpecLogicElectra.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/SpecLogicElectra.java @@ -36,12 +36,12 @@ import tech.pegasys.teku.spec.logic.versions.capella.block.BlockProcessorCapella; import tech.pegasys.teku.spec.logic.versions.capella.operations.validation.OperationValidatorCapella; import tech.pegasys.teku.spec.logic.versions.capella.statetransition.epoch.EpochProcessorCapella; -import tech.pegasys.teku.spec.logic.versions.deneb.block.BlockProcessorDeneb; import tech.pegasys.teku.spec.logic.versions.deneb.helpers.BeaconStateAccessorsDeneb; import tech.pegasys.teku.spec.logic.versions.deneb.helpers.MiscHelpersDeneb; import tech.pegasys.teku.spec.logic.versions.deneb.operations.validation.AttestationDataValidatorDeneb; import tech.pegasys.teku.spec.logic.versions.deneb.util.AttestationUtilDeneb; import tech.pegasys.teku.spec.logic.versions.deneb.util.ForkChoiceUtilDeneb; +import tech.pegasys.teku.spec.logic.versions.electra.block.BlockProcessorElectra; import tech.pegasys.teku.spec.logic.versions.electra.forktransition.ElectraStateUpgrade; import tech.pegasys.teku.spec.schemas.SchemaDefinitionsElectra; @@ -140,8 +140,8 @@ public static SpecLogicElectra create( beaconStateAccessors, validatorsUtil, config, miscHelpers, schemaDefinitions); final LightClientUtil lightClientUtil = new LightClientUtil(beaconStateAccessors, syncCommitteeUtil, schemaDefinitions); - final BlockProcessorDeneb blockProcessor = - new BlockProcessorDeneb( + final BlockProcessorElectra blockProcessor = + new BlockProcessorElectra( config, predicates, miscHelpers, diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/block/BlockProcessorElectra.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/block/BlockProcessorElectra.java new file mode 100644 index 00000000000..f5b6fa3a406 --- /dev/null +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/block/BlockProcessorElectra.java @@ -0,0 +1,134 @@ +/* + * Copyright Consensys Software Inc., 2022 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package tech.pegasys.teku.spec.logic.versions.electra.block; + +import static com.google.common.base.Preconditions.checkArgument; + +import tech.pegasys.teku.infrastructure.ssz.SszList; +import tech.pegasys.teku.infrastructure.unsigned.UInt64; +import tech.pegasys.teku.spec.cache.IndexedAttestationCache; +import tech.pegasys.teku.spec.config.SpecConfigElectra; +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.versions.electra.DepositReceipt; +import tech.pegasys.teku.spec.datastructures.state.beaconstate.BeaconState; +import tech.pegasys.teku.spec.datastructures.state.beaconstate.MutableBeaconState; +import tech.pegasys.teku.spec.datastructures.state.beaconstate.versions.electra.BeaconStateElectra; +import tech.pegasys.teku.spec.datastructures.state.beaconstate.versions.electra.MutableBeaconStateElectra; +import tech.pegasys.teku.spec.logic.common.helpers.BeaconStateMutators; +import tech.pegasys.teku.spec.logic.common.helpers.Predicates; +import tech.pegasys.teku.spec.logic.common.operations.OperationSignatureVerifier; +import tech.pegasys.teku.spec.logic.common.operations.validation.OperationValidator; +import tech.pegasys.teku.spec.logic.common.statetransition.exceptions.BlockProcessingException; +import tech.pegasys.teku.spec.logic.common.util.AttestationUtil; +import tech.pegasys.teku.spec.logic.common.util.BeaconStateUtil; +import tech.pegasys.teku.spec.logic.common.util.SyncCommitteeUtil; +import tech.pegasys.teku.spec.logic.common.util.ValidatorsUtil; +import tech.pegasys.teku.spec.logic.versions.altair.helpers.BeaconStateAccessorsAltair; +import tech.pegasys.teku.spec.logic.versions.deneb.block.BlockProcessorDeneb; +import tech.pegasys.teku.spec.logic.versions.deneb.helpers.MiscHelpersDeneb; +import tech.pegasys.teku.spec.schemas.SchemaDefinitionsDeneb; +import tech.pegasys.teku.spec.schemas.SchemaDefinitionsElectra; + +public class BlockProcessorElectra extends BlockProcessorDeneb { + + public BlockProcessorElectra( + final SpecConfigElectra specConfig, + final Predicates predicates, + final MiscHelpersDeneb miscHelpers, + final SyncCommitteeUtil syncCommitteeUtil, + final BeaconStateAccessorsAltair beaconStateAccessors, + final BeaconStateMutators beaconStateMutators, + final OperationSignatureVerifier operationSignatureVerifier, + final BeaconStateUtil beaconStateUtil, + final AttestationUtil attestationUtil, + final ValidatorsUtil validatorsUtil, + final OperationValidator operationValidator, + final SchemaDefinitionsElectra schemaDefinitions) { + super( + specConfig, + predicates, + miscHelpers, + syncCommitteeUtil, + beaconStateAccessors, + beaconStateMutators, + operationSignatureVerifier, + beaconStateUtil, + attestationUtil, + validatorsUtil, + operationValidator, + SchemaDefinitionsDeneb.required(schemaDefinitions)); + } + + @Override + protected void processOperationsNoValidation( + final MutableBeaconState state, + final BeaconBlockBody body, + final IndexedAttestationCache indexedAttestationCache) + throws BlockProcessingException { + super.processOperationsNoValidation(state, body, indexedAttestationCache); + + safelyProcess( + () -> + processDepositReceipts( + MutableBeaconStateElectra.required(state), + BeaconBlockBodyElectra.required(body).getExecutionPayload().getDepositReceipts())); + } + + /** Disable former deposit mechanism once all prior deposits are processed * */ + @Override + protected void verifyOutstandingDepositsAreProcessed( + final BeaconState state, final BeaconBlockBody body) { + final UInt64 eth1DepositIndexLimit = + state + .getEth1Data() + .getDepositCount() + .min(BeaconStateElectra.required(state).getDepositReceiptsStartIndex()); + + if (state.getEth1DepositIndex().isLessThan(eth1DepositIndexLimit)) { + final int expectedDepositCount = + Math.min( + specConfig.getMaxDeposits(), + state.getEth1DepositIndex().minus(eth1DepositIndexLimit).intValue()); + + checkArgument( + body.getDeposits().size() == expectedDepositCount, + "process_operations: Verify that outstanding deposits are processed up to the maximum number of deposits"); + } else { + checkArgument( + body.getDeposits().isEmpty(), + "process_operations: Verify that former deposit mechanism has been disabled"); + } + } + + public void processDepositReceipts( + final MutableBeaconStateElectra state, final SszList depositReceipts) { + for (DepositReceipt depositReceipt : depositReceipts) { + // process_deposit_receipt + if (state + .getDepositReceiptsStartIndex() + .equals(SpecConfigElectra.UNSET_DEPOSIT_RECEIPTS_START_INDEX)) { + state.setDepositReceiptsStartIndex(depositReceipt.getIndex()); + } + applyDeposit( + state, + null, + depositReceipt.getPubkey(), + depositReceipt.getWithdrawalCredentials(), + depositReceipt.getAmount(), + depositReceipt.getSignature(), + false); + } + } +} From f87dcf11e1eb4be1fa1cade38e203194fc0b0310 Mon Sep 17 00:00:00 2001 From: Stefan Bratanov Date: Tue, 5 Mar 2024 19:01:49 +0000 Subject: [PATCH 02/13] fix bugs --- .../versions/capella/block/BlockProcessorCapella.java | 7 +++++-- .../versions/electra/block/BlockProcessorElectra.java | 11 +++++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/capella/block/BlockProcessorCapella.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/capella/block/BlockProcessorCapella.java index b8a375a9bf3..36b6fc4124c 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/capella/block/BlockProcessorCapella.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/capella/block/BlockProcessorCapella.java @@ -33,7 +33,6 @@ import tech.pegasys.teku.spec.config.SpecConfigCapella; import tech.pegasys.teku.spec.datastructures.blocks.SignedBeaconBlock; import tech.pegasys.teku.spec.datastructures.blocks.blockbody.BeaconBlockBody; -import tech.pegasys.teku.spec.datastructures.blocks.blockbody.versions.capella.BeaconBlockBodyCapella; import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadHeader; import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadSummary; import tech.pegasys.teku.spec.datastructures.execution.versions.capella.Withdrawal; @@ -144,7 +143,11 @@ protected void processOperationsNoValidation( () -> processBlsToExecutionChangesNoValidation( MutableBeaconStateCapella.required(state), - BeaconBlockBodyCapella.required(body).getBlsToExecutionChanges())); + body.getOptionalBlsToExecutionChanges() + .orElseThrow( + () -> + new BlockProcessingException( + "BlsToExecutionChanges was not found during block processing.")))); } @Override diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/block/BlockProcessorElectra.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/block/BlockProcessorElectra.java index f5b6fa3a406..bc62d8f4dc5 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/block/BlockProcessorElectra.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/block/BlockProcessorElectra.java @@ -20,8 +20,9 @@ import tech.pegasys.teku.spec.cache.IndexedAttestationCache; import tech.pegasys.teku.spec.config.SpecConfigElectra; 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.versions.electra.DepositReceipt; +import tech.pegasys.teku.spec.datastructures.execution.versions.electra.ExecutionPayloadElectra; import tech.pegasys.teku.spec.datastructures.state.beaconstate.BeaconState; import tech.pegasys.teku.spec.datastructures.state.beaconstate.MutableBeaconState; import tech.pegasys.teku.spec.datastructures.state.beaconstate.versions.electra.BeaconStateElectra; @@ -83,7 +84,13 @@ protected void processOperationsNoValidation( () -> processDepositReceipts( MutableBeaconStateElectra.required(state), - BeaconBlockBodyElectra.required(body).getExecutionPayload().getDepositReceipts())); + body.getOptionalExecutionPayload() + .flatMap(ExecutionPayload::toVersionElectra) + .map(ExecutionPayloadElectra::getDepositReceipts) + .orElseThrow( + () -> + new BlockProcessingException( + "Deposit receipts were not found during block processing.")))); } /** Disable former deposit mechanism once all prior deposits are processed * */ From 51285a21666be13180807c6079a721c70a927605 Mon Sep 17 00:00:00 2001 From: Stefan Bratanov Date: Fri, 8 Mar 2024 08:55:12 +0000 Subject: [PATCH 03/13] fixes --- .../common/block/AbstractBlockProcessor.java | 26 +++++++++---------- .../electra/block/BlockProcessorElectra.java | 4 +-- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/common/block/AbstractBlockProcessor.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/common/block/AbstractBlockProcessor.java index 6b2c72c4857..b68d10138b6 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/common/block/AbstractBlockProcessor.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/common/block/AbstractBlockProcessor.java @@ -427,22 +427,11 @@ protected void processOperationsNoValidation( throws BlockProcessingException { safelyProcess( () -> { - final int expectedDepositCount = - Math.min( - specConfig.getMaxDeposits(), - state - .getEth1Data() - .getDepositCount() - .minus(state.getEth1DepositIndex()) - .intValue()); + verifyOutstandingDepositsAreProcessed(state, body); final Supplier validatorExitContextSupplier = beaconStateMutators.createValidatorExitContextSupplier(state); - checkArgument( - body.getDeposits().size() == expectedDepositCount, - "process_operations: Verify that outstanding deposits are processed up to the maximum number of deposits"); - processProposerSlashingsNoValidation( state, body.getProposerSlashings(), validatorExitContextSupplier); processAttesterSlashings( @@ -451,10 +440,21 @@ protected void processOperationsNoValidation( processDeposits(state, body.getDeposits()); processVoluntaryExitsNoValidation( state, body.getVoluntaryExits(), validatorExitContextSupplier); - // @process_shard_receipt_proofs }); } + protected void verifyOutstandingDepositsAreProcessed( + final BeaconState state, final BeaconBlockBody body) { + final int expectedDepositCount = + Math.min( + specConfig.getMaxDeposits(), + state.getEth1Data().getDepositCount().minus(state.getEth1DepositIndex()).intValue()); + + checkArgument( + body.getDeposits().size() == expectedDepositCount, + "process_operations: Verify that outstanding deposits are processed up to the maximum number of deposits"); + } + @Override public void processProposerSlashings( final MutableBeaconState state, diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/block/BlockProcessorElectra.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/block/BlockProcessorElectra.java index bc62d8f4dc5..6317fb06ffd 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/block/BlockProcessorElectra.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/block/BlockProcessorElectra.java @@ -15,6 +15,7 @@ import static com.google.common.base.Preconditions.checkArgument; +import java.util.Optional; import tech.pegasys.teku.infrastructure.ssz.SszList; import tech.pegasys.teku.infrastructure.unsigned.UInt64; import tech.pegasys.teku.spec.cache.IndexedAttestationCache; @@ -93,7 +94,6 @@ protected void processOperationsNoValidation( "Deposit receipts were not found during block processing.")))); } - /** Disable former deposit mechanism once all prior deposits are processed * */ @Override protected void verifyOutstandingDepositsAreProcessed( final BeaconState state, final BeaconBlockBody body) { @@ -130,11 +130,11 @@ public void processDepositReceipts( } applyDeposit( state, - null, depositReceipt.getPubkey(), depositReceipt.getWithdrawalCredentials(), depositReceipt.getAmount(), depositReceipt.getSignature(), + Optional.empty(), false); } } From 16720e7d5e088cf0f50ae0bb18f3ef5fc2d6e415 Mon Sep 17 00:00:00 2001 From: Stefan Bratanov Date: Thu, 21 Mar 2024 15:38:58 +0000 Subject: [PATCH 04/13] get Eth1 pending deposits for Electra --- .../coordinator/DepositProvider.java | 65 +++++--- .../coordinator/DepositProviderTest.java | 155 ++++++++++++------ .../java/tech/pegasys/teku/spec/Spec.java | 5 + .../logic/common/helpers/MiscHelpers.java | 4 + .../versions/electra/SpecLogicElectra.java | 5 +- .../electra/block/BlockProcessorElectra.java | 2 +- .../electra/helpers/MiscHelpersElectra.java | 41 +++++ .../helpers/MiscHelpersElectraTest.java | 76 +++++++++ 8 files changed, 276 insertions(+), 77 deletions(-) create mode 100644 ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/helpers/MiscHelpersElectra.java create mode 100644 ethereum/spec/src/test/java/tech/pegasys/teku/spec/logic/versions/electra/helpers/MiscHelpersElectraTest.java diff --git a/beacon/validator/src/main/java/tech/pegasys/teku/validator/coordinator/DepositProvider.java b/beacon/validator/src/main/java/tech/pegasys/teku/validator/coordinator/DepositProvider.java index cfc72391eba..502324f5756 100644 --- a/beacon/validator/src/main/java/tech/pegasys/teku/validator/coordinator/DepositProvider.java +++ b/beacon/validator/src/main/java/tech/pegasys/teku/validator/coordinator/DepositProvider.java @@ -74,8 +74,8 @@ public class DepositProvider private boolean inSync = false; public DepositProvider( - MetricsSystem metricsSystem, - RecentChainData recentChainData, + final MetricsSystem metricsSystem, + final RecentChainData recentChainData, final Eth1DataCache eth1DataCache, final StorageUpdateChannel storageUpdateChannel, final Eth1DepositStorageChannel eth1DepositStorageChannel, @@ -99,7 +99,7 @@ public DepositProvider( } @Override - public synchronized void onDepositsFromBlock(DepositsFromBlockEvent event) { + public synchronized void onDepositsFromBlock(final DepositsFromBlockEvent event) { event.getDeposits().stream() .map(depositUtil::convertDepositEventToOperationDeposit) .forEach( @@ -171,7 +171,7 @@ public void onEth1Block( } @Override - public void onMinGenesisTimeBlock(MinGenesisTimeBlockEvent event) {} + public void onMinGenesisTimeBlock(final MinGenesisTimeBlockEvent event) {} @Override public void onSlot(final UInt64 slot) { @@ -201,33 +201,58 @@ public void onSlot(final UInt64 slot) { .ifExceptionGetsHereRaiseABug(); } - public void onSyncingStatusChanged(boolean inSync) { + public void onSyncingStatusChanged(final boolean inSync) { this.inSync = inSync; } - public synchronized SszList getDeposits(BeaconState state, Eth1Data eth1Data) { + public synchronized SszList getDeposits( + final BeaconState state, final Eth1Data eth1Data) { + final long maxDeposits = spec.getMaxDeposits(state); + final SszListSchema depositsSchema = depositsSchemaCache.get(maxDeposits); + // no Eth1 deposits needed if already transitioned to the EIP-6110 mechanism + if (spec.isFormerDepositMechanismDisabled(state)) { + return depositsSchema.createFromElements(emptyList()); + } final UInt64 eth1DepositCount; if (spec.isEnoughVotesToUpdateEth1Data(state, eth1Data, 1)) { eth1DepositCount = eth1Data.getDepositCount(); } else { eth1DepositCount = state.getEth1Data().getDepositCount(); } - final UInt64 eth1DepositIndex = state.getEth1DepositIndex(); + final UInt64 eth1PendingDepositCount = + state + .toVersionElectra() + .map( + stateElectra -> { + // EIP-6110 + final UInt64 eth1DepositIndexLimit = + eth1DepositCount.min(stateElectra.getDepositReceiptsStartIndex()); + if (eth1DepositIndex.isLessThan(eth1DepositIndexLimit)) { + return eth1DepositIndexLimit.minus(eth1DepositIndex).min(maxDeposits); + } else { + return UInt64.ZERO; + } + }) + .orElseGet( + () -> { + // Phase0 + return eth1DepositCount.minusMinZero(eth1DepositIndex).min(maxDeposits); + }); + + // No deposits to include + if (eth1PendingDepositCount.isZero()) { + return depositsSchema.createFromElements(emptyList()); + } + // We need to have all the deposits that can be included in the state available to ensure // the generated proofs are valid checkRequiredDepositsAvailable(eth1DepositCount, eth1DepositIndex); - final long maxDeposits = spec.getMaxDeposits(state); - final UInt64 latestDepositIndexWithMaxBlock = eth1DepositIndex.plus(spec.getMaxDeposits(state)); - - final UInt64 toDepositIndex = - latestDepositIndexWithMaxBlock.isGreaterThan(eth1DepositCount) - ? eth1DepositCount - : latestDepositIndexWithMaxBlock; + final UInt64 toDepositIndex = eth1DepositIndex.plus(eth1PendingDepositCount); - return getDepositsWithProof(eth1DepositIndex, toDepositIndex, eth1DepositCount, maxDeposits); + return getDepositsWithProof(eth1DepositIndex, toDepositIndex, eth1DepositCount, depositsSchema); } protected synchronized List getAvailableDeposits() { @@ -261,14 +286,12 @@ public synchronized int getDepositMapSize() { * @param eth1DepositCount number of deposits in the merkle tree according to Eth1Data in state */ private SszList getDepositsWithProof( - UInt64 fromDepositIndex, UInt64 toDepositIndex, UInt64 eth1DepositCount, long maxDeposits) { + final UInt64 fromDepositIndex, + final UInt64 toDepositIndex, + final UInt64 eth1DepositCount, + final SszListSchema depositsSchema) { final AtomicReference expectedDepositIndex = new AtomicReference<>(fromDepositIndex); - final SszListSchema depositsSchema = depositsSchemaCache.get(maxDeposits); final SszBytes32VectorSchema depositProofSchema = Deposit.SSZ_SCHEMA.getProofSchema(); - // No deposits to include so don't bother rewinding the merkle tree. - if (fromDepositIndex.equals(toDepositIndex)) { - return depositsSchema.createFromElements(emptyList()); - } if (depositMerkleTree.getDepositCount() < eth1DepositCount.intValue()) { throw MissingDepositsException.missingRange( UInt64.valueOf(depositMerkleTree.getDepositCount()), eth1DepositCount); diff --git a/beacon/validator/src/test/java/tech/pegasys/teku/validator/coordinator/DepositProviderTest.java b/beacon/validator/src/test/java/tech/pegasys/teku/validator/coordinator/DepositProviderTest.java index 8ce844fe380..cc4e5ce97bd 100644 --- a/beacon/validator/src/test/java/tech/pegasys/teku/validator/coordinator/DepositProviderTest.java +++ b/beacon/validator/src/test/java/tech/pegasys/teku/validator/coordinator/DepositProviderTest.java @@ -40,10 +40,10 @@ import tech.pegasys.teku.infrastructure.ssz.schema.SszListSchema; import tech.pegasys.teku.infrastructure.unsigned.UInt64; import tech.pegasys.teku.spec.Spec; +import tech.pegasys.teku.spec.SpecMilestone; import tech.pegasys.teku.spec.SpecVersion; import tech.pegasys.teku.spec.TestSpecFactory; import tech.pegasys.teku.spec.config.SpecConfig; -import tech.pegasys.teku.spec.config.SpecConfigLoader; import tech.pegasys.teku.spec.datastructures.blocks.Eth1Data; import tech.pegasys.teku.spec.datastructures.operations.Deposit; import tech.pegasys.teku.spec.datastructures.operations.DepositData; @@ -51,8 +51,10 @@ import tech.pegasys.teku.spec.datastructures.state.AnchorPoint; import tech.pegasys.teku.spec.datastructures.state.Checkpoint; import tech.pegasys.teku.spec.datastructures.state.beaconstate.BeaconState; +import tech.pegasys.teku.spec.datastructures.state.beaconstate.versions.electra.MutableBeaconStateElectra; import tech.pegasys.teku.spec.datastructures.util.DepositUtil; import tech.pegasys.teku.spec.datastructures.util.MerkleTree; +import tech.pegasys.teku.spec.networks.Eth2Network; import tech.pegasys.teku.spec.util.DataStructureUtil; import tech.pegasys.teku.storage.api.Eth1DepositStorageChannel; import tech.pegasys.teku.storage.api.StorageUpdateChannel; @@ -64,7 +66,7 @@ public class DepositProviderTest { private Spec spec; private DataStructureUtil dataStructureUtil; private final RecentChainData recentChainData = mock(RecentChainData.class); - private final BeaconState state = mock(BeaconState.class); + private BeaconState state; private final Eth1DataCache eth1DataCache = mock(Eth1DataCache.class); private final StorageUpdateChannel storageUpdateChannel = mock(StorageUpdateChannel.class); private final Eth1DepositStorageChannel eth1DepositStorageChannel = @@ -78,12 +80,21 @@ public class DepositProviderTest { private DepositUtil depositUtil; void setup(final int maxDeposits) { - when(state.getSlot()).thenReturn(UInt64.valueOf(1234)); + setup(maxDeposits, SpecMilestone.PHASE0); + } - SpecConfig specConfig = SpecConfigLoader.loadConfig("minimal", b -> b.maxDeposits(maxDeposits)); - spec = TestSpecFactory.createPhase0(specConfig); + void setup(final int maxDeposits, final SpecMilestone milestone) { + spec = TestSpecFactory.create(milestone, Eth2Network.MINIMAL, b -> b.maxDeposits(maxDeposits)); depositUtil = new DepositUtil(spec); dataStructureUtil = new DataStructureUtil(spec); + state = + dataStructureUtil + .randomBeaconState(UInt64.valueOf(1234)) + .updated( + mutableState -> + // no votes + mutableState.setEth1DataVotes( + SszListSchema.create(Eth1Data.SSZ_SCHEMA, 32).of())); depositProvider = new DepositProvider( new StubMetricsSystem(), @@ -96,7 +107,6 @@ void setup(final int maxDeposits) { true); depositProvider.onSyncingStatusChanged(true); depositMerkleTree = new MerkleTree(spec.getGenesisSpecConfig().getDepositContractTreeDepth()); - mockStateEth1DataVotes(); createDepositEvents(40); randomEth1Data = dataStructureUtil.randomEth1Data(); } @@ -104,8 +114,8 @@ void setup(final int maxDeposits) { @Test void stateEth1DepositIndexIsEqualToEth1DataDepositCount_NoDepositReturned() { setup(5); - mockStateEth1DepositIndex(2); - mockEth1DataDepositCount(2); + updateStateEth1DepositIndex(2); + updateStateEth1DataDepositCount(2); mockDepositsFromEth1Block(0, 10); SszList deposits = depositProvider.getDeposits(state, randomEth1Data); assertThat(deposits).isEmpty(); @@ -114,8 +124,8 @@ void stateEth1DepositIndexIsEqualToEth1DataDepositCount_NoDepositReturned() { @Test void numberOfDepositsThatCanBeIncludedLessThanMaxDeposits() { setup(16); - mockStateEth1DepositIndex(5); - mockEth1DataDepositCount(20); + updateStateEth1DepositIndex(5); + updateStateEth1DataDepositCount(20); mockDepositsFromEth1Block(0, 10); mockDepositsFromEth1Block(10, 20); @@ -128,8 +138,8 @@ void numberOfDepositsThatCanBeIncludedLessThanMaxDeposits() { @Test void numberOfDepositsGetsAdjustedAccordingToOurEth1DataVote() { setup(30); - mockStateEth1DepositIndex(5); - mockEth1DataDepositCount(20); + updateStateEth1DepositIndex(5); + updateStateEth1DataDepositCount(20); mockDepositsFromEth1Block(0, 10); mockDepositsFromEth1Block(10, 30); @@ -142,8 +152,8 @@ void numberOfDepositsGetsAdjustedAccordingToOurEth1DataVote() { SszList et1hDataVotes = Stream.generate(() -> newEth1Data) .limit(enoughVoteCount) - .collect(SszListSchema.create(Eth1Data.SSZ_SCHEMA, 50).collector()); - when(state.getEth1DataVotes()).thenReturn(et1hDataVotes); + .collect(SszListSchema.create(Eth1Data.SSZ_SCHEMA, 32).collector()); + state = state.updated(mutableState -> mutableState.setEth1DataVotes(et1hDataVotes)); SszList deposits = depositProvider.getDeposits(state, newEth1Data); assertThat(deposits).hasSize(25); @@ -153,8 +163,8 @@ void numberOfDepositsGetsAdjustedAccordingToOurEth1DataVote() { @Test void numberOfDepositsThatCanBeIncludedMoreThanMaxDeposits() { setup(10); - mockStateEth1DepositIndex(5); - mockEth1DataDepositCount(20); + updateStateEth1DepositIndex(5); + updateStateEth1DataDepositCount(20); mockDepositsFromEth1Block(0, 10); mockDepositsFromEth1Block(10, 20); @@ -164,18 +174,47 @@ void numberOfDepositsThatCanBeIncludedMoreThanMaxDeposits() { checkThatDepositProofIsValid(deposits); } + @Test + void noDepositsIncludedIfFormerDepositMechanismHasBeenDisabled() { + setup(16, SpecMilestone.ELECTRA); + updateStateEth1DepositIndex(5); + updateStateDepositReceiptsStartIndex(5); + + final SszList deposits = depositProvider.getDeposits(state, randomEth1Data); + + assertThat(deposits).isEmpty(); + } + + @Test + void getsRemainingEth1PendingDepositsIfElectraIsEnabled() { + setup(16, SpecMilestone.ELECTRA); + updateStateEth1DepositIndex(5); + updateStateEth1DataDepositCount(20); + // 16th deposit is using the new mechanism + updateStateDepositReceiptsStartIndex(16); + + mockDepositsFromEth1Block(0, 10); + mockDepositsFromEth1Block(10, 20); + + final SszList deposits = depositProvider.getDeposits(state, randomEth1Data); + + // the pending Eth1 deposits (deposit_receipt_start_index - eth1_deposit_index) + assertThat(deposits).hasSize(11); + checkThatDepositProofIsValid(deposits); + } + @Test void depositsWithFinalizedIndicesGetPrunedFromMap() { setup(16); Bytes32 finalizedBlockRoot = Bytes32.fromHexString("0x01"); - mockStateEth1DepositIndex(10); - mockEth1DataDepositCount(10); + updateStateEth1DepositIndex(10); + updateStateEth1DataDepositCount(10); mockDepositsFromEth1Block(0, 20); final AnchorPoint anchorPoint = mock(AnchorPoint.class); final UpdatableStore store = mock(UpdatableStore.class); when(recentChainData.getStore()).thenReturn(store); when(store.getLatestFinalized()).thenReturn(anchorPoint); - when(anchorPoint.getState()).thenReturn(state); + when(anchorPoint.getState()).thenAnswer(__ -> state); assertThat(depositProvider.getDepositMapSize()).isEqualTo(20); @@ -219,8 +258,8 @@ void shouldNotifyEth1DataCacheOfDepositBlocks() { @Test void shouldNotThrowMissingDepositsExceptionWhenAllKnownDepositsHaveBeenIncluded() { setup(16); - mockStateEth1DepositIndex(5); - mockEth1DataDepositCount(5); + updateStateEth1DepositIndex(5); + updateStateEth1DataDepositCount(5); mockDepositsFromEth1Block(0, 5); assertThat(depositProvider.getDeposits(state, randomEth1Data)).isEmpty(); } @@ -228,8 +267,8 @@ void shouldNotThrowMissingDepositsExceptionWhenAllKnownDepositsHaveBeenIncluded( @Test void shouldThrowMissingDepositsExceptionWhenRequiredDepositsAreNotAvailable() { setup(16); - mockStateEth1DepositIndex(5); - mockEth1DataDepositCount(10); + updateStateEth1DepositIndex(5); + updateStateEth1DataDepositCount(10); assertThatThrownBy(() -> depositProvider.getDeposits(state, randomEth1Data)) .isInstanceOf(MissingDepositsException.class) .hasMessageContaining("6 to 10"); @@ -241,8 +280,8 @@ void shouldThrowMissingDepositsExceptionWhenAllDepositsRequiredForStateNotAvaila // To generate a valid proof we need the deposits up to state deposit count // So fail even if we could have filled MAX_DEPOSITS mockDepositsFromEth1Block(0, 8); - mockStateEth1DepositIndex(5); - mockEth1DataDepositCount(10); + updateStateEth1DepositIndex(5); + updateStateEth1DataDepositCount(10); assertThatThrownBy(() -> depositProvider.getDeposits(state, randomEth1Data)) .isInstanceOf(MissingDepositsException.class) @@ -255,8 +294,8 @@ void shouldLogAnEventOnSlotWhenAllDepositsRequiredForStateNotAvailable() { // To generate a valid proof we need the deposits up to state deposit count // So we want to check if on each slot our node has necessary deposit data mockDepositsFromEth1Block(0, 8); - mockStateEth1DepositIndex(5); - mockEth1DataDepositCount(10); + updateStateEth1DepositIndex(5); + updateStateEth1DataDepositCount(10); when(recentChainData.getBestState()).thenReturn(Optional.of(SafeFuture.completedFuture(state))); depositProvider.onSlot(UInt64.ONE); @@ -270,8 +309,8 @@ void shouldNotLogAnEventOnSlotWhenAllDepositsRequiredForStateAvailable() { // To generate a valid proof we need the deposits up to state deposit count // So we want to check if on each slot our node has necessary deposit data mockDepositsFromEth1Block(0, 10); - mockStateEth1DepositIndex(5); - mockEth1DataDepositCount(10); + updateStateEth1DepositIndex(5); + updateStateEth1DataDepositCount(10); when(recentChainData.getBestState()).thenReturn(Optional.of(SafeFuture.completedFuture(state))); depositProvider.onSlot(UInt64.ONE); @@ -285,8 +324,8 @@ void shouldThrowWhenAllDepositsRequiredForStateNotAvailable_skippedDeposit() { mockDepositsFromEth1Block(0, 7); // Deposit 7 is missing mockDepositsFromEth1Block(8, 10); - mockStateEth1DepositIndex(5); - mockEth1DataDepositCount(10); + updateStateEth1DepositIndex(5); + updateStateEth1DataDepositCount(10); assertThatThrownBy(() -> depositProvider.getDeposits(state, randomEth1Data)) .isInstanceOf(MissingDepositsException.class) @@ -299,8 +338,8 @@ void shouldThrowWhenAllDepositsRequiredForStateNotAvailable_skippedDeposits() { mockDepositsFromEth1Block(0, 7); // Deposits 7,8 are missing mockDepositsFromEth1Block(9, 10); - mockStateEth1DepositIndex(5); - mockEth1DataDepositCount(10); + updateStateEth1DepositIndex(5); + updateStateEth1DataDepositCount(10); assertThatThrownBy(() -> depositProvider.getDeposits(state, randomEth1Data)) .isInstanceOf(MissingDepositsException.class) @@ -310,7 +349,7 @@ void shouldThrowWhenAllDepositsRequiredForStateNotAvailable_skippedDeposits() { @Test void whenCallingAvailableDeposits_AllDepositReturned() { setup(5); - mockStateEth1DepositIndex(10); + updateStateEth1DepositIndex(10); mockDepositsFromEth1Block(0, 10); List deposits = depositProvider.getAvailableDeposits(); assertThat(deposits.size()).isEqualTo(10); @@ -319,9 +358,9 @@ void whenCallingAvailableDeposits_AllDepositReturned() { @Test void whenCallingAvailableDepositsAndSomeDepositsAlreadyInState_AllDepositsReturned() { setup(10); - mockStateEth1DepositIndex(2); + updateStateEth1DepositIndex(2); mockDepositsFromEth1Block(0, 10); - mockEth1DataDepositCount(10); + updateStateEth1DataDepositCount(10); SszList deposits = depositProvider.getDeposits(state, randomEth1Data); assertThat(deposits.size()).isEqualTo(8); List availableDeposits = depositProvider.getAvailableDeposits(); @@ -332,14 +371,14 @@ void whenCallingAvailableDepositsAndSomeDepositsAlreadyInState_AllDepositsReturn void whenCallingAvailableDepositsAndSomeDepositsPruned_AllNotPrunedDepositsReturned() { setup(16); Bytes32 finalizedBlockRoot = Bytes32.fromHexString("0x01"); - mockStateEth1DepositIndex(10); - mockEth1DataDepositCount(10); + updateStateEth1DepositIndex(10); + updateStateEth1DataDepositCount(10); mockDepositsFromEth1Block(0, 20); final AnchorPoint anchorPoint = mock(AnchorPoint.class); final UpdatableStore store = mock(UpdatableStore.class); when(recentChainData.getStore()).thenReturn(store); when(store.getLatestFinalized()).thenReturn(anchorPoint); - when(anchorPoint.getState()).thenReturn(state); + when(anchorPoint.getState()).thenAnswer(__ -> state); assertThat(depositProvider.getDepositMapSize()).isEqualTo(20); @@ -364,15 +403,15 @@ void whenCallingForFinalizedSnapshotAndSnapshotAvailable_SnapshotReturned() { dataStructureUtil.randomBytes32(), UInt64.valueOf(10), dataStructureUtil.randomBytes32()); - when(state.getEth1Data()).thenReturn(eth1Data1); + updateStateEth1Data(eth1Data1); Bytes32 finalizedBlockRoot = Bytes32.fromHexString("0x01"); - mockStateEth1DepositIndex(10); + updateStateEth1DepositIndex(10); mockDepositsFromEth1Block(0, 20); final AnchorPoint anchorPoint = mock(AnchorPoint.class); final UpdatableStore store = mock(UpdatableStore.class); when(recentChainData.getStore()).thenReturn(store); when(store.getLatestFinalized()).thenReturn(anchorPoint); - when(anchorPoint.getState()).thenReturn(state); + when(anchorPoint.getState()).thenAnswer(__ -> state); assertThat(depositProvider.getDepositMapSize()).isEqualTo(20); @@ -408,8 +447,8 @@ void whenCallingForFinalizedSnapshotAndSnapshotAvailable_SnapshotReturned() { dataStructureUtil.randomBytes32(), UInt64.valueOf(20), dataStructureUtil.randomBytes32()); - mockStateEth1DepositIndex(20); - when(state.getEth1Data()).thenReturn(eth1Data2); + updateStateEth1DepositIndex(20); + updateStateEth1Data(eth1Data2); when(eth1DataCache.getEth1DataAndHeight(eq(eth1Data2))) .thenReturn( Optional.of(new Eth1DataCache.Eth1DataAndHeight(eth1Data2, UInt64.valueOf(30)))); @@ -464,18 +503,28 @@ private void mockDepositsFromEth1Block(int startIndex, int n) { depositProvider.onDepositsFromBlock(depositsFromBlockEvent); } - private void mockEth1DataDepositCount(int n) { - Eth1Data eth1Data = mock(Eth1Data.class); - when(state.getEth1Data()).thenReturn(eth1Data); - when(eth1Data.getBlockHash()).thenReturn(dataStructureUtil.randomBytes32()); - when(eth1Data.getDepositCount()).thenReturn(UInt64.valueOf(n)); + private void updateStateEth1Data(Eth1Data eth1Data) { + state = state.updated(mutableState -> mutableState.setEth1Data(eth1Data)); + } + + private void updateStateEth1DataDepositCount(int n) { + final Eth1Data eth1Data = + new Eth1Data( + dataStructureUtil.randomBytes32(), + UInt64.valueOf(n), + dataStructureUtil.randomBytes32()); + updateStateEth1Data(eth1Data); } - private void mockStateEth1DepositIndex(int n) { - when(state.getEth1DepositIndex()).thenReturn(UInt64.valueOf(n)); + private void updateStateEth1DepositIndex(int n) { + state = state.updated(mutableState -> mutableState.setEth1DepositIndex(UInt64.valueOf(n))); } - private void mockStateEth1DataVotes() { - when(state.getEth1DataVotes()).thenReturn(SszListSchema.create(Eth1Data.SSZ_SCHEMA, 0).of()); + private void updateStateDepositReceiptsStartIndex(int n) { + state = + state.updated( + mutableState -> + MutableBeaconStateElectra.required(mutableState) + .setDepositReceiptsStartIndex(UInt64.valueOf(n))); } } diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/Spec.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/Spec.java index fe1d2288ff2..695442c4cd5 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/Spec.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/Spec.java @@ -934,6 +934,11 @@ public Optional computeFirstSlotWithBlobSupport() { .map(this::computeStartSlotAtEpoch); } + // Electra Utils + public boolean isFormerDepositMechanismDisabled(BeaconState state) { + return atState(state).miscHelpers().isFormerDepositMechanismDisabled(state); + } + // Deneb private helpers private Optional getSpecConfigDeneb() { final SpecMilestone highestSupportedMilestone = diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/common/helpers/MiscHelpers.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/common/helpers/MiscHelpers.java index 364da862ea6..ace2a21ac51 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/common/helpers/MiscHelpers.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/common/helpers/MiscHelpers.java @@ -374,6 +374,10 @@ public UInt64 getMaxRequestBlocks() { return UInt64.valueOf(specConfig.getNetworkingConfig().getMaxRequestBlocks()); } + public boolean isFormerDepositMechanismDisabled(final BeaconState state) { + return false; + } + public Optional toVersionDeneb() { return Optional.empty(); } diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/SpecLogicElectra.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/SpecLogicElectra.java index 12ec358b02b..bd8f8ee8e39 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/SpecLogicElectra.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/SpecLogicElectra.java @@ -43,6 +43,7 @@ import tech.pegasys.teku.spec.logic.versions.deneb.util.ForkChoiceUtilDeneb; import tech.pegasys.teku.spec.logic.versions.electra.block.BlockProcessorElectra; import tech.pegasys.teku.spec.logic.versions.electra.forktransition.ElectraStateUpgrade; +import tech.pegasys.teku.spec.logic.versions.electra.helpers.MiscHelpersElectra; import tech.pegasys.teku.spec.schemas.SchemaDefinitionsElectra; public class SpecLogicElectra extends AbstractSpecLogic { @@ -93,8 +94,8 @@ public static SpecLogicElectra create( final SpecConfigElectra config, final SchemaDefinitionsElectra schemaDefinitions) { // Helpers final Predicates predicates = new Predicates(config); - final MiscHelpersDeneb miscHelpers = - new MiscHelpersDeneb(config, predicates, schemaDefinitions); + final MiscHelpersElectra miscHelpers = + new MiscHelpersElectra(config, predicates, schemaDefinitions); final BeaconStateAccessorsDeneb beaconStateAccessors = new BeaconStateAccessorsDeneb(config, predicates, miscHelpers); final BeaconStateMutatorsBellatrix beaconStateMutators = diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/block/BlockProcessorElectra.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/block/BlockProcessorElectra.java index 6317fb06ffd..72972137565 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/block/BlockProcessorElectra.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/block/BlockProcessorElectra.java @@ -107,7 +107,7 @@ protected void verifyOutstandingDepositsAreProcessed( final int expectedDepositCount = Math.min( specConfig.getMaxDeposits(), - state.getEth1DepositIndex().minus(eth1DepositIndexLimit).intValue()); + eth1DepositIndexLimit.minus(state.getEth1DepositIndex()).intValue()); checkArgument( body.getDeposits().size() == expectedDepositCount, diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/helpers/MiscHelpersElectra.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/helpers/MiscHelpersElectra.java new file mode 100644 index 00000000000..76e2148a920 --- /dev/null +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/helpers/MiscHelpersElectra.java @@ -0,0 +1,41 @@ +/* + * Copyright Consensys Software Inc., 2024 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package tech.pegasys.teku.spec.logic.versions.electra.helpers; + +import tech.pegasys.teku.spec.config.SpecConfigElectra; +import tech.pegasys.teku.spec.datastructures.state.beaconstate.BeaconState; +import tech.pegasys.teku.spec.datastructures.state.beaconstate.versions.electra.BeaconStateElectra; +import tech.pegasys.teku.spec.logic.common.helpers.Predicates; +import tech.pegasys.teku.spec.logic.versions.deneb.helpers.MiscHelpersDeneb; +import tech.pegasys.teku.spec.schemas.SchemaDefinitionsElectra; + +public class MiscHelpersElectra extends MiscHelpersDeneb { + + public MiscHelpersElectra( + final SpecConfigElectra specConfig, + final Predicates predicates, + final SchemaDefinitionsElectra schemaDefinitions) { + super(specConfig, predicates, schemaDefinitions); + } + + @Override + public boolean isFormerDepositMechanismDisabled(final BeaconState state) { + // if the next deposit to be processed by Eth1Data poll has the index of the first deposit + // processed with the new deposit flow, i.e. `eth1_deposit_index == + // deposit_receipts_start_index`, we should stop Eth1Data deposits processing + return state + .getEth1DepositIndex() + .equals(BeaconStateElectra.required(state).getDepositReceiptsStartIndex()); + } +} diff --git a/ethereum/spec/src/test/java/tech/pegasys/teku/spec/logic/versions/electra/helpers/MiscHelpersElectraTest.java b/ethereum/spec/src/test/java/tech/pegasys/teku/spec/logic/versions/electra/helpers/MiscHelpersElectraTest.java new file mode 100644 index 00000000000..5a3698f1719 --- /dev/null +++ b/ethereum/spec/src/test/java/tech/pegasys/teku/spec/logic/versions/electra/helpers/MiscHelpersElectraTest.java @@ -0,0 +1,76 @@ +/* + * Copyright Consensys Software Inc., 2024 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package tech.pegasys.teku.spec.logic.versions.electra.helpers; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; +import tech.pegasys.teku.infrastructure.unsigned.UInt64; +import tech.pegasys.teku.spec.Spec; +import tech.pegasys.teku.spec.TestSpecFactory; +import tech.pegasys.teku.spec.config.SpecConfigElectra; +import tech.pegasys.teku.spec.datastructures.state.beaconstate.BeaconState; +import tech.pegasys.teku.spec.datastructures.state.beaconstate.versions.electra.BeaconStateElectra; +import tech.pegasys.teku.spec.datastructures.state.beaconstate.versions.electra.MutableBeaconStateElectra; +import tech.pegasys.teku.spec.logic.common.helpers.Predicates; +import tech.pegasys.teku.spec.schemas.SchemaDefinitionsElectra; +import tech.pegasys.teku.spec.util.DataStructureUtil; + +public class MiscHelpersElectraTest { + + private final Spec spec = TestSpecFactory.createMinimalElectra(); + private final Predicates predicates = new Predicates(spec.getGenesisSpecConfig()); + private final SchemaDefinitionsElectra schemaDefinitionsElectra = + SchemaDefinitionsElectra.required(spec.getGenesisSchemaDefinitions()); + private final MiscHelpersElectra miscHelpersElectra = + new MiscHelpersElectra( + spec.getGenesisSpecConfig().toVersionElectra().orElseThrow(), + predicates, + schemaDefinitionsElectra); + private final DataStructureUtil dataStructureUtil = new DataStructureUtil(spec); + + @Test + public void isFormerDepositMechanismDisabled_returnsTrueIfDisabled() { + final BeaconState preState = dataStructureUtil.randomBeaconState(); + + final BeaconState state = + BeaconStateElectra.required(preState) + .updated( + mutableState -> { + final UInt64 eth1DepositIndex = dataStructureUtil.randomUInt64(); + mutableState.setEth1DepositIndex(eth1DepositIndex); + MutableBeaconStateElectra.required(mutableState) + .setDepositReceiptsStartIndex(eth1DepositIndex); + }); + + assertThat(miscHelpersElectra.isFormerDepositMechanismDisabled(state)).isTrue(); + } + + @Test + public void isFormerDepositMechanismDisabled_returnsFalseIfNotDisabled() { + final BeaconState preState = dataStructureUtil.randomBeaconState(); + + final BeaconState state = + BeaconStateElectra.required(preState) + .updated( + mutableState -> { + mutableState.setEth1DepositIndex(UInt64.valueOf(64)); + MutableBeaconStateElectra.required(mutableState) + .setDepositReceiptsStartIndex( + SpecConfigElectra.UNSET_DEPOSIT_RECEIPTS_START_INDEX); + }); + + assertThat(miscHelpersElectra.isFormerDepositMechanismDisabled(state)).isFalse(); + } +} From acf505570f3039a7f20736e93388d45b86858b3b Mon Sep 17 00:00:00 2001 From: Stefan Bratanov Date: Thu, 21 Mar 2024 17:36:30 +0000 Subject: [PATCH 05/13] add test --- .../execution/ExecutionPayloadSchema.java | 4 + .../ExecutionPayloadSchemaBellatrix.java | 7 + .../ExecutionPayloadSchemaCapella.java | 7 + .../deneb/ExecutionPayloadSchemaDeneb.java | 7 + .../ExecutionPayloadSchemaElectra.java | 6 + .../util/DepositReceiptsUtil.java | 55 +++++++ .../block/BlockProcessorBellatrixTest.java | 16 +- .../block/BlockProcessorCapellaTest.java | 13 -- .../deneb/block/BlockProcessorDenebTest.java | 14 +- .../block/BlockProcessorElectraTest.java | 144 ++++++++++++++++++ 10 files changed, 232 insertions(+), 41 deletions(-) create mode 100644 ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/util/DepositReceiptsUtil.java create mode 100644 ethereum/spec/src/test/java/tech/pegasys/teku/spec/logic/versions/electra/block/BlockProcessorElectraTest.java diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/ExecutionPayloadSchema.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/ExecutionPayloadSchema.java index 1eb8b0655e5..c297285abfb 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/ExecutionPayloadSchema.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/ExecutionPayloadSchema.java @@ -22,6 +22,7 @@ import tech.pegasys.teku.spec.datastructures.builder.BuilderPayloadSchema; import tech.pegasys.teku.spec.datastructures.execution.versions.capella.Withdrawal; import tech.pegasys.teku.spec.datastructures.execution.versions.capella.WithdrawalSchema; +import tech.pegasys.teku.spec.datastructures.execution.versions.electra.DepositReceipt; import tech.pegasys.teku.spec.datastructures.execution.versions.electra.DepositReceiptSchema; import tech.pegasys.teku.spec.datastructures.execution.versions.electra.ExecutionLayerExitSchema; @@ -37,6 +38,9 @@ public interface ExecutionPayloadSchema WithdrawalSchema getWithdrawalSchemaRequired(); + SszListSchema> + getDepositReceiptsSchemaRequired(); + DepositReceiptSchema getDepositReceiptSchemaRequired(); ExecutionLayerExitSchema getExecutionLayerExitSchemaRequired(); diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/bellatrix/ExecutionPayloadSchemaBellatrix.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/bellatrix/ExecutionPayloadSchemaBellatrix.java index c9647126a82..be750d29944 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/bellatrix/ExecutionPayloadSchemaBellatrix.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/bellatrix/ExecutionPayloadSchemaBellatrix.java @@ -51,6 +51,7 @@ import tech.pegasys.teku.spec.datastructures.execution.TransactionSchema; import tech.pegasys.teku.spec.datastructures.execution.versions.capella.Withdrawal; import tech.pegasys.teku.spec.datastructures.execution.versions.capella.WithdrawalSchema; +import tech.pegasys.teku.spec.datastructures.execution.versions.electra.DepositReceipt; import tech.pegasys.teku.spec.datastructures.execution.versions.electra.DepositReceiptSchema; import tech.pegasys.teku.spec.datastructures.execution.versions.electra.ExecutionLayerExitSchema; @@ -114,6 +115,12 @@ public WithdrawalSchema getWithdrawalSchemaRequired() { throw new IllegalStateException("Attempted to get a withdrawal schema from bellatrix"); } + @Override + public SszListSchema> + getDepositReceiptsSchemaRequired() { + throw new IllegalStateException("Attempted to get a deposit receipts schema from bellatrix"); + } + @Override public DepositReceiptSchema getDepositReceiptSchemaRequired() { throw new IllegalStateException("Attempted to get a deposit receipt schema from bellatrix"); diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/capella/ExecutionPayloadSchemaCapella.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/capella/ExecutionPayloadSchemaCapella.java index f4b7d448f20..640d4d5aed0 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/capella/ExecutionPayloadSchemaCapella.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/capella/ExecutionPayloadSchemaCapella.java @@ -50,6 +50,7 @@ import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadSchema; import tech.pegasys.teku.spec.datastructures.execution.Transaction; import tech.pegasys.teku.spec.datastructures.execution.TransactionSchema; +import tech.pegasys.teku.spec.datastructures.execution.versions.electra.DepositReceipt; import tech.pegasys.teku.spec.datastructures.execution.versions.electra.DepositReceiptSchema; import tech.pegasys.teku.spec.datastructures.execution.versions.electra.ExecutionLayerExitSchema; @@ -121,6 +122,12 @@ public WithdrawalSchema getWithdrawalSchemaRequired() { return getWithdrawalSchema(); } + @Override + public SszListSchema> + getDepositReceiptsSchemaRequired() { + throw new IllegalStateException("Attempted to get a deposit receipts schema from capella"); + } + @Override public DepositReceiptSchema getDepositReceiptSchemaRequired() { throw new IllegalStateException("Attempted to get a deposit receipt schema from capella"); diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/deneb/ExecutionPayloadSchemaDeneb.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/deneb/ExecutionPayloadSchemaDeneb.java index e30dcd66d28..c1e01b37fd9 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/deneb/ExecutionPayloadSchemaDeneb.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/deneb/ExecutionPayloadSchemaDeneb.java @@ -54,6 +54,7 @@ import tech.pegasys.teku.spec.datastructures.execution.TransactionSchema; import tech.pegasys.teku.spec.datastructures.execution.versions.capella.Withdrawal; import tech.pegasys.teku.spec.datastructures.execution.versions.capella.WithdrawalSchema; +import tech.pegasys.teku.spec.datastructures.execution.versions.electra.DepositReceipt; import tech.pegasys.teku.spec.datastructures.execution.versions.electra.DepositReceiptSchema; import tech.pegasys.teku.spec.datastructures.execution.versions.electra.ExecutionLayerExitSchema; @@ -129,6 +130,12 @@ public WithdrawalSchema getWithdrawalSchemaRequired() { return getWithdrawalSchema(); } + @Override + public SszListSchema> + getDepositReceiptsSchemaRequired() { + throw new IllegalStateException("Attempted to get a deposit receipts schema from deneb"); + } + @Override public DepositReceiptSchema getDepositReceiptSchemaRequired() { throw new IllegalStateException("Attempted to get a deposit receipt schema from deneb"); diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/ExecutionPayloadSchemaElectra.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/ExecutionPayloadSchemaElectra.java index 885956acdbe..211beab72b7 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/ExecutionPayloadSchemaElectra.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/ExecutionPayloadSchemaElectra.java @@ -139,6 +139,12 @@ public WithdrawalSchema getWithdrawalSchemaRequired() { return getWithdrawalSchema(); } + @Override + public SszListSchema> + getDepositReceiptsSchemaRequired() { + return getDepositReceiptsSchema(); + } + @Override public DepositReceiptSchema getDepositReceiptSchemaRequired() { return getDepositReceiptSchema(); diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/util/DepositReceiptsUtil.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/util/DepositReceiptsUtil.java new file mode 100644 index 00000000000..0d8c50bc3fc --- /dev/null +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/util/DepositReceiptsUtil.java @@ -0,0 +1,55 @@ +/* + * Copyright Consensys Software Inc., 2024 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package tech.pegasys.teku.spec.datastructures.util; + +import java.security.SecureRandom; +import org.apache.tuweni.bytes.Bytes32; +import tech.pegasys.teku.bls.BLS; +import tech.pegasys.teku.bls.BLSKeyPair; +import tech.pegasys.teku.bls.BLSPublicKey; +import tech.pegasys.teku.bls.BLSSignature; +import tech.pegasys.teku.infrastructure.unsigned.UInt64; +import tech.pegasys.teku.spec.Spec; +import tech.pegasys.teku.spec.constants.Domain; +import tech.pegasys.teku.spec.datastructures.execution.versions.electra.DepositReceipt; +import tech.pegasys.teku.spec.datastructures.operations.DepositMessage; +import tech.pegasys.teku.spec.logic.common.helpers.MiscHelpers; + +public class DepositReceiptsUtil { + + @SuppressWarnings("DoNotCreateSecureRandomDirectly") + private final SecureRandom random = new SecureRandom(); + + private final Spec spec; + + public DepositReceiptsUtil(final Spec spec) { + this.spec = spec; + } + + public DepositReceipt createDepositReceipt(final UInt64 slot, final UInt64 index) { + final BLSKeyPair validatorKeyPair = BLSKeyPair.random(random); + final BLSPublicKey publicKey = validatorKeyPair.getPublicKey(); + final UInt64 depositAmount = UInt64.THIRTY_TWO_ETH; + final DepositMessage depositMessage = + new DepositMessage(publicKey, Bytes32.ZERO, depositAmount); + final MiscHelpers miscHelpers = spec.atSlot(slot).miscHelpers(); + final Bytes32 depositDomain = miscHelpers.computeDomain(Domain.DEPOSIT); + final BLSSignature signature = + BLS.sign( + validatorKeyPair.getSecretKey(), + miscHelpers.computeSigningRoot(depositMessage, depositDomain)); + return DepositReceipt.SSZ_SCHEMA.create( + publicKey, Bytes32.ZERO, depositAmount, signature, index); + } +} diff --git a/ethereum/spec/src/test/java/tech/pegasys/teku/spec/logic/versions/bellatrix/block/BlockProcessorBellatrixTest.java b/ethereum/spec/src/test/java/tech/pegasys/teku/spec/logic/versions/bellatrix/block/BlockProcessorBellatrixTest.java index 059c91bb7b8..78c47203003 100644 --- a/ethereum/spec/src/test/java/tech/pegasys/teku/spec/logic/versions/bellatrix/block/BlockProcessorBellatrixTest.java +++ b/ethereum/spec/src/test/java/tech/pegasys/teku/spec/logic/versions/bellatrix/block/BlockProcessorBellatrixTest.java @@ -14,38 +14,24 @@ package tech.pegasys.teku.spec.logic.versions.bellatrix.block; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; -import java.util.Optional; import org.junit.jupiter.api.Test; -import tech.pegasys.teku.bls.BLSSignatureVerifier; import tech.pegasys.teku.infrastructure.unsigned.UInt64; import tech.pegasys.teku.spec.Spec; import tech.pegasys.teku.spec.TestSpecFactory; -import tech.pegasys.teku.spec.datastructures.blocks.SignedBeaconBlock; import tech.pegasys.teku.spec.datastructures.blocks.blockbody.BeaconBlockBody; import tech.pegasys.teku.spec.datastructures.execution.NewPayloadRequest; import tech.pegasys.teku.spec.datastructures.state.beaconstate.BeaconState; import tech.pegasys.teku.spec.logic.common.statetransition.exceptions.BlockProcessingException; -import tech.pegasys.teku.spec.logic.common.statetransition.exceptions.StateTransitionException; import tech.pegasys.teku.spec.logic.versions.altair.block.BlockProcessorAltairTest; public class BlockProcessorBellatrixTest extends BlockProcessorAltairTest { + @Override protected Spec createSpec() { return TestSpecFactory.createMainnetBellatrix(); } - @Test - void shouldRejectAltairBlock() { - final BeaconState preState = createBeaconState(); - final SignedBeaconBlock block = - dataStructureUtil.randomSignedBeaconBlock(preState.getSlot().increment()); - assertThatThrownBy( - () -> spec.processBlock(preState, block, BLSSignatureVerifier.SIMPLE, Optional.empty())) - .isInstanceOf(StateTransitionException.class); - } - @Test public void shouldCreateNewPayloadRequest() throws BlockProcessingException { final BeaconState preState = createBeaconState(); diff --git a/ethereum/spec/src/test/java/tech/pegasys/teku/spec/logic/versions/capella/block/BlockProcessorCapellaTest.java b/ethereum/spec/src/test/java/tech/pegasys/teku/spec/logic/versions/capella/block/BlockProcessorCapellaTest.java index c8156d23737..909bd617dc3 100644 --- a/ethereum/spec/src/test/java/tech/pegasys/teku/spec/logic/versions/capella/block/BlockProcessorCapellaTest.java +++ b/ethereum/spec/src/test/java/tech/pegasys/teku/spec/logic/versions/capella/block/BlockProcessorCapellaTest.java @@ -14,7 +14,6 @@ package tech.pegasys.teku.spec.logic.versions.capella.block; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; import java.util.ArrayList; import java.util.List; @@ -29,7 +28,6 @@ import tech.pegasys.teku.spec.Spec; import tech.pegasys.teku.spec.TestSpecFactory; import tech.pegasys.teku.spec.config.SpecConfig; -import tech.pegasys.teku.spec.datastructures.blocks.SignedBeaconBlock; import tech.pegasys.teku.spec.datastructures.execution.versions.capella.Withdrawal; import tech.pegasys.teku.spec.datastructures.operations.BlsToExecutionChange; import tech.pegasys.teku.spec.datastructures.operations.SignedBlsToExecutionChange; @@ -38,7 +36,6 @@ import tech.pegasys.teku.spec.datastructures.state.beaconstate.BeaconState; import tech.pegasys.teku.spec.generator.ChainBuilder; import tech.pegasys.teku.spec.logic.common.statetransition.blockvalidator.BlockValidationResult; -import tech.pegasys.teku.spec.logic.common.statetransition.exceptions.StateTransitionException; import tech.pegasys.teku.spec.logic.versions.bellatrix.block.BlockProcessorBellatrixTest; import tech.pegasys.teku.spec.schemas.SchemaDefinitionsCapella; import tech.pegasys.teku.spec.util.DataStructureUtil; @@ -50,16 +47,6 @@ protected Spec createSpec() { return TestSpecFactory.createMainnetCapella(); } - @Test - void shouldRejectBellatrixBlock() { - BeaconState preState = createBeaconState(); - final SignedBeaconBlock block = - dataStructureUtil.randomSignedBeaconBlock(preState.getSlot().increment()); - assertThatThrownBy( - () -> spec.processBlock(preState, block, BLSSignatureVerifier.SIMPLE, Optional.empty())) - .isInstanceOf(StateTransitionException.class); - } - @Test void shouldCreateExpectedWithdrawalAddress() { Bytes20 eth1Address = dataStructureUtil.randomBytes20(); diff --git a/ethereum/spec/src/test/java/tech/pegasys/teku/spec/logic/versions/deneb/block/BlockProcessorDenebTest.java b/ethereum/spec/src/test/java/tech/pegasys/teku/spec/logic/versions/deneb/block/BlockProcessorDenebTest.java index 072ba7e6873..6dd2c4cbfe7 100644 --- a/ethereum/spec/src/test/java/tech/pegasys/teku/spec/logic/versions/deneb/block/BlockProcessorDenebTest.java +++ b/ethereum/spec/src/test/java/tech/pegasys/teku/spec/logic/versions/deneb/block/BlockProcessorDenebTest.java @@ -20,38 +20,26 @@ import java.util.Optional; import java.util.stream.Collectors; import org.junit.jupiter.api.Test; -import tech.pegasys.teku.bls.BLSSignatureVerifier; import tech.pegasys.teku.infrastructure.unsigned.UInt64; import tech.pegasys.teku.spec.Spec; import tech.pegasys.teku.spec.TestSpecFactory; import tech.pegasys.teku.spec.config.SpecConfigDeneb; -import tech.pegasys.teku.spec.datastructures.blocks.SignedBeaconBlock; import tech.pegasys.teku.spec.datastructures.blocks.blockbody.BeaconBlockBody; import tech.pegasys.teku.spec.datastructures.execution.NewPayloadRequest; import tech.pegasys.teku.spec.datastructures.state.beaconstate.BeaconState; import tech.pegasys.teku.spec.datastructures.type.SszKZGCommitment; import tech.pegasys.teku.spec.logic.common.helpers.MiscHelpers; import tech.pegasys.teku.spec.logic.common.statetransition.exceptions.BlockProcessingException; -import tech.pegasys.teku.spec.logic.common.statetransition.exceptions.StateTransitionException; import tech.pegasys.teku.spec.logic.versions.capella.block.BlockProcessorCapellaTest; import tech.pegasys.teku.spec.logic.versions.deneb.types.VersionedHash; public class BlockProcessorDenebTest extends BlockProcessorCapellaTest { + @Override protected Spec createSpec() { return TestSpecFactory.createMainnetDeneb(); } - @Test - void shouldRejectCapellaBlock() { - BeaconState preState = createBeaconState(); - final SignedBeaconBlock block = - dataStructureUtil.randomSignedBeaconBlock(preState.getSlot().increment()); - assertThatThrownBy( - () -> spec.processBlock(preState, block, BLSSignatureVerifier.SIMPLE, Optional.empty())) - .isInstanceOf(StateTransitionException.class); - } - @Test void shouldFailProcessingIfCommitmentsInBlockAreMoreThanMaxBlobsPerBlock() { final BeaconState preState = createBeaconState(); diff --git a/ethereum/spec/src/test/java/tech/pegasys/teku/spec/logic/versions/electra/block/BlockProcessorElectraTest.java b/ethereum/spec/src/test/java/tech/pegasys/teku/spec/logic/versions/electra/block/BlockProcessorElectraTest.java new file mode 100644 index 00000000000..a9120eb7320 --- /dev/null +++ b/ethereum/spec/src/test/java/tech/pegasys/teku/spec/logic/versions/electra/block/BlockProcessorElectraTest.java @@ -0,0 +1,144 @@ +/* + * Copyright Consensys Software Inc., 2024 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package tech.pegasys.teku.spec.logic.versions.electra.block; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.List; +import java.util.stream.IntStream; +import org.junit.jupiter.api.Test; +import tech.pegasys.teku.infrastructure.ssz.SszList; +import tech.pegasys.teku.infrastructure.ssz.schema.SszListSchema; +import tech.pegasys.teku.infrastructure.unsigned.UInt64; +import tech.pegasys.teku.spec.Spec; +import tech.pegasys.teku.spec.TestSpecFactory; +import tech.pegasys.teku.spec.config.SpecConfigElectra; +import tech.pegasys.teku.spec.datastructures.blocks.Eth1Data; +import tech.pegasys.teku.spec.datastructures.blocks.blockbody.BeaconBlockBody; +import tech.pegasys.teku.spec.datastructures.execution.versions.electra.DepositReceipt; +import tech.pegasys.teku.spec.datastructures.state.beaconstate.BeaconState; +import tech.pegasys.teku.spec.datastructures.state.beaconstate.versions.electra.BeaconStateElectra; +import tech.pegasys.teku.spec.datastructures.state.beaconstate.versions.electra.MutableBeaconStateElectra; +import tech.pegasys.teku.spec.datastructures.util.DepositReceiptsUtil; +import tech.pegasys.teku.spec.logic.versions.deneb.block.BlockProcessorDenebTest; +import tech.pegasys.teku.spec.schemas.SchemaDefinitionsElectra; + +class BlockProcessorElectraTest extends BlockProcessorDenebTest { + + protected DepositReceiptsUtil depositReceiptsUtil = new DepositReceiptsUtil(spec); + + @Override + protected Spec createSpec() { + return TestSpecFactory.createMainnetElectra(); + } + + @Test + public void verifiesOutstandingEth1DepositsAreProcessed() { + final BeaconState state = + createBeaconState() + .updated( + mutableState -> { + final UInt64 eth1DepositCount = UInt64.valueOf(25); + mutableState.setEth1Data( + new Eth1Data( + dataStructureUtil.randomBytes32(), + eth1DepositCount, + dataStructureUtil.randomBytes32())); + final UInt64 eth1DepositIndex = UInt64.valueOf(13); + mutableState.setEth1DepositIndex(eth1DepositIndex); + final UInt64 depositReceiptsStartIndex = UInt64.valueOf(20); + MutableBeaconStateElectra.required(mutableState) + .setDepositReceiptsStartIndex(depositReceiptsStartIndex); + }); + + final BeaconBlockBody body = + dataStructureUtil.randomFullBeaconBlockBody( + // 20 - 13 = 7 + builder -> builder.deposits(dataStructureUtil.randomSszDeposits(7))); + + getBlockProcessor(state).verifyOutstandingDepositsAreProcessed(state, body); + } + + @Test + public void + verifiesNoOutstandingEth1DepositsAreProcessedWhenFormerDepositMechanismHasBeenDisabled() { + final BeaconState state = + createBeaconState() + .updated( + mutableState -> { + final UInt64 eth1DepositCount = UInt64.valueOf(25); + mutableState.setEth1Data( + new Eth1Data( + dataStructureUtil.randomBytes32(), + eth1DepositCount, + dataStructureUtil.randomBytes32())); + final UInt64 eth1DepositIndex = UInt64.valueOf(20); + mutableState.setEth1DepositIndex(eth1DepositIndex); + final UInt64 depositReceiptsStartIndex = UInt64.valueOf(20); + MutableBeaconStateElectra.required(mutableState) + .setDepositReceiptsStartIndex(depositReceiptsStartIndex); + }); + + final BeaconBlockBody body = + dataStructureUtil.randomFullBeaconBlockBody( + // 20 - 20 = 0 + modifier -> modifier.deposits(dataStructureUtil.randomSszDeposits(0))); + + getBlockProcessor(state).verifyOutstandingDepositsAreProcessed(state, body); + } + + @Test + public void processesDepositReceipts() { + final BeaconStateElectra preState = + BeaconStateElectra.required( + createBeaconState() + .updated( + mutableState -> + MutableBeaconStateElectra.required(mutableState) + .setDepositReceiptsStartIndex( + SpecConfigElectra.UNSET_DEPOSIT_RECEIPTS_START_INDEX))); + final int numberOfValidators = preState.getValidators().size(); + + final SszListSchema> depositReceiptsSchema = + SchemaDefinitionsElectra.required(spec.getGenesisSchemaDefinitions()) + .getExecutionPayloadSchema() + .getDepositReceiptsSchemaRequired(); + final int depositReceiptsCount = 3; + final List depositReceipts = + IntStream.range(0, depositReceiptsCount) + .mapToObj( + i -> + depositReceiptsUtil.createDepositReceipt( + preState.getSlot(), UInt64.valueOf(numberOfValidators + i))) + .toList(); + + final BeaconStateElectra state = + BeaconStateElectra.required( + preState.updated( + mutableState -> + getBlockProcessor(preState) + .processDepositReceipts( + MutableBeaconStateElectra.required(mutableState), + depositReceiptsSchema.createFromElements(depositReceipts)))); + + // verify deposit_receipts_start_index has been set + assertThat(state.getDepositReceiptsStartIndex()).isEqualTo(UInt64.valueOf(numberOfValidators)); + // verify validators have been added to the state + assertThat(state.getValidators().size()).isEqualTo(numberOfValidators + depositReceiptsCount); + } + + private BlockProcessorElectra getBlockProcessor(final BeaconState state) { + return (BlockProcessorElectra) spec.getBlockProcessor(state.getSlot()); + } +} From 5e58c86109674808b29b0ebb7ee92f18cee066e3 Mon Sep 17 00:00:00 2001 From: Stefan Bratanov Date: Fri, 22 Mar 2024 11:12:08 +0000 Subject: [PATCH 06/13] fix rebase --- .../versions/electra/block/BlockProcessorElectraTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ethereum/spec/src/test/java/tech/pegasys/teku/spec/logic/versions/electra/block/BlockProcessorElectraTest.java b/ethereum/spec/src/test/java/tech/pegasys/teku/spec/logic/versions/electra/block/BlockProcessorElectraTest.java index a9120eb7320..55353e3dd07 100644 --- a/ethereum/spec/src/test/java/tech/pegasys/teku/spec/logic/versions/electra/block/BlockProcessorElectraTest.java +++ b/ethereum/spec/src/test/java/tech/pegasys/teku/spec/logic/versions/electra/block/BlockProcessorElectraTest.java @@ -63,7 +63,7 @@ public void verifiesOutstandingEth1DepositsAreProcessed() { }); final BeaconBlockBody body = - dataStructureUtil.randomFullBeaconBlockBody( + dataStructureUtil.randomBeaconBlockBody( // 20 - 13 = 7 builder -> builder.deposits(dataStructureUtil.randomSszDeposits(7))); @@ -91,7 +91,7 @@ public void verifiesOutstandingEth1DepositsAreProcessed() { }); final BeaconBlockBody body = - dataStructureUtil.randomFullBeaconBlockBody( + dataStructureUtil.randomBeaconBlockBody( // 20 - 20 = 0 modifier -> modifier.deposits(dataStructureUtil.randomSszDeposits(0))); From b55201ef8f0ad9b51a663533e6b89ac4f6123a00 Mon Sep 17 00:00:00 2001 From: Stefan Bratanov Date: Fri, 22 Mar 2024 15:24:40 +0000 Subject: [PATCH 07/13] small changelog fixing --- CHANGELOG.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 17bb7a1045a..6cfc17e9e95 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,11 +15,11 @@ the [releases page](https://github.com/Consensys/teku/releases). ### Additions and Improvements - Introduced [Validator Slashing Prevention feature](https://docs.teku.consensys.io/how-to/prevent-slashing/detect-slashing). - If the EL supports the `engine_getClientVersionV1` Engine API method, the default graffiti (when no graffiti has been configured by the validator) will include EL as well as CL version information. For more details, please see https://github.com/ethereum/execution-apis/pull/517. -- `—-p2p-private-key-file` command line option supports reading a binary private key file. +- `--p2p-private-key-file` command line option supports reading a binary private key file. - Updated libp2p seen cache configuration to reflect EIP-7045 spec changes. This reduces CPU and network bandwidth consumption. - Increased the attestation cache capacity to allow Teku a bigger pool of attestations when block building. -- Default `--builder-bid-compare-factor` to 90. This makes it necessary for external block builders to give at least 10% additional profit compared to a local build before being taken into consideration. If you would like to go back to the previous default, set `--builder-bid-compare-factor` to 100 -- Added `--p2p-direct-peers` command line option to configure explicit peers as per [Explicit Peering Agreements](https://github.com/libp2p/specs/blob/master/pubsub/gossipsub/gossipsub-v1.1.md#explicit-peering-agreements) libp2p spec +- Defaulted `--builder-bid-compare-factor` to 90. This makes it necessary for external block builders to give at least 10% additional profit compared to a local build before being taken into consideration. If you would like to go back to the previous default, set `--builder-bid-compare-factor` to 100. +- Added `--p2p-direct-peers` command line option to configure explicit peers as per [Explicit Peering Agreements](https://github.com/libp2p/specs/blob/master/pubsub/gossipsub/gossipsub-v1.1.md#explicit-peering-agreements) libp2p spec. ### Bug Fixes - Fix incompatibility between Teku validator client and Lighthouse beacon nodes [#8117](https://github.com/Consensys/teku/pull/8117) From bc5c5d9abc029b0b995d4b4c26341515f481800f Mon Sep 17 00:00:00 2001 From: Stefan Bratanov Date: Mon, 25 Mar 2024 09:28:15 +0000 Subject: [PATCH 08/13] as per feedback --- .../validator/coordinator/DepositProviderTest.java | 2 ++ .../spec/logic/common/helpers/MiscHelpersTest.java | 6 ++++++ .../electra/block/BlockProcessorElectraTest.java | 10 ++++++---- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/beacon/validator/src/test/java/tech/pegasys/teku/validator/coordinator/DepositProviderTest.java b/beacon/validator/src/test/java/tech/pegasys/teku/validator/coordinator/DepositProviderTest.java index cc4e5ce97bd..c595a4cb0f5 100644 --- a/beacon/validator/src/test/java/tech/pegasys/teku/validator/coordinator/DepositProviderTest.java +++ b/beacon/validator/src/test/java/tech/pegasys/teku/validator/coordinator/DepositProviderTest.java @@ -199,6 +199,8 @@ void getsRemainingEth1PendingDepositsIfElectraIsEnabled() { final SszList deposits = depositProvider.getDeposits(state, randomEth1Data); // the pending Eth1 deposits (deposit_receipt_start_index - eth1_deposit_index) + // we need to process eth1_deposit_index deposit (5) up to 16 (exclusive) so 11 is the + // expected size assertThat(deposits).hasSize(11); checkThatDepositProofIsValid(deposits); } diff --git a/ethereum/spec/src/test/java/tech/pegasys/teku/spec/logic/common/helpers/MiscHelpersTest.java b/ethereum/spec/src/test/java/tech/pegasys/teku/spec/logic/common/helpers/MiscHelpersTest.java index 65ac51aa561..3b1932d8b7e 100644 --- a/ethereum/spec/src/test/java/tech/pegasys/teku/spec/logic/common/helpers/MiscHelpersTest.java +++ b/ethereum/spec/src/test/java/tech/pegasys/teku/spec/logic/common/helpers/MiscHelpersTest.java @@ -231,6 +231,12 @@ public void committeeComputationShouldNotOverflow(int activeValidatorsCount, int }); } + @Test + public void isFormerDepositReceiptMechanismDisabled_returnsFalse() { + assertThat(miscHelpers.isFormerDepositMechanismDisabled(dataStructureUtil.randomBeaconState())) + .isFalse(); + } + public static Stream getComputesSlotAtTimeArguments() { // 6 seconds per slot return Stream.of( diff --git a/ethereum/spec/src/test/java/tech/pegasys/teku/spec/logic/versions/electra/block/BlockProcessorElectraTest.java b/ethereum/spec/src/test/java/tech/pegasys/teku/spec/logic/versions/electra/block/BlockProcessorElectraTest.java index 55353e3dd07..833651e3760 100644 --- a/ethereum/spec/src/test/java/tech/pegasys/teku/spec/logic/versions/electra/block/BlockProcessorElectraTest.java +++ b/ethereum/spec/src/test/java/tech/pegasys/teku/spec/logic/versions/electra/block/BlockProcessorElectraTest.java @@ -108,7 +108,7 @@ public void processesDepositReceipts() { MutableBeaconStateElectra.required(mutableState) .setDepositReceiptsStartIndex( SpecConfigElectra.UNSET_DEPOSIT_RECEIPTS_START_INDEX))); - final int numberOfValidators = preState.getValidators().size(); + final int firstElectraDepositReceiptIndex = preState.getValidators().size(); final SszListSchema> depositReceiptsSchema = SchemaDefinitionsElectra.required(spec.getGenesisSchemaDefinitions()) @@ -120,7 +120,7 @@ public void processesDepositReceipts() { .mapToObj( i -> depositReceiptsUtil.createDepositReceipt( - preState.getSlot(), UInt64.valueOf(numberOfValidators + i))) + preState.getSlot(), UInt64.valueOf(firstElectraDepositReceiptIndex + i))) .toList(); final BeaconStateElectra state = @@ -133,9 +133,11 @@ public void processesDepositReceipts() { depositReceiptsSchema.createFromElements(depositReceipts)))); // verify deposit_receipts_start_index has been set - assertThat(state.getDepositReceiptsStartIndex()).isEqualTo(UInt64.valueOf(numberOfValidators)); + assertThat(state.getDepositReceiptsStartIndex()) + .isEqualTo(UInt64.valueOf(firstElectraDepositReceiptIndex)); // verify validators have been added to the state - assertThat(state.getValidators().size()).isEqualTo(numberOfValidators + depositReceiptsCount); + assertThat(state.getValidators().size()) + .isEqualTo(firstElectraDepositReceiptIndex + depositReceiptsCount); } private BlockProcessorElectra getBlockProcessor(final BeaconState state) { From 0586a459c73cc342c72be9a6476d4db22bcb3795 Mon Sep 17 00:00:00 2001 From: Stefan Bratanov Date: Mon, 25 Mar 2024 09:46:56 +0000 Subject: [PATCH 09/13] move deposit receipts test to DataStructureUtil --- .../util/DepositReceiptsUtil.java | 4 +- .../block/BlockProcessorElectraTest.java | 7 +--- .../teku/spec/util/DataStructureUtil.java | 38 ++++++++++++++----- 3 files changed, 32 insertions(+), 17 deletions(-) diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/util/DepositReceiptsUtil.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/util/DepositReceiptsUtil.java index 0d8c50bc3fc..b25accc0315 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/util/DepositReceiptsUtil.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/util/DepositReceiptsUtil.java @@ -36,8 +36,8 @@ public class DepositReceiptsUtil { public DepositReceiptsUtil(final Spec spec) { this.spec = spec; } - - public DepositReceipt createDepositReceipt(final UInt64 slot, final UInt64 index) { + + private DepositReceipt createDepositReceipt(final UInt64 slot, final UInt64 index) { final BLSKeyPair validatorKeyPair = BLSKeyPair.random(random); final BLSPublicKey publicKey = validatorKeyPair.getPublicKey(); final UInt64 depositAmount = UInt64.THIRTY_TWO_ETH; diff --git a/ethereum/spec/src/test/java/tech/pegasys/teku/spec/logic/versions/electra/block/BlockProcessorElectraTest.java b/ethereum/spec/src/test/java/tech/pegasys/teku/spec/logic/versions/electra/block/BlockProcessorElectraTest.java index 833651e3760..2336ef6c09c 100644 --- a/ethereum/spec/src/test/java/tech/pegasys/teku/spec/logic/versions/electra/block/BlockProcessorElectraTest.java +++ b/ethereum/spec/src/test/java/tech/pegasys/teku/spec/logic/versions/electra/block/BlockProcessorElectraTest.java @@ -30,14 +30,11 @@ import tech.pegasys.teku.spec.datastructures.state.beaconstate.BeaconState; import tech.pegasys.teku.spec.datastructures.state.beaconstate.versions.electra.BeaconStateElectra; import tech.pegasys.teku.spec.datastructures.state.beaconstate.versions.electra.MutableBeaconStateElectra; -import tech.pegasys.teku.spec.datastructures.util.DepositReceiptsUtil; import tech.pegasys.teku.spec.logic.versions.deneb.block.BlockProcessorDenebTest; import tech.pegasys.teku.spec.schemas.SchemaDefinitionsElectra; class BlockProcessorElectraTest extends BlockProcessorDenebTest { - protected DepositReceiptsUtil depositReceiptsUtil = new DepositReceiptsUtil(spec); - @Override protected Spec createSpec() { return TestSpecFactory.createMainnetElectra(); @@ -119,8 +116,8 @@ public void processesDepositReceipts() { IntStream.range(0, depositReceiptsCount) .mapToObj( i -> - depositReceiptsUtil.createDepositReceipt( - preState.getSlot(), UInt64.valueOf(firstElectraDepositReceiptIndex + i))) + dataStructureUtil.randomDepositReceiptWithValidSignature( + UInt64.valueOf(firstElectraDepositReceiptIndex + i))) .toList(); final BeaconStateElectra state = 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 5c6607e14f3..ae99ff2768d 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 @@ -52,6 +52,7 @@ import tech.pegasys.teku.infrastructure.bytes.Bytes20; import tech.pegasys.teku.infrastructure.bytes.Bytes4; import tech.pegasys.teku.infrastructure.bytes.Bytes8; +import tech.pegasys.teku.infrastructure.ssz.Merkleizable; import tech.pegasys.teku.infrastructure.ssz.SszData; import tech.pegasys.teku.infrastructure.ssz.SszList; import tech.pegasys.teku.infrastructure.ssz.SszPrimitive; @@ -1520,20 +1521,20 @@ public DepositMessage randomDepositMessage(final BLSKeyPair keyPair) { } public DepositMessage randomDepositMessage() { - final BLSKeyPair keyPair = BLSTestUtil.randomKeyPair(nextSeed()); + final BLSKeyPair keyPair = randomKeyPair(); return randomDepositMessage(keyPair); } public DepositData randomDepositData() { - final BLSKeyPair keyPair = BLSTestUtil.randomKeyPair(nextSeed()); - final DepositMessage proofOfPossessionData = randomDepositMessage(keyPair); + final BLSKeyPair keyPair = randomKeyPair(); + final DepositMessage depositMessage = randomDepositMessage(keyPair); - final Bytes32 domain = computeDomain(); - final Bytes signingRoot = getSigningRoot(proofOfPossessionData, domain); + final Bytes32 domain = computeDepositDomain(); + final Bytes signingRoot = getSigningRoot(depositMessage, domain); - final BLSSignature proofOfPossession = BLS.sign(keyPair.getSecretKey(), signingRoot); + final BLSSignature signature = BLS.sign(keyPair.getSecretKey(), signingRoot); - return new DepositData(proofOfPossessionData, proofOfPossession); + return new DepositData(depositMessage, signature); } public DepositWithIndex randomDepositWithIndex() { @@ -2052,6 +2053,23 @@ public Withdrawal randomWithdrawal() { .create(randomUInt64(), randomValidatorIndex(), randomBytes20(), randomUInt64()); } + public DepositReceipt randomDepositReceiptWithValidSignature(final UInt64 index) { + final BLSKeyPair validatorKeyPair = randomKeyPair(); + final DepositMessage depositMessage = + new DepositMessage(validatorKeyPair.getPublicKey(), randomBytes32(), randomUInt64()); + final Bytes32 domain = computeDepositDomain(); + final Bytes signingRoot = getSigningRoot(depositMessage, domain); + final BLSSignature signature = BLS.sign(validatorKeyPair.getSecretKey(), signingRoot); + return getElectraSchemaDefinitions(randomSlot()) + .getDepositReceiptSchema() + .create( + depositMessage.getPubkey(), + depositMessage.getWithdrawalCredentials(), + depositMessage.getAmount(), + signature, + index); + } + public DepositReceipt randomDepositReceipt() { return getElectraSchemaDefinitions(randomSlot()) .getDepositReceiptSchema() @@ -2497,14 +2515,14 @@ private UInt64 getMaxEffectiveBalance() { return getConstant(SpecConfig::getMaxEffectiveBalance); } - private Bytes32 computeDomain() { + private Bytes32 computeDepositDomain() { final SpecVersion genesisSpec = spec.getGenesisSpec(); final Bytes4 domain = Domain.DEPOSIT; return genesisSpec.miscHelpers().computeDomain(domain); } - private Bytes getSigningRoot(final DepositMessage proofOfPossessionData, final Bytes32 domain) { - return spec.getGenesisSpec().miscHelpers().computeSigningRoot(proofOfPossessionData, domain); + private Bytes getSigningRoot(final Merkleizable object, final Bytes32 domain) { + return spec.getGenesisSpec().miscHelpers().computeSigningRoot(object, domain); } UInt64 computeStartSlotAtEpoch(final UInt64 epoch) { From cb7c6d9189242945ce8645bc79a859edd9c89465 Mon Sep 17 00:00:00 2001 From: Stefan Bratanov Date: Mon, 25 Mar 2024 09:49:38 +0000 Subject: [PATCH 10/13] remove DepositReceiptsUtil for now --- .../util/DepositReceiptsUtil.java | 55 ------------------- 1 file changed, 55 deletions(-) delete mode 100644 ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/util/DepositReceiptsUtil.java diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/util/DepositReceiptsUtil.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/util/DepositReceiptsUtil.java deleted file mode 100644 index b25accc0315..00000000000 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/util/DepositReceiptsUtil.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright Consensys Software Inc., 2024 - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ - -package tech.pegasys.teku.spec.datastructures.util; - -import java.security.SecureRandom; -import org.apache.tuweni.bytes.Bytes32; -import tech.pegasys.teku.bls.BLS; -import tech.pegasys.teku.bls.BLSKeyPair; -import tech.pegasys.teku.bls.BLSPublicKey; -import tech.pegasys.teku.bls.BLSSignature; -import tech.pegasys.teku.infrastructure.unsigned.UInt64; -import tech.pegasys.teku.spec.Spec; -import tech.pegasys.teku.spec.constants.Domain; -import tech.pegasys.teku.spec.datastructures.execution.versions.electra.DepositReceipt; -import tech.pegasys.teku.spec.datastructures.operations.DepositMessage; -import tech.pegasys.teku.spec.logic.common.helpers.MiscHelpers; - -public class DepositReceiptsUtil { - - @SuppressWarnings("DoNotCreateSecureRandomDirectly") - private final SecureRandom random = new SecureRandom(); - - private final Spec spec; - - public DepositReceiptsUtil(final Spec spec) { - this.spec = spec; - } - - private DepositReceipt createDepositReceipt(final UInt64 slot, final UInt64 index) { - final BLSKeyPair validatorKeyPair = BLSKeyPair.random(random); - final BLSPublicKey publicKey = validatorKeyPair.getPublicKey(); - final UInt64 depositAmount = UInt64.THIRTY_TWO_ETH; - final DepositMessage depositMessage = - new DepositMessage(publicKey, Bytes32.ZERO, depositAmount); - final MiscHelpers miscHelpers = spec.atSlot(slot).miscHelpers(); - final Bytes32 depositDomain = miscHelpers.computeDomain(Domain.DEPOSIT); - final BLSSignature signature = - BLS.sign( - validatorKeyPair.getSecretKey(), - miscHelpers.computeSigningRoot(depositMessage, depositDomain)); - return DepositReceipt.SSZ_SCHEMA.create( - publicKey, Bytes32.ZERO, depositAmount, signature, index); - } -} From d1fc8f311a72e74b6059b8b38dfe9dd9ca0b4e42 Mon Sep 17 00:00:00 2001 From: Stefan Bratanov Date: Mon, 25 Mar 2024 09:51:46 +0000 Subject: [PATCH 11/13] nit --- .../java/tech/pegasys/teku/spec/util/DataStructureUtil.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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 ae99ff2768d..987a973f774 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 @@ -2054,12 +2054,12 @@ public Withdrawal randomWithdrawal() { } public DepositReceipt randomDepositReceiptWithValidSignature(final UInt64 index) { - final BLSKeyPair validatorKeyPair = randomKeyPair(); + final BLSKeyPair keyPair = randomKeyPair(); final DepositMessage depositMessage = - new DepositMessage(validatorKeyPair.getPublicKey(), randomBytes32(), randomUInt64()); + new DepositMessage(keyPair.getPublicKey(), randomBytes32(), randomUInt64()); final Bytes32 domain = computeDepositDomain(); final Bytes signingRoot = getSigningRoot(depositMessage, domain); - final BLSSignature signature = BLS.sign(validatorKeyPair.getSecretKey(), signingRoot); + final BLSSignature signature = BLS.sign(keyPair.getSecretKey(), signingRoot); return getElectraSchemaDefinitions(randomSlot()) .getDepositReceiptSchema() .create( From 3d35e74536955eb8284cf405fdde37f909a0310e Mon Sep 17 00:00:00 2001 From: Stefan Bratanov Date: Mon, 25 Mar 2024 10:39:05 +0000 Subject: [PATCH 12/13] simplification --- .../pegasys/teku/validator/coordinator/DepositProvider.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/beacon/validator/src/main/java/tech/pegasys/teku/validator/coordinator/DepositProvider.java b/beacon/validator/src/main/java/tech/pegasys/teku/validator/coordinator/DepositProvider.java index 502324f5756..dac6bd34e0d 100644 --- a/beacon/validator/src/main/java/tech/pegasys/teku/validator/coordinator/DepositProvider.java +++ b/beacon/validator/src/main/java/tech/pegasys/teku/validator/coordinator/DepositProvider.java @@ -229,11 +229,7 @@ public synchronized SszList getDeposits( // EIP-6110 final UInt64 eth1DepositIndexLimit = eth1DepositCount.min(stateElectra.getDepositReceiptsStartIndex()); - if (eth1DepositIndex.isLessThan(eth1DepositIndexLimit)) { - return eth1DepositIndexLimit.minus(eth1DepositIndex).min(maxDeposits); - } else { - return UInt64.ZERO; - } + return eth1DepositIndexLimit.minusMinZero(eth1DepositIndex).min(maxDeposits); }) .orElseGet( () -> { From 6e397adc2866f8f9f5e0c7fb5713fdc1f503f054 Mon Sep 17 00:00:00 2001 From: Stefan Bratanov Date: Mon, 25 Mar 2024 14:59:46 +0000 Subject: [PATCH 13/13] improve test --- .../logic/common/helpers/MiscHelpersTest.java | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/ethereum/spec/src/test/java/tech/pegasys/teku/spec/logic/common/helpers/MiscHelpersTest.java b/ethereum/spec/src/test/java/tech/pegasys/teku/spec/logic/common/helpers/MiscHelpersTest.java index 3b1932d8b7e..66bce5ee02a 100644 --- a/ethereum/spec/src/test/java/tech/pegasys/teku/spec/logic/common/helpers/MiscHelpersTest.java +++ b/ethereum/spec/src/test/java/tech/pegasys/teku/spec/logic/common/helpers/MiscHelpersTest.java @@ -34,8 +34,10 @@ import org.junit.jupiter.params.provider.MethodSource; import tech.pegasys.teku.infrastructure.unsigned.UInt64; import tech.pegasys.teku.spec.Spec; +import tech.pegasys.teku.spec.SpecMilestone; import tech.pegasys.teku.spec.TestSpecFactory; import tech.pegasys.teku.spec.config.SpecConfig; +import tech.pegasys.teku.spec.networks.Eth2Network; import tech.pegasys.teku.spec.util.DataStructureUtil; class MiscHelpersTest { @@ -232,9 +234,17 @@ public void committeeComputationShouldNotOverflow(int activeValidatorsCount, int } @Test - public void isFormerDepositReceiptMechanismDisabled_returnsFalse() { - assertThat(miscHelpers.isFormerDepositMechanismDisabled(dataStructureUtil.randomBeaconState())) - .isFalse(); + public void isFormerDepositReceiptMechanismDisabled_returnsFalseForAllForksPriorToElectra() { + SpecMilestone.getAllPriorMilestones(SpecMilestone.ELECTRA) + .forEach( + milestone -> { + final Spec spec = TestSpecFactory.create(milestone, Eth2Network.MINIMAL); + final MiscHelpers miscHelpers = spec.atSlot(UInt64.ZERO).miscHelpers(); + assertThat( + miscHelpers.isFormerDepositMechanismDisabled( + dataStructureUtil.randomBeaconState())) + .isFalse(); + }); } public static Stream getComputesSlotAtTimeArguments() {