Merge branch 'dev' into deposit_contract
This commit is contained in:
commit
12fee0e9d1
|
@ -17,7 +17,7 @@
|
||||||
- [Initial values](#initial-values)
|
- [Initial values](#initial-values)
|
||||||
- [Time parameters](#time-parameters)
|
- [Time parameters](#time-parameters)
|
||||||
- [State list lengths](#state-list-lengths)
|
- [State list lengths](#state-list-lengths)
|
||||||
- [Reward and penalty quotients](#reward-and-penalty-quotients)
|
- [Rewards and penalties](#rewards-and-penalties)
|
||||||
- [Max operations per block](#max-operations-per-block)
|
- [Max operations per block](#max-operations-per-block)
|
||||||
- [Signature domains](#signature-domains)
|
- [Signature domains](#signature-domains)
|
||||||
- [Data structures](#data-structures)
|
- [Data structures](#data-structures)
|
||||||
|
@ -103,7 +103,7 @@
|
||||||
- [Helper functions](#helper-functions-1)
|
- [Helper functions](#helper-functions-1)
|
||||||
- [Justification and finalization](#justification-and-finalization)
|
- [Justification and finalization](#justification-and-finalization)
|
||||||
- [Crosslinks](#crosslinks)
|
- [Crosslinks](#crosslinks)
|
||||||
- [Rewards and penalties](#rewards-and-penalties)
|
- [Rewards and penalties](#rewards-and-penalties-1)
|
||||||
- [Registry updates](#registry-updates)
|
- [Registry updates](#registry-updates)
|
||||||
- [Slashings](#slashings)
|
- [Slashings](#slashings)
|
||||||
- [Final updates](#final-updates)
|
- [Final updates](#final-updates)
|
||||||
|
@ -220,17 +220,17 @@ These configurations are updated for releases, but may be out of sync during `de
|
||||||
| `LATEST_ACTIVE_INDEX_ROOTS_LENGTH` | `2**13` (= 8,192) | epochs | ~36 days |
|
| `LATEST_ACTIVE_INDEX_ROOTS_LENGTH` | `2**13` (= 8,192) | epochs | ~36 days |
|
||||||
| `LATEST_SLASHED_EXIT_LENGTH` | `2**13` (= 8,192) | epochs | ~36 days |
|
| `LATEST_SLASHED_EXIT_LENGTH` | `2**13` (= 8,192) | epochs | ~36 days |
|
||||||
|
|
||||||
### Reward and penalty quotients
|
### Rewards and penalties
|
||||||
|
|
||||||
| Name | Value |
|
| Name | Value |
|
||||||
| - | - |
|
| - | - |
|
||||||
| `BASE_REWARD_QUOTIENT` | `2**5` (= 32) |
|
| `BASE_REWARD_FACTOR` | `2**5` (= 32) |
|
||||||
| `WHISTLEBLOWING_REWARD_QUOTIENT` | `2**9` (= 512) |
|
| `WHISTLEBLOWING_REWARD_QUOTIENT` | `2**9` (= 512) |
|
||||||
| `PROPOSER_REWARD_QUOTIENT` | `2**3` (= 8) |
|
| `PROPOSER_REWARD_QUOTIENT` | `2**3` (= 8) |
|
||||||
| `INACTIVITY_PENALTY_QUOTIENT` | `2**25` (= 33,554,432) |
|
| `INACTIVITY_PENALTY_QUOTIENT` | `2**25` (= 33,554,432) |
|
||||||
| `MIN_SLASHING_PENALTY_QUOTIENT` | `2**5` (= 32) |
|
| `MIN_SLASHING_PENALTY_QUOTIENT` | `2**5` (= 32) |
|
||||||
|
|
||||||
* **The `BASE_REWARD_QUOTIENT` is NOT final. Once all other protocol details are finalized, it will be adjusted to target a theoretical maximum total issuance of `2**21` ETH per year if `2**27` ETH is validating (and therefore `2**20` per year if `2**25` ETH is validating, etc.)**
|
* **The `BASE_REWARD_FACTOR` is NOT final. Once all other protocol details are finalized, it will be adjusted to target a theoretical maximum total issuance of `2**21` ETH per year if `2**27` ETH is validating (and therefore `2**20` per year if `2**25` ETH is validating, etc.)**
|
||||||
* The `INACTIVITY_PENALTY_QUOTIENT` equals `INVERSE_SQRT_E_DROP_TIME**2` where `INVERSE_SQRT_E_DROP_TIME := 2**12 epochs` (~18 days) is the time it takes the inactivity penalty to reduce the balance of non-participating [validators](#dfn-validator) to about `1/sqrt(e) ~= 60.6%`. Indeed, the balance retained by offline [validators](#dfn-validator) after `n` epochs is about `(1 - 1/INACTIVITY_PENALTY_QUOTIENT)**(n**2/2)` so after `INVERSE_SQRT_E_DROP_TIME` epochs it is roughly `(1 - 1/INACTIVITY_PENALTY_QUOTIENT)**(INACTIVITY_PENALTY_QUOTIENT/2) ~= 1/sqrt(e)`.
|
* The `INACTIVITY_PENALTY_QUOTIENT` equals `INVERSE_SQRT_E_DROP_TIME**2` where `INVERSE_SQRT_E_DROP_TIME := 2**12 epochs` (~18 days) is the time it takes the inactivity penalty to reduce the balance of non-participating [validators](#dfn-validator) to about `1/sqrt(e) ~= 60.6%`. Indeed, the balance retained by offline [validators](#dfn-validator) after `n` epochs is about `(1 - 1/INACTIVITY_PENALTY_QUOTIENT)**(n**2/2)` so after `INVERSE_SQRT_E_DROP_TIME` epochs it is roughly `(1 - 1/INACTIVITY_PENALTY_QUOTIENT)**(INACTIVITY_PENALTY_QUOTIENT/2) ~= 1/sqrt(e)`.
|
||||||
|
|
||||||
### Max operations per block
|
### Max operations per block
|
||||||
|
@ -471,8 +471,6 @@ The types are defined topologically to aid in facilitating an executable version
|
||||||
{
|
{
|
||||||
# Branch in the deposit tree
|
# Branch in the deposit tree
|
||||||
'proof': ['bytes32', DEPOSIT_CONTRACT_TREE_DEPTH],
|
'proof': ['bytes32', DEPOSIT_CONTRACT_TREE_DEPTH],
|
||||||
# Index in the deposit tree
|
|
||||||
'index': 'uint64',
|
|
||||||
# Data
|
# Data
|
||||||
'data': DepositData,
|
'data': DepositData,
|
||||||
}
|
}
|
||||||
|
@ -963,9 +961,9 @@ def bytes_to_int(data: bytes) -> int:
|
||||||
```python
|
```python
|
||||||
def get_total_balance(state: BeaconState, indices: List[ValidatorIndex]) -> Gwei:
|
def get_total_balance(state: BeaconState, indices: List[ValidatorIndex]) -> Gwei:
|
||||||
"""
|
"""
|
||||||
Return the combined effective balance of an array of ``validators``.
|
Return the combined effective balance of the ``indices``. (1 Gwei minimum to avoid divisions by zero.)
|
||||||
"""
|
"""
|
||||||
return sum([state.validator_registry[index].effective_balance for index in indices])
|
return max(sum([state.validator_registry[index].effective_balance for index in indices]), 1)
|
||||||
```
|
```
|
||||||
|
|
||||||
### `get_domain`
|
### `get_domain`
|
||||||
|
@ -1413,10 +1411,9 @@ def process_crosslinks(state: BeaconState) -> None:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def get_base_reward(state: BeaconState, index: ValidatorIndex) -> Gwei:
|
def get_base_reward(state: BeaconState, index: ValidatorIndex) -> Gwei:
|
||||||
adjusted_quotient = integer_squareroot(get_total_active_balance(state)) // BASE_REWARD_QUOTIENT
|
total_balance = get_total_active_balance(state)
|
||||||
if adjusted_quotient == 0:
|
effective_balance = state.validator_registry[index].effective_balance
|
||||||
return 0
|
return effective_balance * BASE_REWARD_FACTOR // integer_squareroot(total_balance) // BASE_REWARDS_PER_EPOCH
|
||||||
return state.validator_registry[index].effective_balance // adjusted_quotient // BASE_REWARDS_PER_EPOCH
|
|
||||||
```
|
```
|
||||||
|
|
||||||
```python
|
```python
|
||||||
|
@ -1531,10 +1528,9 @@ def process_registry_updates(state: BeaconState) -> None:
|
||||||
```python
|
```python
|
||||||
def process_slashings(state: BeaconState) -> None:
|
def process_slashings(state: BeaconState) -> None:
|
||||||
current_epoch = get_current_epoch(state)
|
current_epoch = get_current_epoch(state)
|
||||||
active_validator_indices = get_active_validator_indices(state, current_epoch)
|
total_balance = get_total_active_balance(state)
|
||||||
total_balance = get_total_balance(state, active_validator_indices)
|
|
||||||
|
|
||||||
# Compute `total_penalties`
|
# Compute slashed balances in the current epoch
|
||||||
total_at_start = state.latest_slashed_balances[(current_epoch + 1) % LATEST_SLASHED_EXIT_LENGTH]
|
total_at_start = state.latest_slashed_balances[(current_epoch + 1) % LATEST_SLASHED_EXIT_LENGTH]
|
||||||
total_at_end = state.latest_slashed_balances[current_epoch % LATEST_SLASHED_EXIT_LENGTH]
|
total_at_end = state.latest_slashed_balances[current_epoch % LATEST_SLASHED_EXIT_LENGTH]
|
||||||
total_penalties = total_at_end - total_at_start
|
total_penalties = total_at_end - total_at_start
|
||||||
|
@ -1763,12 +1759,11 @@ def process_deposit(state: BeaconState, deposit: Deposit) -> None:
|
||||||
leaf=hash_tree_root(deposit.data),
|
leaf=hash_tree_root(deposit.data),
|
||||||
proof=deposit.proof,
|
proof=deposit.proof,
|
||||||
depth=DEPOSIT_CONTRACT_TREE_DEPTH,
|
depth=DEPOSIT_CONTRACT_TREE_DEPTH,
|
||||||
index=deposit.index,
|
index=state.deposit_index,
|
||||||
root=state.latest_eth1_data.deposit_root,
|
root=state.latest_eth1_data.deposit_root,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Deposits must be processed in order
|
# Deposits must be processed in order
|
||||||
assert deposit.index == state.deposit_index
|
|
||||||
state.deposit_index += 1
|
state.deposit_index += 1
|
||||||
|
|
||||||
pubkey = deposit.data.pubkey
|
pubkey = deposit.data.pubkey
|
||||||
|
|
|
@ -35,7 +35,8 @@ Test formats:
|
||||||
- [`bls`](./bls/README.md)
|
- [`bls`](./bls/README.md)
|
||||||
- [`operations`](./operations/README.md)
|
- [`operations`](./operations/README.md)
|
||||||
- [`shuffling`](./shuffling/README.md)
|
- [`shuffling`](./shuffling/README.md)
|
||||||
- [`ssz`](./ssz/README.md)
|
- [`ssz_generic`](./ssz_generic/README.md)
|
||||||
|
- [`ssz_static`](./ssz_static/README.md)
|
||||||
- More formats are planned, see tracking issues for CI/testing
|
- More formats are planned, see tracking issues for CI/testing
|
||||||
|
|
||||||
## Glossary
|
## Glossary
|
||||||
|
|
|
@ -1,9 +1,13 @@
|
||||||
import eth2spec.phase0.spec as spec
|
import eth2spec.phase0.spec as spec
|
||||||
from eth2spec.phase0.spec import process_deposit
|
from eth2spec.phase0.spec import process_deposit
|
||||||
from eth2spec.test.context import spec_state_test, expect_assertion_error, always_bls
|
from eth2spec.test.context import spec_state_test, expect_assertion_error, always_bls
|
||||||
from eth2spec.test.helpers.deposits import prepare_state_and_deposit, sign_deposit_data
|
from eth2spec.test.helpers.deposits import (
|
||||||
|
build_deposit,
|
||||||
|
prepare_state_and_deposit,
|
||||||
|
sign_deposit_data,
|
||||||
|
)
|
||||||
from eth2spec.test.helpers.state import get_balance
|
from eth2spec.test.helpers.state import get_balance
|
||||||
from eth2spec.test.helpers.keys import privkeys
|
from eth2spec.test.helpers.keys import privkeys, pubkeys
|
||||||
|
|
||||||
|
|
||||||
def run_deposit_processing(state, deposit, validator_index, valid=True, effective=True):
|
def run_deposit_processing(state, deposit, validator_index, valid=True, effective=True):
|
||||||
|
@ -18,9 +22,6 @@ def run_deposit_processing(state, deposit, validator_index, valid=True, effectiv
|
||||||
pre_balance = 0
|
pre_balance = 0
|
||||||
if validator_index < pre_validator_count:
|
if validator_index < pre_validator_count:
|
||||||
pre_balance = get_balance(state, validator_index)
|
pre_balance = get_balance(state, validator_index)
|
||||||
else:
|
|
||||||
# if it is a new validator, it should be right at the end of the current registry.
|
|
||||||
assert validator_index == pre_validator_count
|
|
||||||
|
|
||||||
yield 'pre', state
|
yield 'pre', state
|
||||||
yield 'deposit', deposit
|
yield 'deposit', deposit
|
||||||
|
@ -93,6 +94,22 @@ def test_invalid_sig_top_up(state):
|
||||||
yield from run_deposit_processing(state, deposit, validator_index, valid=True, effective=True)
|
yield from run_deposit_processing(state, deposit, validator_index, valid=True, effective=True)
|
||||||
|
|
||||||
|
|
||||||
|
@spec_state_test
|
||||||
|
def test_invalid_withdrawal_credentials_top_up(state):
|
||||||
|
validator_index = 0
|
||||||
|
amount = spec.MAX_EFFECTIVE_BALANCE // 4
|
||||||
|
withdrawal_credentials = spec.BLS_WITHDRAWAL_PREFIX_BYTE + spec.hash(b"junk")[1:]
|
||||||
|
deposit = prepare_state_and_deposit(
|
||||||
|
state,
|
||||||
|
validator_index,
|
||||||
|
amount,
|
||||||
|
withdrawal_credentials=withdrawal_credentials
|
||||||
|
)
|
||||||
|
|
||||||
|
# inconsistent withdrawal credentials, in top-ups, are allowed!
|
||||||
|
yield from run_deposit_processing(state, deposit, validator_index, valid=True, effective=True)
|
||||||
|
|
||||||
|
|
||||||
@spec_state_test
|
@spec_state_test
|
||||||
def test_wrong_index(state):
|
def test_wrong_index(state):
|
||||||
validator_index = len(state.validator_registry)
|
validator_index = len(state.validator_registry)
|
||||||
|
@ -107,6 +124,46 @@ def test_wrong_index(state):
|
||||||
yield from run_deposit_processing(state, deposit, validator_index, valid=False)
|
yield from run_deposit_processing(state, deposit, validator_index, valid=False)
|
||||||
|
|
||||||
|
|
||||||
|
@spec_state_test
|
||||||
|
def test_wrong_deposit_for_deposit_count(state):
|
||||||
|
deposit_data_leaves = [spec.ZERO_HASH] * len(state.validator_registry)
|
||||||
|
|
||||||
|
# build root for deposit_1
|
||||||
|
index_1 = len(deposit_data_leaves)
|
||||||
|
pubkey_1 = pubkeys[index_1]
|
||||||
|
privkey_1 = privkeys[index_1]
|
||||||
|
deposit_1, root_1, deposit_data_leaves = build_deposit(
|
||||||
|
state,
|
||||||
|
deposit_data_leaves,
|
||||||
|
pubkey_1,
|
||||||
|
privkey_1,
|
||||||
|
spec.MAX_EFFECTIVE_BALANCE,
|
||||||
|
withdrawal_credentials=b'\x00'*32,
|
||||||
|
signed=True,
|
||||||
|
)
|
||||||
|
deposit_count_1 = len(deposit_data_leaves)
|
||||||
|
|
||||||
|
# build root for deposit_2
|
||||||
|
index_2 = len(deposit_data_leaves)
|
||||||
|
pubkey_2 = pubkeys[index_2]
|
||||||
|
privkey_2 = privkeys[index_2]
|
||||||
|
deposit_2, root_2, deposit_data_leaves = build_deposit(
|
||||||
|
state,
|
||||||
|
deposit_data_leaves,
|
||||||
|
pubkey_2,
|
||||||
|
privkey_2,
|
||||||
|
spec.MAX_EFFECTIVE_BALANCE,
|
||||||
|
withdrawal_credentials=b'\x00'*32,
|
||||||
|
signed=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
# state has root for deposit_2 but is at deposit_count for deposit_1
|
||||||
|
state.latest_eth1_data.deposit_root = root_2
|
||||||
|
state.latest_eth1_data.deposit_count = deposit_count_1
|
||||||
|
|
||||||
|
yield from run_deposit_processing(state, deposit_2, index_2, valid=False)
|
||||||
|
|
||||||
|
|
||||||
# TODO: test invalid signature
|
# TODO: test invalid signature
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -8,11 +8,10 @@ from eth2spec.utils.merkle_minimal import calc_merkle_tree_from_leaves, get_merk
|
||||||
from eth2spec.utils.minimal_ssz import signing_root
|
from eth2spec.utils.minimal_ssz import signing_root
|
||||||
|
|
||||||
|
|
||||||
def build_deposit_data(state, pubkey, privkey, amount, signed=False):
|
def build_deposit_data(state, pubkey, privkey, amount, withdrawal_credentials, signed=False):
|
||||||
deposit_data = DepositData(
|
deposit_data = DepositData(
|
||||||
pubkey=pubkey,
|
pubkey=pubkey,
|
||||||
# insecurely use pubkey as withdrawal key as well
|
withdrawal_credentials=withdrawal_credentials,
|
||||||
withdrawal_credentials=spec.BLS_WITHDRAWAL_PREFIX_BYTE + spec.hash(pubkey)[1:],
|
|
||||||
amount=amount,
|
amount=amount,
|
||||||
)
|
)
|
||||||
if signed:
|
if signed:
|
||||||
|
@ -37,8 +36,9 @@ def build_deposit(state,
|
||||||
pubkey,
|
pubkey,
|
||||||
privkey,
|
privkey,
|
||||||
amount,
|
amount,
|
||||||
|
withdrawal_credentials,
|
||||||
signed):
|
signed):
|
||||||
deposit_data = build_deposit_data(state, pubkey, privkey, amount, signed)
|
deposit_data = build_deposit_data(state, pubkey, privkey, amount, withdrawal_credentials, signed)
|
||||||
|
|
||||||
item = deposit_data.hash_tree_root()
|
item = deposit_data.hash_tree_root()
|
||||||
index = len(deposit_data_leaves)
|
index = len(deposit_data_leaves)
|
||||||
|
@ -57,7 +57,7 @@ def build_deposit(state,
|
||||||
return deposit, root, deposit_data_leaves
|
return deposit, root, deposit_data_leaves
|
||||||
|
|
||||||
|
|
||||||
def prepare_state_and_deposit(state, validator_index, amount, signed=False):
|
def prepare_state_and_deposit(state, validator_index, amount, withdrawal_credentials=None, signed=False):
|
||||||
"""
|
"""
|
||||||
Prepare the state for the deposit, and create a deposit for the given validator, depositing the given amount.
|
Prepare the state for the deposit, and create a deposit for the given validator, depositing the given amount.
|
||||||
"""
|
"""
|
||||||
|
@ -67,12 +67,18 @@ def prepare_state_and_deposit(state, validator_index, amount, signed=False):
|
||||||
|
|
||||||
pubkey = pubkeys[validator_index]
|
pubkey = pubkeys[validator_index]
|
||||||
privkey = privkeys[validator_index]
|
privkey = privkeys[validator_index]
|
||||||
|
|
||||||
|
# insecurely use pubkey as withdrawal key if no credentials provided
|
||||||
|
if withdrawal_credentials is None:
|
||||||
|
withdrawal_credentials = spec.BLS_WITHDRAWAL_PREFIX_BYTE + spec.hash(pubkey)[1:]
|
||||||
|
|
||||||
deposit, root, deposit_data_leaves = build_deposit(
|
deposit, root, deposit_data_leaves = build_deposit(
|
||||||
state,
|
state,
|
||||||
deposit_data_leaves,
|
deposit_data_leaves,
|
||||||
pubkey,
|
pubkey,
|
||||||
privkey,
|
privkey,
|
||||||
amount,
|
amount,
|
||||||
|
withdrawal_credentials,
|
||||||
signed
|
signed
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue