Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix: Partial withdrawals count #8684

Merged
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,7 @@ allprojects {
}
}

def refTestVersion = 'v1.5.0-alpha.7'
def refTestVersion = 'v1.5.0-alpha.8'
def blsRefTestVersion = 'v0.1.2'
def slashingProtectionInterchangeRefTestVersion = 'v5.3.0'
def refTestBaseUrl = 'https://github.com/ethereum/consensus-spec-tests/releases/download'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,18 +130,20 @@ private static ExpectedWithdrawals createFromElectraState(
final MiscHelpersElectra miscHelpers,
final SpecConfigElectra specConfig,
final PredicatesElectra predicates) {
final List<Withdrawal> partialPendingWithdrawals =
final WithdrawalSummary expectedPendingPartialWithdrawals =
getPendingPartialWithdrawals(preState, schemaDefinitions, miscHelpers, specConfig);
final int partialWithdrawalsCount = partialPendingWithdrawals.size();
final List<Withdrawal> capellaWithdrawals =
final List<Withdrawal> partialPendingWithdrawals =
expectedPendingPartialWithdrawals.withdrawalList();
final int partialWithdrawalsCount = expectedPendingPartialWithdrawals.partialWithdrawalCount();
final List<Withdrawal> withdrawals =
getExpectedWithdrawals(
preState,
schemaDefinitions,
miscHelpers,
specConfig,
predicates,
partialPendingWithdrawals);
return new ExpectedWithdrawals(capellaWithdrawals, partialWithdrawalsCount, schemaDefinitions);
return new ExpectedWithdrawals(withdrawals, partialWithdrawalsCount, schemaDefinitions);
}

public List<Withdrawal> getWithdrawalList() {
Expand All @@ -152,7 +154,7 @@ public int getPartialWithdrawalCount() {
return partialWithdrawalCount;
}

private static List<Withdrawal> getPendingPartialWithdrawals(
private static WithdrawalSummary getPendingPartialWithdrawals(
final BeaconStateElectra preState,
final SchemaDefinitionsElectra schemaDefinitions,
final MiscHelpersElectra miscHelpers,
Expand All @@ -162,6 +164,7 @@ private static List<Withdrawal> getPendingPartialWithdrawals(
final List<Withdrawal> partialWithdrawals = new ArrayList<>();
final SszList<PendingPartialWithdrawal> pendingPartialWithdrawals =
preState.getPendingPartialWithdrawals();
int partialWithdrawalsCount = 0;
UInt64 withdrawalIndex = preState.getNextWithdrawalIndex();

for (int i = 0; i < pendingPartialWithdrawals.size() && i < maxPendingPartialWithdrawals; i++) {
Expand Down Expand Up @@ -195,8 +198,9 @@ private static List<Withdrawal> getPendingPartialWithdrawals(
withdrawableBalance));
withdrawalIndex = withdrawalIndex.increment();
}
partialWithdrawalsCount++;
}
return partialWithdrawals;
return new WithdrawalSummary(partialWithdrawals, partialWithdrawalsCount);
}

// get_expected_withdrawals
Expand Down Expand Up @@ -371,4 +375,6 @@ private static void assertWithdrawalsInExecutionPayloadMatchExpected(
private static UInt64 nextWithdrawalAfter(final List<Withdrawal> partialWithdrawals) {
return partialWithdrawals.getLast().getIndex().increment();
}

public record WithdrawalSummary(List<Withdrawal> withdrawalList, int partialWithdrawalCount) {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD: 2

# Withdrawals processing
# ---------------------------------------------------------------
# 2**0 ( = 1) pending withdrawals
MAX_PENDING_PARTIALS_PER_WITHDRAWALS_SWEEP: 1
# 2**1 ( = 2) pending withdrawals
MAX_PENDING_PARTIALS_PER_WITHDRAWALS_SWEEP: 2

# Pending deposits processing
# ---------------------------------------------------------------
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD: 2

# Withdrawals processing
# ---------------------------------------------------------------
# 2**0 ( = 1) pending withdrawals
MAX_PENDING_PARTIALS_PER_WITHDRAWALS_SWEEP: 1
# 2**1 ( = 2) pending withdrawals
MAX_PENDING_PARTIALS_PER_WITHDRAWALS_SWEEP: 2

# Pending deposits processing
# ---------------------------------------------------------------
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,15 +126,51 @@ void electraPendingPartialWithdrawals() {
spec.getBlockProcessor(preState.getSlot()).getExpectedWithdrawals(preState);
final MutableBeaconStateElectra mutableBeaconStateElectra =
MutableBeaconStateElectra.required(preState.createWritableCopy());
assertThat(withdrawals.getPartialWithdrawalCount()).isEqualTo(1);
assertThat(withdrawals.getPartialWithdrawalCount()).isEqualTo(2);

withdrawals.processWithdrawalsUnchecked(
mutableBeaconStateElectra,
SchemaDefinitionsElectra.required(spec.getGenesisSchemaDefinitions()),
spec.getGenesisSpec().beaconStateMutators(),
SpecConfigElectra.required(spec.getGenesisSpecConfig()));
assertThat(mutableBeaconStateElectra.getPendingPartialWithdrawals().size()).isEqualTo(2);
assertThat(mutableBeaconStateElectra.getNextWithdrawalIndex()).isEqualTo(UInt64.ONE);
assertThat(mutableBeaconStateElectra.getPendingPartialWithdrawals().size()).isEqualTo(1);
assertThat(mutableBeaconStateElectra.getNextWithdrawalIndex()).isEqualTo(UInt64.valueOf(2));
assertThat(mutableBeaconStateElectra.getValidators().size()).isEqualTo(3);
}

@Test
void electraPendingPartialCountsSkippedWithdrawals() {
spec = TestSpecFactory.createMinimalElectra();
dataStructureUtil = new DataStructureUtil(spec);
final SpecConfigElectra specConfigElectra =
SpecConfigElectra.required(spec.getGenesisSpec().getConfig());
final UInt64 electraMaxBalance = specConfigElectra.getMaxEffectiveBalance();
final long partialWithdrawalBalance = 10241024L;

final BeaconStateElectra preState =
BeaconStateElectra.required(
new BeaconStateTestBuilder(dataStructureUtil)
.activeConsolidatingValidator(electraMaxBalance.plus(partialWithdrawalBalance))
// the two validators below are skipped because they are queued for exit therefore
// they're withdrawals are skipped
.activeConsolidatingValidatorQueuedForExit(
electraMaxBalance.plus(partialWithdrawalBalance + 1))
.activeConsolidatingValidatorQueuedForExit(
electraMaxBalance.plus(partialWithdrawalBalance + 2))
.pendingPartialWithdrawal(0, electraMaxBalance.plus(partialWithdrawalBalance))
.pendingPartialWithdrawal(
1, electraMaxBalance.plus(partialWithdrawalBalance).plus(1))
.pendingPartialWithdrawal(
2, electraMaxBalance.plus(partialWithdrawalBalance).plus(2))
.build());

final ExpectedWithdrawals withdrawals =
spec.getBlockProcessor(preState.getSlot()).getExpectedWithdrawals(preState);

// even having 2 of the 3 partial withdrawals skipped,
// the count should be 2(which is the MAX_PENDING_PARTIALS_PER_WITHDRAWALS_SWEEP for minimal
// spec)
// because we consider the skipped in the count
assertThat(withdrawals.getPartialWithdrawalCount()).isEqualTo(2);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,19 @@ public BeaconStateTestBuilder activeConsolidatingValidator(final UInt64 balance)
return this;
}

public BeaconStateTestBuilder activeConsolidatingValidatorQueuedForExit(final UInt64 balance) {
validators.add(
dataStructureUtil
.randomValidator()
.withWithdrawalCredentials(dataStructureUtil.randomCompoundingWithdrawalCredentials())
.withEffectiveBalance(
SpecConfigElectra.required(specConfig).getMaxEffectiveBalanceElectra().min(balance))
.withActivationEpoch(UInt64.ZERO)
.withExitEpoch(FAR_FUTURE_EPOCH.minus(1)));
balances.add(balance);
return this;
}

public BeaconState build() {
final SpecVersion specVersion = dataStructureUtil.getSpec().atSlot(slot);
return specVersion
Expand Down