Skip to content

Gloas Light Client -- Fork Logic

Introduction

This document describes how to upgrade existing light client objects based on the Electra specification to Gloas. This is necessary when processing pre-Gloas data with a post-Gloas LightClientStore. Note that the data being exchanged over the network protocols uses the original format.

Upgrading light client data

A Gloas LightClientStore can still process earlier light client data. In order to do so, that pre-Gloas data needs to be locally upgraded to Gloas before processing.

def upgrade_lc_header_to_gloas(pre: electra.LightClientHeader) -> LightClientHeader:
    if pre == electra.LightClientHeader():
        return LightClientHeader()

    epoch = compute_epoch_at_slot(pre.beacon.slot)

    if epoch >= DENEB_FORK_EPOCH:
        BLOCK_HASH_GINDEX = get_generalized_index(deneb.ExecutionPayloadHeader, "block_hash")
        return LightClientHeader(
            beacon=pre.beacon,
            execution_block_hash=pre.execution.block_hash,
            execution_branch=ExecutionBranch(
                normalize_merkle_branch(
                    list(compute_merkle_proof(pre.execution, BLOCK_HASH_GINDEX))
                    + list(pre.execution_branch),
                    EXECUTION_BLOCK_HASH_GINDEX_GLOAS,
                )
            ),
        )

    if epoch >= CAPELLA_FORK_EPOCH:
        execution_header = capella.ExecutionPayloadHeader(
            parent_hash=pre.execution.parent_hash,
            fee_recipient=pre.execution.fee_recipient,
            state_root=pre.execution.state_root,
            receipts_root=pre.execution.receipts_root,
            logs_bloom=pre.execution.logs_bloom,
            prev_randao=pre.execution.prev_randao,
            block_number=pre.execution.block_number,
            gas_limit=pre.execution.gas_limit,
            gas_used=pre.execution.gas_used,
            timestamp=pre.execution.timestamp,
            extra_data=pre.execution.extra_data,
            base_fee_per_gas=pre.execution.base_fee_per_gas,
            block_hash=pre.execution.block_hash,
            transactions_root=pre.execution.transactions_root,
            withdrawals_root=pre.execution.withdrawals_root,
        )
        BLOCK_HASH_GINDEX = get_generalized_index(capella.ExecutionPayloadHeader, "block_hash")
        return LightClientHeader(
            beacon=pre.beacon,
            execution_block_hash=pre.execution.block_hash,
            execution_branch=ExecutionBranch(
                normalize_merkle_branch(
                    list(compute_merkle_proof(execution_header, BLOCK_HASH_GINDEX))
                    + list(pre.execution_branch),
                    EXECUTION_BLOCK_HASH_GINDEX_GLOAS,
                )
            ),
        )

    return LightClientHeader(beacon=pre.beacon)
1
2
3
4
5
6
def upgrade_lc_bootstrap_to_gloas(pre: electra.LightClientBootstrap) -> LightClientBootstrap:
    return LightClientBootstrap(
        header=upgrade_lc_header_to_gloas(pre.header),
        current_sync_committee=pre.current_sync_committee,
        current_sync_committee_branch=pre.current_sync_committee_branch,
    )
def upgrade_lc_update_to_gloas(pre: electra.LightClientUpdate) -> LightClientUpdate:
    return LightClientUpdate(
        attested_header=upgrade_lc_header_to_gloas(pre.attested_header),
        next_sync_committee=pre.next_sync_committee,
        next_sync_committee_branch=pre.next_sync_committee_branch,
        finalized_header=upgrade_lc_header_to_gloas(pre.finalized_header),
        finality_branch=pre.finality_branch,
        sync_aggregate=pre.sync_aggregate,
        signature_slot=pre.signature_slot,
    )
def upgrade_lc_finality_update_to_gloas(
    pre: electra.LightClientFinalityUpdate,
) -> LightClientFinalityUpdate:
    return LightClientFinalityUpdate(
        attested_header=upgrade_lc_header_to_gloas(pre.attested_header),
        finalized_header=upgrade_lc_header_to_gloas(pre.finalized_header),
        finality_branch=pre.finality_branch,
        sync_aggregate=pre.sync_aggregate,
        signature_slot=pre.signature_slot,
    )
1
2
3
4
5
6
7
8
def upgrade_lc_optimistic_update_to_gloas(
    pre: electra.LightClientOptimisticUpdate,
) -> LightClientOptimisticUpdate:
    return LightClientOptimisticUpdate(
        attested_header=upgrade_lc_header_to_gloas(pre.attested_header),
        sync_aggregate=pre.sync_aggregate,
        signature_slot=pre.signature_slot,
    )

Upgrading the store

Existing LightClientStore objects based on Electra MUST be upgraded to Gloas before Gloas based light client data can be processed. The LightClientStore upgrade MAY be performed before GLOAS_FORK_EPOCH.

def upgrade_lc_store_to_gloas(pre: electra.LightClientStore) -> LightClientStore:
    if pre.best_valid_update is None:
        best_valid_update = None
    else:
        best_valid_update = upgrade_lc_update_to_gloas(pre.best_valid_update)
    return LightClientStore(
        finalized_header=upgrade_lc_header_to_gloas(pre.finalized_header),
        current_sync_committee=pre.current_sync_committee,
        next_sync_committee=pre.next_sync_committee,
        best_valid_update=best_valid_update,
        optimistic_header=upgrade_lc_header_to_gloas(pre.optimistic_header),
        previous_max_active_participants=pre.previous_max_active_participants,
        current_max_active_participants=pre.current_max_active_participants,
    )