Merge branch 'dev' into deposit_contract

This commit is contained in:
Hsiao-Wei Wang 2019-05-30 13:19:11 +08:00
commit 12fee0e9d1
No known key found for this signature in database
GPG Key ID: 95B070122902DEA4
4 changed files with 88 additions and 29 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
) )