commit
cca545c30f
|
@ -208,16 +208,14 @@ These configurations are updated for releases, but may be out of sync during `de
|
|||
| Name | Value |
|
||||
| - | - |
|
||||
| `GENESIS_FORK_VERSION` | `int_to_bytes4(0)` |
|
||||
| `GENESIS_SLOT` | `2**32` |
|
||||
| `GENESIS_EPOCH` | `slot_to_epoch(GENESIS_SLOT)` |
|
||||
| `GENESIS_SLOT` | `0` |
|
||||
| `GENESIS_EPOCH` | `0` |
|
||||
| `GENESIS_START_SHARD` | `0` |
|
||||
| `FAR_FUTURE_EPOCH` | `2**64 - 1` |
|
||||
| `ZERO_HASH` | `int_to_bytes32(0)` |
|
||||
| `EMPTY_SIGNATURE` | `int_to_bytes96(0)` |
|
||||
| `BLS_WITHDRAWAL_PREFIX_BYTE` | `int_to_bytes1(0)` |
|
||||
|
||||
* `GENESIS_SLOT` should be at least as large in terms of time as the largest of the time parameters or state list lengths below (ie. it should be at least as large as any value measured in slots, and at least `SLOTS_PER_EPOCH` times as large as any value measured in epochs).
|
||||
|
||||
### Time parameters
|
||||
|
||||
| Name | Value | Unit | Duration |
|
||||
|
@ -678,8 +676,10 @@ def slot_to_epoch(slot: Slot) -> Epoch:
|
|||
def get_previous_epoch(state: BeaconState) -> Epoch:
|
||||
"""`
|
||||
Return the previous epoch of the given ``state``.
|
||||
Return the current epoch if it's genesis epoch.
|
||||
"""
|
||||
return get_current_epoch(state) - 1
|
||||
current_epoch = get_current_epoch(state)
|
||||
return (current_epoch - 1) if current_epoch > GENESIS_EPOCH else current_epoch
|
||||
```
|
||||
|
||||
### `get_current_epoch`
|
||||
|
@ -974,6 +974,7 @@ def get_beacon_proposer_index(state: BeaconState) -> ValidatorIndex:
|
|||
Return the beacon proposer index at ``state.slot``.
|
||||
"""
|
||||
current_epoch = get_current_epoch(state)
|
||||
|
||||
first_committee, _ = get_crosslink_committees_at_slot(state, state.slot)[0]
|
||||
i = 0
|
||||
while True:
|
||||
|
@ -1260,14 +1261,13 @@ Note: All functions in this section mutate `state`.
|
|||
#### `activate_validator`
|
||||
|
||||
```python
|
||||
def activate_validator(state: BeaconState, index: ValidatorIndex, is_genesis: bool) -> None:
|
||||
def activate_validator(state: BeaconState, index: ValidatorIndex) -> None:
|
||||
"""
|
||||
Activate the validator of the given ``index``.
|
||||
Note that this function mutates ``state``.
|
||||
"""
|
||||
validator = state.validator_registry[index]
|
||||
|
||||
if is_genesis:
|
||||
if state.slot == GENESIS_SLOT:
|
||||
validator.activation_eligibility_epoch = GENESIS_EPOCH
|
||||
validator.activation_epoch = GENESIS_EPOCH
|
||||
else:
|
||||
|
@ -1435,7 +1435,7 @@ def get_genesis_beacon_state(genesis_validator_deposits: List[Deposit],
|
|||
# Finality
|
||||
previous_epoch_attestations=[],
|
||||
current_epoch_attestations=[],
|
||||
previous_justified_epoch=GENESIS_EPOCH - 1,
|
||||
previous_justified_epoch=GENESIS_EPOCH,
|
||||
current_justified_epoch=GENESIS_EPOCH,
|
||||
previous_justified_root=ZERO_HASH,
|
||||
current_justified_root=ZERO_HASH,
|
||||
|
@ -1465,7 +1465,7 @@ def get_genesis_beacon_state(genesis_validator_deposits: List[Deposit],
|
|||
# Process genesis activations
|
||||
for index in range(len(state.validator_registry)):
|
||||
if get_effective_balance(state, index) >= MAX_DEPOSIT_AMOUNT:
|
||||
activate_validator(state, index, is_genesis=True)
|
||||
activate_validator(state, index)
|
||||
|
||||
genesis_active_index_root = hash_tree_root(get_active_validator_indices(state, GENESIS_EPOCH))
|
||||
for index in range(LATEST_ACTIVE_INDEX_ROOTS_LENGTH):
|
||||
|
@ -1488,7 +1488,7 @@ For a beacon chain block, `block`, to be processed by a node, the following cond
|
|||
|
||||
* The parent block with root `block.previous_block_root` has been processed and accepted.
|
||||
* An Ethereum 1.0 block pointed to by the `state.latest_eth1_data.block_hash` has been processed and accepted.
|
||||
* The node's Unix time is greater than or equal to `state.genesis_time + (block.slot - GENESIS_SLOT) * SECONDS_PER_SLOT`. (Note that leap seconds mean that slots will occasionally last `SECONDS_PER_SLOT + 1` or `SECONDS_PER_SLOT - 1` seconds, possibly several times a year.)
|
||||
* The node's Unix time is greater than or equal to `state.genesis_time + block.slot * SECONDS_PER_SLOT`. (Note that leap seconds mean that slots will occasionally last `SECONDS_PER_SLOT + 1` or `SECONDS_PER_SLOT - 1` seconds, possibly several times a year.)
|
||||
|
||||
If these conditions are not met, the client should delay processing the beacon block until the conditions are all satisfied.
|
||||
|
||||
|
@ -1575,17 +1575,17 @@ At every `slot > GENESIS_SLOT` run the following function:
|
|||
|
||||
```python
|
||||
def cache_state(state: BeaconState) -> None:
|
||||
previous_slot_state_root = hash_tree_root(state)
|
||||
# Cache latest known state root (for previous slot)
|
||||
latest_state_root = hash_tree_root(state)
|
||||
state.latest_state_roots[state.slot % SLOTS_PER_HISTORICAL_ROOT] = latest_state_root
|
||||
|
||||
# store the previous slot's post state transition root
|
||||
state.latest_state_roots[state.slot % SLOTS_PER_HISTORICAL_ROOT] = previous_slot_state_root
|
||||
|
||||
# cache state root in stored latest_block_header if empty
|
||||
# Store latest known state root (for previous slot) in latest_block_header if it is empty
|
||||
if state.latest_block_header.state_root == ZERO_HASH:
|
||||
state.latest_block_header.state_root = previous_slot_state_root
|
||||
state.latest_block_header.state_root = latest_state_root
|
||||
|
||||
# store latest known block for previous slot
|
||||
state.latest_block_roots[state.slot % SLOTS_PER_HISTORICAL_ROOT] = signing_root(state.latest_block_header)
|
||||
# Cache latest known block root (for previous slot)
|
||||
latest_block_root = signing_root(state.latest_block_header)
|
||||
state.latest_block_roots[state.slot % SLOTS_PER_HISTORICAL_ROOT] = latest_block_root
|
||||
```
|
||||
|
||||
### Per-epoch processing
|
||||
|
@ -1680,6 +1680,9 @@ Run the following function:
|
|||
|
||||
```python
|
||||
def update_justification_and_finalization(state: BeaconState) -> None:
|
||||
if get_current_epoch(state) <= GENESIS_EPOCH + 1:
|
||||
return
|
||||
|
||||
antepenultimate_justified_epoch = state.previous_justified_epoch
|
||||
|
||||
# Process justifications
|
||||
|
@ -1724,9 +1727,8 @@ Run the following function:
|
|||
|
||||
```python
|
||||
def process_crosslinks(state: BeaconState) -> None:
|
||||
current_epoch = get_current_epoch(state)
|
||||
previous_epoch = max(current_epoch - 1, GENESIS_EPOCH)
|
||||
next_epoch = current_epoch + 1
|
||||
previous_epoch = get_previous_epoch(state)
|
||||
next_epoch = get_current_epoch(state) + 1
|
||||
for slot in range(get_epoch_start_slot(previous_epoch), get_epoch_start_slot(next_epoch)):
|
||||
for crosslink_committee, shard in get_crosslink_committees_at_slot(state, slot):
|
||||
winning_root, participants = get_winning_root_and_participants(state, shard)
|
||||
|
@ -1845,6 +1847,9 @@ Run the following:
|
|||
|
||||
```python
|
||||
def apply_rewards(state: BeaconState) -> None:
|
||||
if get_current_epoch(state) == GENESIS_EPOCH:
|
||||
return
|
||||
|
||||
rewards1, penalties1 = get_justification_and_finalization_deltas(state)
|
||||
rewards2, penalties2 = get_crosslink_deltas(state)
|
||||
for i in range(len(state.validator_registry)):
|
||||
|
@ -2100,8 +2105,7 @@ def process_attestation(state: BeaconState, attestation: Attestation) -> None:
|
|||
Process ``Attestation`` operation.
|
||||
Note that this function mutates ``state``.
|
||||
"""
|
||||
assert max(GENESIS_SLOT, state.slot - SLOTS_PER_EPOCH) <= attestation.data.slot
|
||||
assert attestation.data.slot <= state.slot - MIN_ATTESTATION_INCLUSION_DELAY
|
||||
assert attestation.data.slot + MIN_ATTESTATION_INCLUSION_DELAY <= state.slot <= attestation.data.slot + SLOTS_PER_EPOCH
|
||||
|
||||
# Check target epoch, source epoch, and source root
|
||||
target_epoch = slot_to_epoch(attestation.data.slot)
|
||||
|
|
|
@ -9,6 +9,7 @@ from eth2spec.phase0.spec import (
|
|||
)
|
||||
from tests.helpers import (
|
||||
get_valid_attester_slashing,
|
||||
next_epoch,
|
||||
)
|
||||
|
||||
# mark entire file as 'attester_slashing'
|
||||
|
@ -58,6 +59,8 @@ def test_success_double(state):
|
|||
|
||||
|
||||
def test_success_surround(state):
|
||||
next_epoch(state)
|
||||
state.current_justified_epoch += 1
|
||||
attester_slashing = get_valid_attester_slashing(state)
|
||||
|
||||
# set attestion1 to surround attestation 2
|
||||
|
|
|
@ -14,7 +14,6 @@ MINIMAL_CONFIG = {
|
|||
"MIN_ATTESTATION_INCLUSION_DELAY": 2,
|
||||
"TARGET_COMMITTEE_SIZE": 4,
|
||||
"SLOTS_PER_EPOCH": 8,
|
||||
"GENESIS_EPOCH": spec.GENESIS_SLOT // 8,
|
||||
"SLOTS_PER_HISTORICAL_ROOT": 64,
|
||||
"LATEST_RANDAO_MIXES_LENGTH": 64,
|
||||
"LATEST_ACTIVE_INDEX_ROOTS_LENGTH": 64,
|
||||
|
|
|
@ -33,6 +33,8 @@ from eth2spec.phase0.spec import (
|
|||
get_empty_block,
|
||||
get_epoch_start_slot,
|
||||
get_genesis_beacon_state,
|
||||
get_previous_epoch,
|
||||
get_shard_delta,
|
||||
slot_to_epoch,
|
||||
verify_merkle_branch,
|
||||
hash,
|
||||
|
@ -49,6 +51,19 @@ pubkeys = [bls.privtopub(privkey) for privkey in privkeys]
|
|||
pubkey_to_privkey = {pubkey: privkey for privkey, pubkey in zip(privkeys, pubkeys)}
|
||||
|
||||
|
||||
def set_bitfield_bit(bitfield, i):
|
||||
"""
|
||||
Set the bit in ``bitfield`` at position ``i`` to ``1``.
|
||||
"""
|
||||
byte_index = i // 8
|
||||
bit_index = i % 8
|
||||
return (
|
||||
bitfield[:byte_index] +
|
||||
bytes([bitfield[byte_index] | (1 << bit_index)]) +
|
||||
bitfield[byte_index+1:]
|
||||
)
|
||||
|
||||
|
||||
def create_mock_genesis_validator_deposits(num_validators, deposit_data_leaves=None):
|
||||
if not deposit_data_leaves:
|
||||
deposit_data_leaves = []
|
||||
|
@ -132,24 +147,31 @@ def build_deposit_data(state, pubkey, privkey, amount):
|
|||
def build_attestation_data(state, slot, shard):
|
||||
assert state.slot >= slot
|
||||
|
||||
block_root = build_empty_block_for_next_slot(state).previous_block_root
|
||||
if slot == state.slot:
|
||||
block_root = build_empty_block_for_next_slot(state).previous_block_root
|
||||
else:
|
||||
block_root = get_block_root(state, slot)
|
||||
|
||||
epoch_start_slot = get_epoch_start_slot(get_current_epoch(state))
|
||||
if epoch_start_slot == slot:
|
||||
current_epoch_start_slot = get_epoch_start_slot(get_current_epoch(state))
|
||||
if slot < current_epoch_start_slot:
|
||||
epoch_boundary_root = get_block_root(state, get_epoch_start_slot(get_previous_epoch(state)))
|
||||
elif slot == current_epoch_start_slot:
|
||||
epoch_boundary_root = block_root
|
||||
else:
|
||||
get_block_root(state, epoch_start_slot)
|
||||
epoch_boundary_root = get_block_root(state, current_epoch_start_slot)
|
||||
|
||||
if slot < epoch_start_slot:
|
||||
if slot < current_epoch_start_slot:
|
||||
justified_epoch = state.previous_justified_epoch
|
||||
justified_block_root = state.previous_justified_root
|
||||
else:
|
||||
justified_epoch = state.current_justified_epoch
|
||||
justified_block_root = state.current_justified_root
|
||||
|
||||
return AttestationData(
|
||||
slot=slot,
|
||||
shard=shard,
|
||||
beacon_block_root=block_root,
|
||||
source_epoch=state.current_justified_epoch,
|
||||
source_epoch=justified_epoch,
|
||||
source_root=justified_block_root,
|
||||
target_root=epoch_boundary_root,
|
||||
crosslink_data_root=spec.ZERO_HASH,
|
||||
|
@ -254,7 +276,13 @@ def get_valid_attester_slashing(state):
|
|||
def get_valid_attestation(state, slot=None):
|
||||
if slot is None:
|
||||
slot = state.slot
|
||||
shard = state.latest_start_shard
|
||||
|
||||
if slot_to_epoch(slot) == get_current_epoch(state):
|
||||
shard = (state.latest_start_shard + slot) % spec.SLOTS_PER_EPOCH
|
||||
else:
|
||||
previous_shard_delta = get_shard_delta(state, get_previous_epoch(state))
|
||||
shard = (state.latest_start_shard - previous_shard_delta + slot) % spec.SHARD_COUNT
|
||||
|
||||
attestation_data = build_attestation_data(state, slot, shard)
|
||||
|
||||
crosslink_committee = get_crosslink_committee_for_attestation(state, attestation_data)
|
||||
|
@ -308,6 +336,18 @@ def get_attestation_signature(state, attestation_data, privkey, custody_bit=0b0)
|
|||
)
|
||||
|
||||
|
||||
def fill_aggregate_attestation(state, attestation):
|
||||
crosslink_committee = get_crosslink_committee_for_attestation(state, attestation.data)
|
||||
for i in range(len(crosslink_committee)):
|
||||
attestation.aggregation_bitfield = set_bitfield_bit(attestation.aggregation_bitfield, i)
|
||||
|
||||
|
||||
def next_slot(state):
|
||||
block = build_empty_block_for_next_slot(state)
|
||||
state_transition(state, block)
|
||||
|
||||
|
||||
def next_epoch(state):
|
||||
block = build_empty_block_for_next_slot(state)
|
||||
block.slot += spec.SLOTS_PER_EPOCH - (state.slot % spec.SLOTS_PER_EPOCH)
|
||||
state_transition(state, block)
|
||||
|
|
|
@ -39,9 +39,11 @@ from eth2spec.utils.merkle_minimal import (
|
|||
from .helpers import (
|
||||
build_deposit_data,
|
||||
build_empty_block_for_next_slot,
|
||||
fill_aggregate_attestation,
|
||||
get_valid_attestation,
|
||||
get_valid_attester_slashing,
|
||||
get_valid_proposer_slashing,
|
||||
next_slot,
|
||||
privkeys,
|
||||
pubkeys,
|
||||
)
|
||||
|
@ -51,6 +53,33 @@ from .helpers import (
|
|||
pytestmark = pytest.mark.sanity
|
||||
|
||||
|
||||
def check_finality(state,
|
||||
prev_state,
|
||||
current_justified_changed,
|
||||
previous_justified_changed,
|
||||
finalized_changed):
|
||||
if current_justified_changed:
|
||||
assert state.current_justified_epoch > prev_state.current_justified_epoch
|
||||
assert state.current_justified_root != prev_state.current_justified_root
|
||||
else:
|
||||
assert state.current_justified_epoch == prev_state.current_justified_epoch
|
||||
assert state.current_justified_root == prev_state.current_justified_root
|
||||
|
||||
if previous_justified_changed:
|
||||
assert state.previous_justified_epoch > prev_state.previous_justified_epoch
|
||||
assert state.previous_justified_root != prev_state.previous_justified_root
|
||||
else:
|
||||
assert state.previous_justified_epoch == prev_state.previous_justified_epoch
|
||||
assert state.previous_justified_root == prev_state.previous_justified_root
|
||||
|
||||
if finalized_changed:
|
||||
assert state.finalized_epoch > prev_state.finalized_epoch
|
||||
assert state.finalized_root != prev_state.finalized_root
|
||||
else:
|
||||
assert state.finalized_epoch == prev_state.finalized_epoch
|
||||
assert state.finalized_root == prev_state.finalized_root
|
||||
|
||||
|
||||
def test_slot_transition(state):
|
||||
test_state = deepcopy(state)
|
||||
cache_state(test_state)
|
||||
|
@ -115,6 +144,33 @@ def test_empty_epoch_transition_not_finalizing(state):
|
|||
return state, [block], test_state
|
||||
|
||||
|
||||
def test_full_attestations_finalizing(state):
|
||||
test_state = deepcopy(state)
|
||||
|
||||
for slot in range(spec.MIN_ATTESTATION_INCLUSION_DELAY):
|
||||
next_slot(test_state)
|
||||
|
||||
for epoch in range(5):
|
||||
for slot in range(spec.SLOTS_PER_EPOCH):
|
||||
print(test_state.slot)
|
||||
attestation = get_valid_attestation(test_state, test_state.slot - spec.MIN_ATTESTATION_INCLUSION_DELAY)
|
||||
fill_aggregate_attestation(test_state, attestation)
|
||||
block = build_empty_block_for_next_slot(test_state)
|
||||
block.body.attestations.append(attestation)
|
||||
state_transition(test_state, block)
|
||||
|
||||
if epoch == 0:
|
||||
check_finality(test_state, state, False, False, False)
|
||||
elif epoch == 1:
|
||||
check_finality(test_state, state, False, False, False)
|
||||
elif epoch == 2:
|
||||
check_finality(test_state, state, True, False, False)
|
||||
elif epoch == 3:
|
||||
check_finality(test_state, state, True, True, False)
|
||||
elif epoch == 4:
|
||||
check_finality(test_state, state, True, True, True)
|
||||
|
||||
|
||||
def test_proposer_slashing(state):
|
||||
test_state = deepcopy(state)
|
||||
proposer_slashing = get_valid_proposer_slashing(state)
|
||||
|
|
Loading…
Reference in New Issue