Dev Update #10

Hello,

(This blog post was created with the help of 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.

In our last dev update, we highlighted the challenges we've been facing with the sync_committee_rewards. 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.

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:

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:

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:

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 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 theflag:
    • 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.