Line data Source code
1 : #include "fd_slot_delta_parser.h"
2 :
3 : #define SLOT_DELTA_PARSER_DEBUG 0
4 :
5 0 : #define STATE_SLOT_DELTAS_LEN ( 0)
6 0 : #define STATE_SLOT_DELTA_SLOT ( 1)
7 0 : #define STATE_SLOT_DELTA_IS_ROOT ( 2)
8 0 : #define STATE_SLOT_DELTA_STATUS_LEN ( 3)
9 0 : #define STATE_STATUS_BLOCKHASH ( 4)
10 0 : #define STATE_STATUS_TXN_IDX ( 5)
11 0 : #define STATE_CACHE_STATUS_LEN ( 6)
12 0 : #define STATE_CACHE_STATUS_KEY_SLICE ( 7)
13 0 : #define STATE_CACHE_STATUS_RESULT ( 8)
14 0 : #define STATE_CACHE_STATUS_RESULT_ERR ( 9)
15 0 : #define STATE_CACHE_STATUS_RESULT_ERR_INSTR_IDX (10)
16 0 : #define STATE_CACHE_STATUS_RESULT_ERR_INSTR_ERR (11)
17 0 : #define STATE_CACHE_STATUS_RESULT_ERR_INSTR_ERR_CUSTOM (12)
18 0 : #define STATE_CACHE_STATUS_RESULT_ERR_INSTR_ERR_CUSTOM_BORSH_LEN (13)
19 0 : #define STATE_CACHE_STATUS_RESULT_ERR_INSTR_ERR_CUSTOM_BORSH_ERR (14)
20 0 : #define STATE_CACHE_STATUS_RESULT_ERR_IDX (15)
21 0 : #define STATE_DONE (16)
22 :
23 0 : #define FD_SLOT_DELTA_PARSER_SLOT_SET_MAX_ENTRIES (512UL)
24 :
25 : struct fd_slot_delta_parser_private {
26 : int state; /* parser state machine */
27 : int entry_avail; /* whether a parsed entry is available */
28 : int group_avail; /* whether a parsed group is available */
29 : int slot_avail; /* whether a parsed slot is available */
30 :
31 : uchar * dst; /* where to store the next parsed value */
32 : ulong dst_cur; /* offset into dst */
33 : ulong dst_sz; /* size of dst */
34 :
35 : ulong len; /* number of slot delta entries */
36 : int is_root; /* whether the current slot delta entry is rooted */
37 : ulong txnhash_offset; /* offset into the txncache for the current slot delta entry */
38 : ulong slot_delta_status_len; /* number of blockhashes in the slot delta entry */
39 : ulong cache_status_len; /* number of txns associated with the blockhash */
40 : ulong borsh_io_error_len; /* used to parse a variable len borsh_io_error string */
41 : uint error_discriminant; /* stores the error discriminant of a txn result */
42 : uchar error; /* stores the error code of a txn result */
43 :
44 : fd_slot_entry_t * slot_pool; /* pool backing a slot hashset */
45 : slot_set_t * slot_set; /* slot hash set to detect duplicate slots */
46 : ulong slot_pool_ele_cnt; /* count of slots in pool */
47 : fd_sstxncache_entry_t entry[1]; /* parsed slot delta entry */
48 : };
49 :
50 : static inline ulong
51 0 : state_size( fd_slot_delta_parser_t * parser ) {
52 0 : switch( parser->state ) {
53 0 : case STATE_SLOT_DELTAS_LEN: return sizeof(ulong);
54 0 : case STATE_SLOT_DELTA_SLOT: return sizeof(ulong);
55 0 : case STATE_SLOT_DELTA_IS_ROOT: return sizeof(uchar);
56 0 : case STATE_SLOT_DELTA_STATUS_LEN: return sizeof(ulong);
57 0 : case STATE_STATUS_BLOCKHASH: return 32UL;
58 0 : case STATE_STATUS_TXN_IDX: return sizeof(ulong);
59 0 : case STATE_CACHE_STATUS_LEN: return sizeof(ulong);
60 0 : case STATE_CACHE_STATUS_KEY_SLICE: return 20UL;
61 0 : case STATE_CACHE_STATUS_RESULT: return sizeof(uint);
62 0 : case STATE_CACHE_STATUS_RESULT_ERR: return sizeof(uint);
63 0 : case STATE_CACHE_STATUS_RESULT_ERR_INSTR_IDX: return sizeof(uchar);
64 0 : case STATE_CACHE_STATUS_RESULT_ERR_INSTR_ERR: return sizeof(uint);
65 0 : case STATE_CACHE_STATUS_RESULT_ERR_INSTR_ERR_CUSTOM: return sizeof(uint);
66 0 : case STATE_CACHE_STATUS_RESULT_ERR_INSTR_ERR_CUSTOM_BORSH_LEN: return sizeof(ulong);
67 0 : case STATE_CACHE_STATUS_RESULT_ERR_INSTR_ERR_CUSTOM_BORSH_ERR: return parser->borsh_io_error_len;
68 0 : case STATE_CACHE_STATUS_RESULT_ERR_IDX: return sizeof(uchar);
69 0 : case STATE_DONE: return 0UL;
70 0 : default: FD_LOG_ERR(( "unknown state %d", parser->state ));
71 0 : }
72 0 : }
73 :
74 : static inline uchar *
75 0 : state_dst( fd_slot_delta_parser_t * parser ) {
76 0 : switch( parser->state ) {
77 0 : case STATE_SLOT_DELTAS_LEN: return (uchar*)&parser->len;
78 0 : case STATE_SLOT_DELTA_SLOT: return (uchar*)&parser->entry->slot;
79 0 : case STATE_SLOT_DELTA_IS_ROOT: return (uchar*)&parser->is_root;
80 0 : case STATE_SLOT_DELTA_STATUS_LEN: return (uchar*)&parser->slot_delta_status_len;
81 0 : case STATE_STATUS_BLOCKHASH: return parser->entry->blockhash;
82 0 : case STATE_STATUS_TXN_IDX: return (uchar*)&parser->txnhash_offset;
83 0 : case STATE_CACHE_STATUS_LEN: return (uchar*)&parser->cache_status_len;
84 0 : case STATE_CACHE_STATUS_KEY_SLICE: return parser->entry->txnhash;
85 0 : case STATE_CACHE_STATUS_RESULT: return (uchar*)&parser->error_discriminant;
86 0 : case STATE_CACHE_STATUS_RESULT_ERR: return (uchar*)&parser->error_discriminant;
87 0 : case STATE_CACHE_STATUS_RESULT_ERR_INSTR_IDX: return NULL;
88 0 : case STATE_CACHE_STATUS_RESULT_ERR_INSTR_ERR: return (uchar*)&parser->error_discriminant;
89 0 : case STATE_CACHE_STATUS_RESULT_ERR_INSTR_ERR_CUSTOM: return (uchar*)&parser->error_discriminant;
90 0 : case STATE_CACHE_STATUS_RESULT_ERR_INSTR_ERR_CUSTOM_BORSH_LEN: return (uchar*)&parser->borsh_io_error_len;
91 0 : case STATE_CACHE_STATUS_RESULT_ERR_INSTR_ERR_CUSTOM_BORSH_ERR: return NULL;
92 0 : case STATE_CACHE_STATUS_RESULT_ERR_IDX: return (uchar*)&parser->error;
93 0 : case STATE_DONE: return NULL;
94 0 : default: FD_LOG_ERR(( "unknown state %d", parser->state ));
95 0 : }
96 0 : }
97 :
98 : #if SLOT_DELTA_PARSER_DEBUG
99 : static inline void
100 : state_log( fd_slot_delta_parser_t * parser ) {
101 : switch( parser->state ) {
102 : case STATE_SLOT_DELTAS_LEN: FD_LOG_NOTICE(( "STATE_SLOT_DELTAS_LEN: %lu", parser->len )); break;
103 : case STATE_SLOT_DELTA_SLOT: FD_LOG_NOTICE(( "STATE_SLOT_DELTA_SLOT: %lu", parser->entry->slot )); break;
104 : case STATE_SLOT_DELTA_IS_ROOT: FD_LOG_NOTICE(( "STATE_SLOT_DELTA_IS_ROOT: %d", parser->is_root )); break;
105 : case STATE_SLOT_DELTA_STATUS_LEN: FD_LOG_NOTICE(( "STATE_SLOT_DELTA_STATUS_LEN: %lu", parser->slot_delta_status_len )); break;
106 : case STATE_STATUS_BLOCKHASH: {
107 : FD_BASE58_ENCODE_32_BYTES( parser->entry->blockhash, blockhash_b58 );
108 : /* */FD_LOG_NOTICE(( "STATE_STATUS_BLOCKHASH: %s", blockhash_b58 ));
109 : break;
110 : }
111 : case STATE_CACHE_STATUS_LEN: FD_LOG_NOTICE(( "STATE_CACHE_STATUS_LEN: %lu", parser->cache_status_len )); break;
112 : default: break;
113 : }
114 : }
115 : #endif
116 :
117 : static inline int
118 0 : state_validate( fd_slot_delta_parser_t * parser ) {
119 0 : switch( parser->state ) {
120 0 : case STATE_SLOT_DELTAS_LEN:
121 0 : if( FD_UNLIKELY( parser->len>FD_SLOT_DELTA_MAX_ENTRIES ) ) {
122 : /* https://github.com/anza-xyz/agave/blob/v3.1.8/runtime/src/snapshot_bank_utils.rs#L535 */
123 0 : FD_LOG_WARNING(( "slot delta validation failed: %s (%d)", fd_slot_delta_parser_advance_str( FD_SLOT_DELTA_PARSER_ADVANCE_ERROR_TOO_MANY_ENTRIES ), FD_SLOT_DELTA_PARSER_ADVANCE_ERROR_TOO_MANY_ENTRIES ));
124 0 : return FD_SLOT_DELTA_PARSER_ADVANCE_ERROR_TOO_MANY_ENTRIES;
125 0 : }
126 0 : break;
127 0 : case STATE_SLOT_DELTA_SLOT: {
128 0 : ulong slot_idx = slot_set_idx_query_const( parser->slot_set, &parser->entry->slot, ULONG_MAX, parser->slot_pool );
129 : /* https://github.com/anza-xyz/agave/blob/v3.1.8/runtime/src/snapshot_bank_utils.rs#L558 */
130 0 : if( FD_UNLIKELY( slot_idx!=ULONG_MAX ) ) {
131 0 : FD_LOG_WARNING(( "slot delta validation failed: %s (%d)", fd_slot_delta_parser_advance_str( FD_SLOT_DELTA_PARSER_ADVANCE_ERROR_SLOT_HASH_MULTIPLE_ENTRIES ), FD_SLOT_DELTA_PARSER_ADVANCE_ERROR_SLOT_HASH_MULTIPLE_ENTRIES ));
132 0 : return FD_SLOT_DELTA_PARSER_ADVANCE_ERROR_SLOT_HASH_MULTIPLE_ENTRIES;
133 0 : }
134 :
135 0 : if( FD_UNLIKELY( parser->slot_pool_ele_cnt>=FD_SLOT_DELTA_MAX_ENTRIES ) ) {
136 : /* https://github.com/anza-xyz/agave/blob/v3.1.8/runtime/src/snapshot_bank_utils.rs#L535 */
137 0 : FD_LOG_WARNING(( "slot delta validation failed: %s (%d)", fd_slot_delta_parser_advance_str( FD_SLOT_DELTA_PARSER_ADVANCE_ERROR_TOO_MANY_ENTRIES ), FD_SLOT_DELTA_PARSER_ADVANCE_ERROR_TOO_MANY_ENTRIES ));
138 0 : return FD_SLOT_DELTA_PARSER_ADVANCE_ERROR_TOO_MANY_ENTRIES;
139 0 : }
140 :
141 0 : fd_slot_entry_t * slot_entry = &parser->slot_pool[ parser->slot_pool_ele_cnt++ ];
142 0 : slot_entry->slot = parser->entry->slot;
143 0 : slot_set_ele_insert( parser->slot_set, slot_entry, parser->slot_pool );
144 0 : break;
145 0 : }
146 0 : case STATE_SLOT_DELTA_IS_ROOT:
147 0 : if( FD_UNLIKELY( !parser->is_root) ) {
148 : /* https://github.com/anza-xyz/agave/blob/v3.1.8/runtime/src/snapshot_bank_utils.rs#L545 */
149 0 : FD_LOG_WARNING(( "slot delta validation failed: %s (%d)", fd_slot_delta_parser_advance_str( FD_SLOT_DELTA_PARSER_ADVANCE_ERROR_SLOT_IS_NOT_ROOT ), FD_SLOT_DELTA_PARSER_ADVANCE_ERROR_SLOT_IS_NOT_ROOT ));
150 0 : return FD_SLOT_DELTA_PARSER_ADVANCE_ERROR_SLOT_IS_NOT_ROOT;
151 0 : }
152 0 : break;
153 0 : case STATE_STATUS_TXN_IDX:
154 0 : if( FD_UNLIKELY( parser->txnhash_offset>FD_SLOT_DELTA_MAX_TXNHASH_OFFSET ) ) {
155 0 : FD_LOG_WARNING(( "slot delta validation failed: %s (%d)",
156 0 : fd_slot_delta_parser_advance_str( FD_SLOT_DELTA_PARSER_ADVANCE_ERROR_INVALID_TXNHASH_OFFSET ),
157 0 : FD_SLOT_DELTA_PARSER_ADVANCE_ERROR_INVALID_TXNHASH_OFFSET ));
158 0 : return FD_SLOT_DELTA_PARSER_ADVANCE_ERROR_INVALID_TXNHASH_OFFSET;
159 0 : }
160 0 : break;
161 0 : default: break;
162 0 : }
163 :
164 0 : return 0;
165 0 : }
166 :
167 : static inline void
168 0 : loop( fd_slot_delta_parser_t * parser ) {
169 0 : if( FD_LIKELY( parser->cache_status_len ) ) {
170 0 : parser->state = STATE_CACHE_STATUS_KEY_SLICE;
171 0 : } else if( FD_LIKELY( parser->slot_delta_status_len ) ) {
172 0 : parser->state = STATE_STATUS_BLOCKHASH;
173 0 : } else if( FD_LIKELY( parser->len ) ) {
174 0 : parser->state = STATE_SLOT_DELTA_SLOT;
175 0 : } else {
176 0 : parser->state = STATE_DONE;
177 0 : }
178 0 : }
179 :
180 : static inline void
181 0 : result_loop( fd_slot_delta_parser_t * parser ) {
182 0 : parser->entry_avail = 1;
183 0 : loop( parser );
184 0 : }
185 :
186 : static inline void
187 0 : state_process( fd_slot_delta_parser_t * parser ) {
188 0 : FD_TEST( parser->state!=STATE_DONE );
189 :
190 0 : switch( parser->state ) {
191 0 : case STATE_SLOT_DELTAS_LEN:
192 0 : if( FD_UNLIKELY( !parser->len ) ) parser->state = STATE_DONE;
193 0 : else parser->state = STATE_SLOT_DELTA_SLOT;
194 0 : break;
195 0 : case STATE_SLOT_DELTA_SLOT:
196 0 : parser->state = STATE_SLOT_DELTA_IS_ROOT;
197 0 : parser->len--;
198 0 : break;
199 0 : case STATE_SLOT_DELTA_IS_ROOT:
200 0 : parser->state = STATE_SLOT_DELTA_STATUS_LEN;
201 0 : break;
202 0 : case STATE_SLOT_DELTA_STATUS_LEN:
203 0 : parser->slot_avail = 1;
204 0 : if( FD_UNLIKELY( !parser->slot_delta_status_len ) ) loop( parser );
205 0 : else parser->state = STATE_STATUS_BLOCKHASH;
206 0 : break;
207 0 : case STATE_STATUS_BLOCKHASH:
208 0 : parser->state = STATE_STATUS_TXN_IDX;
209 0 : parser->slot_delta_status_len--;
210 0 : break;
211 0 : case STATE_STATUS_TXN_IDX:
212 0 : parser->state = STATE_CACHE_STATUS_LEN;
213 0 : parser->group_avail = 1;
214 0 : break;
215 0 : case STATE_CACHE_STATUS_LEN:
216 0 : if( FD_UNLIKELY( !parser->cache_status_len ) ) loop( parser );
217 0 : else parser->state = STATE_CACHE_STATUS_KEY_SLICE;
218 0 : break;
219 0 : case STATE_CACHE_STATUS_KEY_SLICE:
220 0 : parser->state = STATE_CACHE_STATUS_RESULT;
221 0 : parser->cache_status_len--;
222 0 : break;
223 0 : case STATE_CACHE_STATUS_RESULT:
224 0 : if( FD_LIKELY( !parser->error_discriminant ) ) {
225 0 : parser->entry->result = 0;
226 0 : result_loop( parser );
227 0 : }
228 0 : else {
229 0 : parser->state = STATE_CACHE_STATUS_RESULT_ERR;
230 0 : }
231 0 : break;
232 0 : case STATE_CACHE_STATUS_RESULT_ERR:
233 0 : if( FD_UNLIKELY( parser->error_discriminant==8U ) ) {
234 0 : parser->state = STATE_CACHE_STATUS_RESULT_ERR_INSTR_IDX;
235 0 : } else if( FD_UNLIKELY( parser->error_discriminant==30U || parser->error_discriminant==31U || parser->error_discriminant==35U ) ) {
236 0 : parser->state = STATE_CACHE_STATUS_RESULT_ERR_IDX;
237 0 : } else {
238 0 : parser->entry->result = (uchar)parser->error_discriminant;
239 0 : result_loop( parser );
240 0 : }
241 0 : break;
242 0 : case STATE_CACHE_STATUS_RESULT_ERR_INSTR_IDX:
243 0 : parser->state = STATE_CACHE_STATUS_RESULT_ERR_INSTR_ERR;
244 0 : break;
245 0 : case STATE_CACHE_STATUS_RESULT_ERR_INSTR_ERR:
246 0 : if( FD_UNLIKELY( parser->error_discriminant==25U ) ) {
247 0 : parser->state = STATE_CACHE_STATUS_RESULT_ERR_INSTR_ERR_CUSTOM;
248 0 : } else if( FD_UNLIKELY( parser->error_discriminant==44U ) ) {
249 0 : parser->state = STATE_CACHE_STATUS_RESULT_ERR_INSTR_ERR_CUSTOM_BORSH_LEN;
250 0 : } else {
251 0 : parser->entry->result = (uchar)parser->error_discriminant;
252 0 : result_loop( parser );
253 0 : }
254 0 : break;
255 0 : case STATE_CACHE_STATUS_RESULT_ERR_INSTR_ERR_CUSTOM:
256 0 : parser->entry->result = (uchar)parser->error_discriminant;
257 0 : result_loop( parser );
258 0 : break;
259 0 : case STATE_CACHE_STATUS_RESULT_ERR_INSTR_ERR_CUSTOM_BORSH_LEN:
260 0 : parser->state = STATE_CACHE_STATUS_RESULT_ERR_INSTR_ERR_CUSTOM_BORSH_ERR;
261 0 : break;
262 0 : case STATE_CACHE_STATUS_RESULT_ERR_INSTR_ERR_CUSTOM_BORSH_ERR:
263 0 : parser->entry->result = (uchar)parser->error_discriminant;
264 0 : result_loop( parser );
265 0 : break;
266 0 : case STATE_CACHE_STATUS_RESULT_ERR_IDX:
267 0 : parser->entry->result = (uchar)parser->error;
268 0 : result_loop( parser );
269 0 : break;
270 0 : default: FD_LOG_ERR(( "unknown state %d", parser->state ));
271 0 : }
272 0 : }
273 :
274 : FD_FN_CONST ulong
275 0 : fd_slot_delta_parser_align( void ) {
276 0 : return fd_ulong_max( fd_ulong_max( alignof(fd_slot_delta_parser_t), slot_pool_align() ), slot_set_align() );
277 0 : }
278 :
279 : FD_FN_CONST ulong
280 0 : fd_slot_delta_parser_footprint( void ) {
281 0 : ulong l = FD_LAYOUT_INIT;
282 0 : l = FD_LAYOUT_APPEND( l, alignof(fd_slot_delta_parser_t), sizeof(fd_slot_delta_parser_t) );
283 0 : l = FD_LAYOUT_APPEND( l, slot_pool_align(), slot_pool_footprint( FD_SLOT_DELTA_MAX_ENTRIES ) );
284 0 : l = FD_LAYOUT_APPEND( l, slot_set_align(), slot_set_footprint( FD_SLOT_DELTA_PARSER_SLOT_SET_MAX_ENTRIES ) );
285 0 : return FD_LAYOUT_FINI( l, fd_slot_delta_parser_align() );
286 0 : }
287 :
288 : void *
289 0 : fd_slot_delta_parser_new( void * shmem ) {
290 0 : if( FD_UNLIKELY( !shmem ) ) {
291 0 : FD_LOG_WARNING(( "NULL shmem" ));
292 0 : return NULL;
293 0 : }
294 :
295 0 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shmem, fd_slot_delta_parser_align() ) ) ) {
296 0 : FD_LOG_WARNING(( "unaligned shmem" ));
297 0 : return NULL;
298 0 : }
299 :
300 0 : FD_SCRATCH_ALLOC_INIT( l, shmem );
301 0 : fd_slot_delta_parser_t * parser = FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_slot_delta_parser_t), sizeof(fd_slot_delta_parser_t) );
302 0 : void * slot_pool_mem = FD_SCRATCH_ALLOC_APPEND( l, slot_pool_align(), slot_pool_footprint( FD_SLOT_DELTA_MAX_ENTRIES ) );
303 0 : void * slot_set_mem = FD_SCRATCH_ALLOC_APPEND( l, slot_set_align(), slot_set_footprint( FD_SLOT_DELTA_PARSER_SLOT_SET_MAX_ENTRIES ) );
304 0 : FD_TEST( FD_SCRATCH_ALLOC_FINI( l, fd_slot_delta_parser_align() ) == (ulong)shmem + fd_slot_delta_parser_footprint() );
305 :
306 0 : parser->slot_pool = slot_pool_join( slot_pool_new( slot_pool_mem, FD_SLOT_DELTA_MAX_ENTRIES ) );
307 0 : FD_TEST( parser->slot_pool );
308 :
309 0 : parser->slot_set = slot_set_join( slot_set_new( slot_set_mem, FD_SLOT_DELTA_PARSER_SLOT_SET_MAX_ENTRIES, 1UL ) );
310 0 : FD_TEST( parser->slot_set );
311 :
312 0 : for( ulong i=0UL; i<slot_pool_max( parser->slot_pool ); i++ ) {
313 0 : fd_slot_entry_t * slot_entry = &parser->slot_pool[ i ];
314 0 : slot_entry->slot = ULONG_MAX;
315 0 : }
316 :
317 0 : parser->entry_avail = 0;
318 0 : parser->group_avail = 0;
319 0 : parser->slot_avail = 0;
320 0 : parser->slot_pool_ele_cnt = 0UL;
321 0 : parser->state = STATE_DONE;
322 :
323 0 : return parser;
324 0 : }
325 :
326 : fd_slot_delta_parser_t *
327 0 : fd_slot_delta_parser_join( void * shmem ) {
328 0 : return shmem;
329 0 : }
330 :
331 : void *
332 0 : fd_slot_delta_parser_leave( fd_slot_delta_parser_t * parser ) {
333 0 : return (void *)parser;
334 0 : }
335 :
336 : void *
337 0 : fd_slot_delta_parser_delete( void * shmem ) {
338 0 : return shmem;
339 0 : }
340 :
341 : void
342 0 : fd_slot_delta_parser_init( fd_slot_delta_parser_t * parser ) {
343 0 : parser->state = STATE_SLOT_DELTAS_LEN;
344 0 : parser->len = 0UL;
345 0 : parser->is_root = 0;
346 :
347 0 : parser->slot_delta_status_len = 0UL;
348 0 : parser->cache_status_len = 0UL;
349 0 : parser->borsh_io_error_len = 0UL;
350 0 : parser->error_discriminant = 0U;
351 :
352 0 : for( ulong i=0UL; i<parser->slot_pool_ele_cnt; i++ ) {
353 0 : fd_slot_entry_t * slot_entry = &parser->slot_pool[ i ];
354 0 : slot_set_ele_remove_fast( parser->slot_set, slot_entry, parser->slot_pool );
355 0 : slot_entry->slot = ULONG_MAX;
356 0 : }
357 :
358 0 : parser->slot_pool_ele_cnt = 0UL;
359 :
360 0 : parser->dst = state_dst( parser );
361 0 : parser->dst_sz = state_size( parser );
362 0 : parser->dst_cur = 0UL;
363 :
364 0 : parser->entry_avail = 0;
365 0 : parser->group_avail = 0;
366 0 : parser->slot_avail = 0;
367 0 : }
368 :
369 : int
370 : fd_slot_delta_parser_consume( fd_slot_delta_parser_t * parser,
371 : uchar const * buf,
372 : ulong bufsz,
373 0 : fd_slot_delta_parser_advance_result_t * result ) {
374 0 : uchar const * data = buf;
375 0 : ulong data_sz = bufsz;
376 0 : while( data_sz || parser->dst_cur==parser->dst_sz ) {
377 0 : if( FD_UNLIKELY( parser->state==STATE_DONE ) ) break;
378 :
379 0 : ulong consume = fd_ulong_min( data_sz, parser->dst_sz-parser->dst_cur );
380 :
381 0 : if( FD_LIKELY( parser->dst && consume ) ) {
382 0 : memcpy( parser->dst+parser->dst_cur, data, consume );
383 0 : }
384 :
385 0 : parser->dst_cur += consume;
386 0 : data += consume;
387 0 : data_sz -= consume;
388 :
389 : #if SLOT_DELTA_PARSER_DEBUG
390 : state_log( parser );
391 : #endif
392 :
393 0 : if( FD_LIKELY( parser->dst_cur==parser->dst_sz ) ) {
394 0 : int err = state_validate( parser );
395 0 : if( FD_UNLIKELY( err ) ) {
396 0 : result->bytes_consumed = (ulong)(data - buf);
397 0 : return err;
398 0 : }
399 :
400 0 : state_process( parser );
401 :
402 0 : parser->dst = state_dst( parser );
403 0 : parser->dst_sz = state_size( parser );
404 0 : parser->dst_cur = 0UL;
405 :
406 0 : if( FD_LIKELY( parser->slot_avail ) ) {
407 0 : FD_TEST( parser->entry_avail==0 );
408 0 : FD_TEST( parser->group_avail==0 );
409 0 : parser->slot_avail = 0;
410 0 : result->slot = parser->entry->slot;
411 0 : result->bytes_consumed = (ulong)(data - buf);
412 0 : return FD_SLOT_DELTA_PARSER_ADVANCE_SLOT;
413 0 : } else if( FD_LIKELY( parser->group_avail ) ) {
414 0 : FD_TEST( parser->entry_avail==0 );
415 0 : FD_TEST( parser->slot_avail==0 );
416 0 : parser->group_avail = 0;
417 0 : result->entry = NULL;
418 0 : result->group.blockhash = parser->entry->blockhash;
419 0 : result->group.txnhash_offset = parser->txnhash_offset;
420 0 : result->group.slot = parser->entry->slot;
421 0 : result->bytes_consumed = (ulong)(data - buf);
422 0 : return FD_SLOT_DELTA_PARSER_ADVANCE_GROUP;
423 0 : } else if( FD_LIKELY( parser->entry_avail ) ) {
424 0 : FD_TEST( parser->group_avail==0 );
425 0 : FD_TEST( parser->slot_avail==0 );
426 0 : parser->entry_avail = 0;
427 0 : result->entry = parser->entry;
428 0 : result->bytes_consumed = (ulong)(data - buf);
429 0 : return FD_SLOT_DELTA_PARSER_ADVANCE_ENTRY;
430 0 : }
431 0 : }
432 0 : }
433 :
434 0 : if( FD_UNLIKELY( data_sz ) ) {
435 0 : FD_LOG_WARNING(( "excess data in buffer" ));
436 0 : result->bytes_consumed = (ulong)(data - buf);
437 0 : return FD_SLOT_DELTA_PARSER_ADVANCE_ERROR_EXCESS_DATA_IN_BUFFER;
438 0 : }
439 :
440 0 : result->bytes_consumed = (ulong)(data - buf);
441 0 : if( FD_LIKELY( parser->state==STATE_DONE ) ) return FD_SLOT_DELTA_PARSER_ADVANCE_DONE;
442 :
443 0 : if( FD_UNLIKELY( !bufsz ) ) {
444 0 : FD_LOG_WARNING(( "unexpected end of data while parsing slot delta, state=%d, dst_cur=%lu, dst_sz=%lu",
445 0 : parser->state, parser->dst_cur, parser->dst_sz ));
446 0 : return FD_SLOT_DELTA_PARSER_ADVANCE_ERROR_UNEXPECTED_EOF;
447 0 : }
448 :
449 0 : return FD_SLOT_DELTA_PARSER_ADVANCE_AGAIN;
450 0 : }
451 :
452 : fd_slot_delta_slot_set_t
453 0 : fd_slot_delta_parser_slot_set( fd_slot_delta_parser_t * parser ) {
454 0 : return (fd_slot_delta_slot_set_t){
455 0 : .map = parser->slot_set,
456 0 : .pool = parser->slot_pool,
457 0 : .ele_cnt = parser->slot_pool_ele_cnt
458 0 : };
459 0 : }
|