Skip to content

Commit

Permalink
More fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
Dinonard committed Oct 4, 2023
1 parent a790548 commit 26d7807
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 22 deletions.
29 changes: 19 additions & 10 deletions pallets/dapp-staking-v3/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -615,9 +615,11 @@ pub mod pallet {

let protocol_state = ActiveProtocolState::<T>::get();
let mut ledger = Ledger::<T>::get(&account);

// Staker always stakes from the NEXT era
let stake_era = protocol_state.era.saturating_add(1);

// TODO: staker should be staking from the NEXT era
// TODO: add a check if Build&Earn period ends in the next era. If it does, staking should fail since it's pointless.

// 1.
// Increase stake amount for the next era & current period in staker's ledger
Expand All @@ -634,16 +636,22 @@ pub mod pallet {

// 2.
// Update `StakerInfo` storage with the new stake amount on the specified contract.
// TODO: this might need to be modified - if rewards were claimed for the past period, it should be ok to overwrite the old storage item.
let new_staking_info =
if let Some(mut staking_info) = StakerInfo::<T>::get(&account, &smart_contract) {
ensure!(
staking_info.period_number() == protocol_state.period_info.number,
Error::<T>::InternalStakeError
);
//
// There are two distinct scenarios:
// 1. Existing entry matches the current period number - just update it.
// 2. Entry doesn't exist or it's for an older era - create a new one.
//
// This is ok since we only use this storage entry to keep track of how much each staker
// has staked on each contract in the current period. We only ever need the latest information.
// This is because `AccountLedger` is the one keeping information about how much was staked when.
let new_staking_info = match StakerInfo::<T>::get(&account, &smart_contract) {
Some(mut staking_info)
if staking_info.period_number() == protocol_state.period_info.number =>
{
staking_info.stake(amount, protocol_state.period_info.period_type);
staking_info
} else {
}
_ => {
ensure!(
amount >= T::MinimumStakeAmount::get(),
Error::<T>::InsufficientStakeAmount
Expand All @@ -654,7 +662,8 @@ pub mod pallet {
);
staking_info.stake(amount, protocol_state.period_info.period_type);
staking_info
};
}
};

// 3.
// Update `ContractStake` storage with the new stake amount on the specified contract.
Expand Down
4 changes: 2 additions & 2 deletions pallets/dapp-staking-v3/src/test/tests_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1133,10 +1133,10 @@ fn contract_staking_info_series_stake_is_ok() {
assert_eq!(entry_2_2.era(), era_2);
assert_eq!(entry_2_2.total_staked_amount(), amount * 3);

// 4th scenario - stake in the 3rd era, expect a cleanup
// 4th scenario - stake in the 3rd era
let era_3 = era_2 + 1;
assert!(series.stake(amount, period_info, era_3).is_ok());
assert_eq!(series.len(), 2, "Old entry should have been cleaned up.");
assert_eq!(series.len(), 3, "Old entry should have been cleaned up.");
let entry_3_1 = *series.get_for_era(era_2).unwrap();
let entry_3_2 = *series.get_for_era(era_3).unwrap();
assert_eq!(entry_3_1, entry_2_2);
Expand Down
28 changes: 18 additions & 10 deletions pallets/dapp-staking-v3/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -885,10 +885,11 @@ impl ContractStakingInfo {
}
}

// TODO: the limit `2` might need to be bumped to `3` since we also create one "future" entry when calling "stake"
const STAKING_SERIES_HISTORY: u32 = 3;

/// Composite type that holds information about how much was staked on a contract during some past eras & periods, including the current era & period.
#[derive(Encode, Decode, MaxEncodedLen, Clone, Debug, PartialEq, Eq, TypeInfo, Default)]
pub struct ContractStakingInfoSeries(WeakBoundedVec<ContractStakingInfo, ConstU32<2>>);
pub struct ContractStakingInfoSeries(WeakBoundedVec<ContractStakingInfo, ConstU32<STAKING_SERIES_HISTORY>>);
impl ContractStakingInfoSeries {
/// Length of the series.
pub fn len(&self) -> usize {
Expand Down Expand Up @@ -926,11 +927,17 @@ impl ContractStakingInfoSeries {
}

// Get the most relevant `ContractStakingInfo` instance
let last_element_has_matching_era =
!inner.is_empty() && inner[inner.len() - 1].era() == era;
let last_element_has_matching_period =
!inner.is_empty() && inner[inner.len() - 1].period() == period_info.number;
let (last_element_has_matching_era, last_element_has_matching_period) =
if let Some(last_element) = inner.last() {
(
last_element.era() == era,
last_element.period() == period_info.number,
)
} else {
(false, false)
};

// Prepare the new entry
let mut staking_info = if last_element_has_matching_era {
inner.remove(inner.len() - 1)
} else if last_element_has_matching_period {
Expand All @@ -949,15 +956,16 @@ impl ContractStakingInfoSeries {

// Crate new WeakBoundedVec and cleanup old entries
self.0 = WeakBoundedVec::force_from(inner, None);
self.cleanup_old_entries(era);
self.align_and_cleanup_old_entries(era);

Ok(())
}

/// Remove all entries which are older than 2 eras.
/// Remove all entries which are older than 3 eras.
/// We don't care about them anymore since rewards for them should have been calculated already.
fn cleanup_old_entries(&mut self, era: EraNumber) {
fn align_and_cleanup_old_entries(&mut self, era: EraNumber) {
// TODO: since we can have 3 entries, logic is needed that will align "old" entries around the current era
self.0
.retain(|staking_info| staking_info.era() > era.saturating_sub(2));
.retain(|staking_info| staking_info.era() > era.saturating_sub(STAKING_SERIES_HISTORY));
}
}

0 comments on commit 26d7807

Please sign in to comment.