Merge branch 'master' into vbuterin-patch-18
This commit is contained in:
commit
0de7240452
|
@ -2,7 +2,9 @@
|
||||||
|
|
||||||
[![Join the chat at https://gitter.im/ethereum/sharding](https://badges.gitter.im/ethereum/sharding.svg)](https://gitter.im/ethereum/sharding?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
[![Join the chat at https://gitter.im/ethereum/sharding](https://badges.gitter.im/ethereum/sharding.svg)](https://gitter.im/ethereum/sharding?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||||
|
|
||||||
This repo hosts the current eth2.0 specifications. Discussions about design rationale and proposed changes can be brought up and discussed as issues. Solidified, agreed upon changes to spec can be made through pull requests.
|
To learn more about sharding and eth2.0/Serenity, see the [sharding FAQ](https://github.com/ethereum/wiki/wiki/Sharding-FAQs) and the [research compendium](https://notes.ethereum.org/s/H1PGqDhpm).
|
||||||
|
|
||||||
|
This repo hosts the current eth2.0 specifications. Discussions about design rationale and proposed changes can be brought up and discussed as issues. Solidified, agreed upon changes to spec can be made through pull requests.
|
||||||
|
|
||||||
# Specs
|
# Specs
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,9 @@
|
||||||
- [Helpers](#helpers)
|
- [Helpers](#helpers)
|
||||||
- [`hash_to_G2`](#hash_to_g2)
|
- [`hash_to_G2`](#hash_to_g2)
|
||||||
- [`modular_squareroot`](#modular_squareroot)
|
- [`modular_squareroot`](#modular_squareroot)
|
||||||
|
- [Aggregation operations](#aggregation-operations)
|
||||||
|
- [`bls_aggregate_pubkeys`](#bls_aggregate_pubkeys)
|
||||||
|
- [`bls_aggregate_signatures`](#bls_aggregate_signatures)
|
||||||
- [Signature verification](#signature-verification)
|
- [Signature verification](#signature-verification)
|
||||||
- [`bls_verify`](#bls_verify)
|
- [`bls_verify`](#bls_verify)
|
||||||
- [`bls_verify_multiple`](#bls_verify_multiple)
|
- [`bls_verify_multiple`](#bls_verify_multiple)
|
||||||
|
@ -99,6 +102,16 @@ def modular_squareroot(value: int) -> int:
|
||||||
return None
|
return None
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Aggregation operations
|
||||||
|
|
||||||
|
### `bls_aggregate_pubkeys`
|
||||||
|
|
||||||
|
Let `bls_aggregate_pubkeys(pubkeys: [uint384]) -> uint384` return `pubkeys[0] + .... + pubkeys[len(pubkeys)-1]`, where `+` is the elliptic curve addition operation over the G1 curve.
|
||||||
|
|
||||||
|
### `bls_aggregate_signatures`
|
||||||
|
|
||||||
|
Let `bls_aggregate_signatures(signatures: [[uint384]]) -> [uint384]` return `signatures[0] + .... + signatures[len(signatures)-1]`, where `+` is the elliptic curve addition operation over the G2 curve.
|
||||||
|
|
||||||
## Signature verification
|
## Signature verification
|
||||||
|
|
||||||
In the following `e` is the pairing function and `g` is the G1 generator with the following coordinates (see [here](https://github.com/zkcrypto/pairing/tree/master/src/bls12_381#g1)):
|
In the following `e` is the pairing function and `g` is the G1 generator with the following coordinates (see [here](https://github.com/zkcrypto/pairing/tree/master/src/bls12_381#g1)):
|
|
@ -65,7 +65,6 @@
|
||||||
- [`get_active_validator_indices`](#get_active_validator_indices)
|
- [`get_active_validator_indices`](#get_active_validator_indices)
|
||||||
- [`shuffle`](#shuffle)
|
- [`shuffle`](#shuffle)
|
||||||
- [`split`](#split)
|
- [`split`](#split)
|
||||||
- [`clamp`](#clamp)
|
|
||||||
- [`get_new_shuffling`](#get_new_shuffling)
|
- [`get_new_shuffling`](#get_new_shuffling)
|
||||||
- [`get_shard_committees_at_slot`](#get_shard_committees_at_slot)
|
- [`get_shard_committees_at_slot`](#get_shard_committees_at_slot)
|
||||||
- [`get_block_root`](#get_block_root)
|
- [`get_block_root`](#get_block_root)
|
||||||
|
@ -83,6 +82,7 @@
|
||||||
- [`integer_squareroot`](#integer_squareroot)
|
- [`integer_squareroot`](#integer_squareroot)
|
||||||
- [`bls_verify`](#bls_verify)
|
- [`bls_verify`](#bls_verify)
|
||||||
- [`bls_verify_multiple`](#bls_verify_multiple)
|
- [`bls_verify_multiple`](#bls_verify_multiple)
|
||||||
|
- [`bls_aggregate_pubkeys`](#bls_aggregate_pubkeys)
|
||||||
- [On startup](#on-startup)
|
- [On startup](#on-startup)
|
||||||
- [Routine for processing deposits](#routine-for-processing-deposits)
|
- [Routine for processing deposits](#routine-for-processing-deposits)
|
||||||
- [Routine for updating validator status](#routine-for-updating-validator-status)
|
- [Routine for updating validator status](#routine-for-updating-validator-status)
|
||||||
|
@ -147,7 +147,7 @@ Unless otherwise indicated, code appearing in `this style` is to be interpreted
|
||||||
* **Crosslink** - a set of signatures from a committee attesting to a block in a shard chain, which can be included into the beacon chain. Crosslinks are the main means by which the beacon chain "learns about" the updated state of shard chains.
|
* **Crosslink** - a set of signatures from a committee attesting to a block in a shard chain, which can be included into the beacon chain. Crosslinks are the main means by which the beacon chain "learns about" the updated state of shard chains.
|
||||||
* **Slot** - a period of `SLOT_DURATION` seconds, during which one proposer has the ability to create a beacon chain block and some attesters have the ability to make attestations
|
* **Slot** - a period of `SLOT_DURATION` seconds, during which one proposer has the ability to create a beacon chain block and some attesters have the ability to make attestations
|
||||||
* **Epoch** - an aligned span of slots during which all [validators](#dfn-validator) get exactly one chance to make an attestation
|
* **Epoch** - an aligned span of slots during which all [validators](#dfn-validator) get exactly one chance to make an attestation
|
||||||
* **Finalized**, **justified** - see Casper FFG finalization here: https://arxiv.org/abs/1710.09437
|
* **Finalized**, **justified** - see Casper FFG finalization [[casper-ffg]](#ref-casper-ffg)
|
||||||
* **Withdrawal period** - the number of slots between a [validator](#dfn-validator) exit and the [validator](#dfn-validator) balance being withdrawable
|
* **Withdrawal period** - the number of slots between a [validator](#dfn-validator) exit and the [validator](#dfn-validator) balance being withdrawable
|
||||||
* **Genesis time** - the Unix time of the genesis beacon chain block at slot 0
|
* **Genesis time** - the Unix time of the genesis beacon chain block at slot 0
|
||||||
|
|
||||||
|
@ -455,6 +455,7 @@ Unless otherwise indicated, code appearing in `this style` is to be interpreted
|
||||||
|
|
||||||
# Validator registry
|
# Validator registry
|
||||||
'validator_registry': [ValidatorRecord],
|
'validator_registry': [ValidatorRecord],
|
||||||
|
'validator_balances': ['uint64'],
|
||||||
'validator_registry_latest_change_slot': 'uint64',
|
'validator_registry_latest_change_slot': 'uint64',
|
||||||
'validator_registry_exit_count': 'uint64',
|
'validator_registry_exit_count': 'uint64',
|
||||||
'validator_registry_delta_chain_tip': 'hash32', # For light clients to track deltas
|
'validator_registry_delta_chain_tip': 'hash32', # For light clients to track deltas
|
||||||
|
@ -496,8 +497,6 @@ Unless otherwise indicated, code appearing in `this style` is to be interpreted
|
||||||
'randao_commitment': 'hash32',
|
'randao_commitment': 'hash32',
|
||||||
# Slots the proposer has skipped (i.e. layers of RANDAO expected)
|
# Slots the proposer has skipped (i.e. layers of RANDAO expected)
|
||||||
'randao_layers': 'uint64',
|
'randao_layers': 'uint64',
|
||||||
# Balance in Gwei
|
|
||||||
'balance': 'uint64',
|
|
||||||
# Status code
|
# Status code
|
||||||
'status': 'uint64',
|
'status': 'uint64',
|
||||||
# Slot when validator last changed status (or 0)
|
# Slot when validator last changed status (or 0)
|
||||||
|
@ -833,21 +832,6 @@ def split(values: List[Any], split_count: int) -> List[Any]:
|
||||||
]
|
]
|
||||||
```
|
```
|
||||||
|
|
||||||
#### `clamp`
|
|
||||||
|
|
||||||
```python
|
|
||||||
def clamp(minval: int, maxval: int, x: int) -> int:
|
|
||||||
"""
|
|
||||||
Clamps ``x`` between ``minval`` and ``maxval``.
|
|
||||||
"""
|
|
||||||
if x <= minval:
|
|
||||||
return minval
|
|
||||||
elif x >= maxval:
|
|
||||||
return maxval
|
|
||||||
else:
|
|
||||||
return x
|
|
||||||
```
|
|
||||||
|
|
||||||
#### `get_new_shuffling`
|
#### `get_new_shuffling`
|
||||||
|
|
||||||
```python
|
```python
|
||||||
|
@ -859,10 +843,12 @@ def get_new_shuffling(seed: Hash32,
|
||||||
"""
|
"""
|
||||||
active_validator_indices = get_active_validator_indices(validators)
|
active_validator_indices = get_active_validator_indices(validators)
|
||||||
|
|
||||||
committees_per_slot = clamp(
|
committees_per_slot = max(
|
||||||
1,
|
1,
|
||||||
SHARD_COUNT // EPOCH_LENGTH,
|
min(
|
||||||
len(active_validator_indices) // EPOCH_LENGTH // TARGET_COMMITTEE_SIZE,
|
SHARD_COUNT // EPOCH_LENGTH,
|
||||||
|
len(active_validator_indices) // EPOCH_LENGTH // TARGET_COMMITTEE_SIZE,
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
# Shuffle with seed
|
# Shuffle with seed
|
||||||
|
@ -975,11 +961,11 @@ def get_attestation_participants(state: BeaconState,
|
||||||
#### `get_effective_balance`
|
#### `get_effective_balance`
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def get_effective_balance(validator: ValidatorRecord) -> int:
|
def get_effective_balance(state: State, index: int) -> int:
|
||||||
"""
|
"""
|
||||||
Returns the effective balance (also known as "balance at stake") for the ``validator``.
|
Returns the effective balance (also known as "balance at stake") for a ``validator`` with the given ``index``.
|
||||||
"""
|
"""
|
||||||
return min(validator.balance, MAX_DEPOSIT * GWEI_PER_ETH)
|
return min(state.validator_balances[index], MAX_DEPOSIT * GWEI_PER_ETH)
|
||||||
```
|
```
|
||||||
|
|
||||||
#### `get_new_validator_registry_delta_chain_tip`
|
#### `get_new_validator_registry_delta_chain_tip`
|
||||||
|
@ -994,7 +980,7 @@ def get_new_validator_registry_delta_chain_tip(current_validator_registry_delta_
|
||||||
"""
|
"""
|
||||||
return hash_tree_root(
|
return hash_tree_root(
|
||||||
ValidatorRegistryDeltaBlock(
|
ValidatorRegistryDeltaBlock(
|
||||||
validator_registry_delta_chain_tip=current_validator_registry_delta_chain_tip,
|
latest_registry_delta_root=current_validator_registry_delta_chain_tip,
|
||||||
validator_index=validator_index,
|
validator_index=validator_index,
|
||||||
pubkey=pubkey,
|
pubkey=pubkey,
|
||||||
flag=flag,
|
flag=flag,
|
||||||
|
@ -1102,11 +1088,15 @@ def integer_squareroot(n: int) -> int:
|
||||||
|
|
||||||
#### `bls_verify`
|
#### `bls_verify`
|
||||||
|
|
||||||
`bls_verify` is a function for verifying a BLS12-381 signature, defined in the [BLS Verification spec](https://github.com/ethereum/eth2.0-specs/blob/master/specs/bls_verify.md#bls_verify).
|
`bls_verify` is a function for verifying a BLS12-381 signature, defined in the [BLS Signature spec](https://github.com/ethereum/eth2.0-specs/blob/master/specs/bls_signature.md#bls_verify).
|
||||||
|
|
||||||
#### `bls_verify_multiple`
|
#### `bls_verify_multiple`
|
||||||
|
|
||||||
`bls_verify_multiple` is a function for verifying a BLS12-381 signature constructed from multiple messages, defined in the [BLS Verification spec](https://github.com/ethereum/eth2.0-specs/blob/master/specs/bls_verify.md#bls_verify_multiple).
|
`bls_verify_multiple` is a function for verifying a BLS12-381 signature constructed from multiple messages, defined in the [BLS Signature spec](https://github.com/ethereum/eth2.0-specs/blob/master/specs/bls_signature.md#bls_verify_multiple).
|
||||||
|
|
||||||
|
#### `bls_aggregate_pubkeys`
|
||||||
|
|
||||||
|
`bls_aggregate_pubkeys` is a function for aggregating a BLS12-381 public keys into a single aggregate key, defined in the [BLS Signature spec](https://github.com/ethereum/eth2.0-specs/blob/master/specs/bls_signature.md#bls_aggregate_pubkeys).
|
||||||
|
|
||||||
### On startup
|
### On startup
|
||||||
|
|
||||||
|
@ -1119,8 +1109,8 @@ A valid block with slot `INITIAL_SLOT_NUMBER` (a "genesis block") has the follow
|
||||||
state_root=STARTUP_STATE_ROOT,
|
state_root=STARTUP_STATE_ROOT,
|
||||||
randao_reveal=ZERO_HASH,
|
randao_reveal=ZERO_HASH,
|
||||||
candidate_pow_receipt_root=ZERO_HASH,
|
candidate_pow_receipt_root=ZERO_HASH,
|
||||||
proposer_signature=EMPTY_SIGNATURE,
|
signature=EMPTY_SIGNATURE,
|
||||||
'body': BeaconBlockBody(
|
body=BeaconBlockBody(
|
||||||
proposer_slashings=[],
|
proposer_slashings=[],
|
||||||
casper_slashings=[],
|
casper_slashings=[],
|
||||||
attestations=[],
|
attestations=[],
|
||||||
|
@ -1148,6 +1138,7 @@ def get_initial_beacon_state(initial_validator_deposits: List[Deposit],
|
||||||
|
|
||||||
# Validator registry
|
# Validator registry
|
||||||
validator_registry=[],
|
validator_registry=[],
|
||||||
|
validator_balances=[],
|
||||||
validator_registry_latest_change_slot=INITIAL_SLOT_NUMBER,
|
validator_registry_latest_change_slot=INITIAL_SLOT_NUMBER,
|
||||||
validator_registry_exit_count=0,
|
validator_registry_exit_count=0,
|
||||||
validator_registry_delta_chain_tip=ZERO_HASH,
|
validator_registry_delta_chain_tip=ZERO_HASH,
|
||||||
|
@ -1186,11 +1177,11 @@ def get_initial_beacon_state(initial_validator_deposits: List[Deposit],
|
||||||
withdrawal_credentials=deposit.deposit_data.deposit_input.withdrawal_credentials,
|
withdrawal_credentials=deposit.deposit_data.deposit_input.withdrawal_credentials,
|
||||||
randao_commitment=deposit.deposit_data.deposit_input.randao_commitment
|
randao_commitment=deposit.deposit_data.deposit_input.randao_commitment
|
||||||
)
|
)
|
||||||
if state.validator_registry[index].balance >= MAX_DEPOSIT * GWEI_PER_ETH:
|
if get_effective_balance(state, validator_index) == MAX_DEPOSIT * GWEI_PER_ETH:
|
||||||
update_validator_status(state, index, ACTIVE)
|
update_validator_status(state, validator_index, ACTIVE)
|
||||||
|
|
||||||
# set initial committee shuffling
|
# set initial committee shuffling
|
||||||
initial_shuffling = get_new_shuffling(ZERO_HASH, initial_validator_registry, 0)
|
initial_shuffling = get_new_shuffling(ZERO_HASH, state.validator_registry, 0)
|
||||||
state.shard_committees_at_slots = initial_shuffling + initial_shuffling
|
state.shard_committees_at_slots = initial_shuffling + initial_shuffling
|
||||||
|
|
||||||
# set initial persistent shuffling
|
# set initial persistent shuffling
|
||||||
|
@ -1202,16 +1193,43 @@ def get_initial_beacon_state(initial_validator_deposits: List[Deposit],
|
||||||
|
|
||||||
### Routine for processing deposits
|
### Routine for processing deposits
|
||||||
|
|
||||||
First, a helper function:
|
First, two helper functions:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def min_empty_validator_index(validators: List[ValidatorRecord], current_slot: int) -> int:
|
def min_empty_validator_index(validators: List[ValidatorRecord],
|
||||||
for i, v in enumerate(validators):
|
validator_balances: List[int],
|
||||||
if v.balance == 0 and v.latest_status_change_slot + ZERO_BALANCE_VALIDATOR_TTL <= current_slot:
|
current_slot: int) -> int:
|
||||||
|
for i, (v, vbal) in enumerate(zip(validators, validator_balances)):
|
||||||
|
if vbal == 0 and v.latest_status_change_slot + ZERO_BALANCE_VALIDATOR_TTL <= current_slot:
|
||||||
return i
|
return i
|
||||||
return None
|
return None
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```python
|
||||||
|
def validate_proof_of_possession(state: BeaconState,
|
||||||
|
pubkey: int,
|
||||||
|
proof_of_possession: bytes,
|
||||||
|
withdrawal_credentials: Hash32,
|
||||||
|
randao_commitment: Hash32) -> bool:
|
||||||
|
proof_of_possession_data = DepositInput(
|
||||||
|
pubkey=pubkey,
|
||||||
|
withdrawal_credentials=withdrawal_credentials,
|
||||||
|
randao_commitment=randao_commitment,
|
||||||
|
proof_of_possession=EMPTY_SIGNATURE,
|
||||||
|
)
|
||||||
|
|
||||||
|
return bls_verify(
|
||||||
|
pubkey=pubkey,
|
||||||
|
message=hash_tree_root(proof_of_possession_data),
|
||||||
|
signature=proof_of_possession,
|
||||||
|
domain=get_domain(
|
||||||
|
state.fork_data,
|
||||||
|
state.slot,
|
||||||
|
DOMAIN_DEPOSIT,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
Now, to add a [validator](#dfn-validator) or top up an existing [validator](#dfn-validator)'s balance by some `deposit` amount:
|
Now, to add a [validator](#dfn-validator) or top up an existing [validator](#dfn-validator)'s balance by some `deposit` amount:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
|
@ -1225,23 +1243,15 @@ def process_deposit(state: BeaconState,
|
||||||
Process a deposit from Ethereum 1.0.
|
Process a deposit from Ethereum 1.0.
|
||||||
Note that this function mutates ``state``.
|
Note that this function mutates ``state``.
|
||||||
"""
|
"""
|
||||||
proof_of_possession_data = DepositInput(
|
# Validate the given `proof_of_possession`
|
||||||
pubkey=pubkey,
|
assert validate_proof_of_possession(
|
||||||
withdrawal_credentials=withdrawal_credentials,
|
state,
|
||||||
randao_commitment=randao_commitment,
|
pubkey,
|
||||||
proof_of_possession=EMPTY_SIGNATURE,
|
proof_of_possession,
|
||||||
|
withdrawal_credentials,
|
||||||
|
randao_commitment,
|
||||||
)
|
)
|
||||||
|
|
||||||
assert bls_verify(
|
|
||||||
pubkey=pubkey,
|
|
||||||
message=hash_tree_root(proof_of_possession_data),
|
|
||||||
signature=proof_of_possession,
|
|
||||||
domain=get_domain(
|
|
||||||
state.fork_data,
|
|
||||||
state.slot,
|
|
||||||
DOMAIN_DEPOSIT
|
|
||||||
)
|
|
||||||
)
|
|
||||||
validator_pubkeys = [v.pubkey for v in state.validator_registry]
|
validator_pubkeys = [v.pubkey for v in state.validator_registry]
|
||||||
|
|
||||||
if pubkey not in validator_pubkeys:
|
if pubkey not in validator_pubkeys:
|
||||||
|
@ -1251,25 +1261,25 @@ def process_deposit(state: BeaconState,
|
||||||
withdrawal_credentials=withdrawal_credentials,
|
withdrawal_credentials=withdrawal_credentials,
|
||||||
randao_commitment=randao_commitment,
|
randao_commitment=randao_commitment,
|
||||||
randao_layers=0,
|
randao_layers=0,
|
||||||
balance=deposit,
|
|
||||||
status=PENDING_ACTIVATION,
|
status=PENDING_ACTIVATION,
|
||||||
latest_status_change_slot=state.slot,
|
latest_status_change_slot=state.slot,
|
||||||
exit_count=0
|
exit_count=0
|
||||||
)
|
)
|
||||||
|
|
||||||
index = min_empty_validator_index(validators_copy)
|
index = min_empty_validator_index(state.validator_registry, state.validator_balances, state.slot)
|
||||||
if index is None:
|
if index is None:
|
||||||
state.validator_registry.append(validator)
|
state.validator_registry.append(validator)
|
||||||
index = len(validators_copy) - 1
|
state.validator_balances.append(deposit)
|
||||||
|
index = len(state.validator_registry) - 1
|
||||||
else:
|
else:
|
||||||
state.validator_registry[index] = validator
|
state.validator_registry[index] = validator
|
||||||
|
state.validator_balances[index] = deposit
|
||||||
else:
|
else:
|
||||||
# Increase balance by deposit
|
# Increase balance by deposit
|
||||||
index = validator_pubkeys.index(pubkey)
|
index = validator_pubkeys.index(pubkey)
|
||||||
validator = state.validator_registry[index]
|
assert state.validator_registry[index].withdrawal_credentials == withdrawal_credentials
|
||||||
assert validator.withdrawal_credentials == withdrawal_credentials
|
|
||||||
|
|
||||||
validator.balance += deposit
|
state.validator_balances[index] += deposit
|
||||||
|
|
||||||
return index
|
return index
|
||||||
```
|
```
|
||||||
|
@ -1310,7 +1320,7 @@ def activate_validator(state: BeaconState,
|
||||||
validator.status = ACTIVE
|
validator.status = ACTIVE
|
||||||
validator.latest_status_change_slot = state.slot
|
validator.latest_status_change_slot = state.slot
|
||||||
state.validator_registry_delta_chain_tip = get_new_validator_registry_delta_chain_tip(
|
state.validator_registry_delta_chain_tip = get_new_validator_registry_delta_chain_tip(
|
||||||
validator_registry_delta_chain_tip=state.validator_registry_delta_chain_tip,
|
current_validator_registry_delta_chain_tip=state.validator_registry_delta_chain_tip,
|
||||||
validator_index=index,
|
validator_index=index,
|
||||||
pubkey=validator.pubkey,
|
pubkey=validator.pubkey,
|
||||||
flag=ACTIVATION,
|
flag=ACTIVATION,
|
||||||
|
@ -1351,21 +1361,21 @@ def exit_validator(state: BeaconState,
|
||||||
validator.latest_status_change_slot = state.slot
|
validator.latest_status_change_slot = state.slot
|
||||||
|
|
||||||
if new_status == EXITED_WITH_PENALTY:
|
if new_status == EXITED_WITH_PENALTY:
|
||||||
state.latest_penalized_exit_balances[state.slot // COLLECTIVE_PENALTY_CALCULATION_PERIOD] += get_effective_balance(validator)
|
state.latest_penalized_exit_balances[state.slot // COLLECTIVE_PENALTY_CALCULATION_PERIOD] += get_effective_balance(state, index)
|
||||||
|
|
||||||
whistleblower = state.validator_registry[get_beacon_proposer_index(state, state.slot)]
|
whistleblower_index = get_beacon_proposer_index(state, state.slot)
|
||||||
whistleblower_reward = validator.balance // WHISTLEBLOWER_REWARD_QUOTIENT
|
whistleblower_reward = get_effective_balance(state, index) // WHISTLEBLOWER_REWARD_QUOTIENT
|
||||||
whistleblower.balance += whistleblower_reward
|
state.validator_balances[whistleblower_index] += whistleblower_reward
|
||||||
validator.balance -= whistleblower_reward
|
state.validator_balances[index] -= whistleblower_reward
|
||||||
|
|
||||||
if prev_status == EXITED_WITHOUT_PENALTY
|
if prev_status == EXITED_WITHOUT_PENALTY:
|
||||||
return
|
return
|
||||||
|
|
||||||
# The following updates only occur if not previous exited
|
# The following updates only occur if not previous exited
|
||||||
state.validator_registry_exit_count += 1
|
state.validator_registry_exit_count += 1
|
||||||
validator.exit_count = state.validator_registry_exit_count
|
validator.exit_count = state.validator_registry_exit_count
|
||||||
state.validator_registry_delta_chain_tip = get_new_validator_registry_delta_chain_tip(
|
state.validator_registry_delta_chain_tip = get_new_validator_registry_delta_chain_tip(
|
||||||
validator_registry_delta_chain_tip=state.validator_registry_delta_chain_tip,
|
current_validator_registry_delta_chain_tip=state.validator_registry_delta_chain_tip,
|
||||||
validator_index=index,
|
validator_index=index,
|
||||||
pubkey=validator.pubkey,
|
pubkey=validator.pubkey,
|
||||||
flag=EXIT
|
flag=EXIT
|
||||||
|
@ -1391,7 +1401,7 @@ Below are the processing steps that happen at every slot.
|
||||||
|
|
||||||
### Block roots
|
### Block roots
|
||||||
|
|
||||||
* Let `previous_block_root` be the `hash_tree_root` of the previous beacon block processed in the chain.
|
* Let `previous_block_root` be the `tree_hash_root` of the previous beacon block processed in the chain.
|
||||||
* Set `state.latest_block_roots[(state.slot - 1) % LATEST_BLOCK_ROOTS_LENGTH] = previous_block_root`.
|
* Set `state.latest_block_roots[(state.slot - 1) % LATEST_BLOCK_ROOTS_LENGTH] = previous_block_root`.
|
||||||
* If `state.slot % LATEST_BLOCK_ROOTS_LENGTH == 0` append `merkle_root(state.latest_block_roots)` to `state.batched_block_roots`.
|
* If `state.slot % LATEST_BLOCK_ROOTS_LENGTH == 0` append `merkle_root(state.latest_block_roots)` to `state.batched_block_roots`.
|
||||||
|
|
||||||
|
@ -1470,7 +1480,7 @@ For each `attestation` in `block.body.attestations`:
|
||||||
* Verify that either `attestation.data.latest_crosslink_root` or `attestation.data.shard_block_root` equals `state.latest_crosslinks[shard].shard_block_root`.
|
* Verify that either `attestation.data.latest_crosslink_root` or `attestation.data.shard_block_root` equals `state.latest_crosslinks[shard].shard_block_root`.
|
||||||
* `aggregate_signature` verification:
|
* `aggregate_signature` verification:
|
||||||
* Let `participants = get_attestation_participants(state, attestation.data, attestation.participation_bitfield)`.
|
* Let `participants = get_attestation_participants(state, attestation.data, attestation.participation_bitfield)`.
|
||||||
* Let `group_public_key = BLSAddPubkeys([state.validator_registry[v].pubkey for v in participants])`.
|
* Let `group_public_key = bls_aggregate_pubkeys([state.validator_registry[v].pubkey for v in participants])`.
|
||||||
* Verify that `bls_verify(pubkey=group_public_key, message=hash_tree_root(attestation.data) + bytes1(0), signature=attestation.aggregate_signature, domain=get_domain(state.fork_data, attestation.data.slot, DOMAIN_ATTESTATION))`.
|
* Verify that `bls_verify(pubkey=group_public_key, message=hash_tree_root(attestation.data) + bytes1(0), signature=attestation.aggregate_signature, domain=get_domain(state.fork_data, attestation.data.slot, DOMAIN_ATTESTATION))`.
|
||||||
* [TO BE REMOVED IN PHASE 1] Verify that `attestation.data.shard_block_root == ZERO_HASH`.
|
* [TO BE REMOVED IN PHASE 1] Verify that `attestation.data.shard_block_root == ZERO_HASH`.
|
||||||
* Append `PendingAttestationRecord(data=attestation.data, participation_bitfield=attestation.participation_bitfield, custody_bitfield=attestation.custody_bitfield, slot_included=state.slot)` to `state.latest_attestations`.
|
* Append `PendingAttestationRecord(data=attestation.data, participation_bitfield=attestation.participation_bitfield, custody_bitfield=attestation.custody_bitfield, slot_included=state.slot)` to `state.latest_attestations`.
|
||||||
|
@ -1532,51 +1542,46 @@ The steps below happen when `state.slot % EPOCH_LENGTH == 0`.
|
||||||
|
|
||||||
All [validators](#dfn-validator):
|
All [validators](#dfn-validator):
|
||||||
|
|
||||||
* Let `active_validators = [state.validator_registry[i] for i in get_active_validator_indices(state.validator_registry)]`.
|
* Let `active_validator_indices = get_active_validator_indices(state.validator_registry)`.
|
||||||
* Let `total_balance = sum([get_effective_balance(v) for v in active_validators])`.
|
* Let `total_balance = sum([get_effective_balance(state, i) for i in active_validator_indices])`.
|
||||||
|
|
||||||
[Validators](#dfn-Validator) attesting during the current epoch:
|
[Validators](#dfn-Validator) attesting during the current epoch:
|
||||||
|
|
||||||
* Let `this_epoch_attestations = [a for a in state.latest_attestations if state.slot - EPOCH_LENGTH <= a.data.slot < state.slot]`. (Note: this is the set of attestations of slots in the epoch `state.slot-EPOCH_LENGTH...state.slot-1`, _not_ attestations that got included in the chain during the epoch `state.slot-EPOCH_LENGTH...state.slot-1`.)
|
* Let `this_epoch_attestations = [a for a in state.latest_attestations if state.slot - EPOCH_LENGTH <= a.data.slot < state.slot]`. (Note: this is the set of attestations of slots in the epoch `state.slot-EPOCH_LENGTH...state.slot-1`, _not_ attestations that got included in the chain during the epoch `state.slot-EPOCH_LENGTH...state.slot-1`.)
|
||||||
|
|
||||||
* Validators justifying the epoch boundary block at the start of the current epoch:
|
* Validators justifying the epoch boundary block at the start of the current epoch:
|
||||||
|
|
||||||
* Let `this_epoch_boundary_attestations = [a for a in this_epoch_attestations if a.data.epoch_boundary_root == get_block_root(state, state.slot-EPOCH_LENGTH) and a.justified_slot == state.justified_slot]`.
|
* Let `this_epoch_boundary_attestations = [a for a in this_epoch_attestations if a.data.epoch_boundary_root == get_block_root(state, state.slot-EPOCH_LENGTH) and a.justified_slot == state.justified_slot]`.
|
||||||
* Let `this_epoch_boundary_attester_indices` be the union of the [validator](#dfn-validator) index sets given by `[get_attestation_participants(state, a.data, a.participation_bitfield) for a in this_epoch_boundary_attestations]`.
|
* Let `this_epoch_boundary_attester_indices` be the union of the [validator](#dfn-validator) index sets given by `[get_attestation_participants(state, a.data, a.participation_bitfield) for a in this_epoch_boundary_attestations]`.
|
||||||
* Let `this_epoch_boundary_attesters = [state.validator_registry[i] for indices in this_epoch_boundary_attester_indices for i in indices]`.
|
* Let `this_epoch_boundary_attesting_balance = sum([get_effective_balance(state, i) for i in this_epoch_boundary_attester_indices])`.
|
||||||
* Let `this_epoch_boundary_attesting_balance = sum([get_effective_balance(v) for v in this_epoch_boundary_attesters])`.
|
|
||||||
|
|
||||||
[Validators](#dfn-Validator) attesting during the previous epoch:
|
[Validators](#dfn-Validator) attesting during the previous epoch:
|
||||||
|
|
||||||
* Validators that made an attestation during the previous epoch:
|
* Validators that made an attestation during the previous epoch:
|
||||||
* Let `previous_epoch_attestations = [a for a in state.latest_attestations if state.slot - 2 * EPOCH_LENGTH <= a.slot < state.slot - EPOCH_LENGTH]`.
|
* Let `previous_epoch_attestations = [a for a in state.latest_attestations if state.slot - 2 * EPOCH_LENGTH <= a.slot < state.slot - EPOCH_LENGTH]`.
|
||||||
* Let `previous_epoch_attester_indices` be the union of the validator index sets given by `[get_attestation_participants(state, a.data, a.participation_bitfield) for a in previous_epoch_attestations]`.
|
* Let `previous_epoch_attester_indices` be the union of the validator index sets given by `[get_attestation_participants(state, a.data, a.participation_bitfield) for a in previous_epoch_attestations]`.
|
||||||
* Let `previous_epoch_attesters = [state.validator_registry[i] for indices in previous_epoch_attester_indices for i in indices]`.
|
|
||||||
* Validators targeting the previous justified hash:
|
* Validators targeting the previous justified hash:
|
||||||
* Let `previous_epoch_justified_attestations = [a for a in this_epoch_attestations + previous_epoch_attestations if a.justified_slot == state.previous_justified_slot]`.
|
* Let `previous_epoch_justified_attestations = [a for a in this_epoch_attestations + previous_epoch_attestations if a.justified_slot == state.previous_justified_slot]`.
|
||||||
* Let `previous_epoch_justified_attester_indices` be the union of the validator index sets given by `[get_attestation_participants(state, a.data, a.participation_bitfield) for a in previous_epoch_justified_attestations]`.
|
* Let `previous_epoch_justified_attester_indices` be the union of the validator index sets given by `[get_attestation_participants(state, a.data, a.participation_bitfield) for a in previous_epoch_justified_attestations]`.
|
||||||
* Let `previous_epoch_justified_attesters = [state.validator_registry[i] for indices in previous_epoch_justified_attester_indices for i in indices]`.
|
* Let `previous_epoch_justified_attesting_balance = sum([get_effective_balance(state, i) for i in previous_epoch_justified_attester_indices])`.
|
||||||
* Let `previous_epoch_justified_attesting_balance = sum([get_effective_balance(v) for v in previous_epoch_justified_attesters])`.
|
|
||||||
* Validators justifying the epoch boundary block at the start of the previous epoch:
|
* Validators justifying the epoch boundary block at the start of the previous epoch:
|
||||||
* Let `previous_epoch_boundary_attestations = [a for a in previous_epoch_justified_attestations if a.epoch_boundary_root == get_block_root(state, state.slot - 2 * EPOCH_LENGTH)]`.
|
* Let `previous_epoch_boundary_attestations = [a for a in previous_epoch_justified_attestations if a.epoch_boundary_root == get_block_root(state, state.slot - 2 * EPOCH_LENGTH)]`.
|
||||||
* Let `previous_epoch_boundary_attester_indices` be the union of the validator index sets given by `[get_attestation_participants(state, a.data, a.participation_bitfield) for a in previous_epoch_boundary_attestations]`.
|
* Let `previous_epoch_boundary_attester_indices` be the union of the validator index sets given by `[get_attestation_participants(state, a.data, a.participation_bitfield) for a in previous_epoch_boundary_attestations]`.
|
||||||
* Let `previous_epoch_boundary_attesters = [state.validator_registry[i] for indices in previous_epoch_boundary_attester_indices for i in indices]`.
|
* Let `previous_epoch_boundary_attesting_balance = sum([get_effective_balance(state, i) for i in previous_epoch_boundary_attester_indices])`.
|
||||||
* Let `previous_epoch_boundary_attesting_balance = sum([get_effective_balance(v) for v in previous_epoch_boundary_attesters])`.
|
|
||||||
* Validators attesting to the expected beacon chain head during the previous epoch:
|
* Validators attesting to the expected beacon chain head during the previous epoch:
|
||||||
* Let `previous_epoch_head_attestations = [a for a in previous_epoch_attestations if a.beacon_block_root == get_block_root(state, a.slot)]`.
|
* Let `previous_epoch_head_attestations = [a for a in previous_epoch_attestations if a.beacon_block_root == get_block_root(state, a.slot)]`.
|
||||||
* Let `previous_epoch_head_attester_indices` be the union of the validator index sets given by `[get_attestation_participants(state, a.data, a.participation_bitfield) for a in previous_epoch_head_attestations]`.
|
* Let `previous_epoch_head_attester_indices` be the union of the validator index sets given by `[get_attestation_participants(state, a.data, a.participation_bitfield) for a in previous_epoch_head_attestations]`.
|
||||||
* Let `previous_epoch_head_attesters = [state.validator_registry[i] for indices in previous_epoch_head_attester_indices for i in indices]`.
|
* Let `previous_epoch_head_attesting_balance = sum([get_effective_balance(state, i) for i in previous_epoch_head_attester_indices])`.
|
||||||
* Let `previous_epoch_head_attesting_balance = sum([get_effective_balance(v) for v in previous_epoch_head_attesters])`.
|
|
||||||
|
**Note**: `previous_epoch_boundary_attesting_balance` balance might be marginally different than `this_epoch_boundary_attesting_balance` 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.
|
||||||
|
|
||||||
For every `shard_committee` in `state.shard_committees_at_slots`:
|
For every `shard_committee` in `state.shard_committees_at_slots`:
|
||||||
|
|
||||||
* Let `attesting_validators(shard_committee, shard_block_root)` be the union of the [validator](#dfn-validator) index sets given by `[get_attestation_participants(state, a.data, a.participation_bitfield) for a in this_epoch_attestations + previous_epoch_attestations if a.shard == shard_committee.shard and a.shard_block_root == shard_block_root]`.
|
* Let `attesting_validator_indices(shard_committee, shard_block_root)` be the union of the [validator](#dfn-validator) index sets given by `[get_attestation_participants(state, a.data, a.participation_bitfield) for a in this_epoch_attestations + previous_epoch_attestations if a.shard == shard_committee.shard and a.shard_block_root == shard_block_root]`.
|
||||||
* Let `winning_root(shard_committee)` be equal to the value of `shard_block_root` such that `sum([get_effective_balance(v) for v in attesting_validators(shard_committee, shard_block_root)])` is maximized (ties broken by favoring lower `shard_block_root` values).
|
* Let `winning_root(shard_committee)` be equal to the value of `shard_block_root` such that `sum([get_effective_balance(state, i) for i in attesting_validator_indices(shard_committee, shard_block_root)])` is maximized (ties broken by favoring lower `shard_block_root` values).
|
||||||
* Let `attesting_validators(shard_committee)` be equal to `attesting_validators(shard_committee, winning_root(shard_committee))` for convenience.
|
* Let `attesting_validators(shard_committee)` be equal to `attesting_validators(shard_committee, winning_root(shard_committee))` for convenience.
|
||||||
* Let `total_attesting_balance(shard_committee)` be the sum of the balances-at-stake of `attesting_validators(shard_committee)`.
|
* Let `total_attesting_balance(shard_committee)` be the sum of the balances-at-stake of `attesting_validators(shard_committee)`.
|
||||||
* Let `total_balance(shard_committee) = sum([get_effective_balance(v) for v in shard_committee.committee])`.
|
* Let `total_balance(shard_committee) = sum([get_effective_balance(state, i) for i in shard_committee.committee])`.
|
||||||
* Let `inclusion_slot(v) = a.slot_included` for the attestation `a` where `v` is in `get_attestation_participants(state, a.data, a.participation_bitfield)`.
|
* Let `inclusion_slot(state, index) = a.slot_included` for the attestation `a` where `index` is in `get_attestation_participants(state, a.data, a.participation_bitfield)`.
|
||||||
* Let `inclusion_distance(v) = a.slot_included - a.data.slot` where `a` is the above attestation.
|
* Let `inclusion_distance(state, index) = a.slot_included - a.data.slot` where `a` is the above attestation.
|
||||||
* Let `adjust_for_inclusion_distance(magnitude, distance)` be the function below.
|
* Let `adjust_for_inclusion_distance(magnitude, distance)` be the function below.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
|
@ -1621,8 +1626,8 @@ For every `shard_committee` in `state.shard_committees_at_slots`:
|
||||||
First, we define some additional helpers:
|
First, we define some additional helpers:
|
||||||
|
|
||||||
* Let `base_reward_quotient = BASE_REWARD_QUOTIENT * integer_squareroot(total_balance // GWEI_PER_ETH)`.
|
* Let `base_reward_quotient = BASE_REWARD_QUOTIENT * integer_squareroot(total_balance // GWEI_PER_ETH)`.
|
||||||
* Let `base_reward(v) = get_effective_balance(v) // base_reward_quotient // 4` for any validator `v`.
|
* Let `base_reward(state, index) = get_effective_balance(state, index) // base_reward_quotient // 4` for any validator with the given `index`.
|
||||||
* Let `inactivity_penalty(v, slots_since_finality) = base_reward(v) + get_effective_balance(v) * slots_since_finality // INACTIVITY_PENALTY_QUOTIENT` for any validator `v`.
|
* Let `inactivity_penalty(state, index, slots_since_finality) = base_reward(state, index) + get_effective_balance(state, index) * slots_since_finality // INACTIVITY_PENALTY_QUOTIENT` for any validator with the given `index`.
|
||||||
|
|
||||||
#### Justification and finalization
|
#### Justification and finalization
|
||||||
|
|
||||||
|
@ -1633,32 +1638,32 @@ Note: When applying penalties in the following balance recalculations implemente
|
||||||
Case 1: `slots_since_finality <= 4 * EPOCH_LENGTH`:
|
Case 1: `slots_since_finality <= 4 * EPOCH_LENGTH`:
|
||||||
|
|
||||||
* Expected FFG source:
|
* Expected FFG source:
|
||||||
* Any [validator](#dfn-validator) `v` in `previous_epoch_justified_attesters` gains `adjust_for_inclusion_distance(base_reward(v) * previous_epoch_justified_attesting_balance // total_balance, inclusion_distance(v))`.
|
* Any [validator](#dfn-validator) `index` in `previous_epoch_justified_attester_indices` gains `adjust_for_inclusion_distance(base_reward(state, index) * previous_epoch_justified_attesting_balance // total_balance, inclusion_distance(state, index))`.
|
||||||
* Any [active validator](#dfn-active-validator) `v` not in `previous_epoch_justified_attesters` loses `base_reward(v)`.
|
* Any [active validator](#dfn-active-validator) `v` not in `previous_epoch_justified_attester_indices` loses `base_reward(state, index)`.
|
||||||
* Expected FFG target:
|
* Expected FFG target:
|
||||||
* Any [validator](#dfn-validator) `v` in `previous_epoch_boundary_attesters` gains `adjust_for_inclusion_distance(base_reward(v) * previous_epoch_boundary_attesting_balance // total_balance, inclusion_distance(v))`.
|
* Any [validator](#dfn-validator) `index` in `previous_epoch_boundary_attester_indices` gains `adjust_for_inclusion_distance(base_reward(state, index) * previous_epoch_boundary_attesting_balance // total_balance, inclusion_distance(state, index))`.
|
||||||
* Any [active validator](#dfn-active-validator) `v` not in `previous_epoch_boundary_attesters` loses `base_reward(v)`.
|
* Any [active validator](#dfn-active-validator) `index` not in `previous_epoch_boundary_attester_indices` loses `base_reward(state, index)`.
|
||||||
* Expected beacon chain head:
|
* Expected beacon chain head:
|
||||||
* Any [validator](#dfn-validator) `v` in `previous_epoch_head_attesters` gains `adjust_for_inclusion_distance(base_reward(v) * previous_epoch_head_attesting_balance // total_balance, inclusion_distance(v))`.
|
* Any [validator](#dfn-validator) `index` in `previous_epoch_head_attester_indices` gains `adjust_for_inclusion_distance(base_reward(state, index) * previous_epoch_head_attesting_balance // total_balance, inclusion_distance(state, index))`.
|
||||||
* Any [active validator](#dfn-active-validator) `v` not in `previous_epoch_head_attesters` loses `base_reward(v)`.
|
* Any [active validator](#dfn-active-validator) `index` not in `previous_epoch_head_attester_indices` loses `base_reward(state, index)`.
|
||||||
|
|
||||||
Case 2: `slots_since_finality > 4 * EPOCH_LENGTH`:
|
Case 2: `slots_since_finality > 4 * EPOCH_LENGTH`:
|
||||||
|
|
||||||
* Any [active validator](#dfn-active-validator) `v` not in `previous_epoch_justified_attesters`, loses `inactivity_penalty(v, slots_since_finality)`.
|
* Any [active validator](#dfn-active-validator) `index` not in `previous_epoch_justified_attester_indices`, loses `inactivity_penalty(state, index, slots_since_finality)`.
|
||||||
* Any [active validator](#dfn-active-validator) `v` not in `previous_epoch_boundary_attesters`, loses `inactivity_penalty(v, slots_since_finality)`.
|
* Any [active validator](#dfn-active-validator) `index` not in `previous_epoch_boundary_attester_indices`, loses `inactivity_penalty(state, index, slots_since_finality)`.
|
||||||
* Any [active validator](#dfn-active-validator) `v` not in `previous_epoch_head_attesters`, loses `inactivity_penalty(v, slots_since_finality)`.
|
* Any [active validator](#dfn-active-validator) `index` not in `previous_epoch_head_attester_indices`, loses `inactivity_penalty(state, index, slots_since_finality)`.
|
||||||
* Any [validator](#dfn-validator) with `status == EXITED_WITH_PENALTY`, loses `3 * inactivity_penalty(v, slots_since_finality)`.
|
* Any [validator](#dfn-validator) `index` with `status == EXITED_WITH_PENALTY`, loses `3 * inactivity_penalty(state, index, slots_since_finality)`.
|
||||||
|
|
||||||
#### Attestation inclusion
|
#### Attestation inclusion
|
||||||
|
|
||||||
For each `v` in `previous_epoch_attesters`, we determine the proposer `proposer_index = get_beacon_proposer_index(state, inclusion_slot(v))` and set `state.validator_registry[proposer_index].balance += base_reward(v) // INCLUDER_REWARD_QUOTIENT`.
|
For each `index` in `previous_epoch_attester_indices`, we determine the proposer `proposer_index = get_beacon_proposer_index(state, inclusion_slot(state, index))` and set `state.validator_balances[proposer_index] += base_reward(state, index) // INCLUDER_REWARD_QUOTIENT`.
|
||||||
|
|
||||||
#### Crosslinks
|
#### Crosslinks
|
||||||
|
|
||||||
For every `shard_committee` in `state.shard_committees_at_slots[:EPOCH_LENGTH]` (i.e. the objects corresponding to the epoch before the current one), for each `v` in `[state.validator_registry[index] for index in shard_committee.committee]`, adjust balances as follows:
|
For every `shard_committee` in `state.shard_committees_at_slots[:EPOCH_LENGTH]` (i.e. the objects corresponding to the epoch before the current one), for each `index` in `shard_committee.committee`, adjust balances as follows:
|
||||||
|
|
||||||
* If `v in attesting_validators(shard_committee)`, `v.balance += adjust_for_inclusion_distance(base_reward(v) * total_attesting_balance(shard_committee) // total_balance(shard_committee)), inclusion_distance(v))`.
|
* If `index in attesting_validators(shard_committee)`, `state.validator_balances[index] += adjust_for_inclusion_distance(base_reward(state, index) * total_attesting_balance(shard_committee) // total_balance(shard_committee)), inclusion_distance(state, index))`.
|
||||||
* If `v not in attesting_validators(shard_committee)`, `v.balance -= base_reward(v)`.
|
* If `index not in attesting_validators(shard_committee)`, `state.validator_balances[index] -= base_reward(state, index)`.
|
||||||
|
|
||||||
### Ejections
|
### Ejections
|
||||||
|
|
||||||
|
@ -1671,7 +1676,7 @@ def process_ejections(state: BeaconState) -> None:
|
||||||
and eject active validators with balance below ``EJECTION_BALANCE``.
|
and eject active validators with balance below ``EJECTION_BALANCE``.
|
||||||
"""
|
"""
|
||||||
for index in active_validator_indices(state.validator_registry):
|
for index in active_validator_indices(state.validator_registry):
|
||||||
if state.validator_registry[index].balance < EJECTION_BALANCE:
|
if state.validator_balances[index] < EJECTION_BALANCE:
|
||||||
update_validator_status(state, index, new_status=EXITED_WITHOUT_PENALTY)
|
update_validator_status(state, index, new_status=EXITED_WITHOUT_PENALTY)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -1693,7 +1698,7 @@ def update_validator_registry(state: BeaconState) -> None:
|
||||||
# The active validators
|
# The active validators
|
||||||
active_validator_indices = get_active_validator_indices(state.validator_registry)
|
active_validator_indices = get_active_validator_indices(state.validator_registry)
|
||||||
# The total effective balance of active validators
|
# The total effective balance of active validators
|
||||||
total_balance = sum([get_effective_balance(v) for i, v in enumerate(validator_registry) if i in active_validator_indices])
|
total_balance = sum([get_effective_balance(state, i) for i in active_validator_indices])
|
||||||
|
|
||||||
# The maximum balance churn in Gwei (for deposits and exits separately)
|
# The maximum balance churn in Gwei (for deposits and exits separately)
|
||||||
max_balance_churn = max(
|
max_balance_churn = max(
|
||||||
|
@ -1704,9 +1709,9 @@ def update_validator_registry(state: BeaconState) -> None:
|
||||||
# Activate validators within the allowable balance churn
|
# Activate validators within the allowable balance churn
|
||||||
balance_churn = 0
|
balance_churn = 0
|
||||||
for index, validator in enumerate(state.validator_registry):
|
for index, validator in enumerate(state.validator_registry):
|
||||||
if validator.status == PENDING_ACTIVATION and validator.balance >= MAX_DEPOSIT * GWEI_PER_ETH:
|
if validator.status == PENDING_ACTIVATION and state.validator_balances[index] >= MAX_DEPOSIT * GWEI_PER_ETH:
|
||||||
# Check the balance churn would be within the allowance
|
# Check the balance churn would be within the allowance
|
||||||
balance_churn += get_effective_balance(validator)
|
balance_churn += get_effective_balance(state, index)
|
||||||
if balance_churn > max_balance_churn:
|
if balance_churn > max_balance_churn:
|
||||||
break
|
break
|
||||||
|
|
||||||
|
@ -1718,7 +1723,7 @@ def update_validator_registry(state: BeaconState) -> None:
|
||||||
for index, validator in enumerate(state.validator_registry):
|
for index, validator in enumerate(state.validator_registry):
|
||||||
if validator.status == ACTIVE_PENDING_EXIT:
|
if validator.status == ACTIVE_PENDING_EXIT:
|
||||||
# Check the balance churn would be within the allowance
|
# Check the balance churn would be within the allowance
|
||||||
balance_churn += get_effective_balance(validator)
|
balance_churn += get_effective_balance(state, index)
|
||||||
if balance_churn > max_balance_churn:
|
if balance_churn > max_balance_churn:
|
||||||
break
|
break
|
||||||
|
|
||||||
|
@ -1735,11 +1740,11 @@ def update_validator_registry(state: BeaconState) -> None:
|
||||||
)
|
)
|
||||||
|
|
||||||
# Calculate penalties for slashed validators
|
# Calculate penalties for slashed validators
|
||||||
def to_penalize(v):
|
def to_penalize(index):
|
||||||
return v.status == EXITED_WITH_PENALTY
|
return state.validator_registry[index].status == EXITED_WITH_PENALTY
|
||||||
validators_to_penalize = filter(to_penalize, validator_registry)
|
validators_to_penalize = filter(to_penalize, range(len(validator_registry)))
|
||||||
for v in validators_to_penalize:
|
for index in validators_to_penalize:
|
||||||
v.balance -= get_effective_balance(v) * min(total_penalties * 3, total_balance) // total_balance
|
state.validator_balances[index] -= get_effective_balance(state, index) * min(total_penalties * 3, total_balance) // total_balance
|
||||||
|
|
||||||
return validator_registry, latest_penalized_exit_balances, validator_registry_delta_chain_tip
|
return validator_registry, latest_penalized_exit_balances, validator_registry_delta_chain_tip
|
||||||
```
|
```
|
||||||
|
@ -1799,7 +1804,10 @@ This section is divided into Normative and Informative references. Normative re
|
||||||
## Normative
|
## Normative
|
||||||
|
|
||||||
## Informative
|
## Informative
|
||||||
<a id="ref-python-poc"></a> _**python-poc**_
|
<a id="ref-casper-ffg"></a> _**casper-ffg**_
|
||||||
|
_Casper the Friendly Finality Gadget_. V. Buterin and V. Griffith. URL: https://arxiv.org/abs/1710.09437
|
||||||
|
|
||||||
|
<a id="ref-python-poc"></a> _**python-poc**_
|
||||||
_Python proof-of-concept implementation_. Ethereum Foundation. URL: https://github.com/ethereum/beacon_chain
|
_Python proof-of-concept implementation_. Ethereum Foundation. URL: https://github.com/ethereum/beacon_chain
|
||||||
|
|
||||||
# Copyright
|
# Copyright
|
||||||
|
|
Loading…
Reference in New Issue