-
Notifications
You must be signed in to change notification settings - Fork 997
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
add previous and current crosslinks #874
Merged
Merged
Changes from 21 commits
Commits
Show all changes
33 commits
Select commit
Hold shift + click to select a range
529cf42
add previous and current crosslinks
djrtwo d8df789
simplify get_winning_root logic
djrtwo 39b4ef3
Merge branch 'dev' into prev-cur-crosslinks
djrtwo 1fa88fb
remove previous crosslink check from process_crosslinks
djrtwo d1af914
Update 0_beacon-chain.md
JustinDrake a790afa
Update 0_beacon-chain.md
JustinDrake 3e6dc59
Update helpers.py
JustinDrake dc325f7
clean up a few things from PR
djrtwo f677af2
Merge branch 'dev' into prev-cur-crosslinks
djrtwo 26df4f4
Merge branch 'dev' into prev-cur-crosslinks
djrtwo 42dc003
add previous_crosslink_root and enforce crosslinks form a chain
djrtwo e246c3f
source_crosslink_root to previous_crosslink_root
djrtwo 71a28aa
fix tests
djrtwo 0a5a5b7
Merge branch 'dev' into prev-cur-crosslinks
djrtwo a6b3b11
ensure no reward for crosslinks taht can't form a chain
djrtwo 9489ae5
upate validator guide to new crosslink format
djrtwo eafcab7
check crosslinks validity root against previous
djrtwo 3555ab8
Merge branch 'dev' into prev-cur-crosslinks
djrtwo cc68df8
Merge branch 'dev' into prev-cur-crosslinks
hwwhww ef14396
Merge branch 'dev' into prev-cur-crosslinks
djrtwo 8c5f7a5
Merge branch 'dev' into prev-cur-crosslinks
djrtwo fbaf771
Update 0_beacon-chain.md
JustinDrake 9ecafb2
Update 0_beacon-chain.md
JustinDrake 40b55cf
More fixes
JustinDrake cae5c22
Simplify get_crosslink_committee_for_attestation and move to test hel…
JustinDrake 964b4d3
Fix `pyspec/tests/helpers.py`
hwwhww 743193a
nitpicks
hwwhww 4244db9
More cleanups
JustinDrake 2e09f1a
Merge
JustinDrake 172e106
merge
JustinDrake 857d9b2
Merge branch 'dev' into prev-cur-crosslinks
JustinDrake 7a01648
Moar
JustinDrake 741a74a
re-add crosslink tests and ensure pass
djrtwo File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -305,6 +305,8 @@ The types are defined topologically to aid in facilitating an executable version | |
'epoch': 'uint64', | ||
# Shard data since the previous crosslink | ||
'crosslink_data_root': 'bytes32', | ||
# Root of the previous crosslink | ||
'previous_crosslink_root': 'bytes32', | ||
} | ||
``` | ||
|
||
|
@@ -336,7 +338,7 @@ The types are defined topologically to aid in facilitating an executable version | |
|
||
# Crosslink vote | ||
'shard': 'uint64', | ||
'previous_crosslink': Crosslink, | ||
'previous_crosslink_root': 'bytes32', | ||
'crosslink_data_root': 'bytes32', | ||
} | ||
``` | ||
|
@@ -588,7 +590,8 @@ The types are defined topologically to aid in facilitating an executable version | |
'finalized_root': 'bytes32', | ||
|
||
# Recent state | ||
'latest_crosslinks': [Crosslink, SHARD_COUNT], | ||
'current_crosslinks': [Crosslink, SHARD_COUNT], | ||
'previous_crosslinks': [Crosslink, SHARD_COUNT], | ||
'latest_block_roots': ['bytes32', SLOTS_PER_HISTORICAL_ROOT], | ||
'latest_state_roots': ['bytes32', SLOTS_PER_HISTORICAL_ROOT], | ||
'latest_active_index_roots': ['bytes32', LATEST_ACTIVE_INDEX_ROOTS_LENGTH], | ||
|
@@ -1010,6 +1013,7 @@ def get_crosslink_committee_for_attestation(state: BeaconState, | |
""" | ||
Return the crosslink committee corresponding to ``attestation_data``. | ||
""" | ||
# Find the committee in the list with the desired shard | ||
crosslink_committees = get_crosslink_committees_at_slot(state, attestation_data.slot) | ||
|
||
# Find the committee in the list with the desired shard | ||
|
@@ -1444,7 +1448,8 @@ def get_genesis_beacon_state(genesis_validator_deposits: List[Deposit], | |
finalized_root=ZERO_HASH, | ||
|
||
# Recent state | ||
latest_crosslinks=Vector([Crosslink(epoch=GENESIS_EPOCH, crosslink_data_root=ZERO_HASH) for _ in range(SHARD_COUNT)]), | ||
current_crosslinks=Vector([Crosslink(epoch=GENESIS_EPOCH, crosslink_data_root=ZERO_HASH, previous_crosslink_root=ZERO_HASH) for _ in range(SHARD_COUNT)]), | ||
previous_crosslinks=Vector([Crosslink(epoch=GENESIS_EPOCH, crosslink_data_root=ZERO_HASH, previous_crosslink_root=ZERO_HASH) for _ in range(SHARD_COUNT)]), | ||
latest_block_roots=Vector([ZERO_HASH for _ in range(SLOTS_PER_HISTORICAL_ROOT)]), | ||
latest_state_roots=Vector([ZERO_HASH for _ in range(SLOTS_PER_HISTORICAL_ROOT)]), | ||
latest_active_index_roots=Vector([ZERO_HASH for _ in range(LATEST_ACTIVE_INDEX_ROOTS_LENGTH)]), | ||
|
@@ -1646,25 +1651,28 @@ def get_previous_epoch_matching_head_attestations(state: BeaconState) -> List[Pe | |
**Note**: Total balances computed for the previous epoch might be marginally different than the actual total balances during the previous epoch transition. Due to the tight bound on validator churn each epoch and small per-epoch rewards/penalties, the potential balance difference is very low and only marginally affects consensus safety. | ||
|
||
```python | ||
def get_winning_root_and_participants(state: BeaconState, shard: Shard) -> Tuple[Bytes32, List[ValidatorIndex]]: | ||
all_attestations = state.current_epoch_attestations + state.previous_epoch_attestations | ||
valid_attestations = [ | ||
a for a in all_attestations if a.data.previous_crosslink == state.latest_crosslinks[shard] | ||
] | ||
all_roots = [a.data.crosslink_data_root for a in valid_attestations] | ||
def get_winning_root_and_participants(state: BeaconState, slot: Slot, shard: Shard) -> Tuple[Bytes32, Bytes32, List[ValidatorIndex]]: | ||
attestations = state.current_epoch_attestations if slot_to_epoch(slot) == get_current_epoch(state) else state.previous_epoch_attestations | ||
|
||
valid_attestations = [a for a in attestations if a.data.shard == shard] | ||
all_roots = [(a.data.crosslink_data_root, a.data.previous_crosslink_root) for a in valid_attestations] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ditto, alternatively: crosslink_candidates = [Crosslink(epoch=FAR_FUTURE_EPOCH, crosslink_data_root=a.data.crosslink_data_root, previous_crosslink_root=a.data.previous_crosslink_root) for a in valid_attestations] |
||
|
||
# handle when no attestations for shard available | ||
if len(all_roots) == 0: | ||
return ZERO_HASH, [] | ||
return ZERO_HASH, ZERO_HASH, [] | ||
|
||
def get_attestations_for(root) -> List[PendingAttestation]: | ||
return [a for a in valid_attestations if a.data.crosslink_data_root == root] | ||
|
||
# Winning crosslink root is the root with the most votes for it, ties broken in favor of | ||
# lexicographically higher hash | ||
winning_root = max(all_roots, key=lambda r: (get_attesting_balance(state, get_attestations_for(r)), r)) | ||
winning_root, previous_crosslink_root = max(all_roots, key=lambda r: (get_attesting_balance(state, get_attestations_for(r[0])), r[0])) | ||
|
||
return winning_root, get_unslashed_attesting_indices(state, get_attestations_for(winning_root)) | ||
return ( | ||
winning_root, | ||
previous_crosslink_root, | ||
get_unslashed_attesting_indices(state, get_attestations_for(winning_root)), | ||
) | ||
``` | ||
|
||
```python | ||
|
@@ -1727,17 +1735,21 @@ Run the following function: | |
|
||
```python | ||
def process_crosslinks(state: BeaconState) -> None: | ||
state.previous_crosslinks = [crosslink for crosslink in state.current_crosslinks] | ||
|
||
previous_epoch = get_previous_epoch(state) | ||
next_epoch = get_current_epoch(state) + 1 | ||
for slot in range(get_epoch_start_slot(previous_epoch), get_epoch_start_slot(next_epoch)): | ||
for crosslink_committee, shard in get_crosslink_committees_at_slot(state, slot): | ||
winning_root, participants = get_winning_root_and_participants(state, shard) | ||
winning_root, previous_crosslink_root, participants = get_winning_root_and_participants(state, slot, shard) | ||
expected_crosslink_root = hash_tree_root(state.current_crosslinks[shard]) | ||
participating_balance = get_total_balance(state, participants) | ||
total_balance = get_total_balance(state, crosslink_committee) | ||
if 3 * participating_balance >= 2 * total_balance: | ||
state.latest_crosslinks[shard] = Crosslink( | ||
epoch=min(slot_to_epoch(slot), state.latest_crosslinks[shard].epoch + MAX_CROSSLINK_EPOCHS), | ||
crosslink_data_root=winning_root | ||
if previous_crosslink_root == expected_crosslink_root and 3 * participating_balance >= 2 * total_balance: | ||
state.current_crosslinks[shard] = Crosslink( | ||
epoch=min(slot_to_epoch(slot), state.current_crosslinks[shard].epoch + MAX_CROSSLINK_EPOCHS), | ||
crosslink_data_root=winning_root, | ||
previous_crosslink_root=previous_crosslink_root, | ||
) | ||
``` | ||
|
||
|
@@ -1830,7 +1842,14 @@ def get_crosslink_deltas(state: BeaconState) -> Tuple[List[Gwei], List[Gwei]]: | |
current_epoch_start_slot = get_epoch_start_slot(get_current_epoch(state)) | ||
for slot in range(previous_epoch_start_slot, current_epoch_start_slot): | ||
for crosslink_committee, shard in get_crosslink_committees_at_slot(state, slot): | ||
winning_root, participants = get_winning_root_and_participants(state, shard) | ||
winning_root, previous_crosslink_root, participants = get_winning_root_and_participants(state, slot, shard) | ||
|
||
# do not count as success if winning_root did not or cannot form a chain | ||
attempted_crosslink = Crosslink(epoch=slot_to_epoch(slot), crosslink_data_root=winning_root, previous_crosslink_root=previous_crosslink_root) | ||
actual_crosslink_root = hash_tree_root(state.previous_crosslinks[shard]) | ||
if not actual_crosslink_root in {previous_crosslink_root, hash_tree_root(attempted_crosslink)}: | ||
participants = [] | ||
|
||
participating_balance = get_total_balance(state, participants) | ||
total_balance = get_total_balance(state, crosslink_committee) | ||
for index in crosslink_committee: | ||
|
@@ -2105,32 +2124,26 @@ def process_attestation(state: BeaconState, attestation: Attestation) -> None: | |
Process ``Attestation`` operation. | ||
Note that this function mutates ``state``. | ||
""" | ||
assert attestation.data.slot + MIN_ATTESTATION_INCLUSION_DELAY <= state.slot <= attestation.data.slot + SLOTS_PER_EPOCH | ||
data = attestation.data | ||
min_slot = state.slot - SLOTS_PER_EPOCH if get_current_epoch(state) > GENESIS_EPOCH else GENESIS_SLOT | ||
assert min_slot <= data.slot <= state.slot - MIN_ATTESTATION_INCLUSION_DELAY | ||
|
||
# Check target epoch, source epoch, and source root | ||
target_epoch = slot_to_epoch(attestation.data.slot) | ||
assert (target_epoch, attestation.data.source_epoch, attestation.data.source_root) in { | ||
(get_current_epoch(state), state.current_justified_epoch, state.current_justified_root), | ||
(get_previous_epoch(state), state.previous_justified_epoch, state.previous_justified_root), | ||
# Check target epoch, source epoch, source root, and source crosslink | ||
target_epoch = slot_to_epoch(data.slot) | ||
assert (target_epoch, data.source_epoch, data.source_root, data.previous_crosslink_root) in { | ||
(get_current_epoch(state), state.current_justified_epoch, state.current_justified_root, hash_tree_root(state.current_crosslinks[data.shard])), | ||
(get_previous_epoch(state), state.previous_justified_epoch, state.previous_justified_root, hash_tree_root(state.previous_crosslinks[data.shard])), | ||
} | ||
|
||
# Check crosslink data | ||
assert attestation.data.crosslink_data_root == ZERO_HASH # [to be removed in phase 1] | ||
assert state.latest_crosslinks[attestation.data.shard] in { | ||
attestation.data.previous_crosslink, # Case 1: latest crosslink matches previous crosslink | ||
Crosslink( # Case 2: latest crosslink matches current crosslink | ||
crosslink_data_root=attestation.data.crosslink_data_root, | ||
epoch=min(slot_to_epoch(attestation.data.slot), | ||
attestation.data.previous_crosslink.epoch + MAX_CROSSLINK_EPOCHS) | ||
), | ||
} | ||
# Check crosslink data root | ||
assert data.crosslink_data_root == ZERO_HASH # [to be removed in phase 1] | ||
|
||
# Check signature and bitfields | ||
assert verify_indexed_attestation(state, convert_to_indexed(state, attestation)) | ||
|
||
# Cache pending attestation | ||
pending_attestation = PendingAttestation( | ||
data=attestation.data, | ||
data=data, | ||
aggregation_bitfield=attestation.aggregation_bitfield, | ||
inclusion_slot=state.slot | ||
) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It now returns
winning_root, previous_crosslink_root, participants
. Alternatively, we can reuseCrosslink
by creatingCrosslink(epoch=FAR_FUTURE_EPOCH, crosslink_data_root=winning_root, previous_crosslink_root=previous_crosslink_root)
. So we can change it function to:There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's what I did 👍