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 3606 : #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. */
148 :
149 : void
150 : fd_stake_rewards_insert( fd_stake_rewards_t * stake_rewards,
151 : ushort fork_idx,
152 : fd_pubkey_t const * pubkey,
153 : ulong lamports,
154 : ulong credits_observed );
155 :
156 : /* fd_stake_rewards_fini makes the construction buffer resident without
157 : moving its entries. An empty window releases its buffer. The oldest
158 : resident window is evicted when the completed-window cache is full. */
159 :
160 : void
161 : fd_stake_rewards_fini( fd_stake_rewards_t * stake_rewards,
162 : ushort fork_idx );
163 :
164 : /* Iterator for the rewards in one resident fork partition.
165 : partition_idx must lie inside the fork's window. The caller should
166 : not interleave any other iteration or modification of the stake
167 : rewards structure while iterating.
168 :
169 : Example use:
170 : for( fd_stake_rewards_iter_init( stake_rewards, fork_idx,
171 : partition_idx );
172 : !fd_stake_rewards_iter_done( stake_rewards );
173 : fd_stake_rewards_iter_next( stake_rewards, fork_idx ) ) {
174 : fd_pubkey_t pubkey;
175 : ulong lamports;
176 : ulong credits_observed;
177 : fd_stake_rewards_iter_ele( stake_rewards, fork_idx, &pubkey,
178 : &lamports, &credits_observed );
179 : }
180 : */
181 :
182 : void
183 : fd_stake_rewards_iter_init( fd_stake_rewards_t * stake_rewards,
184 : ushort fork_idx,
185 : uint partition_idx );
186 :
187 : void
188 : fd_stake_rewards_iter_next( fd_stake_rewards_t * stake_rewards,
189 : ushort fork_idx );
190 :
191 : int
192 : fd_stake_rewards_iter_done( fd_stake_rewards_t * stake_rewards );
193 :
194 : void
195 : fd_stake_rewards_iter_ele( fd_stake_rewards_t * stake_rewards,
196 : ushort fork_idx,
197 : fd_pubkey_t * pubkey_out,
198 : ulong * lamports_out,
199 : ulong * credits_observed_out );
200 :
201 : /* Simple accessors for stake rewards information. */
202 :
203 : ulong
204 : fd_stake_rewards_total_rewards( fd_stake_rewards_t const * stake_rewards,
205 : ushort fork_idx );
206 :
207 : uint
208 : fd_stake_rewards_num_partitions( fd_stake_rewards_t const * stake_rewards,
209 : ushort fork_idx );
210 :
211 : ulong
212 : fd_stake_rewards_starting_block_height( fd_stake_rewards_t const * stake_rewards,
213 : ushort fork_idx );
214 :
215 : ulong
216 : fd_stake_rewards_exclusive_ending_block_height( fd_stake_rewards_t const * stake_rewards,
217 : ushort fork_idx );
218 :
219 : FD_PROTOTYPES_END
220 :
221 : #endif /* HEADER_fd_src_flamenco_rewards_fd_stake_rewards_h */
|