Tweaks to reward APIs (#3957)

## Proposed Changes

* Return the effective balance in gwei to align with the spec ([ideal attestation rewards](https://ethereum.github.io/beacon-APIs/?urls.primaryName=dev#/Rewards/getAttestationsRewards)).
* Use quoted `i64`s for attestation and sync committee rewards.
This commit is contained in:
Michael Sproul 2023-02-10 06:19:42 +00:00
parent 5276dd0cb0
commit c9354a9d25
5 changed files with 49 additions and 19 deletions

View File

@ -72,6 +72,8 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
BaseRewardPerIncrement::new(total_active_balance, spec)?; BaseRewardPerIncrement::new(total_active_balance, spec)?;
for effective_balance_eth in 0..=32 { for effective_balance_eth in 0..=32 {
let effective_balance =
effective_balance_eth.safe_mul(spec.effective_balance_increment)?;
let base_reward = let base_reward =
effective_balance_eth.safe_mul(base_reward_per_increment.as_u64())?; effective_balance_eth.safe_mul(base_reward_per_increment.as_u64())?;
@ -86,9 +88,9 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
.safe_div(WEIGHT_DENOMINATOR)?; .safe_div(WEIGHT_DENOMINATOR)?;
if !state.is_in_inactivity_leak(previous_epoch, spec) { if !state.is_in_inactivity_leak(previous_epoch, spec) {
ideal_rewards_hashmap ideal_rewards_hashmap
.insert((flag_index, effective_balance_eth), (ideal_reward, penalty)); .insert((flag_index, effective_balance), (ideal_reward, penalty));
} else { } else {
ideal_rewards_hashmap.insert((flag_index, effective_balance_eth), (0, penalty)); ideal_rewards_hashmap.insert((flag_index, effective_balance), (0, penalty));
} }
} }
} }
@ -119,12 +121,9 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
if eligible { if eligible {
let effective_balance = state.get_effective_balance(*validator_index)?; let effective_balance = state.get_effective_balance(*validator_index)?;
let effective_balance_eth =
effective_balance.safe_div(spec.effective_balance_increment)?;
for flag_index in 0..PARTICIPATION_FLAG_WEIGHTS.len() { for flag_index in 0..PARTICIPATION_FLAG_WEIGHTS.len() {
let (ideal_reward, penalty) = ideal_rewards_hashmap let (ideal_reward, penalty) = ideal_rewards_hashmap
.get(&(flag_index, effective_balance_eth)) .get(&(flag_index, effective_balance))
.ok_or(BeaconChainError::AttestationRewardsError)?; .ok_or(BeaconChainError::AttestationRewardsError)?;
let voted_correctly = participation_cache let voted_correctly = participation_cache
.get_unslashed_participating_indices(flag_index, previous_epoch) .get_unslashed_participating_indices(flag_index, previous_epoch)
@ -160,21 +159,21 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
let mut ideal_rewards: Vec<IdealAttestationRewards> = ideal_rewards_hashmap let mut ideal_rewards: Vec<IdealAttestationRewards> = ideal_rewards_hashmap
.iter() .iter()
.map( .map(
|((flag_index, effective_balance_eth), (ideal_reward, _penalty))| { |((flag_index, effective_balance), (ideal_reward, _penalty))| {
(flag_index, effective_balance_eth, ideal_reward) (flag_index, effective_balance, ideal_reward)
}, },
) )
.fold( .fold(
HashMap::new(), HashMap::new(),
|mut acc, (flag_index, effective_balance_eth, ideal_reward)| { |mut acc, (flag_index, &effective_balance, ideal_reward)| {
let entry = acc.entry(*effective_balance_eth as u32).or_insert( let entry = acc
IdealAttestationRewards { .entry(effective_balance)
effective_balance: *effective_balance_eth, .or_insert(IdealAttestationRewards {
effective_balance,
head: 0, head: 0,
target: 0, target: 0,
source: 0, source: 0,
}, });
);
match *flag_index { match *flag_index {
TIMELY_SOURCE_FLAG_INDEX => entry.source += ideal_reward, TIMELY_SOURCE_FLAG_INDEX => entry.source += ideal_reward,
TIMELY_TARGET_FLAG_INDEX => entry.target += ideal_reward, TIMELY_TARGET_FLAG_INDEX => entry.target += ideal_reward,

View File

@ -28,8 +28,10 @@ pub struct TotalAttestationRewards {
#[serde(with = "eth2_serde_utils::quoted_u64")] #[serde(with = "eth2_serde_utils::quoted_u64")]
pub head: u64, pub head: u64,
// attester's reward for target vote in gwei // attester's reward for target vote in gwei
#[serde(with = "eth2_serde_utils::quoted_i64")]
pub target: i64, pub target: i64,
// attester's reward for source vote in gwei // attester's reward for source vote in gwei
#[serde(with = "eth2_serde_utils::quoted_i64")]
pub source: i64, pub source: i64,
// TBD attester's inclusion_delay reward in gwei (phase0 only) // TBD attester's inclusion_delay reward in gwei (phase0 only)
// pub inclusion_delay: u64, // pub inclusion_delay: u64,

View File

@ -8,5 +8,6 @@ pub struct SyncCommitteeReward {
#[serde(with = "eth2_serde_utils::quoted_u64")] #[serde(with = "eth2_serde_utils::quoted_u64")]
pub validator_index: u64, pub validator_index: u64,
// sync committee reward in gwei for the validator // sync committee reward in gwei for the validator
#[serde(with = "eth2_serde_utils::quoted_i64")]
pub reward: i64, pub reward: i64,
} }

View File

@ -12,4 +12,4 @@ pub mod u64_hex_be;
pub mod u8_hex; pub mod u8_hex;
pub use fixed_bytes_hex::{bytes_4_hex, bytes_8_hex}; pub use fixed_bytes_hex::{bytes_4_hex, bytes_8_hex};
pub use quoted_int::{quoted_u256, quoted_u32, quoted_u64, quoted_u8}; pub use quoted_int::{quoted_i64, quoted_u256, quoted_u32, quoted_u64, quoted_u8};

View File

@ -11,7 +11,7 @@ use std::convert::TryFrom;
use std::marker::PhantomData; use std::marker::PhantomData;
macro_rules! define_mod { macro_rules! define_mod {
($int: ty, $visit_fn: ident) => { ($int: ty) => {
/// Serde support for deserializing quoted integers. /// Serde support for deserializing quoted integers.
/// ///
/// Configurable so that quotes are either required or optional. /// Configurable so that quotes are either required or optional.
@ -140,19 +140,25 @@ macro_rules! define_mod {
pub mod quoted_u8 { pub mod quoted_u8 {
use super::*; use super::*;
define_mod!(u8, visit_u8); define_mod!(u8);
} }
pub mod quoted_u32 { pub mod quoted_u32 {
use super::*; use super::*;
define_mod!(u32, visit_u32); define_mod!(u32);
} }
pub mod quoted_u64 { pub mod quoted_u64 {
use super::*; use super::*;
define_mod!(u64, visit_u64); define_mod!(u64);
}
pub mod quoted_i64 {
use super::*;
define_mod!(i64);
} }
pub mod quoted_u256 { pub mod quoted_u256 {
@ -216,4 +222,26 @@ mod test {
fn u256_without_quotes() { fn u256_without_quotes() {
serde_json::from_str::<WrappedU256>("1").unwrap_err(); serde_json::from_str::<WrappedU256>("1").unwrap_err();
} }
#[derive(Debug, PartialEq, Serialize, Deserialize)]
#[serde(transparent)]
struct WrappedI64(#[serde(with = "quoted_i64")] i64);
#[test]
fn negative_i64_with_quotes() {
assert_eq!(
serde_json::from_str::<WrappedI64>("\"-200\"").unwrap().0,
-200
);
assert_eq!(
serde_json::to_string(&WrappedI64(-12_500)).unwrap(),
"\"-12500\""
);
}
// It would be OK if this worked, but we don't need it to (i64s should always be quoted).
#[test]
fn negative_i64_without_quotes() {
serde_json::from_str::<WrappedI64>("-200").unwrap_err();
}
} }