update to wrap the union, clean up initialization and typing

This commit is contained in:
protolambda 2021-05-28 21:26:06 +02:00
parent e5521af1f8
commit 38a0f4f211
No known key found for this signature in database
GPG Key ID: EC89FDBB2B4C7623
1 changed files with 57 additions and 45 deletions

View File

@ -33,6 +33,7 @@
- [`ShardBlobReference`](#shardblobreference)
- [`SignedShardBlobReference`](#signedshardblobreference)
- [`ShardProposerSlashing`](#shardproposerslashing)
- [`ShardCommitteeWork`](#shardcommitteework)
- [Helper functions](#helper-functions)
- [Misc](#misc-2)
- [`next_power_of_two`](#next_power_of_two)
@ -183,17 +184,8 @@ class BeaconState(merge.BeaconState): # [extends The Merge state]
previous_epoch_attestations: List[PendingAttestation, MAX_ATTESTATIONS * SLOTS_PER_EPOCH]
current_epoch_attestations: List[PendingAttestation, MAX_ATTESTATIONS * SLOTS_PER_EPOCH]
# [New fields]
# A ring buffer of the latest shard headers per slot. Upon confirmation the data is reduced to just the header.
shard_headers: Vector[
List[
Union[ # See Shard Header Status enum
None, # UNCONFIRMED_SHARD_DATA
DataCommitment, # CONFIRMED_SHARD_DATA
List[PendingShardHeader, MAX_SHARD_HEADERS_PER_SHARD] # PENDING_SHARD_DATA
],
MAX_SHARDS
],
SHARD_STATE_MEMORY_SLOTS]
# A ring buffer of the latest slots, with information per active shard.
shard_buffer: Vector[List[ShardCommitteeWork, MAX_SHARDS], SHARD_STATE_MEMORY_SLOTS]
shard_gasprice: uint64
current_epoch_start_shard: Shard
```
@ -288,6 +280,18 @@ class ShardProposerSlashing(Container):
signed_reference_2: SignedShardBlobReference
```
### `ShardCommitteeWork`
```python
class ShardWork(Container):
# Upon confirmation the data is reduced to just the header.
status: Union[ # See Shard Header Status enum
None, # UNCONFIRMED_SHARD_DATA
DataCommitment, # CONFIRMED_SHARD_DATA
List[PendingShardHeader, MAX_SHARD_HEADERS_PER_SHARD] # PENDING_SHARD_DATA
]
```
## Helper functions
### Misc
@ -359,7 +363,7 @@ def get_active_shard_count(state: BeaconState, epoch: Epoch) -> uint64:
Return the number of active shards.
Note that this puts an upper bound on the number of committees per slot.
"""
return INITIAL_ACTIVE_SHARDS # TODO: use shard_headers from state instead?
return INITIAL_ACTIVE_SHARDS
```
#### `get_shard_committee`
@ -461,6 +465,7 @@ def get_start_shard(state: BeaconState, slot: Slot) -> Shard:
```python
def compute_shard_from_committee_index(state: BeaconState, slot: Slot, index: CommitteeIndex) -> Shard:
active_shards = get_active_shard_count(state, compute_epoch_at_slot(slot))
assert index < active_shards
return Shard((index + get_start_shard(state, slot)) % active_shards)
```
@ -468,8 +473,11 @@ def compute_shard_from_committee_index(state: BeaconState, slot: Slot, index: Co
```python
def compute_committee_index_from_shard(state: BeaconState, slot: Slot, shard: Shard) -> CommitteeIndex:
active_shards = get_active_shard_count(state, compute_epoch_at_slot(slot))
return CommitteeIndex((active_shards + shard - get_start_shard(state, slot)) % active_shards)
epoch = compute_epoch_at_slot(slot)
active_shards = get_active_shard_count(state, epoch)
index = CommitteeIndex((active_shards + shard - get_start_shard(state, slot)) % active_shards)
assert index >= get_committee_count_per_slot(state, epoch)
return index
```
@ -530,20 +538,21 @@ def update_pending_votes(state: BeaconState, attestation: Attestation) -> None:
attestation.data.index,
)
buffer_index = attestation.data.slot % SHARD_STATE_MEMORY_SLOTS
shard_header_status = state.shard_headers[buffer_index][attestation_shard]
committee_work = state.shard_buffer[buffer_index][attestation_shard]
# Skip attestation vote accounting if the header is already confirmed
if shard_header_status.selector == CONFIRMED_SHARD_DATA:
if committee_work.status.selector == CONFIRMED_SHARD_DATA:
return
assert shard_header_status.selector == PENDING_SHARD_DATA
current_headers: Sequence[PendingShardHeader] = shard_header_status.value
# Note that shard-slot combinations without an assigned committee do not have a pending state
assert shard_info.status.selector == PENDING_SHARD_DATA
current_headers: Sequence[PendingShardHeader] = committee_work.status.value
# Find the corresponding header, abort if it cannot be found
header_index = [header.root for header in current_headers].index(attestation.data.shard_header_root)
# Update votes bitfield in the state
pending_header = state.shard_headers[buffer_index][attestation_shard][header_index]
pending_header: PendingShardHeader = state.shard_buffer[buffer_index][attestation_shard][header_index]
for i, bit in enumerate(attestation.aggregation_bits):
if bit:
pending_header.votes[i] = True
@ -554,7 +563,14 @@ def update_pending_votes(state: BeaconState, attestation: Attestation) -> None:
full_committee = get_beacon_committee(state, attestation.data.slot, attestation.data.index)
full_committee_balance = get_total_balance(state, set(full_committee))
if participants_balance * 3 >= full_committee_balance * 2:
state.shard_headers[buffer_index][attestation_shard].change(
if pending_header.commitment == DataCommitment():
# The committee voted to not confirm anything
state.shard_buffer[buffer_index][attestation_shard].change(
selector=UNCONFIRMED_SHARD_DATA,
value=None,
)
else:
state.shard_buffer[buffer_index][attestation_shard].change(
selector=CONFIRMED_SHARD_DATA,
value=pending_header.commitment,
)
@ -577,11 +593,11 @@ def process_shard_header(state: BeaconState, signed_header: SignedShardBlobHeade
assert header.body_summary.beacon_block_root == get_block_root_at_slot(state, header.slot - 1)
# Check that this data is still pending
shard_header_status = state.shard_headers[header.slot % SHARD_STATE_MEMORY_SLOTS][header.slot]
assert shard_header_status.selector == PENDING_SHARD_DATA
committee_work = state.shard_buffer[header.slot % SHARD_STATE_MEMORY_SLOTS][header.slot]
assert committee_work.status.selector == PENDING_SHARD_DATA
# Check that this header is not yet in the pending list
current_headers: Sequence[PendingShardHeader] = shard_header_status.value
current_headers: Sequence[PendingShardHeader] = committee_work.status.value
assert header_root not in [pending_header.root for pending_header in current_headers]
# Verify proposer
@ -610,7 +626,7 @@ def process_shard_header(state: BeaconState, signed_header: SignedShardBlobHeade
)
# Include it in the pending list
state.shard_headers[header.slot % SHARD_STATE_MEMORY_SLOTS][header.slot].append(pending_header)
state.shard_buffer[header.slot % SHARD_STATE_MEMORY_SLOTS][header.slot].append(pending_header)
```
The degree proof works as follows. For a block `B` with length `l` (so `l` values in `[0...l - 1]`, seen as a polynomial `B(X)` which takes these values),
@ -689,9 +705,9 @@ def process_pending_headers(state: BeaconState) -> None:
# Mark stale headers as unconfirmed
for slot in range(previous_epoch_start_slot, previous_epoch_start_slot + SLOTS_PER_EPOCH):
buffer_index = slot % SHARD_STATE_MEMORY_SLOTS
for shard_index in range(len(state.shard_headers[buffer_index])):
if state.shard_headers[buffer_index][shard_index].selector == PENDING_SHARD_DATA:
state.shard_headers[buffer_index][shard_index].change(selector=UNCONFIRMED_SHARD_DATA, value=None)
for shard_index in range(len(state.shard_buffer[buffer_index])):
if state.shard_buffer[buffer_index][shard_index].selector == PENDING_SHARD_DATA:
state.shard_buffer[buffer_index][shard_index].change(selector=UNCONFIRMED_SHARD_DATA, value=None)
```
```python
@ -706,9 +722,9 @@ def charge_confirmed_header_fees(state: BeaconState) -> None:
# Iterate through confirmed shard-headers
for slot in range(previous_epoch_start_slot, previous_epoch_start_slot + SLOTS_PER_EPOCH):
buffer_index = slot % SHARD_STATE_MEMORY_SLOTS
for shard_index in range(len(state.shard_headers[buffer_index])):
shard_header_status = state.shard_headers[buffer_index][shard_index]
if shard_header_status.selector == CONFIRMED_SHARD_DATA:
for shard_index in range(len(state.shard_buffer[buffer_index])):
committee_work = state.shard_buffer[buffer_index][shard_index]
if committee_work.status.selector == CONFIRMED_SHARD_DATA:
# Charge EIP 1559 fee
proposer = get_shard_proposer_index(state, slot, Shard(shard_index))
fee = (
@ -728,7 +744,7 @@ def charge_confirmed_header_fees(state: BeaconState) -> None:
```python
def reset_pending_headers(state: BeaconState) -> None:
# Add dummy "empty" PendingShardHeader (default vote for if no shard header available)
# Add dummy "empty" PendingShardHeader (default vote if no shard header is available)
next_epoch = get_current_epoch(state) + 1
next_epoch_start_slot = compute_start_slot_at_epoch(next_epoch)
committees_per_slot = get_committee_count_per_slot(state, next_epoch)
@ -736,16 +752,17 @@ def reset_pending_headers(state: BeaconState) -> None:
for slot in range(next_epoch_start_slot, next_epoch_start_slot + SLOTS_PER_EPOCH):
buffer_index = slot % SHARD_STATE_MEMORY_SLOTS
if len(state.shard_headers[buffer_index]) < active_shards:
state.shard_headers[buffer_index].extend()
# Reset the shard work tracking
state.shard_buffer[buffer_index] = [ShardCommitteeWork() for _ in range(active_shards)]
start_shard = get_start_shard(state, slot)
for shard_index in range(state.shard_headers[buffer_index]):
for shard_index in range(state.shard_buffer[buffer_index]):
if start_shard <= shard_index < start_shard + committees_per_slot:
# a committee is available, initialize a pending shard-header list
committee_index = CommitteeIndex(shard_index - start_shard)
committee_length = len(get_beacon_committee(state, slot, committee_index))
state.shard_headers[buffer_index][shard_index].change(
state.shard_buffer[buffer_index][shard_index].change(
selector=PENDING_SHARD_DATA,
value=List[PendingShardHeader, MAX_SHARD_HEADERS_PER_SHARD](
PendingShardHeader(
@ -755,12 +772,7 @@ def reset_pending_headers(state: BeaconState) -> None:
)
)
)
else:
# shard is inactive, no committee available.
state.shard_headers[buffer_index][shard_index].change(
selector=UNCONFIRMED_SHARD_DATA,
value=None,
)
# the shard is inactive for this slot otherwise, no committee available, default to UNCONFIRMED_SHARD_DATA.
```
#### Shard epoch increment