Skip to content
Open
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
12 changes: 6 additions & 6 deletions define-syscall/src/definitions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,12 @@ define_syscall!(fn sol_get_return_data(data: *mut u8, length: u64, program_id: *
// - `is_writable` (`u8`): `true` if the instruction requires the account to be writable
define_syscall!(fn sol_get_processed_sibling_instruction(index: u64, meta: *mut u8, program_id: *mut u8, data: *mut u8, accounts: *mut u8) -> u64);

// these are to be deprecated once they are superceded by sol_get_sysvar
define_syscall!(fn sol_get_clock_sysvar(addr: *mut u8) -> u64);
define_syscall!(fn sol_get_epoch_schedule_sysvar(addr: *mut u8) -> u64);
define_syscall!(fn sol_get_rent_sysvar(addr: *mut u8) -> u64);
define_syscall!(fn sol_get_last_restart_slot(addr: *mut u8) -> u64);
define_syscall!(fn sol_get_epoch_rewards_sysvar(addr: *mut u8) -> u64);
// these are deprecated - use sol_get_sysvar instead
define_syscall!(#[deprecated(since = "3.0.0", note = "Use `sol_get_sysvar` with `Clock` sysvar address instead")] fn sol_get_clock_sysvar(addr: *mut u8) -> u64);
define_syscall!(#[deprecated(since = "3.0.0", note = "Use `sol_get_sysvar` with `EpochSchedule` sysvar address instead")] fn sol_get_epoch_schedule_sysvar(addr: *mut u8) -> u64);
define_syscall!(#[deprecated(since = "3.0.0", note = "Use `sol_get_sysvar` with `Rent` sysvar address instead")] fn sol_get_rent_sysvar(addr: *mut u8) -> u64);
define_syscall!(#[deprecated(since = "3.0.0", note = "Use `sol_get_sysvar` with `LastRestartSlot` sysvar address instead")] fn sol_get_last_restart_slot(addr: *mut u8) -> u64);
define_syscall!(#[deprecated(since = "3.0.0", note = "Use `sol_get_sysvar` with `EpochRewards` sysvar address instead")] fn sol_get_epoch_rewards_sysvar(addr: *mut u8) -> u64);

// this cannot go through sol_get_sysvar but can be removed once no longer in use
define_syscall!(fn sol_get_fees_sysvar(addr: *mut u8) -> u64);
14 changes: 8 additions & 6 deletions define-syscall/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ pub mod definitions;
))]
#[macro_export]
macro_rules! define_syscall {
(fn $name:ident($($arg:ident: $typ:ty),*) -> $ret:ty) => {
($(#[$attr:meta])* fn $name:ident($($arg:ident: $typ:ty),*) -> $ret:ty) => {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Enabling deprecated to be passed through (as in the original sol_get_sysvar PR)

$(#[$attr])*
#[inline]
pub unsafe fn $name($($arg: $typ),*) -> $ret {
// this enum is used to force the hash to be computed in a const context
Expand All @@ -23,8 +24,8 @@ macro_rules! define_syscall {
}

};
(fn $name:ident($($arg:ident: $typ:ty),*)) => {
define_syscall!(fn $name($($arg: $typ),*) -> ());
($(#[$attr:meta])* fn $name:ident($($arg:ident: $typ:ty),*)) => {
define_syscall!($(#[$attr])* fn $name($($arg: $typ),*) -> ());
}
}

Expand All @@ -34,13 +35,14 @@ macro_rules! define_syscall {
)))]
#[macro_export]
macro_rules! define_syscall {
(fn $name:ident($($arg:ident: $typ:ty),*) -> $ret:ty) => {
($(#[$attr:meta])* fn $name:ident($($arg:ident: $typ:ty),*) -> $ret:ty) => {
extern "C" {
$(#[$attr])*
pub fn $name($($arg: $typ),*) -> $ret;
}
};
(fn $name:ident($($arg:ident: $typ:ty),*)) => {
define_syscall!(fn $name($($arg: $typ),*) -> ());
($(#[$attr:meta])* fn $name:ident($($arg:ident: $typ:ty),*)) => {
define_syscall!($(#[$attr])* fn $name($($arg: $typ),*) -> ());
}
}

Expand Down
91 changes: 56 additions & 35 deletions epoch-rewards/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,18 @@ extern crate std;
use serde_derive::{Deserialize, Serialize};
use {solana_hash::Hash, solana_sdk_macro::CloneZeroed};

#[repr(C, align(16))]
#[repr(C)]
#[cfg_attr(feature = "frozen-abi", derive(solana_frozen_abi_macro::AbiExample))]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[derive(Debug, PartialEq, Eq, Default, CloneZeroed)]
pub struct EpochRewards {
/// The starting block height of the rewards distribution in the current
/// epoch
pub distribution_starting_block_height: u64,
distribution_starting_block_height: [u8; 8],

/// Number of partitions in the rewards distribution in the current epoch,
/// used to generate an EpochRewardsHasher
pub num_partitions: u64,
num_partitions: [u8; 8],

/// The blockhash of the parent block of the first block in the epoch, used
/// to seed an EpochRewardsHasher
Expand All @@ -39,64 +39,85 @@ pub struct EpochRewards {
/// The total rewards points calculated for the current epoch, where points
/// equals the sum of (delegated stake * credits observed) for all
/// delegations
pub total_points: u128,
total_points: [u8; 16],

/// The total rewards calculated for the current epoch. This may be greater
/// than the total `distributed_rewards` at the end of the rewards period,
/// due to rounding and inability to deliver rewards smaller than 1 lamport.
pub total_rewards: u64,
total_rewards: [u8; 8],

/// The rewards currently distributed for the current epoch, in lamports
pub distributed_rewards: u64,
distributed_rewards: [u8; 8],

/// Whether the rewards period (including calculation and distribution) is
/// active
pub active: bool,
pub active: u8,
}

impl EpochRewards {
pub fn distribute(&mut self, amount: u64) {
let new_distributed_rewards = self.distributed_rewards.saturating_add(amount);
assert!(new_distributed_rewards <= self.total_rewards);
self.distributed_rewards = new_distributed_rewards;
pub fn distribution_starting_block_height(&self) -> u64 {
u64::from_le_bytes(self.distribution_starting_block_height)
}
}

#[cfg(test)]
mod tests {
use super::*;
pub fn num_partitions(&self) -> u64 {
u64::from_le_bytes(self.num_partitions)
}

pub fn parent_blockhash(&self) -> &Hash {
&self.parent_blockhash
}

pub fn total_points(&self) -> u128 {
u128::from_le_bytes(self.total_points)
}

pub fn total_rewards(&self) -> u64 {
u64::from_le_bytes(self.total_rewards)
}

impl EpochRewards {
pub fn new(
total_rewards: u64,
distributed_rewards: u64,
distribution_starting_block_height: u64,
) -> Self {
Self {
total_rewards,
distributed_rewards,
distribution_starting_block_height,
..Self::default()
}
pub fn distributed_rewards(&self) -> u64 {
u64::from_le_bytes(self.distributed_rewards)
}

pub fn active(&self) -> bool {
match self.active {
0 => false,
1 => true,
_ => panic!("invalid active value"),
}
}

#[test]
fn test_epoch_rewards_new() {
let epoch_rewards = EpochRewards::new(100, 0, 64);
pub fn new(
total_rewards: u64,
distributed_rewards: u64,
distribution_starting_block_height: u64,
) -> Self {
Self {
distribution_starting_block_height: distribution_starting_block_height.to_le_bytes(),
total_rewards: total_rewards.to_le_bytes(),
distributed_rewards: distributed_rewards.to_le_bytes(),
..Self::default()
}
}

assert_eq!(epoch_rewards.total_rewards, 100);
assert_eq!(epoch_rewards.distributed_rewards, 0);
assert_eq!(epoch_rewards.distribution_starting_block_height, 64);
pub fn distribute(&mut self, amount: u64) {
let new_distributed_rewards = self.distributed_rewards().saturating_add(amount);
assert!(new_distributed_rewards <= self.total_rewards());
self.distributed_rewards = new_distributed_rewards.to_le_bytes();
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_epoch_rewards_distribute() {
let mut epoch_rewards = EpochRewards::new(100, 0, 64);
epoch_rewards.distribute(100);

assert_eq!(epoch_rewards.total_rewards, 100);
assert_eq!(epoch_rewards.distributed_rewards, 100);
assert_eq!(epoch_rewards.total_rewards(), 100);
assert_eq!(epoch_rewards.distributed_rewards(), 100);
}

#[test]
Expand Down
87 changes: 53 additions & 34 deletions epoch-schedule/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,24 +56,24 @@ pub const MINIMUM_SLOTS_PER_EPOCH: u64 = 32;
#[derive(Debug, CloneZeroed, PartialEq, Eq)]
pub struct EpochSchedule {
/// The maximum number of slots in each epoch.
pub slots_per_epoch: u64,
slots_per_epoch: [u8; 8],

/// A number of slots before beginning of an epoch to calculate
/// a leader schedule for that epoch.
pub leader_schedule_slot_offset: u64,
leader_schedule_slot_offset: [u8; 8],

/// Whether epochs start short and grow.
pub warmup: bool,
pub warmup: u8,

/// The first epoch after the warmup period.
///
/// Basically: `log2(slots_per_epoch) - log2(MINIMUM_SLOTS_PER_EPOCH)`.
pub first_normal_epoch: u64,
first_normal_epoch: [u8; 8],

/// The first slot after the warmup period.
///
/// Basically: `MINIMUM_SLOTS_PER_EPOCH * (2.pow(first_normal_epoch) - 1)`.
pub first_normal_slot: u64,
first_normal_slot: [u8; 8],
}

impl Default for EpochSchedule {
Expand All @@ -87,6 +87,30 @@ impl Default for EpochSchedule {
}

impl EpochSchedule {
pub fn slots_per_epoch(&self) -> u64 {
u64::from_le_bytes(self.slots_per_epoch)
}

pub fn leader_schedule_slot_offset(&self) -> u64 {
u64::from_le_bytes(self.leader_schedule_slot_offset)
}

pub fn warmup(&self) -> bool {
match self.warmup {
0 => false,
1 => true,
_ => panic!("invalid warmup value"),
}
}

pub fn first_normal_epoch(&self) -> u64 {
u64::from_le_bytes(self.first_normal_epoch)
}

pub fn first_normal_slot(&self) -> u64 {
u64::from_le_bytes(self.first_normal_slot)
}

pub fn new(slots_per_epoch: u64) -> Self {
Self::custom(slots_per_epoch, slots_per_epoch, true)
}
Expand All @@ -113,40 +137,40 @@ impl EpochSchedule {
(0, 0)
};
EpochSchedule {
slots_per_epoch,
leader_schedule_slot_offset,
warmup,
first_normal_epoch,
first_normal_slot,
slots_per_epoch: slots_per_epoch.to_le_bytes(),
leader_schedule_slot_offset: leader_schedule_slot_offset.to_le_bytes(),
warmup: warmup as u8,
first_normal_epoch: first_normal_epoch.to_le_bytes(),
first_normal_slot: first_normal_slot.to_le_bytes(),
}
}

/// get the length of the given epoch (in slots)
pub fn get_slots_in_epoch(&self, epoch: u64) -> u64 {
if epoch < self.first_normal_epoch {
if epoch < self.first_normal_epoch() {
2u64.saturating_pow(
(epoch as u32).saturating_add(MINIMUM_SLOTS_PER_EPOCH.trailing_zeros()),
)
} else {
self.slots_per_epoch
self.slots_per_epoch()
}
}

/// get the epoch for which the given slot should save off
/// information about stakers
pub fn get_leader_schedule_epoch(&self, slot: u64) -> u64 {
if slot < self.first_normal_slot {
if slot < self.first_normal_slot() {
// until we get to normal slots, behave as if leader_schedule_slot_offset == slots_per_epoch
self.get_epoch_and_slot_index(slot).0.saturating_add(1)
} else {
let new_slots_since_first_normal_slot = slot.saturating_sub(self.first_normal_slot);
let new_first_normal_leader_schedule_slot =
new_slots_since_first_normal_slot.saturating_add(self.leader_schedule_slot_offset);
let new_slots_since_first_normal_slot = slot.saturating_sub(self.first_normal_slot());
let new_first_normal_leader_schedule_slot = new_slots_since_first_normal_slot
.saturating_add(self.leader_schedule_slot_offset());
let new_epochs_since_first_normal_leader_schedule =
new_first_normal_leader_schedule_slot
.checked_div(self.slots_per_epoch)
.checked_div(self.slots_per_epoch())
.unwrap_or(0);
self.first_normal_epoch
self.first_normal_epoch()
.saturating_add(new_epochs_since_first_normal_leader_schedule)
}
}
Expand All @@ -158,7 +182,7 @@ impl EpochSchedule {

/// get epoch and offset into the epoch for the given slot
pub fn get_epoch_and_slot_index(&self, slot: u64) -> (u64, u64) {
if slot < self.first_normal_slot {
if slot < self.first_normal_slot() {
let epoch = slot
.saturating_add(MINIMUM_SLOTS_PER_EPOCH)
.saturating_add(1)
Expand All @@ -175,28 +199,28 @@ impl EpochSchedule {
slot.saturating_sub(epoch_len.saturating_sub(MINIMUM_SLOTS_PER_EPOCH)),
)
} else {
let normal_slot_index = slot.saturating_sub(self.first_normal_slot);
let normal_slot_index = slot.saturating_sub(self.first_normal_slot());
let normal_epoch_index = normal_slot_index
.checked_div(self.slots_per_epoch)
.checked_div(self.slots_per_epoch())
.unwrap_or(0);
let epoch = self.first_normal_epoch.saturating_add(normal_epoch_index);
let epoch = self.first_normal_epoch().saturating_add(normal_epoch_index);
let slot_index = normal_slot_index
.checked_rem(self.slots_per_epoch)
.checked_rem(self.slots_per_epoch())
.unwrap_or(0);
(epoch, slot_index)
}
}

pub fn get_first_slot_in_epoch(&self, epoch: u64) -> u64 {
if epoch <= self.first_normal_epoch {
if epoch <= self.first_normal_epoch() {
2u64.saturating_pow(epoch as u32)
.saturating_sub(1)
.saturating_mul(MINIMUM_SLOTS_PER_EPOCH)
} else {
epoch
.saturating_sub(self.first_normal_epoch)
.saturating_mul(self.slots_per_epoch)
.saturating_add(self.first_normal_slot)
.saturating_sub(self.first_normal_epoch())
.saturating_mul(self.slots_per_epoch())
.saturating_add(self.first_normal_slot())
}
}

Expand Down Expand Up @@ -271,13 +295,8 @@ mod tests {

#[test]
fn test_clone() {
let epoch_schedule = EpochSchedule {
slots_per_epoch: 1,
leader_schedule_slot_offset: 2,
warmup: true,
first_normal_epoch: 4,
first_normal_slot: 5,
};
let epoch_schedule =
EpochSchedule::custom(MINIMUM_SLOTS_PER_EPOCH, MINIMUM_SLOTS_PER_EPOCH, true);
#[allow(clippy::clone_on_copy)]
let cloned_epoch_schedule = epoch_schedule.clone();
assert_eq!(cloned_epoch_schedule, epoch_schedule);
Expand Down
6 changes: 3 additions & 3 deletions genesis-config/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ pub const UNUSED_DEFAULT: u64 = 1024;
#[cfg_attr(
feature = "frozen-abi",
derive(AbiExample),
frozen_abi(digest = "3tUUJkZiUUGfuNCXbDuDR6KCQYPsh3m3cPw5vVUSt113")
frozen_abi(digest = "CR76YX4Y3eHSCoRzkBEaJv7p3vAShUT56fX8WERoLBAp")
)]
#[cfg_attr(
feature = "serde",
Expand Down Expand Up @@ -244,8 +244,8 @@ impl fmt::Display for GenesisConfig {
self.ticks_per_slot,
self.poh_config.hashes_per_tick,
self.poh_config.target_tick_duration,
self.epoch_schedule.slots_per_epoch,
if self.epoch_schedule.warmup {
self.epoch_schedule.slots_per_epoch(),
if self.epoch_schedule.warmup() {
"en"
} else {
"dis"
Expand Down
Loading