Merge pull request #1743 from ethereum/dev

Release v0.11.2
This commit is contained in:
Danny Ryan 2020-04-24 11:09:19 -06:00 committed by GitHub
commit 2898ab0b01
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
52 changed files with 688 additions and 421 deletions

View File

@ -79,16 +79,16 @@ jobs:
# Restore git repo at point close to target branch/revision, to speed up checkout
- restore_cache:
keys:
- v2-specs-repo-{{ .Branch }}-{{ .Revision }}
- v2-specs-repo-{{ .Branch }}-
- v2-specs-repo-
- v3-specs-repo-{{ .Branch }}-{{ .Revision }}
- v3-specs-repo-{{ .Branch }}-
- v3-specs-repo-
- checkout
- run:
name: Clean up git repo to reduce cache size
command: git gc
# Save the git checkout as a cache, to make cloning next time faster.
- save_cache:
key: v2-specs-repo-{{ .Branch }}-{{ .Revision }}
key: v3-specs-repo-{{ .Branch }}-{{ .Revision }}
paths:
- ~/specs-repo
install_pyspec_test:
@ -97,7 +97,7 @@ jobs:
working_directory: ~/specs-repo
steps:
- restore_cache:
key: v2-specs-repo-{{ .Branch }}-{{ .Revision }}
key: v3-specs-repo-{{ .Branch }}-{{ .Revision }}
- restore_pyspec_cached_venv
- run:
name: Install pyspec requirements
@ -109,7 +109,7 @@ jobs:
working_directory: ~/specs-repo
steps:
- restore_cache:
key: v2-specs-repo-{{ .Branch }}-{{ .Revision }}
key: v3-specs-repo-{{ .Branch }}-{{ .Revision }}
- restore_pyspec_cached_venv
- run:
name: Run py-tests
@ -140,7 +140,7 @@ jobs:
working_directory: ~/specs-repo
steps:
- restore_cache:
key: v2-specs-repo-{{ .Branch }}-{{ .Revision }}
key: v3-specs-repo-{{ .Branch }}-{{ .Revision }}
- restore_pyspec_cached_venv
- run:
name: Run linter
@ -152,7 +152,7 @@ jobs:
working_directory: ~/specs-repo
steps:
- restore_cache:
key: v2-specs-repo-{{ .Branch }}-{{ .Revision }}
key: v3-specs-repo-{{ .Branch }}-{{ .Revision }}
- restore_deposit_contract_compiler_cached_venv
- run:
name: Install deposit contract compiler requirements
@ -164,7 +164,7 @@ jobs:
working_directory: ~/specs-repo
steps:
- restore_cache:
key: v2-specs-repo-{{ .Branch }}-{{ .Revision }}
key: v3-specs-repo-{{ .Branch }}-{{ .Revision }}
- restore_deposit_contract_tester_cached_venv
- run:
name: Install deposit contract tester requirements
@ -176,7 +176,7 @@ jobs:
working_directory: ~/specs-repo
steps:
- restore_cache:
key: v2-specs-repo-{{ .Branch }}-{{ .Revision }}
key: v3-specs-repo-{{ .Branch }}-{{ .Revision }}
- restore_deposit_contract_compiler_cached_venv
- run:
name: Run deposit contract compile test
@ -187,7 +187,7 @@ jobs:
working_directory: ~/specs-repo
steps:
- restore_cache:
key: v2-specs-repo-{{ .Branch }}-{{ .Revision }}
key: v3-specs-repo-{{ .Branch }}-{{ .Revision }}
- restore_deposit_contract_tester_cached_venv
- run:
name: Run deposit contract test

View File

@ -117,7 +117,7 @@ install_deposit_contract_compiler:
compile_deposit_contract:
cd $(DEPOSIT_CONTRACT_COMPILER_DIR); . venv/bin/activate; \
python3.7 deposit_contract/compile.py contracts/validator_registration.vy
python3.7 deposit_contract/compile.py ../contracts/validator_registration.vy
test_compile_deposit_contract:
cd $(DEPOSIT_CONTRACT_COMPILER_DIR); . venv/bin/activate; \

View File

@ -162,9 +162,6 @@ DOMAIN_CUSTODY_BIT_SLASHING: 0x83000000
# ---------------------------------------------------------------
PHASE_1_FORK_VERSION: 0x01000000
INITIAL_ACTIVE_SHARDS: 64
# Placeholder
INITIAL_GASPRICE: 10
# Phase 1: General
# ---------------------------------------------------------------
@ -190,8 +187,8 @@ SHARD_BLOCK_OFFSETS: [1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233]
MAX_SHARD_BLOCKS_PER_ATTESTATION: 12
# 2**14 (= 16,384) Gwei
MAX_GASPRICE: 16384
# 2**5 (= 32) Gwei
MIN_GASPRICE: 32
# 2**3 (= 8) Gwei
MIN_GASPRICE: 8
# 2**3 (= 8)
GASPRICE_ADJUSTMENT_COEFFICIENT: 8

View File

@ -164,8 +164,6 @@ DOMAIN_CUSTODY_BIT_SLASHING: 0x83000000
PHASE_1_FORK_VERSION: 0x01000001
# [customized] reduced for testing
INITIAL_ACTIVE_SHARDS: 4
# Placeholder
INITIAL_GASPRICE: 10
# Phase 1: General
@ -192,8 +190,8 @@ SHARD_BLOCK_OFFSETS: [1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233]
MAX_SHARD_BLOCKS_PER_ATTESTATION: 12
# 2**14 (= 16,384) Gwei
MAX_GASPRICE: 16384
# 2**5 (= 32) Gwei
MIN_GASPRICE: 32
# 2**3 (= 8) Gwei
MIN_GASPRICE: 8
# 2**3 (= 8)
GASPRICE_ADJUSTMENT_COEFFICIENT: 8

View File

@ -499,7 +499,7 @@ setup(
"pycryptodome==3.9.4",
"py_ecc==2.0.0",
"dataclasses==0.6",
"remerkleable==0.1.12",
"remerkleable==0.1.13",
"ruamel.yaml==0.16.5",
"lru-dict==1.1.6"
]

View File

@ -684,14 +684,10 @@ def is_slashable_attestation_data(data_1: AttestationData, data_2: AttestationDa
```python
def is_valid_indexed_attestation(state: BeaconState, indexed_attestation: IndexedAttestation) -> bool:
"""
Check if ``indexed_attestation`` has valid indices and signature.
Check if ``indexed_attestation`` has sorted and unique indices and a valid aggregate signature.
"""
indices = indexed_attestation.attesting_indices
# Verify max number of indices
if not len(indices) <= MAX_VALIDATORS_PER_COMMITTEE:
return False
# Verify indices are sorted and unique
indices = indexed_attestation.attesting_indices
if not indices == sorted(set(indices)):
return False
# Verify aggregate signature
@ -1195,7 +1191,7 @@ Let `genesis_block = BeaconBlock(state_root=hash_tree_root(genesis_state))`.
## Beacon chain state transition function
The post-state corresponding to a pre-state `state` and a signed block `signed_block` is defined as `state_transition(state, signed_block)`. State transitions that trigger an unhandled exception (e.g. a failed `assert` or an out-of-range list access) are considered invalid.
The post-state corresponding to a pre-state `state` and a signed block `signed_block` is defined as `state_transition(state, signed_block)`. State transitions that trigger an unhandled exception (e.g. a failed `assert` or an out-of-range list access) are considered invalid. State transitions that cause a `uint64` overflow or underflow are also considered invalid.
```python
def state_transition(state: BeaconState, signed_block: SignedBeaconBlock, validate_result: bool=True) -> BeaconState:

View File

@ -108,7 +108,7 @@ def get_forkchoice_store(anchor_state: BeaconState) -> Store:
justified_checkpoint = Checkpoint(epoch=anchor_epoch, root=anchor_root)
finalized_checkpoint = Checkpoint(epoch=anchor_epoch, root=anchor_root)
return Store(
time=anchor_state.genesis_time,
time=anchor_state.genesis_time + SECONDS_PER_SLOT * anchor_state.slot,
genesis_time=anchor_state.genesis_time,
justified_checkpoint=justified_checkpoint,
finalized_checkpoint=finalized_checkpoint,

View File

@ -105,6 +105,7 @@ It consists of four main sections:
- [Discovery](#discovery)
- [Why are we using discv5 and not libp2p Kademlia DHT?](#why-are-we-using-discv5-and-not-libp2p-kademlia-dht)
- [What is the difference between an ENR and a multiaddr, and why are we using ENRs?](#what-is-the-difference-between-an-enr-and-a-multiaddr-and-why-are-we-using-enrs)
- [Why do we not form ENRs and find peers until genesis block/state is known?](#why-do-we-not-form-enrs-and-find-peers-until-genesis-blockstate-is-known)
- [Compression/Encoding](#compressionencoding)
- [Why are we using SSZ for encoding?](#why-are-we-using-ssz-for-encoding)
- [Why are we compressing, and at which layers?](#why-are-we-compressing-and-at-which-layers)
@ -247,6 +248,8 @@ Topics are plain UTF-8 strings and are encoded on the wire as determined by prot
- `Name` - see table below
- `Encoding` - the encoding strategy describes a specific representation of bytes that will be transmitted over the wire. See the [Encodings](#Encoding-strategies) section for further details.
*Note*: `ForkDigestValue` is composed of values that are not known until the genesis block/state are available. Due to this, clients SHOULD NOT subscribe to gossipsub topics until these genesis values are known.
Each gossipsub [message](https://github.com/libp2p/go-libp2p-pubsub/blob/master/pb/rpc.proto#L17-L24) has a maximum size of `GOSSIP_MAX_SIZE`. 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:
@ -286,8 +289,8 @@ There are two primary global topics used to propagate beacon blocks and aggregat
- The block is proposed by the expected `proposer_index` for the block's slot in the context of the current shuffling (defined by `parent_root`/`slot`). If the `proposer_index` cannot immediately be verified against the expected shuffling, the block MAY be queued for later processing while proposers for the block's branch are calculated.
- `beacon_aggregate_and_proof` - This topic is used to propagate aggregated attestations (as `SignedAggregateAndProof`s) to subscribing nodes (typically validators) to be included in future blocks. The following validations MUST pass before forwarding the `signed_aggregate_and_proof` on the network. (We define the following for convenience -- `aggregate_and_proof = signed_aggregate_and_proof.message` and `aggregate = aggregate_and_proof.aggregate`)
- `aggregate.data.slot` is within the last `ATTESTATION_PROPAGATION_SLOT_RANGE` slots (with a `MAXIMUM_GOSSIP_CLOCK_DISPARITY` allowance) -- i.e. `aggregate.data.slot + ATTESTATION_PROPAGATION_SLOT_RANGE >= current_slot >= aggregate.data.slot` (a client MAY queue future aggregates for processing at the appropriate slot).
- The aggregate attestation defined by `hash_tree_root(aggregate)` has _not_ already been seen (via aggregate gossip, within a block, or through the creation of an equivalent aggregate locally).
- The `aggregate` is the first valid aggregate received for the aggregator with index `aggregate_and_proof.aggregator_index` for the slot `aggregate.data.slot`.
- The aggregate attestation defined by `hash_tree_root(aggregate)` has _not_ already been seen (via aggregate gossip, within a verified block, or through the creation of an equivalent aggregate locally).
- The `aggregate` is the first valid aggregate received for the aggregator with index `aggregate_and_proof.aggregator_index` for the epoch `aggregate.data.target.epoch`.
- The block being voted for (`aggregate.data.beacon_block_root`) passes validation.
- `aggregate_and_proof.selection_proof` selects the validator as an aggregator for the slot -- i.e. `is_aggregator(state, aggregate.data.slot, aggregate.data.index, aggregate_and_proof.selection_proof)` returns `True`.
- The aggregator's validator index is within the aggregate's committee -- i.e. `aggregate_and_proof.aggregator_index in get_attesting_indices(state, aggregate.data, aggregate.aggregation_bits)`.
@ -316,7 +319,7 @@ Attestation subnets are used to propagate unaggregated attestations to subsectio
- The attestation's committee index (`attestation.data.index`) is for the correct subnet.
- `attestation.data.slot` is within the last `ATTESTATION_PROPAGATION_SLOT_RANGE` slots (within a `MAXIMUM_GOSSIP_CLOCK_DISPARITY` allowance) -- i.e. `attestation.data.slot + ATTESTATION_PROPAGATION_SLOT_RANGE >= current_slot >= attestation.data.slot` (a client MAY queue future attestations for processing at the appropriate slot).
- The attestation is unaggregated -- that is, it has exactly one participating validator (`len([bit for bit in attestation.aggregation_bits if bit == 0b1]) == 1`).
- The attestation is the first valid attestation received for the participating validator for the slot, `attestation.data.slot`.
- There has been no other valid attestation seen on an attestation subnet that has an identical `attestation.data.target.epoch` and participating validator index.
- The block being voted for (`attestation.data.beacon_block_root`) passes validation.
- The signature of `attestation` is valid.
@ -342,7 +345,9 @@ Topics are post-fixed with an encoding. Encodings define how the payload of a go
#### Mainnet
- `ssz_snappy` - All objects are SSZ-encoded and then compressed with [Snappy](https://github.com/google/snappy). Example: The beacon aggregate attestation topic string is `/eth2/beacon_aggregate_and_proof/ssz_snappy`, and the data field of a gossipsub message is an `AggregateAndProof` that has been SSZ-encoded and then compressed with Snappy.
- `ssz_snappy` - All objects are SSZ-encoded and then compressed with [Snappy](https://github.com/google/snappy) block compression. Example: The beacon aggregate attestation topic string is `/eth2/beacon_aggregate_and_proof/ssz_snappy`, and the data field of a gossipsub message is an `AggregateAndProof` that has been SSZ-encoded and then compressed with Snappy.
Snappy has two formats: "block" and "frames" (streaming). Gossip messages remain relatively small (100s of bytes to 100s of kilobytes) so [basic snappy block compression](https://github.com/google/snappy/blob/master/format_description.txt) is used to avoid the additional overhead associated with snappy frames.
Implementations MUST use a single encoding. Changing an encoding will require coordination between participating implementations.
@ -445,7 +450,7 @@ Here, `result` represents the 1-byte response code.
The token of the negotiated protocol ID specifies the type of encoding to be used for the req/resp interaction. Two values are possible at this time:
- `ssz`: the contents are [SSZ-encoded](../../ssz/simple-serialize.md). This encoding type MUST be supported by all clients. For objects containing a single field, only the field is SSZ-encoded not a container with a single field. For example, the `BeaconBlocksByRoot` request is an SSZ-encoded list of `Root`'s.
- `ssz_snappy`: The contents are SSZ-encoded and then compressed with [Snappy](https://github.com/google/snappy). MAY be supported in the interoperability testnet; MUST be supported in mainnet.
- `ssz_snappy`: The contents are SSZ-encoded and then compressed with [Snappy](https://github.com/google/snappy) frames compression. MAY be supported in the interoperability testnet; MUST be supported in mainnet.
#### SSZ-encoding strategy (with or without Snappy)
@ -458,7 +463,7 @@ Snappy has two formats: "block" and "frames" (streaming). To support large reque
Since snappy frame contents [have a maximum size of `65536` bytes](https://github.com/google/snappy/blob/master/framing_format.txt#L104)
and frame headers are just `identifier (1) + checksum (4)` bytes, the expected buffering of a single frame is acceptable.
**Encoding-dependent header:** Req/Resp protocols using the `ssz` or `ssz_snappy` encoding strategies MUST encode the length of the raw SSZ bytes, encoded as an unsigned [protobuf varint](https://developers.google.com/protocol-buffers/docs/encoding#varints).
**Encoding-dependent header:** Req/Resp protocols using the `ssz` or `ssz_snappy` encoding strategies MUST encode the length of the raw SSZ bytes, encoded as an unsigned [protobuf varint](https://developers.google.com/protocol-buffers/docs/encoding#varints).
*Writing*: By first computing and writing the SSZ byte length, the SSZ encoder can then directly write the chunk contents to the stream.
If Snappy is applied, it can be passed through a buffered Snappy writer to compress frame by frame.
@ -572,7 +577,7 @@ Response Content:
)
```
Requests count beacon blocks from the peer starting from `start_slot`, leading up to the current head block as selected by fork choice. `step` defines the slot increment between blocks. For example, requesting blocks starting at `start_slot` 2 with a step value of 2 would return the blocks at slots [2, 4, 6, …]. In cases where a slot is empty for a given slot number, no block is returned. For example, if slot 4 were empty in the previous example, the returned array would contain [2, 6, …]. A step value of 1 returns all blocks on the range `[start_slot, start_slot + count)`.
Requests beacon blocks in the slot range `[start_slot, start_slot + count * step)`, leading up to the current head block as selected by fork choice. `step` defines the slot increment between blocks. For example, requesting blocks starting at `start_slot` 2 with a step value of 2 would return the blocks at slots [2, 4, 6, …]. In cases where a slot is empty for a given slot number, no block is returned. For example, if slot 4 were empty in the previous example, the returned array would contain [2, 6, …].
`BeaconBlocksByRange` is primarily used to sync historical blocks.
@ -752,6 +757,8 @@ where the fields of `ENRForkID` are defined as
* `next_fork_version` is the fork version corresponding to the next planned hard fork at a future epoch. If no future fork is planned, set `next_fork_version = current_fork_version` to signal this fact
* `next_fork_epoch` is the epoch at which the next fork is planned and the `current_fork_version` will be updated. If no future fork is planned, set `next_fork_epoch = FAR_FUTURE_EPOCH` to signal this fact
*Note*: `fork_digest` is composed of values that are not not known until the genesis block/state are available. Due to this, clients SHOULD NOT form ENRs and begin peer discovery until genesis values are known. One notable exception to this rule is the distribution of bootnode ENRs prior to genesis. In this case, bootnode ENRs SHOULD be initially distributed with `eth2` field set as `ENRForkID(fork_digest=compute_fork_digest(GENESIS_FORK_VERSION, b'\x00'*32), next_fork_version=GENESIS_FORK_VERSION, next_fork_epoch=FAR_FUTURE_EPOCH)`. After genesis values are known, the bootnodes SHOULD update ENRs to participate in normal discovery operations.
Clients SHOULD connect to peers with `fork_digest`, `next_fork_version`, and `next_fork_epoch` that match local values.
Clients MAY connect to peers with the same `fork_digest` but a different `next_fork_version`/`next_fork_epoch`. Unless `ENRForkID` is manually updated to matching prior to the earlier `next_fork_epoch` of the two clients, these connecting clients will be unable to successfully interact starting at the earlier `next_fork_epoch`.
@ -1092,6 +1099,12 @@ discv5 uses ENRs and we will presumably need to:
1. Add `multiaddr` to the dictionary, so that nodes can advertise their multiaddr under a reserved namespace in ENRs. and/or
2. Define a bi-directional conversion function between multiaddrs and the corresponding denormalized fields in an ENR (ip, ip6, tcp, tcp6, etc.), for compatibility with nodes that do not support multiaddr natively (e.g. Eth 1.0 nodes).
### Why do we not form ENRs and find peers until genesis block/state is known?
Although client software might very well be running locally prior to the solidification of the eth2 genesis state and block, clients cannot form valid ENRs prior to this point. ENRs contain `fork_digest` which utilizes the `genesis_validators_root` for a cleaner separation between chains so prior to knowing genesis, we cannot use `fork_digest` to cleanly find peers on our intended chain. Once genesis data is known, we can then form ENRs and safely find peers.
When using an eth1 deposit contract for deposits, `fork_digest` will be known at least `MIN_GENESIS_DELAY` (24 hours in mainnet configuration) before `genesis_time`, providing ample time to find peers and form initial connections and gossip subnets prior to genesis.
## Compression/Encoding
### Why are we using SSZ for encoding?

View File

@ -34,8 +34,10 @@
- [Misc](#misc-1)
- [`get_previous_slot`](#get_previous_slot)
- [`pack_compact_validator`](#pack_compact_validator)
- [`unpack_compact_validator`](#unpack_compact_validator)
- [`committee_to_compact_committee`](#committee_to_compact_committee)
- [`compute_shard_from_committee_index`](#compute_shard_from_committee_index)
- [`compute_offset_slots`](#compute_offset_slots)
- [Beacon state accessors](#beacon-state-accessors)
- [`get_active_shard_count`](#get_active_shard_count)
- [`get_online_validator_indices`](#get_online_validator_indices)
@ -46,9 +48,10 @@
- [`get_updated_gasprice`](#get_updated_gasprice)
- [`get_start_shard`](#get_start_shard)
- [`get_shard`](#get_shard)
- [`get_next_slot_for_shard`](#get_next_slot_for_shard)
- [`get_latest_slot_for_shard`](#get_latest_slot_for_shard)
- [`get_offset_slots`](#get_offset_slots)
- [Predicates](#predicates)
- [`is_winning_attestation`](#is_winning_attestation)
- [Updated `is_valid_indexed_attestation`](#updated-is_valid_indexed_attestation)
- [Block processing](#block-processing)
- [Operations](#operations)
@ -57,7 +60,7 @@
- [`apply_shard_transition`](#apply_shard_transition)
- [`process_crosslink_for_shard`](#process_crosslink_for_shard)
- [`process_crosslinks`](#process_crosslinks)
- [`process_attestations`](#process_attestations)
- [`process_attestation`](#process_attestation)
- [New Attester slashing processing](#new-attester-slashing-processing)
- [Shard transition false positives](#shard-transition-false-positives)
- [Light client processing](#light-client-processing)
@ -101,7 +104,7 @@ Configuration is not namespaced. Instead it is strictly an extension;
| `SHARD_BLOCK_OFFSETS` | `[1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233]` | |
| `MAX_SHARD_BLOCKS_PER_ATTESTATION` | `len(SHARD_BLOCK_OFFSETS)` | |
| `MAX_GASPRICE` | `Gwei(2**14)` (= 16,384) | Gwei | |
| `MIN_GASPRICE` | `Gwei(2**5)` (= 32) | Gwei | |
| `MIN_GASPRICE` | `Gwei(2**3)` (= 8) | Gwei | |
| `GASPRICE_ADJUSTMENT_COEFFICIENT` | `2**3` (= 8) | |
| `DOMAIN_SHARD_PROPOSAL` | `DomainType('0x80000000')` | |
| `DOMAIN_SHARD_COMMITTEE` | `DomainType('0x81000000')` | |
@ -371,15 +374,29 @@ def get_previous_slot(slot: Slot) -> Slot:
#### `pack_compact_validator`
```python
def pack_compact_validator(index: int, slashed: bool, balance_in_increments: int) -> int:
def pack_compact_validator(index: ValidatorIndex, slashed: bool, balance_in_increments: uint64) -> uint64:
"""
Creates a compact validator object representing index, slashed status, and compressed balance.
Create a compact validator object representing index, slashed status, and compressed balance.
Takes as input balance-in-increments (// EFFECTIVE_BALANCE_INCREMENT) to preserve symmetry with
the unpacking function.
"""
return (index << 16) + (slashed << 15) + balance_in_increments
```
#### `unpack_compact_validator`
```python
def unpack_compact_validator(compact_validator: uint64) -> Tuple[ValidatorIndex, bool, uint64]:
"""
Return validator index, slashed, balance // EFFECTIVE_BALANCE_INCREMENT
"""
return (
ValidatorIndex(compact_validator >> 16),
bool((compact_validator >> 15) % 2),
compact_validator & (2**15 - 1),
)
```
#### `committee_to_compact_committee`
```python
@ -404,6 +421,16 @@ def compute_shard_from_committee_index(state: BeaconState, index: CommitteeIndex
return Shard((index + get_start_shard(state, slot)) % active_shards)
```
#### `compute_offset_slots`
```python
def compute_offset_slots(start_slot: Slot, end_slot: Slot) -> Sequence[Slot]:
"""
Return the offset slots that are greater than ``start_slot`` and less than ``end_slot``.
"""
return [Slot(start_slot + x) for x in SHARD_BLOCK_OFFSETS if start_slot + x < end_slot]
```
### Beacon state accessors
#### `get_active_shard_count`
@ -495,23 +522,40 @@ def get_shard(state: BeaconState, attestation: Attestation) -> Shard:
return compute_shard_from_committee_index(state, attestation.data.index, attestation.data.slot)
```
#### `get_next_slot_for_shard`
#### `get_latest_slot_for_shard`
```python
def get_next_slot_for_shard(state: BeaconState, shard: Shard) -> Slot:
return Slot(state.shard_states[shard].slot + 1)
def get_latest_slot_for_shard(state: BeaconState, shard: Shard) -> Slot:
return state.shard_states[shard].slot
```
#### `get_offset_slots`
```python
def get_offset_slots(state: BeaconState, start_slot: Slot) -> Sequence[Slot]:
return [Slot(start_slot + x) for x in SHARD_BLOCK_OFFSETS if start_slot + x < state.slot]
def get_offset_slots(state: BeaconState, shard: Shard) -> Sequence[Slot]:
return compute_offset_slots(state.shard_states[shard].slot, state.slot)
```
### Predicates
#### `is_winning_attestation`
```python
def is_winning_attestation(state: BeaconState,
attestation: PendingAttestation,
committee_index: CommitteeIndex,
winning_root: Root) -> bool:
"""
Check if ``attestation`` helped contribute to the successful crosslink of
``winning_root`` formed by ``committee_index`` committee at the current slot.
"""
return (
attestation.slot == state.slot
and attestation.data.index == committee_index
and attestation.data.shard_transition_root == winning_root
)
```
#### Updated `is_valid_indexed_attestation`
Note that this replaces the Phase 0 `is_valid_indexed_attestation`.
@ -528,7 +572,7 @@ def is_valid_indexed_attestation(state: BeaconState, indexed_attestation: Indexe
domain = get_domain(state, DOMAIN_BEACON_ATTESTER, attestation.data.target.epoch)
aggregation_bits = attestation.aggregation_bits
assert len(aggregation_bits) == len(indexed_attestation.committee)
if len(attestation.custody_bits_blocks) == 0:
# fall back on phase0 behavior if there is no shard data.
for participant, abit in zip(indexed_attestation.committee, aggregation_bits):
@ -543,8 +587,12 @@ def is_valid_indexed_attestation(state: BeaconState, indexed_attestation: Indexe
if abit:
all_pubkeys.append(state.validators[participant].pubkey)
# Note: only 2N distinct message hashes
all_signing_roots.append(compute_signing_root(
AttestationCustodyBitWrapper(hash_tree_root(attestation.data), i, cbit), domain))
attestation_wrapper = AttestationCustodyBitWrapper(
attestation_data_root=hash_tree_root(attestation.data),
block_index=i,
bit=cbit
)
all_signing_roots.append(compute_signing_root(attestation_wrapper, domain))
else:
assert not cbit
return bls.AggregateVerify(zip(all_pubkeys, all_signing_roots), signature=attestation.signature)
@ -570,23 +618,23 @@ def process_block(state: BeaconState, block: BeaconBlock) -> None:
def process_operations(state: BeaconState, body: BeaconBlockBody) -> None:
# Verify that outstanding deposits are processed up to the maximum number of deposits
assert len(body.deposits) == min(MAX_DEPOSITS, state.eth1_data.deposit_count - state.eth1_deposit_index)
def for_ops(operations: Sequence[Any], fn: Callable[[BeaconState, Any], None]) -> None:
for operation in operations:
fn(state, operation)
for_ops(body.proposer_slashings, process_proposer_slashing)
for_ops(body.attester_slashings, process_attester_slashing)
# New attestation processing
process_attestations(state, body, body.attestations)
for_ops(body.attestations, process_attestation)
for_ops(body.deposits, process_deposit)
for_ops(body.voluntary_exits, process_voluntary_exit)
# See custody game spec.
process_custody_game_operations(state, body)
process_crosslinks(state, body.shard_transitions, body.attestations)
# TODO process_operations(body.shard_receipt_proofs, process_shard_receipt_proofs)
```
@ -600,6 +648,7 @@ def validate_attestation(state: BeaconState, attestation: Attestation) -> None:
assert data.index < get_committee_count_at_slot(state, data.slot)
assert data.index < get_active_shard_count(state)
assert data.target.epoch in (get_previous_epoch(state), get_current_epoch(state))
assert data.target.epoch == compute_epoch_at_slot(data.slot)
assert data.slot + MIN_ATTESTATION_INCLUSION_DELAY <= state.slot <= data.slot + SLOTS_PER_EPOCH
committee = get_beacon_committee(state, data.slot, data.index)
@ -611,40 +660,39 @@ def validate_attestation(state: BeaconState, attestation: Attestation) -> None:
assert attestation.data.source == state.previous_justified_checkpoint
shard = get_shard(state, attestation)
shard_start_slot = get_next_slot_for_shard(state, shard)
# Type 1: on-time attestations, the custody bits should be non-empty.
if attestation.custody_bits_blocks != []:
# Ensure on-time attestation
assert data.slot + MIN_ATTESTATION_INCLUSION_DELAY == state.slot
# Correct data root count
assert len(attestation.custody_bits_blocks) == len(get_offset_slots(state, shard))
# Correct parent block root
assert data.beacon_block_root == get_block_root_at_slot(state, get_previous_slot(state.slot))
# Type 2: no shard transition, no custody bits
else:
# Ensure delayed attestation
assert data.slot + MIN_ATTESTATION_INCLUSION_DELAY < state.slot
# Late attestations cannot have a shard transition root
assert data.shard_transition_root == Root()
# Signature check
assert is_valid_indexed_attestation(state, get_indexed_attestation(state, attestation))
# Type 1: on-time attestations
if attestation.custody_bits_blocks != []:
# Correct slot
assert data.slot + MIN_ATTESTATION_INCLUSION_DELAY == state.slot
# Correct data root count
assert len(attestation.custody_bits_blocks) == len(get_offset_slots(state, shard_start_slot))
# Correct parent block root
assert data.beacon_block_root == get_block_root_at_slot(state, get_previous_slot(state.slot))
# Type 2: no shard transition, no custody bits # TODO: could only allow for older attestations.
else:
# assert state.slot - compute_start_slot_at_epoch(compute_epoch_at_slot(data.slot)) < SLOTS_PER_EPOCH
assert data.shard_transition_root == Root()
```
###### `apply_shard_transition`
```python
def apply_shard_transition(state: BeaconState, shard: Shard, transition: ShardTransition) -> None:
# Slot the attestation starts counting from
start_slot = get_next_slot_for_shard(state, shard)
# Correct data root count
offset_slots = get_offset_slots(state, start_slot)
offset_slots = get_offset_slots(state, shard)
assert (
len(transition.shard_data_roots)
== len(transition.shard_states)
== len(transition.shard_block_lengths)
== len(offset_slots)
)
assert transition.start_slot == start_slot
assert transition.start_slot == offset_slots[0]
# Reconstruct shard headers
headers = []
@ -687,11 +735,12 @@ def apply_shard_transition(state: BeaconState, shard: Shard, transition: ShardTr
```python
def process_crosslink_for_shard(state: BeaconState,
shard: Shard,
committee_index: CommitteeIndex,
shard_transition: ShardTransition,
attestations: Sequence[Attestation]) -> Root:
committee = get_beacon_committee(state, get_current_epoch(state), shard)
committee = get_beacon_committee(state, state.slot, committee_index)
online_indices = get_online_validator_indices(state)
shard = compute_shard_from_committee_index(state, committee_index, state.slot)
# Loop over all shard transition roots
shard_transition_roots = set([a.data.shard_transition_root for a in attestations])
@ -723,7 +772,7 @@ def process_crosslink_for_shard(state: BeaconState,
increase_balance(state, beacon_proposer_index, proposer_reward)
states_slots_lengths = zip(
shard_transition.shard_states,
get_offset_slots(state, get_next_slot_for_shard(state, shard)),
get_offset_slots(state, get_latest_slot_for_shard(state, shard)),
shard_transition.shard_block_lengths
)
for shard_state, slot, length in states_slots_lengths:
@ -742,49 +791,42 @@ def process_crosslink_for_shard(state: BeaconState,
```python
def process_crosslinks(state: BeaconState,
block_body: BeaconBlockBody,
attestations: Sequence[Attestation]) -> Set[Tuple[Shard, Root]]:
winners: Set[Tuple[Shard, Root]] = set()
shard_transitions: Sequence[ShardTransition],
attestations: Sequence[Attestation]) -> None:
committee_count = get_committee_count_at_slot(state, state.slot)
for committee_index in map(CommitteeIndex, range(committee_count)):
shard = compute_shard_from_committee_index(state, committee_index, state.slot)
# All attestations in the block for this shard
# All attestations in the block for this committee/shard and current slot
shard_attestations = [
attestation for attestation in attestations
if get_shard(state, attestation) == shard and attestation.data.slot == state.slot
if attestation.data.index == committee_index and attestation.data.slot == state.slot
]
shard_transition = block_body.shard_transitions[shard]
winning_root = process_crosslink_for_shard(state, shard, shard_transition, shard_attestations)
shard_transition = shard_transitions[shard]
winning_root = process_crosslink_for_shard(state, committee_index, shard_transition, shard_attestations)
if winning_root != Root():
winners.add((shard, winning_root))
return winners
# Mark relevant pending attestations as creating a successful crosslink
for pending_attestation in state.current_epoch_attestations:
if is_winning_attestation(state, pending_attestation, committee_index, winning_root):
pending_attestation.crosslink_success = True
```
###### `process_attestations`
###### `process_attestation`
```python
def process_attestations(state: BeaconState, block_body: BeaconBlockBody, attestations: Sequence[Attestation]) -> None:
# Basic validation
for attestation in attestations:
validate_attestation(state, attestation)
# Process crosslinks
winners = process_crosslinks(state, block_body, attestations)
# Store pending attestations for epoch processing
for attestation in attestations:
is_winning_transition = (get_shard(state, attestation), attestation.data.shard_transition_root) in winners
pending_attestation = PendingAttestation(
aggregation_bits=attestation.aggregation_bits,
data=attestation.data,
inclusion_delay=state.slot - attestation.data.slot,
crosslink_success=is_winning_transition and attestation.data.slot == state.slot,
proposer_index=get_beacon_proposer_index(state),
)
if attestation.data.target.epoch == get_current_epoch(state):
state.current_epoch_attestations.append(pending_attestation)
else:
state.previous_epoch_attestations.append(pending_attestation)
def process_attestation(state: BeaconState, attestation: Attestation) -> None:
validate_attestation(state, attestation)
# Store pending attestation for epoch processing
pending_attestation = PendingAttestation(
aggregation_bits=attestation.aggregation_bits,
data=attestation.data,
inclusion_delay=state.slot - attestation.data.slot,
proposer_index=get_beacon_proposer_index(state),
crosslink_success=False, # To be filled in during process_crosslinks
)
if attestation.data.target.epoch == get_current_epoch(state):
state.current_epoch_attestations.append(pending_attestation)
else:
state.previous_epoch_attestations.append(pending_attestation)
```
##### New Attester slashing processing
@ -803,6 +845,7 @@ def get_indices_from_committee(
def process_attester_slashing(state: BeaconState, attester_slashing: AttesterSlashing) -> None:
indexed_attestation_1 = attester_slashing.attestation_1
indexed_attestation_2 = attester_slashing.attestation_2
assert is_slashable_attestation_data(
indexed_attestation_1.attestation.data,
indexed_attestation_2.attestation.data,
@ -856,7 +899,7 @@ def process_light_client_signatures(state: BeaconState, block_body: BeaconBlockB
slot = get_previous_slot(state.slot)
signing_root = compute_signing_root(get_block_root_at_slot(state, slot),
get_domain(state, DOMAIN_LIGHT_CLIENT, compute_epoch_at_slot(slot)))
return bls.FastAggregateVerify(signer_pubkeys, signing_root, signature=block_body.light_client_signature)
assert bls.FastAggregateVerify(signer_pubkeys, signing_root, signature=block_body.light_client_signature)
```

View File

@ -192,10 +192,10 @@ def get_custody_atoms(bytez: bytes) -> Sequence[bytes]:
def compute_custody_bit(key: BLSSignature, data: bytes) -> bit:
full_G2_element = bls.signature_to_G2(key)
s = full_G2_element[0].coeffs
bits = [legendre_bit(sum(s[i % 2]**i * int.from_bytes(atom, "little")), BLS12_381_Q)
for i, atom in enumerate(get_custody_atoms(data))]
# XOR all atom bits
return bit(sum(bits) % 2)
custody_atoms = get_custody_atoms(data)
n = len(custody_atoms)
a = sum(s[i % 2]**i * int.from_bytes(atom, "little") for i, atom in enumerate(custody_atoms) + s[n % 2]**n)
return legendre_bit(a, BLS12_381_Q)
```
### `get_randao_epoch_for_custody_period`
@ -416,7 +416,13 @@ def process_reveal_deadlines(state: BeaconState) -> None:
epoch = get_current_epoch(state)
for index, validator in enumerate(state.validators):
if get_custody_period_for_validator(ValidatorIndex(index), epoch) > validator.next_custody_secret_to_reveal:
slash_validator(state, ValidatorIndex(index))
# ------------------ WARNING ----------------------- #
# UNSAFE REMOVAL OF SLASHING TO PRIORITIZE PHASE 0 CI #
# Must find generic way to handle key reveals in tests #
# ---------------------------------------------------- #
# slash_validator(state, ValidatorIndex(index))
pass
```
### Final updates

View File

@ -36,7 +36,6 @@ Warning: this configuration is not definitive.
| - | - |
| `PHASE_1_FORK_VERSION` | `Version('0x01000000')` |
| `INITIAL_ACTIVE_SHARDS` | `2**6` (= 64) |
| `INITIAL_GASPRICE` | `Gwei(10)` |
## Fork to Phase 1
@ -102,7 +101,7 @@ def upgrade_to_phase1(pre: phase0.BeaconState) -> BeaconState:
shard_states=List[ShardState, MAX_SHARDS](
ShardState(
slot=pre.slot,
gasprice=INITIAL_GASPRICE,
gasprice=MIN_GASPRICE,
data=Root(),
latest_block_root=Root(),
) for i in range(INITIAL_ACTIVE_SHARDS)

View File

@ -1 +1 @@
0.11.1
0.11.2

View File

@ -8,13 +8,18 @@ config: Dict[str, Any] = {}
# Access to overwrite spec constants based on configuration
# This is called by the spec module after declaring its globals, and applies the loaded presets.
def apply_constants_config(spec_globals: Dict[str, Any]) -> None:
def apply_constants_config(spec_globals: Dict[str, Any], warn_if_unknown: bool = False) -> None:
global config
for k, v in config.items():
if k.startswith('DOMAIN_'):
spec_globals[k] = spec_globals['DomainType'](v) # domain types are defined as bytes in the configs
# the spec should have default values for everything, if not, the config key is invalid.
if k in spec_globals:
# Keep the same type as the default value indicates (which may be an SSZ basic type subclass, e.g. 'Gwei')
spec_globals[k] = spec_globals[k].__class__(v)
else:
spec_globals[k] = v
# Note: Phase 0 spec will not know the phase 1 config values.
# Yet, during debugging you can enable explicit warnings.
if warn_if_unknown:
print(f"WARNING: unknown config key: '{k}' with value: '{v}'")
# Load presets from a file, and then prepares the global config setting. This does not apply the config.
@ -36,7 +41,8 @@ def load_config_file(configs_dir, presets_name) -> Dict[str, Any]:
out = dict()
for k, v in loaded.items():
if isinstance(v, list):
out[k] = v
# Clean up integer values. YAML parser renders lists of ints as list of str
out[k] = [int(item) if item.isdigit() else item for item in v]
elif isinstance(v, str) and v.startswith("0x"):
out[k] = bytes.fromhex(v[2:])
else:

View File

@ -7,7 +7,7 @@ from .helpers.genesis import create_genesis_state
from .utils import vector_test, with_meta_tags
from random import Random
from typing import Any, Callable, Sequence, TypedDict, Protocol
from typing import Any, Callable, NewType, Sequence, TypedDict, Protocol
from importlib import reload
@ -19,25 +19,33 @@ def reload_specs():
# Some of the Spec module functionality is exposed here to deal with phase-specific changes.
SpecForkName = NewType("SpecForkName", str)
PHASE0 = SpecForkName('phase0')
PHASE1 = SpecForkName('phase1')
ALL_PHASES = (PHASE0, PHASE1)
# TODO: currently phases are defined as python modules.
# It would be better if they would be more well-defined interfaces for stronger typing.
class Spec(Protocol):
version: str
class Phase0(Spec):
class SpecPhase0(Spec):
...
class Phase1(Spec):
class SpecPhase1(Spec):
def upgrade_to_phase1(self, state: spec_phase0.BeaconState) -> spec_phase1.BeaconState:
...
# add transfer, bridge, etc. as the spec evolves
class SpecForks(TypedDict, total=False):
phase0: Phase0
phase1: Phase1
PHASE0: SpecPhase0
PHASE1: SpecPhase1
def with_custom_state(balances_fn: Callable[[Any], Sequence[int]],
@ -45,16 +53,19 @@ def with_custom_state(balances_fn: Callable[[Any], Sequence[int]],
def deco(fn):
def entry(*args, spec: Spec, phases: SpecForks, **kw):
try:
p0 = phases["phase0"]
p0 = phases[PHASE0]
balances = balances_fn(p0)
activation_threshold = threshold_fn(p0)
state = create_genesis_state(spec=p0, validator_balances=balances,
activation_threshold=activation_threshold)
if spec.fork == 'phase1':
if spec.fork == PHASE1:
# TODO: instead of upgrading a test phase0 genesis state we can also write a phase1 state helper.
# Decide based on performance/consistency results later.
state = phases["phase1"].upgrade_to_phase1(state)
state = phases[PHASE1].upgrade_to_phase1(state)
# Shard state slot must lag behind BeaconState slot by at least 1
# Will handle this more elegantly with fork mechanics
spec.process_slots(state, state.slot + 1)
kw['state'] = state
except KeyError:
@ -217,14 +228,11 @@ def bls_switch(fn):
return entry
all_phases = ['phase0', 'phase1']
def with_all_phases(fn):
"""
A decorator for running a test with every phase
"""
return with_phases(all_phases)(fn)
return with_phases(ALL_PHASES)(fn)
def with_all_phases_except(exclusion_phases):
@ -232,7 +240,7 @@ def with_all_phases_except(exclusion_phases):
A decorator factory for running a tests with every phase except the ones listed
"""
def decorator(fn):
return with_phases([phase for phase in all_phases if phase not in exclusion_phases])(fn)
return with_phases([phase for phase in ALL_PHASES if phase not in exclusion_phases])(fn)
return decorator
@ -258,18 +266,18 @@ def with_phases(phases, other_phases=None):
# TODO: test state is dependent on phase0 but is immediately transitioned to phase1.
# A new state-creation helper for phase 1 may be in place, and then phase1+ tests can run without phase0
available_phases.add('phase0')
available_phases.add(PHASE0)
phase_dir = {}
if 'phase0' in available_phases:
phase_dir['phase0'] = spec_phase0
if 'phase1' in available_phases:
phase_dir['phase1'] = spec_phase1
if PHASE0 in available_phases:
phase_dir[PHASE0] = spec_phase0
if PHASE1 in available_phases:
phase_dir[PHASE1] = spec_phase1
# return is ignored whenever multiple phases are ran. If
if 'phase0' in run_phases:
if PHASE0 in run_phases:
ret = fn(spec=spec_phase0, phases=phase_dir, *args, **kw)
if 'phase1' in run_phases:
if PHASE1 in run_phases:
ret = fn(spec=spec_phase1, phases=phase_dir, *args, **kw)
return ret
return wrapper

View File

@ -1,9 +1,8 @@
from eth2spec.test.context import with_all_phases, spec_state_test
from eth2spec.test.helpers.attestations import get_valid_attestation
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.state import (
next_epoch,
next_epoch_with_attestations,
state_transition_and_sign_block,
)

View File

@ -1,7 +1,7 @@
from eth2spec.test.context import with_all_phases, spec_state_test
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
from eth2spec.test.helpers.state import transition_to, state_transition_and_sign_block, next_epoch
def run_on_attestation(spec, state, store, attestation, valid=True):
@ -16,7 +16,7 @@ def run_on_attestation(spec, state, store, attestation, valid=True):
indexed_attestation = spec.get_indexed_attestation(state, attestation)
spec.on_attestation(store, attestation)
if spec.fork == 'phase0':
if spec.fork == PHASE0:
sample_index = indexed_attestation.attesting_indices[0]
else:
attesting_indices = [
@ -120,11 +120,12 @@ def test_on_attestation_mismatched_target_and_slot(spec, state):
@spec_state_test
def test_on_attestation_target_not_in_store(spec, state):
store = spec.get_forkchoice_store(state)
time = spec.SECONDS_PER_SLOT * spec.SLOTS_PER_EPOCH
time = store.time + spec.SECONDS_PER_SLOT * spec.SLOTS_PER_EPOCH
spec.on_tick(store, time)
# move to immediately before next epoch to make block new target
transition_to(spec, state, state.slot + spec.SLOTS_PER_EPOCH - 1)
next_epoch = spec.get_current_epoch(state) + 1
transition_to(spec, state, spec.compute_start_slot_at_epoch(next_epoch) - 1)
target_block = build_empty_block_for_next_slot(spec, state)
state_transition_and_sign_block(spec, state, target_block)
@ -141,11 +142,12 @@ def test_on_attestation_target_not_in_store(spec, state):
@spec_state_test
def test_on_attestation_beacon_block_not_in_store(spec, state):
store = spec.get_forkchoice_store(state)
time = spec.SECONDS_PER_SLOT * spec.SLOTS_PER_EPOCH
time = store.time + spec.SECONDS_PER_SLOT * spec.SLOTS_PER_EPOCH
spec.on_tick(store, time)
# move to immediately before next epoch to make block new target
transition_to(spec, state, state.slot + spec.SLOTS_PER_EPOCH - 1)
next_epoch = spec.get_current_epoch(state) + 1
transition_to(spec, state, spec.compute_start_slot_at_epoch(next_epoch) - 1)
target_block = build_empty_block_for_next_slot(spec, state)
signed_target_block = state_transition_and_sign_block(spec, state, target_block)
@ -169,7 +171,7 @@ def test_on_attestation_beacon_block_not_in_store(spec, state):
@spec_state_test
def test_on_attestation_future_epoch(spec, state):
store = spec.get_forkchoice_store(state)
time = 3 * spec.SECONDS_PER_SLOT
time = store.time + 3 * spec.SECONDS_PER_SLOT
spec.on_tick(store, time)
block = build_empty_block_for_next_slot(spec, state)
@ -179,7 +181,7 @@ def test_on_attestation_future_epoch(spec, state):
spec.on_block(store, signed_block)
# move state forward but not store
state.slot = block.slot + spec.SLOTS_PER_EPOCH
next_epoch(spec, state)
attestation = get_valid_attestation(spec, state, slot=state.slot, signed=True)
run_on_attestation(spec, state, store, attestation, False)
@ -189,7 +191,7 @@ def test_on_attestation_future_epoch(spec, state):
@spec_state_test
def test_on_attestation_future_block(spec, state):
store = spec.get_forkchoice_store(state)
time = spec.SECONDS_PER_SLOT * 5
time = store.time + spec.SECONDS_PER_SLOT * 5
spec.on_tick(store, time)
block = build_empty_block_for_next_slot(spec, state)
@ -209,7 +211,7 @@ def test_on_attestation_future_block(spec, state):
@spec_state_test
def test_on_attestation_same_slot(spec, state):
store = spec.get_forkchoice_store(state)
time = 1 * spec.SECONDS_PER_SLOT
time = store.time + spec.SECONDS_PER_SLOT
spec.on_tick(store, time)
block = build_empty_block_for_next_slot(spec, state)
@ -225,7 +227,7 @@ def test_on_attestation_same_slot(spec, state):
@spec_state_test
def test_on_attestation_invalid_attestation(spec, state):
store = spec.get_forkchoice_store(state)
time = 3 * spec.SECONDS_PER_SLOT
time = store.time + 3 * spec.SECONDS_PER_SLOT
spec.on_tick(store, time)
block = build_empty_block_for_next_slot(spec, state)

View File

@ -4,7 +4,8 @@ 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.block import build_empty_block_for_next_slot, sign_block, transition_unsigned_block, \
build_empty_block
from eth2spec.test.helpers.state import next_epoch, next_epoch_with_attestations, state_transition_and_sign_block
from eth2spec.test.helpers.attestations import next_epoch_with_attestations
from eth2spec.test.helpers.state import next_epoch, state_transition_and_sign_block
def run_on_block(spec, store, signed_block, valid=True):
@ -159,6 +160,7 @@ 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)
store.finalized_checkpoint = spec.Checkpoint(

View File

@ -27,14 +27,16 @@ def test_basic(spec, state):
@spec_state_test
def test_update_justified_single(spec, state):
store = spec.get_forkchoice_store(state)
seconds_per_epoch = spec.SECONDS_PER_SLOT * spec.SLOTS_PER_EPOCH
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
store.best_justified_checkpoint = spec.Checkpoint(
epoch=store.justified_checkpoint.epoch + 1,
root=b'\x55' * 32,
)
run_on_tick(spec, store, store.time + seconds_per_epoch, True)
run_on_tick(spec, store, store.time + seconds_until_next_epoch, True)
@with_all_phases

View File

@ -1,10 +1,10 @@
from eth2spec.test.context import spec_test, with_phases, single_phase
from eth2spec.test.context import PHASE0, spec_test, with_phases, single_phase
from eth2spec.test.helpers.deposits import (
prepare_genesis_deposits,
)
@with_phases(['phase0'])
@with_phases(([PHASE0]))
@spec_test
@single_phase
def test_initialize_beacon_state_from_eth1(spec):
@ -32,7 +32,7 @@ def test_initialize_beacon_state_from_eth1(spec):
yield 'state', state
@with_phases(['phase0'])
@with_phases([PHASE0])
@spec_test
@single_phase
def test_initialize_beacon_state_some_small_balances(spec):

View File

@ -1,4 +1,4 @@
from eth2spec.test.context import spec_test, with_phases, single_phase
from eth2spec.test.context import PHASE0, spec_test, with_phases, single_phase
from eth2spec.test.helpers.deposits import (
prepare_genesis_deposits,
)
@ -25,7 +25,7 @@ def run_is_valid_genesis_state(spec, state, valid=True):
assert is_valid == valid
@with_phases(['phase0'])
@with_phases([PHASE0])
@spec_test
@single_phase
def test_is_valid_genesis_state_true(spec):
@ -34,7 +34,7 @@ def test_is_valid_genesis_state_true(spec):
yield from run_is_valid_genesis_state(spec, state, valid=True)
@with_phases(['phase0'])
@with_phases([PHASE0])
@spec_test
@single_phase
def test_is_valid_genesis_state_false_invalid_timestamp(spec):
@ -44,7 +44,7 @@ def test_is_valid_genesis_state_false_invalid_timestamp(spec):
yield from run_is_valid_genesis_state(spec, state, valid=False)
@with_phases(['phase0'])
@with_phases([PHASE0])
@spec_test
@single_phase
def test_is_valid_genesis_state_true_more_balance(spec):
@ -55,7 +55,7 @@ def test_is_valid_genesis_state_true_more_balance(spec):
# TODO: not part of the genesis function yet. Erroneously merged.
# @with_phases(['phase0'])
# @with_phases([PHASE0])
# @spec_test
# def test_is_valid_genesis_state_false_not_enough_balance(spec):
# state = create_valid_beacon_state(spec)
@ -64,7 +64,7 @@ def test_is_valid_genesis_state_true_more_balance(spec):
# yield from run_is_valid_genesis_state(spec, state, valid=False)
@with_phases(['phase0'])
@with_phases([PHASE0])
@spec_test
@single_phase
def test_is_valid_genesis_state_true_one_more_validator(spec):
@ -78,7 +78,7 @@ def test_is_valid_genesis_state_true_one_more_validator(spec):
yield from run_is_valid_genesis_state(spec, state, valid=True)
@with_phases(['phase0'])
@with_phases([PHASE0])
@spec_test
@single_phase
def test_is_valid_genesis_state_false_not_enough_validator(spec):

View File

@ -1,12 +1,48 @@
from typing import List
from eth2spec.test.helpers.block import build_empty_block_for_next_slot, transition_unsigned_block, \
build_empty_block
from eth2spec.test.context import expect_assertion_error, PHASE0
from eth2spec.test.helpers.state import state_transition_and_sign_block
from eth2spec.test.helpers.block import build_empty_block_for_next_slot
from eth2spec.test.helpers.keys import privkeys
from eth2spec.utils import bls
from eth2spec.utils.ssz.ssz_typing import Bitlist
def run_attestation_processing(spec, state, attestation, valid=True):
"""
Run ``process_attestation``, yielding:
- pre-state ('pre')
- attestation ('attestation')
- post-state ('post').
If ``valid == False``, run expecting ``AssertionError``
"""
# yield pre-state
yield 'pre', state
yield 'attestation', attestation
# If the attestation is invalid, processing is aborted, and there is no post-state.
if not valid:
expect_assertion_error(lambda: spec.process_attestation(state, attestation))
yield 'post', None
return
current_epoch_count = len(state.current_epoch_attestations)
previous_epoch_count = len(state.previous_epoch_attestations)
# process attestation
spec.process_attestation(state, attestation)
# Make sure the attestation has been processed
if attestation.data.target.epoch == spec.get_current_epoch(state):
assert len(state.current_epoch_attestations) == current_epoch_count + 1
else:
assert len(state.previous_epoch_attestations) == previous_epoch_count + 1
# yield post-state
yield 'post', state
def build_attestation_data(spec, state, slot, index):
assert state.slot >= slot
@ -39,7 +75,45 @@ def build_attestation_data(spec, state, slot, index):
)
def get_valid_attestation(spec, state, slot=None, index=None, empty=False, signed=False):
def convert_to_valid_on_time_attestation(spec, state, attestation, signed=False):
shard = spec.get_shard(state, attestation)
offset_slots = spec.compute_offset_slots(spec.get_latest_slot_for_shard(state, shard), state.slot + 1)
for offset_slot in offset_slots:
attestation.custody_bits_blocks.append(
Bitlist[spec.MAX_VALIDATORS_PER_COMMITTEE]([0 for _ in attestation.aggregation_bits])
)
if signed:
sign_attestation(spec, state, attestation)
return attestation
def get_valid_on_time_attestation(spec, state, slot=None, index=None, signed=False):
'''
Construct on-time attestation for next slot
'''
if slot is None:
slot = state.slot
if index is None:
index = 0
return get_valid_attestation(spec, state, slot=slot, index=index, signed=signed, on_time=True)
def get_valid_late_attestation(spec, state, slot=None, index=None, signed=False):
'''
Construct on-time attestation for next slot
'''
if slot is None:
slot = state.slot
if index is None:
index = 0
return get_valid_attestation(spec, state, slot=slot, index=index, signed=signed, on_time=False)
def get_valid_attestation(spec, state, slot=None, index=None, empty=False, signed=False, on_time=True):
if slot is None:
slot = state.slot
if index is None:
@ -63,6 +137,10 @@ def get_valid_attestation(spec, state, slot=None, index=None, empty=False, signe
fill_aggregate_attestation(spec, state, attestation)
if signed:
sign_attestation(spec, state, attestation)
if spec.fork == 'phase1' and on_time:
attestation = convert_to_valid_on_time_attestation(spec, state, attestation, signed)
return attestation
@ -78,12 +156,11 @@ def sign_aggregate_attestation(spec, state, attestation_data, participants: List
privkey
)
)
# TODO: we should try signing custody bits if spec.fork == 'phase1'
return bls.Aggregate(signatures)
def sign_indexed_attestation(spec, state, indexed_attestation):
if spec.fork == 'phase0':
if spec.fork == PHASE0:
participants = indexed_attestation.attesting_indices
data = indexed_attestation.data
indexed_attestation.signature = sign_aggregate_attestation(spec, state, data, participants)
@ -96,7 +173,47 @@ def sign_indexed_attestation(spec, state, indexed_attestation):
indexed_attestation.attestation.signature = sign_aggregate_attestation(spec, state, data, participants)
def sign_on_time_attestation(spec, state, attestation):
if not any(attestation.custody_bits_blocks):
sign_attestation(spec, state, attestation)
return
committee = spec.get_beacon_committee(state, attestation.data.slot, attestation.data.index)
signatures = []
for block_index, custody_bits in enumerate(attestation.custody_bits_blocks):
for participant, abit, cbit in zip(committee, attestation.aggregation_bits, custody_bits):
if not abit:
continue
signatures.append(get_attestation_custody_signature(
spec,
state,
attestation.data,
block_index,
cbit,
privkeys[participant]
))
attestation.signature = bls.Aggregate(signatures)
def get_attestation_custody_signature(spec, state, attestation_data, block_index, bit, privkey):
domain = spec.get_domain(state, spec.DOMAIN_BEACON_ATTESTER, attestation_data.target.epoch)
signing_root = spec.compute_signing_root(
spec.AttestationCustodyBitWrapper(
attestation_data_root=attestation_data.hash_tree_root(),
block_index=block_index,
bit=bit,
),
domain,
)
return bls.Sign(privkey, signing_root)
def sign_attestation(spec, state, attestation):
if spec.fork == 'phase1' and any(attestation.custody_bits_blocks):
sign_on_time_attestation(spec, state, attestation)
return
participants = spec.get_attesting_indices(
state,
attestation.data,
@ -113,7 +230,6 @@ def get_attestation_signature(spec, state, attestation_data, privkey):
def fill_aggregate_attestation(spec, state, attestation, signed=False):
beacon_committee = spec.get_beacon_committee(
state,
attestation.data.slot,
@ -127,8 +243,38 @@ def fill_aggregate_attestation(spec, state, attestation, signed=False):
def add_attestations_to_state(spec, state, attestations, slot):
block = build_empty_block(spec, state, slot)
spec.process_slots(state, slot)
for attestation in attestations:
block.body.attestations.append(attestation)
spec.process_slots(state, block.slot)
transition_unsigned_block(spec, state, block)
spec.process_attestation(state, attestation)
def next_epoch_with_attestations(spec,
state,
fill_cur_epoch,
fill_prev_epoch):
assert state.slot % spec.SLOTS_PER_EPOCH == 0
post_state = state.copy()
signed_blocks = []
for _ in range(spec.SLOTS_PER_EPOCH):
block = build_empty_block_for_next_slot(spec, post_state)
if fill_cur_epoch and post_state.slot >= spec.MIN_ATTESTATION_INCLUSION_DELAY:
slot_to_attest = post_state.slot - spec.MIN_ATTESTATION_INCLUSION_DELAY + 1
committees_per_slot = spec.get_committee_count_at_slot(state, slot_to_attest)
if slot_to_attest >= spec.compute_start_slot_at_epoch(spec.get_current_epoch(post_state)):
for index in range(committees_per_slot):
cur_attestation = get_valid_attestation(spec, post_state, slot_to_attest, index=index, signed=True)
block.body.attestations.append(cur_attestation)
if fill_prev_epoch:
slot_to_attest = post_state.slot - spec.SLOTS_PER_EPOCH + 1
committees_per_slot = spec.get_committee_count_at_slot(state, slot_to_attest)
for index in range(committees_per_slot):
prev_attestation = get_valid_attestation(
spec, post_state, slot_to_attest, index=index, signed=True, on_time=False)
block.body.attestations.append(prev_attestation)
signed_block = state_transition_and_sign_block(spec, post_state, block)
signed_blocks.append(signed_block)
return state, signed_blocks, post_state

View File

@ -1,3 +1,4 @@
from eth2spec.test.context import PHASE1
from eth2spec.test.helpers.attestations import get_valid_attestation, sign_attestation
@ -20,7 +21,7 @@ def get_indexed_attestation_participants(spec, indexed_att):
"""
Wrapper around index-attestation to return the list of participant indices, regardless of spec phase.
"""
if spec.fork == "phase1":
if spec.fork == PHASE1:
return list(spec.get_indices_from_committee(
indexed_att.committee,
indexed_att.attestation.aggregation_bits,
@ -33,21 +34,21 @@ def set_indexed_attestation_participants(spec, indexed_att, participants):
"""
Wrapper around index-attestation to return the list of participant indices, regardless of spec phase.
"""
if spec.fork == "phase1":
if spec.fork == PHASE1:
indexed_att.attestation.aggregation_bits = [bool(i in participants) for i in indexed_att.committee]
else:
indexed_att.attesting_indices = participants
def get_attestation_1_data(spec, att_slashing):
if spec.fork == "phase1":
if spec.fork == PHASE1:
return att_slashing.attestation_1.attestation.data
else:
return att_slashing.attestation_1.data
def get_attestation_2_data(spec, att_slashing):
if spec.fork == "phase1":
if spec.fork == PHASE1:
return att_slashing.attestation_2.attestation.data
else:
return att_slashing.attestation_2.data

View File

@ -1,6 +1,6 @@
from py_ecc.bls import G2ProofOfPossession as bls
from eth2spec.phase0 import spec
privkeys = [i + 1 for i in range(spec.SLOTS_PER_EPOCH * 16)]
privkeys = [i + 1 for i in range(spec.SLOTS_PER_EPOCH * 256)]
pubkeys = [bls.PrivToPub(privkey) for privkey in privkeys]
pubkey_to_privkey = {pubkey: privkey for privkey, pubkey in zip(privkeys, pubkeys)}

View File

@ -1,30 +1,63 @@
from eth2spec.test.helpers.keys import privkeys
from eth2spec.utils.ssz.ssz_typing import Bitlist
from eth2spec.utils import bls
from eth2spec.test.helpers.keys import privkeys
import eth2spec.test.helpers.attestations as phase0_attestations
def sign_shard_attestation(spec, beacon_state, shard_state, block, participants):
signatures = []
message_hash = spec.ShardAttestationData(
slot=block.slot,
parent_root=block.parent_root,
).hash_tree_root()
block_epoch = spec.compute_epoch_of_shard_slot(block.slot)
for validator_index in participants:
privkey = privkeys[validator_index]
signatures.append(
get_attestation_signature(
spec,
beacon_state,
shard_state,
message_hash,
block_epoch,
privkey,
)
def get_valid_on_time_attestation(spec, state, index=None, signed=False):
'''
Construct on-time attestation for next slot
'''
if index is None:
index = 0
attestation = phase0_attestations.get_valid_attestation(spec, state, state.slot, index, False)
shard = spec.get_shard(state, attestation)
offset_slots = spec.compute_offset_slots(spec.get_latest_slot_for_shard(state, shard), state.slot + 1)
for _ in offset_slots:
attestation.custody_bits_blocks.append(
Bitlist[spec.MAX_VALIDATORS_PER_COMMITTEE]([0 for _ in attestation.aggregation_bits])
)
return bls.Aggregate(signatures)
if signed:
sign_attestation(spec, state, attestation)
return attestation
def get_attestation_signature(spec, beacon_state, shard_state, message_hash, block_epoch, privkey):
domain = spec.get_domain(beacon_state, spec.DOMAIN_SHARD_ATTESTER, block_epoch)
signing_root = spec.compute_signing_root(message_hash, domain)
def sign_attestation(spec, state, attestation):
if not any(attestation.custody_bits_blocks):
phase0_attestations.sign_attestation(spec, state, attestation)
return
committee = spec.get_beacon_committee(state, attestation.data.slot, attestation.data.index)
signatures = []
for block_index, custody_bits in enumerate(attestation.custody_bits_blocks):
for participant, abit, cbit in zip(committee, attestation.aggregation_bits, custody_bits):
if not abit:
continue
signatures.append(get_attestation_custody_signature(
spec,
state,
attestation.data,
block_index,
cbit,
privkeys[participant]
))
attestation.signature = bls.Aggregate(signatures)
def get_attestation_custody_signature(spec, state, attestation_data, block_index, bit, privkey):
domain = spec.get_domain(state, spec.DOMAIN_BEACON_ATTESTER, attestation_data.target.epoch)
signing_root = spec.compute_signing_root(
spec.AttestationCustodyBitWrapper(
attestation_data.hash_tree_root(),
block_index,
bit,
),
domain,
)
return bls.Sign(privkey, signing_root)

View File

@ -1,6 +1,5 @@
from eth2spec.test.context import expect_assertion_error
from eth2spec.test.helpers.attestations import get_valid_attestation
from eth2spec.test.helpers.block import sign_block, build_empty_block_for_next_slot, transition_unsigned_block
from eth2spec.test.helpers.block import sign_block, transition_unsigned_block
def get_balance(state, index):
@ -14,6 +13,13 @@ def next_slot(spec, state):
spec.process_slots(state, state.slot + 1)
def next_slots(spec, state, slots):
"""
Transition given slots forward.
"""
spec.process_slots(state, state.slot + slots)
def transition_to(spec, state, slot):
"""
Transition to ``slot``.
@ -51,34 +57,3 @@ def state_transition_and_sign_block(spec, state, block, expect_fail=False):
transition_unsigned_block(spec, state, block)
block.state_root = state.hash_tree_root()
return sign_block(spec, state, block)
def next_epoch_with_attestations(spec,
state,
fill_cur_epoch,
fill_prev_epoch):
assert state.slot % spec.SLOTS_PER_EPOCH == 0
post_state = state.copy()
signed_blocks = []
for _ in range(spec.SLOTS_PER_EPOCH):
block = build_empty_block_for_next_slot(spec, post_state)
if fill_cur_epoch and post_state.slot >= spec.MIN_ATTESTATION_INCLUSION_DELAY:
slot_to_attest = post_state.slot - spec.MIN_ATTESTATION_INCLUSION_DELAY + 1
committees_per_slot = spec.get_committee_count_at_slot(state, slot_to_attest)
if slot_to_attest >= spec.compute_start_slot_at_epoch(spec.get_current_epoch(post_state)):
for index in range(committees_per_slot):
cur_attestation = get_valid_attestation(spec, post_state, slot_to_attest, index=index, signed=True)
block.body.attestations.append(cur_attestation)
if fill_prev_epoch:
slot_to_attest = post_state.slot - spec.SLOTS_PER_EPOCH + 1
committees_per_slot = spec.get_committee_count_at_slot(state, slot_to_attest)
for index in range(committees_per_slot):
prev_attestation = get_valid_attestation(spec, post_state, slot_to_attest, index=index, signed=True)
block.body.attestations.append(prev_attestation)
signed_block = state_transition_and_sign_block(spec, post_state, block)
signed_blocks.append(signed_block)
return state, signed_blocks, post_state

View File

@ -1,6 +1,5 @@
from eth2spec.test.context import (
spec_state_test,
expect_assertion_error,
always_bls, never_bls,
with_all_phases,
spec_test,
@ -8,57 +7,26 @@ from eth2spec.test.context import (
with_custom_state,
single_phase)
from eth2spec.test.helpers.attestations import (
run_attestation_processing,
get_valid_attestation,
sign_aggregate_attestation,
sign_attestation,
)
from eth2spec.test.helpers.state import (
next_slot,
next_slots,
next_epoch,
transition_to,
)
from eth2spec.test.helpers.block import apply_empty_block
from eth2spec.utils.ssz.ssz_typing import Bitlist
def run_attestation_processing(spec, state, attestation, valid=True):
"""
Run ``process_attestation``, yielding:
- pre-state ('pre')
- attestation ('attestation')
- post-state ('post').
If ``valid == False``, run expecting ``AssertionError``
"""
# yield pre-state
yield 'pre', state
yield 'attestation', attestation
# If the attestation is invalid, processing is aborted, and there is no post-state.
if not valid:
expect_assertion_error(lambda: spec.process_attestation(state, attestation))
yield 'post', None
return
current_epoch_count = len(state.current_epoch_attestations)
previous_epoch_count = len(state.previous_epoch_attestations)
# process attestation
spec.process_attestation(state, attestation)
# Make sure the attestation has been processed
if attestation.data.target.epoch == spec.get_current_epoch(state):
assert len(state.current_epoch_attestations) == current_epoch_count + 1
else:
assert len(state.previous_epoch_attestations) == previous_epoch_count + 1
# yield post-state
yield 'post', state
@with_all_phases
@spec_state_test
def test_success(spec, state):
attestation = get_valid_attestation(spec, state, signed=True)
state.slot += spec.MIN_ATTESTATION_INCLUSION_DELAY
next_slots(spec, state, spec.MIN_ATTESTATION_INCLUSION_DELAY)
yield from run_attestation_processing(spec, state, attestation)
@ -68,9 +36,9 @@ def test_success(spec, state):
@with_custom_state(balances_fn=low_balances, threshold_fn=lambda spec: spec.EJECTION_BALANCE)
@single_phase
def test_success_multi_proposer_index_iterations(spec, state):
state.slot += spec.SLOTS_PER_EPOCH * 2
next_slots(spec, state, spec.SLOTS_PER_EPOCH * 2)
attestation = get_valid_attestation(spec, state, signed=True)
state.slot += spec.MIN_ATTESTATION_INCLUSION_DELAY
next_slots(spec, state, spec.MIN_ATTESTATION_INCLUSION_DELAY)
yield from run_attestation_processing(spec, state, attestation)
@ -78,8 +46,8 @@ def test_success_multi_proposer_index_iterations(spec, state):
@with_all_phases
@spec_state_test
def test_success_previous_epoch(spec, state):
attestation = get_valid_attestation(spec, state, signed=True)
state.slot = spec.SLOTS_PER_EPOCH - 1
attestation = get_valid_attestation(spec, state, signed=True, on_time=False)
transition_to(spec, state, spec.SLOTS_PER_EPOCH - 1)
next_epoch(spec, state)
apply_empty_block(spec, state)
@ -91,7 +59,7 @@ def test_success_previous_epoch(spec, state):
@always_bls
def test_invalid_attestation_signature(spec, state):
attestation = get_valid_attestation(spec, state)
state.slot += spec.MIN_ATTESTATION_INCLUSION_DELAY
next_slots(spec, state, spec.MIN_ATTESTATION_INCLUSION_DELAY)
yield from run_attestation_processing(spec, state, attestation, False)
@ -108,10 +76,10 @@ def test_before_inclusion_delay(spec, state):
@with_all_phases
@spec_state_test
def test_after_epoch_slots(spec, state):
attestation = get_valid_attestation(spec, state, signed=True)
state.slot = spec.SLOTS_PER_EPOCH - 1
attestation = get_valid_attestation(spec, state, signed=True, on_time=False)
# increment past latest inclusion slot
spec.process_slots(state, state.slot + 2)
transition_to(spec, state, state.slot + spec.SLOTS_PER_EPOCH + 1)
apply_empty_block(spec, state)
yield from run_attestation_processing(spec, state, attestation, False)
@ -120,7 +88,7 @@ def test_after_epoch_slots(spec, state):
@with_all_phases
@spec_state_test
def test_old_source_epoch(spec, state):
state.slot = spec.SLOTS_PER_EPOCH * 5
next_slots(spec, state, spec.SLOTS_PER_EPOCH * 5)
state.finalized_checkpoint.epoch = 2
state.previous_justified_checkpoint.epoch = 3
state.current_justified_checkpoint.epoch = 4
@ -142,7 +110,7 @@ def test_old_source_epoch(spec, state):
@always_bls
def test_wrong_index_for_committee_signature(spec, state):
attestation = get_valid_attestation(spec, state)
state.slot += spec.MIN_ATTESTATION_INCLUSION_DELAY
next_slots(spec, state, spec.MIN_ATTESTATION_INCLUSION_DELAY)
attestation.data.index += 1
@ -153,12 +121,14 @@ def test_wrong_index_for_committee_signature(spec, state):
@spec_state_test
@never_bls
def test_wrong_index_for_slot(spec, state):
committees_per_slot = spec.get_committee_count_at_slot(state, state.slot)
assert committees_per_slot < spec.MAX_COMMITTEES_PER_SLOT
index = committees_per_slot
while spec.get_committee_count_at_slot(state, state.slot) >= spec.MAX_COMMITTEES_PER_SLOT:
state.validators = state.validators[:len(state.validators) // 2]
state.balances = state.balances[:len(state.balances) // 2]
index = spec.MAX_COMMITTEES_PER_SLOT - 1
attestation = get_valid_attestation(spec, state)
state.slot += spec.MIN_ATTESTATION_INCLUSION_DELAY
next_slots(spec, state, spec.MIN_ATTESTATION_INCLUSION_DELAY)
attestation.data.index = index
@ -170,7 +140,7 @@ def test_wrong_index_for_slot(spec, state):
@never_bls
def test_invalid_index(spec, state):
attestation = get_valid_attestation(spec, state)
state.slot += spec.MIN_ATTESTATION_INCLUSION_DELAY
next_slots(spec, state, spec.MIN_ATTESTATION_INCLUSION_DELAY)
# off by one (with respect to valid range) on purpose
attestation.data.index = spec.MAX_COMMITTEES_PER_SLOT
@ -184,7 +154,7 @@ def test_mismatched_target_and_slot(spec, state):
next_epoch(spec, state)
next_epoch(spec, state)
attestation = get_valid_attestation(spec, state)
attestation = get_valid_attestation(spec, state, on_time=False)
attestation.data.slot = attestation.data.slot - spec.SLOTS_PER_EPOCH
sign_attestation(spec, state, attestation)
@ -197,9 +167,9 @@ def test_mismatched_target_and_slot(spec, state):
def test_old_target_epoch(spec, state):
assert spec.MIN_ATTESTATION_INCLUSION_DELAY < spec.SLOTS_PER_EPOCH * 2
attestation = get_valid_attestation(spec, state, signed=True)
attestation = get_valid_attestation(spec, state, signed=True, on_time=False)
state.slot = spec.SLOTS_PER_EPOCH * 2 # target epoch will be too old to handle
next_slots(spec, state, spec.SLOTS_PER_EPOCH * 2) # target epoch will be too old to handle
yield from run_attestation_processing(spec, state, attestation, False)
@ -221,7 +191,7 @@ def test_future_target_epoch(spec, state):
# manually add signature for correct participants
attestation.signature = sign_aggregate_attestation(spec, state, attestation.data, participants)
state.slot += spec.MIN_ATTESTATION_INCLUSION_DELAY
next_slots(spec, state, spec.MIN_ATTESTATION_INCLUSION_DELAY)
yield from run_attestation_processing(spec, state, attestation, False)
@ -230,7 +200,7 @@ def test_future_target_epoch(spec, state):
@spec_state_test
def test_new_source_epoch(spec, state):
attestation = get_valid_attestation(spec, state)
state.slot += spec.MIN_ATTESTATION_INCLUSION_DELAY
next_slots(spec, state, spec.MIN_ATTESTATION_INCLUSION_DELAY)
attestation.data.source.epoch += 1
@ -243,7 +213,7 @@ def test_new_source_epoch(spec, state):
@spec_state_test
def test_source_root_is_target_root(spec, state):
attestation = get_valid_attestation(spec, state)
state.slot += spec.MIN_ATTESTATION_INCLUSION_DELAY
next_slots(spec, state, spec.MIN_ATTESTATION_INCLUSION_DELAY)
attestation.data.source.root = attestation.data.target.root
@ -255,14 +225,15 @@ def test_source_root_is_target_root(spec, state):
@with_all_phases
@spec_state_test
def test_invalid_current_source_root(spec, state):
state.slot = spec.SLOTS_PER_EPOCH * 5
next_slots(spec, state, spec.SLOTS_PER_EPOCH * 5)
state.finalized_checkpoint.epoch = 2
state.previous_justified_checkpoint = spec.Checkpoint(epoch=3, root=b'\x01' * 32)
state.current_justified_checkpoint = spec.Checkpoint(epoch=4, root=b'\x32' * 32)
attestation = get_valid_attestation(spec, state, slot=(spec.SLOTS_PER_EPOCH * 3) + 1)
state.slot += spec.MIN_ATTESTATION_INCLUSION_DELAY
attestation = get_valid_attestation(spec, state, slot=(spec.SLOTS_PER_EPOCH * 3) + 1, on_time=False)
next_slots(spec, state, spec.MIN_ATTESTATION_INCLUSION_DELAY)
# Test logic sanity checks:
assert state.current_justified_checkpoint.root != state.previous_justified_checkpoint.root
@ -280,7 +251,7 @@ def test_invalid_current_source_root(spec, state):
@spec_state_test
def test_bad_source_root(spec, state):
attestation = get_valid_attestation(spec, state)
state.slot += spec.MIN_ATTESTATION_INCLUSION_DELAY
next_slots(spec, state, spec.MIN_ATTESTATION_INCLUSION_DELAY)
attestation.data.source.root = b'\x42' * 32
@ -292,8 +263,9 @@ def test_bad_source_root(spec, state):
@with_all_phases
@spec_state_test
def test_empty_aggregation_bits(spec, state):
next_slot(spec, state)
attestation = get_valid_attestation(spec, state, empty=True)
state.slot += spec.MIN_ATTESTATION_INCLUSION_DELAY
next_slots(spec, state, spec.MIN_ATTESTATION_INCLUSION_DELAY)
assert attestation.aggregation_bits == Bitlist[spec.MAX_VALIDATORS_PER_COMMITTEE](
*([0b0] * len(attestation.aggregation_bits)))
@ -305,7 +277,7 @@ def test_empty_aggregation_bits(spec, state):
@spec_state_test
def test_too_many_aggregation_bits(spec, state):
attestation = get_valid_attestation(spec, state, signed=True)
state.slot += spec.MIN_ATTESTATION_INCLUSION_DELAY
next_slots(spec, state, spec.MIN_ATTESTATION_INCLUSION_DELAY)
# one too many bits
attestation.aggregation_bits.append(0b0)
@ -317,7 +289,7 @@ def test_too_many_aggregation_bits(spec, state):
@spec_state_test
def test_too_few_aggregation_bits(spec, state):
attestation = get_valid_attestation(spec, state)
state.slot += spec.MIN_ATTESTATION_INCLUSION_DELAY
next_slots(spec, state, spec.MIN_ATTESTATION_INCLUSION_DELAY)
attestation.aggregation_bits = Bitlist[spec.MAX_VALIDATORS_PER_COMMITTEE](
*([0b1] + [0b0] * (len(attestation.aggregation_bits) - 1)))

View File

@ -1,4 +1,7 @@
from eth2spec.test.context import spec_state_test, expect_assertion_error, always_bls, with_all_phases, with_phases
from eth2spec.test.context import (
PHASE0, PHASE1,
spec_state_test, expect_assertion_error, always_bls, with_all_phases, with_phases
)
from eth2spec.test.helpers.attestations import sign_indexed_attestation
from eth2spec.test.helpers.attester_slashings import get_valid_attester_slashing, \
get_indexed_attestation_participants, get_attestation_2_data, get_attestation_1_data
@ -161,7 +164,7 @@ def test_same_data(spec, state):
indexed_att_1 = attester_slashing.attestation_1
att_2_data = get_attestation_2_data(spec, attester_slashing)
if spec.fork == 'phase1':
if spec.fork == PHASE1:
indexed_att_1.attestation.data = att_2_data
else:
indexed_att_1.data = att_2_data
@ -199,7 +202,7 @@ def test_participants_already_slashed(spec, state):
# Some of the following tests are phase0 only: phase 1 lists participants with bitfields instead of index list.
@with_phases(['phase0'])
@with_phases([PHASE0])
@spec_state_test
@always_bls
def test_att1_bad_extra_index(spec, state):
@ -215,7 +218,7 @@ def test_att1_bad_extra_index(spec, state):
yield from run_attester_slashing_processing(spec, state, attester_slashing, False)
@with_phases(['phase0'])
@with_phases([PHASE0])
@spec_state_test
@always_bls
def test_att1_bad_replaced_index(spec, state):
@ -231,7 +234,7 @@ def test_att1_bad_replaced_index(spec, state):
yield from run_attester_slashing_processing(spec, state, attester_slashing, False)
@with_phases(['phase0'])
@with_phases([PHASE0])
@spec_state_test
@always_bls
def test_att2_bad_extra_index(spec, state):
@ -247,7 +250,7 @@ def test_att2_bad_extra_index(spec, state):
yield from run_attester_slashing_processing(spec, state, attester_slashing, False)
@with_phases(['phase0'])
@with_phases([PHASE0])
@spec_state_test
@always_bls
def test_att2_bad_replaced_index(spec, state):
@ -263,7 +266,7 @@ def test_att2_bad_replaced_index(spec, state):
yield from run_attester_slashing_processing(spec, state, attester_slashing, False)
@with_phases(['phase0'])
@with_phases([PHASE0])
@spec_state_test
@always_bls
def test_att1_duplicate_index_normal_signed(spec, state):
@ -283,7 +286,7 @@ def test_att1_duplicate_index_normal_signed(spec, state):
yield from run_attester_slashing_processing(spec, state, attester_slashing, False)
@with_phases(['phase0'])
@with_phases([PHASE0])
@spec_state_test
@always_bls
def test_att2_duplicate_index_normal_signed(spec, state):
@ -303,7 +306,7 @@ def test_att2_duplicate_index_normal_signed(spec, state):
yield from run_attester_slashing_processing(spec, state, attester_slashing, False)
@with_phases(['phase0'])
@with_phases([PHASE0])
@spec_state_test
@always_bls
def test_att1_duplicate_index_double_signed(spec, state):
@ -318,7 +321,7 @@ def test_att1_duplicate_index_double_signed(spec, state):
yield from run_attester_slashing_processing(spec, state, attester_slashing, False)
@with_phases(['phase0'])
@with_phases([PHASE0])
@spec_state_test
@always_bls
def test_att2_duplicate_index_double_signed(spec, state):
@ -333,7 +336,7 @@ def test_att2_duplicate_index_double_signed(spec, state):
yield from run_attester_slashing_processing(spec, state, attester_slashing, False)
@with_phases(['phase0'])
@with_phases([PHASE0])
@spec_state_test
def test_unsorted_att_1(spec, state):
attester_slashing = get_valid_attester_slashing(spec, state, signed_1=False, signed_2=True)
@ -346,7 +349,7 @@ def test_unsorted_att_1(spec, state):
yield from run_attester_slashing_processing(spec, state, attester_slashing, False)
@with_phases(['phase0'])
@with_phases([PHASE0])
@spec_state_test
def test_unsorted_att_2(spec, state):
attester_slashing = get_valid_attester_slashing(spec, state, signed_1=True, signed_2=False)

View File

@ -2,7 +2,7 @@ from eth2spec.test.context import spec_state_test, expect_assertion_error, alway
from eth2spec.test.helpers.block_header import sign_block_header
from eth2spec.test.helpers.keys import privkeys
from eth2spec.test.helpers.proposer_slashings import get_valid_proposer_slashing
from eth2spec.test.helpers.state import get_balance
from eth2spec.test.helpers.state import get_balance, next_epoch
def run_proposer_slashing_processing(spec, state, proposer_slashing, valid=True):
@ -152,7 +152,7 @@ def test_proposer_is_withdrawn(spec, state):
proposer_slashing = get_valid_proposer_slashing(spec, state, signed_1=True, signed_2=True)
# move 1 epoch into future, to allow for past withdrawable epoch
state.slot += spec.SLOTS_PER_EPOCH
next_epoch(spec, state)
# set proposer withdrawable_epoch in past
current_epoch = spec.get_current_epoch(state)
proposer_index = proposer_slashing.signed_header_1.message.proposer_index

View File

@ -2,6 +2,7 @@ from eth2spec.test.context import spec_state_test, with_all_phases
from eth2spec.test.phase_0.epoch_processing.run_epoch_process_base import (
run_epoch_processing_with, run_epoch_processing_to
)
from eth2spec.test.helpers.state import transition_to
def run_process_final_updates(spec, state):
@ -13,7 +14,8 @@ def run_process_final_updates(spec, state):
def test_eth1_vote_no_reset(spec, state):
assert spec.EPOCHS_PER_ETH1_VOTING_PERIOD > 1
# skip ahead to the end of the epoch
state.slot = spec.SLOTS_PER_EPOCH - 1
transition_to(spec, state, spec.SLOTS_PER_EPOCH - 1)
for i in range(state.slot + 1): # add a vote for each skipped slot.
state.eth1_data_votes.append(
spec.Eth1Data(deposit_root=b'\xaa' * 32,

View File

@ -2,6 +2,7 @@ from eth2spec.test.context import spec_state_test, with_all_phases
from eth2spec.test.phase_0.epoch_processing.run_epoch_process_base import (
run_epoch_processing_with
)
from eth2spec.test.helpers.state import transition_to
def run_process_just_and_fin(spec, state):
@ -23,7 +24,7 @@ def add_mock_attestations(spec, state, epoch, source, target, sufficient_support
raise Exception(f"cannot include attestations in epoch ${epoch} from epoch ${current_epoch}")
total_balance = spec.get_total_active_balance(state)
remaining_balance = total_balance * 2 // 3
remaining_balance = int(total_balance * 2 // 3) # can become negative
start_slot = spec.compute_start_slot_at_epoch(epoch)
for slot in range(start_slot, start_slot + spec.SLOTS_PER_EPOCH):
@ -41,14 +42,15 @@ def add_mock_attestations(spec, state, epoch, source, target, sufficient_support
aggregation_bits = [0] * len(committee)
for v in range(len(committee) * 2 // 3 + 1):
if remaining_balance > 0:
remaining_balance -= state.validators[v].effective_balance
remaining_balance -= int(state.validators[v].effective_balance)
aggregation_bits[v] = 1
else:
break
# remove just one attester to make the marginal support insufficient
# remove 1/5th of attesters so that support is insufficient
if not sufficient_support:
aggregation_bits[aggregation_bits.index(1)] = 0
for i in range(max(len(committee) // 5, 1)):
aggregation_bits[i] = 0
attestations.append(spec.PendingAttestation(
aggregation_bits=aggregation_bits,
@ -81,7 +83,7 @@ def put_checkpoints_in_block_roots(spec, state, checkpoints):
def finalize_on_234(spec, state, epoch, sufficient_support):
assert epoch > 4
state.slot = (spec.SLOTS_PER_EPOCH * epoch) - 1 # skip ahead to just before epoch
transition_to(spec, state, spec.SLOTS_PER_EPOCH * epoch - 1) # skip ahead to just before epoch
# 43210 -- epochs ago
# 3210x -- justification bitfield indices
@ -116,7 +118,7 @@ def finalize_on_234(spec, state, epoch, sufficient_support):
def finalize_on_23(spec, state, epoch, sufficient_support):
assert epoch > 3
state.slot = (spec.SLOTS_PER_EPOCH * epoch) - 1 # skip ahead to just before epoch
transition_to(spec, state, spec.SLOTS_PER_EPOCH * epoch - 1) # skip ahead to just before epoch
# 43210 -- epochs ago
# 210xx -- justification bitfield indices (pre shift)
@ -194,7 +196,7 @@ def finalize_on_123(spec, state, epoch, sufficient_support):
def finalize_on_12(spec, state, epoch, sufficient_support, messed_up_target):
assert epoch > 2
state.slot = (spec.SLOTS_PER_EPOCH * epoch) - 1 # skip ahead to just before epoch
transition_to(spec, state, spec.SLOTS_PER_EPOCH * epoch - 1) # skip ahead to just before epoch
# 43210 -- epochs ago
# 210xx -- justification bitfield indices (pre shift)

View File

@ -1,4 +1,4 @@
from eth2spec.test.helpers.state import next_epoch
from eth2spec.test.helpers.state import next_epoch, next_slots
from eth2spec.test.context import spec_state_test, with_all_phases
from eth2spec.test.phase_0.epoch_processing.run_epoch_process_base import run_epoch_processing_with
@ -101,7 +101,7 @@ def test_activation_queue_sorting(spec, state):
state.validators[mock_activations - 1].activation_eligibility_epoch = epoch
# move state forward and finalize to allow for activations
state.slot += spec.SLOTS_PER_EPOCH * 3
next_slots(spec, state, spec.SLOTS_PER_EPOCH * 3)
state.finalized_checkpoint.epoch = epoch + 1
yield from run_process_registry_updates(spec, state)
@ -113,10 +113,10 @@ def test_activation_queue_sorting(spec, state):
# the second last is at the end of the queue, and did not make the churn,
# hence is not assigned an activation_epoch yet.
assert state.validators[mock_activations - 2].activation_epoch == spec.FAR_FUTURE_EPOCH
# the one at churn_limit - 1 did not make it, it was out-prioritized
assert state.validators[churn_limit - 1].activation_epoch == spec.FAR_FUTURE_EPOCH
# the one at churn_limit did not make it, it was out-prioritized
assert state.validators[churn_limit].activation_epoch == spec.FAR_FUTURE_EPOCH
# but the the one in front of the above did
assert state.validators[churn_limit - 2].activation_epoch != spec.FAR_FUTURE_EPOCH
assert state.validators[churn_limit - 1].activation_epoch != spec.FAR_FUTURE_EPOCH
@with_all_phases
@ -131,7 +131,8 @@ def test_activation_queue_efficiency(spec, state):
state.validators[i].activation_eligibility_epoch = epoch + 1
# move state forward and finalize to allow for activations
state.slot += spec.SLOTS_PER_EPOCH * 3
next_slots(spec, state, spec.SLOTS_PER_EPOCH * 3)
state.finalized_checkpoint.epoch = epoch + 1
# Run first registry update. Do not yield test vectors

View File

@ -1,8 +1,9 @@
from eth2spec.test.context import (
spec_state_test, with_all_phases, spec_test,
misc_balances, with_custom_state,
low_single_balance, zero_activation_threshold,
single_phase,
spec_state_test, spec_test,
with_all_phases, with_phases, single_phase,
with_custom_state,
zero_activation_threshold,
misc_balances, low_single_balance,
)
from eth2spec.test.helpers.state import (
next_epoch,
@ -20,7 +21,34 @@ def run_process_rewards_and_penalties(spec, state):
yield from run_epoch_processing_with(spec, state, 'process_rewards_and_penalties')
@with_all_phases
def prepare_state_with_full_attestations(spec, state, empty=False):
# Go to start of next epoch to ensure can have full participation
next_epoch(spec, state)
start_slot = state.slot
start_epoch = spec.get_current_epoch(state)
next_epoch_start_slot = spec.compute_start_slot_at_epoch(start_epoch + 1)
attestations = []
for _ in range(spec.SLOTS_PER_EPOCH + spec.MIN_ATTESTATION_INCLUSION_DELAY):
# create an attestation for each index in each slot in epoch
if state.slot < next_epoch_start_slot:
for committee_index in range(spec.get_committee_count_at_slot(state, state.slot)):
attestation = get_valid_attestation(spec, state, index=committee_index, empty=empty, signed=True)
attestations.append(attestation)
# fill each created slot in state after inclusion delay
if state.slot >= start_slot + spec.MIN_ATTESTATION_INCLUSION_DELAY:
inclusion_slot = state.slot - spec.MIN_ATTESTATION_INCLUSION_DELAY
include_attestations = [att for att in attestations if att.data.slot == inclusion_slot]
add_attestations_to_state(spec, state, include_attestations, state.slot)
next_slot(spec, state)
assert state.slot == next_epoch_start_slot + spec.MIN_ATTESTATION_INCLUSION_DELAY
assert len(state.previous_epoch_attestations) == len(attestations)
return attestations
@with_phases(['phase0'])
@spec_state_test
def test_genesis_epoch_no_attestations_no_penalties(spec, state):
pre_state = state.copy()
@ -33,7 +61,7 @@ def test_genesis_epoch_no_attestations_no_penalties(spec, state):
assert state.balances[index] == pre_state.balances[index]
@with_all_phases
@with_phases(['phase0'])
@spec_state_test
def test_genesis_epoch_full_attestations_no_rewards(spec, state):
attestations = []
@ -59,25 +87,6 @@ def test_genesis_epoch_full_attestations_no_rewards(spec, state):
assert state.balances[index] == pre_state.balances[index]
def prepare_state_with_full_attestations(spec, state, empty=False):
attestations = []
for slot in range(spec.SLOTS_PER_EPOCH + spec.MIN_ATTESTATION_INCLUSION_DELAY):
# create an attestation for each slot in epoch
if slot < spec.SLOTS_PER_EPOCH:
attestation = get_valid_attestation(spec, state, empty=empty, signed=True)
attestations.append(attestation)
# fill each created slot in state after inclusion delay
if slot - spec.MIN_ATTESTATION_INCLUSION_DELAY >= 0:
include_att = attestations[slot - spec.MIN_ATTESTATION_INCLUSION_DELAY]
add_attestations_to_state(spec, state, [include_att], state.slot)
next_slot(spec, state)
assert spec.compute_epoch_at_slot(state.slot) == spec.GENESIS_EPOCH + 1
assert len(state.previous_epoch_attestations) == spec.SLOTS_PER_EPOCH
return attestations
@with_all_phases
@spec_state_test
def test_full_attestations(spec, state):
@ -88,7 +97,7 @@ def test_full_attestations(spec, state):
yield from run_process_rewards_and_penalties(spec, state)
attesting_indices = spec.get_unslashed_attesting_indices(state, attestations)
assert len(attesting_indices) > 0
assert len(attesting_indices) == len(pre_state.validators)
for index in range(len(pre_state.validators)):
if index in attesting_indices:
assert state.balances[index] > pre_state.balances[index]
@ -168,6 +177,7 @@ def test_full_attestations_one_validaor_one_gwei(spec, state):
@with_all_phases
@spec_state_test
def test_no_attestations_all_penalties(spec, state):
# Move to next epoch to ensure rewards/penalties are processed
next_epoch(spec, state)
pre_state = state.copy()
@ -237,26 +247,14 @@ def test_duplicate_attestation(spec, state):
@spec_state_test
# Case when some eligible attestations are slashed. Modifies attesting_balance and consequently rewards/penalties.
def test_attestations_some_slashed(spec, state):
attestations = []
for slot in range(spec.SLOTS_PER_EPOCH + spec.MIN_ATTESTATION_INCLUSION_DELAY):
# create an attestation for each slot in epoch
if slot < spec.SLOTS_PER_EPOCH:
attestation = get_valid_attestation(spec, state, signed=True)
attestations.append(attestation)
# fill each created slot in state after inclusion delay
if slot - spec.MIN_ATTESTATION_INCLUSION_DELAY >= 0:
include_att = attestations[slot - spec.MIN_ATTESTATION_INCLUSION_DELAY]
add_attestations_to_state(spec, state, [include_att], state.slot)
next_slot(spec, state)
attestations = prepare_state_with_full_attestations(spec, state)
attesting_indices_before_slashings = list(spec.get_unslashed_attesting_indices(state, attestations))
# Slash maximum amount of validators allowed per epoch.
for i in range(spec.MIN_PER_EPOCH_CHURN_LIMIT):
spec.slash_validator(state, attesting_indices_before_slashings[i])
assert spec.compute_epoch_at_slot(state.slot) == spec.GENESIS_EPOCH + 1
assert len(state.previous_epoch_attestations) == spec.SLOTS_PER_EPOCH
assert len(state.previous_epoch_attestations) == len(attestations)
pre_state = state.copy()
@ -267,6 +265,8 @@ def test_attestations_some_slashed(spec, state):
assert len(attesting_indices_before_slashings) - len(attesting_indices) == spec.MIN_PER_EPOCH_CHURN_LIMIT
for index in range(len(pre_state.validators)):
if index in attesting_indices:
# non-slashed attester should gain reward
assert state.balances[index] > pre_state.balances[index]
else:
# Slashed non-proposer attester should have penalty
assert state.balances[index] < pre_state.balances[index]

View File

@ -2,6 +2,7 @@ from eth2spec.test.context import spec_state_test, with_all_phases
from eth2spec.test.phase_0.epoch_processing.run_epoch_process_base import (
run_epoch_processing_with, run_epoch_processing_to
)
from eth2spec.test.helpers.state import next_epoch
def run_process_slashings(spec, state):
@ -79,7 +80,7 @@ def test_small_penalty(spec, state):
@spec_state_test
def test_scaled_penalties(spec, state):
# skip to next epoch
state.slot = spec.SLOTS_PER_EPOCH
next_epoch(spec, state)
# Also mock some previous slashings, so that we test to have the delta in the penalties computation.
base = spec.EJECTION_BALANCE

View File

@ -0,0 +1,46 @@
from eth2spec.test.context import (
with_all_phases_except,
spec_state_test,
always_bls,
)
from eth2spec.test.helpers.state import transition_to
from eth2spec.test.helpers.attestations import (
run_attestation_processing,
get_valid_late_attestation,
get_valid_on_time_attestation,
)
@with_all_phases_except(['phase0'])
@spec_state_test
@always_bls
def test_on_time_success(spec, state):
attestation = get_valid_on_time_attestation(spec, state, signed=True)
transition_to(spec, state, state.slot + spec.MIN_ATTESTATION_INCLUSION_DELAY)
yield from run_attestation_processing(spec, state, attestation)
@with_all_phases_except(['phase0'])
@spec_state_test
@always_bls
def test_on_time_empty_custody_bits_blocks(spec, state):
attestation = get_valid_late_attestation(spec, state, signed=True)
assert not any(attestation.custody_bits_blocks)
transition_to(spec, state, state.slot + spec.MIN_ATTESTATION_INCLUSION_DELAY)
yield from run_attestation_processing(spec, state, attestation, False)
@with_all_phases_except(['phase0'])
@spec_state_test
@always_bls
def test_late_with_custody_bits_blocks(spec, state):
attestation = get_valid_on_time_attestation(spec, state, signed=True)
transition_to(spec, state, state.slot + spec.MIN_ATTESTATION_INCLUSION_DELAY + 1)
yield from run_attestation_processing(spec, state, attestation, False)

View File

@ -1,5 +1,6 @@
from eth2spec.test.helpers.custody import get_valid_custody_key_reveal
from eth2spec.test.context import (
PHASE0,
with_all_phases_except,
spec_state_test,
expect_assertion_error,
@ -54,7 +55,7 @@ def run_custody_key_reveal_processing(spec, state, custody_key_reveal, valid=Tru
yield 'post', state
@with_all_phases_except(['phase0'])
@with_all_phases_except([PHASE0])
@spec_state_test
@always_bls
def test_success(spec, state):
@ -64,7 +65,7 @@ def test_success(spec, state):
yield from run_custody_key_reveal_processing(spec, state, custody_key_reveal)
@with_all_phases_except(['phase0'])
@with_all_phases_except([PHASE0])
@spec_state_test
@always_bls
def test_reveal_too_early(spec, state):
@ -73,7 +74,7 @@ def test_reveal_too_early(spec, state):
yield from run_custody_key_reveal_processing(spec, state, custody_key_reveal, False)
@with_all_phases_except(['phase0'])
@with_all_phases_except([PHASE0])
@spec_state_test
@always_bls
def test_wrong_period(spec, state):
@ -82,7 +83,7 @@ def test_wrong_period(spec, state):
yield from run_custody_key_reveal_processing(spec, state, custody_key_reveal, False)
@with_all_phases_except(['phase0'])
@with_all_phases_except([PHASE0])
@spec_state_test
@always_bls
def test_late_reveal(spec, state):
@ -92,7 +93,7 @@ def test_late_reveal(spec, state):
yield from run_custody_key_reveal_processing(spec, state, custody_key_reveal)
@with_all_phases_except(['phase0'])
@with_all_phases_except([PHASE0])
@spec_state_test
@always_bls
def test_double_reveal(spec, state):
@ -104,7 +105,7 @@ def test_double_reveal(spec, state):
yield from run_custody_key_reveal_processing(spec, state, custody_key_reveal, False)
@with_all_phases_except(['phase0'])
@with_all_phases_except([PHASE0])
@spec_state_test
@always_bls
def test_max_decrement(spec, state):

View File

@ -2,6 +2,7 @@ from eth2spec.test.helpers.custody import get_valid_early_derived_secret_reveal
from eth2spec.test.helpers.block import apply_empty_block
from eth2spec.test.helpers.state import next_epoch, get_balance
from eth2spec.test.context import (
PHASE0,
with_all_phases_except,
spec_state_test,
expect_assertion_error,
@ -41,7 +42,7 @@ def run_early_derived_secret_reveal_processing(spec, state, randao_key_reveal, v
yield 'post', state
@with_all_phases_except(['phase0'])
@with_all_phases_except([PHASE0])
@spec_state_test
@always_bls
def test_success(spec, state):
@ -50,7 +51,7 @@ def test_success(spec, state):
yield from run_early_derived_secret_reveal_processing(spec, state, randao_key_reveal)
@with_all_phases_except(['phase0'])
@with_all_phases_except([PHASE0])
@spec_state_test
@never_bls
def test_reveal_from_current_epoch(spec, state):
@ -59,7 +60,7 @@ def test_reveal_from_current_epoch(spec, state):
yield from run_early_derived_secret_reveal_processing(spec, state, randao_key_reveal, False)
@with_all_phases_except(['phase0'])
@with_all_phases_except([PHASE0])
@spec_state_test
@never_bls
def test_reveal_from_past_epoch(spec, state):
@ -70,7 +71,7 @@ def test_reveal_from_past_epoch(spec, state):
yield from run_early_derived_secret_reveal_processing(spec, state, randao_key_reveal, False)
@with_all_phases_except(['phase0'])
@with_all_phases_except([PHASE0])
@spec_state_test
@always_bls
def test_reveal_with_custody_padding(spec, state):
@ -82,7 +83,7 @@ def test_reveal_with_custody_padding(spec, state):
yield from run_early_derived_secret_reveal_processing(spec, state, randao_key_reveal, True)
@with_all_phases_except(['phase0'])
@with_all_phases_except([PHASE0])
@spec_state_test
@always_bls
def test_reveal_with_custody_padding_minus_one(spec, state):
@ -94,7 +95,7 @@ def test_reveal_with_custody_padding_minus_one(spec, state):
yield from run_early_derived_secret_reveal_processing(spec, state, randao_key_reveal, True)
@with_all_phases_except(['phase0'])
@with_all_phases_except([PHASE0])
@spec_state_test
@never_bls
def test_double_reveal(spec, state):
@ -115,7 +116,7 @@ def test_double_reveal(spec, state):
yield from run_early_derived_secret_reveal_processing(spec, state, randao_key_reveal2, False)
@with_all_phases_except(['phase0'])
@with_all_phases_except([PHASE0])
@spec_state_test
@never_bls
def test_revealer_is_slashed(spec, state):
@ -125,7 +126,7 @@ def test_revealer_is_slashed(spec, state):
yield from run_early_derived_secret_reveal_processing(spec, state, randao_key_reveal, False)
@with_all_phases_except(['phase0'])
@with_all_phases_except([PHASE0])
@spec_state_test
@never_bls
def test_far_future_epoch(spec, state):

View File

@ -2,7 +2,7 @@ from copy import deepcopy
from eth2spec.utils import bls
from eth2spec.test.helpers.state import get_balance, state_transition_and_sign_block, next_slot
from eth2spec.test.helpers.state import get_balance, state_transition_and_sign_block, next_slot, next_epoch
from eth2spec.test.helpers.block import build_empty_block_for_next_slot, build_empty_block, sign_block, \
transition_unsigned_block
from eth2spec.test.helpers.keys import privkeys, pubkeys
@ -11,7 +11,7 @@ from eth2spec.test.helpers.proposer_slashings import get_valid_proposer_slashing
from eth2spec.test.helpers.attestations import get_valid_attestation
from eth2spec.test.helpers.deposits import prepare_state_and_deposit
from eth2spec.test.context import spec_state_test, with_all_phases, expect_assertion_error, always_bls
from eth2spec.test.context import spec_state_test, with_all_phases, expect_assertion_error, always_bls, with_phases
@with_all_phases
@ -303,7 +303,8 @@ def test_proposer_after_inactive_index(spec, state):
state.validators[inactive_index].exit_epoch = spec.get_current_epoch(state)
# skip forward, get brand new proposers
state.slot = spec.SLOTS_PER_EPOCH * 2
next_epoch(spec, state)
next_epoch(spec, state)
block = build_empty_block_for_next_slot(spec, state)
state_transition_and_sign_block(spec, state, block)
@ -415,7 +416,7 @@ def test_deposit_top_up(spec, state):
@with_all_phases
@spec_state_test
def test_attestation(spec, state):
state.slot = spec.SLOTS_PER_EPOCH
next_epoch(spec, state)
yield 'pre', state
@ -423,7 +424,7 @@ def test_attestation(spec, state):
# Add to state via block transition
pre_current_attestations_len = len(state.current_epoch_attestations)
attestation_block = build_empty_block(spec, state, state.slot + 1 + spec.MIN_ATTESTATION_INCLUSION_DELAY)
attestation_block = build_empty_block(spec, state, state.slot + spec.MIN_ATTESTATION_INCLUSION_DELAY)
attestation_block.body.attestations.append(attestation)
signed_attestation_block = state_transition_and_sign_block(spec, state, attestation_block)
@ -442,7 +443,9 @@ def test_attestation(spec, state):
assert spec.hash_tree_root(state.previous_epoch_attestations) == pre_current_attestations_root
@with_all_phases
# In phase1 a committee is computed for PERSISTENT_COMMITTEE_PERIOD slots ago,
# exceeding the minimal-config randao mixes memory size.
@with_phases(['phase0'])
@spec_state_test
def test_voluntary_exit(spec, state):
validator_index = spec.get_active_validator_indices(

View File

@ -1,5 +1,6 @@
from eth2spec.test.context import spec_state_test, never_bls, with_all_phases
from eth2spec.test.helpers.state import next_epoch, next_epoch_with_attestations
from eth2spec.test.context import spec_state_test, never_bls, with_all_phases, with_phases
from eth2spec.test.helpers.state import next_epoch
from eth2spec.test.helpers.attestations import next_epoch_with_attestations
from eth2spec.test.helpers.block import apply_empty_block
@ -28,7 +29,7 @@ def check_finality(spec,
assert state.finalized_checkpoint == prev_state.finalized_checkpoint
@with_all_phases
@with_phases(["phase0"])
@spec_state_test
@never_bls
def test_finality_no_updates_at_genesis(spec, state):

View File

@ -18,11 +18,11 @@ A YAML-encoded `BeaconState`, the state before applying the operation.
Also available as `pre.ssz`.
### `<operation-name>.yaml`
### `<input-name>.yaml`
A YAML-encoded operation object, e.g. a `ProposerSlashing`, or `Deposit`.
Also available as `<operation-name>.ssz`.
Also available as `<input-name>.ssz`.
### `post.yaml`
@ -39,14 +39,14 @@ This excludes the other parts of the block-transition.
Operations:
| *`operation-name`* | *`operation-object`* | *`input name`* | *`processing call`* |
|-------------------------|----------------------|----------------------|--------------------------------------------------------|
| `attestation` | `Attestation` | `attestation` | `process_attestation(state, attestation)` |
| `attester_slashing` | `AttesterSlashing` | `attester_slashing` | `process_attester_slashing(state, attester_slashing)` |
| `block_header` | `Block` | **`block`** | `process_block_header(state, block)` |
| `deposit` | `Deposit` | `deposit` | `process_deposit(state, deposit)` |
| `proposer_slashing` | `ProposerSlashing` | `proposer_slashing` | `process_proposer_slashing(state, proposer_slashing)` |
| `voluntary_exit` | `VoluntaryExit` | `voluntary_exit` | `process_voluntary_exit(state, voluntary_exit)` |
| *`operation-name`* | *`operation-object`* | *`input name`* | *`processing call`* |
|-------------------------|-----------------------|----------------------|--------------------------------------------------------|
| `attestation` | `Attestation` | `attestation` | `process_attestation(state, attestation)` |
| `attester_slashing` | `AttesterSlashing` | `attester_slashing` | `process_attester_slashing(state, attester_slashing)` |
| `block_header` | `BeaconBlock` | **`block`** | `process_block_header(state, block)` |
| `deposit` | `Deposit` | `deposit` | `process_deposit(state, deposit)` |
| `proposer_slashing` | `ProposerSlashing` | `proposer_slashing` | `process_proposer_slashing(state, proposer_slashing)` |
| `voluntary_exit` | `SignedVoluntaryExit` | `voluntary_exit` | `process_voluntary_exit(state, voluntary_exit)` |
Note that `block_header` is not strictly an operation (and is a full `Block`), but processed in the same manner, and hence included here.

View File

@ -25,7 +25,7 @@ Also available as `pre.ssz`.
A series of files, with `<index>` in range `[0, blocks_count)`. Blocks need to be processed in order,
following the main transition function (i.e. process slot and epoch transitions in between blocks as normal)
Each file is a YAML-encoded `BeaconBlock`.
Each file is a YAML-encoded `SignedBeaconBlock`.
Each block is also available as `blocks_<index>.ssz`

View File

@ -13,6 +13,7 @@ from gen_base import gen_runner, gen_typing
from py_ecc import bls
from hashlib import sha256
from eth2spec.test.context import PHASE0
def hash(x):
return sha256(x).digest()
@ -202,7 +203,7 @@ def create_provider(handler_name: str,
print(data)
(case_name, case_content) = data
yield gen_typing.TestCase(
fork_name='phase0',
fork_name=PHASE0,
runner_name='bls',
handler_name=handler_name,
suite_name='small',

View File

@ -5,7 +5,7 @@ Epoch processing covers the sub-transitions during an epoch change.
An epoch-processing test-runner can consume these sub-transition test-suites,
and handle different kinds of epoch sub-transitions by processing the cases using the specified test handler.
Information on the format of the tests can be found in the [epoch-processing test formats documentation](../../specs/test_formats/epoch_processing/README.md).
Information on the format of the tests can be found in the [epoch-processing test formats documentation](../../formats/epoch_processing/README.md).

View File

@ -13,6 +13,7 @@ from gen_base import gen_runner, gen_typing
from gen_from_tests.gen import generate_from_tests
from importlib import reload
from eth2spec.config import config_util
from eth2spec.test.context import PHASE0
def create_provider(handler_name: str, tests_src, config_name: str) -> gen_typing.TestProvider:
@ -28,7 +29,7 @@ def create_provider(handler_name: str, tests_src, config_name: str) -> gen_typin
runner_name='epoch_processing',
handler_name=handler_name,
src=tests_src,
fork_name='phase0'
fork_name=PHASE0,
)
return gen_typing.TestProvider(prepare=prepare_fn, make_cases=cases_fn)

View File

@ -1,5 +1,6 @@
from typing import Iterable
from eth2spec.test.context import PHASE0
from eth2spec.test.genesis import test_initialization, test_validity
from gen_base import gen_runner, gen_typing
@ -21,7 +22,7 @@ def create_provider(handler_name: str, tests_src, config_name: str) -> gen_typin
runner_name='genesis',
handler_name=handler_name,
src=tests_src,
fork_name='phase0'
fork_name=PHASE0,
)
return gen_typing.TestProvider(prepare=prepare_fn, make_cases=cases_fn)

View File

@ -6,7 +6,7 @@ Operations (or "transactions" in previous spec iterations),
An operation test-runner can consume these operation test-suites,
and handle different kinds of operations by processing the cases using the specified test handler.
Information on the format of the tests can be found in the [operations test formats documentation](../../specs/test_formats/operations/README.md).
Information on the format of the tests can be found in the [operations test formats documentation](../../formats/operations/README.md).

View File

@ -15,6 +15,7 @@ from importlib import reload
from eth2spec.config import config_util
from eth2spec.phase0 import spec as spec_phase0
from eth2spec.phase1 import spec as spec_phase1
from eth2spec.test.context import PHASE0
def create_provider(handler_name: str, tests_src, config_name: str) -> gen_typing.TestProvider:
@ -30,7 +31,7 @@ def create_provider(handler_name: str, tests_src, config_name: str) -> gen_typin
runner_name='operations',
handler_name=handler_name,
src=tests_src,
fork_name='phase0'
fork_name=PHASE0,
)
return gen_typing.TestProvider(prepare=prepare_fn, make_cases=cases_fn)

View File

@ -2,7 +2,7 @@
Sanity tests cover regular state-transitions in a common block-list format, to ensure the basics work.
Information on the format of the tests can be found in the [sanity test formats documentation](../../specs/test_formats/sanity/README.md).
Information on the format of the tests can be found in the [sanity test formats documentation](../../formats/sanity/README.md).

View File

@ -4,6 +4,7 @@ from importlib import reload
from gen_base import gen_runner, gen_typing
from gen_from_tests.gen import generate_from_tests
from eth2spec.test.context import PHASE0
from eth2spec.test.sanity import test_blocks, test_slots
from eth2spec.config import config_util
from eth2spec.phase0 import spec as spec_phase0
@ -23,7 +24,7 @@ def create_provider(handler_name: str, tests_src, config_name: str) -> gen_typin
runner_name='sanity',
handler_name=handler_name,
src=tests_src,
fork_name='phase0'
fork_name=PHASE0,
)
return gen_typing.TestProvider(prepare=prepare_fn, make_cases=cases_fn)

View File

@ -6,6 +6,7 @@ from gen_base import gen_runner, gen_typing
from eth2spec.config import config_util
from eth2spec.phase0 import spec as spec
from eth2spec.test.context import PHASE0
def shuffling_case_fn(seed, count):
@ -37,7 +38,7 @@ def create_provider(config_name: str) -> gen_typing.TestProvider:
def cases_fn() -> Iterable[gen_typing.TestCase]:
for (case_name, case_fn) in shuffling_test_cases():
yield gen_typing.TestCase(
fork_name='phase0',
fork_name=PHASE0,
runner_name='shuffling',
handler_name='core',
suite_name='shuffle',

View File

@ -6,6 +6,7 @@ import ssz_bitvector
import ssz_boolean
import ssz_uints
import ssz_container
from eth2spec.test.context import PHASE0
def create_provider(handler_name: str, suite_name: str, case_maker) -> gen_typing.TestProvider:
@ -16,7 +17,7 @@ def create_provider(handler_name: str, suite_name: str, case_maker) -> gen_typin
def cases_fn() -> Iterable[gen_typing.TestCase]:
for (case_name, case_fn) in case_maker():
yield gen_typing.TestCase(
fork_name='phase0',
fork_name=PHASE0,
runner_name='ssz_generic',
handler_name=handler_name,
suite_name=suite_name,

View File

@ -3,4 +3,4 @@
The purpose of this test-generator is to provide test-vectors for the most important applications of SSZ:
the serialization and hashing of Eth2 data types.
Test-format documentation can be found [here](../../specs/test_formats/ssz_static/README.md).
Test-format documentation can be found [here](../../formats/ssz_static/README.md).

View File

@ -8,6 +8,7 @@ from gen_base import gen_runner, gen_typing
from eth2spec.debug import random_value, encode
from eth2spec.config import config_util
from eth2spec.phase0 import spec
from eth2spec.test.context import PHASE0
from eth2spec.utils.ssz.ssz_typing import Container
from eth2spec.utils.ssz.ssz_impl import (
hash_tree_root,
@ -44,7 +45,7 @@ def ssz_static_cases(seed: int, name, ssz_type, mode: random_value.Randomization
for i in range(count):
yield gen_typing.TestCase(
fork_name='phase0',
fork_name=PHASE0,
runner_name='ssz_static',
handler_name=name,
suite_name=f"ssz_{random_mode_name}{'_chaos' if chaos else ''}",