Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Staking Reward Eras basics #1589

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 16 additions & 12 deletions designdocs/capacity_staking_rewards_implementation.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ pub struct StakingAccountDetails {
pub total: BalanceOf<T>,
pub unlocking: BoundedVec<UnlockChunk<BalanceOf<T>, T::EpochNumber>, T::MaxUnlockingChunks>,
/// The number of the last StakingEra that this account's rewards were claimed.
pub last_rewards_claimed_at: Option<T::StakingEra>, // NEW None means never rewarded, Some(RewardEra) means last rewarded RewardEra.
pub last_rewards_claimed_at: Option<T::RewardEra>, // NEW None means never rewarded, Some(RewardEra) means last rewarded RewardEra.
/// What type of staking this account is doing
pub staking_type: StakingType, // NEW
/// staking amounts that have been retargeted are prevented from being retargeted again for the
Expand Down Expand Up @@ -94,15 +94,12 @@ pub struct StakingRewardClaim<T: Config> {
/// The end state of the staking account if the operations are valid
pub staking_account_end_state: StakingAccountDetails,
/// The starting era for the claimed reward period, inclusive
pub from_era: AtLeast32BitUnsigned,
pub from_era: T::RewardEra,
/// The ending era for the claimed reward period, inclusive
pub to_era: RewardEra,
pub to_era: T::RewardEra,
}

pub trait StakingRewardsProvider {
type Balance;
type AccountId;
type RewardEra;
pub trait StakingRewardsProvider<T: Config> {

/// Return the size of the reward pool for the given era, in token
/// Errors:
Expand All @@ -112,12 +109,12 @@ pub trait StakingRewardsProvider {
/// Return the total unclaimed reward in token for `account_id` for `fromEra` --> `toEra`, inclusive
/// Errors:
/// - EraOutOfRange when fromEra or toEra are prior to the history retention limit, or greater than the current RewardEra.
fn staking_reward_total(account_id: AccountId, fromEra: RewardEra, toEra: RewardEra);
fn staking_reward_total(account_id: T::AccountId, fromEra: T::RewardEra, toEra: T::RewardEra);

/// Validate a payout claim for `account_id`, using `proof` and the provided `payload` StakingRewardClaim.
/// Returns whether the claim passes validation. Accounts must first pass `payoutEligible` test.
/// Errors: None
fn validate_staking_reward_claim(account_id: AccountIdOf<T>, proof: Hash, payload: StakingRewardClaim<T>) -> bool;
fn validate_staking_reward_claim(account_id: T::AccountID, proof: Hash, payload: StakingRewardClaim<T>) -> bool;
}
```

Expand Down Expand Up @@ -173,14 +170,21 @@ pub struct RewardPoolInfo<T: Config> {
pub type StakingRewardPool<T: Config> = <StorageMap<_, Twox64Concat, RewardEra, RewardPoolInfo<T>;
```

### NEW: CurrentEra
Incremented, like CurrentEpoch, tracks the current RewardEra number.
### NEW: CurrentEra, RewardEraInfo
Incremented, like CurrentEpoch, tracks the current RewardEra number and the block when it started.
```rust
#[pallet::storage]
#[pallet::whitelist_storage]
#[pallet::getter(fn get_current_era)]
/// Similar to CurrentEpoch
pub type CurrentEra<T:Config> = StorageValue<_, T::RewardEra, ValueQuery>;
pub type CurrentEraInfo<T:Config> = StorageValue<_, T::RewardEraInfo, ValueQuery>;

pub struct RewardEraInfo<RewardEra, BlockNumber> {
/// the index of this era
pub current_era: RewardEra,
/// the starting block of this era
pub era_start: BlockNumber,
}
```

### NEW: Error enums
Expand Down
27 changes: 25 additions & 2 deletions pallets/capacity/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ pub use common_primitives::{

#[cfg(feature = "runtime-benchmarks")]
use common_primitives::benchmarks::RegisterProviderBenchmarkHelper;
use common_primitives::{capacity::StakingType, node::RewardEra};
use common_primitives::capacity::StakingType;

pub use pallet::*;
pub use types::*;
Expand Down Expand Up @@ -231,6 +231,12 @@ pub mod pallet {
pub type EpochLength<T: Config> =
StorageValue<_, T::BlockNumber, ValueQuery, EpochLengthDefault<T>>;

/// Information for the current era
#[pallet::storage]
#[pallet::getter(fn get_current_era)]
pub type CurrentEraInfo<T: Config> =
StorageValue<_, RewardEraInfo<T::RewardEra, T::BlockNumber>, ValueQuery>;

// Simple declaration of the `Pallet` type. It is placeholder we use to implement traits and
// method.
#[pallet::pallet]
Expand Down Expand Up @@ -328,6 +334,7 @@ pub mod pallet {
impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
fn on_initialize(current: T::BlockNumber) -> Weight {
Self::start_new_epoch_if_needed(current)
.saturating_add(Self::start_new_reward_era_if_needed(current))
}
}

Expand Down Expand Up @@ -634,7 +641,23 @@ impl<T: Config> Pallet<T> {
.saturating_add(T::DbWeight::get().writes(2))
} else {
// 1 for get_current_epoch_info, 1 for get_epoch_length
T::DbWeight::get().reads(2u64).saturating_add(RocksDbWeight::get().writes(1))
T::DbWeight::get().reads(2).saturating_add(RocksDbWeight::get().writes(1))
}
}

fn start_new_reward_era_if_needed(current_block: T::BlockNumber) -> Weight {
let current_era_info: RewardEraInfo<T::RewardEra, T::BlockNumber> = Self::get_current_era();
if current_block.saturating_sub(current_era_info.era_start) >= T::EraLength::get().into() {
CurrentEraInfo::<T>::set(RewardEraInfo {
current_era: current_era_info.current_era.saturating_add(1u8.into()),
era_start: current_block,
});
// TODO: modify reads/writes as needed when RewardPoolInfo stuff is added
T::WeightInfo::on_initialize()
.saturating_add(T::DbWeight::get().reads(1))
.saturating_add(T::DbWeight::get().writes(1))
} else {
T::DbWeight::get().reads(2).saturating_add(RocksDbWeight::get().writes(1))
}
}

Expand Down
25 changes: 25 additions & 0 deletions pallets/capacity/src/tests/eras_tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
use super::mock::*;
use crate::{
tests::testing_utils::{run_to_block, system_run_to_block},
Config, CurrentEraInfo, Error, Event, RewardEraInfo,
};

use frame_support::traits::Get;

#[test]
fn start_new_era_if_needed() {
new_test_ext().execute_with(|| {
CurrentEraInfo::<Test>::set(RewardEraInfo { current_era: 1, era_start: 0 });
system_run_to_block(9);
run_to_block(10);
let mut current_era_info = CurrentEraInfo::<Test>::get();
assert_eq!(current_era_info.current_era, 2u32);
assert_eq!(current_era_info.era_start, 10u32);

system_run_to_block(19);
run_to_block(20);
current_era_info = CurrentEraInfo::<Test>::get();
assert_eq!(current_era_info.current_era, 3u32);
assert_eq!(current_era_info.era_start, 20u32);
})
}
1 change: 1 addition & 0 deletions pallets/capacity/src/tests/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
pub mod capacity_details_tests;
pub mod epochs_tests;
mod eras_tests;
pub mod mock;
pub mod other_tests;
pub mod replenishment_tests;
Expand Down
27 changes: 19 additions & 8 deletions pallets/capacity/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,10 @@ pub struct StakingAccountDetails<T: Config> {
/// What type of staking this account is doing
pub staking_type: StakingType,
/// The None or Some(number): never, or the last RewardEra that this account's rewards were claimed.
pub last_rewards_claimed_at: Option<RewardEra>,
pub last_rewards_claimed_at: Option<T::RewardEra>,
/// Chunks that have been retargeted within T::UnstakingThawPeriod
pub stake_change_unlocking:
BoundedVec<UnlockChunk<BalanceOf<T>, RewardEra>, T::MaxUnlockingChunks>,
BoundedVec<UnlockChunk<BalanceOf<T>, T::RewardEra>, T::MaxUnlockingChunks>,
}

/// The type that is used to record a single request for a number of tokens to be unlocked.
Expand Down Expand Up @@ -260,25 +260,25 @@ pub struct StakingRewardClaim<T: Config> {
/// The end state of the staking account if the operations are valid
pub staking_account_end_state: StakingAccountDetails<T>,
/// The starting era for the claimed reward period, inclusive
pub from_era: RewardEra,
pub from_era: T::RewardEra,
/// The ending era for the claimed reward period, inclusive
pub to_era: RewardEra,
pub to_era: T::RewardEra,
}

/// A trait that provides the Economic Model for Provider Boosting.
pub trait StakingRewardsProvider<T: Config> {
/// Return the size of the reward pool for the given era, in token
/// Errors:
/// - EraOutOfRange when `era` is prior to the history retention limit, or greater than the current Era.
fn reward_pool_size(era: RewardEra) -> BalanceOf<T>;
fn reward_pool_size(era: T::RewardEra) -> BalanceOf<T>;

/// Return the total unclaimed reward in token for `accountId` for `from_era` --> `to_era`, inclusive
/// Errors:
/// - EraOutOfRange when from_era or to_era are prior to the history retention limit, or greater than the current Era.
fn staking_reward_total(
account_id: AccountId,
from_era: RewardEra,
to_era: RewardEra,
account_id: T::AccountId,
from_era: T::RewardEra,
to_era: T::RewardEra,
) -> BalanceOf<T>;

/// Validate a payout claim for `accountId`, using `proof` and the provided `payload` StakingRewardClaim.
Expand All @@ -303,5 +303,16 @@ pub trait StakingRewardsProvider<T: Config> {
fn payout_eligible(account_id: AccountId) -> bool;
}

/// The information needed to track a Reward Era
#[derive(
PartialEq, Eq, Clone, Default, PartialOrd, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen,
)]
pub struct RewardEraInfo<RewardEra, BlockNumber> {
/// the index of this era
pub current_era: RewardEra,
/// the starting block of this era
pub era_start: BlockNumber,
}

/// Needed data about a RewardPool for a given RewardEra.
pub struct RewardPoolInfo {}