Implement attestation_rewards API (per-validator reward) (#3822)

## Issue Addressed

#3661 

## Proposed Changes
`/eth/v1/beacon/rewards/attestations/{epoch}`

```json
{
  "execution_optimistic": false,
  "finalized": false,
  "data": [
    {
      "ideal_rewards": [
        {
          "effective_balance": "1000000000",
          "head": "2500",
          "target": "5000",
          "source": "5000"
        }
      ],
      "total_rewards": [
        {
          "validator_index": "0",
          "head": "2000",
          "target": "2000",
          "source": "4000",
          "inclusion_delay": "2000"
        }
      ]
    }
  ]
}
```

The issue contains the implementation of three per-validator reward APIs:
- [`sync_committee_rewards`](https://github.com/sigp/lighthouse/pull/3790)
- `attestation_rewards`
- `block_rewards`.

This PR *only* implements the `attestation_rewards`.

The endpoints can be viewed in the Ethereum Beacon nodes API browser: https://ethereum.github.io/beacon-APIs/?urls.primaryName=dev#/Rewards

## Additional Info
The implementation of [consensus client reward APIs](https://github.com/eth-protocol-fellows/cohort-three/blob/master/projects/project-ideas.md#consensus-client-reward-apis) is part of the [EPF](https://github.com/eth-protocol-fellows/cohort-three).

---
- [x] `get_state`
- [x] Calculate *ideal rewards* with some logic from  `get_flag_index_deltas`
- [x] Calculate *actual rewards*  with some logic from `get_flag_index_deltas`
- [x] Code cleanup
- [x] Testing
This commit is contained in:
kevinbogner
2023-02-07 00:00:19 +00:00
parent c56706efae
commit 4d07e40501
8 changed files with 322 additions and 1 deletions

View File

@@ -1044,6 +1044,24 @@ impl BeaconNodeHttpClient {
Ok(())
}
/// `POST beacon/rewards/attestations`
pub async fn post_beacon_rewards_attestations(
&self,
attestations: &[ValidatorId],
) -> Result<(), Error> {
let mut path = self.eth_path(V1)?;
path.path_segments_mut()
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
.push("beacon")
.push("rewards")
.push("attestations");
self.post(path, &attestations).await?;
Ok(())
}
/// `POST validator/contribution_and_proofs`
pub async fn post_validator_contribution_and_proofs<T: EthSpec>(
&self,

View File

@@ -1,6 +1,7 @@
//! This module contains endpoints that are non-standard and only available on Lighthouse servers.
mod attestation_performance;
pub mod attestation_rewards;
mod block_packing_efficiency;
mod block_rewards;
mod sync_committee_rewards;
@@ -23,6 +24,7 @@ use store::{AnchorInfo, Split, StoreConfig};
pub use attestation_performance::{
AttestationPerformance, AttestationPerformanceQuery, AttestationPerformanceStatistics,
};
pub use attestation_rewards::StandardAttestationRewards;
pub use block_packing_efficiency::{
BlockPackingEfficiency, BlockPackingEfficiencyQuery, ProposerInfo, UniqueAttestation,
};

View File

@@ -0,0 +1,42 @@
use serde::{Deserialize, Serialize};
// Details about the rewards paid for attestations
// All rewards in GWei
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
pub struct IdealAttestationRewards {
// Validator's effective balance in gwei
#[serde(with = "eth2_serde_utils::quoted_u64")]
pub effective_balance: u64,
// Ideal attester's reward for head vote in gwei
#[serde(with = "eth2_serde_utils::quoted_u64")]
pub head: u64,
// Ideal attester's reward for target vote in gwei
#[serde(with = "eth2_serde_utils::quoted_u64")]
pub target: u64,
// Ideal attester's reward for source vote in gwei
#[serde(with = "eth2_serde_utils::quoted_u64")]
pub source: u64,
}
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
pub struct TotalAttestationRewards {
// one entry for every validator based on their attestations in the epoch
#[serde(with = "eth2_serde_utils::quoted_u64")]
pub validator_index: u64,
// attester's reward for head vote in gwei
#[serde(with = "eth2_serde_utils::quoted_u64")]
pub head: u64,
// attester's reward for target vote in gwei
pub target: i64,
// attester's reward for source vote in gwei
pub source: i64,
// TBD attester's inclusion_delay reward in gwei (phase0 only)
// pub inclusion_delay: u64,
}
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
pub struct StandardAttestationRewards {
pub ideal_rewards: Vec<IdealAttestationRewards>,
pub total_rewards: Vec<TotalAttestationRewards>,
}

View File

@@ -270,11 +270,20 @@ pub struct FinalityCheckpointsData {
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(try_from = "&str")]
pub enum ValidatorId {
PublicKey(PublicKeyBytes),
Index(u64),
}
impl TryFrom<&str> for ValidatorId {
type Error = String;
fn try_from(s: &str) -> Result<Self, Self::Error> {
Self::from_str(s)
}
}
impl FromStr for ValidatorId {
type Err = String;