Line data Source code
1 : #ifndef HEADER_fd_src_flamenco_rewards_fd_stake_rewards_h
2 : #define HEADER_fd_src_flamenco_rewards_fd_stake_rewards_h
3 :
4 : #include "../fd_flamenco_base.h"
5 :
6 : /* fd_stake_rewards tracks pending partitioned epoch rewards across
7 : forks.
8 :
9 : The access pattern is as follows:
10 : 1. Insertion/Hashing: This occurs at the epoch boundary after stake
11 : rewards are computed before rewards are distributed. The stake
12 : account along with corresponding lamports and credits observed are
13 : hashed into a rewards partition. These rewards will be paid out
14 : later.
15 : 2. Iteration: A partition is paid out per slot. All of the accounts
16 : in the partition are iterated over and the rewards are distributed
17 : to the stake accounts involved.
18 :
19 : The protocol level guarantees is just that there can be up to 43200
20 : rewards slots. There is no limit on the number of stake rewards paid
21 : out per slot.
22 :
23 : Reward entries use cache_cnt+1 equivalent buffers: up to cache_cnt
24 : completed windows and one window under construction. Entries are
25 : built directly in the buffer that becomes resident, so finishing a
26 : window does not move them. Per-bank metadata is dynamically sized
27 : and does not multiply reward-entry storage. Finishing a fork when
28 : the completed-window cache is full evicts the least recently finished
29 : window, but keeps that fork's metadata. If an evicted window is
30 : needed, the caller recalculates it.
31 :
32 : As a note, the structure is also only partially fork-aware. It safely
33 : assumes that the epoch boundary of a second epoch will not happen
34 : while the stake rewards are still being paid out of a first epoch.
35 : The protocol guarantees this because stake rewards must be paid out
36 : within the first 10% of an epoch.
37 :
38 : It is assumed that there will not be concurrent users of the stake
39 : rewards structure. The caller is expected to manage synchronization
40 : between threads. */
41 :
42 312 : #define FD_STAKE_REWARDS_ALIGN (128UL)
43 :
44 : struct fd_stake_rewards;
45 : typedef struct fd_stake_rewards fd_stake_rewards_t;
46 :
47 : FD_PROTOTYPES_BEGIN
48 :
49 : /* fd_stake_rewards_align is used to get the alignment for the stake
50 : rewards structure. */
51 :
52 : ulong
53 : fd_stake_rewards_align( void );
54 :
55 : /* fd_stake_rewards_footprint returns the footprint given the maximum
56 : number of stake accounts and banks. max_stake_accounts is the
57 : capacity of each in-memory window, not a bound on the rewards in an
58 : epoch. max_bank_cnt sizes metadata, not reward-entry buffers.
59 : cache_cnt is the number of completed windows retained in memory and
60 : must be in [1,max_bank_cnt+1]. Storage includes one additional
61 : construction buffer. An ancestor bank can retain an older evicted
62 : generation, so there is one metadata slot per bank. An additional
63 : slot allows a cached window to be replaced before its old shared
64 : handle is released. */
65 :
66 : ulong
67 : fd_stake_rewards_footprint( ulong max_stake_accounts,
68 : ulong max_bank_cnt,
69 : ulong cache_cnt );
70 :
71 : /* fd_stake_rewards_new creates a new stake rewards structure. */
72 :
73 : void *
74 : fd_stake_rewards_new( void * shmem,
75 : ulong max_stake_accounts,
76 : ulong max_bank_cnt,
77 : ulong cache_cnt );
78 :
79 : /* fd_stake_rewards_join joins the caller to the stake rewards
80 : structure. */
81 :
82 : fd_stake_rewards_t *
83 : fd_stake_rewards_join( void * shmem );
84 :
85 : /* fd_stake_rewards_clear resets the stake rewards structure to a
86 : post-new state. */
87 :
88 : void
89 : fd_stake_rewards_clear( fd_stake_rewards_t * stake_rewards );
90 :
91 : /* Each stake rewards fork idx must be refcnt'd since they are shared
92 : across banks. fd_stake_rewards_acquire increments the reference
93 : count and fd_stake_rewards_release decrements it. Once the count
94 : reaches zero, the fork is purged. */
95 :
96 : void
97 : fd_stake_rewards_acquire( fd_stake_rewards_t * stake_rewards,
98 : ushort fork_idx );
99 :
100 : void
101 : fd_stake_rewards_release( fd_stake_rewards_t * stake_rewards,
102 : ushort fork_idx );
103 :
104 : ulong
105 : fd_stake_rewards_refcnt( fd_stake_rewards_t const * stake_rewards,
106 : ushort fork_idx );
107 :
108 : /* fd_stake_rewards_free_cnt returns how many forks can still be
109 : acquired, including the replacement slot. A bank needs one whenever
110 : it computes rewards it does not already hold: at an epoch boundary,
111 : or when the partition it has to distribute falls outside its
112 : window. */
113 :
114 : ulong
115 : fd_stake_rewards_free_cnt( fd_stake_rewards_t const * stake_rewards );
116 :
117 : /* fd_stake_rewards_init starts reward calculation for a new fork and
118 : returns its index. win_lo is the first partition to retain. The
119 : fork claims the free construction buffer. No other fork may be
120 : staged. */
121 :
122 : ushort
123 : fd_stake_rewards_init( fd_stake_rewards_t * stake_rewards,
124 : fd_hash_t const * parent_blockhash,
125 : ulong starting_block_height,
126 : uint partitions_cnt,
127 : uint win_lo,
128 : ulong max_rewards_cnt );
129 :
130 : /* fd_stake_rewards_window_{lo,hi} return the inclusive range of
131 : partitions that a fork currently holds. A staged fork reports its
132 : range but is not iterable until fd_stake_rewards_fini. Both return
133 : UINT_MAX for an evicted fork. The caller must recalculate a missing
134 : window. */
135 :
136 : uint
137 : fd_stake_rewards_window_lo( fd_stake_rewards_t const * stake_rewards,
138 : ushort fork_idx );
139 :
140 : uint
141 : fd_stake_rewards_window_hi( fd_stake_rewards_t const * stake_rewards,
142 : ushort fork_idx );
143 :
144 : /* fd_stake_rewards_insert inserts a new stake reward for a given fork.
145 : It hashes the reward into the appropriate partition. The reward is
146 : only stored if its partition falls inside the fork's window, but it
147 : always counts towards fd_stake_rewards_total_rewards and
148 : fd_stake_rewards_total_block_rewards. lamports is the inflation
149 : reward, block_reward the SIMD-0123 block revenue share. */
150 :
151 : void
152 : fd_stake_rewards_insert( fd_stake_rewards_t * stake_rewards,
153 : ushort fork_idx,
154 : fd_pubkey_t const * pubkey,
155 : ulong lamports,
156 : ulong credits_observed,
157 : ulong block_reward );
158 :
159 : /* fd_stake_rewards_fini makes the construction buffer resident without
160 : moving its entries. An empty window releases its buffer. The oldest
161 : resident window is evicted when the completed-window cache is full. */
162 :
163 : void
164 : fd_stake_rewards_fini( fd_stake_rewards_t * stake_rewards,
165 : ushort fork_idx );
166 :
167 : /* Iterator for the rewards in one resident fork partition.
168 : partition_idx must lie inside the fork's window. The caller should
169 : not interleave any other iteration or modification of the stake
170 : rewards structure while iterating.
171 :
172 : Note: block_reward_out may be NULL.
173 :
174 : Example use:
175 : for( fd_stake_rewards_iter_init( stake_rewards, fork_idx,
176 : partition_idx );
177 : !fd_stake_rewards_iter_done( stake_rewards );
178 : fd_stake_rewards_iter_next( stake_rewards, fork_idx ) ) {
179 : fd_pubkey_t pubkey;
180 : ulong lamports;
181 : ulong credits_observed;
182 : ulong block_reward_out;
183 : fd_stake_rewards_iter_ele( stake_rewards, fork_idx, &pubkey,
184 : &lamports, &credits_observed,
185 : &block_reward_out );
186 : }
187 : */
188 :
189 : void
190 : fd_stake_rewards_iter_init( fd_stake_rewards_t * stake_rewards,
191 : ushort fork_idx,
192 : uint partition_idx );
193 :
194 : void
195 : fd_stake_rewards_iter_next( fd_stake_rewards_t * stake_rewards,
196 : ushort fork_idx );
197 :
198 : int
199 : fd_stake_rewards_iter_done( fd_stake_rewards_t * stake_rewards );
200 :
201 : void
202 : fd_stake_rewards_iter_ele( fd_stake_rewards_t * stake_rewards,
203 : ushort fork_idx,
204 : fd_pubkey_t * pubkey_out,
205 : ulong * lamports_out,
206 : ulong * credits_observed_out,
207 : ulong * block_reward_out );
208 :
209 : /* Simple accessors for stake rewards information. */
210 :
211 : ulong
212 : fd_stake_rewards_total_rewards( fd_stake_rewards_t const * stake_rewards,
213 : ushort fork_idx );
214 :
215 : ulong
216 : fd_stake_rewards_total_block_rewards( fd_stake_rewards_t const * stake_rewards,
217 : ushort fork_idx );
218 :
219 : uint
220 : fd_stake_rewards_num_partitions( fd_stake_rewards_t const * stake_rewards,
221 : ushort fork_idx );
222 :
223 : ulong
224 : fd_stake_rewards_starting_block_height( fd_stake_rewards_t const * stake_rewards,
225 : ushort fork_idx );
226 :
227 : ulong
228 : fd_stake_rewards_exclusive_ending_block_height( fd_stake_rewards_t const * stake_rewards,
229 : ushort fork_idx );
230 :
231 : FD_PROTOTYPES_END
232 :
233 : #endif /* HEADER_fd_src_flamenco_rewards_fd_stake_rewards_h */
|