1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
//! Code related to partitioned rewards distribution
//!
use solana_sdk::clock::Slot;
#[allow(dead_code)]
#[derive(Debug)]
/// Configuration options for partitioned epoch rewards.
/// This struct allows various forms of testing, especially prior to feature activation.
pub(crate) struct PartitionedEpochRewardsConfig {
/// Number of blocks for reward calculation and storing vote accounts.
/// Distributing rewards to stake accounts begins AFTER this many blocks.
/// Normally, this will be 1.
/// if force_one_slot_partitioned_rewards, this will be 0 (ie. we take 0 blocks just for reward calculation)
pub(crate) reward_calculation_num_blocks: Slot,
/// number of stake accounts to store in one block during partititioned reward interval
/// normally, this is a number tuned for reasonable performance, such as 4096 accounts/block
/// if force_one_slot_partitioned_rewards, this will usually be u64::MAX so that all stake accounts are written in the first block
pub(crate) stake_account_stores_per_block: Slot,
/// if true, end of epoch bank rewards will force using partitioned rewards distribution.
/// see `set_test_enable_partitioned_rewards`
pub(crate) test_enable_partitioned_rewards: bool,
/// if true, end of epoch non-partitioned bank rewards will test the partitioned rewards distribution vote and stake accounts
/// This has a significant performance impact on the first slot in each new epoch.
pub(crate) test_compare_partitioned_epoch_rewards: bool,
}
impl Default for PartitionedEpochRewardsConfig {
fn default() -> Self {
Self {
/// reward calculation happens synchronously during the first block of the epoch boundary.
/// So, # blocks for reward calculation is 1.
reward_calculation_num_blocks: 1,
/// # stake accounts to store in one block during partitioned reward interval
/// Target to store 64 rewards per entry/tick in a block. A block has a minimum of 64
/// entries/tick. This gives 4096 total rewards to store in one block.
/// This constant affects consensus.
stake_account_stores_per_block: 4096,
test_enable_partitioned_rewards: false,
test_compare_partitioned_epoch_rewards: false,
}
}
}
#[derive(Debug, Default, Clone, Copy)]
pub enum TestPartitionedEpochRewards {
#[default]
None,
CompareResults,
ForcePartitionedEpochRewardsInOneBlock,
}
#[allow(dead_code)]
impl PartitionedEpochRewardsConfig {
pub(crate) fn new(test: TestPartitionedEpochRewards) -> Self {
match test {
TestPartitionedEpochRewards::None => Self::default(),
TestPartitionedEpochRewards::CompareResults => {
Self::set_test_compare_partitioned_epoch_rewards()
}
TestPartitionedEpochRewards::ForcePartitionedEpochRewardsInOneBlock => {
Self::set_test_enable_partitioned_rewards()
}
}
}
/// All rewards will be distributed in the first block in the epoch, maching
/// consensus for the non-partitioned rewards, but running all the partitioned rewards
/// code.
fn set_test_enable_partitioned_rewards() -> Self {
Self {
reward_calculation_num_blocks: 0,
stake_account_stores_per_block: u64::MAX,
test_enable_partitioned_rewards: true,
// irrelevant if we are not running old code path
test_compare_partitioned_epoch_rewards: false,
}
}
/// All rewards will be distributed in the first block in the epoch as normal.
/// Then, the partitioned rewards code will calculate expected results and compare to
/// the old code path's results.
fn set_test_compare_partitioned_epoch_rewards() -> Self {
Self {
test_compare_partitioned_epoch_rewards: true,
..PartitionedEpochRewardsConfig::default()
}
}
}