From db79256d8c41bb25660f1be6db85201f541a4b43 Mon Sep 17 00:00:00 2001 From: Paul Harris Date: Fri, 12 Apr 2024 10:49:53 +1000 Subject: [PATCH 1/2] EIP-7251 - Added minActivationBalance minActivationBalance impacts how validators are deemed to become active, rather than using MAX_EFFECTIVE_BALANCE A flow on of this is that the max_effective_balance can be changed to the electra max_effective_balance Also it updates epoch processing, and we start seeing electra specific beaconStateAccessors and Predicates. Signed-off-by: Paul Harris --- .../spec/constants/WithdrawalPrefixes.java | 2 + .../epoch/AbstractEpochProcessor.java | 21 ++++--- .../versions/electra/SpecLogicElectra.java | 20 +++--- .../helpers/BeaconStateAccessorsElectra.java | 50 +++++++++++++++ .../electra/helpers/PredicatesElectra.java | 62 +++++++++++++++++++ .../epoch/EpochProcessorElectra.java | 59 ++++++++++++++++++ 6 files changed, 197 insertions(+), 17 deletions(-) create mode 100644 ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/helpers/BeaconStateAccessorsElectra.java create mode 100644 ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/helpers/PredicatesElectra.java create mode 100644 ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/statetransition/epoch/EpochProcessorElectra.java diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/constants/WithdrawalPrefixes.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/constants/WithdrawalPrefixes.java index c4d385d5820..d2bd4b0cedd 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/constants/WithdrawalPrefixes.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/constants/WithdrawalPrefixes.java @@ -18,5 +18,7 @@ public class WithdrawalPrefixes { public static final Bytes BLS_WITHDRAWAL_PREFIX = Bytes.fromHexString("0x00"); public static final byte ETH1_ADDRESS_WITHDRAWAL_BYTE = 0x01; + public static final byte COMPOUNDING_WITHDRAWAL_BYTE = 0x02; public static final Bytes ETH1_ADDRESS_WITHDRAWAL_PREFIX = Bytes.of(ETH1_ADDRESS_WITHDRAWAL_BYTE); + public static final Bytes COMPOUNDING_WITHDRAWAL_PREFIX = Bytes.of(COMPOUNDING_WITHDRAWAL_BYTE); } diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/common/statetransition/epoch/AbstractEpochProcessor.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/common/statetransition/epoch/AbstractEpochProcessor.java index 962f366f043..7b39790eca5 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/common/statetransition/epoch/AbstractEpochProcessor.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/common/statetransition/epoch/AbstractEpochProcessor.java @@ -63,6 +63,7 @@ public abstract class AbstractEpochProcessor implements EpochProcessor { protected final BeaconStateMutators beaconStateMutators; private static final Logger LOG = LogManager.getLogger(); + protected final UInt64 maxEffectiveBalance; // Used to log once per epoch (throttlingPeriod = 1) private final Throttler loggerThrottler = new Throttler<>(LOG, UInt64.ONE); @@ -83,6 +84,7 @@ protected AbstractEpochProcessor( this.beaconStateUtil = beaconStateUtil; this.validatorStatusFactory = validatorStatusFactory; this.schemaDefinitions = schemaDefinitions; + this.maxEffectiveBalance = specConfig.getMaxEffectiveBalance(); } /** @@ -310,7 +312,6 @@ public void processRegistryUpdates( SszMutableList validators = state.getValidators(); final UInt64 currentEpoch = beaconStateAccessors.getCurrentEpoch(state); final UInt64 finalizedEpoch = state.getFinalizedCheckpoint().getEpoch(); - final UInt64 maxEffectiveBalance = specConfig.getMaxEffectiveBalance(); final UInt64 ejectionBalance = specConfig.getEjectionBalance(); final Supplier validatorExitContextSupplier = beaconStateMutators.createValidatorExitContextSupplier(state); @@ -318,12 +319,7 @@ public void processRegistryUpdates( for (int index = 0; index < validators.size(); index++) { final ValidatorStatus status = statuses.get(index); - // Slightly optimised form of isEligibleForActivationQueue to avoid accessing the - // state for the majority of validators. Can't be eligible for activation if already active - // or if effective balance is too low. Only get the validator if both those checks pass to - // confirm it isn't already in the queue. - if (!status.isActiveInCurrentEpoch() - && status.getCurrentEpochEffectiveBalance().equals(maxEffectiveBalance)) { + if (isEligibleForActivationQueue(status)) { final Validator validator = validators.get(index); if (validator.getActivationEligibilityEpoch().equals(SpecConfig.FAR_FUTURE_EPOCH)) { validators.set( @@ -381,6 +377,17 @@ public void processRegistryUpdates( } } + /** + * Can't be eligible for activation if already active or if effective balance is too low. + * + * @param status - Validator status + * @return true if validator is eligible to be added to the activation queue + */ + protected boolean isEligibleForActivationQueue(final ValidatorStatus status) { + return !status.isActiveInCurrentEpoch() + && status.getCurrentEpochEffectiveBalance().equals(maxEffectiveBalance); + } + /** Processes slashings */ @Override public void processSlashings( 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 bd8f8ee8e39..aa13b8cc856 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 @@ -28,22 +28,22 @@ import tech.pegasys.teku.spec.logic.common.util.LightClientUtil; 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.altair.statetransition.epoch.ValidatorStatusFactoryAltair; import tech.pegasys.teku.spec.logic.versions.bellatrix.helpers.BeaconStateMutatorsBellatrix; import tech.pegasys.teku.spec.logic.versions.bellatrix.helpers.BellatrixTransitionHelpers; import tech.pegasys.teku.spec.logic.versions.bellatrix.util.BlindBlockUtilBellatrix; 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.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.logic.versions.electra.helpers.BeaconStateAccessorsElectra; import tech.pegasys.teku.spec.logic.versions.electra.helpers.MiscHelpersElectra; +import tech.pegasys.teku.spec.logic.versions.electra.helpers.PredicatesElectra; +import tech.pegasys.teku.spec.logic.versions.electra.statetransition.epoch.EpochProcessorElectra; import tech.pegasys.teku.spec.schemas.SchemaDefinitionsElectra; public class SpecLogicElectra extends AbstractSpecLogic { @@ -53,7 +53,7 @@ public class SpecLogicElectra extends AbstractSpecLogic { private SpecLogicElectra( final Predicates predicates, final MiscHelpersDeneb miscHelpers, - final BeaconStateAccessorsAltair beaconStateAccessors, + final BeaconStateAccessorsElectra beaconStateAccessors, final BeaconStateMutatorsBellatrix beaconStateMutators, final OperationSignatureVerifier operationSignatureVerifier, final ValidatorsUtil validatorsUtil, @@ -61,7 +61,7 @@ private SpecLogicElectra( final AttestationUtil attestationUtil, final OperationValidator operationValidator, final ValidatorStatusFactoryAltair validatorStatusFactory, - final EpochProcessorCapella epochProcessor, + final EpochProcessorElectra epochProcessor, final BlockProcessorCapella blockProcessor, final ForkChoiceUtil forkChoiceUtil, final BlockProposalUtil blockProposalUtil, @@ -93,11 +93,11 @@ private SpecLogicElectra( public static SpecLogicElectra create( final SpecConfigElectra config, final SchemaDefinitionsElectra schemaDefinitions) { // Helpers - final Predicates predicates = new Predicates(config); + final PredicatesElectra predicates = new PredicatesElectra(config); final MiscHelpersElectra miscHelpers = new MiscHelpersElectra(config, predicates, schemaDefinitions); - final BeaconStateAccessorsDeneb beaconStateAccessors = - new BeaconStateAccessorsDeneb(config, predicates, miscHelpers); + final BeaconStateAccessorsElectra beaconStateAccessors = + new BeaconStateAccessorsElectra(config, predicates, miscHelpers); final BeaconStateMutatorsBellatrix beaconStateMutators = new BeaconStateMutatorsBellatrix(config, miscHelpers, beaconStateAccessors); @@ -126,8 +126,8 @@ public static SpecLogicElectra create( predicates, miscHelpers, beaconStateAccessors); - final EpochProcessorCapella epochProcessor = - new EpochProcessorCapella( + final EpochProcessorElectra epochProcessor = + new EpochProcessorElectra( config, miscHelpers, beaconStateAccessors, diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/helpers/BeaconStateAccessorsElectra.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/helpers/BeaconStateAccessorsElectra.java new file mode 100644 index 00000000000..6ffe18810f1 --- /dev/null +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/helpers/BeaconStateAccessorsElectra.java @@ -0,0 +1,50 @@ +/* + * 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.infrastructure.unsigned.UInt64; +import tech.pegasys.teku.spec.config.SpecConfigDeneb; +import tech.pegasys.teku.spec.datastructures.state.Validator; +import tech.pegasys.teku.spec.logic.versions.deneb.helpers.BeaconStateAccessorsDeneb; +import tech.pegasys.teku.spec.logic.versions.deneb.helpers.MiscHelpersDeneb; + +public class BeaconStateAccessorsElectra extends BeaconStateAccessorsDeneb { + + private final UInt64 maxEffectiveBalanceElectra; + private final UInt64 minActivationBalance; + + protected PredicatesElectra predicatesElectra; + + public BeaconStateAccessorsElectra( + SpecConfigDeneb config, PredicatesElectra predicatesElectra, MiscHelpersDeneb miscHelpers) { + super(config, predicatesElectra, miscHelpers); + this.maxEffectiveBalanceElectra = + config.toVersionElectra().orElseThrow().getMaxEffectiveBalanceElectra(); + this.minActivationBalance = config.toVersionElectra().orElseThrow().getMinActivationBalance(); + this.predicatesElectra = predicatesElectra; + } + + /** + * implements get_validator_max_effective_balance state accessor + * + * @param validator - a validator from a state. + * @return the max effective balance for the specified validator based on its withdrawal + * credentials. + */ + public UInt64 getValidatorMaxEffectiveBalance(final Validator validator) { + return predicatesElectra.hasCompoundingWithdrawalCredential(validator) + ? maxEffectiveBalanceElectra + : minActivationBalance; + } +} diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/helpers/PredicatesElectra.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/helpers/PredicatesElectra.java new file mode 100644 index 00000000000..aed7637251c --- /dev/null +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/helpers/PredicatesElectra.java @@ -0,0 +1,62 @@ +/* + * 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 tech.pegasys.teku.spec.constants.WithdrawalPrefixes.COMPOUNDING_WITHDRAWAL_BYTE; + +import org.apache.tuweni.bytes.Bytes32; +import tech.pegasys.teku.infrastructure.unsigned.UInt64; +import tech.pegasys.teku.spec.config.SpecConfig; +import tech.pegasys.teku.spec.config.SpecConfigElectra; +import tech.pegasys.teku.spec.datastructures.state.Validator; +import tech.pegasys.teku.spec.logic.common.helpers.Predicates; + +public class PredicatesElectra extends Predicates { + private final SpecConfigElectra specConfigElectra; + + public PredicatesElectra(SpecConfig specConfig) { + super(specConfig); + this.specConfigElectra = SpecConfigElectra.required(specConfig); + } + + @Override + public boolean isPartiallyWithdrawableValidator(final Validator validator, final UInt64 balance) { + if (hasEth1WithdrawalCredential(validator)) { + return isPartiallyWithdrawableValidatorEth1CredentialsChecked(validator, balance); + } + if (hasCompoundingWithdrawalCredential(validator)) { + return isPartiallyWithdrawableValidatorCompoundingCredentialChecked(validator, balance); + } + + return false; + } + + private boolean isPartiallyWithdrawableValidatorCompoundingCredentialChecked( + final Validator validator, final UInt64 balance) { + final UInt64 maxEffectiveBalance = specConfigElectra.getMaxEffectiveBalanceElectra(); + final boolean hasMaxEffectiveBalance = + validator.getEffectiveBalance().equals(maxEffectiveBalance); + final boolean hasExcessBalance = balance.isGreaterThan(maxEffectiveBalance); + + return hasMaxEffectiveBalance && hasExcessBalance; + } + + protected boolean hasCompoundingWithdrawalCredential(Validator validator) { + return isCompoundingWithdrawalCredential(validator.getWithdrawalCredentials()); + } + + protected boolean isCompoundingWithdrawalCredential(Bytes32 withdrawalCredentials) { + return withdrawalCredentials.get(0) == COMPOUNDING_WITHDRAWAL_BYTE; + } +} diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/statetransition/epoch/EpochProcessorElectra.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/statetransition/epoch/EpochProcessorElectra.java new file mode 100644 index 00000000000..69547810fde --- /dev/null +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/statetransition/epoch/EpochProcessorElectra.java @@ -0,0 +1,59 @@ +/* + * 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.statetransition.epoch; + +import tech.pegasys.teku.infrastructure.unsigned.UInt64; +import tech.pegasys.teku.spec.config.SpecConfigBellatrix; +import tech.pegasys.teku.spec.logic.common.helpers.BeaconStateMutators; +import tech.pegasys.teku.spec.logic.common.statetransition.epoch.status.ValidatorStatus; +import tech.pegasys.teku.spec.logic.common.statetransition.epoch.status.ValidatorStatusFactory; +import tech.pegasys.teku.spec.logic.common.util.BeaconStateUtil; +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.altair.helpers.MiscHelpersAltair; +import tech.pegasys.teku.spec.logic.versions.bellatrix.statetransition.epoch.EpochProcessorBellatrix; +import tech.pegasys.teku.spec.schemas.SchemaDefinitions; + +public class EpochProcessorElectra extends EpochProcessorBellatrix { + + private final UInt64 minActivationBalance; + + public EpochProcessorElectra( + SpecConfigBellatrix specConfig, + MiscHelpersAltair miscHelpers, + BeaconStateAccessorsAltair beaconStateAccessors, + BeaconStateMutators beaconStateMutators, + ValidatorsUtil validatorsUtil, + BeaconStateUtil beaconStateUtil, + ValidatorStatusFactory validatorStatusFactory, + SchemaDefinitions schemaDefinitions) { + super( + specConfig, + miscHelpers, + beaconStateAccessors, + beaconStateMutators, + validatorsUtil, + beaconStateUtil, + validatorStatusFactory, + schemaDefinitions); + this.minActivationBalance = + specConfig.toVersionElectra().orElseThrow().getMinActivationBalance(); + } + + @Override + protected boolean isEligibleForActivationQueue(final ValidatorStatus status) { + return !status.isActiveInCurrentEpoch() + && status.getCurrentEpochEffectiveBalance().isGreaterThanOrEqualTo(minActivationBalance); + } +} From e2d55a917322dedade2af0128405a3ffe993037f Mon Sep 17 00:00:00 2001 From: Paul Harris Date: Sat, 13 Apr 2024 07:56:38 +1000 Subject: [PATCH 2/2] added some basic predicates tests. fixed missed finals Signed-off-by: Paul Harris --- .../helpers/BeaconStateAccessorsElectra.java | 4 +- .../electra/helpers/PredicatesElectra.java | 4 +- .../epoch/EpochProcessorElectra.java | 16 ++-- .../helpers/PredicatesElectraTest.java | 85 +++++++++++++++++++ .../teku/spec/util/DataStructureUtil.java | 7 ++ 5 files changed, 105 insertions(+), 11 deletions(-) create mode 100644 ethereum/spec/src/test/java/tech/pegasys/teku/spec/logic/versions/electra/helpers/PredicatesElectraTest.java diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/helpers/BeaconStateAccessorsElectra.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/helpers/BeaconStateAccessorsElectra.java index 6ffe18810f1..39ca126d53a 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/helpers/BeaconStateAccessorsElectra.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/helpers/BeaconStateAccessorsElectra.java @@ -27,7 +27,9 @@ public class BeaconStateAccessorsElectra extends BeaconStateAccessorsDeneb { protected PredicatesElectra predicatesElectra; public BeaconStateAccessorsElectra( - SpecConfigDeneb config, PredicatesElectra predicatesElectra, MiscHelpersDeneb miscHelpers) { + final SpecConfigDeneb config, + final PredicatesElectra predicatesElectra, + final MiscHelpersDeneb miscHelpers) { super(config, predicatesElectra, miscHelpers); this.maxEffectiveBalanceElectra = config.toVersionElectra().orElseThrow().getMaxEffectiveBalanceElectra(); diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/helpers/PredicatesElectra.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/helpers/PredicatesElectra.java index aed7637251c..404faa9551b 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/helpers/PredicatesElectra.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/helpers/PredicatesElectra.java @@ -52,11 +52,11 @@ private boolean isPartiallyWithdrawableValidatorCompoundingCredentialChecked( return hasMaxEffectiveBalance && hasExcessBalance; } - protected boolean hasCompoundingWithdrawalCredential(Validator validator) { + protected boolean hasCompoundingWithdrawalCredential(final Validator validator) { return isCompoundingWithdrawalCredential(validator.getWithdrawalCredentials()); } - protected boolean isCompoundingWithdrawalCredential(Bytes32 withdrawalCredentials) { + protected boolean isCompoundingWithdrawalCredential(final Bytes32 withdrawalCredentials) { return withdrawalCredentials.get(0) == COMPOUNDING_WITHDRAWAL_BYTE; } } diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/statetransition/epoch/EpochProcessorElectra.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/statetransition/epoch/EpochProcessorElectra.java index 69547810fde..12d70136818 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/statetransition/epoch/EpochProcessorElectra.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/statetransition/epoch/EpochProcessorElectra.java @@ -30,14 +30,14 @@ public class EpochProcessorElectra extends EpochProcessorBellatrix { private final UInt64 minActivationBalance; public EpochProcessorElectra( - SpecConfigBellatrix specConfig, - MiscHelpersAltair miscHelpers, - BeaconStateAccessorsAltair beaconStateAccessors, - BeaconStateMutators beaconStateMutators, - ValidatorsUtil validatorsUtil, - BeaconStateUtil beaconStateUtil, - ValidatorStatusFactory validatorStatusFactory, - SchemaDefinitions schemaDefinitions) { + final SpecConfigBellatrix specConfig, + final MiscHelpersAltair miscHelpers, + final BeaconStateAccessorsAltair beaconStateAccessors, + final BeaconStateMutators beaconStateMutators, + final ValidatorsUtil validatorsUtil, + final BeaconStateUtil beaconStateUtil, + final ValidatorStatusFactory validatorStatusFactory, + final SchemaDefinitions schemaDefinitions) { super( specConfig, miscHelpers, diff --git a/ethereum/spec/src/test/java/tech/pegasys/teku/spec/logic/versions/electra/helpers/PredicatesElectraTest.java b/ethereum/spec/src/test/java/tech/pegasys/teku/spec/logic/versions/electra/helpers/PredicatesElectraTest.java new file mode 100644 index 00000000000..26f8f2ba1b4 --- /dev/null +++ b/ethereum/spec/src/test/java/tech/pegasys/teku/spec/logic/versions/electra/helpers/PredicatesElectraTest.java @@ -0,0 +1,85 @@ +/* + * 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.datastructures.state.Validator; +import tech.pegasys.teku.spec.util.DataStructureUtil; + +class PredicatesElectraTest { + private final Spec spec = TestSpecFactory.createMinimalElectra(); + private final DataStructureUtil dataStructureUtil = new DataStructureUtil(spec); + private final PredicatesElectra predicates = new PredicatesElectra(spec.getGenesisSpecConfig()); + + private final UInt64 excessLargeValidatorBalance = UInt64.valueOf(2050_000_000_000L); + + private final UInt64 maxEffectiveBalanceNonCompounding = UInt64.THIRTY_TWO_ETH; + + private final UInt64 maxEffectiveBalanceCompounding = UInt64.valueOf(2048_000_000_000L); + + @Test + void isPartiallyWithdrawableValidator_shouldNotDetermineBlsWithdrawalAsNotWithdrawable() { + final Validator validator = + dataStructureUtil + .validatorBuilder() + .withdrawalCredentials(dataStructureUtil.randomBlsWithdrawalCredentials()) + .effectiveBalance(maxEffectiveBalanceNonCompounding) + .build(); + assertThat(predicates.isPartiallyWithdrawableValidator(validator, excessLargeValidatorBalance)) + .isFalse(); + } + + @Test + void isPartiallyWithdrawableValidator_shouldDetermineEth1WithdrawalAsWithdrawable() { + final Validator validator = + dataStructureUtil + .validatorBuilder() + .withdrawalCredentials(dataStructureUtil.randomEth1WithdrawalCredentials()) + .effectiveBalance(maxEffectiveBalanceNonCompounding) + .build(); + assertThat(predicates.isPartiallyWithdrawableValidator(validator, excessLargeValidatorBalance)) + .isTrue(); + } + + @Test + void isPartiallyWithdrawableValidator_shouldDetermineCompoundingWithdrawalAsWithdrawable() { + final Validator validator = + dataStructureUtil + .validatorBuilder() + .withdrawalCredentials(dataStructureUtil.randomCompoundingWithdrawalCredentials()) + .effectiveBalance(maxEffectiveBalanceCompounding) + .build(); + assertThat(predicates.isPartiallyWithdrawableValidator(validator, excessLargeValidatorBalance)) + .isTrue(); + } + + @Test + void isPartiallyWithdrawableValidator_shouldDetermineCompoundingWithdrawalAsAsNotWithdrawable() { + final Validator validator = + dataStructureUtil + .validatorBuilder() + .withdrawalCredentials(dataStructureUtil.randomCompoundingWithdrawalCredentials()) + .effectiveBalance(maxEffectiveBalanceNonCompounding) + .build(); + assertThat( + predicates.isPartiallyWithdrawableValidator( + validator, maxEffectiveBalanceNonCompounding)) + .isFalse(); + } +} 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 7d307ecd14c..72b5b57dca3 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 @@ -2135,6 +2135,13 @@ public Bytes32 randomEth1WithdrawalCredentials() { randomEth1Address().getWrappedBytes())); } + public Bytes32 randomCompoundingWithdrawalCredentials() { + return Bytes32.wrap( + Bytes.concatenate( + Bytes.fromHexString("0x020000000000000000000000"), + randomEth1Address().getWrappedBytes())); + } + public List randomVersionedHashes(final int count) { return IntStream.range(0, count) .mapToObj(__ -> new VersionedHash(randomBytes32()))