Line data Source code
1 : #include "fd_multi_epoch_leaders.h"
2 :
3 : void *
4 45 : fd_multi_epoch_leaders_new( void * shmem ) {
5 45 : if( FD_UNLIKELY( !shmem ) ) {
6 0 : FD_LOG_WARNING(( "NULL shmem" ));
7 0 : return NULL;
8 0 : }
9 :
10 45 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shmem, fd_multi_epoch_leaders_align() ) ) ) {
11 0 : FD_LOG_WARNING(( "misaligned shmem" ));
12 0 : return NULL;
13 0 : }
14 :
15 45 : fd_multi_epoch_leaders_t * leaders = (fd_multi_epoch_leaders_t *)shmem;
16 :
17 : /* Initialize all epochs to satisfy invariants */
18 45 : fd_vote_stake_weight_t dummy_stakes[ 1 ] = {{ .vote_key = {{0}}, .id_key = {{0}}, .stake = 1UL }};
19 135 : for( ulong i=0UL; i<MULTI_EPOCH_LEADERS_EPOCH_CNT; i++ ) {
20 90 : leaders->lsched[i] = fd_epoch_leaders_join( fd_epoch_leaders_new( leaders->_lsched[i], i, 0UL, 1UL, 1UL, dummy_stakes, 0UL ) );
21 90 : FD_TEST( leaders->lsched[i] );
22 90 : leaders->init_done[i] = 0;
23 90 : }
24 :
25 45 : return shmem;
26 45 : }
27 :
28 : fd_multi_epoch_leaders_t *
29 45 : fd_multi_epoch_leaders_join( void * shleaders ) { return shleaders; }
30 :
31 : void *
32 24 : fd_multi_epoch_leaders_leave( fd_multi_epoch_leaders_t * mleaders ) { return mleaders; }
33 :
34 : void *
35 24 : fd_multi_epoch_leaders_delete( void * shleaders ) { return shleaders; }
36 :
37 : fd_epoch_leaders_t const *
38 : fd_multi_epoch_leaders_get_lsched_for_epoch( fd_multi_epoch_leaders_t const * mleaders,
39 6 : ulong epoch ) {
40 6 : fd_epoch_leaders_t const * even_lsched = fd_ptr_if( mleaders->init_done[0] & !!(mleaders->lsched[0]->epoch==epoch), mleaders->lsched[0], NULL );
41 6 : fd_epoch_leaders_t const * odd_lsched = fd_ptr_if( mleaders->init_done[1] & !!(mleaders->lsched[1]->epoch==epoch), mleaders->lsched[1], NULL );
42 6 : return fd_ptr_if( !!even_lsched, even_lsched, odd_lsched );
43 6 : }
44 :
45 : static inline ulong
46 : fd_multi_epoch_leaders_get_epoch_idx( fd_multi_epoch_leaders_t const * mleaders,
47 69186 : ulong slot ) {
48 69186 : fd_epoch_leaders_t const * even_lsched = mleaders->lsched[0];
49 69186 : fd_epoch_leaders_t const * odd_lsched = mleaders->lsched[1];
50 :
51 69186 : ulong even_match = fd_ulong_if( mleaders->init_done[0] & !!(even_lsched->slot0<=slot) & !!(slot<even_lsched->slot0+even_lsched->slot_cnt), 0UL, ULONG_MAX );
52 69186 : ulong odd_match = fd_ulong_if( mleaders->init_done[1] & !!(odd_lsched->slot0<=slot) & !!(slot<odd_lsched->slot0+odd_lsched->slot_cnt), 1UL, ULONG_MAX );
53 :
54 69186 : return fd_ulong_if( even_match!=ULONG_MAX, even_match, odd_match );
55 69186 : }
56 :
57 : fd_epoch_leaders_t const *
58 : fd_multi_epoch_leaders_get_lsched_for_slot( fd_multi_epoch_leaders_t const * mleaders,
59 159 : ulong slot ) {
60 159 : const ulong epoch_idx = fd_multi_epoch_leaders_get_epoch_idx( mleaders, slot );
61 159 : if( FD_UNLIKELY( epoch_idx==ULONG_MAX ) ) return NULL;
62 153 : return mleaders->lsched[epoch_idx];
63 159 : }
64 :
65 : ulong
66 : fd_multi_epoch_leaders_get_next_slot( fd_multi_epoch_leaders_t const * mleaders,
67 : ulong start_slot,
68 15 : fd_pubkey_t const * leader_q ) {
69 :
70 : /* Find epoch containing start_slot */
71 15 : ulong epoch_idx = fd_multi_epoch_leaders_get_epoch_idx( mleaders, start_slot );
72 15 : if( FD_UNLIKELY( epoch_idx==ULONG_MAX ) ) return ULONG_MAX;
73 :
74 : /* Start at epoch_idx and seek next slot (across epochs) */
75 24 : for( ulong i=0; i<MULTI_EPOCH_LEADERS_EPOCH_CNT; i++ ) {
76 21 : ulong epoch_i = (epoch_idx + i) % MULTI_EPOCH_LEADERS_EPOCH_CNT;
77 :
78 21 : fd_epoch_leaders_t const * epoch_lsched = mleaders->lsched[ epoch_i ];
79 21 : ulong slot0 = epoch_lsched->slot0;
80 21 : ulong slot_end = slot0 + epoch_lsched->slot_cnt;
81 :
82 : /* skip older epochs */
83 21 : if( FD_UNLIKELY( !mleaders->init_done[epoch_i] ) ) continue;
84 :
85 21 : ulong start_slot_it = fd_ulong_max( start_slot, slot0 );
86 9165 : for( ulong slot=start_slot_it; slot<slot_end; slot++ ) {
87 9156 : fd_pubkey_t const * leader = fd_epoch_leaders_get( epoch_lsched, slot );
88 9156 : if( FD_UNLIKELY( !memcmp( leader->key, leader_q->key, 32UL ) ) ) return slot;
89 9156 : }
90 21 : }
91 :
92 3 : return ULONG_MAX;
93 15 : }
94 :
95 : void
96 : fd_multi_epoch_leaders_stake_msg_init( fd_multi_epoch_leaders_t * mleaders,
97 78 : fd_stake_weight_msg_t const * msg ) {
98 78 : if( FD_UNLIKELY( msg->staked_vote_cnt > MAX_STAKED_LEADERS ) )
99 0 : FD_LOG_ERR(( "Multi-epoch leaders received a malformed update with %lu stakes in it,"
100 78 : " but the maximum allowed is %lu", msg->staked_vote_cnt, MAX_STAKED_LEADERS ));
101 :
102 78 : mleaders->scratch->epoch = msg->epoch;
103 78 : mleaders->scratch->start_slot = msg->start_slot;
104 78 : mleaders->scratch->slot_cnt = msg->slot_cnt;
105 78 : mleaders->scratch->staked_cnt = msg->staked_vote_cnt;
106 :
107 78 : fd_memcpy( mleaders->vote_stake_weight, fd_stake_weight_msg_stake_weights( msg ), msg->staked_vote_cnt*sizeof(fd_vote_stake_weight_t) );
108 78 : }
109 :
110 : void
111 : fd_multi_epoch_leaders_epoch_msg_init( fd_multi_epoch_leaders_t * mleaders,
112 0 : fd_epoch_info_msg_t const * msg ) {
113 0 : if( FD_UNLIKELY( msg->staked_vote_cnt > MAX_COMPRESSED_STAKE_WEIGHTS ) )
114 0 : FD_LOG_ERR(( "Multi-epoch leaders received a malformed update with %lu stakes in it,"
115 0 : " but the maximum allowed is %lu", msg->staked_vote_cnt, MAX_COMPRESSED_STAKE_WEIGHTS ));
116 :
117 0 : mleaders->scratch->epoch = msg->epoch;
118 0 : mleaders->scratch->start_slot = msg->start_slot;
119 0 : mleaders->scratch->slot_cnt = msg->slot_cnt;
120 0 : mleaders->scratch->staked_cnt = msg->staked_vote_cnt;
121 :
122 0 : fd_vote_stake_weight_t const * weights = fd_epoch_info_msg_stake_weights( msg );
123 0 : fd_memcpy( mleaders->vote_stake_weight, weights, msg->staked_vote_cnt*sizeof(fd_vote_stake_weight_t) );
124 0 : }
125 :
126 : void
127 75 : fd_multi_epoch_leaders_stake_msg_fini( fd_multi_epoch_leaders_t * mleaders ) {
128 75 : const ulong epoch = mleaders->scratch->epoch;
129 75 : const ulong slot0 = mleaders->scratch->start_slot;
130 75 : const ulong slot_cnt = mleaders->scratch->slot_cnt;
131 75 : const ulong pub_cnt = mleaders->scratch->staked_cnt;
132 75 : const ulong epoch_idx = epoch % MULTI_EPOCH_LEADERS_EPOCH_CNT;
133 :
134 75 : fd_vote_stake_weight_t * stakes = mleaders->vote_stake_weight;
135 :
136 : /* Clear old data */
137 75 : fd_epoch_leaders_delete( fd_epoch_leaders_leave( mleaders->lsched[epoch_idx] ) );
138 :
139 : /* Populate new lsched */
140 75 : uchar * lsched_mem = mleaders->_lsched[epoch_idx];
141 75 : mleaders->lsched[epoch_idx] = fd_epoch_leaders_join( fd_epoch_leaders_new(
142 75 : lsched_mem, epoch, slot0, slot_cnt,
143 75 : pub_cnt, stakes, 0UL ) );
144 75 : mleaders->init_done[epoch_idx] = 1;
145 75 : }
146 :
147 : void
148 0 : fd_multi_epoch_leaders_epoch_msg_fini( fd_multi_epoch_leaders_t * mleaders ) {
149 0 : fd_multi_epoch_leaders_stake_msg_fini( mleaders );
150 0 : }
151 :
152 : fd_pubkey_t const *
153 : fd_multi_epoch_leaders_get_leader_for_slot( fd_multi_epoch_leaders_t const * mleaders,
154 69012 : ulong slot ) {
155 69012 : const ulong epoch_idx = fd_multi_epoch_leaders_get_epoch_idx( mleaders, slot );
156 69012 : if( FD_UNLIKELY( epoch_idx==ULONG_MAX ) ) return NULL;
157 69012 : return fd_epoch_leaders_get( mleaders->lsched[epoch_idx], slot );
158 69012 : }
159 :
160 : fd_multi_epoch_leaders_lsched_sorted_t
161 15 : fd_multi_epoch_leaders_get_sorted_lscheds( fd_multi_epoch_leaders_t const * mleaders ) {
162 15 : fd_multi_epoch_leaders_lsched_sorted_t ret = { .lscheds = { NULL, NULL } };
163 15 : fd_epoch_leaders_t * even_option = fd_ptr_if( mleaders->init_done[0], mleaders->lsched[0], NULL );
164 15 : fd_epoch_leaders_t * odd_option = fd_ptr_if( mleaders->init_done[1], mleaders->lsched[1], NULL );
165 :
166 : /* Sort by epoch if both non-null, null comes first */
167 15 : if( even_option && odd_option ) {
168 9 : ret.lscheds[0] = fd_ptr_if( even_option->epoch < odd_option->epoch, even_option, odd_option );
169 9 : ret.lscheds[1] = fd_ptr_if( even_option->epoch < odd_option->epoch, odd_option, even_option );
170 9 : } else {
171 : /* if one non-null, this will pick it up. Else, both null and this no-ops */
172 6 : ret.lscheds[0] = fd_ptr_if( !!even_option, even_option, odd_option );
173 6 : }
174 :
175 15 : return ret;
176 15 : }
|