Line data Source code
1 : #include "fd_rpc_history.h"
2 : #include <unistd.h>
3 : #include <fcntl.h>
4 :
5 : #include "../../ballet/block/fd_microblock.h"
6 : #include "../../flamenco/runtime/fd_system_ids.h"
7 :
8 : #include <string.h>
9 :
10 : struct fd_rpc_block {
11 : ulong slot;
12 : ulong next;
13 : fd_replay_slot_completed_t info;
14 : ulong file_offset;
15 : ulong file_size;
16 : };
17 :
18 : typedef struct fd_rpc_block fd_rpc_block_t;
19 :
20 : #define MAP_NAME fd_rpc_block_map
21 0 : #define MAP_T fd_rpc_block_t
22 : #define MAP_KEY_T ulong
23 0 : #define MAP_KEY slot
24 0 : #define MAP_KEY_EQ(k0,k1) ((*k0)==(*k1))
25 0 : #define MAP_KEY_HASH(key,seed) fd_ulong_hash(*key ^ seed)
26 : #include "../../util/tmpl/fd_map_giant.c"
27 :
28 : struct fd_rpc_txn {
29 : fd_rpc_txn_key_t sig;
30 : ulong next;
31 : ulong slot;
32 : ulong file_offset;
33 : ulong file_size;
34 : struct fd_rpc_txn * next_lru;
35 : };
36 : typedef struct fd_rpc_txn fd_rpc_txn_t;
37 :
38 : FD_FN_PURE int
39 0 : fd_rpc_txn_key_equal( fd_rpc_txn_key_t const * k0, fd_rpc_txn_key_t const * k1 ) {
40 0 : for( ulong i = 0; i < FD_ED25519_SIG_SZ / sizeof( ulong ); ++i )
41 0 : if( k0->v[i] != k1->v[i] ) return 0;
42 0 : return 1;
43 0 : }
44 :
45 : FD_FN_PURE ulong
46 0 : fd_rpc_txn_key_hash( fd_rpc_txn_key_t const * k, ulong seed ) {
47 0 : ulong h = seed;
48 0 : for( ulong i = 0; i < FD_ED25519_SIG_SZ / sizeof( ulong ); ++i )
49 0 : h ^= k->v[i];
50 0 : return h;
51 0 : }
52 :
53 : #define MAP_NAME fd_rpc_txn_map
54 0 : #define MAP_T fd_rpc_txn_t
55 0 : #define MAP_KEY sig
56 : #define MAP_KEY_T fd_rpc_txn_key_t
57 0 : #define MAP_KEY_EQ(k0,k1) fd_rpc_txn_key_equal(k0,k1)
58 0 : #define MAP_KEY_HASH(key,seed) fd_rpc_txn_key_hash(key,seed)
59 : #include "../../util/tmpl/fd_map_giant.c"
60 :
61 : struct fd_rpc_acct_map_elem {
62 : fd_pubkey_t key;
63 : ulong next;
64 : ulong slot;
65 : fd_rpc_txn_key_t sig; /* Transaction signature */
66 : struct fd_rpc_acct_map_elem * next_lru;
67 : };
68 : typedef struct fd_rpc_acct_map_elem fd_rpc_acct_map_elem_t;
69 : #define MAP_NAME fd_rpc_acct_map
70 : #define MAP_KEY_T fd_pubkey_t
71 0 : #define MAP_ELE_T fd_rpc_acct_map_elem_t
72 0 : #define MAP_KEY_HASH(key,seed) fd_hash( seed, key, sizeof(fd_pubkey_t) )
73 0 : #define MAP_KEY_EQ(k0,k1) fd_pubkey_eq( k0, k1 )
74 : #define MAP_MULTI 1
75 : #include "../../util/tmpl/fd_map_chain.c"
76 : #define POOL_NAME fd_rpc_acct_map_pool
77 0 : #define POOL_T fd_rpc_acct_map_elem_t
78 : #include "../../util/tmpl/fd_pool.c"
79 :
80 0 : #define FD_REASM_MAP_COL_CNT (1UL<<10)
81 : #define FD_REASM_MAP_COL_HEIGHT (128UL)
82 : struct fd_rpc_reasm_map {
83 : struct fd_rpc_reasm_map_column {
84 : ulong ele_cnt; /* The number of shreds received in this column */ uchar end_found; /* Whether the last slice of the slot has been found */
85 : fd_reasm_fec_t ele[FD_REASM_MAP_COL_HEIGHT];
86 : } cols[FD_REASM_MAP_COL_CNT];
87 : ulong head; /* Next open column */
88 : ulong tail; /* Oldest column */
89 : };
90 : typedef struct fd_rpc_reasm_map fd_rpc_reasm_map_t;
91 :
92 : struct fd_rpc_history {
93 : fd_spad_t * spad;
94 : fd_rpc_block_t * block_map;
95 : ulong block_cnt;
96 : fd_rpc_txn_t * txn_map;
97 : fd_rpc_txn_t * txn_oldest_lru;
98 : fd_rpc_txn_t * txn_newest_lru;
99 : fd_rpc_acct_map_t * acct_map;
100 : fd_rpc_acct_map_elem_t * acct_pool;
101 : fd_rpc_acct_map_elem_t * acct_oldest_lru;
102 : fd_rpc_acct_map_elem_t * acct_newest_lru;
103 : fd_rpc_reasm_map_t * reasm_map;
104 : ulong first_slot;
105 : ulong latest_slot;
106 : int file_fd;
107 : ulong file_totsz;
108 : int include_votes;
109 : };
110 :
111 : fd_rpc_history_t *
112 0 : fd_rpc_history_create(fd_rpcserver_args_t * args) {
113 0 : fd_spad_t * spad = args->spad;
114 0 : fd_rpc_history_t * hist = (fd_rpc_history_t *)fd_spad_alloc( spad, alignof(fd_rpc_history_t), sizeof(fd_rpc_history_t) );
115 0 : memset(hist, 0, sizeof(fd_rpc_history_t));
116 0 : hist->spad = spad;
117 :
118 0 : hist->first_slot = ULONG_MAX;
119 0 : hist->latest_slot = 0;
120 :
121 0 : hist->block_map = fd_rpc_block_map_join( fd_rpc_block_map_new( fd_spad_alloc( spad, fd_rpc_block_map_align(), fd_rpc_block_map_footprint(args->block_index_max) ), args->block_index_max, 0 ) );
122 :
123 0 : hist->txn_map = fd_rpc_txn_map_join( fd_rpc_txn_map_new( fd_spad_alloc( spad, fd_rpc_txn_map_align(), fd_rpc_txn_map_footprint(args->txn_index_max) ), args->txn_index_max, 0 ) );
124 :
125 0 : void * mem = fd_spad_alloc( spad, fd_rpc_acct_map_align(), fd_rpc_acct_map_footprint( args->acct_index_max/2 ) );
126 0 : hist->acct_map = fd_rpc_acct_map_join( fd_rpc_acct_map_new( mem, args->acct_index_max/2, 0 ) );
127 0 : mem = fd_spad_alloc( spad, fd_rpc_acct_map_pool_align(), fd_rpc_acct_map_pool_footprint( args->acct_index_max ) );
128 0 : hist->acct_pool = fd_rpc_acct_map_pool_join( fd_rpc_acct_map_pool_new( mem, args->acct_index_max ) );
129 :
130 0 : mem = fd_spad_alloc( spad, alignof(fd_rpc_reasm_map_t), sizeof(fd_rpc_reasm_map_t) );
131 0 : memset(mem, 0, sizeof(fd_rpc_reasm_map_t));
132 0 : hist->reasm_map = (fd_rpc_reasm_map_t *)mem;
133 :
134 0 : hist->file_fd = open( args->history_file, O_CREAT | O_RDWR | O_TRUNC, 0644 );
135 0 : if( hist->file_fd == -1 ) FD_LOG_ERR(( "unable to open rpc history file: %s", args->history_file ));
136 0 : hist->file_totsz = 0;
137 :
138 0 : hist->include_votes = args->include_votes;
139 :
140 0 : return hist;
141 0 : }
142 :
143 : static fd_rpc_block_t *
144 0 : fd_rpc_history_alloc_block(fd_rpc_history_t * hist, ulong slot) {
145 0 : fd_rpc_block_t * blk = fd_rpc_block_map_query(hist->block_map, &slot, NULL);
146 0 : if( blk ) return blk;
147 0 : if( fd_rpc_block_map_is_full( hist->block_map ) ) return NULL; /* Out of space */
148 0 : blk = fd_rpc_block_map_insert( hist->block_map, &slot );
149 0 : if( blk == NULL ) {
150 0 : FD_LOG_ERR(( "unable to save slot %lu block", slot ));
151 0 : return NULL;
152 0 : }
153 0 : blk->slot = slot;
154 0 : blk->file_offset = 0UL;
155 0 : blk->file_size = 0UL;
156 0 : memset( &blk->info, 0, sizeof(fd_replay_slot_completed_t) );
157 0 : blk->info.slot = slot;
158 0 : if( hist->first_slot == ULONG_MAX ) {
159 0 : hist->first_slot = hist->latest_slot = slot;
160 0 : } else {
161 0 : if( slot < hist->first_slot ) hist->first_slot = slot;
162 0 : else if( slot > hist->latest_slot ) hist->latest_slot = slot;
163 0 : }
164 0 : hist->block_cnt++;
165 0 : return blk;
166 0 : }
167 :
168 : void
169 0 : fd_rpc_history_debug(fd_rpc_history_t * hist) {
170 0 : fd_rpc_reasm_map_t * reasm_map = hist->reasm_map;
171 0 : ulong tot_cnt = 0;
172 0 : for( ulong slot = reasm_map->tail; slot < reasm_map->head; slot++ ) {
173 0 : ulong col_idx = slot & (FD_REASM_MAP_COL_CNT - 1);
174 0 : struct fd_rpc_reasm_map_column * col = &reasm_map->cols[col_idx];
175 0 : FD_LOG_NOTICE(( "slot %lu: %lu fecs", slot, col->ele_cnt ));
176 0 : tot_cnt += col->ele_cnt;
177 0 : }
178 0 : FD_LOG_NOTICE(( "%lu head, %lu tail, %lu total fecs, %lu total blocks",
179 0 : reasm_map->head, reasm_map->tail, tot_cnt, reasm_map->head - reasm_map->tail ));
180 0 : }
181 :
182 : void
183 0 : fd_rpc_history_save_info(fd_rpc_history_t * hist, fd_replay_slot_completed_t * info) {
184 0 : fd_rpc_block_t * blk = fd_rpc_history_alloc_block( hist, info->slot );
185 0 : if( blk == NULL ) return;
186 0 : blk->info = *info;
187 0 : }
188 :
189 : static ulong
190 0 : fd_rpc_history_scan_block(fd_rpc_history_t * hist, ulong slot, ulong file_offset, uchar * blk_data, ulong blk_sz) {
191 0 : ulong blockoff = 0;
192 0 : ulong ret = 0;
193 0 : while (blockoff < blk_sz) {
194 0 : if ( blockoff + sizeof(ulong) > blk_sz )
195 0 : return ret;
196 0 : ulong mcount = *(const ulong *)(blk_data + blockoff);
197 0 : blockoff += sizeof(ulong);
198 :
199 : /* Loop across microblocks */
200 0 : for (ulong mblk = 0; mblk < mcount; ++mblk) {
201 0 : if ( blockoff + sizeof(fd_microblock_hdr_t) > blk_sz ) {
202 0 : FD_LOG_ERR(("premature end of block"));
203 0 : return ret;
204 0 : }
205 0 : fd_microblock_hdr_t * hdr = (fd_microblock_hdr_t *)((const uchar *)blk_data + blockoff);
206 0 : blockoff += sizeof(fd_microblock_hdr_t);
207 :
208 : /* Loop across transactions */
209 0 : for ( ulong txn_idx = 0; txn_idx < hdr->txn_cnt; txn_idx++ ) {
210 0 : uchar txn_out[FD_TXN_MAX_SZ];
211 0 : ulong pay_sz = 0;
212 0 : const uchar* raw = (const uchar *)blk_data + blockoff;
213 0 : ulong txn_sz = fd_txn_parse_core(raw, fd_ulong_min(blk_sz - blockoff, FD_TXN_MTU), txn_out, NULL, &pay_sz);
214 0 : if ( txn_sz == 0 || txn_sz > FD_TXN_MAX_SZ ) {
215 0 : FD_LOG_ERR( ( "failed to parse transaction %lu in microblock %lu (%lu) at offset %lu", txn_idx, mblk, ret,blockoff ) );
216 0 : return ret;
217 0 : }
218 0 : fd_txn_t * txn = (fd_txn_t *)txn_out;
219 :
220 0 : fd_pubkey_t * accs = (fd_pubkey_t *)((uchar *)raw + txn->acct_addr_off);
221 0 : if( !hist->include_votes ) {
222 0 : int skip_txn = 0;
223 0 : for( ulong i = 0UL; i < txn->acct_addr_cnt; i++ ) {
224 0 : if( !memcmp(&accs[i], fd_solana_vote_program_id.key, sizeof(fd_pubkey_t)) ) {
225 0 : skip_txn = 1;
226 0 : break;
227 0 : }
228 0 : }
229 0 : if( skip_txn ) {
230 0 : blockoff += pay_sz;
231 0 : continue;
232 0 : }
233 0 : }
234 :
235 : /* Loop across signatures */
236 0 : fd_ed25519_sig_t const * sigs = (fd_ed25519_sig_t const *)(raw + txn->signature_off);
237 0 : for ( uchar j = 0; j < txn->signature_cnt; j++ ) {
238 0 : while( fd_rpc_txn_map_is_full( hist->txn_map ) ) {
239 : /* Remove the oldest entry from the map */
240 0 : fd_rpc_txn_t * ent = hist->txn_oldest_lru;
241 0 : hist->txn_oldest_lru = ent->next_lru;
242 0 : fd_rpc_txn_map_remove( hist->txn_map, &ent->sig );
243 0 : }
244 :
245 : /* Insert the new entry into the map */
246 0 : fd_rpc_txn_key_t key;
247 0 : memcpy(&key, (const uchar*)&sigs[j], sizeof(key));
248 0 : fd_rpc_txn_t * ent = fd_rpc_txn_map_insert( hist->txn_map, &key );
249 0 : ent->file_offset = file_offset + blockoff;
250 0 : ent->file_size = pay_sz;
251 0 : ent->slot = slot;
252 :
253 : /* Update the LRU chain*/
254 0 : ent->next_lru = NULL;
255 0 : if( hist->txn_newest_lru ) {
256 0 : hist->txn_newest_lru->next_lru = ent;
257 0 : hist->txn_newest_lru = ent;
258 0 : } else {
259 0 : hist->txn_newest_lru = ent;
260 0 : hist->txn_oldest_lru = ent;
261 0 : }
262 0 : }
263 :
264 : /* Loop across accounts */
265 0 : fd_rpc_txn_key_t sig0;
266 0 : memcpy(&sig0, (const uchar*)sigs, sizeof(sig0));
267 0 : for( ulong i = 0UL; i < txn->acct_addr_cnt; i++ ) {
268 0 : if( !memcmp(&accs[i], fd_solana_vote_program_id.key, sizeof(fd_pubkey_t)) ) continue; /* Ignore votes */
269 :
270 0 : while( !fd_rpc_acct_map_pool_free( hist->acct_pool ) ) {
271 : /* Remove the oldest entry from the map */
272 0 : fd_rpc_acct_map_elem_t * ent = hist->acct_oldest_lru;
273 0 : hist->acct_oldest_lru = ent->next_lru;
274 0 : ent = fd_rpc_acct_map_ele_remove( hist->acct_map, &ent->key, NULL, hist->acct_pool );
275 0 : if( ent ) fd_rpc_acct_map_pool_ele_release( hist->acct_pool, ent );
276 0 : }
277 :
278 : /* Insert the new entry into the map */
279 0 : fd_rpc_acct_map_elem_t * ele = fd_rpc_acct_map_pool_ele_acquire( hist->acct_pool );
280 0 : ele->key = accs[i];
281 0 : ele->slot = slot;
282 0 : ele->sig = sig0;
283 0 : fd_rpc_acct_map_ele_insert( hist->acct_map, ele, hist->acct_pool );
284 :
285 : /* Update the LRU chain */
286 0 : ele->next_lru = NULL;
287 0 : if( hist->acct_newest_lru ) {
288 0 : hist->acct_newest_lru->next_lru = ele;
289 0 : hist->acct_newest_lru = ele;
290 0 : } else {
291 0 : hist->acct_newest_lru = ele;
292 0 : hist->acct_oldest_lru = ele;
293 0 : }
294 0 : }
295 :
296 0 : blockoff += pay_sz;
297 0 : }
298 0 : }
299 0 : ret = blockoff;
300 0 : }
301 0 : return ret;
302 0 : }
303 :
304 : void
305 0 : fd_rpc_history_process_column(fd_rpc_history_t * hist, struct fd_rpc_reasm_map_column * col, fd_store_t * store, fd_reasm_fec_t * fec) {
306 0 : ulong slot = fec->slot;
307 :
308 : /* Get a block from the map */
309 0 : fd_rpc_block_t * blk = fd_rpc_history_alloc_block( hist, slot );
310 0 : if( blk == NULL ) return;
311 0 : ulong file_offset = blk->file_offset = hist->file_totsz;
312 0 : blk->file_size = 0;
313 :
314 : /* Look up all the store_fec_t elements for this column */
315 0 : fd_store_fec_t * list[FD_REASM_MAP_COL_HEIGHT];
316 0 : for( ulong idx = 0; idx < col->ele_cnt; ) {
317 0 : ulong end_idx = ULONG_MAX;
318 0 : FD_SPAD_FRAME_BEGIN( hist->spad ) {
319 : /* Query the next batch */
320 0 : fd_store_shacq( store );
321 0 : ulong batch_sz = 0;
322 0 : for( ulong i = idx; i < col->ele_cnt; i++ ) {
323 0 : fd_reasm_fec_t * ele = &col->ele[i];
324 0 : fd_store_fec_t * fec_p = list[i-idx] = fd_store_query( store, &ele->key );
325 0 : if( !fec_p ) {
326 0 : fd_store_shrel( store );
327 0 : FD_LOG_WARNING(( "missing fec when assembling block %lu", slot ));
328 0 : return;
329 0 : }
330 0 : batch_sz += fec_p->data_sz;
331 0 : if( col->ele[i].data_complete ) {
332 0 : end_idx = i;
333 0 : break;
334 0 : }
335 0 : }
336 0 : if( end_idx == ULONG_MAX ) {
337 0 : fd_store_shrel( store );
338 0 : FD_LOG_ERR(( "missing data complete flag" ));
339 0 : return;
340 0 : }
341 0 : uchar * blk_data = fd_spad_alloc( hist->spad, alignof(ulong), batch_sz );
342 0 : ulong batch_off = 0;
343 0 : for( ulong i = idx; i <= end_idx; i++ ) {
344 0 : fd_store_fec_t * fec_p = list[i-idx];
345 0 : fd_memcpy( blk_data + batch_off, fec_p->data, fec_p->data_sz );
346 0 : batch_off += fec_p->data_sz;
347 0 : }
348 0 : FD_TEST( batch_off == batch_sz );
349 0 : fd_store_shrel( store );
350 : /* Scan the block. Trim the padding. */
351 0 : batch_sz = fd_rpc_history_scan_block( hist, slot, file_offset, blk_data, batch_sz );
352 : /* Write the trimmed batch to the file */
353 0 : if( pwrite( hist->file_fd, blk_data, batch_sz, (long)file_offset ) != (ssize_t)batch_sz ) {
354 0 : FD_LOG_ERR(( "unable to write to rpc history file" ));
355 0 : return;
356 0 : }
357 0 : file_offset += batch_sz;
358 0 : blk->file_size += batch_sz;
359 0 : hist->file_totsz = file_offset;
360 0 : } FD_SPAD_FRAME_END;
361 0 : idx = end_idx + 1;
362 0 : }
363 :
364 0 : FD_LOG_NOTICE(( "processed slot %lu", slot ));
365 0 : }
366 :
367 : static void
368 0 : fd_rpc_history_discard_column(fd_rpc_reasm_map_t * reasm_map, ulong slot) {
369 0 : ulong col_idx = slot & (FD_REASM_MAP_COL_CNT - 1);
370 0 : struct fd_rpc_reasm_map_column * col = &reasm_map->cols[col_idx];
371 0 : col->ele_cnt = 0;
372 0 : }
373 :
374 : void
375 0 : fd_rpc_history_save_fec(fd_rpc_history_t * hist, fd_store_t * store, fd_reasm_fec_t * fec_msg ) {
376 0 : fd_rpc_reasm_map_t * reasm_map = hist->reasm_map;
377 :
378 0 : if( reasm_map->head == 0UL ) {
379 0 : reasm_map->head = fec_msg->slot+1;
380 0 : reasm_map->tail = fec_msg->slot;
381 0 : }
382 0 : if( fec_msg->slot < reasm_map->tail ) return; /* Do not go backwards */
383 0 : while( fec_msg->slot >= reasm_map->tail + FD_REASM_MAP_COL_CNT ) {
384 0 : FD_TEST( reasm_map->tail < reasm_map->head );
385 0 : fd_rpc_history_discard_column( reasm_map, reasm_map->tail++ );
386 0 : }
387 0 : while( fec_msg->slot >= reasm_map->head ) {
388 0 : ulong col_idx = (reasm_map->head++) & (FD_REASM_MAP_COL_CNT - 1);
389 0 : struct fd_rpc_reasm_map_column * col = &reasm_map->cols[col_idx];
390 0 : col->ele_cnt = 0;
391 0 : }
392 0 : FD_TEST( fec_msg->slot >= reasm_map->tail && fec_msg->slot < reasm_map->head && reasm_map->head - reasm_map->tail <= FD_REASM_MAP_COL_CNT );
393 :
394 0 : ulong col_idx = fec_msg->slot & (FD_REASM_MAP_COL_CNT - 1);
395 0 : struct fd_rpc_reasm_map_column * col = &reasm_map->cols[col_idx];
396 :
397 0 : if( col->ele_cnt ) {
398 0 : FD_TEST( fec_msg->fec_set_idx > col->ele[col->ele_cnt-1].fec_set_idx );
399 0 : }
400 :
401 0 : FD_TEST( col->ele_cnt < FD_REASM_MAP_COL_HEIGHT );
402 :
403 0 : col->ele[col->ele_cnt++] = *fec_msg;
404 :
405 0 : if( fec_msg->slot_complete ) {
406 : /* We've received all the shreds for this slot. Process it. */
407 0 : fd_rpc_history_process_column( hist, col, store, fec_msg );
408 0 : fd_rpc_history_discard_column( reasm_map, fec_msg->slot );
409 0 : }
410 0 : }
411 :
412 : ulong
413 0 : fd_rpc_history_first_slot(fd_rpc_history_t * hist) {
414 0 : return hist->first_slot;
415 0 : }
416 :
417 : ulong
418 0 : fd_rpc_history_latest_slot(fd_rpc_history_t * hist) {
419 0 : return hist->latest_slot;
420 0 : }
421 :
422 : fd_replay_slot_completed_t *
423 0 : fd_rpc_history_get_block_info(fd_rpc_history_t * hist, ulong slot) {
424 0 : fd_rpc_block_t * blk = fd_rpc_block_map_query( hist->block_map, &slot, NULL );
425 0 : if( !blk ) {
426 0 : return NULL;
427 0 : }
428 0 : return &blk->info;
429 0 : }
430 :
431 : fd_replay_slot_completed_t *
432 0 : fd_rpc_history_get_block_info_by_hash(fd_rpc_history_t * hist, fd_hash_t * h) {
433 0 : for( fd_rpc_block_map_iter_t i = fd_rpc_block_map_iter_init( hist->block_map );
434 0 : !fd_rpc_block_map_iter_done( hist->block_map, i );
435 0 : i = fd_rpc_block_map_iter_next( hist->block_map, i ) ) {
436 0 : fd_rpc_block_t * ele = fd_rpc_block_map_iter_ele( hist->block_map, i );
437 0 : if( fd_hash_eq( &ele->info.block_hash, h ) ) return &ele->info;
438 0 : }
439 0 : return NULL;
440 0 : }
441 :
442 : uchar *
443 0 : fd_rpc_history_get_block(fd_rpc_history_t * hist, ulong slot, ulong * blk_sz) {
444 0 : fd_rpc_block_t * blk = fd_rpc_block_map_query( hist->block_map, &slot, NULL );
445 0 : if( !blk ) {
446 0 : *blk_sz = ULONG_MAX;
447 0 : return NULL;
448 0 : }
449 0 : uchar * blk_data = fd_spad_alloc( hist->spad, 1, blk->file_size );
450 0 : if( pread( hist->file_fd, blk_data, blk->file_size, (long)blk->file_offset ) != (ssize_t)blk->file_size ) {
451 0 : FD_LOG_ERR(( "unable to read rpc history file" ));
452 0 : *blk_sz = ULONG_MAX;
453 0 : return NULL;
454 0 : }
455 0 : *blk_sz = blk->file_size;
456 0 : return blk_data;
457 0 : }
458 :
459 : uchar *
460 0 : fd_rpc_history_get_txn(fd_rpc_history_t * hist, fd_rpc_txn_key_t * sig, ulong * txn_sz, ulong * slot) {
461 0 : fd_rpc_txn_t * txn = fd_rpc_txn_map_query( hist->txn_map, sig, NULL );
462 0 : if( !txn ) {
463 0 : *txn_sz = ULONG_MAX;
464 0 : return NULL;
465 0 : }
466 0 : uchar * txn_data = fd_spad_alloc( hist->spad, 1, txn->file_size );
467 0 : if( pread( hist->file_fd, txn_data, txn->file_size, (long)txn->file_offset ) != (ssize_t)txn->file_size ) {
468 0 : FD_LOG_ERR(( "unable to read rpc history file" ));
469 0 : *txn_sz = ULONG_MAX;
470 0 : return NULL;
471 0 : }
472 0 : *txn_sz = txn->file_size;
473 0 : *slot = txn->slot;
474 0 : return txn_data;
475 0 : }
476 :
477 : const void *
478 0 : fd_rpc_history_first_txn_for_acct(fd_rpc_history_t * hist, fd_pubkey_t * acct, fd_rpc_txn_key_t * sig, ulong * slot) {
479 0 : fd_rpc_acct_map_elem_t const * ele = fd_rpc_acct_map_ele_query_const( hist->acct_map, acct, NULL, hist->acct_pool );
480 0 : if( ele == NULL ) return NULL;
481 0 : *sig = ele->sig;
482 0 : *slot = ele->slot;
483 0 : return ele;
484 0 : }
485 :
486 : const void *
487 0 : fd_rpc_history_next_txn_for_acct(fd_rpc_history_t * hist, fd_rpc_txn_key_t * sig, ulong * slot, const void * iter) {
488 0 : fd_rpc_acct_map_elem_t const * ele = (fd_rpc_acct_map_elem_t const *)iter;
489 0 : ele = fd_rpc_acct_map_ele_next_const( ele, NULL, hist->acct_pool );
490 0 : if( ele == NULL ) return NULL;
491 0 : *sig = ele->sig;
492 0 : *slot = ele->slot;
493 0 : return ele;
494 0 : }
|