Line data Source code
1 : #include "fd_rotor.h"
2 : #include "../../ballet/bmtree/fd_bmtree.h"
3 : #include "../../ballet/sha256/fd_sha256.h"
4 : #include "../../flamenco/alpenglow/fd_block_marker_serde.h"
5 : #include "../../disco/events/generated/fd_event_gen.h"
6 :
7 : static void
8 : blk_treap_insert( fd_rotor_t * rotor,
9 0 : fd_rotor_blk_t * blk ) {
10 0 : fd_rotor_slot_meta_t const * meta = fd_rotor_slot_meta( rotor, blk->slot );
11 0 : ulong idx = fd_rotor_blk_pool_idx( rotor->blk_pool, blk );
12 0 : if( FD_UNLIKELY( blk->in_blk_treap ) ) return;
13 0 : if( FD_UNLIKELY( meta->final!=idx && meta->notar!=idx && meta->eager==idx && !blk->eager ) ) return;
14 0 : fd_rotor_treap_ele_insert( meta->final==idx ? rotor->final_treap : meta->notar==idx ? rotor->notar_treap : rotor->eager_treap, blk, rotor->blk_pool );
15 0 : blk->in_blk_treap = 1;
16 0 : }
17 :
18 : static void
19 : blk_treap_remove( fd_rotor_t * rotor,
20 0 : fd_rotor_blk_t * blk ) {
21 0 : if( FD_LIKELY( !blk->in_blk_treap ) ) return;
22 0 : fd_rotor_slot_meta_t const * meta = fd_rotor_slot_meta( rotor, blk->slot );
23 0 : ulong idx = fd_rotor_blk_pool_idx( rotor->blk_pool, blk );
24 0 : fd_rotor_treap_ele_remove( meta->final==idx ? rotor->final_treap : meta->notar==idx ? rotor->notar_treap : rotor->eager_treap, blk, rotor->blk_pool );
25 0 : blk->in_blk_treap = 0;
26 0 : }
27 :
28 :
29 : /* blk_insert creates a blk of slot named dmr (null for an eager blk)
30 : with nothing received yet. An eager blk is the slot's eager blk. */
31 :
32 : static fd_rotor_blk_t *
33 : blk_insert( fd_rotor_t * rotor,
34 : ulong slot,
35 0 : fd_mr32_t const * dmr ) {
36 0 : FD_TEST( fd_rotor_blk_pool_free( rotor->blk_pool ) );
37 0 : fd_rotor_slot_meta_t * meta = fd_rotor_slot_meta( rotor, slot );
38 0 : fd_rotor_blk_t * blk = fd_rotor_blk_pool_ele_acquire( rotor->blk_pool );
39 0 : blk->slot = slot;
40 0 : blk->dmr = *dmr;
41 0 : blk->parent = fd_rotor_blk_pool_idx_null( rotor->blk_pool );
42 0 : blk->child = fd_rotor_blk_pool_idx_null( rotor->blk_pool );
43 0 : blk->sibling = fd_rotor_blk_pool_idx_null( rotor->blk_pool );
44 0 : blk->cmpl_fec_cnt = 0U;
45 0 : blk->rcvd_fec_cnt = 0U;
46 0 : blk->buff_fec_cnt = 0U;
47 0 : blk->cons_fec_cnt = 0U;
48 0 : blk->wait_fec_cnt = 0U;
49 0 : blk->parent_slot = ULONG_MAX;
50 0 : blk->parent_blk_mr = hash_null;
51 0 : blk->in_blk_treap = 0;
52 0 : blk->eager = (!memcmp( dmr, &hash_null, sizeof(fd_mr32_t)) && !meta->invalidated && meta->final==fd_rotor_blk_pool_idx_null( rotor->blk_pool ) && !meta->leader );
53 0 : blk->meta_req = 0;
54 0 : blk->highest_req = 0;
55 0 : blk->orphan_req = 0;
56 0 : memset( &blk->telemetry, 0, sizeof(blk->telemetry) );
57 0 : blk->telemetry.last_cmpl_fec_idx = UINT_MAX;
58 0 : blk->rcvd_fec_ts = 0L;
59 0 : for( ulong k=0UL; k<rotor->fec_blk_max; k++ ) blk->fecs[ k ] = fd_rotor_fec_pool_idx_null( rotor->fec_pool );
60 0 : fd_rotor_blk_map_ele_insert( rotor->blk_map, blk, rotor->blk_pool );
61 0 : if ( !memcmp( dmr, &hash_null, sizeof(fd_mr32_t) ) ) meta->eager = fd_rotor_blk_pool_idx( rotor->blk_pool, blk );
62 0 : else if( meta->notar==fd_rotor_blk_pool_idx_null( rotor->blk_pool ) ) meta->notar = fd_rotor_blk_pool_idx( rotor->blk_pool, blk );
63 0 : blk_treap_insert( rotor, blk );
64 0 : return blk;
65 0 : }
66 :
67 : /* compute_dmr computes the double merkle root of a complete eager blk:
68 : the merkle tree over its FEC set roots, then a parent info leaf. */
69 :
70 : static void
71 : compute_dmr( fd_rotor_t * rotor,
72 0 : fd_rotor_blk_t * blk ) {
73 0 : uint fec_set_cnt = blk->cmpl_fec_cnt;
74 :
75 0 : uchar tree_mem[ FD_BMTREE_COMMIT_FOOTPRINT( 0UL ) ] __attribute__((aligned(FD_BMTREE_COMMIT_ALIGN)));
76 0 : fd_bmtree_commit_t * tree = fd_bmtree_commit_init( tree_mem, FD_SHRED_MERKLE_NODE_SZ, FD_BMTREE_LONG_PREFIX_SZ, 0UL );
77 0 : for( uint k=0U; k<fec_set_cnt; k++ ) {
78 0 : fd_bmtree_node_t leaf[1];
79 0 : memcpy( leaf->hash, fd_rotor_fec_pool_ele( rotor->fec_pool, blk->fecs[ k ] )->mr32.uc, sizeof(fd_mr32_t) );
80 0 : fd_bmtree_commit_append( tree, leaf, 1UL );
81 0 : }
82 :
83 0 : fd_bmtree_node_t parent_info[1];
84 0 : fd_sha256_t sha[1];
85 0 : fd_sha256_init ( sha );
86 0 : fd_sha256_append( sha, &blk->parent_slot, sizeof(ulong) );
87 0 : fd_sha256_append( sha, blk->parent_blk_mr.uc, sizeof(fd_mr32_t) );
88 0 : fd_sha256_append( sha, &fec_set_cnt, sizeof(uint) );
89 0 : fd_sha256_fini ( sha, parent_info->hash );
90 0 : fd_bmtree_commit_append( tree, parent_info, 1UL );
91 :
92 0 : memcpy( blk->dmr.uc, fd_bmtree_commit_fini( tree ), sizeof(fd_mr32_t) );
93 0 : }
94 :
95 : /* consume pushes buffered FECs onto the reasm queue. The first push
96 : after a reconsume first pushes blk's consumed FECs and its ancestors'
97 : onto the head, so its chain goes out again from the root. */
98 :
99 : static void
100 : consume( fd_rotor_t * rotor,
101 0 : fd_rotor_blk_t * blk ) {
102 0 : fd_rotor_slot_meta_t const * meta = fd_rotor_slot_meta( rotor, blk->slot );
103 0 : if( FD_UNLIKELY( meta->invalidated && !memcmp( &blk->dmr, &hash_null, sizeof(fd_mr32_t) ) ) ) return;
104 0 : if( FD_UNLIKELY( blk->parent==fd_rotor_blk_pool_idx_null( rotor->blk_pool ) ) ) return; /* orphaned, even if partly consumed */
105 0 : if( FD_UNLIKELY( !blk->cons_fec_cnt ) ) {
106 0 : fd_rotor_blk_t const * parent = fd_rotor_blk_pool_ele_const( rotor->blk_pool, blk->parent );
107 0 : if( FD_LIKELY( parent!=rotor->root_blk && ( !parent->cmpl_fec_cnt || parent->cons_fec_cnt!=parent->cmpl_fec_cnt ) ) ) return;
108 0 : }
109 0 : ulong idx = fd_rotor_blk_pool_idx( rotor->blk_pool, blk );
110 0 : fd_rotor_blk_t * eager = fd_rotor_blk_pool_ele( rotor->blk_pool, meta->eager );
111 0 : if( FD_UNLIKELY( eager && meta->eager!=idx && !meta->invalidated && !memcmp( &eager->dmr, &hash_null, sizeof(fd_mr32_t) ) ) ) {
112 0 : if( FD_UNLIKELY( eager->parent==fd_rotor_blk_pool_idx_null( rotor->blk_pool ) && blk->fecs[ 0 ]!=fd_rotor_fec_pool_idx_null( rotor->fec_pool ) && eager->fecs[ 0 ]==blk->fecs[ 0 ] ) ) {
113 0 : if( FD_LIKELY( eager!=rotor->root_blk && memcmp( &eager->parent_blk_mr, &hash_null, sizeof(fd_mr32_t) ) ) ) fd_rotor_orphan_map_ele_remove_fast( rotor->orphan_map, eager, rotor->blk_pool );
114 0 : fd_rotor_blk_t * parent = fd_rotor_blk_pool_ele( rotor->blk_pool, blk->parent );
115 0 : eager->parent_slot = blk->parent_slot;
116 0 : eager->parent_blk_mr = blk->parent_blk_mr;
117 0 : eager->parent = blk->parent;
118 0 : eager->sibling = parent->child;
119 0 : parent->child = meta->eager;
120 0 : }
121 0 : int dup = eager->parent==blk->parent;
122 0 : for( uint k=blk->cons_fec_cnt; dup && k<blk->buff_fec_cnt; k++ ) dup = eager->fecs[ k ]==blk->fecs[ k ];
123 0 : if( FD_LIKELY( dup ) ) {
124 0 : blk = eager;
125 0 : idx = meta->eager;
126 0 : }
127 0 : }
128 0 : if( FD_UNLIKELY( rotor->reconsume && blk->cons_fec_cnt<blk->buff_fec_cnt ) ) {
129 0 : rotor->reconsume = 0;
130 0 : for( fd_rotor_blk_t * anc = blk; anc && anc!=rotor->root_blk; anc = fd_rotor_blk_pool_ele( rotor->blk_pool, anc->parent ) ) {
131 0 : for( uint k=anc->cons_fec_cnt; k; k-- ) fd_rotor_deque_push_head( rotor->reasm_deque, (fd_rotor_deque_t){ .blk_idx = (uint)fd_rotor_blk_pool_idx( rotor->blk_pool, anc ), .fec_idx = k-1U } );
132 0 : }
133 0 : }
134 0 : if( FD_UNLIKELY( meta->leader && meta->eager==idx ) ) { /* our leader blk goes first, in FEC order */
135 0 : for( uint k=blk->buff_fec_cnt; k>blk->cons_fec_cnt; k-- ) fd_rotor_deque_push_head( rotor->reasm_deque, (fd_rotor_deque_t){ .blk_idx = (uint)idx, .fec_idx = k-1U } );
136 0 : blk->cons_fec_cnt = blk->buff_fec_cnt;
137 0 : return;
138 0 : }
139 0 : for( ; blk->cons_fec_cnt<blk->buff_fec_cnt; blk->cons_fec_cnt++ ) fd_rotor_deque_push_tail( rotor->reasm_deque, (fd_rotor_deque_t){ .blk_idx = (uint)idx, .fec_idx = blk->cons_fec_cnt } );
140 0 : }
141 :
142 : /* cascade performs a stackless (ie. O(1) space) preorder traversal. */
143 :
144 : static void
145 : cascade( fd_rotor_t * rotor,
146 0 : fd_rotor_blk_t * root ) {
147 0 : fd_rotor_blk_t * pool = rotor->blk_pool;
148 0 : ulong null = fd_rotor_blk_pool_idx_null( pool );
149 0 : ulong tidx = fd_rotor_blk_pool_idx( pool, root );
150 0 : ulong idx = root->child;
151 0 : while( FD_LIKELY( idx!=null ) ) {
152 0 : fd_rotor_blk_t * blk = fd_rotor_blk_pool_ele( pool, idx );
153 0 : consume( rotor, blk );
154 0 : if( FD_LIKELY( blk->cmpl_fec_cnt && blk->cons_fec_cnt==blk->cmpl_fec_cnt && blk->child!=null ) ) { idx = blk->child; continue; }
155 0 : while( FD_LIKELY( idx!=tidx && fd_rotor_blk_pool_ele( pool, idx )->sibling==null ) ) idx = fd_rotor_blk_pool_ele( pool, idx )->parent;
156 0 : if( FD_UNLIKELY( idx==tidx ) ) break;
157 0 : idx = fd_rotor_blk_pool_ele( pool, idx )->sibling;
158 0 : }
159 0 : }
160 :
161 : /* promote gives blk the slot_meta role (notar or final), moving it to
162 : that role's treap if it was in one. A blk with a role is not
163 : repaired by position. */
164 :
165 : static void
166 : promote( fd_rotor_t * rotor,
167 : fd_rotor_blk_t * blk,
168 0 : ulong * role ) {
169 0 : if( FD_LIKELY( *role==fd_rotor_blk_pool_idx( rotor->blk_pool, blk ) ) ) return;
170 0 : int in_blk_treap = blk->in_blk_treap;
171 0 : blk_treap_remove( rotor, blk );
172 0 : *role = fd_rotor_blk_pool_idx( rotor->blk_pool, blk );
173 0 : blk->eager = 0;
174 0 : if( FD_LIKELY( in_blk_treap ) ) blk_treap_insert( rotor, blk );
175 0 : }
176 :
177 : /* connect_ancestors links a notar or final blk to its ancestors via
178 : parent dmr, creating the ones not held, up to the root or a blk whose
179 : parent is not known.
180 :
181 : For every blk B that is notar or final and whose header is known, the
182 : blk B names must be held, B must be linked under it, and if B is
183 : final so must it be. Then apply the same rule to that parent.
184 :
185 : If the parent was just created, the blk must be re-added to the
186 : treap. It's the responsibility of the blk's presence in the treap for
187 : the tile to make orphan requests; NOT the parent, which only gets a
188 : META request.
189 :
190 : This should be called anytime a blk becomes notar or final and its
191 : header is known, or vice versa.
192 :
193 : Only the highest blk linked here (else blk itself) can have become
194 : consumable: the blks above were linked before and their FEC sets are
195 : untouched, the blks below are reached by its cascade. */
196 :
197 : static void
198 : connect_ancestors( fd_rotor_t * rotor,
199 0 : fd_rotor_blk_t * blk ) {
200 0 : fd_rotor_blk_t * pool = rotor->blk_pool;
201 0 : ulong null = fd_rotor_blk_pool_idx_null( pool );
202 0 : fd_rotor_blk_t * top = blk;
203 0 : for(;;) {
204 0 : if( FD_UNLIKELY( blk->parent_slot==ULONG_MAX || blk->parent_slot<rotor->root ) ) break;
205 0 : if( FD_UNLIKELY( blk->parent_slot!=rotor->root && !memcmp( &blk->parent_blk_mr, &hash_null, sizeof(fd_mr32_t) ) ) ) break;
206 0 : fd_rotor_slot_meta_t * meta = fd_rotor_slot_meta( rotor, blk->slot );
207 0 : fd_rotor_slot_meta_t * pmeta = fd_rotor_slot_meta( rotor, blk->parent_slot );
208 0 : int final = meta->final==fd_rotor_blk_pool_idx( pool, blk );
209 0 : fd_rotor_blk_t * parent = fd_rotor_blk_map_ele_query( rotor->blk_map, &blk->parent_slot, NULL, pool );
210 0 : while( parent && memcmp( &parent->dmr, &blk->parent_blk_mr, sizeof(fd_mr32_t) ) ) parent = (fd_rotor_blk_t *)fd_rotor_blk_map_ele_next_const( parent, NULL, pool );
211 0 : if( FD_UNLIKELY( !parent && blk->parent_slot==rotor->root ) ) break; /* names a root other than ours */
212 0 : int held = !!parent;
213 0 : if( FD_UNLIKELY( !parent ) ) parent = fd_rotor_blk_notarized( rotor, blk->parent_slot, &blk->parent_blk_mr );
214 0 : if( FD_UNLIKELY( !parent ) ) break; /* the parent slot is settled otherwise */
215 0 : if( FD_UNLIKELY( !held ) ) { /* link_children linked blk under the new parent */
216 0 : blk_treap_insert( rotor, blk ); /* its tile asks ORPHAN for eager ancestry, which may merge with the named parents */
217 0 : top = blk;
218 0 : }
219 0 : if( FD_UNLIKELY( blk->parent==null ) ) {
220 0 : if( FD_LIKELY( blk!=rotor->root_blk /* && blk->parent==null */ && memcmp( &blk->parent_blk_mr, &hash_null, sizeof(fd_mr32_t) ) ) ) {
221 0 : fd_rotor_orphan_map_ele_remove_fast( rotor->orphan_map, blk, pool );
222 0 : }
223 0 : blk->parent = fd_rotor_blk_pool_idx( pool, parent );
224 0 : blk->sibling = parent->child;
225 0 : parent->child = fd_rotor_blk_pool_idx( pool, blk );
226 0 : top = blk;
227 0 : }
228 0 : if( FD_UNLIKELY( final && pmeta->final==null ) ) promote( rotor, parent, &pmeta->final );
229 0 : blk = parent;
230 0 : }
231 0 : consume( rotor, top );
232 0 : if( FD_UNLIKELY( top->cmpl_fec_cnt && top->cons_fec_cnt==top->cmpl_fec_cnt ) ) cascade( rotor, top );
233 0 : }
234 :
235 : /* link_parent links an unlinked blk whose header is known under the
236 : held blk it names, if any. Returns the parent linked under. */
237 :
238 : static fd_rotor_blk_t *
239 : link_parent( fd_rotor_t * rotor,
240 0 : fd_rotor_blk_t * blk ) {
241 0 : fd_rotor_blk_t * pool = rotor->blk_pool;
242 0 : if( FD_UNLIKELY( blk->parent_slot==ULONG_MAX ) ) return NULL;
243 0 : if( FD_UNLIKELY( blk->parent_slot!=rotor->root && !memcmp( &blk->parent_blk_mr, &hash_null, sizeof(fd_mr32_t) ) ) ) return NULL;
244 :
245 0 : fd_rotor_blk_t * parent = fd_rotor_blk_map_ele_query( rotor->blk_map, &blk->parent_slot, NULL, pool );
246 0 : while( parent && memcmp( &parent->dmr, &blk->parent_blk_mr, sizeof(fd_mr32_t) ) ) parent = (fd_rotor_blk_t *)fd_rotor_blk_map_ele_next_const( parent, NULL, pool );
247 0 : if( FD_LIKELY( !parent ) ) return NULL;
248 :
249 0 : if( FD_LIKELY( blk!=rotor->root_blk && blk->parent==fd_rotor_blk_pool_idx_null( pool ) && memcmp( &blk->parent_blk_mr, &hash_null, sizeof(fd_mr32_t) ) ) ) {
250 0 : fd_rotor_orphan_map_ele_remove_fast( rotor->orphan_map, blk, pool );
251 0 : }
252 :
253 0 : blk->parent = fd_rotor_blk_pool_idx( pool, parent );
254 0 : blk->sibling = parent->child;
255 0 : parent->child = fd_rotor_blk_pool_idx( pool, blk );
256 0 : return parent;
257 0 : }
258 :
259 : /* link_children links the orphans naming parent's (slot, dmr) under
260 : it: their headers named it before it was held, a notar blk just
261 : created or an eager blk that just completed.
262 : A final child makes the parent final, as connect_ancestors would. */
263 :
264 : static void
265 : link_children( fd_rotor_t * rotor,
266 0 : fd_rotor_blk_t * parent ) {
267 0 : fd_rotor_blk_t * pool = rotor->blk_pool;
268 0 : ulong null = fd_rotor_blk_pool_idx_null( pool );
269 0 : fd_rotor_slot_meta_t * pmeta = fd_rotor_slot_meta( rotor, parent->slot );
270 0 : fd_rotor_blk_t * next;
271 0 : for( fd_rotor_blk_t * blk = fd_rotor_orphan_map_ele_query( rotor->orphan_map, &parent->dmr, NULL, pool );
272 0 : blk;
273 0 : blk = next ) {
274 0 : next = (fd_rotor_blk_t *)fd_rotor_orphan_map_ele_next_const( blk, NULL, pool );
275 0 : if( FD_UNLIKELY( blk->parent_slot!=parent->slot ) ) continue;
276 0 : fd_rotor_orphan_map_ele_remove_fast( rotor->orphan_map, blk, pool );
277 0 : blk->parent = fd_rotor_blk_pool_idx( pool, parent );
278 0 : blk->sibling = parent->child;
279 0 : parent->child = fd_rotor_blk_pool_idx( pool, blk );
280 0 : if( FD_UNLIKELY( fd_rotor_slot_meta( rotor, blk->slot )->final==fd_rotor_blk_pool_idx( pool, blk ) && pmeta->final==null ) ) promote( rotor, parent, &pmeta->final );
281 0 : }
282 0 : }
283 :
284 : static void
285 : unlink( fd_rotor_t * rotor,
286 0 : fd_rotor_blk_t * blk ) {
287 0 : fd_rotor_blk_t * pool = rotor->blk_pool;
288 0 : ulong null = fd_rotor_blk_pool_idx_null( pool );
289 0 : ulong idx = fd_rotor_blk_pool_idx( pool, blk );
290 0 : if( FD_LIKELY( blk->parent!=null ) ) {
291 0 : ulong * link = &fd_rotor_blk_pool_ele( pool, blk->parent )->child;
292 0 : while( *link!=idx ) link = &fd_rotor_blk_pool_ele( pool, *link )->sibling;
293 0 : *link = blk->sibling;
294 0 : }
295 0 : ulong next;
296 0 : for( ulong c=blk->child; c!=null; c=next ) {
297 0 : fd_rotor_blk_t * child = fd_rotor_blk_pool_ele( pool, c );
298 0 : next = child->sibling;
299 0 : child->parent = null;
300 0 : child->sibling = null;
301 0 : if( FD_LIKELY( child!=rotor->root_blk /* && child->parent==null */ && memcmp( &child->parent_blk_mr, &hash_null, sizeof(fd_mr32_t) ) ) ) {
302 0 : fd_rotor_orphan_map_ele_insert( rotor->orphan_map, child, pool ); /* waits for blk's dmr again, should it be held again */
303 0 : }
304 0 : }
305 0 : }
306 :
307 : static void
308 : prune( fd_rotor_t * rotor,
309 0 : fd_rotor_blk_t * blk ) {
310 0 : fd_rotor_blk_t * pool = rotor->blk_pool;
311 0 : if( FD_UNLIKELY( !blk->telemetry.reported && rotor->telemetry.report ) ) rotor->telemetry.report( rotor->telemetry.ctx, blk );
312 0 : for( ulong k=0UL; k<rotor->fec_blk_max; k++ ) {
313 0 : if( FD_LIKELY( blk->fecs[ k ]==fd_rotor_fec_pool_idx_null( rotor->fec_pool ) ) ) continue;
314 0 : int held = 0;
315 0 : for( fd_rotor_blk_t const * other = fd_rotor_blk_map_ele_query_const( rotor->blk_map, &blk->slot, NULL, pool );
316 0 : other && !held;
317 0 : other = fd_rotor_blk_map_ele_next_const( other, NULL, pool ) ) {
318 0 : held = other!=blk && other->fecs[ k ]==blk->fecs[ k ];
319 0 : }
320 0 : if( FD_UNLIKELY( held ) ) continue;
321 0 : fd_rotor_fec_t * fec = fd_rotor_fec_pool_ele( rotor->fec_pool, blk->fecs[ k ] );
322 0 : fd_rotor_fec_map_ele_remove_fast( rotor->fec_map, fec, rotor->fec_pool );
323 0 : fd_rotor_fec_pool_ele_release ( rotor->fec_pool, fec );
324 0 : }
325 0 : unlink( rotor, blk );
326 0 : if( FD_UNLIKELY( blk!=rotor->root_blk && blk->parent==fd_rotor_blk_pool_idx_null( pool ) && memcmp( &blk->parent_blk_mr, &hash_null, sizeof(fd_mr32_t) ) ) ) {
327 0 : fd_rotor_orphan_map_ele_remove_fast( rotor->orphan_map, blk, pool );
328 0 : }
329 0 : blk_treap_remove( rotor, blk );
330 0 : fd_rotor_slot_meta_t * meta = fd_rotor_slot_meta( rotor, blk->slot );
331 0 : if( FD_UNLIKELY( meta->eager==fd_rotor_blk_pool_idx( pool, blk ) ) ) meta->eager = fd_rotor_blk_pool_idx_null( pool );
332 0 : if( FD_UNLIKELY( meta->notar==fd_rotor_blk_pool_idx( pool, blk ) ) ) meta->notar = fd_rotor_blk_pool_idx_null( pool );
333 0 : if( FD_UNLIKELY( meta->final==fd_rotor_blk_pool_idx( pool, blk ) ) ) meta->final = fd_rotor_blk_pool_idx_null( pool );
334 0 : fd_rotor_blk_map_ele_remove_fast( rotor->blk_map, blk, pool );
335 0 : fd_rotor_blk_pool_ele_release ( pool, blk );
336 0 : }
337 :
338 : /* dedup checks for a duplicate of eager among the notar blks. Only the
339 : eager blk can be duplicated, since notar blk DMRs are known a priori.
340 :
341 : Merge strategy if a duplicate is found:
342 : - eager is kept, notar is freed
343 : - eager inherits notar's children
344 : - eager takes notar's parent if it has none, as same DMR implies same
345 : parent
346 :
347 : Replay builds one bank for the block until then: consume holds notar
348 : behind eager, which delivers the FEC sets they share. */
349 :
350 : static void
351 : dedup( fd_rotor_t * rotor,
352 : fd_rotor_blk_t * eager,
353 0 : long ts ) {
354 0 : fd_rotor_blk_t * pool = rotor->blk_pool;
355 0 : ulong null = fd_rotor_blk_pool_idx_null( pool );
356 0 : ulong idx = fd_rotor_blk_pool_idx( pool, eager );
357 :
358 0 : fd_rotor_blk_t * notar = fd_rotor_blk_map_ele_query( rotor->blk_map, &eager->slot, NULL, pool );
359 0 : while( notar && ( notar==eager || memcmp( ¬ar->dmr, &eager->dmr, sizeof(fd_mr32_t) ) ) ) {
360 0 : notar = (fd_rotor_blk_t *)fd_rotor_blk_map_ele_next_const( notar, NULL, pool );
361 0 : }
362 0 : fd_rotor_slot_meta_t * meta = fd_rotor_slot_meta( rotor, eager->slot );
363 0 : if( FD_UNLIKELY( !notar && meta->final!=null ) ) {
364 0 : eager->telemetry.cancelled_ts = fd_long_if( !eager->telemetry.cancelled_reason, ts, eager->telemetry.cancelled_ts );
365 0 : eager->telemetry.cancelled_reason = (uchar)FD_EVENT_BLOCK_RECEIVED_CANCELLED_REASON_NOTARIZED_VERSION;
366 0 : prune( rotor, eager );
367 0 : return;
368 0 : } /* turbine built a blk the cluster did not finalize */
369 0 : if( FD_LIKELY( !notar ) ) return;
370 :
371 0 : ulong next;
372 0 : for( ulong c=notar->child; c!=null; c=next ) {
373 0 : next = fd_rotor_blk_pool_ele( pool, c )->sibling;
374 0 : fd_rotor_blk_pool_ele( pool, c )->parent = idx;
375 0 : fd_rotor_blk_pool_ele( pool, c )->sibling = eager->child;
376 0 : eager->child = c;
377 0 : }
378 0 : notar->child = null;
379 0 : if( FD_UNLIKELY( notar->parent!=null && eager->parent==null ) ) {
380 0 : if( FD_LIKELY( eager!=rotor->root_blk /* && eager->parent==null */ && memcmp( &eager->parent_blk_mr, &hash_null, sizeof(fd_mr32_t) ) ) ) {
381 0 : fd_rotor_orphan_map_ele_remove_fast( rotor->orphan_map, eager, pool );
382 0 : }
383 0 : eager->parent = notar->parent;
384 0 : eager->sibling = fd_rotor_blk_pool_ele( pool, notar->parent )->child;
385 0 : fd_rotor_blk_pool_ele( pool, notar->parent )->child = idx;
386 0 : }
387 0 : blk_treap_remove( rotor, notar );
388 0 : if( FD_UNLIKELY( meta->final==fd_rotor_blk_pool_idx( pool, notar ) ) ) { meta->final = null; promote( rotor, eager, &meta->final ); }
389 0 : if( FD_UNLIKELY( meta->notar==fd_rotor_blk_pool_idx( pool, notar ) ) ) { meta->notar = null; promote( rotor, eager, &meta->notar ); }
390 0 : notar->telemetry.reported = 1; /* the same block lives on as eager, we won't report two different lines for this */
391 :
392 0 : eager->telemetry.req_window_cnt += notar->telemetry.req_window_cnt;
393 0 : eager->telemetry.req_highest_cnt += notar->telemetry.req_highest_cnt;
394 0 : eager->telemetry.req_orphan_cnt += notar->telemetry.req_orphan_cnt;
395 0 : eager->telemetry.req_shred_bid_cnt += notar->telemetry.req_shred_bid_cnt;
396 0 : eager->telemetry.req_parent_cnt += notar->telemetry.req_parent_cnt;
397 0 : eager->telemetry.req_fec_root_cnt += notar->telemetry.req_fec_root_cnt;
398 0 : eager->telemetry.shred_res_cnt += notar->telemetry.shred_res_cnt;
399 0 : eager->telemetry.parent_res_cnt += notar->telemetry.parent_res_cnt;
400 0 : eager->telemetry.fec_root_res_cnt += notar->telemetry.fec_root_res_cnt;
401 : /* first timestamps */
402 0 : eager->telemetry.first_req_ts = fd_long_if( !eager->telemetry.first_req_ts || ( notar->telemetry.first_req_ts && notar->telemetry.first_req_ts <eager->telemetry.first_req_ts ), notar->telemetry.first_req_ts, eager->telemetry.first_req_ts );
403 0 : eager->telemetry.first_meta_res_ts = fd_long_if( !eager->telemetry.first_meta_res_ts || ( notar->telemetry.first_meta_res_ts && notar->telemetry.first_meta_res_ts<eager->telemetry.first_meta_res_ts ), notar->telemetry.first_meta_res_ts, eager->telemetry.first_meta_res_ts );
404 0 : eager->telemetry.last_shred_res_ts = fd_long_max( eager->telemetry.last_shred_res_ts, notar->telemetry.last_shred_res_ts );
405 0 : prune( rotor, notar );
406 0 : connect_ancestors( rotor, eager );
407 0 : }
408 :
409 : FD_FN_CONST ulong
410 0 : fd_rotor_align( void ) {
411 0 : return fd_ulong_max( alignof(fd_rotor_t), 128UL );
412 0 : }
413 :
414 : FD_FN_CONST ulong
415 : fd_rotor_footprint( ulong slot_max,
416 : ulong fec_max,
417 0 : ulong fec_blk_max ) {
418 0 : ulong blk_max = fd_rotor_blk_max( slot_max );
419 0 : return FD_LAYOUT_FINI(
420 0 : FD_LAYOUT_APPEND(
421 0 : FD_LAYOUT_APPEND(
422 0 : FD_LAYOUT_APPEND(
423 0 : FD_LAYOUT_APPEND(
424 0 : FD_LAYOUT_APPEND(
425 0 : FD_LAYOUT_APPEND(
426 0 : FD_LAYOUT_APPEND(
427 0 : FD_LAYOUT_APPEND(
428 0 : FD_LAYOUT_APPEND(
429 0 : FD_LAYOUT_APPEND(
430 0 : FD_LAYOUT_APPEND(
431 0 : FD_LAYOUT_APPEND(
432 0 : FD_LAYOUT_INIT,
433 0 : fd_rotor_align(), sizeof(fd_rotor_t) ),
434 0 : alignof(fd_rotor_slot_meta_t), sizeof(fd_rotor_slot_meta_t)*slot_max ),
435 0 : fd_rotor_blk_pool_align(), fd_rotor_blk_pool_footprint ( blk_max ) ),
436 0 : alignof(ulong), sizeof(ulong)*blk_max*fec_blk_max ),
437 0 : fd_rotor_blk_map_align(), fd_rotor_blk_map_footprint ( fd_rotor_blk_map_chain_cnt_est( blk_max ) ) ),
438 0 : fd_rotor_orphan_map_align(), fd_rotor_orphan_map_footprint( fd_rotor_orphan_map_chain_cnt_est( blk_max ) ) ),
439 0 : fd_rotor_fec_pool_align(), fd_rotor_fec_pool_footprint ( fec_max ) ),
440 0 : fd_rotor_fec_map_align(), fd_rotor_fec_map_footprint ( fd_rotor_fec_map_chain_cnt_est( fec_max ) ) ),
441 0 : fd_rotor_deque_align(), fd_rotor_deque_footprint ( fec_max ) ),
442 0 : fd_rotor_treap_align(), fd_rotor_treap_footprint ( blk_max ) ),
443 0 : fd_rotor_treap_align(), fd_rotor_treap_footprint ( blk_max ) ),
444 0 : fd_rotor_treap_align(), fd_rotor_treap_footprint ( blk_max ) ),
445 0 : fd_rotor_align() );
446 0 : }
447 :
448 : void *
449 : fd_rotor_new( void * shmem,
450 : ulong slot_max,
451 : ulong fec_max,
452 : ulong fec_blk_max,
453 0 : ulong seed ) {
454 0 : ulong footprint = fd_rotor_footprint( slot_max, fec_max, fec_blk_max );
455 0 : if( FD_UNLIKELY( !footprint || fec_blk_max<FD_FEC_BLK_MAX || fec_blk_max>UINT_MAX ) ) {
456 0 : FD_LOG_WARNING(( "bad footprint: %lu %lu %lu", slot_max, fec_max, fec_blk_max ));
457 0 : return NULL;
458 0 : }
459 :
460 0 : fd_memset( shmem, 0, footprint );
461 0 : fd_rotor_t * rotor;
462 :
463 0 : ulong blk_max = fd_rotor_blk_max( slot_max );
464 :
465 0 : FD_SCRATCH_ALLOC_INIT( l, shmem );
466 0 : rotor = FD_SCRATCH_ALLOC_APPEND( l, fd_rotor_align(), sizeof(fd_rotor_t) );
467 0 : void * slot_meta = FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_rotor_slot_meta_t), sizeof(fd_rotor_slot_meta_t)*slot_max );
468 0 : void * blk_pool = FD_SCRATCH_ALLOC_APPEND( l, fd_rotor_blk_pool_align(), fd_rotor_blk_pool_footprint ( blk_max ) );
469 0 : ulong * blk_fecs = FD_SCRATCH_ALLOC_APPEND( l, alignof(ulong), sizeof(ulong)*blk_max*fec_blk_max );
470 0 : void * blk_map = FD_SCRATCH_ALLOC_APPEND( l, fd_rotor_blk_map_align(), fd_rotor_blk_map_footprint ( fd_rotor_blk_map_chain_cnt_est( blk_max ) ) );
471 0 : void * orphan_map = FD_SCRATCH_ALLOC_APPEND( l, fd_rotor_orphan_map_align(), fd_rotor_orphan_map_footprint( fd_rotor_orphan_map_chain_cnt_est( blk_max ) ) );
472 0 : void * fec_pool = FD_SCRATCH_ALLOC_APPEND( l, fd_rotor_fec_pool_align(), fd_rotor_fec_pool_footprint ( fec_max ) );
473 0 : void * fec_map = FD_SCRATCH_ALLOC_APPEND( l, fd_rotor_fec_map_align(), fd_rotor_fec_map_footprint ( fd_rotor_fec_map_chain_cnt_est( fec_max ) ) );
474 0 : void * reasm_deque = FD_SCRATCH_ALLOC_APPEND( l, fd_rotor_deque_align(), fd_rotor_deque_footprint ( fec_max ) );
475 0 : void * eager_treap = FD_SCRATCH_ALLOC_APPEND( l, fd_rotor_treap_align(), fd_rotor_treap_footprint ( blk_max ) );
476 0 : void * notar_treap = FD_SCRATCH_ALLOC_APPEND( l, fd_rotor_treap_align(), fd_rotor_treap_footprint ( blk_max ) );
477 0 : void * final_treap = FD_SCRATCH_ALLOC_APPEND( l, fd_rotor_treap_align(), fd_rotor_treap_footprint ( blk_max ) );
478 0 : FD_TEST( FD_SCRATCH_ALLOC_FINI( l, fd_rotor_align() ) == (ulong)shmem + footprint );
479 :
480 0 : rotor->root = ULONG_MAX;
481 0 : rotor->slot_max = slot_max;
482 0 : rotor->fec_blk_max = fec_blk_max;
483 0 : rotor->slot_meta = (fd_rotor_slot_meta_t *)slot_meta;
484 0 : for( ulong i=0UL; i<slot_max; i++ ) rotor->slot_meta[ i ].slot = ULONG_MAX;
485 0 : rotor->blk_pool = fd_rotor_blk_pool_join( fd_rotor_blk_pool_new( blk_pool, blk_max ) );
486 0 : for( ulong i=0UL; i<blk_max; i++ ) rotor->blk_pool[ i ].fecs = blk_fecs + i*fec_blk_max;
487 0 : rotor->blk_map = fd_rotor_blk_map_join ( fd_rotor_blk_map_new ( blk_map, fd_rotor_blk_map_chain_cnt_est( blk_max ), seed ) );
488 0 : rotor->orphan_map = fd_rotor_orphan_map_join( fd_rotor_orphan_map_new( orphan_map, fd_rotor_orphan_map_chain_cnt_est( blk_max ), seed ) );
489 0 : rotor->fec_pool = fd_rotor_fec_pool_join( fd_rotor_fec_pool_new( fec_pool, fec_max ) );
490 0 : rotor->fec_map = fd_rotor_fec_map_join ( fd_rotor_fec_map_new ( fec_map, fd_rotor_fec_map_chain_cnt_est( fec_max ), seed ) );
491 0 : rotor->reasm_deque = fd_rotor_deque_join ( fd_rotor_deque_new ( reasm_deque, fec_max ) );
492 0 : fd_rotor_treap_seed( rotor->blk_pool, blk_max, seed ); /* the treaps share each blk's prio */
493 0 : rotor->eager_treap = fd_rotor_treap_join( fd_rotor_treap_new( eager_treap, blk_max ) );
494 0 : rotor->notar_treap = fd_rotor_treap_join( fd_rotor_treap_new( notar_treap, blk_max ) );
495 0 : rotor->final_treap = fd_rotor_treap_join( fd_rotor_treap_new( final_treap, blk_max ) );
496 :
497 0 : return shmem;
498 0 : }
499 :
500 : fd_rotor_t *
501 0 : fd_rotor_join( void * shrotor ) {
502 0 : return (fd_rotor_t *)shrotor;
503 0 : }
504 :
505 : void *
506 0 : fd_rotor_leave( fd_rotor_t const * rotor ) {
507 0 : return (void *)rotor;
508 0 : }
509 :
510 : void *
511 0 : fd_rotor_delete( void * shrotor ) {
512 0 : return shrotor;
513 0 : }
514 :
515 : void
516 : fd_rotor_init( fd_rotor_t * rotor,
517 : ulong root,
518 : fd_mr32_t const * root_blk_mr,
519 : fd_rotor_report_fn_t report,
520 0 : void * report_ctx ) {
521 0 : rotor->telemetry.report = report;
522 0 : rotor->telemetry.ctx = report_ctx;
523 0 : fd_rotor_blk_t * blk = blk_insert( rotor, root, root_blk_mr );
524 0 : blk->telemetry.reported = 1; /* the root is not a received block */
525 0 : blk_treap_remove( rotor, blk ); /* the root is never repaired */
526 0 : fd_rotor_slot_meta( rotor, root )->final = fd_rotor_blk_pool_idx( rotor->blk_pool, blk );
527 0 : fd_rotor_slot_meta( rotor, root )->eager = fd_rotor_blk_pool_idx_null( rotor->blk_pool ); /* the genesis root has a null dmr, but is not turbine's */
528 0 : blk->eager = 0;
529 0 : rotor->root = root;
530 0 : rotor->root_blk = blk;
531 0 : rotor->catchup_slot = root;
532 0 : }
533 :
534 : void
535 0 : fd_rotor_fini( fd_rotor_t * rotor ) {
536 0 : for( ulong i=0UL; i<rotor->slot_max; i++ ) rotor->slot_meta[ i ].slot = ULONG_MAX;
537 0 : fd_rotor_blk_map_reset( rotor->blk_map );
538 0 : fd_rotor_orphan_map_reset( rotor->orphan_map );
539 0 : fd_rotor_blk_pool_reset( rotor->blk_pool );
540 0 : fd_rotor_fec_map_reset( rotor->fec_map );
541 0 : fd_rotor_fec_pool_reset( rotor->fec_pool );
542 0 : fd_rotor_deque_remove_all( rotor->reasm_deque );
543 0 : rotor->eager_treap = fd_rotor_treap_join( fd_rotor_treap_new( fd_rotor_treap_leave( rotor->eager_treap ), fd_rotor_blk_pool_max( rotor->blk_pool ) ) );
544 0 : rotor->notar_treap = fd_rotor_treap_join( fd_rotor_treap_new( fd_rotor_treap_leave( rotor->notar_treap ), fd_rotor_blk_pool_max( rotor->blk_pool ) ) );
545 0 : rotor->final_treap = fd_rotor_treap_join( fd_rotor_treap_new( fd_rotor_treap_leave( rotor->final_treap ), fd_rotor_blk_pool_max( rotor->blk_pool ) ) );
546 0 : rotor->root = ULONG_MAX;
547 0 : rotor->root_blk = NULL;
548 0 : rotor->catchup_slot = 0UL;
549 0 : rotor->reconsume = 0;
550 0 : }
551 :
552 : void
553 : fd_rotor_blk_dead( fd_rotor_t * rotor,
554 : ulong slot,
555 0 : fd_mr32_t const * blk_mr ) {
556 0 : fd_rotor_blk_t * dead = fd_rotor_blk_map_ele_query( rotor->blk_map, &slot, NULL, rotor->blk_pool );
557 0 : while( dead && memcmp( &dead->dmr, blk_mr, sizeof(fd_mr32_t) ) ) dead = (fd_rotor_blk_t *)fd_rotor_blk_map_ele_next_const( dead, NULL, rotor->blk_pool );
558 0 : if( FD_UNLIKELY( !dead ) ) return;
559 :
560 0 : fd_rotor_slot_meta_t * meta = fd_rotor_slot_meta( rotor, slot );
561 0 : int eager = meta->eager==fd_rotor_blk_pool_idx( rotor->blk_pool, dead );
562 0 : ulong parent = dead->parent;
563 0 : if( FD_UNLIKELY( eager ) ) meta->invalidated = 1; /* turbine must not rebuild it */
564 0 : prune( rotor, dead );
565 0 : if( FD_UNLIKELY( eager && parent!=fd_rotor_blk_pool_idx_null( rotor->blk_pool ) ) ) cascade( rotor, fd_rotor_blk_pool_ele( rotor->blk_pool, parent ) ); /* delivers the notar blks held behind it */
566 0 : }
567 :
568 : fd_rotor_blk_t *
569 : fd_rotor_blk_finalized( fd_rotor_t * rotor,
570 : ulong slot,
571 : fd_mr32_t const * blk_mr,
572 0 : long ts ) {
573 0 : fd_rotor_slot_meta_t * meta = fd_rotor_slot_meta( rotor, slot );
574 :
575 0 : fd_rotor_blk_t * fin = fd_rotor_blk_map_ele_query( rotor->blk_map, &slot, NULL, rotor->blk_pool );
576 0 : while( fin && memcmp( &fin->dmr, blk_mr, sizeof(fd_mr32_t) ) ) fin = (fd_rotor_blk_t *)fd_rotor_blk_map_ele_next_const( fin, NULL, rotor->blk_pool );
577 0 : if( FD_UNLIKELY( !fin ) ) fin = fd_rotor_blk_notarized( rotor, slot, blk_mr );
578 0 : if( FD_UNLIKELY( !fin ) ) return NULL; /* the slot is already finalized with another blk */
579 :
580 0 : fd_rotor_blk_t * pool = rotor->blk_pool;
581 0 : promote( rotor, fin, &meta->final );
582 : /* The eager blk keeps its positional repair: peers without the whole
583 : block still serve its shreds, which by-id repair cannot ask them for. */
584 :
585 : /* Remove all equivocating blocks except the finalized one. Their
586 : children name them, not the finalized blk, and are unlinked. */
587 :
588 0 : fd_rotor_blk_t * next;
589 0 : for( fd_rotor_blk_t * blk = fd_rotor_blk_map_ele_query( rotor->blk_map, &slot, NULL, pool );
590 0 : blk;
591 0 : blk = next ) {
592 0 : next = (fd_rotor_blk_t *)fd_rotor_blk_map_ele_next_const( blk, NULL, pool );
593 0 : if( FD_LIKELY( blk==fin ) ) continue;
594 0 : if( FD_UNLIKELY( meta->eager==fd_rotor_blk_pool_idx( pool, blk ) && !meta->invalidated && !memcmp( &blk->dmr, &hash_null, sizeof(fd_mr32_t) ) ) ) continue; /* turbine may still complete as the finalized blk, see dedup */
595 0 : blk->telemetry.cancelled_ts = fd_long_if( !blk->telemetry.cancelled_reason, ts, blk->telemetry.cancelled_ts );
596 0 : blk->telemetry.cancelled_reason = (uchar)fd_int_if( !blk->telemetry.cancelled_reason, FD_EVENT_BLOCK_RECEIVED_CANCELLED_REASON_NOTARIZED_VERSION, blk->telemetry.cancelled_reason ); /* an invalidated eager blk keeps its reason */
597 0 : prune( rotor, blk );
598 0 : }
599 0 : connect_ancestors( rotor, fin );
600 0 : return fin;
601 0 : }
602 :
603 : fd_rotor_blk_t *
604 : fd_rotor_blk_notarized( fd_rotor_t * rotor,
605 : ulong slot,
606 0 : fd_mr32_t const * blk_mr ) {
607 0 : fd_rotor_slot_meta_t * meta = fd_rotor_slot_meta( rotor, slot );
608 0 : if( FD_UNLIKELY( !memcmp( blk_mr, &hash_null, sizeof(fd_mr32_t) ) ) ) return NULL; /* never a real blk id, only turbine makes an eager blk */
609 0 : if( FD_UNLIKELY( meta->final!=fd_rotor_blk_pool_idx_null( rotor->blk_pool ) || meta->skipped ) ) return NULL; /* the slot is settled */
610 0 : for( fd_rotor_blk_t * dup = fd_rotor_blk_map_ele_query( rotor->blk_map, &slot, NULL, rotor->blk_pool );
611 0 : dup;
612 0 : dup = (fd_rotor_blk_t *)fd_rotor_blk_map_ele_next_const( dup, NULL, rotor->blk_pool ) ) {
613 0 : if( FD_UNLIKELY( memcmp( &dup->dmr, blk_mr, sizeof(fd_mr32_t) ) ) ) continue;
614 0 : if( FD_LIKELY( meta->notar==fd_rotor_blk_pool_idx_null( rotor->blk_pool ) ) ) promote( rotor, dup, &meta->notar ); /* already have it, now named */
615 0 : connect_ancestors( rotor, dup );
616 0 : return NULL;
617 0 : }
618 0 : fd_rotor_blk_t * blk = blk_insert( rotor, slot, blk_mr );
619 0 : link_children( rotor, blk );
620 0 : return blk;
621 0 : }
622 :
623 : fd_rotor_blk_t *
624 : fd_rotor_blk_parented( fd_rotor_t * rotor,
625 : ulong slot,
626 : fd_mr32_t const * blk_mr,
627 : ulong parent_slot,
628 : fd_mr32_t const * parent_blk_mr,
629 : uint fec_set_cnt,
630 0 : long ts ) {
631 0 : fd_rotor_blk_t * blk = fd_rotor_blk_map_ele_query( rotor->blk_map, &slot, NULL, rotor->blk_pool );
632 0 : while( FD_LIKELY( blk && memcmp( &blk->dmr, blk_mr, sizeof(fd_mr32_t) ) ) ) blk = (fd_rotor_blk_t *)fd_rotor_blk_map_ele_next_const( blk, NULL, rotor->blk_pool );
633 0 : if( FD_UNLIKELY( !blk ) ) return NULL; /* blk was pruned while the response was in flight */
634 0 : blk->telemetry.parent_res_cnt++;
635 0 : blk->telemetry.first_meta_res_ts = fd_long_if( !blk->telemetry.first_meta_res_ts, ts, blk->telemetry.first_meta_res_ts );
636 :
637 0 : if( FD_UNLIKELY( blk->parent_slot!=ULONG_MAX ) ) return NULL; /* duplicate response, eg. a retried request */
638 0 : if( FD_UNLIKELY( parent_slot>=slot ) ) return NULL; /* a blk's parent precedes it */
639 :
640 0 : blk->parent_slot = parent_slot;
641 0 : blk->parent_blk_mr = *parent_blk_mr;
642 0 : blk->cmpl_fec_cnt = fec_set_cnt;
643 0 : blk_treap_insert( rotor, blk ); /* its FEC sets can be discovered now */
644 :
645 0 : if( FD_LIKELY( blk!=rotor->root_blk && blk->parent==fd_rotor_blk_pool_idx_null( rotor->blk_pool ) && memcmp( &blk->parent_blk_mr, &hash_null, sizeof(fd_mr32_t) ) ) ) {
646 0 : fd_rotor_orphan_map_ele_insert( rotor->orphan_map, blk, rotor->blk_pool ); /* names a parent now, link_parent takes it out if the parent is held */
647 0 : }
648 :
649 0 : fd_rotor_blk_t * parent = link_parent( rotor, blk );
650 0 : fd_rotor_blk_t * created = NULL;
651 0 : if( FD_LIKELY( !parent ) ) parent = created = fd_rotor_blk_notarized( rotor, parent_slot, parent_blk_mr ); /* links the child blks naming it */
652 0 : if( FD_LIKELY( parent ) ) {
653 0 : if( FD_UNLIKELY( fd_rotor_slot_meta( rotor, slot )->final==fd_rotor_blk_pool_idx( rotor->blk_pool, blk ) ) ) promote( rotor, parent, &fd_rotor_slot_meta( rotor, parent_slot )->final ); /* finalized ancestry */
654 0 : consume( rotor, blk );
655 0 : if( FD_UNLIKELY( blk->cmpl_fec_cnt && blk->cons_fec_cnt==blk->cmpl_fec_cnt ) ) cascade( rotor, blk );
656 0 : if( FD_LIKELY( !created ) ) connect_ancestors( rotor, parent ); /* a held parent may itself be orphaned */
657 0 : }
658 0 : return created;
659 0 : }
660 :
661 : void
662 : fd_rotor_slot_catchup( fd_rotor_t * rotor,
663 0 : ulong slot ) {
664 0 : for( ulong s=fd_ulong_max( rotor->root+1UL, rotor->catchup_slot ); s<slot; s++ ) {
665 0 : fd_rotor_slot_meta_t * meta = fd_rotor_slot_meta( rotor, s );
666 0 : if( FD_UNLIKELY( meta->skipped || meta->invalidated || meta->final!=fd_rotor_blk_pool_idx_null( rotor->blk_pool ) || meta->eager!=fd_rotor_blk_pool_idx_null( rotor->blk_pool ) ) ) continue;
667 0 : meta->eager = fd_rotor_blk_pool_idx( rotor->blk_pool, blk_insert( rotor, s, &hash_null ) );
668 0 : }
669 0 : rotor->catchup_slot = fd_ulong_max( rotor->catchup_slot, slot );
670 0 : }
671 :
672 : fd_rotor_fec_t *
673 : fd_rotor_fec_complete( fd_rotor_t * rotor,
674 : fd_shred_t const * last_shred,
675 : fd_mr32_t const * fec_mr,
676 : int is_leader,
677 : uint turbine_cnt,
678 : uint repair_cnt,
679 : uint recovered_cnt,
680 : uint data_rcvd,
681 : uint parity_rcvd,
682 : uint repair_rcvd,
683 0 : long ts ) {
684 0 : fd_rotor_shred_insert( rotor, last_shred, fec_mr, 0, ts ); /* the last shred's header, its source was given when it arrived */
685 :
686 0 : fd_mr20_t key;
687 0 : memcpy( key.uc, fec_mr->uc, sizeof(fd_mr20_t) );
688 0 : fd_rotor_fec_t * fec = fd_rotor_fec_map_ele_query( rotor->fec_map, &key, NULL, rotor->fec_pool );
689 0 : if( FD_UNLIKELY( !fec ) ) return NULL; /* fd_rotor_shred_insert dropped it as conflicting with the eager blk */
690 :
691 0 : int first_complete = !fec->complete;
692 0 : fec->cmpl_ts = fd_long_if( first_complete, ts, fec->cmpl_ts );
693 0 : fec->final_src = fd_int_if( first_complete && is_leader, FD_EVENT_BLOCK_RECEIVED_FEC_SETS_FINAL_SHRED_SOURCE_LEADER, fec->final_src );
694 0 : fec->data_rcvd = fd_uint_if( first_complete, data_rcvd, fec->data_rcvd );
695 0 : fec->parity_rcvd = fd_uint_if( first_complete, parity_rcvd, fec->parity_rcvd );
696 0 : fec->repair_rcvd = fd_uint_if( first_complete, repair_rcvd, fec->repair_rcvd );
697 0 : fec->mr32 = *fec_mr;
698 0 : fec->rcvd = UINT_MAX;
699 0 : fec->complete = 1;
700 0 : fec->data_complete = !!( last_shred->data.flags & FD_SHRED_DATA_FLAG_DATA_COMPLETE );
701 0 : fec->is_leader |= !!is_leader; /* a completion again from the network does not clear our own */
702 :
703 0 : ulong slot = last_shred->slot; /* fd_shred_t is packed, the map query needs an aligned key */
704 0 : fd_rotor_slot_meta_t * meta = fd_rotor_slot_meta( rotor, slot );
705 0 : fd_rotor_blk_t * pool = rotor->blk_pool;
706 0 : fd_rotor_blk_t * eager = fd_rotor_blk_pool_ele( pool, meta->eager );
707 0 : int cmpl = eager && !meta->invalidated && eager->cmpl_fec_cnt && !memcmp( &eager->dmr, &hash_null, sizeof(fd_mr32_t) );
708 0 : for( uint k=0U; cmpl && k<eager->cmpl_fec_cnt; k++ ) {
709 0 : cmpl = eager->fecs[ k ]!=fd_rotor_fec_pool_idx_null( rotor->fec_pool ) && fd_rotor_fec_pool_ele( rotor->fec_pool, eager->fecs[ k ] )->complete;
710 0 : }
711 0 : meta->leader |= (uint)!!is_leader;
712 0 : if( FD_UNLIKELY( is_leader && eager ) ) eager->eager = 0; /* our own, never repaired */
713 0 : if( FD_UNLIKELY( is_leader && eager && meta->final!=meta->eager && meta->notar!=meta->eager ) ) blk_treap_remove( rotor, eager );
714 0 : if( FD_UNLIKELY( cmpl ) ) {
715 0 : compute_dmr( rotor, eager );
716 0 : link_children( rotor, eager ); /* the blks naming its dmr waited for it */
717 0 : dedup( rotor, eager, ts );
718 0 : if( FD_UNLIKELY( fd_rotor_fec_map_ele_query( rotor->fec_map, &key, NULL, rotor->fec_pool )!=fec ) ) return NULL; /* dedup pruned eager and with it the FEC set */
719 0 : }
720 :
721 0 : for( fd_rotor_blk_t * blk = fd_rotor_blk_map_ele_query( rotor->blk_map, &slot, NULL, pool );
722 0 : blk;
723 0 : blk = (fd_rotor_blk_t *)fd_rotor_blk_map_ele_next_const( blk, NULL, pool ) ) {
724 0 : if( FD_LIKELY( blk->fecs[ fec->fec_idx ]!=fd_rotor_fec_pool_idx( rotor->fec_pool, fec ) ) ) continue;
725 0 : uint end = fd_uint_if( !!blk->cmpl_fec_cnt, blk->cmpl_fec_cnt, (uint)rotor->fec_blk_max );
726 0 : while( blk->buff_fec_cnt<end
727 0 : && blk->fecs[ blk->buff_fec_cnt ]!=fd_rotor_fec_pool_idx_null( rotor->fec_pool )
728 0 : && fd_rotor_fec_pool_ele( rotor->fec_pool, blk->fecs[ blk->buff_fec_cnt ] )->complete ) {
729 0 : blk->buff_fec_cnt++;
730 0 : }
731 0 : if( FD_LIKELY( first_complete ) ) {
732 0 : blk->telemetry.turbine_shred_cnt += turbine_cnt;
733 0 : blk->telemetry.repair_shred_cnt += repair_cnt;
734 0 : blk->telemetry.recovered_shred_cnt += recovered_cnt;
735 0 : blk->telemetry.last_cmpl_fec_idx = fec->fec_idx*FD_FEC_SHRED_CNT;
736 0 : }
737 0 : blk->telemetry.last_shred_ts = fd_long_if( blk->cmpl_fec_cnt && blk->buff_fec_cnt==blk->cmpl_fec_cnt && !blk->telemetry.last_shred_ts, ts, blk->telemetry.last_shred_ts );
738 0 : if( FD_UNLIKELY( blk->cmpl_fec_cnt && blk->buff_fec_cnt==blk->cmpl_fec_cnt && !blk->telemetry.reported && rotor->telemetry.report ) ) { blk->telemetry.reported = 1; rotor->telemetry.report( rotor->telemetry.ctx, blk ); }
739 0 : consume( rotor, blk );
740 0 : if( FD_UNLIKELY( blk->cmpl_fec_cnt && blk->cons_fec_cnt==blk->cmpl_fec_cnt ) ) cascade( rotor, blk );
741 0 : }
742 0 : return fec;
743 0 : }
744 :
745 : void
746 : fd_rotor_fec_evicted( fd_rotor_t * rotor,
747 : ulong slot,
748 : uint fec_set_idx,
749 0 : fd_mr20_t const * fec_mr ) {
750 0 : uint k = fec_set_idx/FD_FEC_SHRED_CNT;
751 0 : fd_rotor_fec_t * fec = fd_rotor_fec_map_ele_query( rotor->fec_map, fec_mr, NULL, rotor->fec_pool );
752 0 : if( FD_UNLIKELY( !fec || fec->complete || fec->slot!=slot || fec->fec_idx!=k ) ) return;
753 :
754 0 : fec->rcvd = 0U; /* its req, still waiting since the set is incomplete, asks for every shred again */
755 0 : }
756 :
757 : fd_rotor_fec_t *
758 : fd_rotor_fec_notarized( fd_rotor_t * rotor,
759 : ulong slot,
760 : fd_mr32_t const * blk_mr,
761 : uint fec_set_idx,
762 : fd_mr20_t const * fec_mr,
763 0 : long ts ) {
764 :
765 0 : uint fec_idx = fec_set_idx / FD_FEC_SHRED_CNT;
766 :
767 0 : fd_rotor_blk_t * blk = fd_rotor_blk_map_ele_query( rotor->blk_map, &slot, NULL, rotor->blk_pool );
768 0 : while( blk && memcmp( &blk->dmr, blk_mr, sizeof(fd_mr32_t) ) ) blk = (fd_rotor_blk_t *)fd_rotor_blk_map_ele_next_const( blk, NULL, rotor->blk_pool );
769 0 : if( FD_UNLIKELY( !blk ) ) return NULL; /* blk was pruned while the response was in flight */
770 0 : blk->telemetry.fec_root_res_cnt++;
771 0 : blk->telemetry.first_meta_res_ts = fd_long_if( !blk->telemetry.first_meta_res_ts, ts, blk->telemetry.first_meta_res_ts );
772 :
773 0 : if( FD_UNLIKELY( blk->fecs[ fec_idx ]!=fd_rotor_fec_pool_idx_null( rotor->fec_pool ) ) ) return NULL; /* duplicate response, eg. a retried request */
774 :
775 0 : fd_rotor_slot_meta_t * meta = fd_rotor_slot_meta( rotor, slot );
776 0 : fd_rotor_blk_t * eager = fd_rotor_blk_pool_ele( rotor->blk_pool, meta->eager );
777 0 : int eqvoc = eager && eager->fecs[ fec_idx ]!=fd_rotor_fec_pool_idx_null( rotor->fec_pool ) && memcmp( &fd_rotor_fec_pool_ele( rotor->fec_pool, eager->fecs[ fec_idx ] )->key, fec_mr, sizeof(fd_mr20_t) );
778 0 : if( FD_UNLIKELY( eqvoc ) ) fd_rotor_slot_invalidated( rotor, slot, FD_EVENT_BLOCK_RECEIVED_CANCELLED_REASON_MERKLE_ROOT_MISMATCH, ts );
779 :
780 0 : fd_rotor_fec_t * fec = fd_rotor_fec_map_ele_query( rotor->fec_map, fec_mr, NULL, rotor->fec_pool );
781 0 : if( FD_UNLIKELY( fec && ( fec->slot!=slot || fec->fec_idx!=fec_idx ) ) ) return NULL; /* a FEC set root commits to its slot and index, so this leaf names no FEC set a shred can fill */
782 0 : if( FD_UNLIKELY( !fec ) ) {
783 0 : FD_TEST( fd_rotor_fec_pool_free( rotor->fec_pool ) );
784 0 : fec = fd_rotor_fec_pool_ele_acquire( rotor->fec_pool );
785 0 : fec->key = *fec_mr;
786 0 : fec->mr32 = hash_null;
787 0 : fec->fec_idx = fec_idx;
788 0 : fec->slot = slot;
789 0 : fec->rcvd = 0U;
790 0 : fec->complete = 0;
791 0 : fec->data_complete = 0;
792 0 : fec->final_src = 0;
793 0 : fec->first_ts = 0L;
794 0 : fec->cmpl_ts = 0L;
795 0 : fec->is_leader = 0;
796 0 : fec->data_rcvd = 0U;
797 0 : fec->parity_rcvd = 0U;
798 0 : fec->repair_rcvd = 0U;
799 0 : fd_rotor_fec_map_ele_insert( rotor->fec_map, fec, rotor->fec_pool );
800 0 : }
801 0 : fec->notarized = 1;
802 0 : blk->fecs[ fec_idx ] = fd_rotor_fec_pool_idx( rotor->fec_pool, fec );
803 0 : if( FD_LIKELY( !fec->complete ) ) return fec;
804 :
805 0 : uint end = fd_uint_if( !!blk->cmpl_fec_cnt, blk->cmpl_fec_cnt, (uint)rotor->fec_blk_max );
806 0 : while( blk->buff_fec_cnt<end
807 0 : && blk->fecs[ blk->buff_fec_cnt ]!=fd_rotor_fec_pool_idx_null( rotor->fec_pool )
808 0 : && fd_rotor_fec_pool_ele( rotor->fec_pool, blk->fecs[ blk->buff_fec_cnt ] )->complete ) {
809 0 : blk->buff_fec_cnt++;
810 0 : }
811 0 : if( FD_UNLIKELY( blk->cmpl_fec_cnt && blk->buff_fec_cnt==blk->cmpl_fec_cnt && !blk->telemetry.reported && rotor->telemetry.report ) ) { blk->telemetry.reported = 1; rotor->telemetry.report( rotor->telemetry.ctx, blk ); }
812 0 : consume( rotor, blk );
813 0 : if( FD_UNLIKELY( blk->cmpl_fec_cnt && blk->cons_fec_cnt==blk->cmpl_fec_cnt ) ) cascade( rotor, blk );
814 0 : return fec;
815 0 : }
816 :
817 : void
818 : fd_rotor_root_advanced( fd_rotor_t * rotor,
819 : ulong slot,
820 0 : fd_mr32_t const * blk_mr ) {
821 0 : ulong root = rotor->root;
822 0 : fd_rotor_blk_t * root_blk = NULL; /* the new root, if held. rotor->root_blk is the old root until freed below: it left orphan_map on becoming root and must not be removed again */
823 0 : for( ulong s=root; s<=slot; s++ ) {
824 0 : fd_rotor_blk_t * next;
825 0 : for( fd_rotor_blk_t * blk = fd_rotor_blk_map_ele_query( rotor->blk_map, &s, NULL, rotor->blk_pool );
826 0 : blk;
827 0 : blk = next ) {
828 0 : next = (fd_rotor_blk_t *)fd_rotor_blk_map_ele_next_const( blk, NULL, rotor->blk_pool );
829 0 : if( FD_UNLIKELY( !blk->telemetry.reported && rotor->telemetry.report ) ) { blk->telemetry.reported = 1; rotor->telemetry.report( rotor->telemetry.ctx, blk ); }
830 0 : for( ulong k=0UL; k<rotor->fec_blk_max; k++ ) {
831 0 : ulong idx = blk->fecs[ k ];
832 0 : blk->fecs[ k ] = fd_rotor_fec_pool_idx_null( rotor->fec_pool );
833 0 : if( FD_LIKELY( idx==fd_rotor_fec_pool_idx_null( rotor->fec_pool ) ) ) continue;
834 0 : fd_rotor_fec_t * fec = fd_rotor_fec_pool_ele( rotor->fec_pool, idx );
835 0 : if( FD_LIKELY( fd_rotor_fec_map_ele_query( rotor->fec_map, &fec->key, NULL, rotor->fec_pool )!=fec ) ) continue; /* freed through a sibling */
836 0 : fd_rotor_fec_map_ele_remove_fast( rotor->fec_map, fec, rotor->fec_pool );
837 0 : fd_rotor_fec_pool_ele_release ( rotor->fec_pool, fec );
838 0 : }
839 0 : if( FD_UNLIKELY( s==slot && !memcmp( &blk->dmr, blk_mr, sizeof(fd_mr32_t) ) ) ) { /* the new root */
840 0 : blk_treap_remove( rotor, blk ); /* the root is never repaired */
841 0 : if( FD_LIKELY( blk!=rotor->root_blk && blk->parent==fd_rotor_blk_pool_idx_null( rotor->blk_pool ) && memcmp( &blk->parent_blk_mr, &hash_null, sizeof(fd_mr32_t) ) ) ) {
842 0 : fd_rotor_orphan_map_ele_remove_fast( rotor->orphan_map, blk, rotor->blk_pool ); /* its parent was just freed, the root waits for nothing */
843 0 : }
844 0 : fd_rotor_slot_meta( rotor, slot )->final = fd_rotor_blk_pool_idx( rotor->blk_pool, blk );
845 0 : blk->eager = 0;
846 0 : root_blk = blk;
847 0 : continue;
848 0 : }
849 :
850 0 : unlink( rotor, blk );
851 0 : if( FD_UNLIKELY( blk!=rotor->root_blk && blk->parent==fd_rotor_blk_pool_idx_null( rotor->blk_pool ) && memcmp( &blk->parent_blk_mr, &hash_null, sizeof(fd_mr32_t) ) ) ) fd_rotor_orphan_map_ele_remove_fast( rotor->orphan_map, blk, rotor->blk_pool );
852 0 : blk_treap_remove( rotor, blk );
853 0 : fd_rotor_slot_meta_t * meta = fd_rotor_slot_meta( rotor, s );
854 0 : if( FD_UNLIKELY( meta->eager==fd_rotor_blk_pool_idx( rotor->blk_pool, blk ) ) ) meta->eager = fd_rotor_blk_pool_idx_null( rotor->blk_pool ); /* the root slot's meta stays live, its roles must not name freed blks */
855 0 : if( FD_UNLIKELY( meta->notar==fd_rotor_blk_pool_idx( rotor->blk_pool, blk ) ) ) meta->notar = fd_rotor_blk_pool_idx_null( rotor->blk_pool );
856 0 : fd_rotor_blk_map_ele_remove_fast( rotor->blk_map, blk, rotor->blk_pool );
857 0 : fd_rotor_blk_pool_ele_release ( rotor->blk_pool, blk );
858 0 : }
859 0 : }
860 0 : rotor->root_blk = root_blk;
861 0 : rotor->root = slot;
862 0 : }
863 :
864 : void
865 : fd_rotor_shred_insert( fd_rotor_t * rotor,
866 : fd_shred_t const * shred,
867 : fd_mr32_t const * fec_mr,
868 : int src,
869 0 : long ts ) {
870 :
871 0 : fd_mr20_t key;
872 0 : memcpy( key.uc, fec_mr->uc, sizeof(fd_mr20_t) );
873 :
874 : /* First, handle a Notar shred (shred for a FEC set that has already
875 : reached a notarized status ie. SafeToNotar or stronger). It also
876 : belongs to the eager blk, so fall through. */
877 :
878 0 : fd_rotor_fec_t * fec = fd_rotor_fec_map_ele_query( rotor->fec_map, &key, NULL, rotor->fec_pool );
879 0 : uint fec_idx = shred->idx / FD_FEC_SHRED_CNT;
880 0 : if( FD_UNLIKELY( fec && ( fec->slot!=shred->slot || fec->fec_idx!=fec_idx ) ) ) return; /* a 20-byte root collision */
881 0 : if( FD_UNLIKELY( fec && fec->notarized ) ) fec->rcvd = fd_uint_set_bit( fec->rcvd, (int)( shred->idx - fec_idx * FD_FEC_SHRED_CNT ) );
882 0 : if( FD_UNLIKELY( fec && !fec->first_ts ) ) fec->first_ts = ts;
883 0 : if( FD_LIKELY( fec && src && !fec->complete ) ) fec->final_src = src; /* frozen once complete */
884 :
885 : /* Second, handle an Eager shred (from Turbine or Eager Repair). */
886 :
887 0 : ulong parent_slot = shred->slot - shred->data.parent_off;
888 0 : fd_rotor_blk_t * pool = rotor->blk_pool;
889 0 : ulong null = fd_rotor_blk_pool_idx_null( pool );
890 0 : fd_rotor_slot_meta_t * meta = fd_rotor_slot_meta( rotor, shred->slot );
891 0 : fd_rotor_blk_t const * fin = fd_rotor_blk_pool_ele_const( pool, meta->final );
892 0 : int fin_done = fin && fin->cmpl_fec_cnt && fin->buff_fec_cnt==fin->cmpl_fec_cnt;
893 0 : if( FD_UNLIKELY( meta->skipped || meta->invalidated || ( fin_done && meta->eager==null ) ) ) return; /* a final cert ahead of turbine still lets turbine build the blk, dedup merges it */
894 0 : if( FD_UNLIKELY( meta->eager==null ) ) meta->eager = fd_rotor_blk_pool_idx( pool, blk_insert( rotor, shred->slot, &hash_null ) );
895 0 : fd_rotor_blk_t * blk = fd_rotor_blk_pool_ele( pool, meta->eager );
896 0 : if( FD_UNLIKELY( blk->parent_slot==ULONG_MAX ) ) blk->parent_slot = parent_slot; /* created empty by a child or catchup */
897 :
898 : /* Check for misbehavior that can invalidate the eager block. */
899 :
900 0 : fd_block_marker_t marker[1];
901 0 : int bad_header = shred->idx==0U && ( fd_block_marker_de( marker, fd_shred_data_payload( shred ), fd_shred_payload_sz( shred ) ) || marker->kind!=FD_BLOCK_MARKER_KIND_HEADER || marker->header.parent_slot!=parent_slot );
902 0 : fd_mr32_t const * parent_blk_mr = shred->idx==0U ? &marker->header.parent_block_id : NULL;
903 :
904 0 : int slot_complete = !!( shred->data.flags & FD_SHRED_DATA_FLAG_SLOT_COMPLETE );
905 0 : int eqvoc = blk->fecs[ fec_idx ]!=fd_rotor_fec_pool_idx_null( rotor->fec_pool ) && blk->fecs[ fec_idx ]!=fd_rotor_fec_pool_idx( rotor->fec_pool, fec ); /* the leader signed two FEC sets at this index, eg. two shred 0s */
906 0 : int parent_conflict = bad_header || blk->parent_slot!=parent_slot;
907 0 : int complete_conflict = ( blk->cmpl_fec_cnt && fec_idx>=blk->cmpl_fec_cnt ) || ( slot_complete && fec_idx+1U<blk->rcvd_fec_cnt );
908 0 : if( FD_UNLIKELY( eqvoc ) ) { fd_rotor_slot_invalidated( rotor, shred->slot, FD_EVENT_BLOCK_RECEIVED_CANCELLED_REASON_MERKLE_ROOT_MISMATCH, ts ); return; }
909 0 : if( FD_UNLIKELY( parent_conflict ) ) { fd_rotor_slot_invalidated( rotor, shred->slot, bad_header ? FD_EVENT_BLOCK_RECEIVED_CANCELLED_REASON_INVALID_BLOCK_HEADER : FD_EVENT_BLOCK_RECEIVED_CANCELLED_REASON_PARENT_OFF_MISMATCH, ts ); return; }
910 0 : if( FD_UNLIKELY( complete_conflict ) ) { fd_rotor_slot_invalidated( rotor, shred->slot, FD_EVENT_BLOCK_RECEIVED_CANCELLED_REASON_SLOT_COMPLETE_MISMATCH, ts ); return; }
911 :
912 0 : if( FD_UNLIKELY( parent_blk_mr ) ) { /* shred 0 again names the same parent, the key must not change while in orphan_map */
913 0 : if( FD_UNLIKELY( blk!=rotor->root_blk && blk->parent==null && memcmp( &blk->parent_blk_mr, &hash_null, sizeof(fd_mr32_t) ) ) ) fd_rotor_orphan_map_ele_remove_fast( rotor->orphan_map, blk, pool );
914 0 : blk->parent_blk_mr = *parent_blk_mr;
915 0 : if( FD_LIKELY ( blk!=rotor->root_blk && blk->parent==null && memcmp( &blk->parent_blk_mr, &hash_null, sizeof(fd_mr32_t) ) ) ) fd_rotor_orphan_map_ele_insert ( rotor->orphan_map, blk, pool );
916 0 : }
917 0 : if( FD_UNLIKELY( parent_blk_mr && blk->parent==null && !link_parent( rotor, blk ) ) ) { /* waits unlinked for the named parent to be held, eg. to complete on turbine */
918 0 : fd_rotor_slot_meta_t * pmeta = fd_rotor_slot_meta( rotor, parent_slot );
919 0 : if( FD_UNLIKELY( pmeta->eager==null && pmeta->final==null && !pmeta->skipped && !pmeta->invalidated ) ) blk_insert( rotor, parent_slot, &hash_null ); /* seed the parent slot's eager blk, turbine may have lost it */
920 0 : }
921 0 : if( FD_UNLIKELY( slot_complete ) ) blk->cmpl_fec_cnt = fec_idx+1U;
922 0 : if( FD_UNLIKELY( slot_complete || fec_idx+1U>blk->rcvd_fec_cnt ) ) { /* its repair limit moved */
923 0 : blk->rcvd_fec_ts = fd_long_if( fec_idx+1U>blk->rcvd_fec_cnt, ts, blk->rcvd_fec_ts );
924 0 : blk_treap_insert( rotor, blk );
925 0 : }
926 :
927 0 : if( FD_UNLIKELY( !fec ) ) {
928 0 : FD_TEST( fd_rotor_fec_pool_free( rotor->fec_pool ) );
929 0 : fec = fd_rotor_fec_pool_ele_acquire( rotor->fec_pool );
930 0 : fec->key = key;
931 0 : fec->mr32 = hash_null;
932 0 : fec->fec_idx = fec_idx;
933 0 : fec->slot = shred->slot;
934 0 : fec->rcvd = 0U;
935 0 : fec->complete = 0;
936 0 : fec->data_complete = 0;
937 0 : fec->final_src = src;
938 0 : fec->first_ts = ts;
939 0 : fec->cmpl_ts = 0L;
940 0 : fec->is_leader = 0;
941 0 : fec->notarized = 0;
942 0 : fec->data_rcvd = 0U;
943 0 : fec->parity_rcvd = 0U;
944 0 : fec->repair_rcvd = 0U;
945 0 : fd_rotor_fec_map_ele_insert( rotor->fec_map, fec, rotor->fec_pool );
946 0 : }
947 0 : blk->fecs[ fec_idx ] = fd_rotor_fec_pool_idx( rotor->fec_pool, fec );
948 0 : blk->rcvd_fec_cnt = fd_uint_max( blk->rcvd_fec_cnt, fec_idx+1U );
949 0 : fec->rcvd = fd_uint_set_bit( fec->rcvd, (int)( shred->idx - fec_idx*FD_FEC_SHRED_CNT ) );
950 0 : }
951 :
952 : void
953 : fd_rotor_slot_invalidated( fd_rotor_t * rotor,
954 : ulong slot,
955 : int reason,
956 0 : long ts ) {
957 0 : fd_rotor_slot_meta_t * meta = fd_rotor_slot_meta( rotor, slot );
958 0 : fd_rotor_blk_t * eager = fd_rotor_blk_pool_ele( rotor->blk_pool, meta->eager );
959 0 : int first = !meta->invalidated;
960 0 : meta->invalidated = 1;
961 0 : if( FD_LIKELY( eager ) ) {
962 0 : eager->telemetry.cancelled_ts = fd_long_if( !eager->telemetry.cancelled_reason, ts, eager->telemetry.cancelled_ts );
963 0 : eager->telemetry.cancelled_reason = (uchar)reason;
964 0 : eager->eager = 0;
965 0 : }
966 0 : if( FD_LIKELY( eager && meta->final!=meta->eager && meta->notar!=meta->eager ) ) blk_treap_remove( rotor, eager ); /* still the eager blk, never repaired */
967 0 : if( FD_LIKELY( first && eager && eager->parent!=fd_rotor_blk_pool_idx_null( rotor->blk_pool ) ) ) cascade( rotor, fd_rotor_blk_pool_ele( rotor->blk_pool, eager->parent ) ); /* delivers the notar blks held behind it */
968 0 : }
969 :
970 : fd_rotor_slot_meta_t *
971 : fd_rotor_slot_meta( fd_rotor_t * rotor,
972 0 : ulong slot ) {
973 0 : fd_rotor_slot_meta_t * meta = &rotor->slot_meta[ slot % rotor->slot_max ];
974 0 : if( FD_UNLIKELY( meta->slot!=slot ) ) {
975 0 : meta->slot = slot;
976 0 : meta->eager = fd_rotor_blk_pool_idx_null( rotor->blk_pool );
977 0 : meta->notar = fd_rotor_blk_pool_idx_null( rotor->blk_pool );
978 0 : meta->final = fd_rotor_blk_pool_idx_null( rotor->blk_pool );
979 0 : meta->invalidated = 0;
980 0 : meta->skipped = 0;
981 0 : meta->leader = 0;
982 0 : }
983 0 : return meta;
984 0 : }
985 :
986 : void
987 : fd_rotor_slot_skipped( fd_rotor_t * rotor,
988 0 : ulong slot ) {
989 0 : fd_rotor_slot_meta_t * meta = fd_rotor_slot_meta( rotor, slot );
990 0 : meta->skipped = 1; /* late repair requests or shreds for the slot must not recreate blks in it */
991 :
992 0 : fd_rotor_blk_t * next;
993 0 : for( fd_rotor_blk_t * blk = fd_rotor_blk_map_ele_query( rotor->blk_map, &slot, NULL, rotor->blk_pool );
994 0 : blk;
995 0 : blk = next ) {
996 0 : next = (fd_rotor_blk_t *)fd_rotor_blk_map_ele_next_const( blk, NULL, rotor->blk_pool );
997 0 : prune( rotor, blk );
998 0 : }
999 0 : }
|