Skip to content

Commit 533fcc8

Browse files
authored
EIP7251 - voluntary exits operation validation (Consensys#8237)
Extended the voluntary exits validation for electra, where voluntary exits can't be processed if there are pending withdrawals in the queue. Structured this validation to be individually tested but didn't refactor the rest. also looks like a lot of the specLogic classes have heavily duplicated code but this is not really new, so I left it. partially addresses Consensys#8149 Signed-off-by: Paul Harris <[email protected]>
1 parent 283f5d6 commit 533fcc8

File tree

12 files changed

+222
-22
lines changed

12 files changed

+222
-22
lines changed

ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/altair/SpecLogicAltair.java

+8-1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
import tech.pegasys.teku.spec.logic.versions.bellatrix.helpers.BellatrixTransitionHelpers;
3939
import tech.pegasys.teku.spec.logic.versions.phase0.operations.validation.AttestationDataValidatorPhase0;
4040
import tech.pegasys.teku.spec.logic.versions.phase0.operations.validation.OperationValidatorPhase0;
41+
import tech.pegasys.teku.spec.logic.versions.phase0.operations.validation.VoluntaryExitValidator;
4142
import tech.pegasys.teku.spec.logic.versions.phase0.util.AttestationUtilPhase0;
4243
import tech.pegasys.teku.spec.schemas.SchemaDefinitionsAltair;
4344

@@ -110,9 +111,15 @@ public static SpecLogicAltair create(
110111
// execution change
111112
final AttestationDataValidator attestationDataValidator =
112113
new AttestationDataValidatorPhase0(config, miscHelpers, beaconStateAccessors);
114+
final VoluntaryExitValidator voluntaryExitValidator =
115+
new VoluntaryExitValidator(config, predicates, beaconStateAccessors);
113116
final OperationValidator operationValidator =
114117
new OperationValidatorPhase0(
115-
config, predicates, beaconStateAccessors, attestationDataValidator, attestationUtil);
118+
predicates,
119+
beaconStateAccessors,
120+
attestationDataValidator,
121+
attestationUtil,
122+
voluntaryExitValidator);
116123
final ValidatorStatusFactoryAltair validatorStatusFactory =
117124
new ValidatorStatusFactoryAltair(
118125
config,

ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/bellatrix/SpecLogicBellatrix.java

+8-1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import tech.pegasys.teku.spec.logic.versions.bellatrix.util.BlindBlockUtilBellatrix;
4040
import tech.pegasys.teku.spec.logic.versions.phase0.operations.validation.AttestationDataValidatorPhase0;
4141
import tech.pegasys.teku.spec.logic.versions.phase0.operations.validation.OperationValidatorPhase0;
42+
import tech.pegasys.teku.spec.logic.versions.phase0.operations.validation.VoluntaryExitValidator;
4243
import tech.pegasys.teku.spec.logic.versions.phase0.util.AttestationUtilPhase0;
4344
import tech.pegasys.teku.spec.schemas.SchemaDefinitionsBellatrix;
4445

@@ -114,9 +115,15 @@ public static SpecLogicBellatrix create(
114115
new AttestationUtilPhase0(config, schemaDefinitions, beaconStateAccessors, miscHelpers);
115116
final AttestationDataValidator attestationDataValidator =
116117
new AttestationDataValidatorPhase0(config, miscHelpers, beaconStateAccessors);
118+
final VoluntaryExitValidator voluntaryExitValidator =
119+
new VoluntaryExitValidator(config, predicates, beaconStateAccessors);
117120
final OperationValidator operationValidator =
118121
new OperationValidatorPhase0(
119-
config, predicates, beaconStateAccessors, attestationDataValidator, attestationUtil);
122+
predicates,
123+
beaconStateAccessors,
124+
attestationDataValidator,
125+
attestationUtil,
126+
voluntaryExitValidator);
120127
final ValidatorStatusFactoryAltair validatorStatusFactory =
121128
new ValidatorStatusFactoryAltair(
122129
config,

ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/capella/SpecLogicCapella.java

+8-1
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
import tech.pegasys.teku.spec.logic.versions.capella.operations.validation.OperationValidatorCapella;
4141
import tech.pegasys.teku.spec.logic.versions.capella.statetransition.epoch.EpochProcessorCapella;
4242
import tech.pegasys.teku.spec.logic.versions.phase0.operations.validation.AttestationDataValidatorPhase0;
43+
import tech.pegasys.teku.spec.logic.versions.phase0.operations.validation.VoluntaryExitValidator;
4344
import tech.pegasys.teku.spec.logic.versions.phase0.util.AttestationUtilPhase0;
4445
import tech.pegasys.teku.spec.schemas.SchemaDefinitionsCapella;
4546

@@ -114,9 +115,15 @@ public static SpecLogicCapella create(
114115
new AttestationUtilPhase0(config, schemaDefinitions, beaconStateAccessors, miscHelpers);
115116
final AttestationDataValidator attestationDataValidator =
116117
new AttestationDataValidatorPhase0(config, miscHelpers, beaconStateAccessors);
118+
final VoluntaryExitValidator voluntaryExitValidator =
119+
new VoluntaryExitValidator(config, predicates, beaconStateAccessors);
117120
final OperationValidator operationValidator =
118121
new OperationValidatorCapella(
119-
config, predicates, beaconStateAccessors, attestationDataValidator, attestationUtil);
122+
predicates,
123+
beaconStateAccessors,
124+
attestationDataValidator,
125+
attestationUtil,
126+
voluntaryExitValidator);
120127
final ValidatorStatusFactoryAltair validatorStatusFactory =
121128
new ValidatorStatusFactoryAltair(
122129
config,

ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/capella/operations/validation/OperationValidatorCapella.java

+9-4
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
package tech.pegasys.teku.spec.logic.versions.capella.operations.validation;
1515

1616
import java.util.Optional;
17-
import tech.pegasys.teku.spec.config.SpecConfig;
1817
import tech.pegasys.teku.spec.datastructures.operations.BlsToExecutionChange;
1918
import tech.pegasys.teku.spec.datastructures.state.Fork;
2019
import tech.pegasys.teku.spec.datastructures.state.beaconstate.BeaconState;
@@ -24,19 +23,25 @@
2423
import tech.pegasys.teku.spec.logic.common.operations.validation.OperationInvalidReason;
2524
import tech.pegasys.teku.spec.logic.common.util.AttestationUtil;
2625
import tech.pegasys.teku.spec.logic.versions.phase0.operations.validation.OperationValidatorPhase0;
26+
import tech.pegasys.teku.spec.logic.versions.phase0.operations.validation.VoluntaryExitValidator;
2727

2828
public class OperationValidatorCapella extends OperationValidatorPhase0 {
2929

3030
private final BlsToExecutionChangesValidator blsToExecutionChangesValidator =
3131
new BlsToExecutionChangesValidator();
3232

3333
public OperationValidatorCapella(
34-
final SpecConfig specConfig,
3534
final Predicates predicates,
3635
final BeaconStateAccessors beaconStateAccessors,
3736
final AttestationDataValidator attestationDataValidator,
38-
final AttestationUtil attestationUtil) {
39-
super(specConfig, predicates, beaconStateAccessors, attestationDataValidator, attestationUtil);
37+
final AttestationUtil attestationUtil,
38+
final VoluntaryExitValidator voluntaryExitValidator) {
39+
super(
40+
predicates,
41+
beaconStateAccessors,
42+
attestationDataValidator,
43+
attestationUtil,
44+
voluntaryExitValidator);
4045
}
4146

4247
@Override

ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/deneb/SpecLogicDeneb.java

+8-1
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import tech.pegasys.teku.spec.logic.versions.deneb.operations.validation.AttestationDataValidatorDeneb;
4444
import tech.pegasys.teku.spec.logic.versions.deneb.util.AttestationUtilDeneb;
4545
import tech.pegasys.teku.spec.logic.versions.deneb.util.ForkChoiceUtilDeneb;
46+
import tech.pegasys.teku.spec.logic.versions.phase0.operations.validation.VoluntaryExitValidator;
4647
import tech.pegasys.teku.spec.schemas.SchemaDefinitionsDeneb;
4748

4849
public class SpecLogicDeneb extends AbstractSpecLogic {
@@ -114,9 +115,15 @@ public static SpecLogicDeneb create(
114115
new AttestationUtilDeneb(config, schemaDefinitions, beaconStateAccessors, miscHelpers);
115116
final AttestationDataValidator attestationDataValidator =
116117
new AttestationDataValidatorDeneb(config, miscHelpers, beaconStateAccessors);
118+
final VoluntaryExitValidator voluntaryExitValidator =
119+
new VoluntaryExitValidator(config, predicates, beaconStateAccessors);
117120
final OperationValidator operationValidator =
118121
new OperationValidatorCapella(
119-
config, predicates, beaconStateAccessors, attestationDataValidator, attestationUtil);
122+
predicates,
123+
beaconStateAccessors,
124+
attestationDataValidator,
125+
attestationUtil,
126+
voluntaryExitValidator);
120127
final ValidatorStatusFactoryAltair validatorStatusFactory =
121128
new ValidatorStatusFactoryAltair(
122129
config,

ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/SpecLogicElectra.java

+8-1
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
import tech.pegasys.teku.spec.logic.versions.electra.helpers.BeaconStateMutatorsElectra;
4545
import tech.pegasys.teku.spec.logic.versions.electra.helpers.MiscHelpersElectra;
4646
import tech.pegasys.teku.spec.logic.versions.electra.helpers.PredicatesElectra;
47+
import tech.pegasys.teku.spec.logic.versions.electra.operations.validation.VoluntaryExitValidatorElectra;
4748
import tech.pegasys.teku.spec.logic.versions.electra.statetransition.epoch.EpochProcessorElectra;
4849
import tech.pegasys.teku.spec.schemas.SchemaDefinitionsElectra;
4950

@@ -116,9 +117,15 @@ public static SpecLogicElectra create(
116117
new AttestationUtilDeneb(config, schemaDefinitions, beaconStateAccessors, miscHelpers);
117118
final AttestationDataValidator attestationDataValidator =
118119
new AttestationDataValidatorDeneb(config, miscHelpers, beaconStateAccessors);
120+
final VoluntaryExitValidatorElectra voluntaryExitValidatorElectra =
121+
new VoluntaryExitValidatorElectra(config, predicates, beaconStateAccessors);
119122
final OperationValidator operationValidator =
120123
new OperationValidatorCapella(
121-
config, predicates, beaconStateAccessors, attestationDataValidator, attestationUtil);
124+
predicates,
125+
beaconStateAccessors,
126+
attestationDataValidator,
127+
attestationUtil,
128+
voluntaryExitValidatorElectra);
122129
final ValidatorStatusFactoryAltair validatorStatusFactory =
123130
new ValidatorStatusFactoryAltair(
124131
config,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/*
2+
* Copyright Consensys Software Inc., 2024
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
5+
* the License. You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
10+
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
11+
* specific language governing permissions and limitations under the License.
12+
*/
13+
14+
package tech.pegasys.teku.spec.logic.versions.electra.operations.validation;
15+
16+
import static tech.pegasys.teku.spec.logic.common.operations.validation.OperationInvalidReason.check;
17+
import static tech.pegasys.teku.spec.logic.common.operations.validation.OperationInvalidReason.firstOf;
18+
19+
import com.google.common.annotations.VisibleForTesting;
20+
import java.util.Optional;
21+
import tech.pegasys.teku.infrastructure.unsigned.UInt64;
22+
import tech.pegasys.teku.spec.config.SpecConfig;
23+
import tech.pegasys.teku.spec.datastructures.operations.SignedVoluntaryExit;
24+
import tech.pegasys.teku.spec.datastructures.state.Fork;
25+
import tech.pegasys.teku.spec.datastructures.state.beaconstate.BeaconState;
26+
import tech.pegasys.teku.spec.datastructures.state.beaconstate.versions.electra.BeaconStateElectra;
27+
import tech.pegasys.teku.spec.logic.common.helpers.BeaconStateAccessors;
28+
import tech.pegasys.teku.spec.logic.common.helpers.Predicates;
29+
import tech.pegasys.teku.spec.logic.common.operations.validation.OperationInvalidReason;
30+
import tech.pegasys.teku.spec.logic.versions.electra.helpers.BeaconStateAccessorsElectra;
31+
import tech.pegasys.teku.spec.logic.versions.phase0.operations.validation.VoluntaryExitValidator;
32+
33+
public class VoluntaryExitValidatorElectra extends VoluntaryExitValidator {
34+
private final BeaconStateAccessorsElectra stateAccessorsElectra;
35+
36+
public VoluntaryExitValidatorElectra(
37+
final SpecConfig specConfig,
38+
final Predicates predicates,
39+
final BeaconStateAccessors beaconStateAccessors) {
40+
super(specConfig, predicates, beaconStateAccessors);
41+
this.stateAccessorsElectra = BeaconStateAccessorsElectra.required(beaconStateAccessors);
42+
}
43+
44+
@Override
45+
public Optional<OperationInvalidReason> validate(
46+
final Fork fork, final BeaconState state, final SignedVoluntaryExit signedExit) {
47+
final BeaconStateElectra stateElectra = BeaconStateElectra.required(state);
48+
return firstOf(
49+
() -> super.validate(fork, state, signedExit),
50+
() -> validateElectraConditions(stateElectra, signedExit));
51+
}
52+
53+
@VisibleForTesting
54+
Optional<OperationInvalidReason> validateElectraConditions(
55+
final BeaconStateElectra stateElectra, final SignedVoluntaryExit exit) {
56+
final int validatorId = exit.getValidatorId();
57+
return check(
58+
stateAccessorsElectra
59+
.getPendingBalanceToWithdraw(stateElectra, validatorId)
60+
.equals(UInt64.ZERO),
61+
VoluntaryExitValidator.ExitInvalidReason.pendingWithdrawalsInQueue());
62+
}
63+
}

ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/phase0/SpecLogicPhase0.java

+8-1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import tech.pegasys.teku.spec.logic.versions.phase0.helpers.BeaconStateAccessorsPhase0;
3636
import tech.pegasys.teku.spec.logic.versions.phase0.operations.validation.AttestationDataValidatorPhase0;
3737
import tech.pegasys.teku.spec.logic.versions.phase0.operations.validation.OperationValidatorPhase0;
38+
import tech.pegasys.teku.spec.logic.versions.phase0.operations.validation.VoluntaryExitValidator;
3839
import tech.pegasys.teku.spec.logic.versions.phase0.statetransition.epoch.EpochProcessorPhase0;
3940
import tech.pegasys.teku.spec.logic.versions.phase0.statetransition.epoch.ValidatorStatusFactoryPhase0;
4041
import tech.pegasys.teku.spec.logic.versions.phase0.util.AttestationUtilPhase0;
@@ -100,9 +101,15 @@ public static SpecLogicPhase0 create(
100101
new AttestationUtilPhase0(config, schemaDefinitions, beaconStateAccessors, miscHelpers);
101102
final AttestationDataValidator attestationDataValidator =
102103
new AttestationDataValidatorPhase0(config, miscHelpers, beaconStateAccessors);
104+
final VoluntaryExitValidator voluntaryExitValidator =
105+
new VoluntaryExitValidator(config, predicates, beaconStateAccessors);
103106
final OperationValidator operationValidator =
104107
new OperationValidatorPhase0(
105-
config, predicates, beaconStateAccessors, attestationDataValidator, attestationUtil);
108+
predicates,
109+
beaconStateAccessors,
110+
attestationDataValidator,
111+
attestationUtil,
112+
voluntaryExitValidator);
106113
final ValidatorStatusFactoryPhase0 validatorStatusFactory =
107114
new ValidatorStatusFactoryPhase0(
108115
config, beaconStateUtil, attestationUtil, beaconStateAccessors, predicates);

ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/phase0/operations/validation/OperationValidatorPhase0.java

+3-5
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
package tech.pegasys.teku.spec.logic.versions.phase0.operations.validation;
1515

1616
import java.util.Optional;
17-
import tech.pegasys.teku.spec.config.SpecConfig;
1817
import tech.pegasys.teku.spec.datastructures.operations.AttestationData;
1918
import tech.pegasys.teku.spec.datastructures.operations.AttesterSlashing;
2019
import tech.pegasys.teku.spec.datastructures.operations.BlsToExecutionChange;
@@ -38,18 +37,17 @@ public class OperationValidatorPhase0 implements OperationValidator {
3837
private final VoluntaryExitValidator voluntaryExitValidator;
3938

4039
public OperationValidatorPhase0(
41-
final SpecConfig specConfig,
4240
final Predicates predicates,
4341
final BeaconStateAccessors beaconStateAccessors,
4442
final AttestationDataValidator attestationDataValidator,
45-
final AttestationUtil attestationUtil) {
43+
final AttestationUtil attestationUtil,
44+
final VoluntaryExitValidator voluntaryExitValidator) {
4645
this.attestationDataValidator = attestationDataValidator;
4746
this.attesterSlashingValidator =
4847
new AttesterSlashingValidator(predicates, beaconStateAccessors, attestationUtil);
4948
this.proposerSlashingValidator =
5049
new ProposerSlashingValidator(predicates, beaconStateAccessors);
51-
this.voluntaryExitValidator =
52-
new VoluntaryExitValidator(specConfig, predicates, beaconStateAccessors);
50+
this.voluntaryExitValidator = voluntaryExitValidator;
5351
}
5452

5553
@Override

ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/phase0/operations/validation/VoluntaryExitValidator.java

+7-2
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ public class VoluntaryExitValidator
3737
private final Predicates predicates;
3838
private final BeaconStateAccessors beaconStateAccessors;
3939

40-
VoluntaryExitValidator(
40+
public VoluntaryExitValidator(
4141
final SpecConfig specConfig,
4242
final Predicates predicates,
4343
final BeaconStateAccessors beaconStateAccessors) {
@@ -49,7 +49,7 @@ public class VoluntaryExitValidator
4949
@Override
5050
public Optional<OperationInvalidReason> validate(
5151
final Fork fork, final BeaconState state, final SignedVoluntaryExit signedExit) {
52-
VoluntaryExit exit = signedExit.getMessage();
52+
final VoluntaryExit exit = signedExit.getMessage();
5353
return firstOf(
5454
() ->
5555
check(
@@ -109,5 +109,10 @@ public static OperationInvalidReason validatorTooYoung(final UInt64 exitEpoch) {
109109
public static OperationInvalidReason invalidSignature() {
110110
return () -> "Signature is invalid";
111111
}
112+
113+
public static OperationInvalidReason pendingWithdrawalsInQueue() {
114+
return () ->
115+
"Validator cannot be exited while there are pending withdrawals in the withdrawal queue";
116+
}
112117
}
113118
}

0 commit comments

Comments
 (0)