Line data Source code
1 : #include "fd_epoch_rewards.h"
2 : #include "../../ballet/siphash13/fd_siphash13.h"
3 :
4 : #define POOL_NAME fd_epoch_stake_reward_pool
5 708 : #define POOL_T fd_epoch_stake_reward_t
6 : #define POOL_IDX_T uint
7 : #include "../../util/tmpl/fd_pool.c"
8 :
9 : #define MAP_NAME fd_epoch_stake_reward_map
10 : #define MAP_KEY_T fd_pubkey_t
11 : #define MAP_ELE_T fd_epoch_stake_reward_t
12 9 : #define MAP_KEY stake_pubkey
13 0 : #define MAP_KEY_EQ(k0,k1) (fd_pubkey_eq( k0, k1 ))
14 18 : #define MAP_KEY_HASH(key,seed) (fd_hash( seed, key, sizeof(fd_pubkey_t) ))
15 18 : #define MAP_NEXT next_map
16 387 : #define MAP_IDX_T uint
17 : #include "../../util/tmpl/fd_map_chain.c"
18 :
19 : static inline fd_epoch_stake_reward_t *
20 42 : fd_epoch_rewards_get_stake_reward_pool( fd_epoch_rewards_t const * epoch_rewards ) {
21 42 : return fd_epoch_stake_reward_pool_join( (uchar *)epoch_rewards + epoch_rewards->pool_offset );
22 42 : }
23 :
24 : static inline fd_epoch_stake_reward_map_t *
25 36 : fd_epoch_rewards_get_stake_reward_map( fd_epoch_rewards_t const * epoch_rewards ) {
26 36 : return fd_epoch_stake_reward_map_join( (uchar *)epoch_rewards + epoch_rewards->map_offset );
27 36 : }
28 :
29 : static inline fd_epoch_stake_reward_dlist_t *
30 8811 : fd_epoch_rewards_get_partition_index( fd_epoch_rewards_t const * epoch_rewards, ulong idx ) {
31 8811 : fd_epoch_stake_reward_dlist_t * dlist_idx_zero = (fd_epoch_stake_reward_dlist_t *)((uchar *)epoch_rewards + epoch_rewards->dlists_offset);
32 8811 : fd_epoch_stake_reward_dlist_t * partition_dlist = fd_epoch_stake_reward_dlist_join( dlist_idx_zero + idx );
33 8811 : return partition_dlist;
34 8811 : }
35 :
36 : ulong
37 5364 : fd_epoch_rewards_align( void ) {
38 5364 : return FD_EPOCH_REWARDS_ALIGN;
39 5364 : }
40 :
41 : ulong
42 672 : fd_epoch_rewards_footprint( ulong stake_account_max ) {
43 672 : ulong chain_cnt_est = fd_epoch_stake_reward_map_chain_cnt_est( stake_account_max );
44 :
45 672 : ulong l = FD_LAYOUT_INIT;
46 672 : l = FD_LAYOUT_APPEND( l, fd_epoch_rewards_align(), sizeof(fd_epoch_rewards_t) );
47 672 : l = FD_LAYOUT_APPEND( l, fd_epoch_stake_reward_pool_align(), fd_epoch_stake_reward_pool_footprint( stake_account_max ) );
48 672 : l = FD_LAYOUT_APPEND( l, fd_epoch_stake_reward_map_align(), fd_epoch_stake_reward_map_footprint( chain_cnt_est ) );
49 672 : l = FD_LAYOUT_APPEND( l, fd_epoch_stake_reward_dlist_align(), fd_epoch_stake_reward_dlist_footprint() * FD_REWARDS_MAX_PARTITIONS );
50 672 : return FD_LAYOUT_FINI( l, fd_epoch_rewards_align() );
51 672 : }
52 :
53 : void *
54 : fd_epoch_rewards_new( void * shmem,
55 : ulong stake_account_max,
56 327 : ulong seed ) {
57 :
58 327 : if( FD_UNLIKELY( !shmem ) ) {
59 3 : FD_LOG_WARNING(( "NULL mem" ));
60 3 : return NULL;
61 3 : }
62 :
63 324 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shmem, fd_epoch_rewards_align() ) ) ) {
64 0 : FD_LOG_WARNING(( "misaligned mem" ));
65 0 : return NULL;
66 0 : }
67 :
68 324 : FD_SCRATCH_ALLOC_INIT( l, shmem );
69 324 : fd_epoch_rewards_t * epoch_rewards = FD_SCRATCH_ALLOC_APPEND( l, fd_epoch_rewards_align(), sizeof(fd_epoch_rewards_t) );
70 0 : memset( epoch_rewards, 0, sizeof(fd_epoch_rewards_t) );
71 :
72 324 : void * pool = FD_SCRATCH_ALLOC_APPEND( l, fd_epoch_stake_reward_pool_align(), fd_epoch_stake_reward_pool_footprint( stake_account_max ) );
73 0 : epoch_rewards->pool_offset = (ulong)pool - (ulong)shmem;
74 324 : if( FD_UNLIKELY( !fd_epoch_stake_reward_pool_new( pool, stake_account_max ) ) ) {
75 0 : FD_LOG_WARNING(( "bad pool" ));
76 0 : return NULL;
77 0 : }
78 :
79 324 : ulong chain_cnt_est = fd_epoch_stake_reward_map_chain_cnt_est( stake_account_max );
80 324 : void * map = FD_SCRATCH_ALLOC_APPEND( l, fd_epoch_stake_reward_map_align(), fd_epoch_stake_reward_map_footprint( chain_cnt_est ) );
81 0 : epoch_rewards->map_offset = (ulong)map - (ulong)shmem;
82 324 : if( FD_UNLIKELY( !fd_epoch_stake_reward_map_new( map, chain_cnt_est, seed ) ) ) {
83 0 : FD_LOG_WARNING(( "bad map" ));
84 0 : return NULL;
85 0 : }
86 :
87 237816 : for( ulong i=0UL; i<FD_REWARDS_MAX_PARTITIONS; i++ ) {
88 237492 : void * dlist = FD_SCRATCH_ALLOC_APPEND( l, fd_epoch_stake_reward_dlist_align(), fd_epoch_stake_reward_dlist_footprint() );
89 237492 : if( i==0UL ) epoch_rewards->dlists_offset = (ulong)dlist - (ulong)shmem;
90 237492 : if( FD_UNLIKELY( !fd_epoch_stake_reward_dlist_new( dlist ) ) ) {
91 0 : FD_LOG_WARNING(( "bad dlist at idx %lu", i ));
92 0 : return NULL;
93 0 : }
94 237492 : }
95 :
96 324 : if( FD_UNLIKELY( FD_SCRATCH_ALLOC_FINI( l, fd_epoch_rewards_align() ) != (ulong)shmem+fd_epoch_rewards_footprint( stake_account_max ) ) ) {
97 0 : FD_LOG_WARNING(( "bad footprint" ));
98 0 : return NULL;
99 0 : }
100 :
101 :
102 324 : FD_COMPILER_MFENCE();
103 324 : epoch_rewards->magic = FD_EPOCH_REWARDS_MAGIC;
104 324 : FD_COMPILER_MFENCE();
105 :
106 324 : epoch_rewards->stake_account_max = stake_account_max;
107 :
108 324 : return shmem;
109 324 : }
110 :
111 : fd_epoch_rewards_t *
112 345 : fd_epoch_rewards_join( void * shmem ) {
113 345 : if( FD_UNLIKELY( !shmem ) ) {
114 3 : FD_LOG_WARNING(( "NULL mem" ));
115 3 : return NULL;
116 3 : }
117 :
118 342 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shmem, fd_epoch_rewards_align() ) ) ) {
119 0 : FD_LOG_WARNING(( "misaligned mem" ));
120 0 : return NULL;
121 0 : }
122 :
123 342 : FD_SCRATCH_ALLOC_INIT( l, shmem );
124 342 : fd_epoch_rewards_t * epoch_rewards = FD_SCRATCH_ALLOC_APPEND( l, fd_epoch_rewards_align(), sizeof(fd_epoch_rewards_t) );
125 0 : ulong stake_account_max = epoch_rewards->stake_account_max;
126 :
127 342 : void * pool = FD_SCRATCH_ALLOC_APPEND( l, fd_epoch_stake_reward_pool_align(), fd_epoch_stake_reward_pool_footprint( stake_account_max ) );
128 342 : if( FD_UNLIKELY( !fd_epoch_stake_reward_pool_join( pool ) ) ) {
129 0 : FD_LOG_WARNING(( "bad pool" ));
130 0 : return NULL;
131 0 : }
132 :
133 342 : ulong chain_cnt_est = fd_epoch_stake_reward_map_chain_cnt_est( stake_account_max );
134 342 : void * map = FD_SCRATCH_ALLOC_APPEND( l, fd_epoch_stake_reward_map_align(), fd_epoch_stake_reward_map_footprint( chain_cnt_est ) );
135 342 : if( FD_UNLIKELY( !fd_epoch_stake_reward_map_join( map ) ) ) {
136 0 : FD_LOG_WARNING(( "bad map" ));
137 0 : return NULL;
138 0 : }
139 :
140 251028 : for( ulong i=0UL; i<FD_REWARDS_MAX_PARTITIONS; i++ ) {
141 250686 : void * dlist = FD_SCRATCH_ALLOC_APPEND( l, fd_epoch_stake_reward_dlist_align(), fd_epoch_stake_reward_dlist_footprint() );
142 250686 : if( FD_UNLIKELY( !fd_epoch_stake_reward_dlist_join( dlist ) ) ) {
143 0 : FD_LOG_WARNING(( "bad dlist at idx %lu", i ));
144 0 : return NULL;
145 0 : }
146 250686 : }
147 :
148 342 : if( FD_UNLIKELY( FD_SCRATCH_ALLOC_FINI( l, fd_epoch_rewards_align() )!=(ulong)shmem+fd_epoch_rewards_footprint( stake_account_max ) ) ) {
149 0 : FD_LOG_WARNING(( "bad footprint" ));
150 0 : return NULL;
151 0 : }
152 :
153 342 : if( FD_UNLIKELY( epoch_rewards->magic!=FD_EPOCH_REWARDS_MAGIC ) ) {
154 6 : FD_LOG_WARNING(( "bad magic" ));
155 6 : return NULL;
156 6 : }
157 :
158 336 : return epoch_rewards;
159 342 : }
160 :
161 : void *
162 6 : fd_epoch_rewards_leave( fd_epoch_rewards_t const * epoch_rewards ) {
163 6 : return (void *)epoch_rewards;
164 6 : }
165 :
166 : void *
167 3 : fd_epoch_rewards_delete( void * epoch_rewards_shmem ) {
168 3 : fd_epoch_rewards_t * epoch_rewards = (fd_epoch_rewards_t *)epoch_rewards_shmem;
169 :
170 3 : if( FD_UNLIKELY( !epoch_rewards ) ) {
171 0 : FD_LOG_WARNING(( "NULL epoch_rewards" ));
172 0 : return NULL;
173 0 : }
174 :
175 3 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)epoch_rewards, fd_epoch_rewards_align() ) ) ) {
176 0 : FD_LOG_WARNING(( "misaligned epoch_rewards" ));
177 0 : return NULL;
178 0 : }
179 :
180 3 : if( FD_UNLIKELY( epoch_rewards->magic != FD_EPOCH_REWARDS_MAGIC ) ) {
181 0 : FD_LOG_WARNING(( "bad magic" ));
182 0 : return NULL;
183 0 : }
184 :
185 3 : epoch_rewards->magic = 0UL;
186 :
187 3 : return epoch_rewards_shmem;
188 3 : }
189 :
190 : void
191 12 : fd_epoch_rewards_init( fd_epoch_rewards_t * epoch_rewards ) {
192 12 : fd_epoch_stake_reward_t * stake_reward_pool = fd_epoch_rewards_get_stake_reward_pool( epoch_rewards );
193 8808 : for( ulong i=0UL; i<FD_REWARDS_MAX_PARTITIONS; i++ ) {
194 8796 : fd_epoch_stake_reward_dlist_t * dlist = fd_epoch_rewards_get_partition_index( epoch_rewards, i );
195 8796 : fd_epoch_stake_reward_dlist_remove_all( dlist, stake_reward_pool );
196 8796 : }
197 :
198 12 : fd_epoch_stake_reward_map_t * stake_reward_map = fd_epoch_rewards_get_stake_reward_map( epoch_rewards );
199 12 : fd_epoch_stake_reward_map_reset( stake_reward_map );
200 :
201 12 : fd_epoch_stake_reward_pool_reset( stake_reward_pool );
202 :
203 12 : epoch_rewards->stake_rewards_cnt = 0UL;
204 12 : epoch_rewards->total_stake_rewards = 0UL;
205 12 : }
206 :
207 : void
208 : fd_epoch_rewards_insert( fd_epoch_rewards_t * epoch_rewards,
209 : fd_pubkey_t const * pubkey,
210 : ulong credits,
211 9 : ulong lamports ) {
212 9 : fd_epoch_stake_reward_t * stake_reward_pool = fd_epoch_rewards_get_stake_reward_pool( epoch_rewards );
213 9 : fd_epoch_stake_reward_map_t * stake_reward_map = fd_epoch_rewards_get_stake_reward_map( epoch_rewards );
214 :
215 9 : if( FD_UNLIKELY( fd_epoch_stake_reward_map_ele_query( stake_reward_map, pubkey, NULL, stake_reward_pool ) ) ) {
216 0 : FD_LOG_CRIT(( "invariant violation: stake reward entry already exists" ));
217 0 : }
218 :
219 9 : fd_epoch_stake_reward_t * stake_reward = fd_epoch_stake_reward_pool_ele_acquire( stake_reward_pool );
220 :
221 9 : stake_reward->stake_pubkey = *pubkey;
222 9 : stake_reward->credits_observed = credits;
223 9 : stake_reward->lamports = lamports;
224 :
225 9 : fd_epoch_stake_reward_map_ele_insert( stake_reward_map, stake_reward, stake_reward_pool );
226 :
227 9 : epoch_rewards->total_stake_rewards += lamports;
228 9 : epoch_rewards->stake_rewards_cnt++;
229 :
230 9 : }
231 :
232 : void
233 : fd_epoch_rewards_hash_into_partitions( fd_epoch_rewards_t * epoch_rewards,
234 : fd_hash_t const * parent_blockhash,
235 15 : ulong num_partitions ) {
236 :
237 15 : fd_epoch_stake_reward_t * stake_reward_pool = fd_epoch_rewards_get_stake_reward_pool( epoch_rewards );
238 15 : fd_epoch_stake_reward_map_t * stake_reward_map = fd_epoch_rewards_get_stake_reward_map( epoch_rewards );
239 :
240 15 : epoch_rewards->num_partitions = num_partitions;
241 :
242 15 : for( fd_epoch_stake_reward_map_iter_t iter = fd_epoch_stake_reward_map_iter_init( stake_reward_map, stake_reward_pool );
243 24 : !fd_epoch_stake_reward_map_iter_done( iter, stake_reward_map, stake_reward_pool );
244 15 : iter = fd_epoch_stake_reward_map_iter_next( iter, stake_reward_map, stake_reward_pool ) ) {
245 :
246 9 : fd_epoch_stake_reward_t * stake_reward = fd_epoch_stake_reward_map_iter_ele( iter, stake_reward_map, stake_reward_pool );
247 :
248 9 : fd_siphash13_t sip[1] = {0};
249 9 : fd_siphash13_t * hasher = fd_siphash13_init( sip, 0UL, 0UL );
250 9 : hasher = fd_siphash13_append( hasher, parent_blockhash->hash, sizeof(fd_hash_t) );
251 9 : fd_siphash13_append( hasher, (uchar const *)stake_reward->stake_pubkey.uc, sizeof(fd_pubkey_t) );
252 9 : ulong hash64 = fd_siphash13_fini( hasher );
253 :
254 : /* Now get the correct dlist based on the hash. */
255 9 : ulong partition_index = (ulong)((uint128)num_partitions * (uint128) hash64 / ((uint128)ULONG_MAX + 1));
256 :
257 9 : fd_epoch_stake_reward_dlist_t * partition_dlist = fd_epoch_rewards_get_partition_index( epoch_rewards, partition_index );
258 :
259 9 : fd_epoch_stake_reward_dlist_ele_push_tail( partition_dlist, stake_reward, stake_reward_pool );
260 9 : }
261 15 : }
262 :
263 : fd_epoch_stake_reward_t *
264 9 : fd_epoch_rewards_iter_ele( fd_epoch_rewards_iter_t * iter ) {
265 9 : return fd_epoch_stake_reward_dlist_iter_ele( iter->iter, iter->dlist, iter->pool );
266 9 : }
267 :
268 : fd_epoch_rewards_iter_t *
269 : fd_epoch_rewards_iter_init( fd_epoch_rewards_iter_t * iter,
270 : fd_epoch_rewards_t const * epoch_rewards,
271 6 : ulong partition_idx ) {
272 6 : iter->pool = fd_epoch_rewards_get_stake_reward_pool( epoch_rewards );
273 6 : iter->dlist = fd_epoch_rewards_get_partition_index( epoch_rewards, partition_idx );
274 6 : iter->iter = fd_epoch_stake_reward_dlist_iter_fwd_init( iter->dlist, iter->pool );
275 6 : return iter;
276 6 : }
277 :
278 : int
279 15 : fd_epoch_rewards_iter_done( fd_epoch_rewards_iter_t * iter ) {
280 15 : return fd_epoch_stake_reward_dlist_iter_done( iter->iter, iter->dlist, iter->pool );
281 15 : }
282 :
283 : void
284 9 : fd_epoch_rewards_iter_next( fd_epoch_rewards_iter_t * iter ) {
285 9 : iter->iter = fd_epoch_stake_reward_dlist_iter_fwd_next( iter->iter, iter->dlist, iter->pool );
286 9 : }
|