use {
crate::{program_error::ProgramError, stake::MINIMUM_DELINQUENT_EPOCHS_FOR_DEACTIVATION},
solana_clock::Epoch,
};
pub fn get_minimum_delegation() -> Result<u64, ProgramError> {
let instruction = super::instruction::get_minimum_delegation();
crate::program::invoke_unchecked(&instruction, &[])?;
get_minimum_delegation_return_data()
}
fn get_minimum_delegation_return_data() -> Result<u64, ProgramError> {
crate::program::get_return_data()
.ok_or(ProgramError::InvalidInstructionData)
.and_then(|(program_id, return_data)| {
(program_id == super::program::id())
.then_some(return_data)
.ok_or(ProgramError::IncorrectProgramId)
})
.and_then(|return_data| {
return_data
.try_into()
.or(Err(ProgramError::InvalidInstructionData))
})
.map(u64::from_le_bytes)
}
pub fn acceptable_reference_epoch_credits(
epoch_credits: &[(Epoch, u64, u64)],
current_epoch: Epoch,
) -> bool {
if let Some(epoch_index) = epoch_credits
.len()
.checked_sub(MINIMUM_DELINQUENT_EPOCHS_FOR_DEACTIVATION)
{
let mut epoch = current_epoch;
for (vote_epoch, ..) in epoch_credits[epoch_index..].iter().rev() {
if *vote_epoch != epoch {
return false;
}
epoch = epoch.saturating_sub(1);
}
true
} else {
false
}
}
pub fn eligible_for_deactivate_delinquent(
epoch_credits: &[(Epoch, u64, u64)],
current_epoch: Epoch,
) -> bool {
match epoch_credits.last() {
None => true,
Some((epoch, ..)) => {
if let Some(minimum_epoch) =
current_epoch.checked_sub(MINIMUM_DELINQUENT_EPOCHS_FOR_DEACTIVATION as Epoch)
{
*epoch <= minimum_epoch
} else {
false
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_acceptable_reference_epoch_credits() {
let epoch_credits = [];
assert!(!acceptable_reference_epoch_credits(&epoch_credits, 0));
let epoch_credits = [(0, 42, 42), (1, 42, 42), (2, 42, 42), (3, 42, 42)];
assert!(!acceptable_reference_epoch_credits(&epoch_credits, 3));
let epoch_credits = [
(0, 42, 42),
(1, 42, 42),
(2, 42, 42),
(3, 42, 42),
(4, 42, 42),
];
assert!(!acceptable_reference_epoch_credits(&epoch_credits, 3));
assert!(acceptable_reference_epoch_credits(&epoch_credits, 4));
let epoch_credits = [
(1, 42, 42),
(2, 42, 42),
(3, 42, 42),
(4, 42, 42),
(5, 42, 42),
];
assert!(acceptable_reference_epoch_credits(&epoch_credits, 5));
let epoch_credits = [
(0, 42, 42),
(2, 42, 42),
(3, 42, 42),
(4, 42, 42),
(5, 42, 42),
];
assert!(!acceptable_reference_epoch_credits(&epoch_credits, 5));
}
#[test]
fn test_eligible_for_deactivate_delinquent() {
let epoch_credits = [];
assert!(eligible_for_deactivate_delinquent(&epoch_credits, 42));
let epoch_credits = [(0, 42, 42)];
assert!(!eligible_for_deactivate_delinquent(&epoch_credits, 0));
let epoch_credits = [(0, 42, 42)];
assert!(!eligible_for_deactivate_delinquent(
&epoch_credits,
MINIMUM_DELINQUENT_EPOCHS_FOR_DEACTIVATION as Epoch - 1
));
assert!(eligible_for_deactivate_delinquent(
&epoch_credits,
MINIMUM_DELINQUENT_EPOCHS_FOR_DEACTIVATION as Epoch
));
let epoch_credits = [(100, 42, 42)];
assert!(!eligible_for_deactivate_delinquent(
&epoch_credits,
100 + MINIMUM_DELINQUENT_EPOCHS_FOR_DEACTIVATION as Epoch - 1
));
assert!(eligible_for_deactivate_delinquent(
&epoch_credits,
100 + MINIMUM_DELINQUENT_EPOCHS_FOR_DEACTIVATION as Epoch
));
}
}