Line data Source code
1 : #include "fd_epoch_rewards.h"
2 : #include "../../ballet/siphash13/fd_siphash13.h"
3 :
4 : ulong
5 843 : fd_epoch_rewards_align( void ) {
6 843 : return FD_EPOCH_REWARDS_ALIGN;
7 843 : }
8 :
9 : ulong
10 21 : fd_epoch_rewards_footprint( ulong stake_account_max ) {
11 21 : ulong l = FD_LAYOUT_INIT;
12 21 : l = FD_LAYOUT_APPEND( l, fd_epoch_rewards_align(), sizeof(fd_epoch_rewards_t) );
13 21 : l = FD_LAYOUT_APPEND( l, fd_epoch_stake_reward_pool_align(), fd_epoch_stake_reward_pool_footprint( stake_account_max ) );
14 21 : l = FD_LAYOUT_APPEND( l, fd_epoch_stake_reward_dlist_align(), fd_epoch_stake_reward_dlist_footprint() * FD_REWARDS_MAX_PARTITIONS );
15 21 : return FD_LAYOUT_FINI( l, fd_epoch_rewards_align() );
16 21 : }
17 :
18 : void *
19 9 : fd_epoch_rewards_new( void * shmem, ulong stake_account_max ) {
20 :
21 9 : if( FD_UNLIKELY( !shmem ) ) {
22 3 : FD_LOG_WARNING(( "NULL mem" ));
23 3 : return NULL;
24 3 : }
25 :
26 6 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shmem, fd_epoch_rewards_align() ) ) ) {
27 0 : FD_LOG_WARNING(( "misaligned mem" ));
28 0 : return NULL;
29 0 : }
30 :
31 6 : FD_SCRATCH_ALLOC_INIT( l, shmem );
32 6 : fd_epoch_rewards_t * epoch_rewards = FD_SCRATCH_ALLOC_APPEND( l, fd_epoch_rewards_align(), sizeof(fd_epoch_rewards_t) );
33 :
34 6 : void * pool = FD_SCRATCH_ALLOC_APPEND( l, fd_epoch_stake_reward_pool_align(), fd_epoch_stake_reward_pool_footprint( stake_account_max ) );
35 6 : if( FD_UNLIKELY( !fd_epoch_stake_reward_pool_new( pool, stake_account_max ) ) ) {
36 0 : FD_LOG_WARNING(( "bad pool" ));
37 0 : return NULL;
38 0 : }
39 :
40 3096 : for( ulong i=0UL; i<FD_REWARDS_MAX_PARTITIONS; i++ ) {
41 3090 : void * dlist = FD_SCRATCH_ALLOC_APPEND( l, fd_epoch_stake_reward_dlist_align(), fd_epoch_stake_reward_dlist_footprint() );
42 3090 : if( FD_UNLIKELY( !fd_epoch_stake_reward_dlist_new( dlist ) ) ) {
43 0 : FD_LOG_WARNING(( "bad dlist at idx %lu", i ));
44 0 : return NULL;
45 0 : }
46 3090 : }
47 :
48 6 : if( FD_UNLIKELY( FD_SCRATCH_ALLOC_FINI( l, fd_epoch_rewards_align() ) != (ulong)shmem+fd_epoch_rewards_footprint( stake_account_max ) ) ) {
49 0 : FD_LOG_WARNING(( "bad footprint" ));
50 0 : return NULL;
51 0 : }
52 :
53 6 : memset( epoch_rewards, 0, sizeof(fd_epoch_rewards_t) );
54 :
55 6 : epoch_rewards->magic = FD_EPOCH_REWARDS_MAGIC;
56 6 : epoch_rewards->stake_account_max_ = stake_account_max;
57 :
58 6 : return shmem;
59 6 : }
60 :
61 : fd_epoch_rewards_t *
62 15 : fd_epoch_rewards_join( void * shmem ) {
63 15 : if( FD_UNLIKELY( !shmem ) ) {
64 3 : FD_LOG_WARNING(( "NULL mem" ));
65 3 : return NULL;
66 3 : }
67 :
68 12 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shmem, fd_epoch_rewards_align() ) ) ) {
69 0 : FD_LOG_WARNING(( "misaligned mem" ));
70 0 : return NULL;
71 0 : }
72 :
73 12 : FD_SCRATCH_ALLOC_INIT( l, shmem );
74 12 : fd_epoch_rewards_t * epoch_rewards = FD_SCRATCH_ALLOC_APPEND( l, fd_epoch_rewards_align(), sizeof(fd_epoch_rewards_t) );
75 0 : ulong stake_account_max = epoch_rewards->stake_account_max_;
76 :
77 12 : void * pool = FD_SCRATCH_ALLOC_APPEND( l, fd_epoch_stake_reward_pool_align(), fd_epoch_stake_reward_pool_footprint( stake_account_max ) );
78 12 : if( FD_UNLIKELY( !fd_epoch_stake_reward_pool_join( pool ) ) ) {
79 0 : FD_LOG_WARNING(( "bad pool" ));
80 0 : return NULL;
81 0 : }
82 :
83 6192 : for( ulong i=0UL; i<FD_REWARDS_MAX_PARTITIONS; i++ ) {
84 6180 : void * dlist = FD_SCRATCH_ALLOC_APPEND( l, fd_epoch_stake_reward_dlist_align(), fd_epoch_stake_reward_dlist_footprint() );
85 6180 : if( FD_UNLIKELY( !fd_epoch_stake_reward_dlist_join( dlist ) ) ) {
86 0 : FD_LOG_WARNING(( "bad dlist at idx %lu", i ));
87 0 : return NULL;
88 0 : }
89 6180 : }
90 :
91 12 : if( FD_UNLIKELY( FD_SCRATCH_ALLOC_FINI( l, fd_epoch_rewards_align() ) != (ulong)shmem+fd_epoch_rewards_footprint( stake_account_max ) ) ) {
92 0 : FD_LOG_WARNING(( "bad footprint" ));
93 0 : return NULL;
94 0 : }
95 :
96 12 : if( FD_UNLIKELY( epoch_rewards->magic!=FD_EPOCH_REWARDS_MAGIC ) ) {
97 6 : FD_LOG_WARNING(( "bad magic" ));
98 6 : return NULL;
99 6 : }
100 :
101 6 : return epoch_rewards;
102 12 : }
103 :
104 : void *
105 6 : fd_epoch_rewards_leave( fd_epoch_rewards_t const * epoch_rewards ) {
106 6 : return (void *)epoch_rewards;
107 6 : }
108 :
109 : void *
110 3 : fd_epoch_rewards_delete( void * epoch_rewards_shmem ) {
111 3 : fd_epoch_rewards_t * epoch_rewards = (fd_epoch_rewards_t *)epoch_rewards_shmem;
112 :
113 3 : if( FD_UNLIKELY( !epoch_rewards ) ) {
114 0 : FD_LOG_WARNING(( "NULL epoch_rewards" ));
115 0 : return NULL;
116 0 : }
117 :
118 3 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)epoch_rewards, fd_epoch_rewards_align() ) ) ) {
119 0 : FD_LOG_WARNING(( "misaligned epoch_rewards" ));
120 0 : return NULL;
121 0 : }
122 :
123 3 : if( FD_UNLIKELY( epoch_rewards->magic != FD_EPOCH_REWARDS_MAGIC ) ) {
124 0 : FD_LOG_WARNING(( "bad magic" ));
125 0 : return NULL;
126 0 : }
127 :
128 3 : epoch_rewards->magic = 0UL;
129 :
130 3 : return epoch_rewards_shmem;
131 3 : }
132 :
133 : fd_epoch_stake_reward_dlist_t *
134 324 : fd_epoch_rewards_get_partition_index( fd_epoch_rewards_t const * epoch_rewards, ulong idx ) {
135 324 : if( FD_UNLIKELY( idx >= epoch_rewards->num_partitions_ ) ) {
136 9 : FD_LOG_WARNING(( "idx: %lu is greater than num_partitions: %lu", idx, epoch_rewards->num_partitions_ ));
137 9 : return NULL;
138 9 : }
139 :
140 315 : FD_SCRATCH_ALLOC_INIT( l, epoch_rewards );
141 315 : FD_SCRATCH_ALLOC_APPEND( l, fd_epoch_rewards_align(), sizeof(fd_epoch_rewards_t) );
142 315 : FD_SCRATCH_ALLOC_APPEND( l, fd_epoch_stake_reward_pool_align(), fd_epoch_stake_reward_pool_footprint( epoch_rewards->stake_account_max_ ) );
143 15891 : for( ulong i=0UL; i<idx; i++ ) {
144 15576 : FD_SCRATCH_ALLOC_APPEND( l, fd_epoch_stake_reward_dlist_align(), fd_epoch_stake_reward_dlist_footprint() );
145 15576 : }
146 315 : void * dlist = FD_SCRATCH_ALLOC_APPEND( l, fd_epoch_stake_reward_dlist_align(), fd_epoch_stake_reward_dlist_footprint() );
147 :
148 0 : fd_epoch_stake_reward_dlist_t * partition_dlist = fd_epoch_stake_reward_dlist_join( dlist );
149 315 : if( FD_UNLIKELY( !partition_dlist ) ) {
150 0 : FD_LOG_WARNING(( "bad dlist" ));
151 0 : return NULL;
152 0 : }
153 315 : return partition_dlist;
154 315 : }
155 :
156 : fd_epoch_stake_reward_t *
157 15 : fd_epoch_rewards_get_stake_reward_pool( fd_epoch_rewards_t const * epoch_rewards ) {
158 15 : if( FD_UNLIKELY( !epoch_rewards ) ) {
159 3 : FD_LOG_WARNING(( "NULL epoch_rewards" ));
160 3 : return NULL;
161 3 : }
162 :
163 12 : FD_SCRATCH_ALLOC_INIT( l, epoch_rewards );
164 12 : FD_SCRATCH_ALLOC_APPEND( l, fd_epoch_rewards_align(), sizeof(fd_epoch_rewards_t) );
165 12 : void * pool = FD_SCRATCH_ALLOC_APPEND( l, fd_epoch_stake_reward_pool_align(), fd_epoch_stake_reward_pool_footprint( epoch_rewards->stake_account_max_ ) );
166 0 : fd_epoch_stake_reward_t * stake_reward_pool = fd_epoch_stake_reward_pool_join( pool );
167 12 : if( FD_UNLIKELY( !stake_reward_pool ) ) {
168 0 : FD_LOG_WARNING(( "bad stake_reward_pool" ));
169 0 : return NULL;
170 0 : }
171 12 : return stake_reward_pool;
172 12 : }
173 :
174 : int
175 : fd_epoch_rewards_hash_and_insert( fd_epoch_rewards_t * epoch_rewards,
176 : fd_hash_t const * parent_blockhash,
177 : fd_pubkey_t const * pubkey,
178 : ulong credits,
179 18 : ulong lamports ) {
180 :
181 18 : if( FD_UNLIKELY( !epoch_rewards ) ) {
182 3 : FD_LOG_WARNING(( "NULL epoch_rewards" ));
183 3 : return 1;
184 3 : }
185 :
186 15 : if( FD_UNLIKELY( !parent_blockhash ) ) {
187 3 : FD_LOG_WARNING(( "NULL parent_blockhash" ));
188 3 : return 1;
189 3 : }
190 :
191 12 : if( FD_UNLIKELY( !pubkey ) ) {
192 3 : FD_LOG_WARNING(( "NULL pubkey" ));
193 3 : return 1;
194 3 : }
195 :
196 : /* First figure out which partition the pubkey belongs to. */
197 9 : fd_siphash13_t sip[1] = {0};
198 9 : fd_siphash13_t * hasher = fd_siphash13_init( sip, 0UL, 0UL );
199 :
200 9 : hasher = fd_siphash13_append( hasher, parent_blockhash->hash, sizeof(fd_hash_t) );
201 9 : fd_siphash13_append( hasher, (uchar const *)pubkey, sizeof(fd_pubkey_t) );
202 9 : ulong hash64 = fd_siphash13_fini( hasher );
203 :
204 : /* Now get the correct dlist based on the hash. */
205 9 : ulong partition_index = (ulong)((uint128)epoch_rewards->num_partitions_ * (uint128) hash64 / ((uint128)ULONG_MAX + 1));
206 :
207 9 : fd_epoch_stake_reward_dlist_t * partition_dlist = fd_epoch_rewards_get_partition_index( epoch_rewards, partition_index );
208 9 : if( FD_UNLIKELY( !partition_dlist ) ) {
209 0 : FD_LOG_WARNING(( "bad partition_dlist" ));
210 0 : return 1;
211 0 : }
212 :
213 : /* Acquire a stake reward from the pool's free list and add it to
214 : the tail of the dlist. */
215 9 : fd_epoch_stake_reward_t * stake_reward_pool = fd_epoch_rewards_get_stake_reward_pool( epoch_rewards );
216 9 : if( FD_UNLIKELY( !stake_reward_pool ) ) {
217 0 : FD_LOG_WARNING(( "bad stake_reward_pool" ));
218 0 : return 1;
219 0 : }
220 :
221 9 : if( FD_UNLIKELY( !fd_epoch_stake_reward_pool_free( stake_reward_pool ) ) ) {
222 0 : FD_LOG_WARNING(( "stake_reward_pool is full" ));
223 0 : return 1;
224 0 : }
225 :
226 9 : fd_epoch_stake_reward_t * stake_reward = fd_epoch_stake_reward_pool_ele_acquire( stake_reward_pool );
227 9 : if( FD_UNLIKELY( !stake_reward ) ) {
228 0 : FD_LOG_WARNING(( "bad stake_reward" ));
229 0 : return 1;
230 0 : }
231 :
232 9 : stake_reward->stake_pubkey = *pubkey;
233 9 : stake_reward->credits_observed = credits;
234 9 : stake_reward->lamports = lamports;
235 :
236 9 : fd_epoch_stake_reward_dlist_ele_push_tail( partition_dlist, stake_reward, stake_reward_pool );
237 9 : return 0;
238 9 : }
239 :
|