Merge branch 'dev' into carl-patch-1
This commit is contained in:
commit
d118eb03c9
|
@ -15,13 +15,13 @@ jobs:
|
|||
name: Run py-tests
|
||||
command: make test
|
||||
|
||||
- run:
|
||||
name: Generate YAML tests
|
||||
command: make gen_yaml_tests
|
||||
|
||||
# TODO in future PR (after #851): decide on CI triggering of yaml tests building,
|
||||
# TODO see #928: decide on CI triggering of yaml tests building,
|
||||
# and destination of output (new yaml tests LFS-configured repository)
|
||||
#
|
||||
# - run:
|
||||
# name: Generate YAML tests
|
||||
# command: make gen_yaml_tests
|
||||
#
|
||||
# - store_artifacts:
|
||||
# path: test-reports
|
||||
# destination: test-reports
|
||||
|
|
5
Makefile
5
Makefile
|
@ -2,7 +2,6 @@ SPEC_DIR = ./specs
|
|||
SCRIPT_DIR = ./scripts
|
||||
TEST_LIBS_DIR = ./test_libs
|
||||
PY_SPEC_DIR = $(TEST_LIBS_DIR)/pyspec
|
||||
PY_TEST_DIR = ./py_tests
|
||||
YAML_TEST_DIR = ./yaml_tests
|
||||
GENERATOR_DIR = ./test_generators
|
||||
CONFIGS_DIR = ./configs
|
||||
|
@ -24,7 +23,7 @@ all: $(PY_SPEC_ALL_TARGETS) $(YAML_TEST_DIR) $(YAML_TEST_TARGETS)
|
|||
clean:
|
||||
rm -rf $(YAML_TEST_DIR)
|
||||
rm -rf $(GENERATOR_VENVS)
|
||||
rm -rf $(PY_TEST_DIR)/venv $(PY_TEST_DIR)/.pytest_cache
|
||||
rm -rf $(PY_SPEC_DIR)/venv $(PY_SPEC_DIR)/.pytest_cache
|
||||
rm -rf $(PY_SPEC_ALL_TARGETS)
|
||||
|
||||
# "make gen_yaml_tests" to run generators
|
||||
|
@ -32,7 +31,7 @@ gen_yaml_tests: $(YAML_TEST_DIR) $(YAML_TEST_TARGETS)
|
|||
|
||||
# runs a limited set of tests against a minimal config
|
||||
test: $(PY_SPEC_ALL_TARGETS)
|
||||
cd $(PY_TEST_DIR); python3 -m venv venv; . venv/bin/activate; pip3 install -r requirements.txt; pytest -m minimal_config .
|
||||
cd $(PY_SPEC_DIR); python3 -m venv venv; . venv/bin/activate; pip3 install -r requirements.txt; python -m pytest -m minimal_config .
|
||||
|
||||
# "make pyspec" to create the pyspec for all phases.
|
||||
pyspec: $(PY_SPEC_ALL_TARGETS)
|
||||
|
|
|
@ -37,6 +37,5 @@ The following are the broad design goals for Ethereum 2.0:
|
|||
|
||||
Documentation on the different components used during spec writing can be found here:
|
||||
* [YAML Test Generators](test_generators/README.md)
|
||||
* [Executable Python Spec](test_libs/eth2spec/README.md)
|
||||
* [Py-tests](py_tests/README.md)
|
||||
* [Executable Python Spec, with Py-tests](test_libs/pyspec/README.md)
|
||||
|
||||
|
|
|
@ -5,16 +5,16 @@
|
|||
|
||||
# Misc
|
||||
# ---------------------------------------------------------------
|
||||
# 2**10 ` (= 1,024)
|
||||
# 2**10 (= 1,024)
|
||||
SHARD_COUNT: 1024
|
||||
# 2**7 ` (= 128)
|
||||
# 2**7 (= 128)
|
||||
TARGET_COMMITTEE_SIZE: 128
|
||||
# 2**5 ` (= 32)
|
||||
MAX_BALANCE_CHURN_QUOTIENT: 32
|
||||
# 2**12 ` (= 4,096)
|
||||
# 2**12 (= 4,096)
|
||||
MAX_ATTESTATION_PARTICIPANTS: 4096
|
||||
# 2**2 ` (= 4)
|
||||
MAX_EXIT_DEQUEUES_PER_EPOCH: 4
|
||||
# 2**2 (= 4)
|
||||
MIN_PER_EPOCH_CHURN_LIMIT: 4
|
||||
# 2**16 (= 65,536)
|
||||
CHURN_LIMIT_QUOTIENT: 65536
|
||||
# See issue 563
|
||||
SHUFFLE_ROUND_COUNT: 90
|
||||
|
||||
|
@ -23,19 +23,19 @@ SHUFFLE_ROUND_COUNT: 90
|
|||
# ---------------------------------------------------------------
|
||||
# **TBD**
|
||||
DEPOSIT_CONTRACT_ADDRESS: 0x1234567890123456789012345678901234567890
|
||||
# 2**5 ` (= 32)
|
||||
# 2**5 (= 32)
|
||||
DEPOSIT_CONTRACT_TREE_DEPTH: 32
|
||||
|
||||
|
||||
# Gwei values
|
||||
# ---------------------------------------------------------------
|
||||
# 2**0 * 10**9 ` (= 1,000,000,000) Gwei
|
||||
# 2**0 * 10**9 (= 1,000,000,000) Gwei
|
||||
MIN_DEPOSIT_AMOUNT: 1000000000
|
||||
# 2**5 * 10**9 ` (= 32,000,000,000) Gwei
|
||||
# 2**5 * 10**9 (= 32,000,000,000) Gwei
|
||||
MAX_DEPOSIT_AMOUNT: 32000000000
|
||||
# 2**4 * 10**9 ` (= 16,000,000,000) Gwei
|
||||
# 2**4 * 10**9 (= 16,000,000,000) Gwei
|
||||
EJECTION_BALANCE: 16000000000
|
||||
# 2**0 * 10**9 ` (= 1,000,000,000) Gwei
|
||||
# 2**0 * 10**9 (= 1,000,000,000) Gwei
|
||||
HIGH_BALANCE_INCREMENT: 1000000000
|
||||
|
||||
|
||||
|
@ -54,63 +54,63 @@ BLS_WITHDRAWAL_PREFIX_BYTE: 0x00
|
|||
# ---------------------------------------------------------------
|
||||
# 6 seconds 6 seconds
|
||||
SECONDS_PER_SLOT: 6
|
||||
# 2**2 ` (= 4) slots 24 seconds
|
||||
# 2**2 (= 4) slots 24 seconds
|
||||
MIN_ATTESTATION_INCLUSION_DELAY: 4
|
||||
# 2**6 ` (= 64) slots 6.4 minutes
|
||||
# 2**6 (= 64) slots 6.4 minutes
|
||||
SLOTS_PER_EPOCH: 64
|
||||
# 2**0 ` (= 1) epochs 6.4 minutes
|
||||
# 2**0 (= 1) epochs 6.4 minutes
|
||||
MIN_SEED_LOOKAHEAD: 1
|
||||
# 2**2 ` (= 4) epochs 25.6 minutes
|
||||
# 2**2 (= 4) epochs 25.6 minutes
|
||||
ACTIVATION_EXIT_DELAY: 4
|
||||
# 2**4 ` (= 16) epochs ~1.7 hours
|
||||
EPOCHS_PER_ETH1_VOTING_PERIOD: 16
|
||||
# 2**13 ` (= 8,192) slots ~13 hours
|
||||
# 2**10 (= 1,024) slots ~1.7 hours
|
||||
SLOTS_PER_ETH1_VOTING_PERIOD: 1024
|
||||
# 2**13 (= 8,192) slots ~13 hours
|
||||
SLOTS_PER_HISTORICAL_ROOT: 8192
|
||||
# 2**8 ` (= 256) epochs ~27 hours
|
||||
# 2**8 (= 256) epochs ~27 hours
|
||||
MIN_VALIDATOR_WITHDRAWABILITY_DELAY: 256
|
||||
# 2**11 ` (= 2,048) epochs 9 days
|
||||
# 2**11 (= 2,048) epochs 9 days
|
||||
PERSISTENT_COMMITTEE_PERIOD: 2048
|
||||
# 2**6 ` (= 64)
|
||||
# 2**6 (= 64) epochs ~7 hours
|
||||
MAX_CROSSLINK_EPOCHS: 64
|
||||
|
||||
|
||||
# State list lengths
|
||||
# ---------------------------------------------------------------
|
||||
# 2**13 ` (= 8,192) epochs ~36 days
|
||||
# 2**13 (= 8,192) epochs ~36 days
|
||||
LATEST_RANDAO_MIXES_LENGTH: 8192
|
||||
# 2**13 ` (= 8,192) epochs ~36 days
|
||||
# 2**13 (= 8,192) epochs ~36 days
|
||||
LATEST_ACTIVE_INDEX_ROOTS_LENGTH: 8192
|
||||
# 2**13 ` (= 8,192) epochs ~36 days
|
||||
# 2**13 (= 8,192) epochs ~36 days
|
||||
LATEST_SLASHED_EXIT_LENGTH: 8192
|
||||
|
||||
|
||||
# Reward and penalty quotients
|
||||
# ---------------------------------------------------------------
|
||||
# 2**5 ` (= 32)
|
||||
# 2**5 (= 32)
|
||||
BASE_REWARD_QUOTIENT: 32
|
||||
# 2**9 ` (= 512)
|
||||
# 2**9 (= 512)
|
||||
WHISTLEBLOWING_REWARD_QUOTIENT: 512
|
||||
# 2**3 ` (= 8)
|
||||
# 2**3 (= 8)
|
||||
PROPOSER_REWARD_QUOTIENT: 8
|
||||
# 2**24 ` (= 16,777,216)
|
||||
# 2**24 (= 16,777,216)
|
||||
INACTIVITY_PENALTY_QUOTIENT: 16777216
|
||||
|
||||
|
||||
# Max operations per block
|
||||
# ---------------------------------------------------------------
|
||||
# 2**5 ` (= 32)
|
||||
# 2**5 (= 32)
|
||||
MIN_PENALTY_QUOTIENT: 32
|
||||
# 2**4 ` (= 16)
|
||||
# 2**4 (= 16)
|
||||
MAX_PROPOSER_SLASHINGS: 16
|
||||
# 2**0 ` (= 1)
|
||||
# 2**0 (= 1)
|
||||
MAX_ATTESTER_SLASHINGS: 1
|
||||
# 2**7 ` (= 128)
|
||||
# 2**7 (= 128)
|
||||
MAX_ATTESTATIONS: 128
|
||||
# 2**4 ` (= 16)
|
||||
# 2**4 (= 16)
|
||||
MAX_DEPOSITS: 16
|
||||
# 2**4 ` (= 16)
|
||||
# 2**4 (= 16)
|
||||
MAX_VOLUNTARY_EXITS: 16
|
||||
# 2**4 ` (= 16)
|
||||
# 2**4 (= 16)
|
||||
MAX_TRANSFERS: 16
|
||||
|
||||
|
||||
|
|
|
@ -9,13 +9,13 @@ SHARD_COUNT: 8
|
|||
|
||||
# [customized] unsecure, but fast
|
||||
TARGET_COMMITTEE_SIZE: 4
|
||||
# 2**5 ` (= 32)
|
||||
MAX_BALANCE_CHURN_QUOTIENT: 32
|
||||
# 2**12 ` (= 4,096)
|
||||
# 2**12 (= 4,096)
|
||||
MAX_ATTESTATION_PARTICIPANTS: 4096
|
||||
# 2**2 ` (= 4)
|
||||
MAX_EXIT_DEQUEUES_PER_EPOCH: 4
|
||||
# See issue 563
|
||||
# 2**2 (= 4)
|
||||
MIN_PER_EPOCH_CHURN_LIMIT: 4
|
||||
# 2**16 (= 65,536)
|
||||
CHURN_LIMIT_QUOTIENT: 65536
|
||||
# [customized] Faster, but unsecure.
|
||||
SHUFFLE_ROUND_COUNT: 10
|
||||
|
||||
|
||||
|
@ -23,19 +23,19 @@ SHUFFLE_ROUND_COUNT: 10
|
|||
# ---------------------------------------------------------------
|
||||
# **TBD**
|
||||
DEPOSIT_CONTRACT_ADDRESS: 0x1234567890123456789012345678901234567890
|
||||
# 2**5 ` (= 32)
|
||||
# 2**5 (= 32)
|
||||
DEPOSIT_CONTRACT_TREE_DEPTH: 32
|
||||
|
||||
|
||||
# Gwei values
|
||||
# ---------------------------------------------------------------
|
||||
# 2**0 * 10**9 ` (= 1,000,000,000) Gwei
|
||||
# 2**0 * 10**9 (= 1,000,000,000) Gwei
|
||||
MIN_DEPOSIT_AMOUNT: 1000000000
|
||||
# 2**5 * 10**9 ` (= 32,000,000,000) Gwei
|
||||
# 2**5 * 10**9 (= 32,000,000,000) Gwei
|
||||
MAX_DEPOSIT_AMOUNT: 32000000000
|
||||
# 2**4 * 10**9 ` (= 16,000,000,000) Gwei
|
||||
# 2**4 * 10**9 (= 16,000,000,000) Gwei
|
||||
EJECTION_BALANCE: 16000000000
|
||||
# 2**0 * 10**9 ` (= 1,000,000,000) Gwei
|
||||
# 2**0 * 10**9 (= 1,000,000,000) Gwei
|
||||
HIGH_BALANCE_INCREMENT: 1000000000
|
||||
|
||||
|
||||
|
@ -58,19 +58,19 @@ SECONDS_PER_SLOT: 6
|
|||
MIN_ATTESTATION_INCLUSION_DELAY: 2
|
||||
# [customized] fast epochs
|
||||
SLOTS_PER_EPOCH: 8
|
||||
# 2**0 ` (= 1) epochs 6.4 minutes
|
||||
# 2**0 (= 1) epochs 6.4 minutes
|
||||
MIN_SEED_LOOKAHEAD: 1
|
||||
# 2**2 ` (= 4) epochs 25.6 minutes
|
||||
# 2**2 (= 4) epochs 25.6 minutes
|
||||
ACTIVATION_EXIT_DELAY: 4
|
||||
# [customized] higher frequency new deposits from eth1 for testing
|
||||
EPOCHS_PER_ETH1_VOTING_PERIOD: 2
|
||||
SLOTS_PER_ETH1_VOTING_PERIOD: 16
|
||||
# [customized] smaller state
|
||||
SLOTS_PER_HISTORICAL_ROOT: 64
|
||||
# 2**8 ` (= 256) epochs ~27 hours
|
||||
# 2**8 (= 256) epochs ~27 hours
|
||||
MIN_VALIDATOR_WITHDRAWABILITY_DELAY: 256
|
||||
# 2**11 ` (= 2,048) epochs 9 days
|
||||
# 2**11 (= 2,048) epochs 9 days
|
||||
PERSISTENT_COMMITTEE_PERIOD: 2048
|
||||
# 2**6 ` (= 64)
|
||||
# 2**6 (= 64) epochs ~7 hours
|
||||
MAX_CROSSLINK_EPOCHS: 64
|
||||
|
||||
|
||||
|
@ -86,31 +86,31 @@ LATEST_SLASHED_EXIT_LENGTH: 64
|
|||
|
||||
# Reward and penalty quotients
|
||||
# ---------------------------------------------------------------
|
||||
# 2**5 ` (= 32)
|
||||
# 2**5 (= 32)
|
||||
BASE_REWARD_QUOTIENT: 32
|
||||
# 2**9 ` (= 512)
|
||||
# 2**9 (= 512)
|
||||
WHISTLEBLOWING_REWARD_QUOTIENT: 512
|
||||
# 2**3 ` (= 8)
|
||||
# 2**3 (= 8)
|
||||
PROPOSER_REWARD_QUOTIENT: 8
|
||||
# 2**24 ` (= 16,777,216)
|
||||
# 2**24 (= 16,777,216)
|
||||
INACTIVITY_PENALTY_QUOTIENT: 16777216
|
||||
|
||||
|
||||
# Max operations per block
|
||||
# ---------------------------------------------------------------
|
||||
# 2**5 ` (= 32)
|
||||
# 2**5 (= 32)
|
||||
MIN_PENALTY_QUOTIENT: 32
|
||||
# 2**4 ` (= 16)
|
||||
# 2**4 (= 16)
|
||||
MAX_PROPOSER_SLASHINGS: 16
|
||||
# 2**0 ` (= 1)
|
||||
# 2**0 (= 1)
|
||||
MAX_ATTESTER_SLASHINGS: 1
|
||||
# 2**7 ` (= 128)
|
||||
# 2**7 (= 128)
|
||||
MAX_ATTESTATIONS: 128
|
||||
# 2**4 ` (= 16)
|
||||
# 2**4 (= 16)
|
||||
MAX_DEPOSITS: 16
|
||||
# 2**4 ` (= 16)
|
||||
# 2**4 (= 16)
|
||||
MAX_VOLUNTARY_EXITS: 16
|
||||
# 2**4 ` (= 16)
|
||||
# 2**4 (= 16)
|
||||
MAX_TRANSFERS: 16
|
||||
|
||||
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
# ETH 2.0 py-tests
|
||||
|
||||
These tests are not intended for client-consumption.
|
||||
These tests are sanity tests, to verify if the spec itself is consistent.
|
||||
|
||||
There are ideas to port these tests to the YAML test suite,
|
||||
but we are still looking for inputs on how this should work.
|
||||
|
||||
## How to run tests
|
||||
|
||||
### Automated
|
||||
|
||||
Run `make test` from the root of the spec repository.
|
||||
|
||||
### Manual
|
||||
|
||||
From within the py_tests folder:
|
||||
|
||||
Install dependencies:
|
||||
```bash
|
||||
python3 -m venv venv
|
||||
. venv/bin/activate
|
||||
pip3 install -r requirements.txt
|
||||
```
|
||||
Note: make sure to run `make pyspec` from the root of the specs repository, to build the pyspec requirement.
|
||||
|
||||
Run the tests:
|
||||
```
|
||||
pytest -m minimal_config .
|
||||
```
|
|
@ -1,7 +0,0 @@
|
|||
eth-utils>=1.3.0,<2
|
||||
eth-typing>=2.1.0,<3.0.0
|
||||
oyaml==0.7
|
||||
pycryptodome==3.7.3
|
||||
py_ecc>=1.6.0
|
||||
pytest>=3.6,<3.7
|
||||
../test_libs/pyspec
|
|
@ -25,7 +25,6 @@
|
|||
- [`Fork`](#fork)
|
||||
- [`Crosslink`](#crosslink)
|
||||
- [`Eth1Data`](#eth1data)
|
||||
- [`Eth1DataVote`](#eth1datavote)
|
||||
- [`AttestationData`](#attestationdata)
|
||||
- [`AttestationDataAndCustodyBit`](#attestationdataandcustodybit)
|
||||
- [`IndexedAttestation`](#indexedattestation)
|
||||
|
@ -116,7 +115,6 @@
|
|||
- [Helper functions](#helper-functions-1)
|
||||
- [Justification](#justification)
|
||||
- [Crosslinks](#crosslinks)
|
||||
- [Eth1 data](#eth1-data)
|
||||
- [Rewards and penalties](#rewards-and-penalties)
|
||||
- [Justification and finalization](#justification-and-finalization)
|
||||
- [Crosslinks](#crosslinks-1)
|
||||
|
@ -229,7 +227,7 @@ These configurations are updated for releases, but may be out of sync during `de
|
|||
| `SLOTS_PER_EPOCH` | `2**6` (= 64) | slots | 6.4 minutes |
|
||||
| `MIN_SEED_LOOKAHEAD` | `2**0` (= 1) | epochs | 6.4 minutes |
|
||||
| `ACTIVATION_EXIT_DELAY` | `2**2` (= 4) | epochs | 25.6 minutes |
|
||||
| `EPOCHS_PER_ETH1_VOTING_PERIOD` | `2**4` (= 16) | epochs | ~1.7 hours |
|
||||
| `SLOTS_PER_ETH1_VOTING_PERIOD` | `2**10` (= 1,024) | slots | ~1.7 hours |
|
||||
| `SLOTS_PER_HISTORICAL_ROOT` | `2**13` (= 8,192) | slots | ~13 hours |
|
||||
| `MIN_VALIDATOR_WITHDRAWABILITY_DELAY` | `2**8` (= 256) | epochs | ~27 hours |
|
||||
| `PERSISTENT_COMMITTEE_PERIOD` | `2**11` (= 2,048) | epochs | 9 days |
|
||||
|
@ -325,17 +323,6 @@ The types are defined topologically to aid in facilitating an executable version
|
|||
}
|
||||
```
|
||||
|
||||
#### `Eth1DataVote`
|
||||
|
||||
```python
|
||||
{
|
||||
# Data being voted for
|
||||
'eth1_data': Eth1Data,
|
||||
# Vote count
|
||||
'vote_count': 'uint64',
|
||||
}
|
||||
```
|
||||
|
||||
#### `AttestationData`
|
||||
|
||||
```python
|
||||
|
@ -615,7 +602,7 @@ The types are defined topologically to aid in facilitating an executable version
|
|||
|
||||
# Ethereum 1.0 chain data
|
||||
'latest_eth1_data': Eth1Data,
|
||||
'eth1_data_votes': [Eth1DataVote],
|
||||
'eth1_data_votes': [Eth1Data],
|
||||
'deposit_index': 'uint64',
|
||||
}
|
||||
```
|
||||
|
@ -984,25 +971,17 @@ def generate_seed(state: BeaconState,
|
|||
### `get_beacon_proposer_index`
|
||||
|
||||
```python
|
||||
def get_beacon_proposer_index(state: BeaconState,
|
||||
slot: Slot) -> ValidatorIndex:
|
||||
def get_beacon_proposer_index(state: BeaconState) -> ValidatorIndex:
|
||||
"""
|
||||
Return the beacon proposer index for the ``slot``.
|
||||
Due to proposer selection being based upon the validator balances during
|
||||
the epoch in question, this can only be run for the current epoch.
|
||||
Return the beacon proposer index at ``state.slot``.
|
||||
"""
|
||||
current_epoch = get_current_epoch(state)
|
||||
assert slot_to_epoch(slot) == current_epoch
|
||||
|
||||
first_committee, _ = get_crosslink_committees_at_slot(state, slot)[0]
|
||||
first_committee, _ = get_crosslink_committees_at_slot(state, state.slot)[0]
|
||||
i = 0
|
||||
while True:
|
||||
rand_byte = hash(
|
||||
generate_seed(state, current_epoch) +
|
||||
int_to_bytes8(i // 32)
|
||||
)[i % 32]
|
||||
candidate = first_committee[(current_epoch + i) % len(first_committee)]
|
||||
if get_effective_balance(state, candidate) * 256 > MAX_EFFECTIVE_BALANCE * rand_byte:
|
||||
random_byte = hash(generate_seed(state, current_epoch) + int_to_bytes8(i // 32))[i % 32]
|
||||
if get_effective_balance(state, candidate) * 256 > MAX_EFFECTIVE_BALANCE * random_byte:
|
||||
return candidate
|
||||
i += 1
|
||||
```
|
||||
|
@ -1051,16 +1030,8 @@ def get_attestation_participants(state: BeaconState,
|
|||
Return the sorted participant indices corresponding to ``attestation_data`` and ``bitfield``.
|
||||
"""
|
||||
crosslink_committee = get_crosslink_committee_for_attestation(state, attestation_data)
|
||||
|
||||
assert verify_bitfield(bitfield, len(crosslink_committee))
|
||||
|
||||
# Find the participating attesters in the committee
|
||||
participants = []
|
||||
for i, validator_index in enumerate(crosslink_committee):
|
||||
aggregation_bit = get_bitfield_bit(bitfield, i)
|
||||
if aggregation_bit == 0b1:
|
||||
participants.append(validator_index)
|
||||
return sorted(participants)
|
||||
return sorted([index for i, index in enumerate(crosslink_committee) if get_bitfield_bit(bitfield, i) == 0b1])
|
||||
```
|
||||
|
||||
### `int_to_bytes1`, `int_to_bytes2`, ...
|
||||
|
@ -1344,7 +1315,7 @@ def slash_validator(state: BeaconState, slashed_index: ValidatorIndex, whistlebl
|
|||
slashed_balance = get_effective_balance(state, slashed_index)
|
||||
state.latest_slashed_balances[get_current_epoch(state) % LATEST_SLASHED_EXIT_LENGTH] += slashed_balance
|
||||
|
||||
proposer_index = get_beacon_proposer_index(state, state.slot)
|
||||
proposer_index = get_beacon_proposer_index(state)
|
||||
if whistleblower_index is None:
|
||||
whistleblower_index = proposer_index
|
||||
whistleblowing_reward = slashed_balance // WHISTLEBLOWING_REWARD_QUOTIENT
|
||||
|
@ -1494,9 +1465,9 @@ def get_genesis_beacon_state(genesis_validator_deposits: List[Deposit],
|
|||
process_deposit(state, deposit)
|
||||
|
||||
# Process genesis activations
|
||||
for validator_index in range(len(state.validator_registry)):
|
||||
if get_effective_balance(state, validator_index) >= MAX_EFFECTIVE_BALANCE:
|
||||
activate_validator(state, validator_index, is_genesis=True)
|
||||
for index in range(len(state.validator_registry)):
|
||||
if get_effective_balance(state, index) >= MAX_EFFECTIVE_BALANCE:
|
||||
activate_validator(state, index, is_genesis=True)
|
||||
|
||||
genesis_active_index_root = hash_tree_root(get_active_validator_indices(state, GENESIS_EPOCH))
|
||||
for index in range(LATEST_ACTIVE_INDEX_ROOTS_LENGTH):
|
||||
|
@ -1547,8 +1518,8 @@ def get_ancestor(store: Store, block: BeaconBlock, slot: Slot) -> BeaconBlock:
|
|||
return get_ancestor(store, store.get_parent(block), slot)
|
||||
```
|
||||
|
||||
* Let `get_latest_attestation(store: Store, validator_index: ValidatorIndex) -> Attestation` be the attestation with the highest slot number in `store` from the validator with the given `validator_index`. If several such attestations exist, use the one the [validator](#dfn-validator) `v` observed first.
|
||||
* Let `get_latest_attestation_target(store: Store, validator_index: ValidatorIndex) -> BeaconBlock` be the target block in the attestation `get_latest_attestation(store, validator_index)`.
|
||||
* Let `get_latest_attestation(store: Store, index: ValidatorIndex) -> Attestation` be the attestation with the highest slot number in `store` from the validator with the given `index`. If several such attestations exist, use the one the [validator](#dfn-validator) `v` observed first.
|
||||
* Let `get_latest_attestation_target(store: Store, index: ValidatorIndex) -> BeaconBlock` be the target block in the attestation `get_latest_attestation(store, index)`.
|
||||
* Let `get_children(store: Store, block: BeaconBlock) -> List[BeaconBlock]` returns the child blocks of the given `block`.
|
||||
* Let `justified_head_state` be the resulting `BeaconState` object from processing the chain up to the `justified_head`.
|
||||
* The `head` is `lmd_ghost(store, justified_head_state, justified_head)` where the function `lmd_ghost` is defined below. Note that the implementation below is suboptimal; there are implementations that compute the head in time logarithmic in slot count.
|
||||
|
@ -1560,10 +1531,7 @@ def lmd_ghost(store: Store, start_state: BeaconState, start_block: BeaconBlock)
|
|||
"""
|
||||
validators = start_state.validator_registry
|
||||
active_validator_indices = get_active_validator_indices(validators, slot_to_epoch(start_state.slot))
|
||||
attestation_targets = [
|
||||
(validator_index, get_latest_attestation_target(store, validator_index))
|
||||
for validator_index in active_validator_indices
|
||||
]
|
||||
attestation_targets = [(i, get_latest_attestation_target(store, i)) for i 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
|
||||
|
@ -1628,7 +1596,7 @@ The steps below happen when `state.slot > GENESIS_SLOT and (state.slot + 1) % SL
|
|||
|
||||
#### Helper functions
|
||||
|
||||
We define some helper functions utilized when processing an epoch transition:
|
||||
We define epoch transition helper functions:
|
||||
|
||||
```python
|
||||
def get_current_total_balance(state: BeaconState) -> Gwei:
|
||||
|
@ -1702,71 +1670,54 @@ def get_winning_root_and_participants(state: BeaconState, shard: Shard) -> Tuple
|
|||
```
|
||||
|
||||
```python
|
||||
def earliest_attestation(state: BeaconState, validator_index: ValidatorIndex) -> PendingAttestation:
|
||||
def get_earliest_attestation(state: BeaconState, attestations: List[PendingAttestation], index: ValidatorIndex) -> PendingAttestation:
|
||||
return min([
|
||||
a for a in state.previous_epoch_attestations if
|
||||
validator_index in get_attestation_participants(state, a.data, a.aggregation_bitfield)
|
||||
a for a in attestations if index in get_attestation_participants(state, a.data, a.aggregation_bitfield)
|
||||
], key=lambda a: a.inclusion_slot)
|
||||
```
|
||||
|
||||
```python
|
||||
def inclusion_slot(state: BeaconState, validator_index: ValidatorIndex) -> Slot:
|
||||
return earliest_attestation(state, validator_index).inclusion_slot
|
||||
```
|
||||
|
||||
```python
|
||||
def inclusion_distance(state: BeaconState, validator_index: ValidatorIndex) -> int:
|
||||
attestation = earliest_attestation(state, validator_index)
|
||||
return attestation.inclusion_slot - attestation.data.slot
|
||||
```
|
||||
|
||||
#### Justification
|
||||
|
||||
Run the following function:
|
||||
|
||||
```python
|
||||
def update_justification_and_finalization(state: BeaconState) -> None:
|
||||
new_justified_epoch = state.current_justified_epoch
|
||||
new_finalized_epoch = state.finalized_epoch
|
||||
antepenultimate_justified_epoch = state.previous_justified_epoch
|
||||
|
||||
# Rotate the justification bitfield up one epoch to make room for the current epoch (and limit to 64 bits)
|
||||
# Process justifications
|
||||
state.previous_justified_epoch = state.current_justified_epoch
|
||||
state.previous_justified_root = state.current_justified_root
|
||||
state.justification_bitfield = (state.justification_bitfield << 1) % 2**64
|
||||
# If the previous epoch gets justified, fill the second last bit
|
||||
previous_boundary_attesting_balance = get_attesting_balance(state, get_previous_epoch_boundary_attestations(state))
|
||||
if previous_boundary_attesting_balance * 3 >= get_previous_total_balance(state) * 2:
|
||||
new_justified_epoch = get_current_epoch(state) - 1
|
||||
state.justification_bitfield |= 2
|
||||
# If the current epoch gets justified, fill the last bit
|
||||
state.current_justified_epoch = get_previous_epoch(state)
|
||||
state.current_justified_root = get_block_root(state, get_epoch_start_slot(state.current_justified_epoch))
|
||||
state.justification_bitfield |= (1 << 1)
|
||||
current_boundary_attesting_balance = get_attesting_balance(state, get_current_epoch_boundary_attestations(state))
|
||||
if current_boundary_attesting_balance * 3 >= get_current_total_balance(state) * 2:
|
||||
new_justified_epoch = get_current_epoch(state)
|
||||
state.justification_bitfield |= 1
|
||||
state.current_justified_epoch = get_current_epoch(state)
|
||||
state.current_justified_root = get_block_root(state, get_epoch_start_slot(state.current_justified_epoch))
|
||||
state.justification_bitfield |= (1 << 0)
|
||||
|
||||
# Process finalizations
|
||||
bitfield = state.justification_bitfield
|
||||
current_epoch = get_current_epoch(state)
|
||||
# The 2nd/3rd/4th most recent epochs are all justified, the 2nd using the 4th as source
|
||||
if (bitfield >> 1) % 8 == 0b111 and state.previous_justified_epoch == current_epoch - 3:
|
||||
new_finalized_epoch = state.previous_justified_epoch
|
||||
# The 2nd/3rd most recent epochs are both justified, the 2nd using the 3rd as source
|
||||
if (bitfield >> 1) % 4 == 0b11 and state.previous_justified_epoch == current_epoch - 2:
|
||||
new_finalized_epoch = state.previous_justified_epoch
|
||||
# The 1st/2nd/3rd most recent epochs are all justified, the 1st using the 3rd as source
|
||||
if (bitfield >> 0) % 8 == 0b111 and state.current_justified_epoch == current_epoch - 2:
|
||||
new_finalized_epoch = state.current_justified_epoch
|
||||
# The 1st/2nd most recent epochs are both justified, the 1st using the 2nd as source
|
||||
if (bitfield >> 0) % 4 == 0b11 and state.current_justified_epoch == current_epoch - 1:
|
||||
new_finalized_epoch = state.current_justified_epoch
|
||||
|
||||
# Update state jusification/finality fields
|
||||
state.previous_justified_epoch = state.current_justified_epoch
|
||||
state.previous_justified_root = state.current_justified_root
|
||||
if new_justified_epoch != state.current_justified_epoch:
|
||||
state.current_justified_epoch = new_justified_epoch
|
||||
state.current_justified_root = get_block_root(state, get_epoch_start_slot(new_justified_epoch))
|
||||
if new_finalized_epoch != state.finalized_epoch:
|
||||
state.finalized_epoch = new_finalized_epoch
|
||||
state.finalized_root = get_block_root(state, get_epoch_start_slot(new_finalized_epoch))
|
||||
# The 2nd/3rd/4th most recent epochs are justified, the 2nd using the 4th as source
|
||||
if (bitfield >> 1) % 8 == 0b111 and antepenultimate_justified_epoch == current_epoch - 3:
|
||||
state.finalized_epoch = antepenultimate_justified_epoch
|
||||
state.finalized_root = get_block_root(state, get_epoch_start_slot(state.finalized_epoch))
|
||||
# The 2nd/3rd most recent epochs are justified, the 2nd using the 3rd as source
|
||||
if (bitfield >> 1) % 4 == 0b11 and antepenultimate_justified_epoch == current_epoch - 2:
|
||||
state.finalized_epoch = antepenultimate_justified_epoch
|
||||
state.finalized_root = get_block_root(state, get_epoch_start_slot(state.finalized_epoch))
|
||||
# The 1st/2nd/3rd most recent epochs are justified, the 1st using the 3rd as source
|
||||
if (bitfield >> 0) % 8 == 0b111 and state.previous_justified_root == current_epoch - 2:
|
||||
state.finalized_epoch = state.previous_justified_root
|
||||
state.finalized_root = get_block_root(state, get_epoch_start_slot(state.finalized_epoch))
|
||||
# The 1st/2nd most recent epochs are justified, the 1st using the 2nd as source
|
||||
if (bitfield >> 0) % 4 == 0b11 and state.previous_justified_root == current_epoch - 1:
|
||||
state.finalized_epoch = state.previous_justified_root
|
||||
state.finalized_root = get_block_root(state, get_epoch_start_slot(state.finalized_epoch))
|
||||
```
|
||||
|
||||
#### Crosslinks
|
||||
|
@ -1790,34 +1741,24 @@ def process_crosslinks(state: BeaconState) -> None:
|
|||
)
|
||||
```
|
||||
|
||||
#### Eth1 data
|
||||
|
||||
Run the following function:
|
||||
|
||||
```python
|
||||
def maybe_reset_eth1_period(state: BeaconState) -> None:
|
||||
if (get_current_epoch(state) + 1) % EPOCHS_PER_ETH1_VOTING_PERIOD == 0:
|
||||
for eth1_data_vote in state.eth1_data_votes:
|
||||
# If a majority of all votes were for a particular eth1_data value,
|
||||
# then set that as the new canonical value
|
||||
if eth1_data_vote.vote_count * 2 > EPOCHS_PER_ETH1_VOTING_PERIOD * SLOTS_PER_EPOCH:
|
||||
state.latest_eth1_data = eth1_data_vote.eth1_data
|
||||
state.eth1_data_votes = []
|
||||
```
|
||||
|
||||
#### Rewards and penalties
|
||||
|
||||
First, we define some additional helpers:
|
||||
|
||||
```python
|
||||
def get_base_reward(state: BeaconState, index: ValidatorIndex) -> Gwei:
|
||||
if get_previous_total_balance(state) == 0:
|
||||
def get_base_reward_from_total_balance(state: BeaconState, total_balance: Gwei, index: ValidatorIndex) -> Gwei:
|
||||
if total_balance == 0:
|
||||
return 0
|
||||
|
||||
adjusted_quotient = integer_squareroot(get_previous_total_balance(state)) // BASE_REWARD_QUOTIENT
|
||||
adjusted_quotient = integer_squareroot(total_balance) // BASE_REWARD_QUOTIENT
|
||||
return get_effective_balance(state, index) // adjusted_quotient // 5
|
||||
```
|
||||
|
||||
```python
|
||||
def get_base_reward(state: BeaconState, index: ValidatorIndex) -> Gwei:
|
||||
return get_base_reward_from_total_balance(state, get_previous_total_balance(state), index)
|
||||
```
|
||||
|
||||
```python
|
||||
def get_inactivity_penalty(state: BeaconState, index: ValidatorIndex, epochs_since_finality: int) -> Gwei:
|
||||
if epochs_since_finality <= 4:
|
||||
|
@ -1858,10 +1799,9 @@ def get_justification_and_finalization_deltas(state: BeaconState) -> Tuple[List[
|
|||
if index in get_unslashed_attesting_indices(state, state.previous_epoch_attestations):
|
||||
rewards[index] += base_reward * total_attesting_balance // total_balance
|
||||
# Inclusion speed bonus
|
||||
rewards[index] += (
|
||||
base_reward * MIN_ATTESTATION_INCLUSION_DELAY //
|
||||
inclusion_distance(state, index)
|
||||
)
|
||||
earliest_attestation = get_earliest_attestation(state, state.previous_epoch_attestations, index)
|
||||
inclusion_delay = earliest_attestation.inclusion_slot - earliest_attestation.data.slot
|
||||
rewards[index] += base_reward * MIN_ATTESTATION_INCLUSION_DELAY // inclusion_delay
|
||||
else:
|
||||
penalties[index] += base_reward
|
||||
# Expected FFG target
|
||||
|
@ -1874,10 +1814,6 @@ def get_justification_and_finalization_deltas(state: BeaconState) -> Tuple[List[
|
|||
rewards[index] += base_reward * matching_head_balance // total_balance
|
||||
else:
|
||||
penalties[index] += base_reward
|
||||
# Proposer bonus
|
||||
if index in get_unslashed_attesting_indices(state, state.previous_epoch_attestations):
|
||||
proposer_index = get_beacon_proposer_index(state, inclusion_slot(state, index))
|
||||
rewards[proposer_index] += base_reward // PROPOSER_REWARD_QUOTIENT
|
||||
# Take away max rewards if we're not finalizing
|
||||
if epochs_since_finality > 4:
|
||||
penalties[index] += base_reward * 4
|
||||
|
@ -1914,14 +1850,8 @@ def apply_rewards(state: BeaconState) -> None:
|
|||
rewards1, penalties1 = get_justification_and_finalization_deltas(state)
|
||||
rewards2, penalties2 = get_crosslink_deltas(state)
|
||||
for i in range(len(state.validator_registry)):
|
||||
set_balance(
|
||||
state,
|
||||
i,
|
||||
max(
|
||||
0,
|
||||
get_balance(state, i) + rewards1[i] + rewards2[i] - penalties1[i] - penalties2[i],
|
||||
),
|
||||
)
|
||||
increase_balance(state, i, rewards1[i] + rewards2[i])
|
||||
decrease_balance(state, i, penalties1[i] + penalties2[i])
|
||||
```
|
||||
|
||||
#### Balance-driven status transitions
|
||||
|
@ -2000,6 +1930,9 @@ Run the following function:
|
|||
def finish_epoch_update(state: BeaconState) -> None:
|
||||
current_epoch = get_current_epoch(state)
|
||||
next_epoch = current_epoch + 1
|
||||
# Reset eth1 data votes
|
||||
if state.slot % SLOTS_PER_ETH1_VOTING_PERIOD == 0:
|
||||
state.eth1_data_votes = []
|
||||
# Set active index root
|
||||
index_root_position = (next_epoch + ACTIVATION_EXIT_DELAY) % LATEST_ACTIVE_INDEX_ROOTS_LENGTH
|
||||
state.latest_active_index_roots[index_root_position] = hash_tree_root(
|
||||
|
@ -2047,7 +1980,7 @@ def process_block_header(state: BeaconState, block: BeaconBlock) -> None:
|
|||
# Save current block as the new latest block
|
||||
state.latest_block_header = get_temporary_block_header(block)
|
||||
# Verify proposer is not slashed
|
||||
proposer = state.validator_registry[get_beacon_proposer_index(state, state.slot)]
|
||||
proposer = state.validator_registry[get_beacon_proposer_index(state)]
|
||||
assert not proposer.slashed
|
||||
# Verify proposer signature
|
||||
assert bls_verify(
|
||||
|
@ -2062,7 +1995,7 @@ def process_block_header(state: BeaconState, block: BeaconBlock) -> None:
|
|||
|
||||
```python
|
||||
def process_randao(state: BeaconState, block: BeaconBlock) -> None:
|
||||
proposer = state.validator_registry[get_beacon_proposer_index(state, state.slot)]
|
||||
proposer = state.validator_registry[get_beacon_proposer_index(state)]
|
||||
# Verify that the provided randao value is valid
|
||||
assert bls_verify(
|
||||
pubkey=proposer.pubkey,
|
||||
|
@ -2081,13 +2014,9 @@ def process_randao(state: BeaconState, block: BeaconBlock) -> None:
|
|||
|
||||
```python
|
||||
def process_eth1_data(state: BeaconState, block: BeaconBlock) -> None:
|
||||
for eth1_data_vote in state.eth1_data_votes:
|
||||
# If someone else has already voted for the same hash, add to its counter
|
||||
if eth1_data_vote.eth1_data == block.body.eth1_data:
|
||||
eth1_data_vote.vote_count += 1
|
||||
return
|
||||
# If we're seeing this hash for the first time, make a new counter
|
||||
state.eth1_data_votes.append(Eth1DataVote(eth1_data=block.body.eth1_data, vote_count=1))
|
||||
state.eth1_data_votes.append(block.body.eth1_data)
|
||||
if state.eth1_data_votes.count(block.body.eth1_data) * 2 > SLOTS_PER_ETH1_VOTING_PERIOD:
|
||||
state.latest_eth1_data = block.body.eth1_data
|
||||
```
|
||||
|
||||
#### Operations
|
||||
|
@ -2210,6 +2139,18 @@ def process_attestation(state: BeaconState, attestation: Attestation) -> None:
|
|||
state.previous_epoch_attestations.append(pending_attestation)
|
||||
```
|
||||
|
||||
Run `process_proposer_attestation_rewards(state)`.
|
||||
|
||||
```python
|
||||
def process_proposer_attestation_rewards(state: BeaconState) -> None:
|
||||
proposer_index = get_beacon_proposer_index(state)
|
||||
for pending_attestations in (state.previous_epoch_attestations, state.current_epoch_attestations):
|
||||
for index in get_unslashed_attesting_indices(state, pending_attestations):
|
||||
if get_earliest_attestation(state, pending_attestations, index).inclusion_slot == state.slot:
|
||||
base_reward = get_base_reward_from_total_balance(state, get_current_total_balance(state), index)
|
||||
increase_balance(state, proposer_index, base_reward // PROPOSER_REWARD_QUOTIENT)
|
||||
```
|
||||
|
||||
##### Deposits
|
||||
|
||||
Verify that `len(block.body.deposits) == min(MAX_DEPOSITS, latest_eth1_data.deposit_count - state.deposit_index)`.
|
||||
|
@ -2356,7 +2297,7 @@ def process_transfer(state: BeaconState, transfer: Transfer) -> None:
|
|||
# Process the transfer
|
||||
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)
|
||||
increase_balance(state, get_beacon_proposer_index(state), transfer.fee)
|
||||
# Verify balances are not dust
|
||||
assert not (0 < get_balance(state, transfer.sender) < MIN_DEPOSIT_AMOUNT)
|
||||
assert not (0 < get_balance(state, transfer.recipient) < MIN_DEPOSIT_AMOUNT)
|
||||
|
|
|
@ -283,7 +283,7 @@ def process_custody_reveal(state: BeaconState,
|
|||
assert is_active_validator(revealer, get_current_epoch(state)) or revealer.exit_epoch > get_current_epoch(state)
|
||||
revealer.custody_reveal_index += 1
|
||||
revealer.max_reveal_lateness = max(revealer.max_reveal_lateness, current_custody_period - reveal.period)
|
||||
proposer_index = get_beacon_proposer_index(state, state.slot)
|
||||
proposer_index = get_beacon_proposer_index(state)
|
||||
increase_balance(state, proposer_index, base_reward(state, index) // MINOR_REWARD_QUOTIENT)
|
||||
|
||||
# Case 2: masked punitive early reveal
|
||||
|
@ -323,7 +323,7 @@ def process_chunk_challenge(state: BeaconState,
|
|||
# Add new chunk challenge record
|
||||
state.custody_chunk_challenge_records.append(CustodyChunkChallengeRecord(
|
||||
challenge_index=state.custody_challenge_index,
|
||||
challenger_index=get_beacon_proposer_index(state, state.slot),
|
||||
challenger_index=get_beacon_proposer_index(state),
|
||||
responder_index=challenge.responder_index
|
||||
deadline=get_current_epoch(state) + CUSTODY_RESPONSE_DEADLINE,
|
||||
crosslink_data_root=challenge.attestation.data.crosslink_data_root,
|
||||
|
@ -436,7 +436,7 @@ def process_chunk_challenge_response(state: BeaconState,
|
|||
# Clear the challenge
|
||||
state.custody_chunk_challenge_records.remove(challenge)
|
||||
# Reward the proposer
|
||||
proposer_index = get_beacon_proposer_index(state, state.slot)
|
||||
proposer_index = get_beacon_proposer_index(state)
|
||||
increase_balance(state, proposer_index, base_reward(state, index) // MINOR_REWARD_QUOTIENT)
|
||||
```
|
||||
|
||||
|
|
|
@ -406,4 +406,4 @@ def is_valid_beacon_attestation(shard: Shard,
|
|||
|
||||
## Shard fork choice rule
|
||||
|
||||
The fork choice rule for any shard is LMD GHOST using the shard attestations of the persistent committee and the beacon chain attestations of the crosslink committee currently assigned to that shard, but instead of being rooted in the genesis it is rooted in the block referenced in the most recent accepted crosslink (i.e. `state.crosslinks[shard].shard_block_root`). Only blocks whose `beacon_chain_root` is the block in the main beacon chain at the specified `slot` should be considered. (If the beacon chain skips a slot, then the block at that slot is considered to be the block in the beacon chain at the highest slot lower than a slot.)
|
||||
The fork choice rule for any shard is LMD GHOST using the shard attestations of the persistent committee and the beacon chain attestations of the crosslink committee currently assigned to that shard, but instead of being rooted in the genesis it is rooted in the block referenced in the most recent accepted crosslink (i.e. `state.crosslinks[shard].shard_block_root`). Only blocks whose `beacon_chain_root` is the block in the main beacon chain at the specified `slot` should be considered. (If the beacon chain skips a slot, then the block at that slot is considered to be the block in the beacon chain at the highest slot lower than that slot.)
|
||||
|
|
|
@ -369,24 +369,23 @@ def get_committee_assignment(
|
|||
return assignment
|
||||
```
|
||||
|
||||
A validator can use the following function to see if they are supposed to propose during their assigned committee slot. This function can only be run during the epoch of the slot in question and can not reliably be used to predict an epoch in advance.
|
||||
A validator can use the following function to see if they are supposed to propose during their assigned committee slot. This function can only be run during the slot in question and can not reliably be used to predict in advance.
|
||||
|
||||
```python
|
||||
def is_proposer_at_slot(state: BeaconState,
|
||||
slot: Slot,
|
||||
validator_index: ValidatorIndex) -> bool:
|
||||
current_epoch = get_current_epoch(state)
|
||||
assert slot_to_epoch(slot) == current_epoch
|
||||
assert state.slot == slot
|
||||
|
||||
return get_beacon_proposer_index(state, slot) == validator_index
|
||||
return get_beacon_proposer_index(state) == validator_index
|
||||
```
|
||||
|
||||
_Note_: If a validator is assigned to the 0th slot of an epoch, the validator must run an empty slot transition from the previous epoch into the 0th slot of the epoch to be able to check if they are a proposer at that slot.
|
||||
_Note_: To see if a validator is assigned to proposer during the slot, the validator must run an empty slot transition from the previous state to the current slot.
|
||||
|
||||
|
||||
### Lookahead
|
||||
|
||||
The beacon chain shufflings are designed to provide a minimum of 1 epoch lookahead on the validator's upcoming committee assignments for attesting dictated by the shuffling and slot. Note that this lookahead does not apply to proposing which must checked during the epoch in question.
|
||||
The beacon chain shufflings are designed to provide a minimum of 1 epoch lookahead on the validator's upcoming committee assignments for attesting dictated by the shuffling and slot. Note that this lookahead does not apply to proposing which must checked during the slot in question.
|
||||
|
||||
`get_committee_assignment` should be called at the start of each epoch to get the assignment for the next epoch (`current_epoch + 1`). A validator should plan for future assignments which involves noting at which future slot one will have to attest and also which shard one should begin syncing (in phase 1+).
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ With this executable spec,
|
|||
test-generators can easily create test-vectors for client implementations,
|
||||
and the spec itself can be verified to be consistent and coherent, through sanity tests implemented with pytest.
|
||||
|
||||
|
||||
## Building
|
||||
|
||||
All the dynamic parts of the spec can be build at once with `make pyspec`.
|
||||
|
@ -15,12 +16,42 @@ Alternatively, you can build a sub-set of the pyspec: `make phase0`.
|
|||
|
||||
Or, to build a single file, specify the path, e.g. `make test_libs/pyspec/eth2spec/phase0/spec.py`
|
||||
|
||||
|
||||
## Py-tests
|
||||
|
||||
These tests are not intended for client-consumption.
|
||||
These tests are sanity tests, to verify if the spec itself is consistent.
|
||||
|
||||
### How to run tests
|
||||
|
||||
#### Automated
|
||||
|
||||
Run `make test` from the root of the spec repository.
|
||||
|
||||
#### Manual
|
||||
|
||||
From within the `pyspec` folder:
|
||||
|
||||
Install dependencies:
|
||||
```bash
|
||||
python3 -m venv venv
|
||||
. venv/bin/activate
|
||||
pip3 install -r requirements.txt
|
||||
```
|
||||
Note: make sure to run `make pyspec` from the root of the specs repository,
|
||||
to build the parts of the pyspec module derived from the markdown specs.
|
||||
|
||||
Run the tests:
|
||||
```
|
||||
pytest -m minimal_config .
|
||||
```
|
||||
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributions are welcome, but consider implementing your idea as part of the spec itself first.
|
||||
The pyspec is not a replacement.
|
||||
If you see opportunity to include any of the `pyspec/eth2spec/utils/` code in the spec,
|
||||
please submit an issue or PR.
|
||||
|
||||
|
||||
## License
|
||||
|
||||
|
|
|
@ -10,7 +10,8 @@ from typing import (
|
|||
from .spec import (
|
||||
BeaconState,
|
||||
BeaconBlock,
|
||||
Slot
|
||||
Slot,
|
||||
process_proposer_attestation_rewards,
|
||||
)
|
||||
|
||||
|
||||
|
@ -51,6 +52,7 @@ def process_operations(state: BeaconState, block: BeaconBlock) -> None:
|
|||
spec.MAX_ATTESTATIONS,
|
||||
spec.process_attestation,
|
||||
)
|
||||
process_proposer_attestation_rewards(state)
|
||||
|
||||
assert len(block.body.deposits) == expected_deposit_count(state)
|
||||
process_operation_type(
|
||||
|
@ -91,7 +93,6 @@ def process_block(state: BeaconState,
|
|||
def process_epoch_transition(state: BeaconState) -> None:
|
||||
spec.update_justification_and_finalization(state)
|
||||
spec.process_crosslinks(state)
|
||||
spec.maybe_reset_eth1_period(state)
|
||||
spec.apply_rewards(state)
|
||||
spec.process_balance_driven_status_transitions(state)
|
||||
spec.update_registry(state)
|
||||
|
@ -112,4 +113,3 @@ def state_transition(state: BeaconState,
|
|||
verify_state_root: bool=False) -> BeaconState:
|
||||
state_transition_to(state, block.slot)
|
||||
process_block(state, block, verify_state_root)
|
||||
|
||||
|
|
|
@ -2,3 +2,4 @@ eth-utils>=1.3.0,<2
|
|||
eth-typing>=2.1.0,<3.0.0
|
||||
pycryptodome==3.7.3
|
||||
py_ecc>=1.6.0
|
||||
pytest>=3.6,<3.7
|
||||
|
|
|
@ -3,6 +3,7 @@ from setuptools import setup, find_packages
|
|||
setup(
|
||||
name='pyspec',
|
||||
packages=find_packages(),
|
||||
tests_require=["pytest"],
|
||||
install_requires=[
|
||||
"eth-utils>=1.3.0,<2",
|
||||
"eth-typing>=2.1.0,<3.0.0",
|
||||
|
|
|
@ -11,7 +11,7 @@ from eth2spec.phase0.spec import (
|
|||
process_attestation,
|
||||
slot_to_epoch,
|
||||
)
|
||||
from phase0.helpers import (
|
||||
from tests.helpers import (
|
||||
build_empty_block_for_next_slot,
|
||||
get_valid_attestation,
|
||||
)
|
|
@ -7,7 +7,7 @@ from eth2spec.phase0.spec import (
|
|||
get_beacon_proposer_index,
|
||||
process_attester_slashing,
|
||||
)
|
||||
from phase0.helpers import (
|
||||
from tests.helpers import (
|
||||
get_valid_attester_slashing,
|
||||
)
|
||||
|
||||
|
@ -39,7 +39,7 @@ def run_attester_slashing_processing(state, attester_slashing, valid=True):
|
|||
get_balance(post_state, slashed_index) <
|
||||
get_balance(state, slashed_index)
|
||||
)
|
||||
proposer_index = get_beacon_proposer_index(state, state.slot)
|
||||
proposer_index = get_beacon_proposer_index(state)
|
||||
# gained whistleblower reward
|
||||
assert (
|
||||
get_balance(post_state, proposer_index) >
|
|
@ -8,8 +8,9 @@ from eth2spec.phase0.spec import (
|
|||
advance_slot,
|
||||
process_block_header,
|
||||
)
|
||||
from phase0.helpers import (
|
||||
from tests.helpers import (
|
||||
build_empty_block_for_next_slot,
|
||||
next_slot,
|
||||
)
|
||||
|
||||
# mark entire file as 'header'
|
||||
|
@ -61,8 +62,12 @@ def test_invalid_previous_block_root(state):
|
|||
|
||||
|
||||
def test_proposer_slashed(state):
|
||||
# use stub state to get proposer index of next slot
|
||||
stub_state = deepcopy(state)
|
||||
next_slot(stub_state)
|
||||
proposer_index = get_beacon_proposer_index(stub_state)
|
||||
|
||||
# set proposer to slashed
|
||||
proposer_index = get_beacon_proposer_index(state, state.slot + 1)
|
||||
state.validator_registry[proposer_index].slashed = True
|
||||
|
||||
block = build_empty_block_for_next_slot(state)
|
|
@ -8,7 +8,7 @@ from eth2spec.phase0.spec import (
|
|||
ZERO_HASH,
|
||||
process_deposit,
|
||||
)
|
||||
from phase0.helpers import (
|
||||
from tests.helpers import (
|
||||
build_deposit,
|
||||
privkeys,
|
||||
pubkeys,
|
|
@ -7,7 +7,7 @@ from eth2spec.phase0.spec import (
|
|||
get_current_epoch,
|
||||
process_proposer_slashing,
|
||||
)
|
||||
from phase0.helpers import (
|
||||
from tests.helpers import (
|
||||
get_valid_proposer_slashing,
|
||||
)
|
||||
|
|
@ -9,7 +9,7 @@ from eth2spec.phase0.spec import (
|
|||
get_current_epoch,
|
||||
process_voluntary_exit,
|
||||
)
|
||||
from phase0.helpers import (
|
||||
from tests.helpers import (
|
||||
build_voluntary_exit,
|
||||
pubkey_to_privkey,
|
||||
)
|
|
@ -2,6 +2,9 @@ from copy import deepcopy
|
|||
|
||||
from py_ecc import bls
|
||||
|
||||
from eth2spec.phase0.state_transition import (
|
||||
state_transition,
|
||||
)
|
||||
import eth2spec.phase0.spec as spec
|
||||
from eth2spec.utils.minimal_ssz import signing_root
|
||||
from eth2spec.phase0.spec import (
|
||||
|
@ -303,3 +306,8 @@ def get_attestation_signature(state, attestation_data, privkey, custody_bit=0b0)
|
|||
domain_type=spec.DOMAIN_ATTESTATION,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def next_slot(state):
|
||||
block = build_empty_block_for_next_slot(state)
|
||||
state_transition(state, block)
|
|
@ -160,7 +160,7 @@ def test_attester_slashing(state):
|
|||
# lost whistleblower reward
|
||||
assert get_balance(test_state, validator_index) < get_balance(state, validator_index)
|
||||
|
||||
proposer_index = get_beacon_proposer_index(test_state, test_state.slot)
|
||||
proposer_index = get_beacon_proposer_index(test_state)
|
||||
# gained whistleblower reward
|
||||
assert (
|
||||
get_balance(test_state, proposer_index) >
|
||||
|
@ -260,6 +260,9 @@ def test_attestation(state):
|
|||
|
||||
assert len(test_state.current_epoch_attestations) == len(state.current_epoch_attestations) + 1
|
||||
|
||||
proposer_index = get_beacon_proposer_index(test_state)
|
||||
assert test_state.balances[proposer_index] > state.balances[proposer_index]
|
||||
|
||||
#
|
||||
# Epoch transition should move to previous_epoch_attestations
|
||||
#
|
Loading…
Reference in New Issue