# FOCIL Prysm Implementation Notes **Last updated date**: Tuesday, January 14, 2025 **Reference**: [Prysm PR #14754](https://github.com/prysmaticlabs/prysm/pull/14754) ## Block Processing ### Syncing a non-current slot block lacks an inclusion list While a Prysm node syncing to the head of the chain, a node may lack historical inclusion lists. However, it still needs to call `engine_newPayloadV5`. - In Prysm, if the payload being synced is not for the current slot, the node uses an empty inclusion transaction list as there's nothing in the inclusion list cache. **Action Item**: Review the engine API definition to clarify constraints for same-slot scenarios. ### Node remembrance of unsatisfied inclusion list block root The `engine_newPayloadV5` API introduces a new argument, it's an inclusion list `transactions` field (`Array of DATA`). If any transactions are not part of the `executionPayload` (even if they can be appended at the end), the API returns: - **Status**: `INVALID_INCLUSION_LIST` - **latestValidHash**: `null` - **validationError**: `null` If a newly imported execution payload is marked `INVALID_INCLUSION_LIST`, the Prysm node stores its block root as `badInclusionListBlock`. It's just a single root, as an inclusion list only applies to the current slot, so no more than one root should be cached at a given time. ### Unsatisfied inclusion list block root filters the head root Prysm node adds a new function, `FilteredHeadRoot`, which returns the filtered head root to be used for valiator duties. In the function, if the head root matches `badInclusionListBlock`, it returns the parent block of that root. This method is used for: - **Attesters**: To attest to `beacon_block_root`. - **Sync committees**: To vote on `head_root`. - **Proposers**: To build on top of `parent_root`. **Action Item**: - The spec already contains `get_proposer_head` for reorg late block, we should use that and have a consistence place to return head for validator duty. ## Block Building ### Integrate inclusion lists into block building Prysm node has a new background routine (`updateInclusionListBlockInterval`) for updating inclusion lists for execution layer block construction: 1. Gather the current slot's inclusion list transactions. 2. Filter out duplicates. 3. Call `engine_updatePayloadWithInclusionListV1` with the existing `payloadID`. 4. Cache the new `payloadID`, which will be used for proposer at the slot of. This routine runs only if the node is the next slot proposer and a `payloadID` already exists on top of `headRoot` for `currentSlot + 1`. **Action Item**: - Review Beacon api event stream endpoint for payload attribute, whether we need to add inclusion list there. - Another design space is to overload `forkchoiceUpdated + attribute` to update inclusion list ## Syncing ### Gossip Validation Pipeline Prysm has added gossip validation for inclusion lists following the specification. Key points: - Inclusion list transactions have the same SSZ list size as the execution payload. - Manual checks ensure transactions do not exceed 8 KB. **Action Item**: Review and potentially reshuffle the gossip pipeline to address potential DoS concerns. ### Inclusion list cache Inclusion lists are cached in Prysm node using the following structure: - Key `map[primitives.Slot]map[primitives.ValidatorIndex]` - Value `[][]byte` (represents inclusion list transactions) - A special flag, `seenTwice`, tracks repeated entries. The cache has these methods: - **`Add`**: Adds an inclusion list entry. If an entry is added twice or more, `seenTwice` is set to `true`, and the original transactions are removed. - **`SeenTwice`**: Returns `true` if the `seenTwice` flag is active for a given slot and index. - **`Get`**: Returns all inclusion list transactions for a slot, excluding duplicates. - **`Delete`**: Deletes all inclusion list transactions for a slot. **Design considerations**: - Worst case memory usage is ~4 MB per slot (8 KB per validator, 512 validators per slot). - Frequent pruning is necessary. Potential strategies: - Prune after processing a block using the block's slot. - Use a background pruning routine to handle scenarios where on-chain liveness prevents immediate pruning. ## Validator API ### Inclusion list duty retrival Inclusion list duties are returned alongside beacon committee and proposer duties. Prysm provides a gRPC API for this but has not yet added support for the beacon API. **Action Item**: - Implement beacon API for inclusion lists. - Optimize inclusion list committee caching (current shuffling is expensive). ### Inclusion list retrival for validator signing The `GetInclusionList` endpoint: - **Input**: Slot (supports current and previous slots only). - **Process**: 1. Fetch the head block hash. 2. Retrieve the inclusion list from the execution client. 3. Compute the inclusion list committee. 4. Populate inclusion list fields and return them. 5. Return `InclusionList` with transactions and sync committee root filled. Note: it keeps the validator index empty. Inclusion list has a validator index field but validator client can just fill that themselves **Action Item**: Cache inclusion list responses to prevent repeated execution client calls. Ensure the execution client doesn't prematurely remove transactions. The tradoff here is two seperate requests may produce the same outtime. Leaning towards client implementation detail. ### Validator Client Changes Validator client changes are straightforward: 1. When a validator is assigned a duty, it waits until the duty time. 2. Fetches the inclusion list (excluding the validator's own index) from the beacon node. 3. Signs the inclusion list. 4. Submits the signed version.