mirror of
https://github.com/status-im/eth2.0-specs.git
synced 2025-01-13 12:14:19 +00:00
Update 0_beacon-chain.md
This commit is contained in:
parent
8c5f7a571d
commit
fbaf771b1a
@ -77,7 +77,7 @@
|
|||||||
- [`get_beacon_proposer_index`](#get_beacon_proposer_index)
|
- [`get_beacon_proposer_index`](#get_beacon_proposer_index)
|
||||||
- [`verify_merkle_branch`](#verify_merkle_branch)
|
- [`verify_merkle_branch`](#verify_merkle_branch)
|
||||||
- [`get_crosslink_committee_for_attestation`](#get_crosslink_committee_for_attestation)
|
- [`get_crosslink_committee_for_attestation`](#get_crosslink_committee_for_attestation)
|
||||||
- [`get_attestation_participants`](#get_attestation_participants)
|
- [`get_attesting_indices`](#get_attesting_indices)
|
||||||
- [`int_to_bytes1`, `int_to_bytes2`, ...](#int_to_bytes1-int_to_bytes2-)
|
- [`int_to_bytes1`, `int_to_bytes2`, ...](#int_to_bytes1-int_to_bytes2-)
|
||||||
- [`bytes_to_int`](#bytes_to_int)
|
- [`bytes_to_int`](#bytes_to_int)
|
||||||
- [`get_effective_balance`](#get_effective_balance)
|
- [`get_effective_balance`](#get_effective_balance)
|
||||||
@ -180,7 +180,7 @@ These configurations are updated for releases, but may be out of sync during `de
|
|||||||
| - | - |
|
| - | - |
|
||||||
| `SHARD_COUNT` | `2**10` (= 1,024) |
|
| `SHARD_COUNT` | `2**10` (= 1,024) |
|
||||||
| `TARGET_COMMITTEE_SIZE` | `2**7` (= 128) |
|
| `TARGET_COMMITTEE_SIZE` | `2**7` (= 128) |
|
||||||
| `MAX_ATTESTATION_PARTICIPANTS` | `2**12` (= 4,096) |
|
| `MAX_INDICES_PER_ATTESTATION` | `2**12` (= 4,096) |
|
||||||
| `MIN_PER_EPOCH_CHURN_LIMIT` | `2**2` (= 4) |
|
| `MIN_PER_EPOCH_CHURN_LIMIT` | `2**2` (= 4) |
|
||||||
| `CHURN_LIMIT_QUOTIENT` | `2**16` (= 65,536) |
|
| `CHURN_LIMIT_QUOTIENT` | `2**16` (= 65,536) |
|
||||||
| `SHUFFLE_ROUND_COUNT` | 90 |
|
| `SHUFFLE_ROUND_COUNT` | 90 |
|
||||||
@ -303,10 +303,10 @@ The types are defined topologically to aid in facilitating an executable version
|
|||||||
{
|
{
|
||||||
# Epoch number
|
# Epoch number
|
||||||
'epoch': 'uint64',
|
'epoch': 'uint64',
|
||||||
# Shard data since the previous crosslink
|
|
||||||
'crosslink_data_root': 'bytes32',
|
|
||||||
# Root of the previous crosslink
|
# Root of the previous crosslink
|
||||||
'previous_crosslink_root': 'bytes32',
|
'previous_crosslink_root': 'bytes32',
|
||||||
|
# Shard data since the previous crosslink
|
||||||
|
'crosslink_data_root': 'bytes32',
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -1023,14 +1023,14 @@ def get_crosslink_committee_for_attestation(state: BeaconState,
|
|||||||
return crosslink_committee
|
return crosslink_committee
|
||||||
```
|
```
|
||||||
|
|
||||||
### `get_attestation_participants`
|
### `get_attesting_indices`
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def get_attestation_participants(state: BeaconState,
|
def get_attesting_indices(state: BeaconState,
|
||||||
attestation_data: AttestationData,
|
attestation_data: AttestationData,
|
||||||
bitfield: bytes) -> List[ValidatorIndex]:
|
bitfield: bytes) -> List[ValidatorIndex]:
|
||||||
"""
|
"""
|
||||||
Return the sorted participant indices corresponding to ``attestation_data`` and ``bitfield``.
|
Return the sorted attesting indices corresponding to ``attestation_data`` and ``bitfield``.
|
||||||
"""
|
"""
|
||||||
crosslink_committee = get_crosslink_committee_for_attestation(state, attestation_data)
|
crosslink_committee = get_crosslink_committee_for_attestation(state, attestation_data)
|
||||||
assert verify_bitfield(bitfield, len(crosslink_committee))
|
assert verify_bitfield(bitfield, len(crosslink_committee))
|
||||||
@ -1129,8 +1129,8 @@ def convert_to_indexed(state: BeaconState, attestation: Attestation) -> IndexedA
|
|||||||
"""
|
"""
|
||||||
Convert ``attestation`` to (almost) indexed-verifiable form.
|
Convert ``attestation`` to (almost) indexed-verifiable form.
|
||||||
"""
|
"""
|
||||||
attesting_indices = get_attestation_participants(state, attestation.data, attestation.aggregation_bitfield)
|
attesting_indices = get_attesting_indices(state, attestation.data, attestation.aggregation_bitfield)
|
||||||
custody_bit_1_indices = get_attestation_participants(state, attestation.data, attestation.custody_bitfield)
|
custody_bit_1_indices = get_attesting_indices(state, attestation.data, attestation.custody_bitfield)
|
||||||
custody_bit_0_indices = [index for index in attesting_indices if index not in custody_bit_1_indices]
|
custody_bit_0_indices = [index for index in attesting_indices if index not in custody_bit_1_indices]
|
||||||
|
|
||||||
return IndexedAttestation(
|
return IndexedAttestation(
|
||||||
@ -1151,14 +1151,13 @@ def verify_indexed_attestation(state: BeaconState, indexed_attestation: IndexedA
|
|||||||
custody_bit_0_indices = indexed_attestation.custody_bit_0_indices
|
custody_bit_0_indices = indexed_attestation.custody_bit_0_indices
|
||||||
custody_bit_1_indices = indexed_attestation.custody_bit_1_indices
|
custody_bit_1_indices = indexed_attestation.custody_bit_1_indices
|
||||||
|
|
||||||
# ensure no duplicate indices across custody bits
|
# Ensure no duplicate indices across custody bits
|
||||||
assert len(set(custody_bit_0_indices).intersection(set(custody_bit_1_indices))) == 0
|
assert len(set(custody_bit_0_indices).intersection(set(custody_bit_1_indices))) == 0
|
||||||
|
|
||||||
if len(custody_bit_1_indices) > 0: # [TO BE REMOVED IN PHASE 1]
|
if len(custody_bit_1_indices) > 0: # [TO BE REMOVED IN PHASE 1]
|
||||||
return False
|
return False
|
||||||
|
|
||||||
total_attesting_indices = len(custody_bit_0_indices) + len(custody_bit_1_indices)
|
if not (1 <= len(custody_bit_0_indices) + len(custody_bit_1_indices) <= MAX_INDICES_PER_ATTESTATION):
|
||||||
if not (1 <= total_attesting_indices <= MAX_ATTESTATION_PARTICIPANTS):
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if custody_bit_0_indices != sorted(custody_bit_0_indices):
|
if custody_bit_0_indices != sorted(custody_bit_0_indices):
|
||||||
@ -1615,7 +1614,7 @@ def get_previous_total_balance(state: BeaconState) -> Gwei:
|
|||||||
def get_unslashed_attesting_indices(state: BeaconState, attestations: List[PendingAttestation]) -> List[ValidatorIndex]:
|
def get_unslashed_attesting_indices(state: BeaconState, attestations: List[PendingAttestation]) -> List[ValidatorIndex]:
|
||||||
output = set()
|
output = set()
|
||||||
for a in attestations:
|
for a in attestations:
|
||||||
output = output.union(get_attestation_participants(state, a.data, a.aggregation_bitfield))
|
output = output.union(get_attesting_indices(state, a.data, a.aggregation_bitfield))
|
||||||
return sorted(filter(lambda index: not state.validator_registry[index].slashed, list(output)))
|
return sorted(filter(lambda index: not state.validator_registry[index].slashed, list(output)))
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -1651,34 +1650,31 @@ def get_previous_epoch_matching_head_attestations(state: BeaconState) -> List[Pe
|
|||||||
**Note**: Total balances computed for the previous epoch might be marginally different than the actual total balances during the previous epoch transition. Due to the tight bound on validator churn each epoch and small per-epoch rewards/penalties, the potential balance difference is very low and only marginally affects consensus safety.
|
**Note**: Total balances computed for the previous epoch might be marginally different than the actual total balances during the previous epoch transition. Due to the tight bound on validator churn each epoch and small per-epoch rewards/penalties, the potential balance difference is very low and only marginally affects consensus safety.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def get_winning_root_and_participants(state: BeaconState, slot: Slot, shard: Shard) -> Tuple[Bytes32, Bytes32, List[ValidatorIndex]]:
|
def get_winning_crosslink_and_attesting_indices(state: BeaconState, epoch: Epoch, shard: Shard) -> Tuple[Crosslink, List[ValidatorIndex]]:
|
||||||
attestations = state.current_epoch_attestations if slot_to_epoch(slot) == get_current_epoch(state) else state.previous_epoch_attestations
|
pending_attestations = state.current_epoch_attestations if epoch == get_current_epoch(state) else state.previous_epoch_attestations
|
||||||
|
crosslink_data_roots = [(a.data.crosslink_data_root, a.data.previous_crosslink_root) for a in pending_attestations if a.data.shard == shard]
|
||||||
valid_attestations = [a for a in attestations if a.data.shard == shard]
|
|
||||||
all_roots = [(a.data.crosslink_data_root, a.data.previous_crosslink_root) for a in valid_attestations]
|
|
||||||
|
|
||||||
# handle when no attestations for shard available
|
|
||||||
if len(all_roots) == 0:
|
|
||||||
return ZERO_HASH, ZERO_HASH, []
|
|
||||||
|
|
||||||
def get_attestations_for(root) -> List[PendingAttestation]:
|
def get_attestations_for(root) -> List[PendingAttestation]:
|
||||||
return [a for a in valid_attestations if a.data.crosslink_data_root == root]
|
return [a for a in valid_attestations if a.data.shard == shard and a.data.crosslink_data_root == root]
|
||||||
|
|
||||||
# Winning crosslink root is the root with the most votes for it, ties broken in favor of
|
# Winning crosslink data root is the root with the most votes for it (ties broken lexicographically)
|
||||||
# lexicographically higher hash
|
crosslink_data_root, previous_crosslink_root = max(crosslink_data_roots,
|
||||||
winning_root, previous_crosslink_root = max(all_roots, key=lambda r: (get_attesting_balance(state, get_attestations_for(r[0])), r[0]))
|
key=lambda r: (get_attesting_balance(state, get_attestations_for(r[0])), r[0]),
|
||||||
|
default=ZERO_HASH, ZERO_HASH
|
||||||
return (
|
|
||||||
winning_root,
|
|
||||||
previous_crosslink_root,
|
|
||||||
get_unslashed_attesting_indices(state, get_attestations_for(winning_root)),
|
|
||||||
)
|
)
|
||||||
|
winning_crosslink = Crosslink(
|
||||||
|
epoch=min(epoch, state.current_crosslinks[shard].epoch + MAX_CROSSLINK_EPOCHS),
|
||||||
|
crosslink_data_root=crosslink_data_root,
|
||||||
|
previous_crosslink_root=previous_crosslink_root,
|
||||||
|
)
|
||||||
|
|
||||||
|
return winning_crosslink, get_unslashed_attesting_indices(state, get_attestations_for(crosslink_data_root))
|
||||||
```
|
```
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def get_earliest_attestation(state: BeaconState, attestations: List[PendingAttestation], index: ValidatorIndex) -> PendingAttestation:
|
def get_earliest_attestation(state: BeaconState, attestations: List[PendingAttestation], index: ValidatorIndex) -> PendingAttestation:
|
||||||
return min([
|
return min([
|
||||||
a for a in attestations if index in get_attestation_participants(state, a.data, a.aggregation_bitfield)
|
a for a in attestations if index in get_attesting_indices(state, a.data, a.aggregation_bitfield)
|
||||||
], key=lambda a: a.inclusion_slot)
|
], key=lambda a: a.inclusion_slot)
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -1735,22 +1731,18 @@ Run the following function:
|
|||||||
|
|
||||||
```python
|
```python
|
||||||
def process_crosslinks(state: BeaconState) -> None:
|
def process_crosslinks(state: BeaconState) -> None:
|
||||||
state.previous_crosslinks = [crosslink for crosslink in state.current_crosslinks]
|
state.previous_crosslinks = state.current_crosslinks
|
||||||
|
|
||||||
previous_epoch = get_previous_epoch(state)
|
for slot in range(get_epoch_start_slot(get_previous_epoch(state)), get_epoch_start_slot(get_current_epoch(state) + 1)):
|
||||||
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):
|
for crosslink_committee, shard in get_crosslink_committees_at_slot(state, slot):
|
||||||
winning_root, previous_crosslink_root, participants = get_winning_root_and_participants(state, slot, shard)
|
winning_crosslink, attesting_indices = get_winning_crosslink_and_attesting_indices(state, slot, shard)
|
||||||
expected_crosslink_root = hash_tree_root(state.current_crosslinks[shard])
|
attesting_balance = get_total_balance(state, attesting_indices)
|
||||||
participating_balance = get_total_balance(state, participants)
|
committee_balance = get_total_balance(state, crosslink_committee)
|
||||||
total_balance = get_total_balance(state, crosslink_committee)
|
if (
|
||||||
if previous_crosslink_root == expected_crosslink_root and 3 * participating_balance >= 2 * total_balance:
|
winning_crosslink.previous_crosslink_root == hash_tree_root(state.current_crosslinks[shard]) and
|
||||||
state.current_crosslinks[shard] = Crosslink(
|
3 * attesting_balance >= 2 * committee_balance
|
||||||
epoch=min(slot_to_epoch(slot), state.current_crosslinks[shard].epoch + MAX_CROSSLINK_EPOCHS),
|
):
|
||||||
crosslink_data_root=winning_root,
|
state.current_crosslinks[shard] = winning_crosslink
|
||||||
previous_crosslink_root=previous_crosslink_root,
|
|
||||||
)
|
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Rewards and penalties
|
#### Rewards and penalties
|
||||||
@ -1838,23 +1830,22 @@ def get_justification_and_finalization_deltas(state: BeaconState) -> Tuple[List[
|
|||||||
def get_crosslink_deltas(state: BeaconState) -> Tuple[List[Gwei], List[Gwei]]:
|
def get_crosslink_deltas(state: BeaconState) -> Tuple[List[Gwei], List[Gwei]]:
|
||||||
rewards = [0 for index in range(len(state.validator_registry))]
|
rewards = [0 for index in range(len(state.validator_registry))]
|
||||||
penalties = [0 for index in range(len(state.validator_registry))]
|
penalties = [0 for index in range(len(state.validator_registry))]
|
||||||
previous_epoch_start_slot = get_epoch_start_slot(get_previous_epoch(state))
|
for slot in range(get_epoch_start_slot(get_previous_epoch(state)), get_epoch_start_slot(get_current_epoch(state))):
|
||||||
current_epoch_start_slot = get_epoch_start_slot(get_current_epoch(state))
|
|
||||||
for slot in range(previous_epoch_start_slot, current_epoch_start_slot):
|
|
||||||
for crosslink_committee, shard in get_crosslink_committees_at_slot(state, slot):
|
for crosslink_committee, shard in get_crosslink_committees_at_slot(state, slot):
|
||||||
winning_root, previous_crosslink_root, participants = get_winning_root_and_participants(state, slot, shard)
|
winning_crosslink, attesting_indices = get_winning_crosslink_and_attesting_indices(state, slot, shard)
|
||||||
|
|
||||||
# do not count as success if winning_root did not or cannot form a chain
|
# Do not count as success if winning_crosslink did not or cannot form a chain
|
||||||
attempted_crosslink = Crosslink(epoch=slot_to_epoch(slot), crosslink_data_root=winning_root, previous_crosslink_root=previous_crosslink_root)
|
if not hash_tree_root(state.previous_crosslinks[shard]) in (
|
||||||
actual_crosslink_root = hash_tree_root(state.previous_crosslinks[shard])
|
winning_crosslink.previous_crosslink_root,
|
||||||
if not actual_crosslink_root in {previous_crosslink_root, hash_tree_root(attempted_crosslink)}:
|
hash_tree_root(winning_crosslink)
|
||||||
participants = []
|
):
|
||||||
|
attesting_indices = []
|
||||||
|
|
||||||
participating_balance = get_total_balance(state, participants)
|
attesting_balance = get_total_balance(state, attesting_indices)
|
||||||
total_balance = get_total_balance(state, crosslink_committee)
|
committee_balance = get_total_balance(state, crosslink_committee)
|
||||||
for index in crosslink_committee:
|
for index in crosslink_committee:
|
||||||
if index in participants:
|
if index in attesting_indices:
|
||||||
rewards[index] += get_base_reward(state, index) * participating_balance // total_balance
|
rewards[index] += get_base_reward(state, index) * attesting_balance // committee_balance
|
||||||
else:
|
else:
|
||||||
penalties[index] += get_base_reward(state, index)
|
penalties[index] += get_base_reward(state, index)
|
||||||
return [rewards, penalties]
|
return [rewards, penalties]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user