Merge branch 'dev' into testgenphase1

This commit is contained in:
Hsiao-Wei Wang 2020-09-17 21:11:49 +08:00
commit 5374890da0
No known key found for this signature in database
GPG Key ID: 95B070122902DEA4
20 changed files with 169 additions and 113 deletions

View File

@ -1,6 +1,6 @@
# Ethereum 2.0 Specifications
[![Join the chat at https://discord.gg/qGpsxSA](https://img.shields.io/badge/chat-on%20discord-blue.svg)](https://discord.gg/hpFs23p) [![Join the chat at https://gitter.im/ethereum/sharding](https://badges.gitter.im/ethereum/sharding.svg)](https://gitter.im/ethereum/sharding?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![Join the chat at https://discord.gg/qGpsxSA](https://img.shields.io/badge/chat-on%20discord-blue.svg)](https://discord.gg/qGpsxSA) [![Join the chat at https://gitter.im/ethereum/sharding](https://badges.gitter.im/ethereum/sharding.svg)](https://gitter.im/ethereum/sharding?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
To learn more about sharding and Ethereum 2.0 (Serenity), see the [sharding FAQ](https://eth.wiki/sharding/Sharding-FAQs) and the [research compendium](https://notes.ethereum.org/s/H1PGqDhpm).

View File

@ -102,8 +102,6 @@ SLOTS_PER_HISTORICAL_ROOT: 8192
MIN_VALIDATOR_WITHDRAWABILITY_DELAY: 256
# 2**8 (= 256) epochs ~27 hours
SHARD_COMMITTEE_PERIOD: 256
# 2**6 (= 64) epochs ~7 hours
MAX_EPOCHS_PER_CROSSLINK: 64
# 2**2 (= 4) epochs 25.6 minutes
MIN_EPOCHS_TO_INACTIVITY_PENALTY: 4

View File

@ -101,8 +101,6 @@ SLOTS_PER_HISTORICAL_ROOT: 64
MIN_VALIDATOR_WITHDRAWABILITY_DELAY: 256
# [customized] higher frequency of committee turnover and faster time to acceptable voluntary exit
SHARD_COMMITTEE_PERIOD: 64
# [customized] fast catchup crosslinks
MAX_EPOCHS_PER_CROSSLINK: 4
# 2**2 (= 4) epochs
MIN_EPOCHS_TO_INACTIVITY_PENALTY: 4

View File

@ -127,6 +127,7 @@ from eth2spec.config.config_util import apply_constants_config
from typing import (
Any, Dict, Set, Sequence, NewType, Tuple, TypeVar, Callable, Optional
)
from typing import List as PyList
from dataclasses import (
dataclass,

View File

@ -11,6 +11,24 @@ See this [blog post](https://blog.ethereum.org/2020/06/23/eth2-quick-update-no-1
In August 2020, version `r2` was released with metadata modifications and relicensed to CC0-1.0. Afterward, this contract has been ported back to from [`axic/eth2-deposit-contract`](https://github.com/axic/eth2-deposit-contract) to this repository and replaced the Vyper deposit contract.
## Compiling solidity deposit contract
In the `eth2.0-specs` directory run:
```sh
make compile_deposit_contract
```
The following parameters were used to generate the bytecode for the `DepositContract` available in this repository:
* Contract Name: `DepositContract`
* Compiler Version: Solidity `v0.6.11+commit.5ef660b1`
* Optimization Enabled: `Yes` with `5000000` runs
* Metadata Options: `--metadata-literal` (to verify metadata hash)
```sh
solc --optimize --optimize-runs 5000000 --metadata-literal --bin deposit_contract.sol
```
## Running web3 tests
1. In the `eth2.0-specs` directory run `make install_deposit_contract_web3_tester` to install the tools needed (make sure to have Python 3.7 and pip installed).

View File

@ -603,7 +603,7 @@ def bytes_to_uint64(data: bytes) -> uint64:
#### BLS Signatures
Eth2 makes use of BLS signatures as specified in the [IETF draft BLS specification draft-irtf-cfrg-bls-signature-02](https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-02) but uses [Hashing to Elliptic Curves - draft-irtf-cfrg-hash-to-curve-07](https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-07) instead of draft-irtf-cfrg-hash-to-curve-06. Specifically, eth2 uses the `BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_` ciphersuite which implements the following interfaces:
Eth2 makes use of BLS signatures as specified in the [IETF draft BLS specification draft-irtf-cfrg-bls-signature-03](https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-03). Specifically, eth2 uses the `BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_` ciphersuite which implements the following interfaces:
- `def Sign(SK: int, message: Bytes) -> BLSSignature`
- `def Verify(PK: BLSPubkey, message: Bytes, signature: BLSSignature) -> bool`
@ -613,8 +613,6 @@ Eth2 makes use of BLS signatures as specified in the [IETF draft BLS specificati
Within these specifications, BLS signatures are treated as a module for notational clarity, thus to verify a signature `bls.Verify(...)` is used.
*Note*: The non-standard configuration of the BLS and hash to curve specs is temporary and will be resolved once IETF releases BLS spec draft 3.
### Predicates
#### `is_active_validator`
@ -774,7 +772,7 @@ def compute_committee(indices: Sequence[ValidatorIndex],
Return the committee corresponding to ``indices``, ``seed``, ``index``, and committee ``count``.
"""
start = (len(indices) * index) // count
end = (len(indices) * (index + 1)) // count
end = (len(indices) * uint64(index + 1)) // count
return [indices[compute_shuffled_index(uint64(i), uint64(len(indices)), seed)] for i in range(start, end)]
```
@ -1455,7 +1453,7 @@ def get_inclusion_delay_deltas(state: BeaconState) -> Tuple[Sequence[Gwei], Sequ
if index in get_attesting_indices(state, a.data, a.aggregation_bits)
], key=lambda a: a.inclusion_delay)
rewards[attestation.proposer_index] += get_proposer_reward(state, index)
max_attester_reward = get_base_reward(state, index) - get_proposer_reward(state, index)
max_attester_reward = Gwei(get_base_reward(state, index) - get_proposer_reward(state, index))
rewards[index] += Gwei(max_attester_reward // attestation.inclusion_delay)
# No penalties associated with inclusion delay
@ -1576,7 +1574,7 @@ def process_final_updates(state: BeaconState) -> None:
# Update effective balances with hysteresis
for index, validator in enumerate(state.validators):
balance = state.balances[index]
HYSTERESIS_INCREMENT = EFFECTIVE_BALANCE_INCREMENT // HYSTERESIS_QUOTIENT
HYSTERESIS_INCREMENT = uint64(EFFECTIVE_BALANCE_INCREMENT // HYSTERESIS_QUOTIENT)
DOWNWARD_THRESHOLD = HYSTERESIS_INCREMENT * HYSTERESIS_DOWNWARD_MULTIPLIER
UPWARD_THRESHOLD = HYSTERESIS_INCREMENT * HYSTERESIS_UPWARD_MULTIPLIER
if (

View File

@ -98,14 +98,10 @@ This should be the genesis state for a full client.
*Note* With regards to fork choice, block headers are interchangeable with blocks. The spec is likely to move to headers for reduced overhead in test vectors and better encapsulation. Full implementations store blocks as part of their database and will often use full blocks when dealing with production fork choice.
_The block for `anchor_root` is incorrectly initialized to the block header, rather than the full block. This does not affect functionality but will be cleaned up in subsequent releases._
```python
def get_forkchoice_store(anchor_state: BeaconState) -> Store:
anchor_block_header = copy(anchor_state.latest_block_header)
if anchor_block_header.state_root == Bytes32():
anchor_block_header.state_root = hash_tree_root(anchor_state)
anchor_root = hash_tree_root(anchor_block_header)
def get_forkchoice_store(anchor_state: BeaconState, anchor_block: BeaconBlock) -> Store:
assert anchor_block.state_root == hash_tree_root(anchor_state)
anchor_root = hash_tree_root(anchor_block)
anchor_epoch = get_current_epoch(anchor_state)
justified_checkpoint = Checkpoint(epoch=anchor_epoch, root=anchor_root)
finalized_checkpoint = Checkpoint(epoch=anchor_epoch, root=anchor_root)
@ -115,7 +111,7 @@ def get_forkchoice_store(anchor_state: BeaconState) -> Store:
justified_checkpoint=justified_checkpoint,
finalized_checkpoint=finalized_checkpoint,
best_justified_checkpoint=justified_checkpoint,
blocks={anchor_root: anchor_block_header},
blocks={anchor_root: copy(anchor_block)},
block_states={anchor_root: copy(anchor_state)},
checkpoint_states={justified_checkpoint: copy(anchor_state)},
)

View File

@ -243,12 +243,11 @@ Each gossipsub [message](https://github.com/libp2p/go-libp2p-pubsub/blob/master/
Clients MUST reject (fail validation) messages that are over this size limit.
Likewise, clients MUST NOT emit or propagate messages larger than this limit.
The `message-id` of a gossipsub message MUST be:
The `message-id` of a gossipsub message MUST be the first 8 bytes of the SHA-256 hash of the message data, i.e.:
```python
message-id: base64(SHA256(message.data))
message-id: SHA256(message.data)[0:8]
```
where `base64` is the [URL-safe base64 alphabet](https://tools.ietf.org/html/rfc4648#section-3.2) with padding characters omitted.
The payload is carried in the `data` field of a gossipsub message, and varies depending on the topic:
@ -383,6 +382,7 @@ The `beacon_attestation_{subnet_id}` topics are used to propagate unaggregated a
to the subnet `subnet_id` (typically beacon and persistent committees) to be aggregated before being gossiped to `beacon_aggregate_and_proof`.
The following validations MUST pass before forwarding the `attestation` on the subnet.
- _[REJECT]_ The committee index is within the expected range -- i.e. `data.index < get_committee_count_per_slot(state, data.target.epoch)`.
- _[REJECT]_ The attestation is for the correct subnet --
i.e. `compute_subnet_for_attestation(committees_per_slot, attestation.data.slot, attestation.data.index) == subnet_id`,
where `committees_per_slot = get_committee_count_per_slot(state, attestation.data.target.epoch)`,
@ -395,6 +395,8 @@ The following validations MUST pass before forwarding the `attestation` on the s
compute_epoch_at_slot(attestation.data.slot)`
- _[REJECT]_ The attestation is unaggregated --
that is, it has exactly one participating validator (`len([bit for bit in attestation.aggregation_bits if bit]) == 1`, i.e. exactly 1 bit is set).
- _[REJECT]_ The number of aggregation bits matches the committee size -- i.e.
`len(attestation.aggregation_bits) == len(get_beacon_committee(state, data.slot, data.index))`.
- _[IGNORE]_ There has been no other valid attestation seen on an attestation subnet
that has an identical `attestation.data.target.epoch` and participating validator index.
- _[REJECT]_ The signature of `attestation` is valid.
@ -410,7 +412,6 @@ The following validations MUST pass before forwarding the `attestation` on the s
#### Attestations and Aggregation
Attestation broadcasting is grouped into subnets defined by a topic.

View File

@ -168,7 +168,7 @@ def get_committee_assignment(state: BeaconState,
* ``assignment[2]`` is the slot at which the committee is assigned
Return None if no assignment.
"""
next_epoch = get_current_epoch(state) + 1
next_epoch = Epoch(get_current_epoch(state) + 1)
assert epoch <= next_epoch
start_slot = compute_start_slot_at_epoch(epoch)
@ -460,7 +460,7 @@ def compute_subnet_for_attestation(committees_per_slot: uint64, slot: Slot, comm
Compute the correct subnet for an attestation for Phase 0.
Note, this mimics expected Phase 1 behavior where attestations will be mapped to their shard subnet.
"""
slots_since_epoch_start = slot % SLOTS_PER_EPOCH
slots_since_epoch_start = uint64(slot % SLOTS_PER_EPOCH)
committees_since_epoch_start = committees_per_slot * slots_since_epoch_start
return uint64((committees_since_epoch_start + committee_index) % ATTESTATION_SUBNET_COUNT)

View File

@ -105,20 +105,20 @@ Configuration is not namespaced. Instead it is strictly an extension;
| Name | Value |
| - | - |
| `MAX_SHARDS` | `2**10` (= 1024) |
| `INITIAL_ACTIVE_SHARDS` | `2**6` (= 64) |
| `LIGHT_CLIENT_COMMITTEE_SIZE` | `2**7` (= 128) |
| `GASPRICE_ADJUSTMENT_COEFFICIENT` | `2**3` (= 8) |
| `MAX_SHARDS` | `uint64(2**10)` (= 1024) |
| `INITIAL_ACTIVE_SHARDS` | `uint64(2**6)` (= 64) |
| `LIGHT_CLIENT_COMMITTEE_SIZE` | `uint64(2**7)` (= 128) |
| `GASPRICE_ADJUSTMENT_COEFFICIENT` | `uint64(2**3)` (= 8) |
### Shard block configs
| Name | Value | Unit |
| - | - | - |
| `MAX_SHARD_BLOCK_SIZE` | `2**20` (= 1,048,576) | bytes |
| `TARGET_SHARD_BLOCK_SIZE` | `2**18` (= 262,144) | bytes |
| `SHARD_BLOCK_OFFSETS` | `[1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233]` | - |
| `MAX_SHARD_BLOCK_SIZE` | `uint64(2**20)` (= 1,048,576) | bytes |
| `TARGET_SHARD_BLOCK_SIZE` | `uint64(2**18)` (= 262,144) | bytes |
| `SHARD_BLOCK_OFFSETS` | `List[uint64, 12]([1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233])` | - |
| `MAX_SHARD_BLOCKS_PER_ATTESTATION` | `len(SHARD_BLOCK_OFFSETS)` | - |
| `BYTES_PER_CUSTODY_CHUNK` | `2**12` (= 4,096) | bytes |
| `BYTES_PER_CUSTODY_CHUNK` | `uint64(2**12)` (= 4,096) | bytes |
| `CUSTODY_RESPONSE_DEPTH` | `ceillog2(MAX_SHARD_BLOCK_SIZE // BYTES_PER_CUSTODY_CHUNK)` | - |
### Gwei values
@ -504,7 +504,7 @@ def compute_committee_source_epoch(epoch: Epoch, period: uint64) -> Epoch:
"""
Return the source epoch for computing the committee.
"""
source_epoch = epoch - epoch % period
source_epoch = Epoch(epoch - epoch % period)
if source_epoch >= period:
source_epoch -= period # `period` epochs lookahead
return source_epoch
@ -575,7 +575,7 @@ def get_light_client_committee(beacon_state: BeaconState, epoch: Epoch) -> Seque
return compute_committee(
indices=active_validator_indices,
seed=seed,
index=0,
index=uint64(0),
count=get_active_shard_count(beacon_state),
)[:LIGHT_CLIENT_COMMITTEE_SIZE]
```
@ -601,10 +601,10 @@ def get_committee_count_delta(state: BeaconState, start_slot: Slot, stop_slot: S
"""
Return the sum of committee counts in range ``[start_slot, stop_slot)``.
"""
return sum(
return uint64(sum(
get_committee_count_per_slot(state, compute_epoch_at_slot(Slot(slot)))
for slot in range(start_slot, stop_slot)
)
))
```
#### `get_start_shard`

View File

@ -56,10 +56,10 @@ This document details the beacon chain additions and changes in Phase 1 of Ether
| Name | Value | Unit |
| - | - | - |
| `CUSTODY_PRIME` | `2 ** 256 - 189` | - |
| `CUSTODY_SECRETS` | `3` | - |
| `BYTES_PER_CUSTODY_ATOM` | `32` | bytes |
| `CUSTODY_PROBABILITY_EXPONENT` | `10` | - |
| `CUSTODY_PRIME` | `int(2 ** 256 - 189)` | - |
| `CUSTODY_SECRETS` | `uint64(3)` | - |
| `BYTES_PER_CUSTODY_ATOM` | `uint64(32)` | bytes |
| `CUSTODY_PROBABILITY_EXPONENT` | `uint64(10)` | - |
## Configuration
@ -67,29 +67,29 @@ This document details the beacon chain additions and changes in Phase 1 of Ether
| Name | Value | Unit | Duration |
| - | - | :-: | :-: |
| `RANDAO_PENALTY_EPOCHS` | `2**1` (= 2) | epochs | 12.8 minutes |
| `EARLY_DERIVED_SECRET_PENALTY_MAX_FUTURE_EPOCHS` | `2**15` (= 32,768) | epochs | ~146 days |
| `EPOCHS_PER_CUSTODY_PERIOD` | `2**14` (= 16,384) | epochs | ~73 days |
| `CUSTODY_PERIOD_TO_RANDAO_PADDING` | `2**11` (= 2,048) | epochs | ~9 days |
| `MAX_CHUNK_CHALLENGE_DELAY` | `2**15` (= 32,768) | epochs | ~146 days |
| `RANDAO_PENALTY_EPOCHS` | `uint64(2**1)` (= 2) | epochs | 12.8 minutes |
| `EARLY_DERIVED_SECRET_PENALTY_MAX_FUTURE_EPOCHS` | `uint64(2**15)` (= 32,768) | epochs | ~146 days |
| `EPOCHS_PER_CUSTODY_PERIOD` | `uint64(2**14)` (= 16,384) | epochs | ~73 days |
| `CUSTODY_PERIOD_TO_RANDAO_PADDING` | `uint64(2**11)` (= 2,048) | epochs | ~9 days |
| `MAX_CHUNK_CHALLENGE_DELAY` | `uint64(2**15)` (= 32,768) | epochs | ~146 days |
### Max operations per block
| Name | Value |
| - | - |
| `MAX_CUSTODY_CHUNK_CHALLENGE_RECORDS` | `2**20` (= 1,048,576) |
| `MAX_CUSTODY_KEY_REVEALS` | `2**8` (= 256) |
| `MAX_EARLY_DERIVED_SECRET_REVEALS` | `2**0` (= 1) |
| `MAX_CUSTODY_CHUNK_CHALLENGES` | `2**2` (= 4) |
| `MAX_CUSTODY_CHUNK_CHALLENGE_RESPONSES` | `2**4` (= 16) |
| `MAX_CUSTODY_SLASHINGS` | `2**0` (= 1) |
| `MAX_CUSTODY_CHUNK_CHALLENGE_RECORDS` | `uint64(2**20)` (= 1,048,576) |
| `MAX_CUSTODY_KEY_REVEALS` | `uint64(2**8)` (= 256) |
| `MAX_EARLY_DERIVED_SECRET_REVEALS` | `uint64(2**0)` (= 1) |
| `MAX_CUSTODY_CHUNK_CHALLENGES` | `uint64(2**2)` (= 4) |
| `MAX_CUSTODY_CHUNK_CHALLENGE_RESPONSES` | `uint64(2**4)` (= 16) |
| `MAX_CUSTODY_SLASHINGS` | `uint64(2**0)` (= 1) |
### Reward and penalty quotients
| Name | Value |
| - | - |
| `EARLY_DERIVED_SECRET_REVEAL_SLOT_REWARD_MULTIPLE` | `2**1` (= 2) |
| `MINOR_REWARD_QUOTIENT` | `2**8` (= 256) |
| `EARLY_DERIVED_SECRET_REVEAL_SLOT_REWARD_MULTIPLE` | `uint64(2**1)` (= 2) |
| `MINOR_REWARD_QUOTIENT` | `uint64(2**8)` (= 256) |
## Data structures
@ -265,12 +265,12 @@ def universal_hash_function(data_chunks: Sequence[bytes], secrets: Sequence[int]
### `compute_custody_bit`
```python
def compute_custody_bit(key: BLSSignature, data: ByteList[MAX_SHARD_BLOCK_SIZE]) -> bit:
def compute_custody_bit(key: BLSSignature, data: ByteList) -> bit:
custody_atoms = get_custody_atoms(data)
secrets = get_custody_secrets(key)
uhf = universal_hash_function(custody_atoms, secrets)
legendre_bits = [legendre_bit(uhf + secrets[0] + i, CUSTODY_PRIME) for i in range(CUSTODY_PROBABILITY_EXPONENT)]
return all(legendre_bits)
return bit(all(legendre_bits))
```
### `get_randao_epoch_for_custody_period`
@ -316,7 +316,7 @@ def process_chunk_challenge(state: BeaconState, challenge: CustodyChunkChallenge
# Verify the attestation
assert is_valid_indexed_attestation(state, get_indexed_attestation(state, challenge.attestation))
# Verify it is not too late to challenge the attestation
max_attestation_challenge_epoch = challenge.attestation.data.target.epoch + MAX_CHUNK_CHALLENGE_DELAY
max_attestation_challenge_epoch = Epoch(challenge.attestation.data.target.epoch + MAX_CHUNK_CHALLENGE_DELAY)
assert get_current_epoch(state) <= max_attestation_challenge_epoch
# Verify it is not too late to challenge the responder
responder = state.validators[challenge.responder_index]
@ -438,7 +438,7 @@ def process_early_derived_secret_reveal(state: BeaconState, reveal: EarlyDerived
Note that this function mutates ``state``.
"""
revealed_validator = state.validators[reveal.revealed_index]
derived_secret_location = reveal.epoch % EARLY_DERIVED_SECRET_PENALTY_MAX_FUTURE_EPOCHS
derived_secret_location = uint64(reveal.epoch % EARLY_DERIVED_SECRET_PENALTY_MAX_FUTURE_EPOCHS)
assert reveal.epoch >= get_current_epoch(state) + RANDAO_PENALTY_EPOCHS
assert reveal.epoch < get_current_epoch(state) + EARLY_DERIVED_SECRET_PENALTY_MAX_FUTURE_EPOCHS

View File

@ -71,11 +71,9 @@ class ShardStore:
#### Updated `get_forkchoice_store`
```python
def get_forkchoice_store(anchor_state: BeaconState) -> Store:
anchor_block_header = anchor_state.latest_block_header.copy()
if anchor_block_header.state_root == Bytes32():
anchor_block_header.state_root = hash_tree_root(anchor_state)
anchor_root = hash_tree_root(anchor_block_header)
def get_forkchoice_store(anchor_state: BeaconState, anchor_block: BeaconBlock) -> Store:
assert anchor_block.state_root == hash_tree_root(anchor_state)
anchor_root = hash_tree_root(anchor_block)
anchor_epoch = get_current_epoch(anchor_state)
justified_checkpoint = Checkpoint(epoch=anchor_epoch, root=anchor_root)
finalized_checkpoint = Checkpoint(epoch=anchor_epoch, root=anchor_root)
@ -85,7 +83,7 @@ def get_forkchoice_store(anchor_state: BeaconState) -> Store:
justified_checkpoint=justified_checkpoint,
finalized_checkpoint=finalized_checkpoint,
best_justified_checkpoint=justified_checkpoint,
blocks={anchor_root: anchor_block_header},
blocks={anchor_root: copy(anchor_block)},
block_states={anchor_root: anchor_state.copy()},
checkpoint_states={justified_checkpoint: anchor_state.copy()},
shard_stores={

View File

@ -281,9 +281,9 @@ def get_shard_transition_fields(
shard: Shard,
shard_blocks: Sequence[SignedShardBlock],
) -> Tuple[Sequence[uint64], Sequence[Root], Sequence[ShardState]]:
shard_states = []
shard_data_roots = []
shard_block_lengths = []
shard_block_lengths = [] # type: PyList[uint64]
shard_data_roots = [] # type: PyList[Root]
shard_states = [] # type: PyList[ShardState]
shard_state = beacon_state.shard_states[shard]
shard_block_slots = [shard_block.message.slot for shard_block in shard_blocks]
@ -301,7 +301,7 @@ def get_shard_transition_fields(
shard_state = shard_state.copy()
process_shard_block(shard_state, shard_block.message)
shard_states.append(shard_state)
shard_block_lengths.append(len(shard_block.message.body))
shard_block_lengths.append(uint64(len(shard_block.message.body)))
return shard_block_lengths, shard_data_roots, shard_states
```

View File

@ -1,3 +1,6 @@
from eth2spec.phase0 import spec as phase0_spec
def get_anchor_root(spec, state):
anchor_block_header = state.latest_block_header.copy()
if anchor_block_header.state_root == spec.Bytes32():
@ -25,3 +28,10 @@ def add_attestation_to_store(spec, store, attestation):
spec.on_tick(store, next_epoch_time)
spec.on_attestation(store, attestation)
def get_genesis_forkchoice_store(spec, genesis_state):
assert genesis_state.slot == spec.GENESIS_SLOT
# The genesis block must be a Phase 0 `BeaconBlock`
genesis_block = phase0_spec.BeaconBlock(state_root=genesis_state.hash_tree_root())
return spec.get_forkchoice_store(genesis_state, genesis_block)

View File

@ -79,6 +79,20 @@ def test_invalid_sig_1_and_2(spec, state):
yield from run_proposer_slashing_processing(spec, state, proposer_slashing, False)
@with_all_phases
@spec_state_test
@always_bls
def test_invalid_sig_1_and_2_swap(spec, state):
# Get valid signatures for the slashings
proposer_slashing = get_valid_proposer_slashing(spec, state, signed_1=True, signed_2=True)
# But swap them
signature_1 = proposer_slashing.signed_header_1.signature
proposer_slashing.signed_header_1.signature = proposer_slashing.signed_header_2.signature
proposer_slashing.signed_header_2.signature = signature_1
yield from run_proposer_slashing_processing(spec, state, proposer_slashing, False)
@with_all_phases
@spec_state_test
def test_invalid_proposer_index(spec, state):
@ -122,11 +136,26 @@ def test_epochs_are_different(spec, state):
@with_all_phases
@spec_state_test
def test_headers_are_same(spec, state):
def test_headers_are_same_sigs_are_same(spec, state):
proposer_slashing = get_valid_proposer_slashing(spec, state, signed_1=True, signed_2=False)
# set headers to be the same
proposer_slashing.signed_header_2 = proposer_slashing.signed_header_1
proposer_slashing.signed_header_2 = proposer_slashing.signed_header_1.copy()
yield from run_proposer_slashing_processing(spec, state, proposer_slashing, False)
@with_all_phases
@spec_state_test
def test_headers_are_same_sigs_are_different(spec, state):
proposer_slashing = get_valid_proposer_slashing(spec, state, signed_1=True, signed_2=False)
# set headers to be the same
proposer_slashing.signed_header_2 = proposer_slashing.signed_header_1.copy()
# but signatures to be different
proposer_slashing.signed_header_2.signature = proposer_slashing.signed_header_2.signature[:-1] + b'\x00'
assert proposer_slashing.signed_header_1.signature != proposer_slashing.signed_header_2.signature
yield from run_proposer_slashing_processing(spec, state, proposer_slashing, False)

View File

@ -1,7 +1,11 @@
from eth2spec.test.context import with_all_phases, spec_state_test
from eth2spec.test.helpers.attestations import get_valid_attestation, next_epoch_with_attestations
from eth2spec.test.helpers.block import build_empty_block_for_next_slot
from eth2spec.test.helpers.fork_choice import add_attestation_to_store, add_block_to_store, get_anchor_root
from eth2spec.test.helpers.fork_choice import (
add_attestation_to_store,
add_block_to_store, get_anchor_root,
get_genesis_forkchoice_store,
)
from eth2spec.test.helpers.state import (
next_epoch,
state_transition_and_sign_block,
@ -12,7 +16,7 @@ from eth2spec.test.helpers.state import (
@spec_state_test
def test_genesis(spec, state):
# Initialization
store = spec.get_forkchoice_store(state)
store = get_genesis_forkchoice_store(spec, state)
anchor_root = get_anchor_root(spec, state)
assert spec.get_head(store) == anchor_root
@ -21,7 +25,7 @@ def test_genesis(spec, state):
@spec_state_test
def test_chain_no_attestations(spec, state):
# Initialization
store = spec.get_forkchoice_store(state)
store = get_genesis_forkchoice_store(spec, state)
anchor_root = get_anchor_root(spec, state)
assert spec.get_head(store) == anchor_root
@ -44,7 +48,7 @@ def test_split_tie_breaker_no_attestations(spec, state):
genesis_state = state.copy()
# Initialization
store = spec.get_forkchoice_store(state)
store = get_genesis_forkchoice_store(spec, state)
anchor_root = get_anchor_root(spec, state)
assert spec.get_head(store) == anchor_root
@ -72,13 +76,13 @@ def test_shorter_chain_but_heavier_weight(spec, state):
genesis_state = state.copy()
# Initialization
store = spec.get_forkchoice_store(state)
store = get_genesis_forkchoice_store(spec, state)
anchor_root = get_anchor_root(spec, state)
assert spec.get_head(store) == anchor_root
# build longer tree
long_state = genesis_state.copy()
for i in range(3):
for _ in range(3):
long_block = build_empty_block_for_next_slot(spec, long_state)
signed_long_block = state_transition_and_sign_block(spec, long_state, long_block)
add_block_to_store(spec, store, signed_long_block)
@ -100,7 +104,7 @@ def test_shorter_chain_but_heavier_weight(spec, state):
@spec_state_test
def test_filtered_block_tree(spec, state):
# Initialization
store = spec.get_forkchoice_store(state)
store = get_genesis_forkchoice_store(spec, state)
anchor_root = get_anchor_root(spec, state)
# transition state past initial couple of epochs

View File

@ -2,6 +2,7 @@ from eth2spec.test.context import PHASE0, with_all_phases, spec_state_test
from eth2spec.test.helpers.block import build_empty_block_for_next_slot
from eth2spec.test.helpers.attestations import get_valid_attestation, sign_attestation
from eth2spec.test.helpers.state import transition_to, state_transition_and_sign_block, next_epoch, next_slot
from eth2spec.test.helpers.fork_choice import get_genesis_forkchoice_store
def run_on_attestation(spec, state, store, attestation, valid=True):
@ -41,7 +42,7 @@ def run_on_attestation(spec, state, store, attestation, valid=True):
@with_all_phases
@spec_state_test
def test_on_attestation_current_epoch(spec, state):
store = spec.get_forkchoice_store(state)
store = get_genesis_forkchoice_store(spec, state)
spec.on_tick(store, store.time + spec.SECONDS_PER_SLOT * 2)
block = build_empty_block_for_next_slot(spec, state)
@ -60,7 +61,7 @@ def test_on_attestation_current_epoch(spec, state):
@with_all_phases
@spec_state_test
def test_on_attestation_previous_epoch(spec, state):
store = spec.get_forkchoice_store(state)
store = get_genesis_forkchoice_store(spec, state)
spec.on_tick(store, store.time + spec.SECONDS_PER_SLOT * spec.SLOTS_PER_EPOCH)
block = build_empty_block_for_next_slot(spec, state)
@ -79,7 +80,7 @@ def test_on_attestation_previous_epoch(spec, state):
@with_all_phases
@spec_state_test
def test_on_attestation_past_epoch(spec, state):
store = spec.get_forkchoice_store(state)
store = get_genesis_forkchoice_store(spec, state)
# move time forward 2 epochs
time = store.time + 2 * spec.SECONDS_PER_SLOT * spec.SLOTS_PER_EPOCH
@ -101,7 +102,7 @@ def test_on_attestation_past_epoch(spec, state):
@with_all_phases
@spec_state_test
def test_on_attestation_mismatched_target_and_slot(spec, state):
store = spec.get_forkchoice_store(state)
store = get_genesis_forkchoice_store(spec, state)
spec.on_tick(store, store.time + spec.SECONDS_PER_SLOT * spec.SLOTS_PER_EPOCH)
block = build_empty_block_for_next_slot(spec, state)
@ -124,7 +125,7 @@ def test_on_attestation_mismatched_target_and_slot(spec, state):
@with_all_phases
@spec_state_test
def test_on_attestation_inconsistent_target_and_head(spec, state):
store = spec.get_forkchoice_store(state)
store = get_genesis_forkchoice_store(spec, state)
spec.on_tick(store, store.time + 2 * spec.SECONDS_PER_SLOT * spec.SLOTS_PER_EPOCH)
# Create chain 1 as empty chain between genesis and start of 1st epoch
@ -162,7 +163,7 @@ def test_on_attestation_inconsistent_target_and_head(spec, state):
@with_all_phases
@spec_state_test
def test_on_attestation_target_block_not_in_store(spec, state):
store = spec.get_forkchoice_store(state)
store = get_genesis_forkchoice_store(spec, state)
time = store.time + spec.SECONDS_PER_SLOT * (spec.SLOTS_PER_EPOCH + 1)
spec.on_tick(store, time)
@ -184,7 +185,7 @@ def test_on_attestation_target_block_not_in_store(spec, state):
@with_all_phases
@spec_state_test
def test_on_attestation_target_checkpoint_not_in_store(spec, state):
store = spec.get_forkchoice_store(state)
store = get_genesis_forkchoice_store(spec, state)
time = store.time + spec.SECONDS_PER_SLOT * (spec.SLOTS_PER_EPOCH + 1)
spec.on_tick(store, time)
@ -209,7 +210,7 @@ def test_on_attestation_target_checkpoint_not_in_store(spec, state):
@with_all_phases
@spec_state_test
def test_on_attestation_target_checkpoint_not_in_store_diff_slot(spec, state):
store = spec.get_forkchoice_store(state)
store = get_genesis_forkchoice_store(spec, state)
time = store.time + spec.SECONDS_PER_SLOT * (spec.SLOTS_PER_EPOCH + 1)
spec.on_tick(store, time)
@ -236,7 +237,7 @@ def test_on_attestation_target_checkpoint_not_in_store_diff_slot(spec, state):
@with_all_phases
@spec_state_test
def test_on_attestation_beacon_block_not_in_store(spec, state):
store = spec.get_forkchoice_store(state)
store = get_genesis_forkchoice_store(spec, state)
time = store.time + spec.SECONDS_PER_SLOT * (spec.SLOTS_PER_EPOCH + 1)
spec.on_tick(store, time)
@ -265,7 +266,7 @@ def test_on_attestation_beacon_block_not_in_store(spec, state):
@with_all_phases
@spec_state_test
def test_on_attestation_future_epoch(spec, state):
store = spec.get_forkchoice_store(state)
store = get_genesis_forkchoice_store(spec, state)
time = store.time + 3 * spec.SECONDS_PER_SLOT
spec.on_tick(store, time)
@ -285,7 +286,7 @@ def test_on_attestation_future_epoch(spec, state):
@with_all_phases
@spec_state_test
def test_on_attestation_future_block(spec, state):
store = spec.get_forkchoice_store(state)
store = get_genesis_forkchoice_store(spec, state)
time = store.time + spec.SECONDS_PER_SLOT * 5
spec.on_tick(store, time)
@ -305,7 +306,7 @@ def test_on_attestation_future_block(spec, state):
@with_all_phases
@spec_state_test
def test_on_attestation_same_slot(spec, state):
store = spec.get_forkchoice_store(state)
store = get_genesis_forkchoice_store(spec, state)
time = store.time + spec.SECONDS_PER_SLOT
spec.on_tick(store, time)
@ -321,7 +322,7 @@ def test_on_attestation_same_slot(spec, state):
@with_all_phases
@spec_state_test
def test_on_attestation_invalid_attestation(spec, state):
store = spec.get_forkchoice_store(state)
store = get_genesis_forkchoice_store(spec, state)
time = store.time + 3 * spec.SECONDS_PER_SLOT
spec.on_tick(store, time)

View File

@ -2,10 +2,11 @@ from copy import deepcopy
from eth2spec.utils.ssz.ssz_impl import hash_tree_root
from eth2spec.test.context import with_all_phases, spec_state_test
from eth2spec.test.helpers.attestations import next_epoch_with_attestations
from eth2spec.test.helpers.block import build_empty_block_for_next_slot, sign_block, transition_unsigned_block, \
build_empty_block
from eth2spec.test.helpers.attestations import next_epoch_with_attestations
from eth2spec.test.helpers.state import next_epoch, state_transition_and_sign_block
from eth2spec.test.helpers.fork_choice import get_genesis_forkchoice_store
from eth2spec.test.helpers.state import next_epoch, state_transition_and_sign_block, transition_to
def run_on_block(spec, store, signed_block, valid=True):
@ -37,7 +38,7 @@ def apply_next_epoch_with_attestations(spec, state, store):
@spec_state_test
def test_basic(spec, state):
# Initialization
store = spec.get_forkchoice_store(state)
store = get_genesis_forkchoice_store(spec, state)
time = 100
spec.on_tick(store, time)
assert store.time == time
@ -61,7 +62,7 @@ def test_basic(spec, state):
@spec_state_test
def test_on_block_checkpoints(spec, state):
# Initialization
store = spec.get_forkchoice_store(state)
store = get_genesis_forkchoice_store(spec, state)
time = 100
spec.on_tick(store, time)
@ -87,7 +88,7 @@ def test_on_block_checkpoints(spec, state):
@spec_state_test
def test_on_block_future_block(spec, state):
# Initialization
store = spec.get_forkchoice_store(state)
store = get_genesis_forkchoice_store(spec, state)
# do not tick time
@ -101,7 +102,7 @@ def test_on_block_future_block(spec, state):
@spec_state_test
def test_on_block_bad_parent_root(spec, state):
# Initialization
store = spec.get_forkchoice_store(state)
store = get_genesis_forkchoice_store(spec, state)
time = 100
spec.on_tick(store, time)
@ -121,7 +122,7 @@ def test_on_block_bad_parent_root(spec, state):
@spec_state_test
def test_on_block_before_finalized(spec, state):
# Initialization
store = spec.get_forkchoice_store(state)
store = get_genesis_forkchoice_store(spec, state)
time = 100
spec.on_tick(store, time)
@ -140,7 +141,7 @@ def test_on_block_before_finalized(spec, state):
@spec_state_test
def test_on_block_finalized_skip_slots(spec, state):
# Initialization
store = spec.get_forkchoice_store(state)
store = get_genesis_forkchoice_store(spec, state)
time = 100
spec.on_tick(store, time)
@ -160,16 +161,18 @@ def test_on_block_finalized_skip_slots(spec, state):
@spec_state_test
def test_on_block_finalized_skip_slots_not_in_skip_chain(spec, state):
# Initialization
next_epoch(spec, state)
store = spec.get_forkchoice_store(state)
transition_to(spec, state, state.slot + spec.SLOTS_PER_EPOCH - 1)
block = build_empty_block_for_next_slot(spec, state)
transition_unsigned_block(spec, state, block)
block.state_root = state.hash_tree_root()
store = spec.get_forkchoice_store(state, block)
store.finalized_checkpoint = spec.Checkpoint(
epoch=store.finalized_checkpoint.epoch + 2,
root=store.finalized_checkpoint.root
)
# First transition through the epoch to ensure no skipped slots
state, store, last_signed_block = apply_next_epoch_with_attestations(spec, state, store)
state, store, _ = apply_next_epoch_with_attestations(spec, state, store)
# Now build a block at later slot than finalized epoch
# Includes finalized block in chain, but not at appropriate skip slot
@ -183,7 +186,7 @@ def test_on_block_finalized_skip_slots_not_in_skip_chain(spec, state):
@spec_state_test
def test_on_block_update_justified_checkpoint_within_safe_slots(spec, state):
# Initialization
store = spec.get_forkchoice_store(state)
store = get_genesis_forkchoice_store(spec, state)
time = 0
spec.on_tick(store, time)
@ -214,7 +217,7 @@ def test_on_block_update_justified_checkpoint_within_safe_slots(spec, state):
@spec_state_test
def test_on_block_outside_safe_slots_and_multiple_better_justified(spec, state):
# Initialization
store = spec.get_forkchoice_store(state)
store = get_genesis_forkchoice_store(spec, state)
time = 0
spec.on_tick(store, time)
@ -264,7 +267,7 @@ def test_on_block_outside_safe_slots_and_multiple_better_justified(spec, state):
@spec_state_test
def test_on_block_outside_safe_slots_but_finality(spec, state):
# Initialization
store = spec.get_forkchoice_store(state)
store = get_genesis_forkchoice_store(spec, state)
time = 100
spec.on_tick(store, time)

View File

@ -1,4 +1,5 @@
from eth2spec.test.context import with_all_phases, spec_state_test
from eth2spec.test.helpers.fork_choice import get_genesis_forkchoice_store
def run_on_tick(spec, store, time, new_justified_checkpoint=False):
@ -19,14 +20,14 @@ def run_on_tick(spec, store, time, new_justified_checkpoint=False):
@with_all_phases
@spec_state_test
def test_basic(spec, state):
store = spec.get_forkchoice_store(state)
store = get_genesis_forkchoice_store(spec, state)
run_on_tick(spec, store, store.time + 1)
@with_all_phases
@spec_state_test
def test_update_justified_single(spec, state):
store = spec.get_forkchoice_store(state)
store = get_genesis_forkchoice_store(spec, state)
next_epoch = spec.get_current_epoch(state) + 1
next_epoch_start_slot = spec.compute_start_slot_at_epoch(next_epoch)
seconds_until_next_epoch = next_epoch_start_slot * spec.SECONDS_PER_SLOT - store.time
@ -42,7 +43,7 @@ def test_update_justified_single(spec, state):
@with_all_phases
@spec_state_test
def test_no_update_same_slot_at_epoch_boundary(spec, state):
store = spec.get_forkchoice_store(state)
store = get_genesis_forkchoice_store(spec, state)
seconds_per_epoch = spec.SECONDS_PER_SLOT * spec.SLOTS_PER_EPOCH
store.best_justified_checkpoint = spec.Checkpoint(
@ -59,7 +60,7 @@ def test_no_update_same_slot_at_epoch_boundary(spec, state):
@with_all_phases
@spec_state_test
def test_no_update_not_epoch_boundary(spec, state):
store = spec.get_forkchoice_store(state)
store = get_genesis_forkchoice_store(spec, state)
store.best_justified_checkpoint = spec.Checkpoint(
epoch=store.justified_checkpoint.epoch + 1,
@ -72,7 +73,7 @@ def test_no_update_not_epoch_boundary(spec, state):
@with_all_phases
@spec_state_test
def test_no_update_new_justified_equal_epoch(spec, state):
store = spec.get_forkchoice_store(state)
store = get_genesis_forkchoice_store(spec, state)
seconds_per_epoch = spec.SECONDS_PER_SLOT * spec.SLOTS_PER_EPOCH
store.best_justified_checkpoint = spec.Checkpoint(
@ -91,7 +92,7 @@ def test_no_update_new_justified_equal_epoch(spec, state):
@with_all_phases
@spec_state_test
def test_no_update_new_justified_later_epoch(spec, state):
store = spec.get_forkchoice_store(state)
store = get_genesis_forkchoice_store(spec, state)
seconds_per_epoch = spec.SECONDS_PER_SLOT * spec.SLOTS_PER_EPOCH
store.best_justified_checkpoint = spec.Checkpoint(

View File

@ -7,7 +7,7 @@ from eth2spec.test.helpers.shard_block import (
get_shard_transitions,
get_committee_index_of_shard,
)
from eth2spec.test.helpers.fork_choice import add_block_to_store, get_anchor_root
from eth2spec.test.helpers.fork_choice import add_block_to_store, get_anchor_root, get_genesis_forkchoice_store
from eth2spec.test.helpers.state import state_transition_and_sign_block
from eth2spec.test.helpers.block import build_empty_block
@ -28,7 +28,7 @@ def run_on_shard_block(spec, store, signed_block, valid=True):
def initialize_store(spec, state, shards):
store = spec.get_forkchoice_store(state)
store = get_genesis_forkchoice_store(spec, state)
anchor_root = get_anchor_root(spec, state)
assert spec.get_head(store) == anchor_root