Skip to content

Commit

Permalink
chore: give reasoning on how UintNum64 is good for state.slashings
Browse files Browse the repository at this point in the history
  • Loading branch information
twoeths committed Nov 24, 2023
1 parent 0df2f64 commit ac08e7d
Show file tree
Hide file tree
Showing 2 changed files with 13 additions and 3 deletions.
9 changes: 6 additions & 3 deletions packages/state-transition/src/block/slashValidator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,12 @@ export function slashValidator(
validator.withdrawableEpoch = Math.max(validator.withdrawableEpoch, epoch + EPOCHS_PER_SLASHINGS_VECTOR);

const {effectiveBalance} = validator;
// state.slashings is a number because it's reset per epoch in processSlashingsReset()
// for each epoch, there are 8704 max validators to slash so it's safe to use Number
// also we don't need to compute the total slashings from state.slashings, it's handled by totalSlashingsByIncrement in EpochCache

// state.slashings is initially a Gwei (BigInt) vector, however since Nov 2023 it's converted to UintNum64 (number) vector in the state transition because:
// - state.slashings[nextEpoch % EPOCHS_PER_SLASHINGS_VECTOR] is reset per epoch in processSlashingsReset()
// - max slashed validators per epoch is SLOTS_PER_EPOCH * MAX_ATTESTER_SLASHINGS * MAX_VALIDATORS_PER_COMMITTEE which is 32 * 2 * 2048 = 131072 on mainnet

This comment has been minimized.

Copy link
@dapplion

dapplion Nov 28, 2023

Contributor

Can you hardcode this invariant somewhere? Other network may use different parameters. For example in the start of epoch processing check this condition

if (
  SLOTS_PER_EPOCH * MAX_ATTESTER_SLASHINGS * MAX_VALIDATORS_PER_COMMITTEE
  > Math.floor(Number.MAX_SAFE_INTEGER / MAX_EFFECTIVE_BALANCE)
) {
  throw Error(`Lodestar does not support (... explanation)`)
}
// - with that and 32_000_000_000 MAX_EFFECTIVE_BALANCE, it still fits in a number given that Math.floor(Number.MAX_SAFE_INTEGER / 32_000_000_000) = 281474
// - we don't need to compute the total slashings from state.slashings, it's handled by totalSlashingsByIncrement in EpochCache
const slashingIndex = epoch % EPOCHS_PER_SLASHINGS_VECTOR;
state.slashings.set(slashingIndex, (state.slashings.get(slashingIndex) ?? 0) + effectiveBalance);
epochCtx.totalSlashingsByIncrement += effectiveBalanceIncrements[slashedIndex];
Expand Down
7 changes: 7 additions & 0 deletions packages/types/src/phase0/sszTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,13 @@ export const Validator = ValidatorNodeStruct;
export const Validators = new ListCompositeType(ValidatorNodeStruct, VALIDATOR_REGISTRY_LIMIT);
export const Balances = new ListBasicType(UintNum64, VALIDATOR_REGISTRY_LIMIT);
export const RandaoMixes = new VectorCompositeType(Bytes32, EPOCHS_PER_HISTORICAL_VECTOR);
/**
* This is initially a Gwei (BigInt) vector, however since Nov 2023 it's converted to UintNum64 (number) vector in the state transition because:
* - state.slashings[nextEpoch % EPOCHS_PER_SLASHINGS_VECTOR] is reset per epoch in processSlashingsReset()
* - max slashed validators per epoch is SLOTS_PER_EPOCH * MAX_ATTESTER_SLASHINGS * MAX_VALIDATORS_PER_COMMITTEE which is 32 * 2 * 2048 = 131072 on mainnet
* - with that and 32_000_000_000 MAX_EFFECTIVE_BALANCE, it still fits in a number given that Math.floor(Number.MAX_SAFE_INTEGER / 32_000_000_000) = 281474
* - we don't need to compute the total slashings from state.slashings, it's handled by totalSlashingsByIncrement in EpochCache
*/
export const Slashings = new VectorBasicType(UintNum64, EPOCHS_PER_SLASHINGS_VECTOR);
export const JustificationBits = new BitVectorType(JUSTIFICATION_BITS_LENGTH);

Expand Down

0 comments on commit ac08e7d

Please sign in to comment.