# Week 14 Hi everyone, Rupam here. This week I fully implemented the `block_to_light_client_header` function along with its tests from CL specs into Prysm upto Deneb in this [PR](https://github.com/prysmaticlabs/prysm/pull/14433). This is a pretty important function because its used in the implementation of `create_light_client_bootstrap`. Now you might think that `create_light_client_bootstrap` is already implemented in Prysm, how come we didn't need `block_to_light_client_header` for that before? Well, as I said in my last update, `create_light_client_bootstrap` implementation in Prysm doesn't follow the `dev` branch of CL specs as reference and follows [this](https://github.com/ethereum/consensus-specs/blob/3d235740e5f1e641d3b160c8688f26e7dc5a1894/specs/altair/light-client/full-node.md#create_light_client_bootstrap) instead. From what I realised, this makes it harder to implement the function for newer forks. I confirmed this with Etan too and he said the same. We still had the `create_light_client_bootstrap` function implemented for the newer forks somehow and as I expected they are pretty much wrong as far as the specs go. Radek also opened a [PR](https://github.com/prysmaticlabs/prysm/pull/14434) to refactor some light client structs and functions for better readability and while reviewing his PR I noticed there are infact a lot of light client functions which do not follow the `dev` branch as reference. Although they are **NOT inherently wrong**, it is harder to update them for newer forks as all the newer forks follow the `dev` branch. So I have decided to take up the work of updating all the functions to follow the `dev` branch in my next PR. ## (If it works then don't touch it) Why Upgrade Then? Consider the `block_to_light_client_header` implementation of Deneb from `dev` branch: ```python def block_to_light_client_header(block: SignedBeaconBlock) -> LightClientHeader: epoch = compute_epoch_at_slot(block.message.slot) if epoch >= CAPELLA_FORK_EPOCH: payload = block.message.body.execution_payload execution_header = ExecutionPayloadHeader( parent_hash=payload.parent_hash, fee_recipient=payload.fee_recipient, state_root=payload.state_root, receipts_root=payload.receipts_root, logs_bloom=payload.logs_bloom, prev_randao=payload.prev_randao, block_number=payload.block_number, gas_limit=payload.gas_limit, gas_used=payload.gas_used, timestamp=payload.timestamp, extra_data=payload.extra_data, base_fee_per_gas=payload.base_fee_per_gas, block_hash=payload.block_hash, transactions_root=hash_tree_root(payload.transactions), withdrawals_root=hash_tree_root(payload.withdrawals), ) # [New in Deneb:EIP4844] if epoch >= DENEB_FORK_EPOCH: execution_header.blob_gas_used = payload.blob_gas_used execution_header.excess_blob_gas = payload.excess_blob_gas execution_branch = ExecutionBranch( compute_merkle_proof(block.message.body, EXECUTION_PAYLOAD_GINDEX)) else: # Note that during fork transitions, `finalized_header` may still point to earlier forks. # While Bellatrix blocks also contain an `ExecutionPayload` (minus `withdrawals_root`), # it was not included in the corresponding light client data. To ensure compatibility # with legacy data going through `upgrade_lc_header_to_capella`, leave out execution data. execution_header = ExecutionPayloadHeader() execution_branch = ExecutionBranch() return LightClientHeader( beacon=BeaconBlockHeader( slot=block.message.slot, proposer_index=block.message.proposer_index, parent_root=block.message.parent_root, state_root=block.message.state_root, body_root=hash_tree_root(block.message.body), ), execution=execution_header, execution_branch=execution_branch, ) ``` The `execution_header` has 2 new fields compared to Altair, `blob_gas_used` and `excess_blob_gas`. These fields are not set in our Prysm implementation making it incorrect. However there are no new changes mentioned in the `create_light_client_bootstrap` function in Deneb. Now there's the catch. The `create_light_client_bootstrap` is only defined in Altair as follows: ```python def create_light_client_bootstrap(state: BeaconState, block: SignedBeaconBlock) -> LightClientBootstrap: assert compute_epoch_at_slot(state.slot) >= ALTAIR_FORK_EPOCH assert state.slot == state.latest_block_header.slot header = state.latest_block_header.copy() header.state_root = hash_tree_root(state) assert hash_tree_root(header) == hash_tree_root(block.message) return LightClientBootstrap( header=block_to_light_client_header(block), current_sync_committee=state.current_sync_committee, current_sync_committee_branch=CurrentSyncCommitteeBranch( compute_merkle_proof(state, current_sync_committee_gindex_at_slot(state.slot))), ) ``` The `block_to_light_client_header` function is called inside which itself changes over forks. Hence it is necessary to update the `create_light_client_bootstrap` function to follow the `dev` branch even though it is not explicitly mentioned. Right now I have not looked deeper into the other functions so I don't know if they have this issue too. However updating all of them to use the `dev` branch will solve this problem before even needing to search for them. I will be opening a PR soon to address these.