From 0759e170a7faafca0cee7b9b8929b0c6e15bcf77 Mon Sep 17 00:00:00 2001 From: vbuterin Date: Thu, 7 Mar 2019 01:38:03 -0600 Subject: [PATCH 01/17] High/low balance separation See #685 for reasoning --- specs/core/0_beacon-chain.md | 95 +++++++++++++++++++++++++++--------- 1 file changed, 72 insertions(+), 23 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index bd709218a..3c2d90b69 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -64,6 +64,10 @@ - [`get_epoch_start_slot`](#get_epoch_start_slot) - [`is_active_validator`](#is_active_validator) - [`get_active_validator_indices`](#get_active_validator_indices) + - [`get_balance`](#get_balance) + - [`set_balance`](#set_balance) + - [`increase_balance`](#increase_balance) + - [`decrease_balance`](#decrease_balance) - [`get_permuted_index`](#get_permuted_index) - [`split`](#split) - [`get_epoch_committee_count`](#get_epoch_committee_count) @@ -205,10 +209,10 @@ Code snippets appearing in `this style` are to be interpreted as Python code. | Name | Value | Unit | | - | - | :-: | -| `MIN_DEPOSIT_AMOUNT` | `2**0 * 10**9` (= 1,000,000,000) | Gwei | +| `MIN_DEPOSIT_AMOUNT` | `2**0 * 10**9` (= 2,000,000,000) | Gwei | | `MAX_DEPOSIT_AMOUNT` | `2**5 * 10**9` (= 32,000,000,000) | Gwei | -| `FORK_CHOICE_BALANCE_INCREMENT` | `2**0 * 10**9` (= 1,000,000,000) | Gwei | | `EJECTION_BALANCE` | `2**4 * 10**9` (= 16,000,000,000) | Gwei | +| `HIGH_BALANCE_INCREMENT` | `10 ** 9` (= 1,000,000,000) | Gwei | ### Initial values @@ -516,7 +520,7 @@ The following data structures are defined as [SimpleSerialize (SSZ)](https://git # Validator registry 'validator_registry': [Validator], - 'validator_balances': ['uint64'], + 'low_balances': ['uint32'], 'validator_registry_update_epoch': 'uint64', # Randomness and committees @@ -570,6 +574,8 @@ The following data structures are defined as [SimpleSerialize (SSZ)](https://git 'initiated_exit': 'bool', # Was the validator slashed 'slashed': 'bool', + # Rounded balance + 'high_balance': 'uint32' } ``` @@ -749,6 +755,45 @@ def get_active_validator_indices(validators: List[Validator], epoch: Epoch) -> L return [i for i, v in enumerate(validators) if is_active_validator(v, epoch)] ``` +### `get_balance` + +```python +def get_balance(state: BeaconState, index: int) -> int: + return ( + state.validator_registry[index].high_balance * HIGH_BALANCE_INCREMENT + + state.low_balances[index] + ) +``` +#### `set_balance` + +````python +def set_balance(state: BeaconState, index: int, new_balance: int) -> None: + validator = state.validator_registry[index] + HALF_INCREMENT = HIGH_BALANCE_INCREMENT // 2 + if ( + validator.rounded_balance * HIGH_BALANCE_INCREMENT > new_balance or + validator.rounded_balance * HIGH_BALANCE_INCREMENT + HALF_INCREMENT * 3 < new_balance + ): + validator.rounded_balance = new_balance // HIGH_BALANCE_INCREMENT + state.validator_fractional_balances[index] = ( + new_balance - validator.rounded_balance * HIGH_BALANCE_INCREMENT + ) +```` + +#### `increase_balance` + +````python +def increase_balance(state: BeaconState, index: int, delta: int) -> None: + set_balance(state, index, get_balance(state, index) + delta) +```` + +#### `decrease_balance` + +````python +def decrease_balance(state: BeaconState, index: int, delta: int) -> None: + set_balance(state, index, get_balance(state, index) - delta) +```` + ### `get_permuted_index` ```python @@ -1105,7 +1150,7 @@ def get_effective_balance(state: BeaconState, index: ValidatorIndex) -> Gwei: """ Return the effective balance (also known as "balance at stake") for a validator with the given ``index``. """ - return min(state.validator_balances[index], MAX_DEPOSIT_AMOUNT) + return min(get_balance(state, index), MAX_DEPOSIT_AMOUNT) ``` ### `get_total_balance` @@ -1351,17 +1396,18 @@ def process_deposit(state: BeaconState, deposit: Deposit) -> None: withdrawable_epoch=FAR_FUTURE_EPOCH, initiated_exit=False, slashed=False, + high_balance=0 ) # Note: In phase 2 registry indices that have been withdrawn for a long time will be recycled. state.validator_registry.append(validator) - state.validator_balances.append(amount) + state.low_balances.append(0) + set_balance(state, len(state.validator_registry)-1, amount) else: # Increase balance by deposit amount index = validator_pubkeys.index(pubkey) assert state.validator_registry[index].withdrawal_credentials == withdrawal_credentials - - state.validator_balances[index] += amount + increase_balance(state, index, amount) ``` ### Routines for updating validator status @@ -1426,8 +1472,8 @@ def slash_validator(state: BeaconState, index: ValidatorIndex) -> None: whistleblower_index = get_beacon_proposer_index(state, state.slot) whistleblower_reward = get_effective_balance(state, index) // WHISTLEBLOWER_REWARD_QUOTIENT - state.validator_balances[whistleblower_index] += whistleblower_reward - state.validator_balances[index] -= whistleblower_reward + increase_balance(state, whistleblower_index, whistleblower_reward) + decrease_balance(state, index, whistleblower_reward) validator.slashed = True validator.withdrawable_epoch = get_current_epoch(state) + LATEST_SLASHED_EXIT_LENGTH ``` @@ -1545,7 +1591,7 @@ def get_genesis_beacon_state(genesis_validator_deposits: List[Deposit], # Validator registry validator_registry=[], - validator_balances=[], + low_balances=[], validator_registry_update_epoch=GENESIS_EPOCH, # Randomness and committees @@ -1657,9 +1703,12 @@ def lmd_ghost(store: Store, start_state: BeaconState, start_block: BeaconBlock) for validator_index in active_validator_indices ] + # Use the rounded-balance-with-hysteresis supplied by the protocol for fork + # choice voting. This reduces the number of recomputations that need to be + # made for optimized implementations that precompute and save data def get_vote_count(block: BeaconBlock) -> int: return sum( - get_effective_balance(start_state.validator_balances[validator_index]) // FORK_CHOICE_BALANCE_INCREMENT + start_state.validator_registry[validator_index].high_balance for validator_index, target in attestation_targets if get_ancestor(store, target, block.slot) == block ) @@ -1956,12 +2005,12 @@ def process_transfer(state: BeaconState, transfer: Transfer) -> None: Note that this function mutates ``state``. """ # Verify the amount and fee aren't individually too big (for anti-overflow purposes) - assert state.validator_balances[transfer.sender] >= max(transfer.amount, transfer.fee) + assert get_balance(state, transfer.sender) >= max(transfer.amount, transfer.fee) # Verify that we have enough ETH to send, and that after the transfer the balance will be either # exactly zero or at least MIN_DEPOSIT_AMOUNT assert ( - state.validator_balances[transfer.sender] == transfer.amount + transfer.fee or - state.validator_balances[transfer.sender] >= transfer.amount + transfer.fee + MIN_DEPOSIT_AMOUNT + get_balance(state, transfer.sender) == transfer.amount + transfer.fee or + get_balance(state, transfer.sender) >= transfer.amount + transfer.fee + MIN_DEPOSIT_AMOUNT ) # A transfer is valid in only one slot assert state.slot == transfer.slot @@ -1983,9 +2032,9 @@ def process_transfer(state: BeaconState, transfer: Transfer) -> None: domain=get_domain(state.fork, slot_to_epoch(transfer.slot), DOMAIN_TRANSFER) ) # Process the transfer - state.validator_balances[transfer.sender] -= transfer.amount + transfer.fee - state.validator_balances[transfer.recipient] += transfer.amount - state.validator_balances[get_beacon_proposer_index(state, state.slot)] += transfer.fee + decrease_balance(state, transfer.sender, transfer.amount + transfer.fee) + increase_balance(state, transfer.recipient, transfer.amount) + increase_balance(state, get_beacon_proposer_index(state, state.slot), transfer.fee) ``` ### Per-epoch processing @@ -2320,10 +2369,10 @@ def apply_rewards(state: BeaconState) -> None: deltas1 = get_justification_and_finalization_deltas(state) deltas2 = get_crosslink_deltas(state) for i in range(len(state.validator_registry)): - state.validator_balances[i] = max( + set_balance(state, i, max( 0, - state.validator_balances[i] + deltas1[0][i] + deltas2[0][i] - deltas1[1][i] - deltas2[1][i] - ) + get_balance(state, i) + deltas1[0][i] + deltas2[0][i] - deltas1[1][i] - deltas2[1][i] + )) ``` #### Ejections @@ -2337,7 +2386,7 @@ def process_ejections(state: BeaconState) -> None: and eject active validators with balance below ``EJECTION_BALANCE``. """ for index in get_active_validator_indices(state.validator_registry, get_current_epoch(state)): - if state.validator_balances[index] < EJECTION_BALANCE: + if get_balance(state, index) < EJECTION_BALANCE: exit_validator(state, index) ``` @@ -2380,7 +2429,7 @@ def update_validator_registry(state: BeaconState) -> None: # Activate validators within the allowable balance churn balance_churn = 0 for index, validator in enumerate(state.validator_registry): - if validator.activation_epoch == FAR_FUTURE_EPOCH and state.validator_balances[index] >= MAX_DEPOSIT_AMOUNT: + if validator.activation_epoch == FAR_FUTURE_EPOCH and get_balance(state, index) >= MAX_DEPOSIT_AMOUNT: # Check the balance churn would be within the allowance balance_churn += get_effective_balance(state, index) if balance_churn > max_balance_churn: @@ -2461,7 +2510,7 @@ def process_slashings(state: BeaconState) -> None: get_effective_balance(state, index) * min(total_penalties * 3, total_balance) // total_balance, get_effective_balance(state, index) // MIN_PENALTY_QUOTIENT ) - state.validator_balances[index] -= penalty + decrease_balance(state, index, penalty) ``` ```python From be4b912373b9ee89851e217e8f500f444ef0e1fa Mon Sep 17 00:00:00 2001 From: vbuterin Date: Thu, 7 Mar 2019 04:02:53 -0600 Subject: [PATCH 02/17] Added underflow checking to decrease_balance --- specs/core/0_beacon-chain.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 3c2d90b69..b0b3dbb2a 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -791,7 +791,8 @@ def increase_balance(state: BeaconState, index: int, delta: int) -> None: ````python def decrease_balance(state: BeaconState, index: int, delta: int) -> None: - set_balance(state, index, get_balance(state, index) - delta) + cur_balance = get_balance(state, index) + set_balance(state, index, cur_balance - delta if cur_balance >= delta else 0) ```` ### `get_permuted_index` From f9a07f7653890fd74c6c023182ccb56004b5579d Mon Sep 17 00:00:00 2001 From: vbuterin Date: Thu, 7 Mar 2019 04:04:05 -0600 Subject: [PATCH 03/17] Fixed MIN_DEPOSIT_AMOUNT --- specs/core/0_beacon-chain.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index b0b3dbb2a..c548dbe14 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -209,10 +209,10 @@ Code snippets appearing in `this style` are to be interpreted as Python code. | Name | Value | Unit | | - | - | :-: | -| `MIN_DEPOSIT_AMOUNT` | `2**0 * 10**9` (= 2,000,000,000) | Gwei | +| `MIN_DEPOSIT_AMOUNT` | `10**9` (= 1,000,000,000) | Gwei | | `MAX_DEPOSIT_AMOUNT` | `2**5 * 10**9` (= 32,000,000,000) | Gwei | | `EJECTION_BALANCE` | `2**4 * 10**9` (= 16,000,000,000) | Gwei | -| `HIGH_BALANCE_INCREMENT` | `10 ** 9` (= 1,000,000,000) | Gwei | +| `HIGH_BALANCE_INCREMENT` | `10**9` (= 1,000,000,000) | Gwei | ### Initial values From bf6bdbb0210ee8020cac21b3f731178caad03ab7 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Mon, 11 Mar 2019 12:38:11 -0600 Subject: [PATCH 04/17] cleanup minor var errors --- specs/core/0_beacon-chain.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index f5fa2128a..ec9eedb51 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -768,12 +768,12 @@ def set_balance(state: BeaconState, index: int, new_balance: int) -> None: validator = state.validator_registry[index] HALF_INCREMENT = HIGH_BALANCE_INCREMENT // 2 if ( - validator.rounded_balance * HIGH_BALANCE_INCREMENT > new_balance or - validator.rounded_balance * HIGH_BALANCE_INCREMENT + HALF_INCREMENT * 3 < new_balance + validator.high_balance * HIGH_BALANCE_INCREMENT > new_balance or + validator.high_balance * HIGH_BALANCE_INCREMENT + HALF_INCREMENT * 3 < new_balance ): - validator.rounded_balance = new_balance // HIGH_BALANCE_INCREMENT - state.validator_fractional_balances[index] = ( - new_balance - validator.rounded_balance * HIGH_BALANCE_INCREMENT + validator.high_balance = new_balance // HIGH_BALANCE_INCREMENT + state.low_balances[index] = ( + new_balance - validator.high_balance * HIGH_BALANCE_INCREMENT ) ```` From a7544864d5de8eaa27f4630d2740f4acc8383d99 Mon Sep 17 00:00:00 2001 From: Justin Date: Tue, 12 Mar 2019 10:02:52 +0000 Subject: [PATCH 05/17] Update 0_beacon-chain.md --- specs/core/0_beacon-chain.md | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index ec9eedb51..7d59a9e6d 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -203,10 +203,10 @@ Code snippets appearing in `this style` are to be interpreted as Python code. | Name | Value | Unit | | - | - | :-: | -| `MIN_DEPOSIT_AMOUNT` | `10**9` (= 1,000,000,000) | Gwei | +| `MIN_DEPOSIT_AMOUNT` | `2**0 * 10**9` (= 1,000,000,000) | Gwei | | `MAX_DEPOSIT_AMOUNT` | `2**5 * 10**9` (= 32,000,000,000) | Gwei | | `EJECTION_BALANCE` | `2**4 * 10**9` (= 16,000,000,000) | Gwei | -| `HIGH_BALANCE_INCREMENT` | `10**9` (= 1,000,000,000) | Gwei | +| `HIGH_BALANCE_INCREMENT` | `2**0 * 10**9` (= 1,000,000,000) | Gwei | ### Initial values @@ -440,7 +440,7 @@ The types are defined topologically to aid in facilitating an executable version # Was the validator slashed 'slashed': 'bool', # Rounded balance - 'high_balance': 'uint32' + 'high_balance': 'uint64' } ``` @@ -756,25 +756,17 @@ def get_active_validator_indices(validators: List[Validator], epoch: Epoch) -> L ```python def get_balance(state: BeaconState, index: int) -> int: - return ( - state.validator_registry[index].high_balance * HIGH_BALANCE_INCREMENT + - state.low_balances[index] - ) + return state.validator_registry[index].high_balance + state.low_balances[index] ``` #### `set_balance` ````python -def set_balance(state: BeaconState, index: int, new_balance: int) -> None: +def set_balance(state: BeaconState, index: int, balance: int) -> None: validator = state.validator_registry[index] HALF_INCREMENT = HIGH_BALANCE_INCREMENT // 2 - if ( - validator.high_balance * HIGH_BALANCE_INCREMENT > new_balance or - validator.high_balance * HIGH_BALANCE_INCREMENT + HALF_INCREMENT * 3 < new_balance - ): - validator.high_balance = new_balance // HIGH_BALANCE_INCREMENT - state.low_balances[index] = ( - new_balance - validator.high_balance * HIGH_BALANCE_INCREMENT - ) + if validator.high_balance > balance or validator.high_balance + 3 * HALF_INCREMENT < balance: + validator.high_balance = balance - balance % HIGH_BALANCE_INCREMENT + state.low_balances[index] = balance - validator.high_balance ```` #### `increase_balance` From 0a349f8bdc31d08f2c6f4a5b8e98427845c1716e Mon Sep 17 00:00:00 2001 From: Justin Date: Tue, 12 Mar 2019 15:58:31 +0000 Subject: [PATCH 06/17] Update 0_beacon-chain.md --- specs/core/0_beacon-chain.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 7d59a9e6d..63737962d 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -601,7 +601,7 @@ The types are defined topologically to aid in facilitating an executable version # Validator registry 'validator_registry': [Validator], - 'low_balances': ['uint32'], + 'balances': ['uint64'], 'validator_registry_update_epoch': 'uint64', # Randomness and committees @@ -756,7 +756,7 @@ def get_active_validator_indices(validators: List[Validator], epoch: Epoch) -> L ```python def get_balance(state: BeaconState, index: int) -> int: - return state.validator_registry[index].high_balance + state.low_balances[index] + return state.balances[index] ``` #### `set_balance` @@ -766,7 +766,7 @@ def set_balance(state: BeaconState, index: int, balance: int) -> None: HALF_INCREMENT = HIGH_BALANCE_INCREMENT // 2 if validator.high_balance > balance or validator.high_balance + 3 * HALF_INCREMENT < balance: validator.high_balance = balance - balance % HIGH_BALANCE_INCREMENT - state.low_balances[index] = balance - validator.high_balance + state.balances[index] = balance ```` #### `increase_balance` @@ -1377,7 +1377,7 @@ def process_deposit(state: BeaconState, deposit: Deposit) -> None: # Note: In phase 2 registry indices that have been withdrawn for a long time will be recycled. state.validator_registry.append(validator) - state.low_balances.append(0) + state.balances.append(0) set_balance(state, len(state.validator_registry)-1, amount) else: # Increase balance by deposit amount @@ -1567,7 +1567,7 @@ def get_genesis_beacon_state(genesis_validator_deposits: List[Deposit], # Validator registry validator_registry=[], - low_balances=[], + balances=[], validator_registry_update_epoch=GENESIS_EPOCH, # Randomness and committees From dc4b652f72339063bfbaae378e850d173168c9f6 Mon Sep 17 00:00:00 2001 From: Justin Date: Tue, 19 Mar 2019 11:03:42 +0000 Subject: [PATCH 07/17] Only slash active validators This is to prevent a spam/DoS attack where validators with zero balance get "slashed" but no validator loses any balance. --- specs/core/0_beacon-chain.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index a631bf2fc..2113472e3 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -2315,8 +2315,8 @@ def process_proposer_slashing(state: BeaconState, assert slot_to_epoch(proposer_slashing.header_1.slot) == slot_to_epoch(proposer_slashing.header_2.slot) # But the headers are different assert proposer_slashing.header_1 != proposer_slashing.header_2 - # Proposer is not yet slashed - assert proposer.slashed is False + # Proposer is active and not already slashed + assert is_active_validator(proposer) and proposer.slashed is False # Signatures are valid for header in (proposer_slashing.header_1, proposer_slashing.header_2): assert bls_verify( @@ -2355,6 +2355,7 @@ def process_attester_slashing(state: BeaconState, index for index in attestation1.validator_indices if ( index in attestation2.validator_indices and + is_active_validator(state.validator_registry[index]) and state.validator_registry[index].slashed is False ) ] From 2b454d57f11d8e1bde78dd1aa83116df2b2417ee Mon Sep 17 00:00:00 2001 From: Justin Date: Tue, 19 Mar 2019 11:08:17 +0000 Subject: [PATCH 08/17] Update 0_beacon-chain.md --- specs/core/0_beacon-chain.md | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 2113472e3..9ed620b83 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -59,6 +59,7 @@ - [`get_current_epoch`](#get_current_epoch) - [`get_epoch_start_slot`](#get_epoch_start_slot) - [`is_active_validator`](#is_active_validator) + - [`is_slashable_validator`](#is_slashable_validator) - [`get_active_validator_indices`](#get_active_validator_indices) - [`get_permuted_index`](#get_permuted_index) - [`split`](#split) @@ -737,6 +738,18 @@ def is_active_validator(validator: Validator, epoch: Epoch) -> bool: return validator.activation_epoch <= epoch < validator.exit_epoch ``` +### `is_slashable_validator` +```python +def is_slashable_validator(validator: Validator, epoch: Epoch) -> bool: + """ + Check if ``validator`` is slashable. + """ + return ( + validator.activation_epoch <= epoch < validator.withdrawable_epoch and + validator.slashed is False + ) +``` + ### `get_active_validator_indices` ```python @@ -2315,8 +2328,8 @@ def process_proposer_slashing(state: BeaconState, assert slot_to_epoch(proposer_slashing.header_1.slot) == slot_to_epoch(proposer_slashing.header_2.slot) # But the headers are different assert proposer_slashing.header_1 != proposer_slashing.header_2 - # Proposer is active and not already slashed - assert is_active_validator(proposer) and proposer.slashed is False + # Check proposer is slashable + assert is_slashable_validator(proposer) # Signatures are valid for header in (proposer_slashing.header_1, proposer_slashing.header_2): assert bls_verify( @@ -2355,8 +2368,7 @@ def process_attester_slashing(state: BeaconState, index for index in attestation1.validator_indices if ( index in attestation2.validator_indices and - is_active_validator(state.validator_registry[index]) and - state.validator_registry[index].slashed is False + is_slashable_validator(state.validator_registry[index]) ) ] assert len(slashable_indices) >= 1 From 0c383ce4a1d4770bdb21975023a2ca7a3ef5f522 Mon Sep 17 00:00:00 2001 From: Justin Date: Tue, 19 Mar 2019 11:11:18 +0000 Subject: [PATCH 09/17] Update 0_beacon-chain.md --- specs/core/0_beacon-chain.md | 1 - 1 file changed, 1 deletion(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 9ed620b83..d377b8d45 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1412,7 +1412,6 @@ def slash_validator(state: BeaconState, index: ValidatorIndex) -> None: Note that this function mutates ``state``. """ validator = state.validator_registry[index] - assert state.slot < get_epoch_start_slot(validator.withdrawable_epoch) # [TO BE REMOVED IN PHASE 2] exit_validator(state, index) state.latest_slashed_balances[get_current_epoch(state) % LATEST_SLASHED_EXIT_LENGTH] += get_effective_balance(state, index) From e91036cfc9fbf9d05b03da0180ed5be95cc916ca Mon Sep 17 00:00:00 2001 From: Justin Date: Tue, 19 Mar 2019 11:12:50 +0000 Subject: [PATCH 10/17] Update 0_beacon-chain.md --- specs/core/0_beacon-chain.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index d377b8d45..4a6170418 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -2328,7 +2328,7 @@ def process_proposer_slashing(state: BeaconState, # But the headers are different assert proposer_slashing.header_1 != proposer_slashing.header_2 # Check proposer is slashable - assert is_slashable_validator(proposer) + assert is_slashable_validator(proposer, get_current_epoch(state)) # Signatures are valid for header in (proposer_slashing.header_1, proposer_slashing.header_2): assert bls_verify( @@ -2367,7 +2367,7 @@ def process_attester_slashing(state: BeaconState, index for index in attestation1.validator_indices if ( index in attestation2.validator_indices and - is_slashable_validator(state.validator_registry[index]) + is_slashable_validator(state.validator_registry[index], get_current_epoch(state)) ) ] assert len(slashable_indices) >= 1 From 833691b8afe9ca68c75588e0f528780f200de0ee Mon Sep 17 00:00:00 2001 From: Justin Date: Wed, 20 Mar 2019 08:16:39 +0000 Subject: [PATCH 11/17] Update 0_beacon-chain.md --- specs/core/0_beacon-chain.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 4935ab7d7..099d12b95 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -256,7 +256,7 @@ Code snippets appearing in `this style` are to be interpreted as Python code. | `MIN_PENALTY_QUOTIENT` | `2**5` (= 32) | * The `BASE_REWARD_QUOTIENT` parameter dictates the per-epoch reward. It corresponds to ~2.54% annual interest assuming 10 million participating ETH in every epoch. -* 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 transactions per block @@ -789,7 +789,7 @@ def decrease_balance(state: BeaconState, index: int, delta: int) -> None: ```python def get_permuted_index(index: int, list_size: int, seed: Bytes32) -> int: """ - Return `p(index)` in a pseudorandom permutation `p` of `0...list_size-1` with ``seed`` as entropy. + Return `p(index)` in a pseudorandom permutation `p` of `0...list_size - 1` with ``seed`` as entropy. Utilizes 'swap or not' shuffling found in https://link.springer.com/content/pdf/10.1007%2F978-3-642-32009-5_1.pdf @@ -1376,7 +1376,7 @@ def process_deposit(state: BeaconState, deposit: Deposit) -> None: # Note: In phase 2 registry indices that have been withdrawn for a long time will be recycled. state.validator_registry.append(validator) state.balances.append(0) - set_balance(state, len(state.validator_registry)-1, amount) + set_balance(state, len(state.validator_registry) - 1, amount) else: # Increase balance by deposit amount index = validator_pubkeys.index(pubkey) From 47477b8e55dba85f7e4e12c3b0cf99bc594ac81d Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Thu, 21 Mar 2019 09:37:06 -0600 Subject: [PATCH 12/17] cleanup tests to use get_balance and set_balance --- .../block_processing/test_process_deposit.py | 10 ++++---- tests/phase0/test_sanity.py | 23 +++++++++++-------- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/tests/phase0/block_processing/test_process_deposit.py b/tests/phase0/block_processing/test_process_deposit.py index 297ad37f1..9f1b6add6 100644 --- a/tests/phase0/block_processing/test_process_deposit.py +++ b/tests/phase0/block_processing/test_process_deposit.py @@ -5,6 +5,7 @@ import build.phase0.spec as spec from build.phase0.spec import ( Deposit, + get_balance, process_deposit, ) from tests.phase0.helpers import ( @@ -38,8 +39,9 @@ def test_success(state, deposit_data_leaves, pubkeys, privkeys): process_deposit(post_state, deposit) assert len(post_state.validator_registry) == len(state.validator_registry) + 1 - assert len(post_state.validator_balances) == len(state.validator_balances) + 1 + assert len(post_state.balances) == len(state.balances) + 1 assert post_state.validator_registry[index].pubkey == pubkeys[index] + assert get_balance(post_state, index) == spec.MAX_DEPOSIT_AMOUNT assert post_state.deposit_index == post_state.latest_eth1_data.deposit_count return pre_state, deposit, post_state @@ -62,16 +64,16 @@ def test_success_top_up(state, deposit_data_leaves, pubkeys, privkeys): pre_state.latest_eth1_data.deposit_root = root pre_state.latest_eth1_data.deposit_count = len(deposit_data_leaves) - pre_balance = pre_state.validator_balances[validator_index] + pre_balance = get_balance(pre_state, validator_index) post_state = deepcopy(pre_state) process_deposit(post_state, deposit) assert len(post_state.validator_registry) == len(state.validator_registry) - assert len(post_state.validator_balances) == len(state.validator_balances) + assert len(post_state.balances) == len(state.balances) assert post_state.deposit_index == post_state.latest_eth1_data.deposit_count - assert post_state.validator_balances[validator_index] == pre_balance + amount + assert get_balance(post_state, validator_index) == pre_balance + amount return pre_state, deposit, post_state diff --git a/tests/phase0/test_sanity.py b/tests/phase0/test_sanity.py index 91bd9fe7a..ec03fb355 100644 --- a/tests/phase0/test_sanity.py +++ b/tests/phase0/test_sanity.py @@ -21,6 +21,7 @@ from build.phase0.spec import ( # functions get_active_validator_indices, get_attestation_participants, + get_balance, get_block_root, get_crosslink_committees_at_slot, get_current_epoch, @@ -28,6 +29,7 @@ from build.phase0.spec import ( get_state_root, advance_slot, cache_state, + set_balance, verify_merkle_branch, hash, ) @@ -168,7 +170,7 @@ def test_proposer_slashing(state, pubkeys, privkeys): assert slashed_validator.exit_epoch < spec.FAR_FUTURE_EPOCH assert slashed_validator.withdrawable_epoch < spec.FAR_FUTURE_EPOCH # lost whistleblower reward - assert test_state.validator_balances[validator_index] < state.validator_balances[validator_index] + assert get_balance(test_state, validator_index) < get_balance(state, validator_index) return state, [block], test_state @@ -203,7 +205,8 @@ def test_deposit_in_block(state, deposit_data_leaves, pubkeys, privkeys): state_transition(post_state, block) assert len(post_state.validator_registry) == len(state.validator_registry) + 1 - assert len(post_state.validator_balances) == len(state.validator_balances) + 1 + assert len(post_state.balances) == len(state.balances) + 1 + assert get_balance(post_state, index) == spec.MAX_DEPOSIT_AMOUNT assert post_state.validator_registry[index].pubkey == pubkeys[index] return pre_state, [block], post_state @@ -238,12 +241,12 @@ def test_deposit_top_up(state, pubkeys, privkeys, deposit_data_leaves): block = build_empty_block_for_next_slot(pre_state) block.body.deposits.append(deposit) - pre_balance = pre_state.validator_balances[validator_index] + pre_balance = get_balance(pre_state, validator_index) post_state = deepcopy(pre_state) state_transition(post_state, block) assert len(post_state.validator_registry) == len(pre_state.validator_registry) - assert len(post_state.validator_balances) == len(pre_state.validator_balances) - assert post_state.validator_balances[validator_index] == pre_balance + amount + assert len(post_state.balances) == len(pre_state.balances) + assert get_balance(post_state, validator_index) == pre_balance + amount return pre_state, [block], post_state @@ -412,8 +415,8 @@ def test_transfer(state, pubkeys, privkeys): recipient_index = get_active_validator_indices(pre_state.validator_registry, current_epoch)[0] transfer_pubkey = pubkeys[-1] transfer_privkey = privkeys[-1] - amount = pre_state.validator_balances[sender_index] - pre_transfer_recipient_balance = pre_state.validator_balances[recipient_index] + amount = get_balance(pre_state, sender_index) + pre_transfer_recipient_balance = get_balance(pre_state, recipient_index) transfer = Transfer( sender=sender_index, recipient=recipient_index, @@ -448,8 +451,8 @@ def test_transfer(state, pubkeys, privkeys): block.body.transfers.append(transfer) state_transition(post_state, block) - sender_balance = post_state.validator_balances[sender_index] - recipient_balance = post_state.validator_balances[recipient_index] + sender_balance = get_balance(post_state, sender_index) + recipient_balance = get_balance(post_state, recipient_index) assert sender_balance == 0 assert recipient_balance == pre_transfer_recipient_balance + amount @@ -465,7 +468,7 @@ def test_ejection(state): assert pre_state.validator_registry[validator_index].exit_epoch == spec.FAR_FUTURE_EPOCH # set validator balance to below ejection threshold - pre_state.validator_balances[validator_index] = spec.EJECTION_BALANCE - 1 + set_balance(pre_state, validator_index, spec.EJECTION_BALANCE - 1) post_state = deepcopy(pre_state) # From f6da42ffb32fed8e22769dbf77f906889b1e02a2 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Thu, 21 Mar 2019 10:04:20 -0600 Subject: [PATCH 13/17] fix markdown issues --- specs/core/0_beacon-chain.md | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 3bc95f717..4eee3dcb5 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -61,9 +61,9 @@ - [`is_active_validator`](#is_active_validator) - [`get_active_validator_indices`](#get_active_validator_indices) - [`get_balance`](#get_balance) - - [`set_balance`](#set_balance) - - [`increase_balance`](#increase_balance) - - [`decrease_balance`](#decrease_balance) + - [`set_balance`](#set_balance) + - [`increase_balance`](#increase_balance) + - [`decrease_balance`](#decrease_balance) - [`get_permuted_index`](#get_permuted_index) - [`get_split_offset`](#get_split_offset) - [`get_epoch_committee_count`](#get_epoch_committee_count) @@ -760,31 +760,32 @@ def get_active_validator_indices(validators: List[Validator], epoch: Epoch) -> L def get_balance(state: BeaconState, index: int) -> int: return state.balances[index] ``` -#### `set_balance` -````python +### `set_balance` + +```python def set_balance(state: BeaconState, index: int, balance: int) -> None: validator = state.validator_registry[index] HALF_INCREMENT = HIGH_BALANCE_INCREMENT // 2 if validator.high_balance > balance or validator.high_balance + 3 * HALF_INCREMENT < balance: validator.high_balance = balance - balance % HIGH_BALANCE_INCREMENT state.balances[index] = balance -```` +``` -#### `increase_balance` +### `increase_balance` -````python +```python def increase_balance(state: BeaconState, index: int, delta: int) -> None: set_balance(state, index, get_balance(state, index) + delta) -```` +``` -#### `decrease_balance` +### `decrease_balance` -````python +```python def decrease_balance(state: BeaconState, index: int, delta: int) -> None: cur_balance = get_balance(state, index) set_balance(state, index, cur_balance - delta if cur_balance >= delta else 0) -```` +``` ### `get_permuted_index` From d3f175d7289befde23d9810a29ee1ca40f02216a Mon Sep 17 00:00:00 2001 From: terence tsao Date: Thu, 21 Mar 2019 11:33:36 -0700 Subject: [PATCH 14/17] Update sync_protocol.md --- specs/light_client/sync_protocol.md | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/specs/light_client/sync_protocol.md b/specs/light_client/sync_protocol.md index 8878545bb..575df60fe 100644 --- a/specs/light_client/sync_protocol.md +++ b/specs/light_client/sync_protocol.md @@ -1,6 +1,18 @@ -# Beacon chain light client syncing +# Beacon Chain Light Client Syncing + +__NOTICE__: This document is a work-in-progress for researchers and implementers. One of the design goals of the eth2 beacon chain is light-client friendlines, both to allow low-resource clients (mobile phones, IoT, etc) to maintain access to the blockchain in a reasonably safe way, but also to facilitate the development of "bridges" between the eth2 beacon chain and other chains. + +## Table of Contents + + +- [Beacon Chain Light Client Syncing](#beacon-chain-light-client-syncing) + - [Table of Contents](#table-of-contents) + - [Light client state](#light-client-state) + - [Updating the shuffled committee](#updating-the-shuffled-committee) + - [Computing the current committee](#computing-the-current-committee) + - [Verifying blocks](#verifying-blocks) + -One of the design goals of the eth2 beacon chain is light-client friendlines, both to allow low-resource clients (mobile phones, IoT, etc) to maintain access to the blockchain in a reasonably safe way, but also to facilitate the development of "bridges" between the eth2 beacon chain and other chains. ### Preliminaries From 3ece05ccc1a5e126e934c57aa091386a4afeb8ef Mon Sep 17 00:00:00 2001 From: vbuterin Date: Thu, 21 Mar 2019 16:36:31 -0500 Subject: [PATCH 15/17] Small cosmetic change to slashable attestations --- specs/core/0_beacon-chain.md | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 1067c3dc0..c7c74279f 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -182,7 +182,7 @@ Code snippets appearing in `this style` are to be interpreted as Python code. | `SHARD_COUNT` | `2**10` (= 1,024) | | `TARGET_COMMITTEE_SIZE` | `2**7` (= 128) | | `MAX_BALANCE_CHURN_QUOTIENT` | `2**5` (= 32) | -| `MAX_INDICES_PER_SLASHABLE_VOTE` | `2**12` (= 4,096) | +| `MAX_SLASHABLE_ATTESTATION_PARTICIPANTS` | `2**12` (= 4,096) | | `MAX_EXIT_DEQUEUES_PER_EPOCH` | `2**2` (= 4) | | `SHUFFLE_ROUND_COUNT` | 90 | @@ -1159,7 +1159,7 @@ def verify_slashable_attestation(state: BeaconState, slashable_attestation: Slas if slashable_attestation.custody_bitfield != b'\x00' * len(slashable_attestation.custody_bitfield): # [TO BE REMOVED IN PHASE 1] return False - if len(slashable_attestation.validator_indices) == 0: + if not (1 <= len(slashable_attestation.validator_indices) <= MAX_SLASHABLE_ATTESTATION_PARTICIPANTS): return False for i in range(len(slashable_attestation.validator_indices) - 1): @@ -1169,9 +1169,6 @@ def verify_slashable_attestation(state: BeaconState, slashable_attestation: Slas if not verify_bitfield(slashable_attestation.custody_bitfield, len(slashable_attestation.validator_indices)): return False - if len(slashable_attestation.validator_indices) > MAX_INDICES_PER_SLASHABLE_VOTE: - return False - custody_bit_0_indices = [] custody_bit_1_indices = [] for i, validator_index in enumerate(slashable_attestation.validator_indices): From e313c5ba5abd949e2af87919a36f84937ee6b68c Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Thu, 21 Mar 2019 17:08:54 -0600 Subject: [PATCH 16/17] add tests for proposer slashing --- .../test_process_proposer_slashing.py | 97 +++++++++++++++++++ tests/phase0/helpers.py | 44 +++++++++ tests/phase0/test_sanity.py | 39 +------- 3 files changed, 144 insertions(+), 36 deletions(-) create mode 100644 tests/phase0/block_processing/test_process_proposer_slashing.py diff --git a/tests/phase0/block_processing/test_process_proposer_slashing.py b/tests/phase0/block_processing/test_process_proposer_slashing.py new file mode 100644 index 000000000..467d2164b --- /dev/null +++ b/tests/phase0/block_processing/test_process_proposer_slashing.py @@ -0,0 +1,97 @@ +from copy import deepcopy +import pytest + +import build.phase0.spec as spec +from build.phase0.spec import ( + get_balance, + get_current_epoch, + process_proposer_slashing, +) +from tests.phase0.helpers import ( + get_valid_proposer_slashing, +) + +# mark entire file as 'header' +pytestmark = pytest.mark.proposer_slashings + + +def run_proposer_slashing_processing(state, proposer_slashing, valid=True): + """ + Run ``process_proposer_slashing`` returning the pre and post state. + If ``valid == False``, run expecting ``AssertionError`` + """ + post_state = deepcopy(state) + + if not valid: + with pytest.raises(AssertionError): + process_proposer_slashing(post_state, proposer_slashing) + return state, None + + process_proposer_slashing(post_state, proposer_slashing) + + slashed_validator = post_state.validator_registry[proposer_slashing.proposer_index] + assert not slashed_validator.initiated_exit + assert slashed_validator.slashed + assert slashed_validator.exit_epoch < spec.FAR_FUTURE_EPOCH + assert slashed_validator.withdrawable_epoch < spec.FAR_FUTURE_EPOCH + # lost whistleblower reward + assert ( + get_balance(post_state, proposer_slashing.proposer_index) < + get_balance(state, proposer_slashing.proposer_index) + ) + + return state, post_state + + +def test_success(state): + proposer_slashing = get_valid_proposer_slashing(state) + + pre_state, post_state = run_proposer_slashing_processing(state, proposer_slashing) + + return pre_state, proposer_slashing, post_state + + +def test_epochs_are_different(state): + proposer_slashing = get_valid_proposer_slashing(state) + + # set slots to be in different epochs + proposer_slashing.header_2.slot += spec.SLOTS_PER_EPOCH + + pre_state, post_state = run_proposer_slashing_processing(state, proposer_slashing, False) + + return pre_state, proposer_slashing, post_state + + +def test_headers_are_same(state): + proposer_slashing = get_valid_proposer_slashing(state) + + # set headers to be the same + proposer_slashing.header_2 = proposer_slashing.header_1 + + pre_state, post_state = run_proposer_slashing_processing(state, proposer_slashing, False) + + return pre_state, proposer_slashing, post_state + + +def test_proposer_is_slashed(state): + proposer_slashing = get_valid_proposer_slashing(state) + + # set proposer to slashed + state.validator_registry[proposer_slashing.proposer_index].slashed = True + + pre_state, post_state = run_proposer_slashing_processing(state, proposer_slashing, False) + + return pre_state, proposer_slashing, post_state + + +def test_proposer_is_withdrawn(state): + proposer_slashing = get_valid_proposer_slashing(state) + + # set proposer withdrawable_epoch in past + current_epoch = get_current_epoch(state) + proposer_index = proposer_slashing.proposer_index + state.validator_registry[proposer_index].withdrawable_epoch = current_epoch - 1 + + pre_state, post_state = run_proposer_slashing_processing(state, proposer_slashing, False) + + return pre_state, proposer_slashing, post_state diff --git a/tests/phase0/helpers.py b/tests/phase0/helpers.py index 5c61685a6..3987289bf 100644 --- a/tests/phase0/helpers.py +++ b/tests/phase0/helpers.py @@ -7,14 +7,18 @@ from build.phase0.utils.minimal_ssz import signed_root from build.phase0.spec import ( # constants EMPTY_SIGNATURE, + ZERO_HASH, # SSZ AttestationData, + BeaconBlockHeader, Deposit, DepositInput, DepositData, Eth1Data, + ProposerSlashing, VoluntaryExit, # functions + get_active_validator_indices, get_block_root, get_current_epoch, get_domain, @@ -199,3 +203,43 @@ def build_deposit(state, ) return deposit, root, deposit_data_leaves + + +def get_valid_proposer_slashing(state): + current_epoch = get_current_epoch(state) + validator_index = get_active_validator_indices(state.validator_registry, current_epoch)[-1] + privkey = pubkey_to_privkey[state.validator_registry[validator_index].pubkey] + slot = state.slot + + header_1 = BeaconBlockHeader( + slot=slot, + previous_block_root=ZERO_HASH, + state_root=ZERO_HASH, + block_body_root=ZERO_HASH, + signature=EMPTY_SIGNATURE, + ) + header_2 = deepcopy(header_1) + header_2.previous_block_root = b'\x02' * 32 + header_2.slot = slot + 1 + + domain = get_domain( + fork=state.fork, + epoch=get_current_epoch(state), + domain_type=spec.DOMAIN_BEACON_BLOCK, + ) + header_1.signature = bls.sign( + message_hash=signed_root(header_1), + privkey=privkey, + domain=domain, + ) + header_2.signature = bls.sign( + message_hash=signed_root(header_2), + privkey=privkey, + domain=domain, + ) + + return ProposerSlashing( + proposer_index=validator_index, + header_1=header_1, + header_2=header_2, + ) diff --git a/tests/phase0/test_sanity.py b/tests/phase0/test_sanity.py index ec03fb355..444075a13 100644 --- a/tests/phase0/test_sanity.py +++ b/tests/phase0/test_sanity.py @@ -46,6 +46,7 @@ from tests.phase0.helpers import ( build_deposit_data, build_empty_block_for_next_slot, force_registry_change_at_next_epoch, + get_valid_proposer_slashing, ) @@ -117,42 +118,8 @@ def test_empty_epoch_transition_not_finalizing(state): def test_proposer_slashing(state, pubkeys, privkeys): test_state = deepcopy(state) - current_epoch = get_current_epoch(test_state) - validator_index = get_active_validator_indices(test_state.validator_registry, current_epoch)[-1] - privkey = privkeys[validator_index] - slot = spec.GENESIS_SLOT - header_1 = BeaconBlockHeader( - slot=slot, - previous_block_root=ZERO_HASH, - state_root=ZERO_HASH, - block_body_root=ZERO_HASH, - signature=EMPTY_SIGNATURE, - ) - header_2 = deepcopy(header_1) - header_2.previous_block_root = b'\x02' * 32 - header_2.slot = slot + 1 - - domain = get_domain( - fork=test_state.fork, - epoch=get_current_epoch(test_state), - domain_type=spec.DOMAIN_BEACON_BLOCK, - ) - header_1.signature = bls.sign( - message_hash=signed_root(header_1), - privkey=privkey, - domain=domain, - ) - header_2.signature = bls.sign( - message_hash=signed_root(header_2), - privkey=privkey, - domain=domain, - ) - - proposer_slashing = ProposerSlashing( - proposer_index=validator_index, - header_1=header_1, - header_2=header_2, - ) + proposer_slashing = get_valid_proposer_slashing(state) + validator_index = proposer_slashing.proposer_index # # Add to state via block transition From 11c3291817f3d590723298877c41d0bf244b789b Mon Sep 17 00:00:00 2001 From: terence tsao Date: Thu, 21 Mar 2019 16:30:45 -0700 Subject: [PATCH 17/17] Update sync_protocol.md --- specs/light_client/sync_protocol.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/specs/light_client/sync_protocol.md b/specs/light_client/sync_protocol.md index 8878545bb..143f82a39 100644 --- a/specs/light_client/sync_protocol.md +++ b/specs/light_client/sync_protocol.md @@ -40,8 +40,8 @@ def get_later_start_epoch(slot: Slot) -> int: return slot - slot % PERSISTENT_COMMITTEE_PERIOD - PERSISTENT_COMMITTEE_PERIOD def get_earlier_period_data(block: ExtendedBeaconBlock, shard_id: Shard) -> PeriodData: - period_start = get_earlier_start_epoch(header.slot) - validator_count = len(get_active_validator_indices(state, period_start)) + period_start = get_earlier_start_epoch(block.slot) + validator_count = len(get_active_validator_indices(block.state, period_start)) committee_count = validator_count // (SHARD_COUNT * TARGET_COMMITTEE_SIZE) + 1 indices = get_shuffled_committee(block.state, shard_id, period_start, 0, committee_count) return PeriodData( @@ -51,8 +51,8 @@ def get_earlier_period_data(block: ExtendedBeaconBlock, shard_id: Shard) -> Peri ) def get_later_period_data(block: ExtendedBeaconBlock, shard_id: Shard) -> PeriodData: - period_start = get_later_start_epoch(header.slot) - validator_count = len(get_active_validator_indices(state, period_start)) + period_start = get_later_start_epoch(block.slot) + validator_count = len(get_active_validator_indices(block.state, period_start)) committee_count = validator_count // (SHARD_COUNT * TARGET_COMMITTEE_SIZE) + 1 indices = get_shuffled_committee(block.state, shard_id, period_start, 0, committee_count) return PeriodData(