Skip to content

Commit

Permalink
Update EIP-7688: add additional beacon chain changes
Browse files Browse the repository at this point in the history
  • Loading branch information
wemeetagain committed May 29, 2024
1 parent f8adac6 commit 1edf0e5
Showing 1 changed file with 241 additions and 0 deletions.
241 changes: 241 additions & 0 deletions EIPS/eip-7688.md
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,247 @@ class BeaconState(Variant[StableBeaconState]):
... # Additional features from the fork that introduces this EIP
```

### Additional consensus spec changes

Due to changing the merkle tree depth of `BeaconState` and `BeaconBlockBody`, several `_GINDEX` and `_PROOF_DEPTH` constants need to be redefined.

Changes come from two sources, Altair light client proofs and Deneb kzg commitment inclusion proofs.

#### Altair

##### Constants

*[New in EIP7688]*

| Name | Value |
| - | - |
| `FINALIZED_ROOT_GINDEX_STABLE` | `get_generalized_index(StableBeaconState, 'finalized_checkpoint', 'root')` (= 210) |
| `CURRENT_SYNC_COMMITTEE_GINDEX_STABLE` | `get_generalized_index(StableBeaconState, 'current_sync_committee')` (= 108) |

Check failure on line 325 in EIPS/eip-7688.md

View workflow job for this annotation

GitHub Actions / EIP Walidator

proposals must be referenced with the form `EIP-N` (not `EIPN` or `EIP N`)

error[markdown-re-eip-dash]: proposals must be referenced with the form `EIP-N` (not `EIPN` or `EIP N`) --> EIPS/eip-7688.md | 325 | *[New in EIP7688]* | = info: the pattern in question: `(?i)eip[\s]*[0-9]+` = help: see https://ethereum.github.io/eipw/markdown-re-eip-dash/
| `NEXT_SYNC_COMMITTEE_GINDEX_STABLE` | `get_generalized_index(StableBeaconState, 'next_sync_committee')` (= 110) |

##### Redefined types

| Name | SSZ equivalent | Description |
| - | - | - |
| `FinalityBranch` | `Vector[Bytes32, floorlog2(FINALIZED_ROOT_GINDEX_STABLE)]` | Merkle branch of `finalized_checkpoint.root` within `BeaconState` |
| `CurrentSyncCommitteeBranch` | `Vector[Bytes32, floorlog2(CURRENT_SYNC_COMMITTEE_GINDEX_STABLE)]` | Merkle branch of `current_sync_committee` within `BeaconState` |
| `NextSyncCommitteeBranch` | `Vector[Bytes32, floorlog2(NEXT_SYNC_COMMITTEE_GINDEX_STABLE)]` | Merkle branch of `next_sync_committee` within `BeaconState` |

##### Redefined containers

###### `LightClientBootstrap`

```python
class LightClientBootstrap(Container):
# Header matching the requested beacon block root
header: LightClientHeader
# Current sync committee corresponding to `header.beacon.state_root`
current_sync_committee: SyncCommittee
current_sync_committee_branch: CurrentSyncCommitteeBranch # changed in EIP-7688
```

###### `LightClientUpdate`

```python
class LightClientUpdate(Container):
# Header attested to by the sync committee
attested_header: LightClientHeader
# Next sync committee corresponding to `attested_header.beacon.state_root`
next_sync_committee: SyncCommittee
next_sync_committee_branch: NextSyncCommitteeBranch # changed in EIP-7688
# Finalized header corresponding to `attested_header.beacon.state_root`
finalized_header: LightClientHeader
finality_branch: FinalityBranch # changed in EIP-7688
# Sync committee aggregate signature
sync_aggregate: SyncAggregate
# Slot at which the aggregate signature was created (untrusted)
signature_slot: Slot
```

###### `LightClientFinalityUpdate`

```python
class LightClientFinalityUpdate(Container):
# Header attested to by the sync committee
attested_header: LightClientHeader
# Finalized header corresponding to `attested_header.beacon.state_root`
finalized_header: LightClientHeader
finality_branch: FinalityBranch # changed in EIP-7688
# Sync committee aggregate signature
sync_aggregate: SyncAggregate
# Slot at which the aggregate signature was created (untrusted)
signature_slot: Slot
```

###### `LightClientOptimisticUpdate`

```python
class LightClientOptimisticUpdate(Container):
# Header attested to by the sync committee
attested_header: LightClientHeader
# Sync committee aggregate signature
sync_aggregate: SyncAggregate # changed in EIP-7688
# Slot at which the aggregate signature was created (untrusted)
signature_slot: Slot
```

##### Redefined functions


###### `initialize_light_client_store`

```python
def initialize_light_client_store(trusted_block_root: Root,
bootstrap: LightClientBootstrap) -> LightClientStore:
assert is_valid_light_client_header(bootstrap.header)
assert hash_tree_root(bootstrap.header.beacon) == trusted_block_root

assert is_valid_merkle_branch(
leaf=hash_tree_root(bootstrap.current_sync_committee),
branch=bootstrap.current_sync_committee_branch,
depth=floorlog2(CURRENT_SYNC_COMMITTEE_GINDEX_STABLE), # changed in EIP-7688
index=get_subtree_index(CURRENT_SYNC_COMMITTEE_GINDEX_STABLE), # changed in EIP-7688
root=bootstrap.header.beacon.state_root,
)

return LightClientStore(
finalized_header=bootstrap.header,
current_sync_committee=bootstrap.current_sync_committee,
next_sync_committee=SyncCommittee(),
best_valid_update=None,
optimistic_header=bootstrap.header,
previous_max_active_participants=0,
current_max_active_participants=0,
)
```

### `validate_light_client_update`

```python
def validate_light_client_update(store: LightClientStore,
update: LightClientUpdate,
current_slot: Slot,
genesis_validators_root: Root) -> None:
# Verify sync committee has sufficient participants
sync_aggregate = update.sync_aggregate
assert sum(sync_aggregate.sync_committee_bits) >= MIN_SYNC_COMMITTEE_PARTICIPANTS

# Verify update does not skip a sync committee period
assert is_valid_light_client_header(update.attested_header)
update_attested_slot = update.attested_header.beacon.slot
update_finalized_slot = update.finalized_header.beacon.slot
assert current_slot >= update.signature_slot > update_attested_slot >= update_finalized_slot
store_period = compute_sync_committee_period_at_slot(store.finalized_header.beacon.slot)
update_signature_period = compute_sync_committee_period_at_slot(update.signature_slot)
if is_next_sync_committee_known(store):
assert update_signature_period in (store_period, store_period + 1)
else:
assert update_signature_period == store_period

# Verify update is relevant
update_attested_period = compute_sync_committee_period_at_slot(update_attested_slot)
update_has_next_sync_committee = not is_next_sync_committee_known(store) and (
is_sync_committee_update(update) and update_attested_period == store_period
)
assert (
update_attested_slot > store.finalized_header.beacon.slot
or update_has_next_sync_committee
)

# Verify that the `finality_branch`, if present, confirms `finalized_header`
# to match the finalized checkpoint root saved in the state of `attested_header`.
# Note that the genesis finalized checkpoint root is represented as a zero hash.
if not is_finality_update(update):
assert update.finalized_header == LightClientHeader()
else:
if update_finalized_slot == GENESIS_SLOT:
assert update.finalized_header == LightClientHeader()
finalized_root = Bytes32()
else:
assert is_valid_light_client_header(update.finalized_header)
finalized_root = hash_tree_root(update.finalized_header.beacon)
assert is_valid_merkle_branch(
leaf=finalized_root,
branch=update.finality_branch,
depth=floorlog2(FINALIZED_ROOT_GINDEX_STABLE), # changed in EIP-7688
index=get_subtree_index(FINALIZED_ROOT_GINDEX_STABLE), # changed in EIP-7688
root=update.attested_header.beacon.state_root,
)

# Verify that the `next_sync_committee`, if present, actually is the next sync committee saved in the
# state of the `attested_header`
if not is_sync_committee_update(update):
assert update.next_sync_committee == SyncCommittee()
else:
if update_attested_period == store_period and is_next_sync_committee_known(store):
assert update.next_sync_committee == store.next_sync_committee
assert is_valid_merkle_branch(
leaf=hash_tree_root(update.next_sync_committee),
branch=update.next_sync_committee_branch,
depth=floorlog2(NEXT_SYNC_COMMITTEE_GINDEX_STABLE), # changed in EIP-7688
index=get_subtree_index(NEXT_SYNC_COMMITTEE_GINDEX_STABLE), # changed in EIP-7688
root=update.attested_header.beacon.state_root,
)

# Verify sync committee aggregate signature
if update_signature_period == store_period:
sync_committee = store.current_sync_committee
else:
sync_committee = store.next_sync_committee
participant_pubkeys = [
pubkey for (bit, pubkey) in zip(sync_aggregate.sync_committee_bits, sync_committee.pubkeys)
if bit
]
fork_version_slot = max(update.signature_slot, Slot(1)) - Slot(1)
fork_version = compute_fork_version(compute_epoch_at_slot(fork_version_slot))
domain = compute_domain(DOMAIN_SYNC_COMMITTEE, fork_version, genesis_validators_root)
signing_root = compute_signing_root(update.attested_header.beacon, domain)
assert bls.FastAggregateVerify(participant_pubkeys, signing_root, sync_aggregate.sync_committee_signature)
```

#### Deneb

##### Preset

*[New in EIP7688]*

| Name | Value | Description |
|------------------------------------------|-----------------------------------|---------------------------------------------------------------------|
| `KZG_COMMITMENT_INCLUSION_PROOF_DEPTH_STABLE` | `uint64(floorlog2(get_generalized_index(StableBeaconBlockBody, 'blob_kzg_commitments')) + 1 + ceillog2(MAX_BLOB_COMMITMENTS_PER_BLOCK))` (= 18) | <!-- predefined --> Merkle proof depth for `blob_kzg_commitments` list item |

Check failure on line 517 in EIPS/eip-7688.md

View workflow job for this annotation

GitHub Actions / EIP Walidator

proposals must be referenced with the form `EIP-N` (not `EIPN` or `EIP N`)

error[markdown-re-eip-dash]: proposals must be referenced with the form `EIP-N` (not `EIPN` or `EIP N`) --> EIPS/eip-7688.md | 517 | *[New in EIP7688]* | = info: the pattern in question: `(?i)eip[\s]*[0-9]+`

##### Redefined Containers

###### `BlobSidecar`

*[Changed in EIP-7688]*

```python
class BlobSidecar(Container):
index: BlobIndex # Index of blob in block
blob: Blob

Check failure on line 528 in EIPS/eip-7688.md

View workflow job for this annotation

GitHub Actions / EIP Walidator

the first match of the given pattern must be a link

error[markdown-link-first]: the first match of the given pattern must be a link --> EIPS/eip-7688.md | 528 | *[Changed in EIP-7688]* | = info: the pattern in question: `(?i)(?:eip|erc)-[0-9]+` = help: see https://ethereum.github.io/eipw/markdown-link-first/
kzg_commitment: KZGCommitment
kzg_proof: KZGProof # Allows for quick verification of kzg_commitment
signed_block_header: SignedBeaconBlockHeader
kzg_commitment_inclusion_proof: Vector[Bytes32, KZG_COMMITMENT_INCLUSION_PROOF_DEPTH_STABLE] # changed in EIP-7688
```

##### Redefined functions

###### `verify_blob_sidecar_inclusion_proof`

```python
def verify_blob_sidecar_inclusion_proof(blob_sidecar: BlobSidecar) -> bool:
gindex = get_subtree_index(get_generalized_index(BeaconBlockBody, 'blob_kzg_commitments', blob_sidecar.index))
return is_valid_merkle_branch(
leaf=blob_sidecar.kzg_commitment.hash_tree_root(),
branch=blob_sidecar.kzg_commitment_inclusion_proof,
depth=KZG_COMMITMENT_INCLUSION_PROOF_DEPTH_STABLE, # changed in EIP-7688
index=gindex,
root=blob_sidecar.signed_block_header.message.body_root,
)
```

## Rationale

### Best timing?
Expand Down

0 comments on commit 1edf0e5

Please sign in to comment.