Skip to content

Commit fa5db38

Browse files
committed
rework sysvars to byte arrays and accessors
1 parent 6070ca0 commit fa5db38

File tree

7 files changed

+168
-257
lines changed

7 files changed

+168
-257
lines changed

epoch-rewards/src/lib.rs

Lines changed: 62 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -19,18 +19,18 @@ extern crate std;
1919
use serde_derive::{Deserialize, Serialize};
2020
use {solana_hash::Hash, solana_sdk_macro::CloneZeroed};
2121

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

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

3535
/// The blockhash of the parent block of the first block in the epoch, used
3636
/// to seed an EpochRewardsHasher
@@ -39,70 +39,94 @@ pub struct EpochRewards {
3939
/// The total rewards points calculated for the current epoch, where points
4040
/// equals the sum of (delegated stake * credits observed) for all
4141
/// delegations
42-
pub total_points: u128,
42+
total_points: [u8; 16],
4343

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

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

5252
/// Whether the rewards period (including calculation and distribution) is
5353
/// active
54-
pub active: bool,
54+
pub active: u8,
5555
}
5656

5757
impl EpochRewards {
58-
pub fn distribute(&mut self, amount: u64) {
59-
let new_distributed_rewards = self.distributed_rewards.saturating_add(amount);
60-
assert!(new_distributed_rewards <= self.total_rewards);
61-
self.distributed_rewards = new_distributed_rewards;
58+
pub fn distribution_starting_block_height(&self) -> u64 {
59+
u64::from_le_bytes(self.distribution_starting_block_height)
6260
}
63-
}
6461

65-
#[cfg(test)]
66-
mod tests {
67-
use super::*;
62+
pub fn num_partitions(&self) -> u64 {
63+
u64::from_le_bytes(self.num_partitions)
64+
}
6865

69-
impl EpochRewards {
70-
pub fn new(
71-
total_rewards: u64,
72-
distributed_rewards: u64,
73-
distribution_starting_block_height: u64,
74-
) -> Self {
75-
Self {
76-
total_rewards,
77-
distributed_rewards,
78-
distribution_starting_block_height,
79-
..Self::default()
80-
}
81-
}
66+
pub fn parent_blockhash(&self) -> &Hash {
67+
&self.parent_blockhash
8268
}
8369

84-
#[test]
85-
fn test_epoch_rewards_new() {
86-
let epoch_rewards = EpochRewards::new(100, 0, 64);
70+
pub fn total_points(&self) -> u128 {
71+
u128::from_le_bytes(self.total_points)
72+
}
73+
74+
pub fn total_rewards(&self) -> u64 {
75+
u64::from_le_bytes(self.total_rewards)
76+
}
77+
78+
pub fn distributed_rewards(&self) -> u64 {
79+
u64::from_le_bytes(self.distributed_rewards)
80+
}
81+
82+
pub fn active(&self) -> bool {
83+
self.active != 0
84+
}
85+
86+
pub fn new(
87+
distribution_starting_block_height: u64,
88+
num_partitions: u64,
89+
parent_blockhash: Hash,
90+
total_points: u128,
91+
total_rewards: u64,
92+
distributed_rewards: u64,
93+
active: bool,
94+
) -> Self {
95+
Self {
96+
distribution_starting_block_height: distribution_starting_block_height.to_le_bytes(),
97+
num_partitions: num_partitions.to_le_bytes(),
98+
parent_blockhash,
99+
total_points: total_points.to_le_bytes(),
100+
total_rewards: total_rewards.to_le_bytes(),
101+
distributed_rewards: distributed_rewards.to_le_bytes(),
102+
active: active as u8,
103+
}
104+
}
87105

88-
assert_eq!(epoch_rewards.total_rewards, 100);
89-
assert_eq!(epoch_rewards.distributed_rewards, 0);
90-
assert_eq!(epoch_rewards.distribution_starting_block_height, 64);
106+
pub fn distribute(&mut self, amount: u64) {
107+
let new_distributed_rewards = self.distributed_rewards().saturating_add(amount);
108+
assert!(new_distributed_rewards <= self.total_rewards());
109+
self.distributed_rewards = new_distributed_rewards.to_le_bytes();
91110
}
111+
}
112+
113+
#[cfg(test)]
114+
mod tests {
115+
use super::*;
92116

93117
#[test]
94118
fn test_epoch_rewards_distribute() {
95-
let mut epoch_rewards = EpochRewards::new(100, 0, 64);
119+
let mut epoch_rewards = EpochRewards::new(64, 0, Hash::default(), 0, 100, 0, false);
96120
epoch_rewards.distribute(100);
97121

98-
assert_eq!(epoch_rewards.total_rewards, 100);
99-
assert_eq!(epoch_rewards.distributed_rewards, 100);
122+
assert_eq!(epoch_rewards.total_rewards(), 100);
123+
assert_eq!(epoch_rewards.distributed_rewards(), 100);
100124
}
101125

102126
#[test]
103127
#[should_panic(expected = "new_distributed_rewards <= self.total_rewards")]
104128
fn test_epoch_rewards_distribute_panic() {
105-
let mut epoch_rewards = EpochRewards::new(100, 0, 64);
129+
let mut epoch_rewards = EpochRewards::new(64, 0, Hash::default(), 0, 100, 0, false);
106130
epoch_rewards.distribute(200);
107131
}
108132
}

epoch-schedule/src/lib.rs

Lines changed: 52 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -56,24 +56,24 @@ pub const MINIMUM_SLOTS_PER_EPOCH: u64 = 32;
5656
#[derive(Debug, CloneZeroed, PartialEq, Eq)]
5757
pub struct EpochSchedule {
5858
/// The maximum number of slots in each epoch.
59-
pub slots_per_epoch: u64,
59+
slots_per_epoch: [u8; 8],
6060

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

6565
/// Whether epochs start short and grow.
66-
pub warmup: bool,
66+
pub warmup: u8,
6767

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

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

7979
impl Default for EpochSchedule {
@@ -87,6 +87,30 @@ impl Default for EpochSchedule {
8787
}
8888

8989
impl EpochSchedule {
90+
pub fn slots_per_epoch(&self) -> u64 {
91+
u64::from_le_bytes(self.slots_per_epoch)
92+
}
93+
94+
pub fn leader_schedule_slot_offset(&self) -> u64 {
95+
u64::from_le_bytes(self.leader_schedule_slot_offset)
96+
}
97+
98+
pub fn warmup(&self) -> bool {
99+
match self.warmup {
100+
0 => false,
101+
1 => true,
102+
_ => panic!("invalid warmup value"),
103+
}
104+
}
105+
106+
pub fn first_normal_epoch(&self) -> u64 {
107+
u64::from_le_bytes(self.first_normal_epoch)
108+
}
109+
110+
pub fn first_normal_slot(&self) -> u64 {
111+
u64::from_le_bytes(self.first_normal_slot)
112+
}
113+
90114
pub fn new(slots_per_epoch: u64) -> Self {
91115
Self::custom(slots_per_epoch, slots_per_epoch, true)
92116
}
@@ -113,40 +137,40 @@ impl EpochSchedule {
113137
(0, 0)
114138
};
115139
EpochSchedule {
116-
slots_per_epoch,
117-
leader_schedule_slot_offset,
118-
warmup,
119-
first_normal_epoch,
120-
first_normal_slot,
140+
slots_per_epoch: slots_per_epoch.to_le_bytes(),
141+
leader_schedule_slot_offset: leader_schedule_slot_offset.to_le_bytes(),
142+
warmup: warmup as u8,
143+
first_normal_epoch: first_normal_epoch.to_le_bytes(),
144+
first_normal_slot: first_normal_slot.to_le_bytes(),
121145
}
122146
}
123147

124148
/// get the length of the given epoch (in slots)
125149
pub fn get_slots_in_epoch(&self, epoch: u64) -> u64 {
126-
if epoch < self.first_normal_epoch {
150+
if epoch < self.first_normal_epoch() {
127151
2u64.saturating_pow(
128152
(epoch as u32).saturating_add(MINIMUM_SLOTS_PER_EPOCH.trailing_zeros()),
129153
)
130154
} else {
131-
self.slots_per_epoch
155+
self.slots_per_epoch()
132156
}
133157
}
134158

135159
/// get the epoch for which the given slot should save off
136160
/// information about stakers
137161
pub fn get_leader_schedule_epoch(&self, slot: u64) -> u64 {
138-
if slot < self.first_normal_slot {
162+
if slot < self.first_normal_slot() {
139163
// until we get to normal slots, behave as if leader_schedule_slot_offset == slots_per_epoch
140164
self.get_epoch_and_slot_index(slot).0.saturating_add(1)
141165
} else {
142-
let new_slots_since_first_normal_slot = slot.saturating_sub(self.first_normal_slot);
143-
let new_first_normal_leader_schedule_slot =
144-
new_slots_since_first_normal_slot.saturating_add(self.leader_schedule_slot_offset);
166+
let new_slots_since_first_normal_slot = slot.saturating_sub(self.first_normal_slot());
167+
let new_first_normal_leader_schedule_slot = new_slots_since_first_normal_slot
168+
.saturating_add(self.leader_schedule_slot_offset());
145169
let new_epochs_since_first_normal_leader_schedule =
146170
new_first_normal_leader_schedule_slot
147-
.checked_div(self.slots_per_epoch)
171+
.checked_div(self.slots_per_epoch())
148172
.unwrap_or(0);
149-
self.first_normal_epoch
173+
self.first_normal_epoch()
150174
.saturating_add(new_epochs_since_first_normal_leader_schedule)
151175
}
152176
}
@@ -158,7 +182,7 @@ impl EpochSchedule {
158182

159183
/// get epoch and offset into the epoch for the given slot
160184
pub fn get_epoch_and_slot_index(&self, slot: u64) -> (u64, u64) {
161-
if slot < self.first_normal_slot {
185+
if slot < self.first_normal_slot() {
162186
let epoch = slot
163187
.saturating_add(MINIMUM_SLOTS_PER_EPOCH)
164188
.saturating_add(1)
@@ -175,28 +199,28 @@ impl EpochSchedule {
175199
slot.saturating_sub(epoch_len.saturating_sub(MINIMUM_SLOTS_PER_EPOCH)),
176200
)
177201
} else {
178-
let normal_slot_index = slot.saturating_sub(self.first_normal_slot);
202+
let normal_slot_index = slot.saturating_sub(self.first_normal_slot());
179203
let normal_epoch_index = normal_slot_index
180-
.checked_div(self.slots_per_epoch)
204+
.checked_div(self.slots_per_epoch())
181205
.unwrap_or(0);
182-
let epoch = self.first_normal_epoch.saturating_add(normal_epoch_index);
206+
let epoch = self.first_normal_epoch().saturating_add(normal_epoch_index);
183207
let slot_index = normal_slot_index
184-
.checked_rem(self.slots_per_epoch)
208+
.checked_rem(self.slots_per_epoch())
185209
.unwrap_or(0);
186210
(epoch, slot_index)
187211
}
188212
}
189213

190214
pub fn get_first_slot_in_epoch(&self, epoch: u64) -> u64 {
191-
if epoch <= self.first_normal_epoch {
215+
if epoch <= self.first_normal_epoch() {
192216
2u64.saturating_pow(epoch as u32)
193217
.saturating_sub(1)
194218
.saturating_mul(MINIMUM_SLOTS_PER_EPOCH)
195219
} else {
196220
epoch
197-
.saturating_sub(self.first_normal_epoch)
198-
.saturating_mul(self.slots_per_epoch)
199-
.saturating_add(self.first_normal_slot)
221+
.saturating_sub(self.first_normal_epoch())
222+
.saturating_mul(self.slots_per_epoch())
223+
.saturating_add(self.first_normal_slot())
200224
}
201225
}
202226

@@ -271,13 +295,7 @@ mod tests {
271295

272296
#[test]
273297
fn test_clone() {
274-
let epoch_schedule = EpochSchedule {
275-
slots_per_epoch: 1,
276-
leader_schedule_slot_offset: 2,
277-
warmup: true,
278-
first_normal_epoch: 4,
279-
first_normal_slot: 5,
280-
};
298+
let epoch_schedule = EpochSchedule::custom(1, 2, true);
281299
#[allow(clippy::clone_on_copy)]
282300
let cloned_epoch_schedule = epoch_schedule.clone();
283301
assert_eq!(cloned_epoch_schedule, epoch_schedule);

0 commit comments

Comments
 (0)