diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/common/helpers/MiscHelpers.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/common/helpers/MiscHelpers.java index 3d6df9eee96..8ee882c205e 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/common/helpers/MiscHelpers.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/common/helpers/MiscHelpers.java @@ -97,6 +97,14 @@ public int computeShuffledIndex(final int index, final int indexCount, final Byt public int computeProposerIndex( final BeaconState state, final IntList indices, final Bytes32 seed) { + return computeProposerIndex(state, indices, seed, specConfig.getMaxEffectiveBalance()); + } + + protected int computeProposerIndex( + final BeaconState state, + final IntList indices, + final Bytes32 seed, + final UInt64 maxEffectiveBalance) { checkArgument(!indices.isEmpty(), "compute_proposer_index indices must not be empty"); final Sha256 sha256 = getSha256Instance(); @@ -110,10 +118,11 @@ public int computeProposerIndex( hash = sha256.digest(seed, uint64ToBytes(Math.floorDiv(i, 32L))); } int randomByte = UnsignedBytes.toInt(hash[i % 32]); - UInt64 effectiveBalance = state.getValidators().get(candidateIndex).getEffectiveBalance(); - if (effectiveBalance + UInt64 validatorEffectiveBalance = + state.getValidators().get(candidateIndex).getEffectiveBalance(); + if (validatorEffectiveBalance .times(MAX_RANDOM_BYTE) - .isGreaterThanOrEqualTo(specConfig.getMaxEffectiveBalance().times(randomByte))) { + .isGreaterThanOrEqualTo(maxEffectiveBalance.times(randomByte))) { return candidateIndex; } i++; diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/altair/helpers/BeaconStateAccessorsAltair.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/altair/helpers/BeaconStateAccessorsAltair.java index 592776c6fbd..d8826b49ecc 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/altair/helpers/BeaconStateAccessorsAltair.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/altair/helpers/BeaconStateAccessorsAltair.java @@ -98,6 +98,11 @@ public UInt64 getBaseReward(final BeaconState state, final int validatorIndex) { * @return the sequence of sync committee indices */ public IntList getNextSyncCommitteeIndices(final BeaconState state) { + return getNextSyncCommitteeIndices(state, config.getMaxEffectiveBalance()); + } + + protected IntList getNextSyncCommitteeIndices( + final BeaconState state, final UInt64 maxEffectiveBalance) { final UInt64 epoch = getCurrentEpoch(state).plus(1); final IntList activeValidatorIndices = getActiveValidatorIndices(state, epoch); final int activeValidatorCount = activeValidatorIndices.size(); @@ -107,7 +112,6 @@ public IntList getNextSyncCommitteeIndices(final BeaconState state) { int i = 0; final SszList validators = state.getValidators(); final IntList syncCommitteeIndices = new IntArrayList(); - final UInt64 maxEffectiveBalance = config.getMaxEffectiveBalance(); final int syncCommitteeSize = altairConfig.getSyncCommitteeSize(); final Sha256 sha256 = getSha256Instance(); 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 7b77b070ff8..49bf6eca7ea 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 @@ -15,6 +15,7 @@ import static com.google.common.base.Preconditions.checkArgument; +import it.unimi.dsi.fastutil.ints.IntList; import java.util.List; import tech.pegasys.teku.infrastructure.unsigned.UInt64; import tech.pegasys.teku.spec.config.SpecConfig; @@ -26,7 +27,6 @@ import tech.pegasys.teku.spec.datastructures.state.versions.electra.PendingPartialWithdrawal; import tech.pegasys.teku.spec.logic.common.helpers.BeaconStateAccessors; 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 { @@ -36,7 +36,7 @@ public class BeaconStateAccessorsElectra extends BeaconStateAccessorsDeneb { public BeaconStateAccessorsElectra( final SpecConfig config, final PredicatesElectra predicatesElectra, - final MiscHelpersDeneb miscHelpers) { + final MiscHelpersElectra miscHelpers) { super(SpecConfigDeneb.required(config), predicatesElectra, miscHelpers); configElectra = config.toVersionElectra().orElseThrow(); this.predicatesElectra = predicatesElectra; @@ -57,7 +57,6 @@ public UInt64 getActivationExitChurnLimit(final BeaconStateElectra state) { * * @param state The state to get the effective balance from * @param validatorIndex the index of the validator - * @return */ public UInt64 getActiveBalance(final BeaconState state, final int validatorIndex) { final Validator validator = state.getValidators().get(validatorIndex); @@ -101,7 +100,6 @@ public UInt64 getBalanceChurnLimit(final BeaconStateElectra state) { * get_consolidation_churn_limit * * @param state state to read churn limits from - * @return */ public UInt64 getConsolidationChurnLimit(final BeaconStateElectra state) { return getBalanceChurnLimit(state).minusMinZero(getActivationExitChurnLimit(state)); @@ -127,4 +125,9 @@ public static BeaconStateAccessorsElectra required( public UInt64 getValidatorMaxEffectiveBalance(final Validator validator) { return predicatesElectra.getValidatorMaxEffectiveBalance(validator); } + + @Override + public IntList getNextSyncCommitteeIndices(final BeaconState state) { + return getNextSyncCommitteeIndices(state, configElectra.getMaxEffectiveBalanceElectra()); + } } diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/helpers/MiscHelpersElectra.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/helpers/MiscHelpersElectra.java index 96c98bcc10a..3d2f1a0ccd7 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/helpers/MiscHelpersElectra.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/helpers/MiscHelpersElectra.java @@ -13,9 +13,11 @@ package tech.pegasys.teku.spec.logic.versions.electra.helpers; +import it.unimi.dsi.fastutil.ints.IntList; import java.util.Optional; -import tech.pegasys.teku.spec.config.SpecConfig; +import org.apache.tuweni.bytes.Bytes32; import tech.pegasys.teku.spec.config.SpecConfigDeneb; +import tech.pegasys.teku.spec.config.SpecConfigElectra; import tech.pegasys.teku.spec.datastructures.state.beaconstate.BeaconState; import tech.pegasys.teku.spec.datastructures.state.beaconstate.versions.electra.BeaconStateElectra; import tech.pegasys.teku.spec.logic.common.helpers.MiscHelpers; @@ -27,7 +29,7 @@ public class MiscHelpersElectra extends MiscHelpersDeneb { public MiscHelpersElectra( - final SpecConfig specConfig, + final SpecConfigElectra specConfig, final Predicates predicates, final SchemaDefinitions schemaDefinitions) { super( @@ -46,6 +48,16 @@ public static MiscHelpersElectra required(final MiscHelpers miscHelpers) { + miscHelpers.getClass().getSimpleName())); } + @Override + public int computeProposerIndex( + final BeaconState state, final IntList indices, final Bytes32 seed) { + return computeProposerIndex( + state, + indices, + seed, + SpecConfigElectra.required(specConfig).getMaxEffectiveBalanceElectra()); + } + @Override public Optional toVersionElectra() { return Optional.of(this); diff --git a/ethereum/spec/src/test/java/tech/pegasys/teku/spec/logic/versions/electra/forktransition/ElectraStateUpgradeTest.java b/ethereum/spec/src/test/java/tech/pegasys/teku/spec/logic/versions/electra/forktransition/ElectraStateUpgradeTest.java index 8900228df8f..5161a292afa 100644 --- a/ethereum/spec/src/test/java/tech/pegasys/teku/spec/logic/versions/electra/forktransition/ElectraStateUpgradeTest.java +++ b/ethereum/spec/src/test/java/tech/pegasys/teku/spec/logic/versions/electra/forktransition/ElectraStateUpgradeTest.java @@ -43,7 +43,9 @@ class ElectraStateUpgradeTest { SchemaDefinitionsElectra.required(spec.getGenesisSchemaDefinitions()); private final MiscHelpersElectra miscHelpersElectra = new MiscHelpersElectra( - spec.getGenesisSpecConfig(), predicatesElectra, spec.getGenesisSchemaDefinitions()); + spec.getGenesisSpecConfig().toVersionElectra().orElseThrow(), + predicatesElectra, + spec.getGenesisSchemaDefinitions()); final BeaconStateAccessorsElectra stateAccessorsElectra = new BeaconStateAccessorsElectra( spec.getGenesisSpecConfig(), predicatesElectra, miscHelpersElectra); diff --git a/ethereum/spec/src/test/java/tech/pegasys/teku/spec/logic/versions/electra/helpers/BeaconStateAccessorsElectraTest.java b/ethereum/spec/src/test/java/tech/pegasys/teku/spec/logic/versions/electra/helpers/BeaconStateAccessorsElectraTest.java new file mode 100644 index 00000000000..3a6eb21c073 --- /dev/null +++ b/ethereum/spec/src/test/java/tech/pegasys/teku/spec/logic/versions/electra/helpers/BeaconStateAccessorsElectraTest.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 org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; + +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.config.SpecConfigElectra; +import tech.pegasys.teku.spec.datastructures.state.BeaconStateTestBuilder; +import tech.pegasys.teku.spec.datastructures.state.beaconstate.BeaconState; +import tech.pegasys.teku.spec.schemas.SchemaDefinitionsElectra; +import tech.pegasys.teku.spec.util.DataStructureUtil; + +class BeaconStateAccessorsElectraTest { + + private final Spec spec = TestSpecFactory.createMinimalElectra(); + private final DataStructureUtil dataStructureUtil = new DataStructureUtil(spec); + private final SpecConfigElectra specConfig = + spy(SpecConfigElectra.required(spec.atSlot(UInt64.ZERO).getConfig())); + private final PredicatesElectra predicatesElectra = new PredicatesElectra(specConfig); + private final SchemaDefinitionsElectra schemaDefinitionsElectra = + new SchemaDefinitionsElectra(SpecConfigElectra.required(specConfig)); + private final MiscHelpersElectra miscHelpersElectra = + new MiscHelpersElectra( + SpecConfigElectra.required(specConfig), predicatesElectra, schemaDefinitionsElectra); + + @Test + public void getNextSyncCommitteeIndicesShouldUseMaxEffectiveBalanceElectra() { + final BeaconStateAccessorsElectra beaconStateAccessorsElectra = + new BeaconStateAccessorsElectra(specConfig, predicatesElectra, miscHelpersElectra); + + beaconStateAccessorsElectra.getNextSyncCommitteeIndices(createBeaconState()); + + verify(specConfig).getMaxEffectiveBalanceElectra(); + verify(specConfig, never()).getMaxEffectiveBalance(); + } + + private BeaconState createBeaconState() { + return new BeaconStateTestBuilder(dataStructureUtil) + .forkVersion(specConfig.getGenesisForkVersion()) + .activeValidator(UInt64.THIRTY_TWO_ETH) + .activeValidator(UInt64.THIRTY_TWO_ETH) + .activeValidator(UInt64.THIRTY_TWO_ETH) + .build(); + } +} diff --git a/ethereum/spec/src/test/java/tech/pegasys/teku/spec/logic/versions/electra/helpers/MiscHelpersElectraTest.java b/ethereum/spec/src/test/java/tech/pegasys/teku/spec/logic/versions/electra/helpers/MiscHelpersElectraTest.java index 007c0f45727..5549a68965e 100644 --- a/ethereum/spec/src/test/java/tech/pegasys/teku/spec/logic/versions/electra/helpers/MiscHelpersElectraTest.java +++ b/ethereum/spec/src/test/java/tech/pegasys/teku/spec/logic/versions/electra/helpers/MiscHelpersElectraTest.java @@ -14,12 +14,18 @@ package tech.pegasys.teku.spec.logic.versions.electra.helpers; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import it.unimi.dsi.fastutil.ints.IntList; +import org.apache.tuweni.bytes.Bytes32; 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.config.SpecConfigElectra; +import tech.pegasys.teku.spec.datastructures.state.BeaconStateTestBuilder; import tech.pegasys.teku.spec.datastructures.state.beaconstate.BeaconState; import tech.pegasys.teku.spec.datastructures.state.beaconstate.versions.electra.BeaconStateElectra; import tech.pegasys.teku.spec.datastructures.state.beaconstate.versions.electra.MutableBeaconStateElectra; @@ -73,4 +79,25 @@ public void isFormerDepositMechanismDisabled_returnsFalseIfNotDisabled() { assertThat(miscHelpersElectra.isFormerDepositMechanismDisabled(state)).isFalse(); } + + @Test + public void computeProposerIndexShouldUseMaxEffectiveBalanceElectra() { + final SpecConfigElectra specConfigElectra = + spy(SpecConfigElectra.required(spec.getGenesisSpecConfig())); + final MiscHelpersElectra miscHelpersElectra = + new MiscHelpersElectra(specConfigElectra, predicates, schemaDefinitionsElectra); + + final BeaconState state = + new BeaconStateTestBuilder(dataStructureUtil) + .forkVersion(spec.getGenesisSpecConfig().getGenesisForkVersion()) + .activeValidator(UInt64.THIRTY_TWO_ETH) + .activeValidator(UInt64.THIRTY_TWO_ETH) + .activeValidator(UInt64.THIRTY_TWO_ETH) + .build(); + + miscHelpersElectra.computeProposerIndex(state, IntList.of(0, 1, 2), Bytes32.ZERO); + + verify(specConfigElectra).getMaxEffectiveBalanceElectra(); + verify(specConfigElectra, never()).getMaxEffectiveBalance(); + } }