Skip to content

Commit

Permalink
Switch to compounding when consolidating with source==target (#8646)
Browse files Browse the repository at this point in the history
  • Loading branch information
lucassaldanha authored Oct 7, 2024
1 parent c76765e commit 8a9fa11
Show file tree
Hide file tree
Showing 6 changed files with 123 additions and 40 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,9 @@ public class EpochProcessingTestExecutor implements TestExecutor {
.put(
"epoch_processing/inactivity_updates",
new EpochProcessingTestExecutor(EpochOperation.INACTIVITY_UPDATES))
// TODO re-enable consolidation tests (https://github.com/Consensys/teku/issues/8617)
.put("epoch_processing/pending_consolidations", TestExecutor.IGNORE_TESTS)
.put(
"epoch_processing/pending_consolidations",
new EpochProcessingTestExecutor(EpochOperation.PENDING_CONSOLIDATIONS))
.put(
"epoch_processing/pending_deposits",
new EpochProcessingTestExecutor(EpochOperation.PENDING_DEPOSITS))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -930,6 +930,14 @@ public void processConsolidationRequests(
// No Consolidations until Electra
}

@Override
public boolean isValidSwitchToCompoundingRequest(
final BeaconState beaconState, final ConsolidationRequest consolidationRequest)
throws BlockProcessingException {
// No Consolidations until Electra
return false;
}

// Catch generic errors and wrap them in a BlockProcessingException
protected void safelyProcess(final BlockProcessingAction action) throws BlockProcessingException {
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,10 @@ void processConsolidationRequests(
MutableBeaconState state, List<ConsolidationRequest> consolidationRequests)
throws BlockProcessingException;

boolean isValidSwitchToCompoundingRequest(
BeaconState beaconState, ConsolidationRequest consolidationRequest)
throws BlockProcessingException;

ExpectedWithdrawals getExpectedWithdrawals(BeaconState preState);

default Optional<BlockProcessorAltair> toVersionAltair() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ public void processWithdrawalRequests(
if (maybeValidatorIndex.isEmpty()) {
LOG.debug(
"process_withdrawal_request: no matching validator for public key {}",
withdrawalRequest.getValidatorPublicKey());
withdrawalRequest.getValidatorPublicKey().toAbbreviatedString());
return;
}

Expand Down Expand Up @@ -377,7 +377,7 @@ public void processDepositRequests(
public void processConsolidationRequests(
final MutableBeaconState state, final List<ConsolidationRequest> consolidationRequests) {
LOG.debug(
"process_consolidation_request: {} consolidation request to process from block at "
"process_consolidation_request: {} consolidation requests to process from block at "
+ "slot {}",
consolidationRequests.size(),
state.getSlot());
Expand All @@ -392,6 +392,27 @@ private void processConsolidationRequest(
final UInt64 slot = state.getSlot();
final UInt64 currentEpoch = miscHelpers.computeEpochAtSlot(slot);

if (isValidSwitchToCompoundingRequest(state, consolidationRequest)) {
LOG.debug(
"process_consolidation_request: switching validator {} to compounding address",
consolidationRequest.getSourcePubkey().toAbbreviatedString());
validatorsUtil
.getValidatorIndex(state, consolidationRequest.getSourcePubkey())
.ifPresent(
sourceValidatorIndex ->
beaconStateMutatorsElectra.switchToCompoundingValidator(
state, sourceValidatorIndex));
return;
}

// Verify that source != target, so a consolidation cannot be used as an exit
if (consolidationRequest.getSourcePubkey().equals(consolidationRequest.getTargetPubkey())) {
LOG.debug(
"process_consolidation_request: source_pubkey and target_pubkey must be different (pubkey = {})",
consolidationRequest.getSourcePubkey().toAbbreviatedString());
return;
}

// If the pending consolidations queue is full, consolidation requests are ignored
if (state.getPendingConsolidations().size()
== specConfigElectra.getPendingConsolidationsLimit()) {
Expand All @@ -414,7 +435,7 @@ private void processConsolidationRequest(
if (maybeSourceValidatorIndex.isEmpty()) {
LOG.debug(
"process_consolidation_request: source_pubkey {} not found",
consolidationRequest.getSourcePubkey());
consolidationRequest.getSourcePubkey().toAbbreviatedString());
return;
}

Expand All @@ -424,18 +445,14 @@ private void processConsolidationRequest(
if (maybeTargetValidatorIndex.isEmpty()) {
LOG.debug(
"process_consolidation_request: target_pubkey {} not found",
consolidationRequest.getTargetPubkey());
return;
}

// Verify that source != target, so a consolidation cannot be used as an exit.
if (maybeSourceValidatorIndex.get().equals(maybeTargetValidatorIndex.get())) {
LOG.debug("process_consolidation_request: source_pubkey and target_pubkey must be different");
consolidationRequest.getTargetPubkey().toAbbreviatedString());
return;
}

final Validator sourceValidator = state.getValidators().get(maybeSourceValidatorIndex.get());
final Validator targetValidator = state.getValidators().get(maybeTargetValidatorIndex.get());
final int sourceValidatorIndex = maybeSourceValidatorIndex.get();
final Validator sourceValidator = state.getValidators().get(sourceValidatorIndex);
final int targetValidatorIndex = maybeTargetValidatorIndex.get();
final Validator targetValidator = state.getValidators().get(targetValidatorIndex);

// Verify source withdrawal credentials
final boolean sourceHasExecutionWithdrawalCredentials =
Expand All @@ -459,21 +476,25 @@ private void processConsolidationRequest(

// Verify the source and the target are active
if (!predicatesElectra.isActiveValidator(sourceValidator, currentEpoch)) {
LOG.debug("process_consolidation_request: source validator is inactive");
LOG.debug(
"process_consolidation_request: source validator {} is inactive", sourceValidatorIndex);
return;
}
if (!predicatesElectra.isActiveValidator(targetValidator, currentEpoch)) {
LOG.debug("process_consolidation_request: target validator is inactive");
LOG.debug(
"process_consolidation_request: target validator {} is inactive", targetValidatorIndex);
return;
}

// Verify exits for source and target have not been initiated
if (!sourceValidator.getExitEpoch().equals(FAR_FUTURE_EPOCH)) {
LOG.debug("process_consolidation_request: source validator is exiting");
LOG.debug(
"process_consolidation_request: source validator {} is exiting", sourceValidatorIndex);
return;
}
if (!targetValidator.getExitEpoch().equals(FAR_FUTURE_EPOCH)) {
LOG.debug("process_consolidation_request: target validator is exiting");
LOG.debug(
"process_consolidation_request: target validator {} is exiting", targetValidatorIndex);
return;
}

Expand All @@ -487,24 +508,81 @@ private void processConsolidationRequest(
state
.getValidators()
.update(
maybeSourceValidatorIndex.get(),
sourceValidatorIndex,
v -> v.withExitEpoch(exitEpoch).withWithdrawableEpoch(withdrawableEpoch));
LOG.debug(
"process_consolidation_request: updated validator {} with exit_epoch = {}, withdrawable_epoch = {}",
maybeSourceValidatorIndex.get(),
sourceValidatorIndex,
exitEpoch,
withdrawableEpoch);

final PendingConsolidation pendingConsolidation =
new PendingConsolidation(
schemaDefinitionsElectra.getPendingConsolidationSchema(),
SszUInt64.of(UInt64.valueOf(maybeSourceValidatorIndex.get())),
SszUInt64.of(UInt64.valueOf(maybeTargetValidatorIndex.get())));
SszUInt64.of(UInt64.valueOf(sourceValidatorIndex)),
SszUInt64.of(UInt64.valueOf(targetValidatorIndex)));
state.getPendingConsolidations().append(pendingConsolidation);

// Churn any target excess active balance of target and raise its max
if (predicatesElectra.hasEth1WithdrawalCredential(targetValidator)) {
beaconStateMutatorsElectra.switchToCompoundingValidator(state, targetValidatorIndex);
}

LOG.debug("process_consolidation_request: created {}", pendingConsolidation);
}

/**
* Implements function is_valid_switch_to_compounding_request
*
* @see <a
* href="https://github.com/ethereum/consensus-specs/blob/dev/specs/electra/beacon-chain.md#new-is_valid_switch_to_compounding_request"/>
*/
@Override
public boolean isValidSwitchToCompoundingRequest(
final BeaconState state, final ConsolidationRequest consolidationRequest) {

// Switch to compounding requires source and target be equal
if (!consolidationRequest.getSourcePubkey().equals(consolidationRequest.getTargetPubkey())) {
return false;
}

// Verify source_pubkey exists
final Optional<Integer> maybeSourceValidatorIndex =
validatorsUtil.getValidatorIndex(state, consolidationRequest.getSourcePubkey());
if (maybeSourceValidatorIndex.isEmpty()) {
return false;
}

final int sourceValidatorIndex = maybeSourceValidatorIndex.get();
final Validator sourceValidator = state.getValidators().get(sourceValidatorIndex);

// Verify request has been authorized
final Eth1Address sourceValidatorExecutionAddress =
Predicates.getExecutionAddressUnchecked(sourceValidator.getWithdrawalCredentials());
if (!sourceValidatorExecutionAddress.equals(
Eth1Address.fromBytes(consolidationRequest.getSourceAddress().getWrappedBytes()))) {
return false;
}

// Verify source withdrawal credentials
if (!predicatesElectra.hasEth1WithdrawalCredential(sourceValidator)) {
return false;
}

// Verify the source is active
final UInt64 currentEpoch = miscHelpers.computeEpochAtSlot(state.getSlot());
if (!predicatesElectra.isActiveValidator(sourceValidator, currentEpoch)) {
return false;
}

// Verify exit for source has not been initiated
if (!sourceValidator.getExitEpoch().equals(FAR_FUTURE_EPOCH)) {
return false;
}

return true;
}

@Override
public void applyDeposit(
final MutableBeaconState state,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -184,19 +184,16 @@ public UInt64 computeConsolidationEpochAndUpdateChurn(
* @param index validatorIndex
*/
public void switchToCompoundingValidator(final MutableBeaconStateElectra state, final int index) {
if (PredicatesElectra.isEth1WithdrawalCredential(
state.getValidators().get(index).getWithdrawalCredentials())) {
final byte[] withdrawalCredentialsUpdated =
state.getValidators().get(index).getWithdrawalCredentials().toArray();
withdrawalCredentialsUpdated[0] = COMPOUNDING_WITHDRAWAL_BYTE;
state
.getValidators()
.update(
index,
validator ->
validator.withWithdrawalCredentials(Bytes32.wrap(withdrawalCredentialsUpdated)));
queueExcessActiveBalance(state, index);
}
final byte[] withdrawalCredentialsUpdated =
state.getValidators().get(index).getWithdrawalCredentials().toArray();
withdrawalCredentialsUpdated[0] = COMPOUNDING_WITHDRAWAL_BYTE;
state
.getValidators()
.update(
index,
validator ->
validator.withWithdrawalCredentials(Bytes32.wrap(withdrawalCredentialsUpdated)));
queueExcessActiveBalance(state, index);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@
import tech.pegasys.teku.spec.logic.versions.altair.helpers.BeaconStateAccessorsAltair;
import tech.pegasys.teku.spec.logic.versions.capella.statetransition.epoch.EpochProcessorCapella;
import tech.pegasys.teku.spec.logic.versions.electra.helpers.BeaconStateAccessorsElectra;
import tech.pegasys.teku.spec.logic.versions.electra.helpers.BeaconStateMutatorsElectra;
import tech.pegasys.teku.spec.logic.versions.electra.helpers.MiscHelpersElectra;
import tech.pegasys.teku.spec.schemas.SchemaDefinitions;
import tech.pegasys.teku.spec.schemas.SchemaDefinitionsElectra;
Expand All @@ -63,7 +62,6 @@ public class EpochProcessorElectra extends EpochProcessorCapella {

private final UInt64 minActivationBalance;
private final BeaconStateAccessorsElectra stateAccessorsElectra;
private final BeaconStateMutatorsElectra stateMutatorsElectra;
private final SchemaDefinitionsElectra schemaDefinitionsElectra;

public EpochProcessorElectra(
Expand All @@ -89,7 +87,6 @@ public EpochProcessorElectra(
this.minActivationBalance =
specConfig.toVersionElectra().orElseThrow().getMinActivationBalance();
this.stateAccessorsElectra = BeaconStateAccessorsElectra.required(beaconStateAccessors);
this.stateMutatorsElectra = BeaconStateMutatorsElectra.required(beaconStateMutators);
this.schemaDefinitionsElectra = SchemaDefinitionsElectra.required(schemaDefinitions);
}

Expand Down Expand Up @@ -391,8 +388,6 @@ public void processPendingConsolidations(final MutableBeaconState state) {
break;
}

stateMutatorsElectra.switchToCompoundingValidator(
stateElectra, pendingConsolidation.getTargetIndex());
final UInt64 activeBalance =
stateAccessorsElectra.getActiveBalance(state, pendingConsolidation.getSourceIndex());
beaconStateMutators.decreaseBalance(
Expand Down

0 comments on commit 8a9fa11

Please sign in to comment.