# EPF Weeks 12/13
These weeks were focused on researching the idea of converting the Validator to a Staker, and creating multiple specialised roles for it. I looked into how this intersects with Rainbow Staking, Delegating, and the Lean protocol.
I also created a [PR in the lean repo](https://github.com/leanEthereum/leanSpec/pull/36) that showcases how such a separation could look like at the protocol level, and how we could control/set up the staking.
### Renaming the Validator
In lean, there is the idea to rename the Validator to Staker. The roles of the validator will be split anyway, so it makes sense to rename it because 'validating' will be only one of the roles in the upcoming chain.
That means that we can have a Staker (because it will need to stake some Eth to participate in the protocol), and a bunch of roles it can assume.
One of the ideas is to use 3 roles. Attester, Proposer, Includer. Any Staker should be able to assume one, two or all of those roles, provided it has enough balance at stake.
These roles are not 'everything' a staker can do, there are other duties a staker can or must fulfill.
### Attester
Attesters should vote on block validity. They put up stake that is slashable is they misbehave. They get rewards for securing the consensus.
Attesters should be able to run on modest hardware, and be stateless. In a Lean world, it would have to check a ZK proof against the block.
### Includers
Includers are used to construct inclusion lists from the transactions in the mempool, and practically force proposers to include certain transactions in a given block. Their entry capital requirement is low.
### Execution proposers
They will propose a valid execution payload, order and include trasactions - while respecting the inclusion lists. EP will run on specialised hardware and be quite sophisticated.
## The separation
The separation of those roles, in code, for Lean, was quite simple.
```python=
class AttesterRole(StrictBaseModel):
"""Parameters for the Attester Role."""
activation_eligibility_epoch: Epoch
"""The epoch in which the role enters the activation queue."""
activation_epoch: Epoch
"""The epoch in which the role becomes active."""
exit_epoch: Epoch
"""The epoch in which the delegated balance stops participating in the
protocol but remains accountable."""
withdrawable_epoch: Epoch
"""The epoch in which the delegated balance is no longer held
accountable and is credited to the delegator."""
is_active: bool
"""Determines if the role is active or not."""
balance: Gwei
"""The actual balance of the staker's role."""
slashed: bool
"""Determines if the staker has been slashed for this role."""
staker_quota: Uint64
"""The quota of the staker's role in the delegation."""
delegations_quotas: List[Uint64,
DEVNET_STAKER_CONFIG.delegations_registry_limit]
"""The quotas of each delegated balance for this role. This list is
parallel with the stakers list from the state."""
delegated_balances: List[Uint64,
DEVNET_STAKER_CONFIG.delegations_registry_limit]
"""The delegated balances for each staker. This list is parallel with
the stakers list from the state."""
total_delegated_balance: Gwei
"""This is the sum of every value in `delegated_balances` and is used
for performance optimisation purposes."""
class IncluderRole(StrictBaseModel):
"""Parameters for the Includer Role."""
is_active: bool
"""Determines if the role is active or not."""
balance: Gwei
"""The actual balance of the staker's role."""
staker_quota: Uint64
"""The quota of the staker's role in the delegation."""
delegations_quotas: List[Uint64,
DEVNET_STAKER_CONFIG.delegations_registry_limit]
"""The quotas of each delegated balance for this role. This list is
parallel with the stakers list from the state."""
delegated_balances: List[Uint64,
DEVNET_STAKER_CONFIG.delegations_registry_limit]
"""The delegated balances for each staker. This list is parallel with
the stakers list from the state."""
total_delegated_balance: Gwei
"""This is the sum of every value in `delegated_balances` and is used
for performance optimisation purposes."""
class ProposerRole(StrictBaseModel):
"""Parameters for the Proposer Role."""
activation_eligibility_epoch: Epoch
"""The epoch in which the role enters the activation queue."""
activation_epoch: Epoch
"""The epoch in which the role becomes active."""
exit_epoch: Epoch
"""The epoch in which the delegated balance stops participating in the
protocol but remains accountable."""
withdrawable_epoch: Epoch
"""The epoch in which the delegated balance is no longer held
accountable and is credited to the delegator."""
is_active: bool
"""Determines if the role is active or not."""
balance: Gwei
"""The actual balance of the staker's role."""
slashed: bool
"""Determines if the staker has been slashed for this role."""
staker_quota: Uint64
"""The quota of the staker's role in the delegation."""
delegations_quotas: List[Uint64,
DEVNET_STAKER_CONFIG.delegations_registry_limit]
"""The quotas of each delegated balance for this role. This list is
parallel with the stakers list from the state."""
delegated_balances: List[Uint64,
DEVNET_STAKER_CONFIG.delegations_registry_limit]
"""The delegated balances for each staker. This list is parallel with
the stakers list from the state."""
total_delegated_balance: Gwei
"""This is the sum of every value in `delegated_balances` and is used
for performance optimisation purposes."""
```
Three classes were defined, one per role, each with its set of required parameters.
## How do we control the Staker's settings?
I mentioned that a Staker, in theory, can assume one two or three roles. Or however many there will be. In theory.
But how will it assume those roles? For that, a settings mechanism was created, that can be epanded to be used with any number of roles.
These StakerSettings specify if the role is delegated, if it can receive delegations, the fees, and if it's active or not.
```python=
class StakerSettings(BaseModel):
"""Parameters for the StakerSettings."""
role_identifier: Byte
"""The role for which these settings are applied."""
active: bool
"""Determines if the role should be active or not."""
delegated: bool
"""Determines if the role should be delegated or not."""
target_staker: StakerIndex
"""Represents the index of a target staker that should receive the
delegation."""
delegatable: bool
"""Determines if the staker should accept delegations for this role."""
fee_quotient: Uint64
"""Defines the quotient used to calculate the fees that the delegate
owes to the staker."""
```
Everything connects in the Staker class, where the setting, configs and roles are stored.
```python=
class Staker(StrictBaseModel):
"""The consensus staker object."""
role_config: Annotated[
list[StakerSettings],
Field(min_length=3, max_length=3),
]
"""The list contains the settings for each of the roles the staker can
activate."""
attester_role: AttesterRole
"""
Contains the state related to the Attester role.
This role is responsible for providing economic security by voting on the
validity of blocks. This field tracks all attestation-specific data.
"""
includer_role: IncluderRole
"""
Contains the state related to the Includer role.
This role upholds censorship resistance by creating inclusion lists (ILs)
that constrain block producers. This field tracks all inclusion-specific
data.
"""
proposer_role: ProposerRole
"""
Contains the state related to the Execution Proposer role.
This role focuses on performance by building and proposing valuable
execution blocks, including transaction ordering and MEV extraction.
"""
```
The idea is to be able to update these settings via a matrix. That matrix of information contains all the delegations, role activations, fee configs and so on. Whenever the matrix is updated, the protocol should be able to diff the changes and apply them accordingly.
This can be used to delegate, undelegate, redelegate, activate/deactivate roles.

### Resources
[Three-Tier staking](https://ethresear.ch/t/three-tier-staking-3ts-unbundling-attesters-includers-and-execution-proposers/21648)
[Towards Attester-Includer Separation](https://ethresear.ch/t/towards-attester-includer-separation/21306)
[Making Sense of a ZK Staking Node](https://paragraph.com/@ethstaker/making-sense-of-a-zk-staking-node)