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