Merge pull request #2176 from ethereum/accounting-reform
Accounting reform [isolated]
This commit is contained in:
commit
6f2c69e79f
|
@ -1,4 +1,4 @@
|
|||
# Ethereum 2.0 Light Client Support
|
||||
# Ethereum 2.0 HF1
|
||||
|
||||
## Table of contents
|
||||
|
||||
|
@ -7,10 +7,13 @@
|
|||
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
|
||||
|
||||
- [Introduction](#introduction)
|
||||
- [Custom types](#custom-types)
|
||||
- [Constants](#constants)
|
||||
- [Configuration](#configuration)
|
||||
- [Constants](#constants-1)
|
||||
- [Validator action flags](#validator-action-flags)
|
||||
- [Participation rewards](#participation-rewards)
|
||||
- [Misc](#misc)
|
||||
- [Configuration](#configuration)
|
||||
- [Misc](#misc-1)
|
||||
- [Time parameters](#time-parameters)
|
||||
- [Domain types](#domain-types)
|
||||
- [Containers](#containers)
|
||||
|
@ -22,36 +25,78 @@
|
|||
- [Helper functions](#helper-functions)
|
||||
- [`Predicates`](#predicates)
|
||||
- [`eth2_fast_aggregate_verify`](#eth2_fast_aggregate_verify)
|
||||
- [Misc](#misc-2)
|
||||
- [`flags_and_numerators`](#flags_and_numerators)
|
||||
- [Beacon state accessors](#beacon-state-accessors)
|
||||
- [`get_sync_committee_indices`](#get_sync_committee_indices)
|
||||
- [`get_sync_committee`](#get_sync_committee)
|
||||
- [`get_base_reward`](#get_base_reward)
|
||||
- [`get_unslashed_participating_indices`](#get_unslashed_participating_indices)
|
||||
- [`get_flag_deltas`](#get_flag_deltas)
|
||||
- [New `get_inactivity_penalty_deltas`](#new-get_inactivity_penalty_deltas)
|
||||
- [Block processing](#block-processing)
|
||||
- [New `process_attestation`](#new-process_attestation)
|
||||
- [New `process_deposit`](#new-process_deposit)
|
||||
- [Sync committee processing](#sync-committee-processing)
|
||||
- [Epoch processing](#epoch-processing)
|
||||
- [Components of attestation deltas](#components-of-attestation-deltas)
|
||||
- [New `process_justification_and_finalization`](#new-process_justification_and_finalization)
|
||||
- [New `process_rewards_and_penalties`](#new-process_rewards_and_penalties)
|
||||
- [Sync committee updates](#sync-committee-updates)
|
||||
- [Participation flags updates](#participation-flags-updates)
|
||||
|
||||
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
||||
<!-- /TOC -->
|
||||
|
||||
## Introduction
|
||||
|
||||
This is a standalone beacon chain patch adding light client support via sync committees.
|
||||
This is a patch implementing the first hard fork to the beacon chain, tentatively named HF1 pending a permanent name. It has three main features:
|
||||
|
||||
* Light client support via sync committees
|
||||
* Incentive accounting reforms, reducing spec complexity
|
||||
and [TODO] reducing the cost of processing chains that have very little or zero participation for a long span of epochs
|
||||
* Fork choice rule changes to address weaknesses recently discovered in the existing fork choice
|
||||
|
||||
## Custom types
|
||||
|
||||
| Name | SSZ equivalent | Description |
|
||||
| - | - | - |
|
||||
| `ValidatorFlag` | `uint8` | Bitflags to track validator actions with |
|
||||
|
||||
## Constants
|
||||
|
||||
### Validator action flags
|
||||
|
||||
This is formatted as an enum, with values `2**i` that can be combined as bit-flags.
|
||||
The `0` value is reserved as default. Remaining bits in `ValidatorFlag` may be used in future hardforks.
|
||||
|
||||
**Note**: Unlike Phase0, a `TIMELY_TARGET_FLAG` does not necessarily imply a `TIMELY_SOURCE_FLAG`
|
||||
due to the varying slot delay requirements of each.
|
||||
|
||||
| Name | Value |
|
||||
| - | - |
|
||||
| `BASE_REWARDS_PER_EPOCH` | `uint64(5)` |
|
||||
| - | - |
|
||||
| `TIMELY_HEAD_FLAG` | `ValidatorFlag(2**0)` (= 1) |
|
||||
| `TIMELY_SOURCE_FLAG` | `ValidatorFlag(2**1)` (= 2) |
|
||||
| `TIMELY_TARGET_FLAG` | `ValidatorFlag(2**2)` (= 4) |
|
||||
|
||||
## Configuration
|
||||
### Participation rewards
|
||||
|
||||
### Constants
|
||||
| Name | Value |
|
||||
| - | - |
|
||||
| `TIMELY_HEAD_NUMERATOR` | `12` |
|
||||
| `TIMELY_SOURCE_NUMERATOR` | `12` |
|
||||
| `TIMELY_TARGET_NUMERATOR` | `32` |
|
||||
| `REWARD_DENOMINATOR` | `64` |
|
||||
|
||||
The reward fractions add up to 7/8, leaving the remaining 1/8 for proposer rewards and other future micro-rewards.
|
||||
|
||||
### Misc
|
||||
|
||||
| Name | Value |
|
||||
| - | - |
|
||||
| `G2_POINT_AT_INFINITY` | `BLSSignature(b'\xc0' + b'\x00' * 95)` |
|
||||
|
||||
## Configuration
|
||||
|
||||
### Misc
|
||||
|
||||
| Name | Value |
|
||||
|
@ -90,8 +135,37 @@ class BeaconBlockBody(phase0.BeaconBlockBody):
|
|||
#### `BeaconState`
|
||||
|
||||
```python
|
||||
class BeaconState(phase0.BeaconState):
|
||||
# Sync committees
|
||||
class BeaconState(Container):
|
||||
# Versioning
|
||||
genesis_time: uint64
|
||||
genesis_validators_root: Root
|
||||
slot: Slot
|
||||
fork: Fork
|
||||
# History
|
||||
latest_block_header: BeaconBlockHeader
|
||||
block_roots: Vector[Root, SLOTS_PER_HISTORICAL_ROOT]
|
||||
state_roots: Vector[Root, SLOTS_PER_HISTORICAL_ROOT]
|
||||
historical_roots: List[Root, HISTORICAL_ROOTS_LIMIT]
|
||||
# Eth1
|
||||
eth1_data: Eth1Data
|
||||
eth1_data_votes: List[Eth1Data, EPOCHS_PER_ETH1_VOTING_PERIOD * SLOTS_PER_EPOCH]
|
||||
eth1_deposit_index: uint64
|
||||
# Registry
|
||||
validators: List[Validator, VALIDATOR_REGISTRY_LIMIT]
|
||||
balances: List[Gwei, VALIDATOR_REGISTRY_LIMIT]
|
||||
# Randomness
|
||||
randao_mixes: Vector[Bytes32, EPOCHS_PER_HISTORICAL_VECTOR]
|
||||
# Slashings
|
||||
slashings: Vector[Gwei, EPOCHS_PER_SLASHINGS_VECTOR] # Per-epoch sums of slashed effective balances
|
||||
# Participation
|
||||
previous_epoch_participation: List[ValidatorFlag, VALIDATOR_REGISTRY_LIMIT]
|
||||
current_epoch_participation: List[ValidatorFlag, VALIDATOR_REGISTRY_LIMIT]
|
||||
# Finality
|
||||
justification_bits: Bitvector[JUSTIFICATION_BITS_LENGTH] # Bit set for every recent justified epoch
|
||||
previous_justified_checkpoint: Checkpoint
|
||||
current_justified_checkpoint: Checkpoint
|
||||
finalized_checkpoint: Checkpoint
|
||||
# Light client sync committees
|
||||
current_sync_committee: SyncCommittee
|
||||
next_sync_committee: SyncCommittee
|
||||
```
|
||||
|
@ -122,6 +196,29 @@ def eth2_fast_aggregate_verify(pubkeys: Sequence[BLSPubkey], message: Bytes32, s
|
|||
return bls.FastAggregateVerify(pubkeys, message, signature)
|
||||
```
|
||||
|
||||
### Misc
|
||||
|
||||
#### `flags_and_numerators`
|
||||
|
||||
```python
|
||||
def get_flags_and_numerators() -> Sequence[Tuple[ValidatorFlag, int]]:
|
||||
return (
|
||||
(TIMELY_HEAD_FLAG, TIMELY_HEAD_NUMERATOR),
|
||||
(TIMELY_SOURCE_FLAG, TIMELY_SOURCE_NUMERATOR),
|
||||
(TIMELY_TARGET_FLAG, TIMELY_TARGET_NUMERATOR)
|
||||
)
|
||||
```
|
||||
|
||||
```python
|
||||
def add_validator_flags(flags: ValidatorFlag, add: ValidatorFlag) -> ValidatorFlag:
|
||||
return flags | add
|
||||
```
|
||||
|
||||
```python
|
||||
def has_validator_flags(flags: ValidatorFlag, has: ValidatorFlag) -> bool:
|
||||
return flags & has == has
|
||||
```
|
||||
|
||||
### Beacon state accessors
|
||||
|
||||
#### `get_sync_committee_indices`
|
||||
|
@ -166,6 +263,97 @@ def get_sync_committee(state: BeaconState, epoch: Epoch) -> SyncCommittee:
|
|||
return SyncCommittee(pubkeys=pubkeys, pubkey_aggregates=aggregates)
|
||||
```
|
||||
|
||||
#### `get_base_reward`
|
||||
|
||||
*Note*: The function `get_base_reward` is modified with the removal of `BASE_REWARDS_PER_EPOCH`.
|
||||
|
||||
```python
|
||||
def get_base_reward(state: BeaconState, index: ValidatorIndex) -> Gwei:
|
||||
total_balance = get_total_active_balance(state)
|
||||
effective_balance = state.validators[index].effective_balance
|
||||
return Gwei(effective_balance * BASE_REWARD_FACTOR // integer_squareroot(total_balance))
|
||||
```
|
||||
|
||||
#### `get_unslashed_participating_indices`
|
||||
|
||||
```python
|
||||
def get_unslashed_participating_indices(state: BeaconState, flags: ValidatorFlag, epoch: Epoch) -> Set[ValidatorIndex]:
|
||||
"""
|
||||
Retrieve the active validator indices of the given epoch, which are not slashed, and have all of the given flags.
|
||||
"""
|
||||
assert epoch in (get_previous_epoch(state), get_current_epoch(state))
|
||||
if epoch == get_current_epoch(state):
|
||||
epoch_participation = state.current_epoch_participation
|
||||
else:
|
||||
epoch_participation = state.previous_epoch_participation
|
||||
participating_indices = [
|
||||
index for index in get_active_validator_indices(state, epoch)
|
||||
if has_validator_flags(epoch_participation[index], flags)
|
||||
]
|
||||
return set(filter(lambda index: not state.validators[index].slashed, participating_indices))
|
||||
```
|
||||
|
||||
#### `get_flag_deltas`
|
||||
|
||||
```python
|
||||
def get_flag_deltas(state: BeaconState,
|
||||
flag: ValidatorFlag,
|
||||
numerator: uint64) -> Tuple[Sequence[Gwei], Sequence[Gwei]]:
|
||||
"""
|
||||
Compute the rewards and penalties associated with a particular duty, by scanning through the participation
|
||||
flags to determine who participated and who did not and assigning them the appropriate rewards and penalties.
|
||||
"""
|
||||
rewards = [Gwei(0)] * len(state.validators)
|
||||
penalties = [Gwei(0)] * len(state.validators)
|
||||
|
||||
unslashed_participating_indices = get_unslashed_participating_indices(state, flag, get_previous_epoch(state))
|
||||
increment = EFFECTIVE_BALANCE_INCREMENT # Factored out from balances to avoid uint64 overflow
|
||||
unslashed_participating_increments = get_total_balance(state, unslashed_participating_indices) // increment
|
||||
active_increments = get_total_active_balance(state) // increment
|
||||
for index in get_eligible_validator_indices(state):
|
||||
base_reward = get_base_reward(state, index)
|
||||
if index in unslashed_participating_indices:
|
||||
if is_in_inactivity_leak(state):
|
||||
# Optimal participatition is fully rewarded to cancel the inactivity penalty
|
||||
rewards[index] = base_reward * numerator // REWARD_DENOMINATOR
|
||||
else:
|
||||
rewards[index] = (
|
||||
(base_reward * numerator * unslashed_participating_increments)
|
||||
// (active_increments * REWARD_DENOMINATOR)
|
||||
)
|
||||
else:
|
||||
penalties[index] = base_reward * numerator // REWARD_DENOMINATOR
|
||||
return rewards, penalties
|
||||
```
|
||||
|
||||
#### New `get_inactivity_penalty_deltas`
|
||||
|
||||
*Note*: The function `get_inactivity_penalty_deltas` is modified in the selection of matching target indices and the removal of `BASE_REWARDS_PER_EPOCH`.
|
||||
|
||||
```python
|
||||
def get_inactivity_penalty_deltas(state: BeaconState) -> Tuple[Sequence[Gwei], Sequence[Gwei]]:
|
||||
"""
|
||||
Compute the penalties associated with the inactivity leak, by scanning through the participation
|
||||
flags to determine who participated and who did not, applying the leak penalty globally and applying
|
||||
compensatory rewards to participants.
|
||||
"""
|
||||
penalties = [Gwei(0) for _ in range(len(state.validators))]
|
||||
if is_in_inactivity_leak(state):
|
||||
reward_numerator_sum = sum(numerator for (_, numerator) in get_flags_and_numerators())
|
||||
matching_target_attesting_indices = get_unslashed_participating_indices(
|
||||
state, TIMELY_TARGET_FLAG, get_previous_epoch(state)
|
||||
)
|
||||
for index in get_eligible_validator_indices(state):
|
||||
# If validator is performing optimally this cancels all attestation rewards for a neutral balance
|
||||
penalties[index] += Gwei(get_base_reward(state, index) * reward_numerator_sum // REWARD_DENOMINATOR)
|
||||
if index not in matching_target_attesting_indices:
|
||||
effective_balance = state.validators[index].effective_balance
|
||||
penalties[index] += Gwei(effective_balance * get_finality_delay(state) // INACTIVITY_PENALTY_QUOTIENT)
|
||||
|
||||
rewards = [Gwei(0) for _ in range(len(state.validators))]
|
||||
return rewards, penalties
|
||||
```
|
||||
|
||||
### Block processing
|
||||
|
||||
```python
|
||||
|
@ -178,6 +366,105 @@ def process_block(state: BeaconState, block: BeaconBlock) -> None:
|
|||
process_sync_committee(state, block.body)
|
||||
```
|
||||
|
||||
#### New `process_attestation`
|
||||
|
||||
*Note*: The function `process_attestation` is modified to do incentive accounting with epoch participation flags.
|
||||
|
||||
```python
|
||||
def process_attestation(state: BeaconState, attestation: Attestation) -> None:
|
||||
data = attestation.data
|
||||
assert data.target.epoch in (get_previous_epoch(state), get_current_epoch(state))
|
||||
assert data.target.epoch == compute_epoch_at_slot(data.slot)
|
||||
assert data.slot + MIN_ATTESTATION_INCLUSION_DELAY <= state.slot <= data.slot + SLOTS_PER_EPOCH
|
||||
assert data.index < get_committee_count_per_slot(state, data.target.epoch)
|
||||
|
||||
committee = get_beacon_committee(state, data.slot, data.index)
|
||||
assert len(attestation.aggregation_bits) == len(committee)
|
||||
|
||||
if data.target.epoch == get_current_epoch(state):
|
||||
epoch_participation = state.current_epoch_participation
|
||||
justified_checkpoint = state.current_justified_checkpoint
|
||||
else:
|
||||
epoch_participation = state.previous_epoch_participation
|
||||
justified_checkpoint = state.previous_justified_checkpoint
|
||||
|
||||
# Matching roots
|
||||
is_matching_head = data.beacon_block_root == get_block_root_at_slot(state, data.slot)
|
||||
is_matching_source = data.source == justified_checkpoint
|
||||
is_matching_target = data.target.root == get_block_root(state, data.target.epoch)
|
||||
assert is_matching_source
|
||||
|
||||
# Verify signature
|
||||
assert is_valid_indexed_attestation(state, get_indexed_attestation(state, attestation))
|
||||
|
||||
# Participation flags
|
||||
participation_flags = []
|
||||
if is_matching_head and is_matching_target and state.slot <= data.slot + MIN_ATTESTATION_INCLUSION_DELAY:
|
||||
participation_flags.append(TIMELY_HEAD_FLAG)
|
||||
if is_matching_source and state.slot <= data.slot + integer_squareroot(SLOTS_PER_EPOCH):
|
||||
participation_flags.append(TIMELY_SOURCE_FLAG)
|
||||
if is_matching_target and state.slot <= data.slot + SLOTS_PER_EPOCH:
|
||||
participation_flags.append(TIMELY_TARGET_FLAG)
|
||||
|
||||
# Update epoch participation flags
|
||||
proposer_reward_numerator = 0
|
||||
for index in get_attesting_indices(state, data, attestation.aggregation_bits):
|
||||
for flag, numerator in get_flags_and_numerators():
|
||||
if flag in participation_flags and not has_validator_flags(epoch_participation[index], flag):
|
||||
epoch_participation[index] = add_validator_flags(epoch_participation[index], flag)
|
||||
proposer_reward_numerator += get_base_reward(state, index) * numerator
|
||||
|
||||
# Reward proposer
|
||||
proposer_reward = Gwei(proposer_reward_numerator // (REWARD_DENOMINATOR * PROPOSER_REWARD_QUOTIENT))
|
||||
increase_balance(state, get_beacon_proposer_index(state), proposer_reward)
|
||||
```
|
||||
|
||||
|
||||
#### New `process_deposit`
|
||||
|
||||
*Note*: The function `process_deposit` is modified to initialize `previous_epoch_participation` and `current_epoch_participation`.
|
||||
|
||||
```python
|
||||
def process_deposit(state: BeaconState, deposit: Deposit) -> None:
|
||||
# Verify the Merkle branch
|
||||
assert is_valid_merkle_branch(
|
||||
leaf=hash_tree_root(deposit.data),
|
||||
branch=deposit.proof,
|
||||
depth=DEPOSIT_CONTRACT_TREE_DEPTH + 1, # Add 1 for the List length mix-in
|
||||
index=state.eth1_deposit_index,
|
||||
root=state.eth1_data.deposit_root,
|
||||
)
|
||||
|
||||
# Deposits must be processed in order
|
||||
state.eth1_deposit_index += 1
|
||||
|
||||
pubkey = deposit.data.pubkey
|
||||
amount = deposit.data.amount
|
||||
validator_pubkeys = [v.pubkey for v in state.validators]
|
||||
if pubkey not in validator_pubkeys:
|
||||
# Verify the deposit signature (proof of possession) which is not checked by the deposit contract
|
||||
deposit_message = DepositMessage(
|
||||
pubkey=deposit.data.pubkey,
|
||||
withdrawal_credentials=deposit.data.withdrawal_credentials,
|
||||
amount=deposit.data.amount,
|
||||
)
|
||||
domain = compute_domain(DOMAIN_DEPOSIT) # Fork-agnostic domain since deposits are valid across forks
|
||||
signing_root = compute_signing_root(deposit_message, domain)
|
||||
if not bls.Verify(pubkey, signing_root, deposit.data.signature):
|
||||
return
|
||||
|
||||
# Add validator and balance entries
|
||||
state.validators.append(get_validator_from_deposit(state, deposit))
|
||||
state.balances.append(amount)
|
||||
# [Added in hf-1] Initialize empty participation flags for new validator
|
||||
state.previous_epoch_participation.append(ValidatorFlag(0))
|
||||
state.current_epoch_participation.append(ValidatorFlag(0))
|
||||
else:
|
||||
# Increase balance by deposit amount
|
||||
index = ValidatorIndex(validator_pubkeys.index(pubkey))
|
||||
increase_balance(state, index, amount)
|
||||
```
|
||||
|
||||
#### Sync committee processing
|
||||
|
||||
```python
|
||||
|
@ -211,8 +498,8 @@ def process_sync_committee(state: BeaconState, body: BeaconBlockBody) -> None:
|
|||
|
||||
```python
|
||||
def process_epoch(state: BeaconState) -> None:
|
||||
process_justification_and_finalization(state)
|
||||
process_rewards_and_penalties(state)
|
||||
process_justification_and_finalization(state) # [Updated in HF1]
|
||||
process_rewards_and_penalties(state) # [Updated in HF1]
|
||||
process_registry_updates(state)
|
||||
process_slashings(state)
|
||||
process_eth1_data_reset(state)
|
||||
|
@ -220,43 +507,95 @@ def process_epoch(state: BeaconState) -> None:
|
|||
process_slashings_reset(state)
|
||||
process_randao_mixes_reset(state)
|
||||
process_historical_roots_update(state)
|
||||
process_participation_record_updates(state)
|
||||
# Light client patch
|
||||
# [Removed in HF1] -- process_participation_record_updates(state)
|
||||
# [Added in HF1]
|
||||
process_participation_flag_updates(state)
|
||||
process_sync_committee_updates(state)
|
||||
```
|
||||
|
||||
#### Components of attestation deltas
|
||||
#### New `process_justification_and_finalization`
|
||||
|
||||
*Note*: The function `get_inactivity_penalty_deltas` is modified with `BASE_REWARDS_PER_EPOCH` replaced by `BASE_REWARDS_PER_EPOCH - 1`.
|
||||
*Note*: The function `process_justification_and_finalization` is modified with `matching_target_attestations` replaced by `matching_target_indices`.
|
||||
|
||||
```python
|
||||
def get_inactivity_penalty_deltas(state: BeaconState) -> Tuple[Sequence[Gwei], Sequence[Gwei]]:
|
||||
"""
|
||||
Return inactivity reward/penalty deltas for each validator.
|
||||
"""
|
||||
penalties = [Gwei(0) for _ in range(len(state.validators))]
|
||||
if is_in_inactivity_leak(state):
|
||||
matching_target_attestations = get_matching_target_attestations(state, get_previous_epoch(state))
|
||||
matching_target_attesting_indices = get_unslashed_attesting_indices(state, matching_target_attestations)
|
||||
for index in get_eligible_validator_indices(state):
|
||||
# Penalize validator so that optimal attestation performance is rewarded with one base reward per epoch
|
||||
base_reward = get_base_reward(state, index)
|
||||
penalties[index] += Gwei((BASE_REWARDS_PER_EPOCH - 1) * base_reward - get_proposer_reward(state, index))
|
||||
if index not in matching_target_attesting_indices:
|
||||
effective_balance = state.validators[index].effective_balance
|
||||
penalties[index] += Gwei(effective_balance * get_finality_delay(state) // INACTIVITY_PENALTY_QUOTIENT)
|
||||
def process_justification_and_finalization(state: BeaconState) -> None:
|
||||
# Initial FFG checkpoint values have a `0x00` stub for `root`.
|
||||
# Skip FFG updates in the first two epochs to avoid corner cases that might result in modifying this stub.
|
||||
if get_current_epoch(state) <= GENESIS_EPOCH + 1:
|
||||
return
|
||||
previous_epoch = get_previous_epoch(state)
|
||||
current_epoch = get_current_epoch(state)
|
||||
old_previous_justified_checkpoint = state.previous_justified_checkpoint
|
||||
old_current_justified_checkpoint = state.current_justified_checkpoint
|
||||
|
||||
# No rewards associated with inactivity penalties
|
||||
rewards = [Gwei(0) for _ in range(len(state.validators))]
|
||||
return rewards, penalties
|
||||
# Process justifications
|
||||
state.previous_justified_checkpoint = state.current_justified_checkpoint
|
||||
state.justification_bits[1:] = state.justification_bits[:JUSTIFICATION_BITS_LENGTH - 1]
|
||||
state.justification_bits[0] = 0b0
|
||||
matching_target_indices = get_unslashed_participating_indices(state, TIMELY_TARGET_FLAG, previous_epoch)
|
||||
if get_total_balance(state, matching_target_indices) * 3 >= get_total_active_balance(state) * 2:
|
||||
state.current_justified_checkpoint = Checkpoint(epoch=previous_epoch,
|
||||
root=get_block_root(state, previous_epoch))
|
||||
state.justification_bits[1] = 0b1
|
||||
matching_target_indices = get_unslashed_participating_indices(state, TIMELY_TARGET_FLAG, current_epoch)
|
||||
if get_total_balance(state, matching_target_indices) * 3 >= get_total_active_balance(state) * 2:
|
||||
state.current_justified_checkpoint = Checkpoint(epoch=current_epoch,
|
||||
root=get_block_root(state, current_epoch))
|
||||
state.justification_bits[0] = 0b1
|
||||
|
||||
# Process finalizations
|
||||
bits = state.justification_bits
|
||||
# The 2nd/3rd/4th most recent epochs are justified, the 2nd using the 4th as source
|
||||
if all(bits[1:4]) and old_previous_justified_checkpoint.epoch + 3 == current_epoch:
|
||||
state.finalized_checkpoint = old_previous_justified_checkpoint
|
||||
# The 2nd/3rd most recent epochs are justified, the 2nd using the 3rd as source
|
||||
if all(bits[1:3]) and old_previous_justified_checkpoint.epoch + 2 == current_epoch:
|
||||
state.finalized_checkpoint = old_previous_justified_checkpoint
|
||||
# The 1st/2nd/3rd most recent epochs are justified, the 1st using the 3rd as source
|
||||
if all(bits[0:3]) and old_current_justified_checkpoint.epoch + 2 == current_epoch:
|
||||
state.finalized_checkpoint = old_current_justified_checkpoint
|
||||
# The 1st/2nd most recent epochs are justified, the 1st using the 2nd as source
|
||||
if all(bits[0:2]) and old_current_justified_checkpoint.epoch + 1 == current_epoch:
|
||||
state.finalized_checkpoint = old_current_justified_checkpoint
|
||||
```
|
||||
|
||||
#### New `process_rewards_and_penalties`
|
||||
|
||||
*Note*: The function `process_rewards_and_penalties` is modified to use participation flag deltas.
|
||||
|
||||
```python
|
||||
def process_rewards_and_penalties(state: BeaconState) -> None:
|
||||
# No rewards are applied at the end of `GENESIS_EPOCH` because rewards are for work done in the previous epoch
|
||||
if get_current_epoch(state) == GENESIS_EPOCH:
|
||||
return
|
||||
flag_deltas = [get_flag_deltas(state, flag, numerator) for (flag, numerator) in get_flags_and_numerators()]
|
||||
deltas = flag_deltas + [get_inactivity_penalty_deltas(state)]
|
||||
for (rewards, penalties) in deltas:
|
||||
for index in range(len(state.validators)):
|
||||
increase_balance(state, ValidatorIndex(index), rewards[index])
|
||||
decrease_balance(state, ValidatorIndex(index), penalties[index])
|
||||
```
|
||||
|
||||
#### Sync committee updates
|
||||
|
||||
```python
|
||||
def process_sync_committee_updates(state: BeaconState) -> None:
|
||||
"""
|
||||
Call to ``proces_sync_committee_updates`` added to ``process_epoch`` in HF1
|
||||
"""
|
||||
next_epoch = get_current_epoch(state) + Epoch(1)
|
||||
if next_epoch % EPOCHS_PER_SYNC_COMMITTEE_PERIOD == 0:
|
||||
state.current_sync_committee = state.next_sync_committee
|
||||
state.next_sync_committee = get_sync_committee(state, next_epoch + EPOCHS_PER_SYNC_COMMITTEE_PERIOD)
|
||||
```
|
||||
|
||||
#### Participation flags updates
|
||||
|
||||
```python
|
||||
def process_participation_flag_updates(state: BeaconState) -> None:
|
||||
"""
|
||||
Call to ``process_participation_flag_updates`` added to ``process_epoch`` in HF1
|
||||
"""
|
||||
state.previous_epoch_participation = state.current_epoch_participation
|
||||
state.current_epoch_participation = [ValidatorFlag(0) for _ in range(len(state.validators))]
|
||||
```
|
||||
|
|
|
@ -43,6 +43,7 @@ def upgrade_to_lightclient_patch(pre: phase0.BeaconState) -> BeaconState:
|
|||
epoch = get_current_epoch(pre)
|
||||
post = BeaconState(
|
||||
genesis_time=pre.genesis_time,
|
||||
genesis_validators_root=pre.genesis_validators_root,
|
||||
slot=pre.slot,
|
||||
fork=Fork(
|
||||
previous_version=pre.fork.current_version,
|
||||
|
@ -66,10 +67,8 @@ def upgrade_to_lightclient_patch(pre: phase0.BeaconState) -> BeaconState:
|
|||
# Slashings
|
||||
slashings=pre.slashings,
|
||||
# Attestations
|
||||
# previous_epoch_attestations is cleared on upgrade.
|
||||
previous_epoch_attestations=List[PendingAttestation, MAX_ATTESTATIONS * SLOTS_PER_EPOCH](),
|
||||
# empty in pre state, since the upgrade is performed just after an epoch boundary.
|
||||
current_epoch_attestations=List[PendingAttestation, MAX_ATTESTATIONS * SLOTS_PER_EPOCH](),
|
||||
previous_epoch_participation=[ValidatorFlag(0) for _ in range(len(pre.validators))],
|
||||
current_epoch_participation=[ValidatorFlag(0) for _ in range(len(pre.validators))],
|
||||
# Finality
|
||||
justification_bits=pre.justification_bits,
|
||||
previous_justified_checkpoint=pre.previous_justified_checkpoint,
|
||||
|
|
|
@ -390,3 +390,11 @@ def only_full_crosslink(fn):
|
|||
return None
|
||||
return fn(*args, spec=spec, state=state, **kw)
|
||||
return wrapper
|
||||
|
||||
|
||||
def is_post_lightclient_patch(spec):
|
||||
if spec.fork in [PHASE0, PHASE1]:
|
||||
# TODO: PHASE1 fork is temporarily parallel to LIGHTCLIENT_PATCH.
|
||||
# Will make PHASE1 fork inherit LIGHTCLIENT_PATCH later.
|
||||
return False
|
||||
return True
|
||||
|
|
|
@ -2,7 +2,7 @@ from lru import LRU
|
|||
|
||||
from typing import List
|
||||
|
||||
from eth2spec.test.context import expect_assertion_error, PHASE1
|
||||
from eth2spec.test.context import expect_assertion_error, PHASE1, is_post_lightclient_patch
|
||||
from eth2spec.test.helpers.state import state_transition_and_sign_block, next_epoch, next_slot
|
||||
from eth2spec.test.helpers.block import build_empty_block_for_next_slot
|
||||
from eth2spec.test.helpers.shard_transitions import get_shard_transition_of_committee
|
||||
|
@ -30,17 +30,22 @@ def run_attestation_processing(spec, state, attestation, valid=True):
|
|||
yield 'post', None
|
||||
return
|
||||
|
||||
current_epoch_count = len(state.current_epoch_attestations)
|
||||
previous_epoch_count = len(state.previous_epoch_attestations)
|
||||
if not is_post_lightclient_patch(spec):
|
||||
current_epoch_count = len(state.current_epoch_attestations)
|
||||
previous_epoch_count = len(state.previous_epoch_attestations)
|
||||
|
||||
# process attestation
|
||||
spec.process_attestation(state, attestation)
|
||||
|
||||
# Make sure the attestation has been processed
|
||||
if attestation.data.target.epoch == spec.get_current_epoch(state):
|
||||
assert len(state.current_epoch_attestations) == current_epoch_count + 1
|
||||
if not is_post_lightclient_patch(spec):
|
||||
if attestation.data.target.epoch == spec.get_current_epoch(state):
|
||||
assert len(state.current_epoch_attestations) == current_epoch_count + 1
|
||||
else:
|
||||
assert len(state.previous_epoch_attestations) == previous_epoch_count + 1
|
||||
else:
|
||||
assert len(state.previous_epoch_attestations) == previous_epoch_count + 1
|
||||
# After accounting reform, there are cases when processing an attestation does not result in any flag updates
|
||||
pass
|
||||
|
||||
# yield post-state
|
||||
yield 'post', state
|
||||
|
@ -315,7 +320,8 @@ def prepare_state_with_attestations(spec, state, participation_fn=None):
|
|||
next_slot(spec, state)
|
||||
|
||||
assert state.slot == next_epoch_start_slot + spec.MIN_ATTESTATION_INCLUSION_DELAY
|
||||
assert len(state.previous_epoch_attestations) == len(attestations)
|
||||
if not is_post_lightclient_patch(spec):
|
||||
assert len(state.previous_epoch_attestations) == len(attestations)
|
||||
|
||||
return attestations
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from eth2spec.test.context import LIGHTCLIENT_PATCH
|
||||
from eth2spec.test.context import is_post_lightclient_patch
|
||||
from eth2spec.test.helpers.keys import privkeys
|
||||
from eth2spec.utils import bls
|
||||
from eth2spec.utils.bls import only_with_bls
|
||||
|
@ -91,7 +91,7 @@ def build_empty_block(spec, state, slot=None):
|
|||
empty_block.body.eth1_data.deposit_count = state.eth1_deposit_index
|
||||
empty_block.parent_root = parent_block_root
|
||||
|
||||
if spec.fork == LIGHTCLIENT_PATCH:
|
||||
if is_post_lightclient_patch(spec):
|
||||
empty_block.body.sync_committee_signature = spec.G2_POINT_AT_INFINITY
|
||||
|
||||
apply_randao_reveal(spec, state, empty_block)
|
||||
|
|
|
@ -1,23 +1,29 @@
|
|||
|
||||
process_calls = [
|
||||
# PHASE0
|
||||
'process_justification_and_finalization',
|
||||
'process_rewards_and_penalties',
|
||||
'process_registry_updates',
|
||||
'process_reveal_deadlines',
|
||||
'process_challenge_deadlines',
|
||||
'process_slashings',
|
||||
'process_eth1_data_reset',
|
||||
'process_effective_balance_updates',
|
||||
'process_slashings_reset',
|
||||
'process_randao_mixes_reset',
|
||||
'process_historical_roots_update',
|
||||
'process_participation_record_updates',
|
||||
# LIGHTCLIENT_PATCH
|
||||
'process_sync_committee_updates',
|
||||
# PHASE1
|
||||
'process_phase_1_final_updates',
|
||||
]
|
||||
from eth2spec.test.context import is_post_lightclient_patch
|
||||
|
||||
|
||||
def get_process_calls(spec):
|
||||
return [
|
||||
# PHASE0
|
||||
'process_justification_and_finalization',
|
||||
'process_rewards_and_penalties',
|
||||
'process_registry_updates',
|
||||
'process_reveal_deadlines',
|
||||
'process_challenge_deadlines',
|
||||
'process_slashings',
|
||||
'process_eth1_data_reset',
|
||||
'process_effective_balance_updates',
|
||||
'process_slashings_reset',
|
||||
'process_randao_mixes_reset',
|
||||
'process_historical_roots_update',
|
||||
# HF1 replaced `process_participation_record_updates` with `process_participation_flag_updates`
|
||||
'process_participation_flag_updates' if is_post_lightclient_patch(spec) else (
|
||||
'process_participation_record_updates'
|
||||
),
|
||||
'process_sync_committee_updates',
|
||||
# PHASE1
|
||||
'process_phase_1_final_updates',
|
||||
]
|
||||
|
||||
|
||||
def run_epoch_processing_to(spec, state, process_name: str):
|
||||
|
@ -34,7 +40,7 @@ def run_epoch_processing_to(spec, state, process_name: str):
|
|||
spec.process_slot(state)
|
||||
|
||||
# process components of epoch transition before final-updates
|
||||
for name in process_calls:
|
||||
for name in get_process_calls(spec):
|
||||
if name == process_name:
|
||||
break
|
||||
# only run when present. Later phases introduce more to the epoch-processing.
|
||||
|
|
|
@ -2,7 +2,7 @@ from random import Random
|
|||
from lru import LRU
|
||||
|
||||
from eth2spec.phase0 import spec as spec_phase0
|
||||
from eth2spec.test.context import LIGHTCLIENT_PATCH
|
||||
from eth2spec.test.context import is_post_lightclient_patch
|
||||
from eth2spec.test.helpers.attestations import cached_prepare_state_with_attestations
|
||||
from eth2spec.test.helpers.deposits import mock_deposit
|
||||
from eth2spec.test.helpers.state import next_epoch
|
||||
|
@ -38,24 +38,35 @@ def run_deltas(spec, state):
|
|||
- inactivity penalty deltas ('inactivity_penalty_deltas')
|
||||
"""
|
||||
yield 'pre', state
|
||||
|
||||
if is_post_lightclient_patch(spec):
|
||||
def get_source_deltas(state):
|
||||
return spec.get_flag_deltas(state, spec.TIMELY_SOURCE_FLAG, spec.TIMELY_SOURCE_NUMERATOR)
|
||||
|
||||
def get_head_deltas(state):
|
||||
return spec.get_flag_deltas(state, spec.TIMELY_HEAD_FLAG, spec.TIMELY_HEAD_NUMERATOR)
|
||||
|
||||
def get_target_deltas(state):
|
||||
return spec.get_flag_deltas(state, spec.TIMELY_TARGET_FLAG, spec.TIMELY_TARGET_NUMERATOR)
|
||||
|
||||
yield from run_attestation_component_deltas(
|
||||
spec,
|
||||
state,
|
||||
spec.get_source_deltas,
|
||||
spec.get_source_deltas if not is_post_lightclient_patch(spec) else get_source_deltas,
|
||||
spec.get_matching_source_attestations,
|
||||
'source_deltas',
|
||||
)
|
||||
yield from run_attestation_component_deltas(
|
||||
spec,
|
||||
state,
|
||||
spec.get_target_deltas,
|
||||
spec.get_target_deltas if not is_post_lightclient_patch(spec) else get_target_deltas,
|
||||
spec.get_matching_target_attestations,
|
||||
'target_deltas',
|
||||
)
|
||||
yield from run_attestation_component_deltas(
|
||||
spec,
|
||||
state,
|
||||
spec.get_head_deltas,
|
||||
spec.get_head_deltas if not is_post_lightclient_patch(spec) else get_head_deltas,
|
||||
spec.get_matching_head_attestations,
|
||||
'head_deltas',
|
||||
)
|
||||
|
@ -63,6 +74,16 @@ def run_deltas(spec, state):
|
|||
yield from run_get_inactivity_penalty_deltas(spec, state)
|
||||
|
||||
|
||||
def deltas_name_to_flag(spec, deltas_name):
|
||||
if 'source' in deltas_name:
|
||||
return spec.TIMELY_SOURCE_FLAG
|
||||
elif 'head' in deltas_name:
|
||||
return spec.TIMELY_HEAD_FLAG
|
||||
elif 'target' in deltas_name:
|
||||
return spec.TIMELY_TARGET_FLAG
|
||||
raise ValueError("Wrong deltas_name %s" % deltas_name)
|
||||
|
||||
|
||||
def run_attestation_component_deltas(spec, state, component_delta_fn, matching_att_fn, deltas_name):
|
||||
"""
|
||||
Run ``component_delta_fn``, yielding:
|
||||
|
@ -72,8 +93,14 @@ def run_attestation_component_deltas(spec, state, component_delta_fn, matching_a
|
|||
|
||||
yield deltas_name, Deltas(rewards=rewards, penalties=penalties)
|
||||
|
||||
matching_attestations = matching_att_fn(state, spec.get_previous_epoch(state))
|
||||
matching_indices = spec.get_unslashed_attesting_indices(state, matching_attestations)
|
||||
if not is_post_lightclient_patch(spec):
|
||||
matching_attestations = matching_att_fn(state, spec.get_previous_epoch(state))
|
||||
matching_indices = spec.get_unslashed_attesting_indices(state, matching_attestations)
|
||||
else:
|
||||
matching_indices = spec.get_unslashed_participating_indices(
|
||||
state, deltas_name_to_flag(spec, deltas_name), spec.get_previous_epoch(state)
|
||||
)
|
||||
|
||||
eligible_indices = spec.get_eligible_validator_indices(state)
|
||||
for index in range(len(state.validators)):
|
||||
if index not in eligible_indices:
|
||||
|
@ -102,6 +129,12 @@ def run_get_inclusion_delay_deltas(spec, state):
|
|||
Run ``get_inclusion_delay_deltas``, yielding:
|
||||
- inclusion delay deltas ('inclusion_delay_deltas')
|
||||
"""
|
||||
if is_post_lightclient_patch(spec):
|
||||
# No inclusion_delay_deltas
|
||||
yield 'inclusion_delay_deltas', Deltas(rewards=[0] * len(state.validators),
|
||||
penalties=[0] * len(state.validators))
|
||||
return
|
||||
|
||||
rewards, penalties = spec.get_inclusion_delay_deltas(state)
|
||||
|
||||
yield 'inclusion_delay_deltas', Deltas(rewards=rewards, penalties=penalties)
|
||||
|
@ -149,8 +182,14 @@ def run_get_inactivity_penalty_deltas(spec, state):
|
|||
|
||||
yield 'inactivity_penalty_deltas', Deltas(rewards=rewards, penalties=penalties)
|
||||
|
||||
matching_attestations = spec.get_matching_target_attestations(state, spec.get_previous_epoch(state))
|
||||
matching_attesting_indices = spec.get_unslashed_attesting_indices(state, matching_attestations)
|
||||
if not is_post_lightclient_patch(spec):
|
||||
matching_attestations = spec.get_matching_target_attestations(state, spec.get_previous_epoch(state))
|
||||
matching_attesting_indices = spec.get_unslashed_attesting_indices(state, matching_attestations)
|
||||
else:
|
||||
matching_attesting_indices = spec.get_unslashed_participating_indices(
|
||||
state, spec.TIMELY_TARGET_FLAG, spec.get_previous_epoch(state)
|
||||
)
|
||||
reward_numerator_sum = sum(numerator for (_, numerator) in spec.get_flags_and_numerators())
|
||||
|
||||
eligible_indices = spec.get_eligible_validator_indices(state)
|
||||
for index in range(len(state.validators)):
|
||||
|
@ -160,12 +199,14 @@ def run_get_inactivity_penalty_deltas(spec, state):
|
|||
continue
|
||||
|
||||
if spec.is_in_inactivity_leak(state):
|
||||
if spec.fork == LIGHTCLIENT_PATCH:
|
||||
cancel_base_rewards_per_epoch = spec.BASE_REWARDS_PER_EPOCH - 1
|
||||
else:
|
||||
# Compute base_penalty
|
||||
if not is_post_lightclient_patch(spec):
|
||||
cancel_base_rewards_per_epoch = spec.BASE_REWARDS_PER_EPOCH
|
||||
base_reward = spec.get_base_reward(state, index)
|
||||
base_penalty = cancel_base_rewards_per_epoch * base_reward - spec.get_proposer_reward(state, index)
|
||||
base_reward = spec.get_base_reward(state, index)
|
||||
base_penalty = cancel_base_rewards_per_epoch * base_reward - spec.get_proposer_reward(state, index)
|
||||
else:
|
||||
base_penalty = spec.get_base_reward(state, index) * reward_numerator_sum // spec.REWARD_DENOMINATOR
|
||||
|
||||
if not has_enough_for_reward(spec, state, index):
|
||||
assert penalties[index] == 0
|
||||
elif index in matching_attesting_indices:
|
||||
|
@ -267,8 +308,13 @@ def run_test_full_all_correct(spec, state):
|
|||
def run_test_full_but_partial_participation(spec, state, rng=Random(5522)):
|
||||
cached_prepare_state_with_attestations(spec, state)
|
||||
|
||||
for a in state.previous_epoch_attestations:
|
||||
a.aggregation_bits = [rng.choice([True, False]) for _ in a.aggregation_bits]
|
||||
if not is_post_lightclient_patch(spec):
|
||||
for a in state.previous_epoch_attestations:
|
||||
a.aggregation_bits = [rng.choice([True, False]) for _ in a.aggregation_bits]
|
||||
else:
|
||||
for index in range(len(state.validators)):
|
||||
if rng.choice([True, False]):
|
||||
state.previous_epoch_participation[index] = spec.ValidatorFlag(0)
|
||||
|
||||
yield from run_deltas(spec, state)
|
||||
|
||||
|
@ -277,8 +323,12 @@ def run_test_partial(spec, state, fraction_filled):
|
|||
cached_prepare_state_with_attestations(spec, state)
|
||||
|
||||
# Remove portion of attestations
|
||||
num_attestations = int(len(state.previous_epoch_attestations) * fraction_filled)
|
||||
state.previous_epoch_attestations = state.previous_epoch_attestations[:num_attestations]
|
||||
if not is_post_lightclient_patch(spec):
|
||||
num_attestations = int(len(state.previous_epoch_attestations) * fraction_filled)
|
||||
state.previous_epoch_attestations = state.previous_epoch_attestations[:num_attestations]
|
||||
else:
|
||||
for index in range(int(len(state.validators) * fraction_filled)):
|
||||
state.previous_epoch_participation[index] = spec.ValidatorFlag(0)
|
||||
|
||||
yield from run_deltas(spec, state)
|
||||
|
||||
|
@ -333,13 +383,18 @@ def run_test_some_very_low_effective_balances_that_attested(spec, state):
|
|||
def run_test_some_very_low_effective_balances_that_did_not_attest(spec, state):
|
||||
cached_prepare_state_with_attestations(spec, state)
|
||||
|
||||
# Remove attestation
|
||||
attestation = state.previous_epoch_attestations[0]
|
||||
state.previous_epoch_attestations = state.previous_epoch_attestations[1:]
|
||||
# Set removed indices effective balance to very low amount
|
||||
indices = spec.get_unslashed_attesting_indices(state, [attestation])
|
||||
for i, index in enumerate(indices):
|
||||
state.validators[index].effective_balance = i
|
||||
if not is_post_lightclient_patch(spec):
|
||||
# Remove attestation
|
||||
attestation = state.previous_epoch_attestations[0]
|
||||
state.previous_epoch_attestations = state.previous_epoch_attestations[1:]
|
||||
# Set removed indices effective balance to very low amount
|
||||
indices = spec.get_unslashed_attesting_indices(state, [attestation])
|
||||
for i, index in enumerate(indices):
|
||||
state.validators[index].effective_balance = i
|
||||
else:
|
||||
index = 0
|
||||
state.validators[index].effective_balance = 1
|
||||
state.previous_epoch_participation[index] = spec.ValidatorFlag(0)
|
||||
|
||||
yield from run_deltas(spec, state)
|
||||
|
||||
|
@ -447,16 +502,42 @@ def run_test_full_random(spec, state, rng=Random(8020)):
|
|||
|
||||
cached_prepare_state_with_attestations(spec, state)
|
||||
|
||||
for pending_attestation in state.previous_epoch_attestations:
|
||||
# ~1/3 have bad target
|
||||
if rng.randint(0, 2) == 0:
|
||||
pending_attestation.data.target.root = b'\x55' * 32
|
||||
# ~1/3 have bad head
|
||||
if rng.randint(0, 2) == 0:
|
||||
pending_attestation.data.beacon_block_root = b'\x66' * 32
|
||||
# ~50% participation
|
||||
pending_attestation.aggregation_bits = [rng.choice([True, False]) for _ in pending_attestation.aggregation_bits]
|
||||
# Random inclusion delay
|
||||
pending_attestation.inclusion_delay = rng.randint(1, spec.SLOTS_PER_EPOCH)
|
||||
if not is_post_lightclient_patch(spec):
|
||||
for pending_attestation in state.previous_epoch_attestations:
|
||||
# ~1/3 have bad target
|
||||
if rng.randint(0, 2) == 0:
|
||||
pending_attestation.data.target.root = b'\x55' * 32
|
||||
# ~1/3 have bad head
|
||||
if rng.randint(0, 2) == 0:
|
||||
pending_attestation.data.beacon_block_root = b'\x66' * 32
|
||||
# ~50% participation
|
||||
pending_attestation.aggregation_bits = [rng.choice([True, False])
|
||||
for _ in pending_attestation.aggregation_bits]
|
||||
# Random inclusion delay
|
||||
pending_attestation.inclusion_delay = rng.randint(1, spec.SLOTS_PER_EPOCH)
|
||||
else:
|
||||
for index in range(len(state.validators)):
|
||||
# ~1/3 have bad head or bad target or not timely enough
|
||||
is_timely_correct_head = rng.randint(0, 2) != 0
|
||||
flags = state.previous_epoch_participation[index]
|
||||
|
||||
def set_flag(f, v):
|
||||
nonlocal flags
|
||||
if v:
|
||||
flags |= f
|
||||
else:
|
||||
flags &= 0xff ^ f
|
||||
|
||||
set_flag(spec.TIMELY_HEAD_FLAG, is_timely_correct_head)
|
||||
if is_timely_correct_head:
|
||||
# If timely head, then must be timely target
|
||||
set_flag(spec.TIMELY_TARGET_FLAG, True)
|
||||
# If timely head, then must be timely source
|
||||
set_flag(spec.TIMELY_SOURCE_FLAG, True)
|
||||
else:
|
||||
# ~50% of remaining have bad target or not timely enough
|
||||
set_flag(spec.TIMELY_TARGET_FLAG, rng.choice([True, False]))
|
||||
# ~50% of remaining have bad source or not timely enough
|
||||
set_flag(spec.TIMELY_SOURCE_FLAG, rng.choice([True, False]))
|
||||
state.previous_epoch_participation[index] = flags
|
||||
yield from run_deltas(spec, state)
|
||||
|
|
|
@ -18,6 +18,7 @@ from eth2spec.test.context import (
|
|||
with_all_phases_except,
|
||||
with_configs,
|
||||
spec_state_test,
|
||||
always_bls,
|
||||
)
|
||||
from eth2spec.utils.hash_function import hash
|
||||
|
||||
|
@ -196,6 +197,7 @@ def test_sync_committee_rewards_duplicate_committee(spec, state):
|
|||
|
||||
@with_all_phases_except([PHASE0, PHASE1])
|
||||
@spec_state_test
|
||||
@always_bls
|
||||
def test_invalid_signature_past_block(spec, state):
|
||||
committee = spec.get_sync_committee_indices(state, spec.get_current_epoch(state))
|
||||
|
||||
|
@ -237,6 +239,7 @@ def test_invalid_signature_past_block(spec, state):
|
|||
@with_all_phases_except([PHASE0, PHASE1])
|
||||
@with_configs([MINIMAL], reason="to produce different committee sets")
|
||||
@spec_state_test
|
||||
@always_bls
|
||||
def test_invalid_signature_previous_committee(spec, state):
|
||||
# NOTE: the `state` provided is at genesis and the process to select
|
||||
# sync committees currently returns the same committee for the first and second
|
||||
|
|
|
@ -2,10 +2,13 @@ from eth2spec.test.context import (
|
|||
spec_state_test,
|
||||
always_bls, never_bls,
|
||||
with_all_phases,
|
||||
with_all_phases_except,
|
||||
spec_test,
|
||||
low_balances,
|
||||
with_custom_state,
|
||||
single_phase)
|
||||
single_phase,
|
||||
PHASE1,
|
||||
)
|
||||
from eth2spec.test.helpers.attestations import (
|
||||
run_attestation_processing,
|
||||
get_valid_attestation,
|
||||
|
@ -329,3 +332,212 @@ def test_too_few_aggregation_bits(spec, state):
|
|||
attestation.aggregation_bits = attestation.aggregation_bits[:-1]
|
||||
|
||||
yield from run_attestation_processing(spec, state, attestation, False)
|
||||
|
||||
|
||||
#
|
||||
# Full correct atttestation contents at different slot inclusions
|
||||
#
|
||||
|
||||
@with_all_phases
|
||||
@spec_state_test
|
||||
def test_correct_min_inclusion_delay(spec, state):
|
||||
attestation = get_valid_attestation(spec, state, signed=True)
|
||||
next_slots(spec, state, spec.MIN_ATTESTATION_INCLUSION_DELAY)
|
||||
|
||||
yield from run_attestation_processing(spec, state, attestation)
|
||||
|
||||
|
||||
@with_all_phases
|
||||
@spec_state_test
|
||||
def test_correct_sqrt_epoch_delay(spec, state):
|
||||
attestation = get_valid_attestation(spec, state, signed=True, on_time=False)
|
||||
next_slots(spec, state, spec.integer_squareroot(spec.SLOTS_PER_EPOCH))
|
||||
|
||||
yield from run_attestation_processing(spec, state, attestation)
|
||||
|
||||
|
||||
@with_all_phases
|
||||
@spec_state_test
|
||||
def test_correct_epoch_delay(spec, state):
|
||||
attestation = get_valid_attestation(spec, state, signed=True, on_time=False)
|
||||
next_slots(spec, state, spec.SLOTS_PER_EPOCH)
|
||||
|
||||
yield from run_attestation_processing(spec, state, attestation)
|
||||
|
||||
|
||||
@with_all_phases
|
||||
@spec_state_test
|
||||
def test_correct_after_epoch_delay(spec, state):
|
||||
attestation = get_valid_attestation(spec, state, signed=True, on_time=False)
|
||||
|
||||
# increment past latest inclusion slot
|
||||
next_slots(spec, state, spec.SLOTS_PER_EPOCH + 1)
|
||||
|
||||
yield from run_attestation_processing(spec, state, attestation, False)
|
||||
|
||||
|
||||
#
|
||||
# Incorrect head but correct source/target at different slot inclusions
|
||||
#
|
||||
|
||||
@with_all_phases_except([PHASE1])
|
||||
@spec_state_test
|
||||
def test_incorrect_head_min_inclusion_delay(spec, state):
|
||||
attestation = get_valid_attestation(spec, state, signed=False)
|
||||
next_slots(spec, state, spec.MIN_ATTESTATION_INCLUSION_DELAY)
|
||||
|
||||
attestation.data.beacon_block_root = b'\x42' * 32
|
||||
sign_attestation(spec, state, attestation)
|
||||
|
||||
yield from run_attestation_processing(spec, state, attestation)
|
||||
|
||||
|
||||
@with_all_phases
|
||||
@spec_state_test
|
||||
def test_incorrect_head_sqrt_epoch_delay(spec, state):
|
||||
attestation = get_valid_attestation(spec, state, signed=False, on_time=False)
|
||||
next_slots(spec, state, spec.integer_squareroot(spec.SLOTS_PER_EPOCH))
|
||||
|
||||
attestation.data.beacon_block_root = b'\x42' * 32
|
||||
sign_attestation(spec, state, attestation)
|
||||
|
||||
yield from run_attestation_processing(spec, state, attestation)
|
||||
|
||||
|
||||
@with_all_phases
|
||||
@spec_state_test
|
||||
def test_incorrect_head_epoch_delay(spec, state):
|
||||
attestation = get_valid_attestation(spec, state, signed=False, on_time=False)
|
||||
next_slots(spec, state, spec.SLOTS_PER_EPOCH)
|
||||
|
||||
attestation.data.beacon_block_root = b'\x42' * 32
|
||||
sign_attestation(spec, state, attestation)
|
||||
|
||||
yield from run_attestation_processing(spec, state, attestation)
|
||||
|
||||
|
||||
@with_all_phases
|
||||
@spec_state_test
|
||||
def test_incorrect_head_after_epoch_delay(spec, state):
|
||||
attestation = get_valid_attestation(spec, state, signed=False, on_time=False)
|
||||
|
||||
# increment past latest inclusion slot
|
||||
next_slots(spec, state, spec.SLOTS_PER_EPOCH + 1)
|
||||
|
||||
attestation.data.beacon_block_root = b'\x42' * 32
|
||||
sign_attestation(spec, state, attestation)
|
||||
|
||||
yield from run_attestation_processing(spec, state, attestation, False)
|
||||
|
||||
|
||||
#
|
||||
# Incorrect head and target but correct source at different slot inclusions
|
||||
#
|
||||
|
||||
# Note: current phase 1 spec checks
|
||||
# `assert data.beacon_block_root == get_block_root_at_slot(state, compute_previous_slot(state.slot))`
|
||||
# so this test can't pass that until phase 1 refactor is merged
|
||||
@with_all_phases_except([PHASE1])
|
||||
@spec_state_test
|
||||
def test_incorrect_head_and_target_min_inclusion_delay(spec, state):
|
||||
attestation = get_valid_attestation(spec, state, signed=False)
|
||||
next_slots(spec, state, spec.MIN_ATTESTATION_INCLUSION_DELAY)
|
||||
|
||||
attestation.data.beacon_block_root = b'\x42' * 32
|
||||
attestation.data.target.root = b'\x42' * 32
|
||||
sign_attestation(spec, state, attestation)
|
||||
|
||||
yield from run_attestation_processing(spec, state, attestation)
|
||||
|
||||
|
||||
@with_all_phases
|
||||
@spec_state_test
|
||||
def test_incorrect_head_and_target_sqrt_epoch_delay(spec, state):
|
||||
attestation = get_valid_attestation(spec, state, signed=False, on_time=False)
|
||||
next_slots(spec, state, spec.integer_squareroot(spec.SLOTS_PER_EPOCH))
|
||||
|
||||
attestation.data.beacon_block_root = b'\x42' * 32
|
||||
attestation.data.target.root = b'\x42' * 32
|
||||
sign_attestation(spec, state, attestation)
|
||||
|
||||
yield from run_attestation_processing(spec, state, attestation)
|
||||
|
||||
|
||||
@with_all_phases
|
||||
@spec_state_test
|
||||
def test_incorrect_head_and_target_epoch_delay(spec, state):
|
||||
attestation = get_valid_attestation(spec, state, signed=False, on_time=False)
|
||||
next_slots(spec, state, spec.SLOTS_PER_EPOCH)
|
||||
|
||||
attestation.data.beacon_block_root = b'\x42' * 32
|
||||
attestation.data.target.root = b'\x42' * 32
|
||||
sign_attestation(spec, state, attestation)
|
||||
|
||||
yield from run_attestation_processing(spec, state, attestation)
|
||||
|
||||
|
||||
@with_all_phases
|
||||
@spec_state_test
|
||||
def test_incorrect_head_and_target_after_epoch_delay(spec, state):
|
||||
attestation = get_valid_attestation(spec, state, signed=False, on_time=False)
|
||||
# increment past latest inclusion slot
|
||||
next_slots(spec, state, spec.SLOTS_PER_EPOCH + 1)
|
||||
|
||||
attestation.data.beacon_block_root = b'\x42' * 32
|
||||
attestation.data.target.root = b'\x42' * 32
|
||||
sign_attestation(spec, state, attestation)
|
||||
|
||||
yield from run_attestation_processing(spec, state, attestation, False)
|
||||
|
||||
|
||||
#
|
||||
# Correct head and source but incorrect target at different slot inclusions
|
||||
#
|
||||
|
||||
@with_all_phases_except([PHASE1])
|
||||
@spec_state_test
|
||||
def test_incorrect_target_min_inclusion_delay(spec, state):
|
||||
attestation = get_valid_attestation(spec, state, signed=False)
|
||||
next_slots(spec, state, spec.MIN_ATTESTATION_INCLUSION_DELAY)
|
||||
|
||||
attestation.data.target.root = b'\x42' * 32
|
||||
sign_attestation(spec, state, attestation)
|
||||
|
||||
yield from run_attestation_processing(spec, state, attestation)
|
||||
|
||||
|
||||
@with_all_phases
|
||||
@spec_state_test
|
||||
def test_incorrect_target_sqrt_epoch_delay(spec, state):
|
||||
attestation = get_valid_attestation(spec, state, signed=False, on_time=False)
|
||||
next_slots(spec, state, spec.integer_squareroot(spec.SLOTS_PER_EPOCH))
|
||||
|
||||
attestation.data.target.root = b'\x42' * 32
|
||||
sign_attestation(spec, state, attestation)
|
||||
|
||||
yield from run_attestation_processing(spec, state, attestation)
|
||||
|
||||
|
||||
@with_all_phases
|
||||
@spec_state_test
|
||||
def test_incorrect_target_epoch_delay(spec, state):
|
||||
attestation = get_valid_attestation(spec, state, signed=False, on_time=False)
|
||||
next_slots(spec, state, spec.SLOTS_PER_EPOCH)
|
||||
|
||||
attestation.data.target.root = b'\x42' * 32
|
||||
sign_attestation(spec, state, attestation)
|
||||
|
||||
yield from run_attestation_processing(spec, state, attestation)
|
||||
|
||||
|
||||
@with_all_phases
|
||||
@spec_state_test
|
||||
def test_incorrect_target_after_epoch_delay(spec, state):
|
||||
attestation = get_valid_attestation(spec, state, signed=False, on_time=False)
|
||||
# increment past latest inclusion slot
|
||||
next_slots(spec, state, spec.SLOTS_PER_EPOCH + 1)
|
||||
|
||||
attestation.data.target.root = b'\x42' * 32
|
||||
sign_attestation(spec, state, attestation)
|
||||
|
||||
yield from run_attestation_processing(spec, state, attestation, False)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
from eth2spec.test.context import spec_state_test, with_all_phases
|
||||
from eth2spec.test.context import is_post_lightclient_patch, spec_state_test, with_all_phases
|
||||
from eth2spec.test.helpers.epoch_processing import (
|
||||
run_epoch_processing_with
|
||||
run_epoch_processing_with,
|
||||
)
|
||||
from eth2spec.test.helpers.state import transition_to
|
||||
|
||||
|
@ -16,12 +16,20 @@ def add_mock_attestations(spec, state, epoch, source, target, sufficient_support
|
|||
previous_epoch = spec.get_previous_epoch(state)
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
|
||||
if current_epoch == epoch:
|
||||
attestations = state.current_epoch_attestations
|
||||
elif previous_epoch == epoch:
|
||||
attestations = state.previous_epoch_attestations
|
||||
if not is_post_lightclient_patch(spec):
|
||||
if current_epoch == epoch:
|
||||
attestations = state.current_epoch_attestations
|
||||
elif previous_epoch == epoch:
|
||||
attestations = state.previous_epoch_attestations
|
||||
else:
|
||||
raise Exception(f"cannot include attestations in epoch ${epoch} from epoch ${current_epoch}")
|
||||
else:
|
||||
raise Exception(f"cannot include attestations in epoch ${epoch} from epoch ${current_epoch}")
|
||||
if current_epoch == epoch:
|
||||
epoch_participation = state.current_epoch_participation
|
||||
elif previous_epoch == epoch:
|
||||
epoch_participation = state.previous_epoch_participation
|
||||
else:
|
||||
raise Exception(f"cannot include attestations in epoch ${epoch} from epoch ${current_epoch}")
|
||||
|
||||
total_balance = spec.get_total_active_balance(state)
|
||||
remaining_balance = int(total_balance * 2 // 3) # can become negative
|
||||
|
@ -52,19 +60,28 @@ def add_mock_attestations(spec, state, epoch, source, target, sufficient_support
|
|||
for i in range(max(len(committee) // 5, 1)):
|
||||
aggregation_bits[i] = 0
|
||||
|
||||
attestations.append(spec.PendingAttestation(
|
||||
aggregation_bits=aggregation_bits,
|
||||
data=spec.AttestationData(
|
||||
slot=slot,
|
||||
beacon_block_root=b'\xff' * 32, # irrelevant to testing
|
||||
source=source,
|
||||
target=target,
|
||||
index=index,
|
||||
),
|
||||
inclusion_delay=1,
|
||||
))
|
||||
if messed_up_target:
|
||||
attestations[len(attestations) - 1].data.target.root = b'\x99' * 32
|
||||
# Update state
|
||||
if not is_post_lightclient_patch(spec):
|
||||
attestations.append(spec.PendingAttestation(
|
||||
aggregation_bits=aggregation_bits,
|
||||
data=spec.AttestationData(
|
||||
slot=slot,
|
||||
beacon_block_root=b'\xff' * 32, # irrelevant to testing
|
||||
source=source,
|
||||
target=target,
|
||||
index=index,
|
||||
),
|
||||
inclusion_delay=1,
|
||||
))
|
||||
if messed_up_target:
|
||||
attestations[len(attestations) - 1].data.target.root = b'\x99' * 32
|
||||
else:
|
||||
for i, index in enumerate(committee):
|
||||
if aggregation_bits[i]:
|
||||
epoch_participation[index] |= spec.TIMELY_HEAD_FLAG
|
||||
epoch_participation[index] |= spec.TIMELY_SOURCE_FLAG
|
||||
if not messed_up_target:
|
||||
epoch_participation[index] |= spec.TIMELY_TARGET_FLAG
|
||||
|
||||
|
||||
def get_checkpoints(spec, epoch):
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from eth2spec.test.context import spec_state_test, with_all_phases
|
||||
from eth2spec.test.context import PHASE0, spec_state_test, with_phases
|
||||
from eth2spec.test.helpers.epoch_processing import (
|
||||
run_epoch_processing_with
|
||||
)
|
||||
|
@ -8,7 +8,7 @@ def run_process_participation_record_updates(spec, state):
|
|||
yield from run_epoch_processing_with(spec, state, 'process_participation_record_updates')
|
||||
|
||||
|
||||
@with_all_phases
|
||||
@with_phases([PHASE0])
|
||||
@spec_state_test
|
||||
def test_updated_participation_record(spec, state):
|
||||
state.previous_epoch_attestations = [spec.PendingAttestation(proposer_index=100)]
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
from eth2spec.test.context import (
|
||||
LIGHTCLIENT_PATCH,
|
||||
spec_state_test, spec_test,
|
||||
with_all_phases, single_phase,
|
||||
with_phases, PHASE0,
|
||||
with_phases, PHASE0, PHASE1,
|
||||
with_custom_state,
|
||||
zero_activation_threshold,
|
||||
misc_balances, low_single_balance,
|
||||
is_post_lightclient_patch,
|
||||
)
|
||||
from eth2spec.test.helpers.state import (
|
||||
next_epoch,
|
||||
|
@ -66,7 +66,7 @@ def test_genesis_epoch_full_attestations_no_rewards(spec, state):
|
|||
assert state.balances[index] == pre_state.balances[index]
|
||||
|
||||
|
||||
@with_all_phases
|
||||
@with_phases([PHASE0, PHASE1])
|
||||
@spec_state_test
|
||||
def test_full_attestations_random_incorrect_fields(spec, state):
|
||||
attestations = prepare_state_with_attestations(spec, state)
|
||||
|
@ -159,11 +159,11 @@ def run_with_participation(spec, state, participation_fn):
|
|||
return att_participants
|
||||
|
||||
attestations = prepare_state_with_attestations(spec, state, participation_fn=participation_tracker)
|
||||
proposer_indices = [a.proposer_index for a in state.previous_epoch_attestations]
|
||||
|
||||
pre_state = state.copy()
|
||||
|
||||
if spec.fork == LIGHTCLIENT_PATCH:
|
||||
if not is_post_lightclient_patch(spec):
|
||||
proposer_indices = [a.proposer_index for a in state.previous_epoch_attestations]
|
||||
else:
|
||||
sync_committee_indices = spec.get_sync_committee_indices(state, spec.get_current_epoch(state))
|
||||
|
||||
yield from run_process_rewards_and_penalties(spec, state)
|
||||
|
@ -173,11 +173,11 @@ def run_with_participation(spec, state, participation_fn):
|
|||
|
||||
for index in range(len(pre_state.validators)):
|
||||
if spec.is_in_inactivity_leak(state):
|
||||
# Proposers can still make money during a leak
|
||||
if index in proposer_indices and index in participated:
|
||||
# Proposers can still make money during a leak before LIGHTCLIENT_PATCH
|
||||
if not is_post_lightclient_patch(spec) and index in proposer_indices and index in participated:
|
||||
assert state.balances[index] > pre_state.balances[index]
|
||||
elif index in attesting_indices:
|
||||
if spec.fork == LIGHTCLIENT_PATCH and index in sync_committee_indices:
|
||||
if is_post_lightclient_patch(spec) and index in sync_committee_indices:
|
||||
# The sync committee reward has not been canceled, so the sync committee participants still earn it
|
||||
assert state.balances[index] >= pre_state.balances[index]
|
||||
else:
|
||||
|
@ -428,7 +428,8 @@ def test_attestations_some_slashed(spec, state):
|
|||
for i in range(spec.MIN_PER_EPOCH_CHURN_LIMIT):
|
||||
spec.slash_validator(state, attesting_indices_before_slashings[i])
|
||||
|
||||
assert len(state.previous_epoch_attestations) == len(attestations)
|
||||
if not is_post_lightclient_patch(spec):
|
||||
assert len(state.previous_epoch_attestations) == len(attestations)
|
||||
|
||||
pre_state = state.copy()
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from eth2spec.test.context import with_all_phases, spec_state_test
|
||||
from eth2spec.test.context import PHASE0, PHASE1, with_all_phases, with_phases, spec_state_test
|
||||
import eth2spec.test.helpers.rewards as rewards_helpers
|
||||
|
||||
|
||||
|
@ -32,7 +32,7 @@ def test_full_but_partial_participation(spec, state):
|
|||
yield from rewards_helpers.run_test_full_but_partial_participation(spec, state)
|
||||
|
||||
|
||||
@with_all_phases
|
||||
@with_phases([PHASE0, PHASE1])
|
||||
@spec_state_test
|
||||
def test_one_attestation_one_correct(spec, state):
|
||||
yield from rewards_helpers.run_test_one_attestation_one_correct(spec, state)
|
||||
|
@ -75,7 +75,7 @@ def test_some_very_low_effective_balances_that_did_not_attest(spec, state):
|
|||
#
|
||||
|
||||
|
||||
@with_all_phases
|
||||
@with_phases([PHASE0, PHASE1])
|
||||
@spec_state_test
|
||||
def test_full_half_correct_target_incorrect_head(spec, state):
|
||||
yield from rewards_helpers.run_test_full_fraction_incorrect(
|
||||
|
@ -86,7 +86,7 @@ def test_full_half_correct_target_incorrect_head(spec, state):
|
|||
)
|
||||
|
||||
|
||||
@with_all_phases
|
||||
@with_phases([PHASE0, PHASE1])
|
||||
@spec_state_test
|
||||
def test_full_correct_target_incorrect_head(spec, state):
|
||||
yield from rewards_helpers.run_test_full_fraction_incorrect(
|
||||
|
@ -97,7 +97,7 @@ def test_full_correct_target_incorrect_head(spec, state):
|
|||
)
|
||||
|
||||
|
||||
@with_all_phases
|
||||
@with_phases([PHASE0, PHASE1])
|
||||
@spec_state_test
|
||||
def test_full_half_incorrect_target_incorrect_head(spec, state):
|
||||
yield from rewards_helpers.run_test_full_fraction_incorrect(
|
||||
|
@ -108,7 +108,7 @@ def test_full_half_incorrect_target_incorrect_head(spec, state):
|
|||
)
|
||||
|
||||
|
||||
@with_all_phases
|
||||
@with_phases([PHASE0, PHASE1])
|
||||
@spec_state_test
|
||||
def test_full_half_incorrect_target_correct_head(spec, state):
|
||||
yield from rewards_helpers.run_test_full_fraction_incorrect(
|
||||
|
@ -119,31 +119,31 @@ def test_full_half_incorrect_target_correct_head(spec, state):
|
|||
)
|
||||
|
||||
|
||||
@with_all_phases
|
||||
@with_phases([PHASE0, PHASE1])
|
||||
@spec_state_test
|
||||
def test_full_delay_one_slot(spec, state):
|
||||
yield from rewards_helpers.run_test_full_delay_one_slot(spec, state)
|
||||
|
||||
|
||||
@with_all_phases
|
||||
@with_phases([PHASE0, PHASE1])
|
||||
@spec_state_test
|
||||
def test_full_delay_max_slots(spec, state):
|
||||
yield from rewards_helpers.run_test_full_delay_max_slots(spec, state)
|
||||
|
||||
|
||||
@with_all_phases
|
||||
@with_phases([PHASE0, PHASE1])
|
||||
@spec_state_test
|
||||
def test_full_mixed_delay(spec, state):
|
||||
yield from rewards_helpers.run_test_full_mixed_delay(spec, state)
|
||||
|
||||
|
||||
@with_all_phases
|
||||
@with_phases([PHASE0, PHASE1])
|
||||
@spec_state_test
|
||||
def test_proposer_not_in_attestations(spec, state):
|
||||
yield from rewards_helpers.run_test_proposer_not_in_attestations(spec, state)
|
||||
|
||||
|
||||
@with_all_phases
|
||||
@with_phases([PHASE0, PHASE1])
|
||||
@spec_state_test
|
||||
def test_duplicate_attestations_at_later_slots(spec, state):
|
||||
yield from rewards_helpers.run_test_duplicate_attestations_at_later_slots(spec, state)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from eth2spec.test.context import with_all_phases, spec_state_test
|
||||
from eth2spec.test.context import PHASE0, PHASE1, with_all_phases, with_phases, spec_state_test
|
||||
from eth2spec.test.helpers.rewards import leaking
|
||||
import eth2spec.test.helpers.rewards as rewards_helpers
|
||||
|
||||
|
@ -38,7 +38,7 @@ def test_full_but_partial_participation_leak(spec, state):
|
|||
yield from rewards_helpers.run_test_full_but_partial_participation(spec, state)
|
||||
|
||||
|
||||
@with_all_phases
|
||||
@with_phases([PHASE0, PHASE1])
|
||||
@spec_state_test
|
||||
@leaking()
|
||||
def test_one_attestation_one_correct_leak(spec, state):
|
||||
|
@ -87,7 +87,7 @@ def test_some_very_low_effective_balances_that_did_not_attest_leak(spec, state):
|
|||
#
|
||||
|
||||
|
||||
@with_all_phases
|
||||
@with_phases([PHASE0, PHASE1])
|
||||
@spec_state_test
|
||||
@leaking()
|
||||
def test_full_half_correct_target_incorrect_head_leak(spec, state):
|
||||
|
@ -99,7 +99,7 @@ def test_full_half_correct_target_incorrect_head_leak(spec, state):
|
|||
)
|
||||
|
||||
|
||||
@with_all_phases
|
||||
@with_phases([PHASE0, PHASE1])
|
||||
@spec_state_test
|
||||
@leaking()
|
||||
def test_full_correct_target_incorrect_head_leak(spec, state):
|
||||
|
@ -111,7 +111,7 @@ def test_full_correct_target_incorrect_head_leak(spec, state):
|
|||
)
|
||||
|
||||
|
||||
@with_all_phases
|
||||
@with_phases([PHASE0, PHASE1])
|
||||
@spec_state_test
|
||||
@leaking()
|
||||
def test_full_half_incorrect_target_incorrect_head_leak(spec, state):
|
||||
|
@ -123,7 +123,7 @@ def test_full_half_incorrect_target_incorrect_head_leak(spec, state):
|
|||
)
|
||||
|
||||
|
||||
@with_all_phases
|
||||
@with_phases([PHASE0, PHASE1])
|
||||
@spec_state_test
|
||||
@leaking()
|
||||
def test_full_half_incorrect_target_correct_head_leak(spec, state):
|
||||
|
|
|
@ -29,6 +29,12 @@ def test_full_random_2(spec, state):
|
|||
yield from rewards_helpers.run_test_full_random(spec, state, rng=Random(3030))
|
||||
|
||||
|
||||
@with_all_phases
|
||||
@spec_state_test
|
||||
def test_full_random_3(spec, state):
|
||||
yield from rewards_helpers.run_test_full_random(spec, state, rng=Random(4040))
|
||||
|
||||
|
||||
@with_all_phases
|
||||
@with_custom_state(balances_fn=low_balances, threshold_fn=lambda spec: spec.EJECTION_BALANCE)
|
||||
@spec_test
|
||||
|
|
|
@ -35,6 +35,7 @@ from eth2spec.test.context import (
|
|||
with_configs,
|
||||
with_custom_state,
|
||||
large_validator_set,
|
||||
is_post_lightclient_patch,
|
||||
)
|
||||
|
||||
|
||||
|
@ -780,15 +781,19 @@ def test_attestation(spec, state):
|
|||
spec, state, shard_transition=shard_transition, index=index, signed=True, on_time=True
|
||||
)
|
||||
|
||||
if not is_post_lightclient_patch(spec):
|
||||
pre_current_attestations_len = len(state.current_epoch_attestations)
|
||||
|
||||
# Add to state via block transition
|
||||
pre_current_attestations_len = len(state.current_epoch_attestations)
|
||||
attestation_block.body.attestations.append(attestation)
|
||||
signed_attestation_block = state_transition_and_sign_block(spec, state, attestation_block)
|
||||
|
||||
assert len(state.current_epoch_attestations) == pre_current_attestations_len + 1
|
||||
|
||||
# Epoch transition should move to previous_epoch_attestations
|
||||
pre_current_attestations_root = spec.hash_tree_root(state.current_epoch_attestations)
|
||||
if not is_post_lightclient_patch(spec):
|
||||
assert len(state.current_epoch_attestations) == pre_current_attestations_len + 1
|
||||
# Epoch transition should move to previous_epoch_attestations
|
||||
pre_current_attestations_root = spec.hash_tree_root(state.current_epoch_attestations)
|
||||
else:
|
||||
pre_current_epoch_participation_root = spec.hash_tree_root(state.current_epoch_participation)
|
||||
|
||||
epoch_block = build_empty_block(spec, state, state.slot + spec.SLOTS_PER_EPOCH)
|
||||
signed_epoch_block = state_transition_and_sign_block(spec, state, epoch_block)
|
||||
|
@ -796,8 +801,13 @@ def test_attestation(spec, state):
|
|||
yield 'blocks', [signed_attestation_block, signed_epoch_block]
|
||||
yield 'post', state
|
||||
|
||||
assert len(state.current_epoch_attestations) == 0
|
||||
assert spec.hash_tree_root(state.previous_epoch_attestations) == pre_current_attestations_root
|
||||
if not is_post_lightclient_patch(spec):
|
||||
assert len(state.current_epoch_attestations) == 0
|
||||
assert spec.hash_tree_root(state.previous_epoch_attestations) == pre_current_attestations_root
|
||||
else:
|
||||
for index in range(len(state.validators)):
|
||||
assert state.current_epoch_participation[index] == 0
|
||||
assert spec.hash_tree_root(state.previous_epoch_participation) == pre_current_epoch_participation_root
|
||||
|
||||
|
||||
# In phase1 a committee is computed for SHARD_COMMITTEE_PERIOD slots ago,
|
||||
|
|
Loading…
Reference in New Issue