# Dev Update #10
Hello,
(*This blog post was created with the help of [ChatGPT](https://openai.com/blog/chatgpt/) and ~~minor~~ major modifications by myself as a fun little exercise.*)
Welcome to the latest dev update for our software project! In *this* update, we will discuss our progress on the [`attestation_rewards`](https://github.com/sigp/lighthouse/pull/3822).
In our [last dev update](https://hackmd.io/@kevinbogner/dev-update-9), we highlighted the challenges we've been facing with the [`sync_committee_rewards`](https://github.com/sigp/lighthouse/pull/3790). Since then, we've had a productive meeting with NC and sproul, during which we discussed the plan for implementing the `attestation_rewards`. The meeting notes created by sproul, which guide us through the implementation process, can be found [here](https://hackmd.io/@sproul/consensus-rewards-m2#Attestation-Rewards-Plan).
While NC focuses on testing the `sync_committee_rewards` API manually, we will be using the meeting notes to guide the development of the `attestation_rewards` feature. It's the holiday season, so things are moving slower than usual. However, we will return to our regular pace in the coming week.
Moving on to the next topic, let's take a closer look at the structure of the `attestation_rewards` feature based on the meeting notes. In this blog post, we will cover the following topics:
- [Getting the correct state](#Correct-state)
- [Calculating ideal rewards](#Ideal-rewards)
- [Calculating actual rewards](#Actual-rewards)
- [Discussing next steps.](#Next-steps)
## Correct state
To determine the attestation rewards for epoch `N`, we need to load the state from the last slot of epoch `N + 1`. The reason for this is that attestation rewards for epoch `N` are calculated at the transition from epoch `N + 1` to epoch `N + 2` to take into account the attestations included on-chain from up to 32 slots ago (e.g., epoch `N` attestations can get included on-chain during epoch `N + 1`). Here's the code that will accomplish this:
```rust
let state_slot = (epoch + 1).end_slot(T::EthSpec::slots_per_epoch());
let state_root = chain.state_root_at_slot(state_slot)??;
let mut state = chain.get_state(state_root, Some(state_slot))??;
```
Once we have the state, we can proceed to calculate the ideal rewards and the actual rewards. The ideal rewards represent the maximum rewards validators could have received if the attestations were perfect. On the other hand, the actual rewards consider the actually received rewards.
Calculating the ideal and actual rewards involves several steps, which we will cover in the next two sections.
## Ideal rewards
To calculate the ideal rewards for each validator, we need to consider the validator's effective balance. It is always in increments of `1 ETH` and can only be in the range `0…=32 ETH` (i.e., 33 possible values).
The ideal rewards are calculated for each possible value of effective balance.
The formula for the ideal reward is:
```python
reward_numerator = base_reward * weight * unslashed_participating_increments
reward = reward_numerator // (active_increments * WEIGHT_DENOMINATOR)
```
This formula is extracted from the [`get_flag_index_deltas`](https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/beacon-chain.md#get_flag_index_deltas) function in the Ethereum specification. Following similar logic to the `get_flag_index_deltas function`, we can compute the ideal rewards for each effective balance. This will give us a map like (`flag`, `effective_balance`) -> `ideal_reward`, where `flag` is `head`, `target`, `source`, or its integer representation.
The only case where this is not the ideal reward is when `is_in_inactivity_leak(state)` is `true`, in which case the ideal reward is `0`.
Once we have calculated the ideal rewards for each validator, we can calculate the actual rewards.
## Actual rewards
To calculate the actual rewards for a given validator, we need to follow these steps:
1. Check if the validator is eligible for rewards in the current epoch by calling `state.is_eligible_validator(epoch, validator_index)`. If the validator is not eligible, their reward is `0`.
2. Check if the validator voted correctly for the flag (head/target/source) by calling `participation_cache.get_unslashed_participating_indices(flag, epoch)` and checking if the validator's index is included in the resulting list.
3. If the validator votes correctly, their reward is the ideal reward for the combination of flag and the validator's effective balance. This value can be looked up in the ideal rewards map.
4. If the validator voted incorrectly, their reward is calculated differently based on the`flag`:
- For the `head` vote, the reward is `0`.
- For the `target` and `source` votes, the reward is `-1 * base_reward * weight // WEIGHT_DENOMINATOR`.
And that's it! Now that we have calculated both the ideal and actual rewards, we can discuss the next mandatory steps for the `attestation_rewards`.
## Next steps
With the calculation of the ideal and actual rewards for the `attestation_rewards` now complete, the next steps in the development process include thoroughly testing the resulting API. As with any new feature, it is crucial to ensure that the `attestation_rewards` works as intended and produces accurate results.
NC will continue to manually testing the `sync_committee_rewards` API while I focus on deploying the `attestation_rewards`.
That concludes *this* dev update. Thank you for following along, and stay tuned for the next update, where we will provide updates on the progress of both the `sync_committee_rewards` and `attestation_rewards`. We are excited to see these new additions to our project and look forward to sharing the results with you in the near future.