mirror of
https://github.com/status-im/eth2.0-specs.git
synced 2025-02-22 15:28:11 +00:00
Merge branch 'dev' into hwwhww/strict-uint64
This commit is contained in:
commit
b239f6108c
@ -303,6 +303,7 @@ def store_target_checkpoint_state(store: Store, target: Checkpoint) -> None:
|
|||||||
# Store target checkpoint state if not yet seen
|
# Store target checkpoint state if not yet seen
|
||||||
if target not in store.checkpoint_states:
|
if target not in store.checkpoint_states:
|
||||||
base_state = copy(store.block_states[target.root])
|
base_state = copy(store.block_states[target.root])
|
||||||
|
if base_state.slot < compute_start_slot_at_epoch(target.epoch):
|
||||||
process_slots(base_state, compute_start_slot_at_epoch(target.epoch))
|
process_slots(base_state, compute_start_slot_at_epoch(target.epoch))
|
||||||
store.checkpoint_states[target] = base_state
|
store.checkpoint_states[target] = base_state
|
||||||
```
|
```
|
||||||
|
@ -569,7 +569,7 @@ def get_light_client_committee(beacon_state: BeaconState, epoch: Epoch) -> Seque
|
|||||||
seed=seed,
|
seed=seed,
|
||||||
index=0,
|
index=0,
|
||||||
count=get_active_shard_count(beacon_state),
|
count=get_active_shard_count(beacon_state),
|
||||||
)[:TARGET_COMMITTEE_SIZE]
|
)[:LIGHT_CLIENT_COMMITTEE_SIZE]
|
||||||
```
|
```
|
||||||
|
|
||||||
#### `get_shard_proposer_index`
|
#### `get_shard_proposer_index`
|
||||||
@ -652,11 +652,11 @@ def get_offset_slots(state: BeaconState, shard: Shard) -> Sequence[Slot]:
|
|||||||
|
|
||||||
```python
|
```python
|
||||||
def is_on_time_attestation(state: BeaconState,
|
def is_on_time_attestation(state: BeaconState,
|
||||||
attestation: Attestation) -> bool:
|
attestation_data: AttestationData) -> bool:
|
||||||
"""
|
"""
|
||||||
Check if the given attestation is on-time.
|
Check if the given ``attestation_data`` is on-time.
|
||||||
"""
|
"""
|
||||||
return attestation.data.slot == compute_previous_slot(state.slot)
|
return attestation_data.slot == compute_previous_slot(state.slot)
|
||||||
```
|
```
|
||||||
|
|
||||||
#### `is_winning_attestation`
|
#### `is_winning_attestation`
|
||||||
@ -667,11 +667,11 @@ def is_winning_attestation(state: BeaconState,
|
|||||||
committee_index: CommitteeIndex,
|
committee_index: CommitteeIndex,
|
||||||
winning_root: Root) -> bool:
|
winning_root: Root) -> bool:
|
||||||
"""
|
"""
|
||||||
Check if ``attestation`` helped contribute to the successful crosslink of
|
Check if on-time ``attestation`` helped contribute to the successful crosslink of
|
||||||
``winning_root`` formed by ``committee_index`` committee at the current slot.
|
``winning_root`` formed by ``committee_index`` committee.
|
||||||
"""
|
"""
|
||||||
return (
|
return (
|
||||||
attestation.data.slot == state.slot
|
is_on_time_attestation(state, attestation.data)
|
||||||
and attestation.data.index == committee_index
|
and attestation.data.index == committee_index
|
||||||
and attestation.data.shard_transition_root == winning_root
|
and attestation.data.shard_transition_root == winning_root
|
||||||
)
|
)
|
||||||
@ -766,12 +766,14 @@ def validate_attestation(state: BeaconState, attestation: Attestation) -> None:
|
|||||||
assert attestation.data.source == state.previous_justified_checkpoint
|
assert attestation.data.source == state.previous_justified_checkpoint
|
||||||
|
|
||||||
# Type 1: on-time attestations
|
# Type 1: on-time attestations
|
||||||
if is_on_time_attestation(state, attestation):
|
if is_on_time_attestation(state, attestation.data):
|
||||||
# Correct parent block root
|
# Correct parent block root
|
||||||
assert data.beacon_block_root == get_block_root_at_slot(state, compute_previous_slot(state.slot))
|
assert data.beacon_block_root == get_block_root_at_slot(state, compute_previous_slot(state.slot))
|
||||||
# Correct shard number
|
# Correct shard number
|
||||||
shard = compute_shard_from_committee_index(state, attestation.data.index, attestation.data.slot)
|
shard = compute_shard_from_committee_index(state, attestation.data.index, attestation.data.slot)
|
||||||
assert attestation.data.shard == shard
|
assert attestation.data.shard == shard
|
||||||
|
# On-time attestations should have a non-empty shard transition root
|
||||||
|
assert attestation.data.shard_transition_root != hash_tree_root(ShardTransition())
|
||||||
# Type 2: no shard transition
|
# Type 2: no shard transition
|
||||||
else:
|
else:
|
||||||
# Ensure delayed attestation
|
# Ensure delayed attestation
|
||||||
@ -886,9 +888,6 @@ def process_crosslink_for_shard(state: BeaconState,
|
|||||||
for attestation in transition_attestations:
|
for attestation in transition_attestations:
|
||||||
participants = get_attesting_indices(state, attestation.data, attestation.aggregation_bits)
|
participants = get_attesting_indices(state, attestation.data, attestation.aggregation_bits)
|
||||||
transition_participants = transition_participants.union(participants)
|
transition_participants = transition_participants.union(participants)
|
||||||
assert attestation.data.shard_head_root == shard_transition.shard_data_roots[
|
|
||||||
len(shard_transition.shard_data_roots) - 1
|
|
||||||
]
|
|
||||||
|
|
||||||
enough_online_stake = (
|
enough_online_stake = (
|
||||||
get_total_balance(state, online_indices.intersection(transition_participants)) * 3 >=
|
get_total_balance(state, online_indices.intersection(transition_participants)) * 3 >=
|
||||||
@ -901,6 +900,12 @@ def process_crosslink_for_shard(state: BeaconState,
|
|||||||
# Attestation <-> shard transition consistency
|
# Attestation <-> shard transition consistency
|
||||||
assert shard_transition_root == hash_tree_root(shard_transition)
|
assert shard_transition_root == hash_tree_root(shard_transition)
|
||||||
|
|
||||||
|
# Check `shard_head_root` of the winning root
|
||||||
|
last_offset_index = len(shard_transition.shard_states) - 1
|
||||||
|
shard_head_root = shard_transition.shard_states[last_offset_index].latest_block_root
|
||||||
|
for attestation in transition_attestations:
|
||||||
|
assert attestation.data.shard_head_root == shard_head_root
|
||||||
|
|
||||||
# Apply transition
|
# Apply transition
|
||||||
apply_shard_transition(state, shard, shard_transition)
|
apply_shard_transition(state, shard, shard_transition)
|
||||||
# Apply proposer reward and cost
|
# Apply proposer reward and cost
|
||||||
@ -939,7 +944,7 @@ def process_crosslinks(state: BeaconState,
|
|||||||
# Since the attestations are validated, all `shard_attestations` satisfy `attestation.data.shard == shard`
|
# Since the attestations are validated, all `shard_attestations` satisfy `attestation.data.shard == shard`
|
||||||
shard_attestations = [
|
shard_attestations = [
|
||||||
attestation for attestation in attestations
|
attestation for attestation in attestations
|
||||||
if is_on_time_attestation(state, attestation) and attestation.data.index == committee_index
|
if is_on_time_attestation(state, attestation.data) and attestation.data.index == committee_index
|
||||||
]
|
]
|
||||||
winning_root = process_crosslink_for_shard(
|
winning_root = process_crosslink_for_shard(
|
||||||
state, committee_index, shard_transitions[shard], shard_attestations
|
state, committee_index, shard_transitions[shard], shard_attestations
|
||||||
|
@ -111,7 +111,7 @@ def upgrade_to_phase1(pre: phase0.BeaconState) -> BeaconState:
|
|||||||
current_light_committee=CompactCommittee(), # computed after state creation
|
current_light_committee=CompactCommittee(), # computed after state creation
|
||||||
next_light_committee=CompactCommittee(),
|
next_light_committee=CompactCommittee(),
|
||||||
# Custody game
|
# Custody game
|
||||||
exposed_derived_secrets=[] * EARLY_DERIVED_SECRET_PENALTY_MAX_FUTURE_EPOCHS,
|
exposed_derived_secrets=[()] * EARLY_DERIVED_SECRET_PENALTY_MAX_FUTURE_EPOCHS,
|
||||||
# exposed_derived_secrets will fully default to zeroes
|
# exposed_derived_secrets will fully default to zeroes
|
||||||
)
|
)
|
||||||
next_epoch = Epoch(epoch + 1)
|
next_epoch = Epoch(epoch + 1)
|
||||||
|
@ -36,7 +36,7 @@ This document is the shard chain fork choice spec for part of Ethereum 2.0 Phase
|
|||||||
@dataclass
|
@dataclass
|
||||||
class ShardStore:
|
class ShardStore:
|
||||||
shard: Shard
|
shard: Shard
|
||||||
blocks: Dict[Root, ShardBlock] = field(default_factory=dict)
|
signed_blocks: Dict[Root, SignedShardBlock] = field(default_factory=dict)
|
||||||
block_states: Dict[Root, ShardState] = field(default_factory=dict)
|
block_states: Dict[Root, ShardState] = field(default_factory=dict)
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -46,7 +46,11 @@ class ShardStore:
|
|||||||
def get_forkchoice_shard_store(anchor_state: BeaconState, shard: Shard) -> ShardStore:
|
def get_forkchoice_shard_store(anchor_state: BeaconState, shard: Shard) -> ShardStore:
|
||||||
return ShardStore(
|
return ShardStore(
|
||||||
shard=shard,
|
shard=shard,
|
||||||
blocks={anchor_state.shard_states[shard].latest_block_root: ShardBlock(slot=anchor_state.slot, shard=shard)},
|
signed_blocks={
|
||||||
|
anchor_state.shard_states[shard].latest_block_root: SignedShardBlock(
|
||||||
|
message=ShardBlock(slot=anchor_state.slot, shard=shard)
|
||||||
|
)
|
||||||
|
},
|
||||||
block_states={anchor_state.shard_states[shard].latest_block_root: anchor_state.copy().shard_states[shard]},
|
block_states={anchor_state.shard_states[shard].latest_block_root: anchor_state.copy().shard_states[shard]},
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
@ -65,7 +69,7 @@ def get_shard_latest_attesting_balance(store: Store, shard_store: ShardStore, ro
|
|||||||
# would be ignored once their newer vote is accepted. Check if it makes sense.
|
# would be ignored once their newer vote is accepted. Check if it makes sense.
|
||||||
and store.latest_messages[i].shard == shard_store.shard
|
and store.latest_messages[i].shard == shard_store.shard
|
||||||
and get_shard_ancestor(
|
and get_shard_ancestor(
|
||||||
store, shard_store, store.latest_messages[i].shard_root, shard_store.blocks[root].slot
|
store, shard_store, store.latest_messages[i].shard_root, shard_store.signed_blocks[root].message.slot
|
||||||
) == root
|
) == root
|
||||||
)
|
)
|
||||||
))
|
))
|
||||||
@ -80,8 +84,8 @@ def get_shard_head(store: Store, shard_store: ShardStore) -> Root:
|
|||||||
shard_head_state = store.block_states[beacon_head_root].shard_states[shard_store.shard]
|
shard_head_state = store.block_states[beacon_head_root].shard_states[shard_store.shard]
|
||||||
shard_head_root = shard_head_state.latest_block_root
|
shard_head_root = shard_head_state.latest_block_root
|
||||||
shard_blocks = {
|
shard_blocks = {
|
||||||
root: shard_block for root, shard_block in shard_store.blocks.items()
|
root: signed_shard_block.message for root, signed_shard_block in shard_store.signed_blocks.items()
|
||||||
if shard_block.slot > shard_head_state.slot
|
if signed_shard_block.message.slot > shard_head_state.slot
|
||||||
}
|
}
|
||||||
while True:
|
while True:
|
||||||
# Find the valid child block roots
|
# Find the valid child block roots
|
||||||
@ -101,7 +105,7 @@ def get_shard_head(store: Store, shard_store: ShardStore) -> Root:
|
|||||||
|
|
||||||
```python
|
```python
|
||||||
def get_shard_ancestor(store: Store, shard_store: ShardStore, root: Root, slot: Slot) -> Root:
|
def get_shard_ancestor(store: Store, shard_store: ShardStore, root: Root, slot: Slot) -> Root:
|
||||||
block = shard_store.blocks[root]
|
block = shard_store.signed_blocks[root].message
|
||||||
if block.slot > slot:
|
if block.slot > slot:
|
||||||
return get_shard_ancestor(store, shard_store, block.shard_parent_root, slot)
|
return get_shard_ancestor(store, shard_store, block.shard_parent_root, slot)
|
||||||
elif block.slot == slot:
|
elif block.slot == slot:
|
||||||
@ -114,7 +118,7 @@ def get_shard_ancestor(store: Store, shard_store: ShardStore, root: Root, slot:
|
|||||||
#### `get_pending_shard_blocks`
|
#### `get_pending_shard_blocks`
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def get_pending_shard_blocks(store: Store, shard_store: ShardStore) -> Sequence[ShardBlock]:
|
def get_pending_shard_blocks(store: Store, shard_store: ShardStore) -> Sequence[SignedShardBlock]:
|
||||||
"""
|
"""
|
||||||
Return the canonical shard block branch that has not yet been crosslinked.
|
Return the canonical shard block branch that has not yet been crosslinked.
|
||||||
"""
|
"""
|
||||||
@ -126,14 +130,14 @@ def get_pending_shard_blocks(store: Store, shard_store: ShardStore) -> Sequence[
|
|||||||
|
|
||||||
shard_head_root = get_shard_head(store, shard_store)
|
shard_head_root = get_shard_head(store, shard_store)
|
||||||
root = shard_head_root
|
root = shard_head_root
|
||||||
shard_blocks = []
|
signed_shard_blocks = []
|
||||||
while root != latest_shard_block_root:
|
while root != latest_shard_block_root:
|
||||||
shard_block = shard_store.blocks[root]
|
signed_shard_block = shard_store.signed_blocks[root]
|
||||||
shard_blocks.append(shard_block)
|
signed_shard_blocks.append(signed_shard_block)
|
||||||
root = shard_block.shard_parent_root
|
root = signed_shard_block.message.shard_parent_root
|
||||||
|
|
||||||
shard_blocks.reverse()
|
signed_shard_blocks.reverse()
|
||||||
return shard_blocks
|
return signed_shard_blocks
|
||||||
```
|
```
|
||||||
|
|
||||||
### Handlers
|
### Handlers
|
||||||
@ -169,14 +173,15 @@ def on_shard_block(store: Store, shard_store: ShardStore, signed_shard_block: Si
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Check the block is valid and compute the post-state
|
# Check the block is valid and compute the post-state
|
||||||
assert verify_shard_block_message(beacon_parent_state, shard_parent_state, shard_block)
|
shard_state = shard_parent_state.copy()
|
||||||
assert verify_shard_block_signature(beacon_parent_state, signed_shard_block)
|
shard_state_transition(
|
||||||
|
shard_state, signed_shard_block,
|
||||||
post_state = get_post_shard_state(shard_parent_state, shard_block)
|
validate=True, beacon_parent_state=beacon_parent_state)
|
||||||
|
|
||||||
# Add new block to the store
|
# Add new block to the store
|
||||||
shard_store.blocks[hash_tree_root(shard_block)] = shard_block
|
# Note: storing `SignedShardBlock` format for computing `ShardTransition.proposer_signature_aggregate`
|
||||||
|
shard_store.signed_blocks[hash_tree_root(shard_block)] = signed_shard_block
|
||||||
|
|
||||||
# Add new state for this block to the store
|
# Add new state for this block to the store
|
||||||
shard_store.block_states[hash_tree_root(shard_block)] = post_state
|
shard_store.block_states[hash_tree_root(shard_block)] = shard_state
|
||||||
```
|
```
|
||||||
|
@ -42,8 +42,6 @@ def verify_shard_block_message(beacon_parent_state: BeaconState,
|
|||||||
next_slot = Slot(block.slot + 1)
|
next_slot = Slot(block.slot + 1)
|
||||||
offset_slots = compute_offset_slots(get_latest_slot_for_shard(beacon_parent_state, shard), next_slot)
|
offset_slots = compute_offset_slots(get_latest_slot_for_shard(beacon_parent_state, shard), next_slot)
|
||||||
assert block.slot in offset_slots
|
assert block.slot in offset_slots
|
||||||
# Check `shard` field
|
|
||||||
assert block.shard == shard
|
|
||||||
# Check `proposer_index` field
|
# Check `proposer_index` field
|
||||||
assert block.proposer_index == get_shard_proposer_index(beacon_parent_state, block.slot, shard)
|
assert block.proposer_index == get_shard_proposer_index(beacon_parent_state, block.slot, shard)
|
||||||
# Check `body` field
|
# Check `body` field
|
||||||
@ -52,10 +50,10 @@ def verify_shard_block_message(beacon_parent_state: BeaconState,
|
|||||||
```
|
```
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def verify_shard_block_signature(beacon_state: BeaconState,
|
def verify_shard_block_signature(beacon_parent_state: BeaconState,
|
||||||
signed_block: SignedShardBlock) -> bool:
|
signed_block: SignedShardBlock) -> bool:
|
||||||
proposer = beacon_state.validators[signed_block.message.proposer_index]
|
proposer = beacon_parent_state.validators[signed_block.message.proposer_index]
|
||||||
domain = get_domain(beacon_state, DOMAIN_SHARD_PROPOSAL, compute_epoch_at_slot(signed_block.message.slot))
|
domain = get_domain(beacon_parent_state, DOMAIN_SHARD_PROPOSAL, compute_epoch_at_slot(signed_block.message.slot))
|
||||||
signing_root = compute_signing_root(signed_block.message, domain)
|
signing_root = compute_signing_root(signed_block.message, domain)
|
||||||
return bls.Verify(proposer.pubkey, signing_root, signed_block.signature)
|
return bls.Verify(proposer.pubkey, signing_root, signed_block.signature)
|
||||||
```
|
```
|
||||||
@ -64,6 +62,20 @@ def verify_shard_block_signature(beacon_state: BeaconState,
|
|||||||
|
|
||||||
```python
|
```python
|
||||||
def shard_state_transition(shard_state: ShardState,
|
def shard_state_transition(shard_state: ShardState,
|
||||||
|
signed_block: SignedShardBlock,
|
||||||
|
validate: bool = True,
|
||||||
|
beacon_parent_state: Optional[BeaconState] = None) -> ShardState:
|
||||||
|
if validate:
|
||||||
|
assert beacon_parent_state is not None
|
||||||
|
assert verify_shard_block_message(beacon_parent_state, shard_state, signed_block.message)
|
||||||
|
assert verify_shard_block_signature(beacon_parent_state, signed_block)
|
||||||
|
|
||||||
|
process_shard_block(shard_state, signed_block.message)
|
||||||
|
return shard_state
|
||||||
|
```
|
||||||
|
|
||||||
|
```python
|
||||||
|
def process_shard_block(shard_state: ShardState,
|
||||||
block: ShardBlock) -> None:
|
block: ShardBlock) -> None:
|
||||||
"""
|
"""
|
||||||
Update ``shard_state`` with shard ``block``.
|
Update ``shard_state`` with shard ``block``.
|
||||||
@ -79,19 +91,6 @@ def shard_state_transition(shard_state: ShardState,
|
|||||||
shard_state.latest_block_root = latest_block_root
|
shard_state.latest_block_root = latest_block_root
|
||||||
```
|
```
|
||||||
|
|
||||||
We have a pure function `get_post_shard_state` for describing the fraud proof verification and honest validator behavior.
|
|
||||||
|
|
||||||
```python
|
|
||||||
def get_post_shard_state(shard_state: ShardState,
|
|
||||||
block: ShardBlock) -> ShardState:
|
|
||||||
"""
|
|
||||||
A pure function that returns a new post ShardState instead of modifying the given `shard_state`.
|
|
||||||
"""
|
|
||||||
post_state = shard_state.copy()
|
|
||||||
shard_state_transition(post_state, block)
|
|
||||||
return post_state
|
|
||||||
```
|
|
||||||
|
|
||||||
## Fraud proofs
|
## Fraud proofs
|
||||||
|
|
||||||
### Verifying the proof
|
### Verifying the proof
|
||||||
@ -129,7 +128,7 @@ def is_valid_fraud_proof(beacon_state: BeaconState,
|
|||||||
else:
|
else:
|
||||||
shard_state = transition.shard_states[offset_index - 1] # Not doing the actual state updates here.
|
shard_state = transition.shard_states[offset_index - 1] # Not doing the actual state updates here.
|
||||||
|
|
||||||
shard_state = get_post_shard_state(shard_state, block)
|
shard_state_transition(shard_state, block, validate=False)
|
||||||
if shard_state != transition.shard_states[offset_index]:
|
if shard_state != transition.shard_states[offset_index]:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@ -157,7 +157,7 @@ def get_shard_winning_roots(state: BeaconState,
|
|||||||
# All attestations in the block for this committee/shard and are "on time"
|
# All attestations in the block for this committee/shard and are "on time"
|
||||||
shard_attestations = [
|
shard_attestations = [
|
||||||
attestation for attestation in attestations
|
attestation for attestation in attestations
|
||||||
if is_on_time_attestation(state, attestation) and attestation.data.index == committee_index
|
if is_on_time_attestation(state, attestation.data) and attestation.data.index == committee_index
|
||||||
]
|
]
|
||||||
committee = get_beacon_committee(state, on_time_attestation_slot, committee_index)
|
committee = get_beacon_committee(state, on_time_attestation_slot, committee_index)
|
||||||
|
|
||||||
@ -280,7 +280,6 @@ def get_shard_transition_fields(
|
|||||||
beacon_state: BeaconState,
|
beacon_state: BeaconState,
|
||||||
shard: Shard,
|
shard: Shard,
|
||||||
shard_blocks: Sequence[SignedShardBlock],
|
shard_blocks: Sequence[SignedShardBlock],
|
||||||
validate_signature: bool=True,
|
|
||||||
) -> Tuple[Sequence[uint64], Sequence[Root], Sequence[ShardState]]:
|
) -> Tuple[Sequence[uint64], Sequence[Root], Sequence[ShardState]]:
|
||||||
shard_states = []
|
shard_states = []
|
||||||
shard_data_roots = []
|
shard_data_roots = []
|
||||||
@ -299,7 +298,8 @@ def get_shard_transition_fields(
|
|||||||
else:
|
else:
|
||||||
shard_block = SignedShardBlock(message=ShardBlock(slot=slot, shard=shard))
|
shard_block = SignedShardBlock(message=ShardBlock(slot=slot, shard=shard))
|
||||||
shard_data_roots.append(Root())
|
shard_data_roots.append(Root())
|
||||||
shard_state = get_post_shard_state(shard_state, shard_block.message)
|
shard_state = shard_state.copy()
|
||||||
|
shard_state_transition(shard_state, shard_block, validate=False)
|
||||||
shard_states.append(shard_state)
|
shard_states.append(shard_state)
|
||||||
shard_block_lengths.append(len(shard_block.message.body))
|
shard_block_lengths.append(len(shard_block.message.body))
|
||||||
|
|
||||||
|
@ -251,7 +251,7 @@ We similarly define "summary types" and "expansion types". For example, [`Beacon
|
|||||||
| Rust | Lighthouse | Sigma Prime | [https://github.com/sigp/lighthouse/tree/master/eth2/utils/ssz](https://github.com/sigp/lighthouse/tree/master/eth2/utils/ssz) |
|
| Rust | Lighthouse | Sigma Prime | [https://github.com/sigp/lighthouse/tree/master/eth2/utils/ssz](https://github.com/sigp/lighthouse/tree/master/eth2/utils/ssz) |
|
||||||
| Nim | Nimbus | Status | [https://github.com/status-im/nim-beacon-chain/blob/master/beacon_chain/ssz.nim](https://github.com/status-im/nim-beacon-chain/blob/master/beacon_chain/ssz.nim) |
|
| Nim | Nimbus | Status | [https://github.com/status-im/nim-beacon-chain/blob/master/beacon_chain/ssz.nim](https://github.com/status-im/nim-beacon-chain/blob/master/beacon_chain/ssz.nim) |
|
||||||
| Rust | Shasper | ParityTech | [https://github.com/paritytech/shasper/tree/master/utils/ssz](https://github.com/paritytech/shasper/tree/master/utils/ssz) |
|
| Rust | Shasper | ParityTech | [https://github.com/paritytech/shasper/tree/master/utils/ssz](https://github.com/paritytech/shasper/tree/master/utils/ssz) |
|
||||||
| TypeScript | Lodestar | ChainSafe Systems | [https://github.com/ChainSafe/ssz-js](https://github.com/ChainSafe/ssz-js) |
|
| TypeScript | Lodestar | ChainSafe Systems | [https://github.com/ChainSafe/ssz-js](https://github.com/ChainSafe/ssz) |
|
||||||
| Java | Cava | ConsenSys | [https://www.github.com/ConsenSys/cava/tree/master/ssz](https://www.github.com/ConsenSys/cava/tree/master/ssz) |
|
| Java | Cava | ConsenSys | [https://www.github.com/ConsenSys/cava/tree/master/ssz](https://www.github.com/ConsenSys/cava/tree/master/ssz) |
|
||||||
| Go | Prysm | Prysmatic Labs | [https://github.com/prysmaticlabs/go-ssz](https://github.com/prysmaticlabs/go-ssz) |
|
| Go | Prysm | Prysmatic Labs | [https://github.com/prysmaticlabs/go-ssz](https://github.com/prysmaticlabs/go-ssz) |
|
||||||
| Swift | Yeeth | Dean Eigenmann | [https://github.com/yeeth/SimpleSerialize.swift](https://github.com/yeeth/SimpleSerialize.swift) |
|
| Swift | Yeeth | Dean Eigenmann | [https://github.com/yeeth/SimpleSerialize.swift](https://github.com/yeeth/SimpleSerialize.swift) |
|
||||||
|
@ -158,9 +158,9 @@ def test_on_attestation_inconsistent_target_and_head(spec, state):
|
|||||||
|
|
||||||
@with_all_phases
|
@with_all_phases
|
||||||
@spec_state_test
|
@spec_state_test
|
||||||
def test_on_attestation_target_not_in_store(spec, state):
|
def test_on_attestation_target_block_not_in_store(spec, state):
|
||||||
store = spec.get_forkchoice_store(state)
|
store = spec.get_forkchoice_store(state)
|
||||||
time = store.time + spec.SECONDS_PER_SLOT * spec.SLOTS_PER_EPOCH
|
time = store.time + spec.SECONDS_PER_SLOT * (spec.SLOTS_PER_EPOCH + 1)
|
||||||
spec.on_tick(store, time)
|
spec.on_tick(store, time)
|
||||||
|
|
||||||
# move to immediately before next epoch to make block new target
|
# move to immediately before next epoch to make block new target
|
||||||
@ -178,11 +178,63 @@ def test_on_attestation_target_not_in_store(spec, state):
|
|||||||
run_on_attestation(spec, state, store, attestation, False)
|
run_on_attestation(spec, state, store, attestation, False)
|
||||||
|
|
||||||
|
|
||||||
|
@with_all_phases
|
||||||
|
@spec_state_test
|
||||||
|
def test_on_attestation_target_checkpoint_not_in_store(spec, state):
|
||||||
|
store = spec.get_forkchoice_store(state)
|
||||||
|
time = store.time + spec.SECONDS_PER_SLOT * (spec.SLOTS_PER_EPOCH + 1)
|
||||||
|
spec.on_tick(store, time)
|
||||||
|
|
||||||
|
# move to immediately before next epoch to make block new target
|
||||||
|
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)
|
||||||
|
|
||||||
|
# add target block to store
|
||||||
|
spec.on_block(store, signed_target_block)
|
||||||
|
|
||||||
|
# target checkpoint state is not yet in store
|
||||||
|
|
||||||
|
attestation = get_valid_attestation(spec, state, slot=target_block.slot, signed=True)
|
||||||
|
assert attestation.data.target.root == target_block.hash_tree_root()
|
||||||
|
|
||||||
|
run_on_attestation(spec, state, store, attestation)
|
||||||
|
|
||||||
|
|
||||||
|
@with_all_phases
|
||||||
|
@spec_state_test
|
||||||
|
def test_on_attestation_target_checkpoint_not_in_store_diff_slot(spec, state):
|
||||||
|
store = spec.get_forkchoice_store(state)
|
||||||
|
time = store.time + spec.SECONDS_PER_SLOT * (spec.SLOTS_PER_EPOCH + 1)
|
||||||
|
spec.on_tick(store, time)
|
||||||
|
|
||||||
|
# move to two slots before next epoch to make target block one before an empty slot
|
||||||
|
next_epoch = spec.get_current_epoch(state) + 1
|
||||||
|
transition_to(spec, state, spec.compute_start_slot_at_epoch(next_epoch) - 2)
|
||||||
|
|
||||||
|
target_block = build_empty_block_for_next_slot(spec, state)
|
||||||
|
signed_target_block = state_transition_and_sign_block(spec, state, target_block)
|
||||||
|
|
||||||
|
# add target block to store
|
||||||
|
spec.on_block(store, signed_target_block)
|
||||||
|
|
||||||
|
# target checkpoint state is not yet in store
|
||||||
|
|
||||||
|
attestation_slot = target_block.slot + 1
|
||||||
|
transition_to(spec, state, attestation_slot)
|
||||||
|
attestation = get_valid_attestation(spec, state, slot=attestation_slot, signed=True)
|
||||||
|
assert attestation.data.target.root == target_block.hash_tree_root()
|
||||||
|
|
||||||
|
run_on_attestation(spec, state, store, attestation)
|
||||||
|
|
||||||
|
|
||||||
@with_all_phases
|
@with_all_phases
|
||||||
@spec_state_test
|
@spec_state_test
|
||||||
def test_on_attestation_beacon_block_not_in_store(spec, state):
|
def test_on_attestation_beacon_block_not_in_store(spec, state):
|
||||||
store = spec.get_forkchoice_store(state)
|
store = spec.get_forkchoice_store(state)
|
||||||
time = store.time + spec.SECONDS_PER_SLOT * spec.SLOTS_PER_EPOCH
|
time = store.time + spec.SECONDS_PER_SLOT * (spec.SLOTS_PER_EPOCH + 1)
|
||||||
spec.on_tick(store, time)
|
spec.on_tick(store, time)
|
||||||
|
|
||||||
# move to immediately before next epoch to make block new target
|
# move to immediately before next epoch to make block new target
|
||||||
|
@ -22,7 +22,7 @@ def run_on_shard_block(spec, store, shard_store, signed_block, valid=True):
|
|||||||
assert False
|
assert False
|
||||||
|
|
||||||
spec.on_shard_block(store, shard_store, signed_block)
|
spec.on_shard_block(store, shard_store, signed_block)
|
||||||
assert shard_store.blocks[hash_tree_root(signed_block.message)] == signed_block.message
|
assert shard_store.signed_blocks[hash_tree_root(signed_block.message)] == signed_block
|
||||||
|
|
||||||
|
|
||||||
def apply_shard_block(spec, store, shard_store, beacon_parent_state, shard_blocks_buffer):
|
def apply_shard_block(spec, store, shard_store, beacon_parent_state, shard_blocks_buffer):
|
||||||
@ -41,10 +41,7 @@ def apply_shard_block(spec, store, shard_store, beacon_parent_state, shard_block
|
|||||||
|
|
||||||
|
|
||||||
def check_pending_shard_blocks(spec, store, shard_store, shard_blocks_buffer):
|
def check_pending_shard_blocks(spec, store, shard_store, shard_blocks_buffer):
|
||||||
pending_shard_blocks = [
|
pending_shard_blocks = spec.get_pending_shard_blocks(store, shard_store)
|
||||||
spec.SignedShardBlock(message=b)
|
|
||||||
for b in spec.get_pending_shard_blocks(store, shard_store)
|
|
||||||
]
|
|
||||||
assert pending_shard_blocks == shard_blocks_buffer
|
assert pending_shard_blocks == shard_blocks_buffer
|
||||||
|
|
||||||
|
|
||||||
@ -72,7 +69,7 @@ def apply_shard_and_beacon(spec, state, store, shard_store, shard_blocks_buffer)
|
|||||||
shard_transitions = get_shard_transitions(
|
shard_transitions = get_shard_transitions(
|
||||||
spec,
|
spec,
|
||||||
state,
|
state,
|
||||||
shard_blocks={shard: shard_blocks_buffer},
|
shard_block_dict={shard: shard_blocks_buffer},
|
||||||
)
|
)
|
||||||
shard_transition = shard_transitions[shard]
|
shard_transition = shard_transitions[shard]
|
||||||
attestation = get_valid_on_time_attestation(
|
attestation = get_valid_on_time_attestation(
|
||||||
|
@ -83,14 +83,14 @@ def build_attestation_data(spec, state, slot, index, shard=None, shard_transitio
|
|||||||
attestation_data.shard = shard
|
attestation_data.shard = shard
|
||||||
|
|
||||||
if shard_transition is not None:
|
if shard_transition is not None:
|
||||||
lastest_shard_data_root_index = len(shard_transition.shard_data_roots) - 1
|
last_offset_index = len(shard_transition.shard_data_roots) - 1
|
||||||
attestation_data.shard_head_root = shard_transition.shard_data_roots[lastest_shard_data_root_index]
|
attestation_data.shard_head_root = shard_transition.shard_states[last_offset_index].latest_block_root
|
||||||
attestation_data.shard_transition_root = shard_transition.hash_tree_root()
|
attestation_data.shard_transition_root = shard_transition.hash_tree_root()
|
||||||
else:
|
else:
|
||||||
if on_time:
|
if on_time:
|
||||||
shard_transition = spec.get_shard_transition(state, shard, shard_blocks=[])
|
shard_transition = spec.get_shard_transition(state, shard, shard_blocks=[])
|
||||||
lastest_shard_data_root_index = len(shard_transition.shard_data_roots) - 1
|
last_offset_index = len(shard_transition.shard_data_roots) - 1
|
||||||
attestation_data.shard_head_root = shard_transition.shard_data_roots[lastest_shard_data_root_index]
|
attestation_data.shard_head_root = shard_transition.shard_states[last_offset_index].latest_block_root
|
||||||
attestation_data.shard_transition_root = shard_transition.hash_tree_root()
|
attestation_data.shard_transition_root = shard_transition.hash_tree_root()
|
||||||
else:
|
else:
|
||||||
attestation_data.shard_head_root = state.shard_states[shard].latest_block_root
|
attestation_data.shard_head_root = state.shard_states[shard].latest_block_root
|
||||||
|
@ -172,7 +172,7 @@ def get_sample_shard_transition(spec, start_slot, block_lengths):
|
|||||||
start_slot=start_slot,
|
start_slot=start_slot,
|
||||||
shard_block_lengths=block_lengths,
|
shard_block_lengths=block_lengths,
|
||||||
shard_data_roots=b,
|
shard_data_roots=b,
|
||||||
shard_states=[spec.Root() for x in block_lengths],
|
shard_states=[spec.ShardState() for x in block_lengths],
|
||||||
proposer_signature_aggregate=spec.BLSSignature(),
|
proposer_signature_aggregate=spec.BLSSignature(),
|
||||||
)
|
)
|
||||||
return shard_transition
|
return shard_transition
|
||||||
|
@ -30,7 +30,7 @@ def build_shard_block(spec,
|
|||||||
slot = shard_parent_state.slot + 1
|
slot = shard_parent_state.slot + 1
|
||||||
|
|
||||||
if body is None:
|
if body is None:
|
||||||
body = b'\x56' * 128
|
body = get_sample_shard_block_body(spec)
|
||||||
|
|
||||||
beacon_state, beacon_parent_root = get_state_and_beacon_parent_root_at_slot(spec, beacon_state, slot)
|
beacon_state, beacon_parent_root = get_state_and_beacon_parent_root_at_slot(spec, beacon_state, slot)
|
||||||
proposer_index = spec.get_shard_proposer_index(beacon_state, slot, shard)
|
proposer_index = spec.get_shard_proposer_index(beacon_state, slot, shard)
|
||||||
@ -52,10 +52,10 @@ def build_shard_block(spec,
|
|||||||
return signed_block
|
return signed_block
|
||||||
|
|
||||||
|
|
||||||
def get_shard_transitions(spec, parent_beacon_state, shard_blocks):
|
def get_shard_transitions(spec, parent_beacon_state, shard_block_dict):
|
||||||
shard_transitions = [spec.ShardTransition()] * spec.MAX_SHARDS
|
shard_transitions = [spec.ShardTransition()] * spec.MAX_SHARDS
|
||||||
on_time_slot = parent_beacon_state.slot + 1
|
on_time_slot = parent_beacon_state.slot + 1
|
||||||
for shard, blocks in shard_blocks.items():
|
for shard, blocks in shard_block_dict.items():
|
||||||
shard_transition = spec.get_shard_transition(parent_beacon_state, shard, blocks)
|
shard_transition = spec.get_shard_transition(parent_beacon_state, shard, blocks)
|
||||||
offset_slots = spec.compute_offset_slots(
|
offset_slots = spec.compute_offset_slots(
|
||||||
spec.get_latest_slot_for_shard(parent_beacon_state, shard),
|
spec.get_latest_slot_for_shard(parent_beacon_state, shard),
|
||||||
@ -81,3 +81,8 @@ def get_committee_index_of_shard(spec, state, slot, shard): # Optional[Committe
|
|||||||
if (start_shard + committee_index) % active_shard_count == shard:
|
if (start_shard + committee_index) % active_shard_count == shard:
|
||||||
return committee_index
|
return committee_index
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def get_sample_shard_block_body(spec, is_max=False):
|
||||||
|
size = spec.MAX_SHARD_BLOCK_SIZE if is_max else 128
|
||||||
|
return b'\x56' * size
|
||||||
|
@ -197,6 +197,71 @@ 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.
|
# Some of the following tests are phase0 only: phase 1 lists participants with bitfields instead of index list.
|
||||||
|
|
||||||
|
|
||||||
|
@with_phases([PHASE0])
|
||||||
|
@spec_state_test
|
||||||
|
@always_bls
|
||||||
|
def test_att1_high_index(spec, state):
|
||||||
|
attester_slashing = get_valid_attester_slashing(spec, state, signed_1=True, signed_2=True)
|
||||||
|
|
||||||
|
indices = get_indexed_attestation_participants(spec, attester_slashing.attestation_1)
|
||||||
|
indices.append(spec.ValidatorIndex(len(state.validators))) # off by 1
|
||||||
|
attester_slashing.attestation_1.attesting_indices = indices
|
||||||
|
|
||||||
|
yield from run_attester_slashing_processing(spec, state, attester_slashing, False)
|
||||||
|
|
||||||
|
|
||||||
|
@with_phases([PHASE0])
|
||||||
|
@spec_state_test
|
||||||
|
@always_bls
|
||||||
|
def test_att2_high_index(spec, state):
|
||||||
|
attester_slashing = get_valid_attester_slashing(spec, state, signed_1=True, signed_2=True)
|
||||||
|
|
||||||
|
indices = get_indexed_attestation_participants(spec, attester_slashing.attestation_2)
|
||||||
|
indices.append(spec.ValidatorIndex(len(state.validators))) # off by 1
|
||||||
|
attester_slashing.attestation_2.attesting_indices = indices
|
||||||
|
|
||||||
|
yield from run_attester_slashing_processing(spec, state, attester_slashing, False)
|
||||||
|
|
||||||
|
|
||||||
|
@with_phases([PHASE0])
|
||||||
|
@spec_state_test
|
||||||
|
@always_bls
|
||||||
|
def test_att1_empty_indices(spec, state):
|
||||||
|
attester_slashing = get_valid_attester_slashing(spec, state, signed_1=False, signed_2=True)
|
||||||
|
|
||||||
|
attester_slashing.attestation_1.attesting_indices = []
|
||||||
|
attester_slashing.attestation_1.signature = spec.bls.Z2_SIGNATURE
|
||||||
|
|
||||||
|
yield from run_attester_slashing_processing(spec, state, attester_slashing, False)
|
||||||
|
|
||||||
|
|
||||||
|
@with_phases([PHASE0])
|
||||||
|
@spec_state_test
|
||||||
|
@always_bls
|
||||||
|
def test_att2_empty_indices(spec, state):
|
||||||
|
attester_slashing = get_valid_attester_slashing(spec, state, signed_1=True, signed_2=False)
|
||||||
|
|
||||||
|
attester_slashing.attestation_2.attesting_indices = []
|
||||||
|
attester_slashing.attestation_2.signature = spec.bls.Z2_SIGNATURE
|
||||||
|
|
||||||
|
yield from run_attester_slashing_processing(spec, state, attester_slashing, False)
|
||||||
|
|
||||||
|
|
||||||
|
@with_phases([PHASE0])
|
||||||
|
@spec_state_test
|
||||||
|
@always_bls
|
||||||
|
def test_all_empty_indices(spec, state):
|
||||||
|
attester_slashing = get_valid_attester_slashing(spec, state, signed_1=False, signed_2=False)
|
||||||
|
|
||||||
|
attester_slashing.attestation_1.attesting_indices = []
|
||||||
|
attester_slashing.attestation_1.signature = spec.bls.Z2_SIGNATURE
|
||||||
|
|
||||||
|
attester_slashing.attestation_2.attesting_indices = []
|
||||||
|
attester_slashing.attestation_2.signature = spec.bls.Z2_SIGNATURE
|
||||||
|
|
||||||
|
yield from run_attester_slashing_processing(spec, state, attester_slashing, False)
|
||||||
|
|
||||||
|
|
||||||
@with_phases([PHASE0])
|
@with_phases([PHASE0])
|
||||||
@spec_state_test
|
@spec_state_test
|
||||||
@always_bls
|
@always_bls
|
||||||
|
@ -3,69 +3,208 @@ from eth2spec.test.context import (
|
|||||||
with_all_phases_except,
|
with_all_phases_except,
|
||||||
spec_state_test,
|
spec_state_test,
|
||||||
)
|
)
|
||||||
from eth2spec.test.helpers.attestations import get_valid_on_time_attestation
|
from eth2spec.test.helpers.attestations import (
|
||||||
|
get_valid_attestation,
|
||||||
|
get_valid_on_time_attestation,
|
||||||
|
run_attestation_processing,
|
||||||
|
)
|
||||||
from eth2spec.test.helpers.shard_transitions import run_shard_transitions_processing
|
from eth2spec.test.helpers.shard_transitions import run_shard_transitions_processing
|
||||||
from eth2spec.test.helpers.shard_block import (
|
from eth2spec.test.helpers.shard_block import (
|
||||||
build_shard_block,
|
build_shard_block,
|
||||||
get_shard_transitions,
|
get_shard_transitions,
|
||||||
|
get_sample_shard_block_body,
|
||||||
|
get_committee_index_of_shard,
|
||||||
)
|
)
|
||||||
from eth2spec.test.helpers.state import transition_to, transition_to_valid_shard_slot, next_slot
|
from eth2spec.test.helpers.state import transition_to, transition_to_valid_shard_slot, next_slot
|
||||||
|
|
||||||
|
|
||||||
def run_basic_crosslink_tests(spec, state, target_len_offset_slot, valid=True):
|
def get_initial_env(spec, state, target_len_offset_slot):
|
||||||
state = transition_to_valid_shard_slot(spec, state)
|
state = transition_to_valid_shard_slot(spec, state)
|
||||||
committee_index = spec.CommitteeIndex(0)
|
committee_index = spec.CommitteeIndex(0)
|
||||||
init_slot = state.slot
|
target_shard_slot = state.slot + target_len_offset_slot - 1
|
||||||
shard_slot = state.slot + target_len_offset_slot - 1
|
shard = spec.compute_shard_from_committee_index(state, committee_index, target_shard_slot)
|
||||||
shard = spec.compute_shard_from_committee_index(state, committee_index, shard_slot)
|
assert state.shard_states[shard].slot == state.slot - 1
|
||||||
assert state.shard_states[shard].slot == init_slot - 1
|
return state, shard, target_shard_slot
|
||||||
|
|
||||||
# Create SignedShardBlock
|
|
||||||
body = b'\x56' * spec.MAX_SHARD_BLOCK_SIZE
|
|
||||||
shard_block = build_shard_block(spec, state, shard, body=body, slot=state.slot, signed=True)
|
|
||||||
shard_blocks = [shard_block]
|
|
||||||
|
|
||||||
# Transition state latest shard slot
|
def get_attestations_and_shard_transitions(spec, state, shard_block_dict):
|
||||||
transition_to(spec, state, shard_slot)
|
shard_transitions = get_shard_transitions(spec, state, shard_block_dict)
|
||||||
# Create a shard_transitions that would be included at beacon block `state.slot + target_len_offset_slot`
|
attestations = [
|
||||||
shard_transitions = get_shard_transitions(
|
get_valid_on_time_attestation(
|
||||||
spec,
|
spec, state,
|
||||||
state,
|
index=get_committee_index_of_shard(spec, state, state.slot, shard),
|
||||||
shard_blocks={shard: shard_blocks},
|
|
||||||
)
|
|
||||||
shard_transition = shard_transitions[shard]
|
|
||||||
attestation = get_valid_on_time_attestation(
|
|
||||||
spec,
|
|
||||||
state,
|
|
||||||
index=committee_index,
|
|
||||||
shard_transition=shard_transition,
|
shard_transition=shard_transition,
|
||||||
signed=False,
|
signed=True,
|
||||||
)
|
)
|
||||||
|
for shard, shard_transition in enumerate(shard_transitions)
|
||||||
|
if shard_transition != spec.ShardTransition()
|
||||||
|
]
|
||||||
|
return attestations, shard_transitions
|
||||||
|
|
||||||
|
|
||||||
|
def is_full_crosslink(spec, state):
|
||||||
|
epoch = spec.compute_epoch_at_slot(state.slot)
|
||||||
|
return spec.get_committee_count_per_slot(state, epoch) >= spec.get_active_shard_count(state)
|
||||||
|
|
||||||
|
|
||||||
|
def run_successful_crosslink_tests(spec, state, target_len_offset_slot):
|
||||||
|
state, shard, target_shard_slot = get_initial_env(spec, state, target_len_offset_slot)
|
||||||
|
init_slot = state.slot
|
||||||
|
|
||||||
|
# Create SignedShardBlock at init_slot
|
||||||
|
shard_block = build_shard_block(
|
||||||
|
spec, state, shard,
|
||||||
|
slot=init_slot, body=get_sample_shard_block_body(spec, is_max=True), signed=True
|
||||||
|
)
|
||||||
|
|
||||||
|
# Transition state to target shard slot
|
||||||
|
transition_to(spec, state, target_shard_slot)
|
||||||
|
|
||||||
|
# Create a shard_transitions that would be included at beacon block `target_shard_slot + 1`
|
||||||
|
shard_block_dict = {shard: [shard_block]}
|
||||||
|
attestations, shard_transitions = get_attestations_and_shard_transitions(spec, state, shard_block_dict)
|
||||||
|
|
||||||
next_slot(spec, state)
|
next_slot(spec, state)
|
||||||
|
|
||||||
|
for attestation in attestations:
|
||||||
|
_, _, _ = run_attestation_processing(spec, state, attestation)
|
||||||
|
|
||||||
|
_, winning_roots = spec.get_shard_winning_roots(state, attestations)
|
||||||
|
assert len(winning_roots) == 1
|
||||||
|
shard_transition = shard_transitions[shard]
|
||||||
|
assert winning_roots[0] == shard_transition.hash_tree_root()
|
||||||
|
|
||||||
pre_gasprice = state.shard_states[shard].gasprice
|
pre_gasprice = state.shard_states[shard].gasprice
|
||||||
|
pre_shard_states = state.shard_states.copy()
|
||||||
|
yield from run_shard_transitions_processing(spec, state, shard_transitions, attestations)
|
||||||
|
|
||||||
transition_to(spec, state, init_slot + target_len_offset_slot)
|
for index, shard_state in enumerate(state.shard_states):
|
||||||
pre_shard_state = state.shard_states[shard]
|
if index == shard:
|
||||||
yield from run_shard_transitions_processing(spec, state, shard_transitions, [attestation], valid=valid)
|
assert shard_state != pre_shard_states[index]
|
||||||
|
|
||||||
if valid:
|
|
||||||
shard_state = state.shard_states[shard]
|
|
||||||
assert shard_state != pre_shard_state
|
|
||||||
assert shard_state == shard_transition.shard_states[len(shard_transition.shard_states) - 1]
|
assert shard_state == shard_transition.shard_states[len(shard_transition.shard_states) - 1]
|
||||||
assert shard_state.latest_block_root == shard_block.message.hash_tree_root()
|
assert shard_state.latest_block_root == shard_block.message.hash_tree_root()
|
||||||
if target_len_offset_slot == 1:
|
if target_len_offset_slot == 1:
|
||||||
assert shard_state.gasprice > pre_gasprice
|
assert shard_state.gasprice > pre_gasprice
|
||||||
|
else:
|
||||||
|
assert shard_state == pre_shard_states[index]
|
||||||
|
|
||||||
|
for pending_attestation in state.current_epoch_attestations:
|
||||||
|
assert bool(pending_attestation.crosslink_success) is True
|
||||||
|
|
||||||
|
|
||||||
@with_all_phases_except([PHASE0])
|
@with_all_phases_except([PHASE0])
|
||||||
@spec_state_test
|
@spec_state_test
|
||||||
def test_basic_crosslinks(spec, state):
|
def test_basic_crosslinks(spec, state):
|
||||||
# NOTE: this test is only for full crosslink (minimal config), not for mainnet
|
if not is_full_crosslink(spec, state):
|
||||||
yield from run_basic_crosslink_tests(spec, state, target_len_offset_slot=1, valid=True)
|
# Skip this test
|
||||||
|
return
|
||||||
|
|
||||||
|
yield from run_successful_crosslink_tests(spec, state, target_len_offset_slot=1)
|
||||||
|
|
||||||
|
|
||||||
@with_all_phases_except([PHASE0])
|
@with_all_phases_except([PHASE0])
|
||||||
@spec_state_test
|
@spec_state_test
|
||||||
def test_multiple_offset_slots(spec, state):
|
def test_multiple_offset_slots(spec, state):
|
||||||
# NOTE: this test is only for full crosslink (minimal config), not for mainnet
|
if not is_full_crosslink(spec, state):
|
||||||
yield from run_basic_crosslink_tests(spec, state, target_len_offset_slot=2, valid=True)
|
# Skip this test
|
||||||
|
return
|
||||||
|
|
||||||
|
yield from run_successful_crosslink_tests(spec, state, target_len_offset_slot=2)
|
||||||
|
|
||||||
|
|
||||||
|
@with_all_phases_except([PHASE0])
|
||||||
|
@spec_state_test
|
||||||
|
def test_no_winning_root(spec, state):
|
||||||
|
if not is_full_crosslink(spec, state):
|
||||||
|
# Skip this test
|
||||||
|
return
|
||||||
|
|
||||||
|
state, shard, target_shard_slot = get_initial_env(spec, state, target_len_offset_slot=1)
|
||||||
|
init_slot = state.slot
|
||||||
|
|
||||||
|
# Create SignedShardBlock at init_slot
|
||||||
|
shard_block = build_shard_block(
|
||||||
|
spec, state, shard,
|
||||||
|
slot=init_slot, body=get_sample_shard_block_body(spec, is_max=True), signed=True
|
||||||
|
)
|
||||||
|
|
||||||
|
# Transition state to target shard slot
|
||||||
|
transition_to(spec, state, target_shard_slot)
|
||||||
|
|
||||||
|
# Create a shard_transitions that would be included at beacon block `target_shard_slot + 1`
|
||||||
|
shard_transitions = get_shard_transitions(spec, state, {shard: [shard_block]})
|
||||||
|
shard_transition = shard_transitions[shard]
|
||||||
|
committee_index = get_committee_index_of_shard(spec, state, state.slot, shard)
|
||||||
|
attestation = get_valid_attestation(
|
||||||
|
spec, state,
|
||||||
|
index=committee_index,
|
||||||
|
shard_transition=shard_transition,
|
||||||
|
# Decrease attested participants to 1/3 committee
|
||||||
|
filter_participant_set=lambda committee: set(list(committee)[:len(committee) // 3]),
|
||||||
|
signed=True,
|
||||||
|
on_time=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
next_slot(spec, state)
|
||||||
|
|
||||||
|
_, _, _ = run_attestation_processing(spec, state, attestation)
|
||||||
|
|
||||||
|
_, winning_roots = spec.get_shard_winning_roots(state, [attestation])
|
||||||
|
assert len(winning_roots) == 0
|
||||||
|
|
||||||
|
# No winning root, shard_transitions[shard] is empty
|
||||||
|
shard_transitions = [spec.ShardTransition()] * spec.MAX_SHARDS
|
||||||
|
pre_shard_states = state.shard_states.copy()
|
||||||
|
yield from run_shard_transitions_processing(spec, state, shard_transitions, [attestation])
|
||||||
|
|
||||||
|
for pending_attestation in state.current_epoch_attestations:
|
||||||
|
assert bool(pending_attestation.crosslink_success) is False
|
||||||
|
|
||||||
|
assert state.shard_states == pre_shard_states
|
||||||
|
|
||||||
|
|
||||||
|
@with_all_phases_except([PHASE0])
|
||||||
|
@spec_state_test
|
||||||
|
def test_wrong_shard_transition_root(spec, state):
|
||||||
|
if not is_full_crosslink(spec, state):
|
||||||
|
# Skip this test
|
||||||
|
return
|
||||||
|
|
||||||
|
state, shard, target_shard_slot = get_initial_env(spec, state, target_len_offset_slot=1)
|
||||||
|
init_slot = state.slot
|
||||||
|
|
||||||
|
# Create SignedShardBlock at init_slot
|
||||||
|
shard_block = build_shard_block(
|
||||||
|
spec, state, shard,
|
||||||
|
slot=init_slot, body=get_sample_shard_block_body(spec, is_max=True), signed=True
|
||||||
|
)
|
||||||
|
|
||||||
|
# Transition state to target shard slot
|
||||||
|
transition_to(spec, state, target_shard_slot)
|
||||||
|
|
||||||
|
# Create a shard_transitions that would be included at beacon block `target_shard_slot + 1`
|
||||||
|
shard_transitions = get_shard_transitions(spec, state, {shard: [shard_block]})
|
||||||
|
shard_transition = shard_transitions[shard]
|
||||||
|
wrong_shard_transition = shard_transition.copy()
|
||||||
|
wrong_shard_transition.shard_states[shard].gasprice = shard_transition.shard_states[shard].gasprice + 1
|
||||||
|
committee_index = get_committee_index_of_shard(spec, state, state.slot, shard)
|
||||||
|
attestation = get_valid_attestation(
|
||||||
|
spec, state,
|
||||||
|
index=committee_index,
|
||||||
|
shard_transition=wrong_shard_transition,
|
||||||
|
signed=True,
|
||||||
|
on_time=True,
|
||||||
|
)
|
||||||
|
attestations = [attestation]
|
||||||
|
|
||||||
|
next_slot(spec, state)
|
||||||
|
|
||||||
|
run_attestation_processing(spec, state, attestation)
|
||||||
|
|
||||||
|
# Check if winning root != shard_transition.hash_tree_root()
|
||||||
|
_, winning_roots = spec.get_shard_winning_roots(state, attestations)
|
||||||
|
assert len(winning_roots) == 1
|
||||||
|
shard_transition = shard_transitions[shard]
|
||||||
|
assert winning_roots[0] != shard_transition.hash_tree_root()
|
||||||
|
|
||||||
|
yield from run_shard_transitions_processing(spec, state, shard_transitions, attestations, valid=False)
|
||||||
|
@ -19,9 +19,9 @@ def run_beacon_block_with_shard_blocks(spec, state, target_len_offset_slot, comm
|
|||||||
|
|
||||||
body = b'\x56' * spec.MAX_SHARD_BLOCK_SIZE
|
body = b'\x56' * spec.MAX_SHARD_BLOCK_SIZE
|
||||||
shard_block = build_shard_block(spec, state, shard, body=body, slot=state.slot, signed=True)
|
shard_block = build_shard_block(spec, state, shard, body=body, slot=state.slot, signed=True)
|
||||||
shard_blocks: Dict[spec.Shard, Sequence[spec.SignedShardBlock]] = {shard: [shard_block]}
|
shard_block_dict: Dict[spec.Shard, Sequence[spec.SignedShardBlock]] = {shard: [shard_block]}
|
||||||
|
|
||||||
shard_transitions = get_shard_transitions(spec, state, shard_blocks)
|
shard_transitions = get_shard_transitions(spec, state, shard_block_dict)
|
||||||
attestations = [
|
attestations = [
|
||||||
get_valid_on_time_attestation(
|
get_valid_on_time_attestation(
|
||||||
spec,
|
spec,
|
||||||
@ -30,7 +30,7 @@ def run_beacon_block_with_shard_blocks(spec, state, target_len_offset_slot, comm
|
|||||||
shard_transition=shard_transitions[shard],
|
shard_transition=shard_transitions[shard],
|
||||||
signed=True,
|
signed=True,
|
||||||
)
|
)
|
||||||
for shard in shard_blocks.keys()
|
for shard in shard_block_dict.keys()
|
||||||
]
|
]
|
||||||
|
|
||||||
beacon_block = build_empty_block(spec, state, slot=state.slot + 1)
|
beacon_block = build_empty_block(spec, state, slot=state.slot + 1)
|
||||||
@ -50,16 +50,16 @@ def run_beacon_block_with_shard_blocks(spec, state, target_len_offset_slot, comm
|
|||||||
|
|
||||||
for shard in range(spec.get_active_shard_count(state)):
|
for shard in range(spec.get_active_shard_count(state)):
|
||||||
post_shard_state = state.shard_states[shard]
|
post_shard_state = state.shard_states[shard]
|
||||||
if shard in shard_blocks:
|
if shard in shard_block_dict:
|
||||||
# Shard state has been changed to state_transition result
|
# Shard state has been changed to state_transition result
|
||||||
assert post_shard_state == shard_transitions[shard].shard_states[
|
assert post_shard_state == shard_transitions[shard].shard_states[
|
||||||
len(shard_transitions[shard].shard_states) - 1
|
len(shard_transitions[shard].shard_states) - 1
|
||||||
]
|
]
|
||||||
assert post_shard_state.slot == state.slot - 1
|
assert post_shard_state.slot == state.slot - 1
|
||||||
if len(shard_blocks[shard]) == 0:
|
if len((shard_block_dict[shard])) == 0:
|
||||||
# `latest_block_root` is the same
|
# `latest_block_root` is the same
|
||||||
assert post_shard_state.latest_block_root == pre_shard_states[shard].latest_block_root
|
assert post_shard_state.latest_block_root == pre_shard_states[shard].latest_block_root
|
||||||
if target_len_offset_slot == 1 and len(shard_blocks) > 0:
|
if target_len_offset_slot == 1 and len(shard_block_dict[shard]) > 0:
|
||||||
assert post_shard_state.gasprice > pre_gasprice
|
assert post_shard_state.gasprice > pre_gasprice
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user