Skip to content

Commit

Permalink
remove clutter
Browse files Browse the repository at this point in the history
  • Loading branch information
potuz committed Aug 25, 2023
1 parent 2a6400a commit c852a4e
Showing 1 changed file with 1 addition and 286 deletions.
287 changes: 1 addition & 286 deletions specs/_features/epbs/beacon-chain.md
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ class BeaconBlockBody(Container):
# Removed execution_payload [ Removed in ePBS]
signed_execution_payload_header: SignedExecutionPayloadHeader # [New in ePBS]
bls_to_execution_changes: List[SignedBLSToExecutionChange, MAX_BLS_TO_EXECUTION_CHANGES]
blob_kzg_commitments: List[KZGCommitment, MAX_BLOB_COMMITMENTS_PER_BLOCK] # [New in Deneb:EIP4844]
blob_kzg_commitments: List[KZGCommitment, MAX_BLOB_COMMITMENTS_PER_BLOCK]
```

#### `ExecutionPayload`
Expand Down Expand Up @@ -280,291 +280,6 @@ class BeaconState(Container):
# PBS
current_signed_execution_payload_header: SignedExecutionPayloadHeader # [New in ePBS]
```
## Helper functions

### Predicates

#### New `is_active_builder`

```python
def is_active_builder(builder: Builder, epoch: Epoch) -> bool:
return epoch < builder.exit_epoch
```

#### New `is_slashable_builder`

```python
def is_slashable_builder(builder: Builder, epoch: Epoch) -> bool:
"""
Check if ``builder`` is slashable.
"""
return (not validator.slashed) and (epoch < builder.withdrawable_epoch)
```

#### New `is_active_validator_at_index`

```python
def is_active_validator_at_index(state: BeaconState, index: ValidatorIndex, epoch: Epoch) -> bool:
if index < len(state.validators):
return is_active_validator(state.validators[index], epoch)
return is_active_builder(state.builders[index-len(state.validators)], epoch)
```

#### Modified `is_valid_indexed_attestation`

```python
def is_valid_indexed_attestation(state: BeaconState, indexed_attestation: IndexedAttestation) -> bool:
"""
Check if ``indexed_attestation`` is not empty, has sorted and unique indices and has a valid aggregate signature.
"""
# Verify indices are sorted and unique
indices = indexed_attestation.attesting_indices
if len(indices) == 0 or not indices == sorted(set(indices)):
return False
# Verify aggregate signature
pubkeys = [state.validators[i].pubkey if i < len(state.validators) else state.builders[i - len(state.validators)].pubkey for i in indices]
domain = get_domain(state, DOMAIN_BEACON_ATTESTER, indexed_attestation.data.target.epoch)
signing_root = compute_signing_root(indexed_attestation.data, domain)
return bls.FastAggregateVerify(pubkeys, signing_root, indexed_attestation.signature)
```


### Misc

#### Modified `compute_proposer_index`
*Note*: `compute_proposer_index` is modified to account for builders being validators

TODO: actually do the sampling proportional to effective balance

### Beacon state accessors

#### Modified `get_active_validator_indices`

```python
def get_active_validator_indices(state: BeaconState, epoch: Epoch) -> Sequence[ValidatorIndex]:
"""
Return the sequence of active validator indices at ``epoch``.
"""
builder_indices = [ValidatorIndex(len(state.validators) + i) for i,b in enumerate(state.builders) if is_active_builder(b,epoch)]
return [ValidatorIndex(i) for i, v in enumerate(state.validators) if is_active_validator(v, epoch)] + builder_indices
```

#### New `get_effective_balance`

```python
def get_effective_balance(state: BeaconState, index: ValidatorIndex) -> Gwei:
"""
Return the effective balance for the validator or the builder indexed by ``index``
"""
if index < len(state.validators):
return state.validators[index].effective_balance
return state.builders[index-len(state.validators)].effective_balance
```

#### Modified `get_total_balance`

```python
def get_total_balance(state: BeaconState, indices: Set[ValidatorIndex]) -> Gwei:
"""
Return the combined effective balance of the ``indices``.
``EFFECTIVE_BALANCE_INCREMENT`` Gwei minimum to avoid divisions by zero.
Math safe up to ~10B ETH, after which this overflows uint64.
"""
return Gwei(max(EFFECTIVE_BALANCE_INCREMENT, sum([get_effective_balance(state, index) for index in indices])))
```

#### Modified `get_next_sync_committee_indices`

*TODO*: make the shuffling actually weighted by the builder's effective balance

```python
def get_next_sync_committee_indices(state: BeaconState) -> Sequence[ValidatorIndex]:
"""
Return the sync committee indices, with possible duplicates, for the next sync committee.
"""
epoch = Epoch(get_current_epoch(state) + 1)

MAX_RANDOM_BYTE = 2**8 - 1
active_validator_indices = get_active_validator_indices(state, epoch)
active_validator_count = uint64(len(active_validator_indices))
seed = get_seed(state, epoch, DOMAIN_SYNC_COMMITTEE)
i = 0
sync_committee_indices: List[ValidatorIndex] = []
while len(sync_committee_indices) < SYNC_COMMITTEE_SIZE:
shuffled_index = compute_shuffled_index(uint64(i % active_validator_count), active_validator_count, seed)
candidate_index = active_validator_indices[shuffled_index]
random_byte = hash(seed + uint_to_bytes(uint64(i // 32)))[i % 32]
if candidate_index >= len(state.validators):
sync_commitee_indices.append(candidate_index)
else:
effective_balance = state.validators[candidate_index].effective_balance
if effective_balance * MAX_RANDOM_BYTE >= MAX_EFFECTIVE_BALANCE * random_byte:
sync_committee_indices.append(candidate_index)
i += 1
return sync_committee_indices
```

#### Modified `get_next_sync_committee`

```python
def get_next_sync_committee(state: BeaconState) -> SyncCommittee:
"""
Return the next sync committee, with possible pubkey duplicates.
"""
indices = get_next_sync_committee_indices(state)
pubkeys = [state.validators[index].pubkey if index < len(state.validators) else state.builders[index-len(state.validators)] for index in indices]
aggregate_pubkey = eth_aggregate_pubkeys(pubkeys)
return SyncCommittee(pubkeys=pubkeys, aggregate_pubkey=aggregate_pubkey)
```

#### Modified `get_unslashed_participating_indices`

```python
def get_unslashed_participating_indices(state: BeaconState, flag_index: int, epoch: Epoch) -> Set[ValidatorIndex]:
"""
Return the set of validator indices that are both active and unslashed for the given ``flag_index`` and ``epoch``.
"""
assert epoch in (get_previous_epoch(state), get_current_epoch(state))
if epoch == get_current_epoch(state):
epoch_participation = state.current_epoch_participation
epoch_builder_participation = state.current_epoch_builder_participation
else:
epoch_participation = state.previous_epoch_participation
epoch_builder_participation = state.previous_epoch_builder_participation
active_validator_indices = get_active_validator_indices(state, epoch)
participating_indices = [i for i in active_validator_indices if (has_flag(epoch_participation[i], flag_index) if i < len(state.validators) else has_flag(epoch_builder_participation[i-len(state.validators)], flag_index))]
return set(filter(lambda index: not state.validators[index].slashed if index < len(state.validators) else not state.builders[index-len(state.validators)].slashed, participating_indices))
```

#### Modified `get_flag_index_deltas`

```python
def get_flag_index_deltas(state: BeaconState, flag_index: int) -> Tuple[Sequence[Gwei], Sequence[Gwei]]:
"""
Return the deltas for a given ``flag_index`` by scanning through the participation flags.
"""
rewards = [Gwei(0)] * (len(state.validators) + len(state.builders))
penalties = [Gwei(0)] * (len(state.validators) + len(state.builders)
previous_epoch = get_previous_epoch(state)
unslashed_participating_indices = get_unslashed_participating_indices(state, flag_index, previous_epoch)
weight = PARTICIPATION_FLAG_WEIGHTS[flag_index]
unslashed_participating_balance = get_total_balance(state, unslashed_participating_indices)
unslashed_participating_increments = unslashed_participating_balance // EFFECTIVE_BALANCE_INCREMENT
active_increments = get_total_active_balance(state) // EFFECTIVE_BALANCE_INCREMENT
for index in get_eligible_validator_indices(state):
base_reward = get_base_reward(state, index)
if index in unslashed_participating_indices:
if not is_in_inactivity_leak(state):
reward_numerator = base_reward * weight * unslashed_participating_increments
rewards[index] += Gwei(reward_numerator // (active_increments * WEIGHT_DENOMINATOR))
elif flag_index != TIMELY_HEAD_FLAG_INDEX:
penalties[index] += Gwei(base_reward * weight // WEIGHT_DENOMINATOR)
return rewards, penalties
```


### Beacon state mutators

#### Modified `increase_balance`

```python
def increase_balance(state: BeaconState, index: ValidatorIndex, delta: Gwei) -> None:
"""
Increase the validator balance at index ``index`` by ``delta``.
"""
if index < len(state.validators):
state.balances[index] += delta
return
state.builder_balances[index-len(state.validators)] += delta
```

#### Modified `decrease_balance`

```python
def decrease_balance(state: BeaconState, index: ValidatorIndex, delta: Gwei) -> None:
"""
Decrease the validator balance at index ``index`` by ``delta``, with underflow protection.
"""
if index < len(state.validators)
state.balances[index] = 0 if delta > state.balances[index] else state.balances[index] - delta
return
index -= len(state.validators)
state.builder_balances[index] = 0 if delta > state.builder_balances[index] else state.builder_balances[index] - delta
```

#### Modified `initiate_validator_exit`

```python
def initiate_validator_exit(state: BeaconState, index: ValidatorIndex) -> None:
"""
Initiate the exit of the validator with index ``index``.
"""
# Notice that the local variable ``validator`` may refer to a builder. Also that it continues defined outside
# its declaration scope. This is valid Python.
if index < len(state.validators):
validator = state.validators[index]
else:
validator = state.builders[index - len(state.validators)]

# Return if validator already initiated exit
if validator.exit_epoch != FAR_FUTURE_EPOCH:
return

# Compute exit queue epoch
exit_epochs = [v.exit_epoch for v in state.validators + state.builders if v.exit_epoch != FAR_FUTURE_EPOCH]
exit_queue_epoch = max(exit_epochs + [compute_activation_exit_epoch(get_current_epoch(state))])
exit_queue_churn = len([v for v in state.validators + state.builders if v.exit_epoch == exit_queue_epoch])
if exit_queue_churn >= get_validator_churn_limit(state):
exit_queue_epoch += Epoch(1)

# Set validator exit epoch and withdrawable epoch
validator.exit_epoch = exit_queue_epoch
validator.withdrawable_epoch = Epoch(validator.exit_epoch + MIN_VALIDATOR_WITHDRAWABILITY_DELAY) # TODO: Do we want to differentiate builders here?
```

#### New `proposer_slashing_amount`

```python
def proposer_slashing_amount(slashed_index: ValidatorIndex, effective_balance: Gwei):
return min(MAX_EFFECTIVE_BALANCE, effective_balance) // MIN_SLASHING_PENALTY_QUOTIENT
```

#### Modified `slash_validator`

```python
def slash_validator(state: BeaconState,
slashed_index: ValidatorIndex,
proposer_slashing: bool,
whistleblower_index: ValidatorIndex=None) -> None:
"""
Slash the validator with index ``slashed_index``.
"""
epoch = get_current_epoch(state)
initiate_validator_exit(state, slashed_index)
# Notice that the local variable ``validator`` may refer to a builder. Also that it continues defined outside
# its declaration scope. This is valid Python.
if index < len(state.validators):
validator = state.validators[slashed_index]
else:
validator = state.builders[slashed_index - len(state.validators)]
validator.slashed = True
validator.withdrawable_epoch = max(validator.withdrawable_epoch, Epoch(epoch + EPOCHS_PER_SLASHINGS_VECTOR))
state.slashings[epoch % EPOCHS_PER_SLASHINGS_VECTOR] += validator.effective_balance
if proposer_slashing:
decrease_balance(state, slashed_index, proposer_slashing_amount(slashed_index, validator.effective_balance))
else:
decrease_balance(state, slashed_index, validator.effective_balance // MIN_SLASHING_PENALTY_QUOTIENT)

# Apply proposer and whistleblower rewards
proposer_index = get_beacon_proposer_index(state)
if whistleblower_index is None:
whistleblower_index = proposer_index
whistleblower_reward = Gwei(max(MAX_EFFECTIVE_BALANCE, validator.effective_balance) // WHISTLEBLOWER_REWARD_QUOTIENT)
proposer_reward = Gwei(whistleblower_reward // PROPOSER_REWARD_QUOTIENT)
increase_balance(state, proposer_index, proposer_reward)
increase_balance(state, whistleblower_index, Gwei(whistleblower_reward - proposer_reward))
```


## Beacon chain state transition function

Expand Down

0 comments on commit c852a4e

Please sign in to comment.