Skip to content

Commit

Permalink
EIP-7251 - Added minActivationBalance (#8190)
Browse files Browse the repository at this point in the history
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 <paul.harris@consensys.net>
  • Loading branch information
rolfyone authored Apr 12, 2024
1 parent c862af7 commit a3248fe
Show file tree
Hide file tree
Showing 8 changed files with 291 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Original file line number Diff line number Diff line change
Expand Up @@ -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<Logger> loggerThrottler = new Throttler<>(LOG, UInt64.ONE);

Expand All @@ -83,6 +84,7 @@ protected AbstractEpochProcessor(
this.beaconStateUtil = beaconStateUtil;
this.validatorStatusFactory = validatorStatusFactory;
this.schemaDefinitions = schemaDefinitions;
this.maxEffectiveBalance = specConfig.getMaxEffectiveBalance();
}

/**
Expand Down Expand Up @@ -310,20 +312,14 @@ public void processRegistryUpdates(
SszMutableList<Validator> 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<ValidatorExitContext> validatorExitContextSupplier =
beaconStateMutators.createValidatorExitContextSupplier(state);

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(
Expand Down Expand Up @@ -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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -53,15 +53,15 @@ 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,
final BeaconStateUtil beaconStateUtil,
final AttestationUtil attestationUtil,
final OperationValidator operationValidator,
final ValidatorStatusFactoryAltair validatorStatusFactory,
final EpochProcessorCapella epochProcessor,
final EpochProcessorElectra epochProcessor,
final BlockProcessorCapella blockProcessor,
final ForkChoiceUtil forkChoiceUtil,
final BlockProposalUtil blockProposalUtil,
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -126,8 +126,8 @@ public static SpecLogicElectra create(
predicates,
miscHelpers,
beaconStateAccessors);
final EpochProcessorCapella epochProcessor =
new EpochProcessorCapella(
final EpochProcessorElectra epochProcessor =
new EpochProcessorElectra(
config,
miscHelpers,
beaconStateAccessors,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* 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(
final SpecConfigDeneb config,
final PredicatesElectra predicatesElectra,
final 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;
}
}
Original file line number Diff line number Diff line change
@@ -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(final Validator validator) {
return isCompoundingWithdrawalCredential(validator.getWithdrawalCredentials());
}

protected boolean isCompoundingWithdrawalCredential(final Bytes32 withdrawalCredentials) {
return withdrawalCredentials.get(0) == COMPOUNDING_WITHDRAWAL_BYTE;
}
}
Original file line number Diff line number Diff line change
@@ -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(
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,
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);
}
}
Original file line number Diff line number Diff line change
@@ -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();
}
}
Loading

0 comments on commit a3248fe

Please sign in to comment.