5
5
6
6
#include "../../disco/topo/fd_topo.h"
7
7
#include "../../disco/metrics/fd_metrics.h"
8
+ #include "../../flamenco/gossip/fd_gossip_types.h"
8
9
9
10
#include <errno.h>
10
11
#include <fcntl.h>
39
40
40
41
#define SNAPRD_FILE_BUF_SZ (1024UL*1024UL) /* 1 MiB */
41
42
43
+ #define IN_KIND_SNAPCTL (0)
44
+ #define IN_KIND_GOSSIP (1)
45
+ #define MAX_IN_LINKS (3)
46
+
42
47
struct fd_snaprd_tile {
43
48
fd_ssping_t * ssping ;
44
49
fd_sshttp_t * sshttp ;
@@ -64,6 +69,15 @@ struct fd_snaprd_tile {
64
69
int incremental_snapshot_fd ;
65
70
} local_out ;
66
71
72
+ struct {
73
+ fd_wksp_t * mem ;
74
+ ulong chunk0 ;
75
+ ulong wmark ;
76
+ ulong mtu ;
77
+ } gossip_in ;
78
+
79
+ uchar in_kind [ MAX_IN_LINKS ];
80
+
67
81
struct {
68
82
ulong full_snapshot_slot ;
69
83
int full_snapshot_fd ;
@@ -98,6 +112,11 @@ struct fd_snaprd_tile {
98
112
} incremental ;
99
113
} metrics ;
100
114
115
+ struct {
116
+ fd_ip4_port_t * ci_table ;
117
+ fd_gossip_update_message_t tmp_upd_buf ;
118
+ } gossip ;
119
+
101
120
struct {
102
121
fd_wksp_t * wksp ;
103
122
ulong chunk0 ;
@@ -121,6 +140,7 @@ scratch_footprint( fd_topo_tile_t const * tile ) {
121
140
l = FD_LAYOUT_APPEND ( l , alignof(fd_snaprd_tile_t ), sizeof (fd_snaprd_tile_t ) );
122
141
l = FD_LAYOUT_APPEND ( l , fd_sshttp_align (), fd_sshttp_footprint () );
123
142
l = FD_LAYOUT_APPEND ( l , fd_ssping_align (), fd_ssping_footprint ( 65536UL ) );
143
+ l = FD_LAYOUT_APPEND ( l , alignof(fd_ip4_port_t ), sizeof (fd_ip4_port_t )* FD_CONTACT_INFO_TABLE_SIZE );
124
144
return FD_LAYOUT_FINI ( l , alignof(fd_snaprd_tile_t ) );
125
145
}
126
146
@@ -204,7 +224,7 @@ read_http_data( fd_snaprd_tile_t * ctx,
204
224
case FD_SSHTTP_ADVANCE_AGAIN : break ;
205
225
case FD_SSHTTP_ADVANCE_ERROR : {
206
226
FD_LOG_NOTICE (( "error downloading snapshot from http://" FD_IP4_ADDR_FMT ":%hu/snapshot.tar.bz2" ,
207
- FD_IP4_ADDR_FMT_ARGS ( ctx -> addr .addr ), ctx -> addr .port ));
227
+ FD_IP4_ADDR_FMT_ARGS ( ctx -> addr .addr ), fd_ushort_bswap ( ctx -> addr .port ) ));
208
228
fd_ssping_invalidate ( ctx -> ssping , ctx -> addr , now );
209
229
fd_stem_publish ( stem , 0UL , FD_SNAPSHOT_MSG_CTRL_RESET_FULL , 0UL , 0UL , 0UL , 0UL , 0UL );
210
230
ctx -> state = FD_SNAPRD_STATE_FLUSHING_FULL_HTTP_RESET ;
@@ -378,7 +398,7 @@ after_credit( fd_snaprd_tile_t * ctx,
378
398
FD_LOG_NOTICE (( "loading full snapshot from local file `%s`" , ctx -> local_in .full_snapshot_path ));
379
399
ctx -> state = FD_SNAPRD_STATE_READING_FULL_FILE ;
380
400
} else {
381
- FD_LOG_NOTICE (( "downloading full snapshot from http://" FD_IP4_ADDR_FMT ":%hu/snapshot.tar.bz2" , FD_IP4_ADDR_FMT_ARGS ( best .addr ), best .port ));
401
+ FD_LOG_NOTICE (( "downloading full snapshot from http://" FD_IP4_ADDR_FMT ":%hu/snapshot.tar.bz2" , FD_IP4_ADDR_FMT_ARGS ( best .addr ), fd_ushort_bswap ( best .port ) ));
382
402
ctx -> addr = best ;
383
403
ctx -> state = FD_SNAPRD_STATE_READING_FULL_HTTP ;
384
404
fd_sshttp_init ( ctx -> sshttp , best , "/snapshot.tar.bz2" , 17UL , now );
@@ -445,7 +465,7 @@ after_credit( fd_snaprd_tile_t * ctx,
445
465
break ;
446
466
}
447
467
448
- FD_LOG_NOTICE (( "downloading incremental snapshot from http://" FD_IP4_ADDR_FMT ":%hu/incremental-snapshot.tar.bz2" , FD_IP4_ADDR_FMT_ARGS ( ctx -> addr .addr ), ctx -> addr .port ));
468
+ FD_LOG_NOTICE (( "downloading incremental snapshot from http://" FD_IP4_ADDR_FMT ":%hu/incremental-snapshot.tar.bz2" , FD_IP4_ADDR_FMT_ARGS ( ctx -> addr .addr ), fd_ushort_bswap ( ctx -> addr .port ) ));
449
469
fd_sshttp_init ( ctx -> sshttp , ctx -> addr , "/incremental-snapshot.tar.bz2" , 29UL , fd_log_wallclock () );
450
470
ctx -> state = FD_SNAPRD_STATE_READING_INCREMENTAL_HTTP ;
451
471
break ;
@@ -474,6 +494,37 @@ after_credit( fd_snaprd_tile_t * ctx,
474
494
}
475
495
}
476
496
497
+ static int
498
+ before_frag ( fd_snaprd_tile_t * ctx FD_PARAM_UNUSED ,
499
+ ulong in_idx ,
500
+ ulong seq FD_PARAM_UNUSED ,
501
+ ulong sig ) {
502
+ if ( ctx -> in_kind [ in_idx ]== IN_KIND_GOSSIP ) {
503
+ return !( sig == FD_GOSSIP_UPDATE_TAG_CONTACT_INFO ||
504
+ sig == FD_GOSSIP_UPDATE_TAG_CONTACT_INFO_REMOVE ||
505
+ sig == FD_GOSSIP_UPDATE_TAG_SNAPSHOT_HASHES );
506
+ }
507
+ return 0 ;
508
+ }
509
+
510
+ static void
511
+ during_frag ( fd_snaprd_tile_t * ctx ,
512
+ ulong in_idx ,
513
+ ulong seq FD_PARAM_UNUSED ,
514
+ ulong sig FD_PARAM_UNUSED ,
515
+ ulong chunk ,
516
+ ulong sz ,
517
+ ulong ctl FD_PARAM_UNUSED ) {
518
+ if ( ctx -> in_kind [ in_idx ]!= IN_KIND_GOSSIP ) return ;
519
+
520
+ if ( FD_UNLIKELY ( chunk < ctx -> gossip_in .chunk0 ||
521
+ chunk > ctx -> gossip_in .wmark ||
522
+ sz > sizeof (fd_gossip_update_message_t ) ) ) {
523
+ FD_LOG_ERR (( "snaprd: unexpected chunk %lu" , chunk ));
524
+ }
525
+ fd_memcpy ( & ctx -> gossip .tmp_upd_buf , fd_chunk_to_laddr ( ctx -> gossip_in .mem , chunk ), sz );
526
+ }
527
+
477
528
static void
478
529
after_frag ( fd_snaprd_tile_t * ctx ,
479
530
ulong in_idx ,
@@ -489,50 +540,80 @@ after_frag( fd_snaprd_tile_t * ctx,
489
540
(void )tspub ;
490
541
(void )sz ;
491
542
492
- FD_TEST ( sig == FD_SNAPSHOT_MSG_CTRL_ACK || sig == FD_SNAPSHOT_MSG_CTRL_MALFORMED );
493
-
494
- if ( FD_LIKELY ( sig == FD_SNAPSHOT_MSG_CTRL_ACK ) ) ctx -> ack_cnt ++ ;
495
- else {
496
- FD_TEST ( ctx -> state != FD_SNAPRD_STATE_SHUTDOWN &&
497
- ctx -> state != FD_SNAPRD_STATE_COLLECTING_PEERS &&
498
- ctx -> state != FD_SNAPRD_STATE_WAITING_FOR_PEERS );
499
-
500
- switch ( ctx -> state ) {
501
- case FD_SNAPRD_STATE_READING_FULL_FILE :
502
- case FD_SNAPRD_STATE_FLUSHING_FULL_FILE :
503
- case FD_SNAPRD_STATE_FLUSHING_FULL_FILE_RESET :
504
- FD_LOG_ERR (( "error reading snapshot from local file `%s`" , ctx -> local_in .full_snapshot_path ));
505
- case FD_SNAPRD_STATE_READING_INCREMENTAL_FILE :
506
- case FD_SNAPRD_STATE_FLUSHING_INCREMENTAL_FILE :
507
- FD_LOG_ERR (( "error reading snapshot from local file `%s`" , ctx -> local_in .incremental_snapshot_path ));
508
- case FD_SNAPRD_STATE_READING_FULL_HTTP :
509
- case FD_SNAPRD_STATE_READING_INCREMENTAL_HTTP :
510
- FD_LOG_NOTICE (( "error downloading snapshot from http://" FD_IP4_ADDR_FMT ":%hu/snapshot.tar.bz2" ,
511
- FD_IP4_ADDR_FMT_ARGS ( ctx -> addr .addr ), ctx -> addr .port ));
512
- fd_sshttp_cancel ( ctx -> sshttp );
513
- fd_ssping_invalidate ( ctx -> ssping , ctx -> addr , fd_log_wallclock () );
514
- fd_stem_publish ( stem , 0UL , FD_SNAPSHOT_MSG_CTRL_RESET_FULL , 0UL , 0UL , 0UL , 0UL , 0UL );
515
- ctx -> state = FD_SNAPRD_STATE_FLUSHING_FULL_HTTP_RESET ;
516
- break ;
517
- case FD_SNAPRD_STATE_FLUSHING_FULL_HTTP :
518
- case FD_SNAPRD_STATE_FLUSHING_INCREMENTAL_HTTP :
519
- FD_LOG_NOTICE (( "error downloading snapshot from http://" FD_IP4_ADDR_FMT ":%hu/snapshot.tar.bz2" ,
520
- FD_IP4_ADDR_FMT_ARGS ( ctx -> addr .addr ), ctx -> addr .port ));
521
- fd_sshttp_cancel ( ctx -> sshttp );
522
- fd_ssping_invalidate ( ctx -> ssping , ctx -> addr , fd_log_wallclock () );
523
- /* We would like to transition to FULL_HTTP_RESET, but we can't
524
- do it just yet, because we have already sent a DONE control
525
- fragment, and need to wait for acknowledges to come back
526
- first, to ensure there's only one control message outstanding
527
- at a time. */
528
- ctx -> malformed = 1 ;
543
+ if ( FD_UNLIKELY ( ctx -> in_kind [ in_idx ]== IN_KIND_GOSSIP ) ) {
544
+ fd_gossip_update_message_t * msg = & ctx -> gossip .tmp_upd_buf ;
545
+ switch ( msg -> tag ) {
546
+ case FD_GOSSIP_UPDATE_TAG_CONTACT_INFO : {
547
+ fd_ip4_port_t cur_addr = ctx -> gossip .ci_table [ msg -> contact_info .idx ];
548
+ fd_ip4_port_t new_addr = msg -> contact_info .contact_info -> sockets [ FD_CONTACT_INFO_SOCKET_RPC ];
549
+ if ( FD_UNLIKELY ( cur_addr .l != new_addr .l ) ) {
550
+ if ( FD_LIKELY ( !!cur_addr .l ) ) fd_ssping_remove ( ctx -> ssping , cur_addr );
551
+ if ( FD_LIKELY ( !!new_addr .l ) ) {
552
+ FD_LOG_INFO (( "adding contact info for peer " FD_IP4_ADDR_FMT ":%hu " ,
553
+ FD_IP4_ADDR_FMT_ARGS ( new_addr .addr ), fd_ushort_bswap ( new_addr .port ) ));
554
+ fd_ssping_add ( ctx -> ssping , new_addr );
555
+ }
556
+ }
557
+ ctx -> gossip .ci_table [ msg -> contact_info .idx ] = new_addr ;
558
+ }
529
559
break ;
530
- case FD_SNAPRD_STATE_FLUSHING_FULL_HTTP_RESET :
560
+ case FD_GOSSIP_UPDATE_TAG_CONTACT_INFO_REMOVE : {
561
+ fd_ip4_port_t addr = ctx -> gossip .ci_table [ msg -> contact_info_remove .idx ];
562
+ if ( FD_LIKELY ( !!addr .l ) ) fd_ssping_remove ( ctx -> ssping , addr );
563
+ ctx -> gossip .ci_table [ msg -> contact_info_remove .idx ].l = 0UL ;
564
+ }
531
565
break ;
532
- default :
533
- FD_LOG_ERR (( "unexpected state %d" , ctx -> state ));
566
+ case FD_GOSSIP_UPDATE_TAG_SNAPSHOT_HASHES :
567
+ /* TODO */
534
568
break ;
535
569
}
570
+
571
+ } else {
572
+ FD_TEST ( sig == FD_SNAPSHOT_MSG_CTRL_ACK || sig == FD_SNAPSHOT_MSG_CTRL_MALFORMED );
573
+
574
+ if ( FD_LIKELY ( sig == FD_SNAPSHOT_MSG_CTRL_ACK ) ) ctx -> ack_cnt ++ ;
575
+ else {
576
+ FD_TEST ( ctx -> state != FD_SNAPRD_STATE_SHUTDOWN &&
577
+ ctx -> state != FD_SNAPRD_STATE_COLLECTING_PEERS &&
578
+ ctx -> state != FD_SNAPRD_STATE_WAITING_FOR_PEERS );
579
+
580
+ switch ( ctx -> state ) {
581
+ case FD_SNAPRD_STATE_READING_FULL_FILE :
582
+ case FD_SNAPRD_STATE_FLUSHING_FULL_FILE :
583
+ case FD_SNAPRD_STATE_FLUSHING_FULL_FILE_RESET :
584
+ FD_LOG_ERR (( "error reading snapshot from local file `%s`" , ctx -> local_in .full_snapshot_path ));
585
+ case FD_SNAPRD_STATE_READING_INCREMENTAL_FILE :
586
+ case FD_SNAPRD_STATE_FLUSHING_INCREMENTAL_FILE :
587
+ FD_LOG_ERR (( "error reading snapshot from local file `%s`" , ctx -> local_in .incremental_snapshot_path ));
588
+ case FD_SNAPRD_STATE_READING_FULL_HTTP :
589
+ case FD_SNAPRD_STATE_READING_INCREMENTAL_HTTP :
590
+ FD_LOG_NOTICE (( "error downloading snapshot from http://" FD_IP4_ADDR_FMT ":%hu/snapshot.tar.bz2" ,
591
+ FD_IP4_ADDR_FMT_ARGS ( ctx -> addr .addr ), fd_ushort_bswap ( ctx -> addr .port ) ));
592
+ fd_sshttp_cancel ( ctx -> sshttp );
593
+ fd_ssping_invalidate ( ctx -> ssping , ctx -> addr , fd_log_wallclock () );
594
+ fd_stem_publish ( stem , 0UL , FD_SNAPSHOT_MSG_CTRL_RESET_FULL , 0UL , 0UL , 0UL , 0UL , 0UL );
595
+ ctx -> state = FD_SNAPRD_STATE_FLUSHING_FULL_HTTP_RESET ;
596
+ break ;
597
+ case FD_SNAPRD_STATE_FLUSHING_FULL_HTTP :
598
+ case FD_SNAPRD_STATE_FLUSHING_INCREMENTAL_HTTP :
599
+ FD_LOG_NOTICE (( "error downloading snapshot from http://" FD_IP4_ADDR_FMT ":%hu/snapshot.tar.bz2" ,
600
+ FD_IP4_ADDR_FMT_ARGS ( ctx -> addr .addr ), fd_ushort_bswap ( ctx -> addr .port ) ));
601
+ fd_sshttp_cancel ( ctx -> sshttp );
602
+ fd_ssping_invalidate ( ctx -> ssping , ctx -> addr , fd_log_wallclock () );
603
+ /* We would like to transition to FULL_HTTP_RESET, but we can't
604
+ do it just yet, because we have already sent a DONE control
605
+ fragment, and need to wait for acknowledges to come back
606
+ first, to ensure there's only one control message outstanding
607
+ at a time. */
608
+ ctx -> malformed = 1 ;
609
+ break ;
610
+ case FD_SNAPRD_STATE_FLUSHING_FULL_HTTP_RESET :
611
+ break ;
612
+ default :
613
+ FD_LOG_ERR (( "unexpected state %d" , ctx -> state ));
614
+ break ;
615
+ }
616
+ }
536
617
}
537
618
}
538
619
@@ -619,9 +700,10 @@ unprivileged_init( fd_topo_t * topo,
619
700
void * scratch = fd_topo_obj_laddr ( topo , tile -> tile_obj_id );
620
701
621
702
FD_SCRATCH_ALLOC_INIT ( l , scratch );
622
- fd_snaprd_tile_t * ctx = FD_SCRATCH_ALLOC_APPEND ( l , alignof(fd_snaprd_tile_t ), sizeof (fd_snaprd_tile_t ) );
623
- void * _sshttp = FD_SCRATCH_ALLOC_APPEND ( l , fd_sshttp_align (), fd_sshttp_footprint () );
624
- void * _ssping = FD_SCRATCH_ALLOC_APPEND ( l , fd_ssping_align (), fd_ssping_footprint ( 65536UL ) );
703
+ fd_snaprd_tile_t * ctx = FD_SCRATCH_ALLOC_APPEND ( l , alignof(fd_snaprd_tile_t ), sizeof (fd_snaprd_tile_t ) );
704
+ void * _sshttp = FD_SCRATCH_ALLOC_APPEND ( l , fd_sshttp_align (), fd_sshttp_footprint () );
705
+ void * _ssping = FD_SCRATCH_ALLOC_APPEND ( l , fd_ssping_align (), fd_ssping_footprint ( 65536UL ) );
706
+ void * _ci_table = FD_SCRATCH_ALLOC_APPEND ( l , alignof(fd_ip4_port_t ), sizeof (fd_ip4_port_t )* FD_CONTACT_INFO_TABLE_SIZE );
625
707
626
708
ctx -> ack_cnt = 0UL ;
627
709
ctx -> malformed = 0 ;
@@ -646,27 +728,50 @@ unprivileged_init( fd_topo_t * topo,
646
728
ctx -> sshttp = fd_sshttp_join ( fd_sshttp_new ( _sshttp ) );
647
729
FD_TEST ( ctx -> sshttp );
648
730
649
- if ( FD_LIKELY ( !strcmp ( tile -> snaprd .cluster , "testnet" ) ) ) {
650
- fd_ip4_port_t initial_peers [ 2UL ] = {
651
- { .addr = FD_IP4_ADDR ( 35 , 214 , 172 , 227 ), .port = 8899 },
652
- { .addr = FD_IP4_ADDR ( 145 , 40 , 95 , 69 ), .port = 8899 }, /* Solana testnet peer */
653
- };
654
- for ( ulong i = 0UL ; i < 2UL ; i ++ ) fd_ssping_add ( ctx -> ssping , initial_peers [ i ] );
655
- } else if ( FD_LIKELY ( !strcmp ( tile -> snaprd .cluster , "private" ) ) ) {
656
- fd_ip4_port_t initial_peers [ 1UL ] = {
657
- { .addr = FD_IP4_ADDR ( 147 , 28 , 185 , 47 ), .port = 8899 } /* A private cluster peer */
658
- };
659
- for ( ulong i = 0UL ; i < 1UL ; i ++ ) fd_ssping_add ( ctx -> ssping , initial_peers [ i ] );
660
- } else if (FD_LIKELY ( !strcmp ( tile -> snaprd .cluster , "mainnet" ) ) ) {
731
+ ctx -> gossip .ci_table = _ci_table ;
732
+ /* zero-out memory so that we can perform null checks in after_frag */
733
+ fd_memset ( ctx -> gossip .ci_table , 0 , sizeof (fd_ip4_port_t )* FD_CONTACT_INFO_TABLE_SIZE );
734
+
735
+ FD_TEST ( tile -> in_cnt <=MAX_IN_LINKS );
736
+ uchar has_gossip_in = 0 ;
737
+ for ( ulong i = 0UL ; i < (tile -> in_cnt ); i ++ ){
738
+ fd_topo_link_t * in_link = & topo -> links [ tile -> in_link_id [ i ] ];
739
+ if ( 0 == strcmp ( in_link -> name , "gossip_out" ) ) {
740
+ has_gossip_in = 1 ;
741
+ ctx -> in_kind [ i ] = IN_KIND_GOSSIP ;
742
+ ctx -> gossip_in .mem = topo -> workspaces [ topo -> objs [ in_link -> dcache_obj_id ].wksp_id ].wksp ;
743
+ ctx -> gossip_in .chunk0 = fd_dcache_compact_chunk0 ( ctx -> gossip_in .mem , in_link -> dcache );
744
+ ctx -> gossip_in .wmark = fd_dcache_compact_wmark ( ctx -> gossip_in .mem , in_link -> dcache , in_link -> mtu );
745
+ ctx -> gossip_in .mtu = in_link -> mtu ;
746
+ } else if ( 0 == strcmp ( in_link -> name , "snapdc_rd" ) ||
747
+ 0 == strcmp ( in_link -> name , "snapin_rd" ) ) {
748
+ ctx -> in_kind [ i ] = IN_KIND_SNAPCTL ;
749
+ }
750
+ }
751
+
752
+ if ( FD_UNLIKELY ( !has_gossip_in ) ) {
753
+ FD_LOG_NOTICE (( "no gossip input link found, using initial peers for %s" , tile -> snaprd .cluster ));
754
+ if ( FD_LIKELY ( !strcmp ( tile -> snaprd .cluster , "testnet" ) ) ) {
755
+ fd_ip4_port_t initial_peers [ 2UL ] = {
756
+ { .addr = FD_IP4_ADDR ( 35 , 214 , 172 , 227 ), .port = fd_ushort_bswap (8899 ) },
757
+ { .addr = FD_IP4_ADDR ( 145 , 40 , 95 , 69 ), .port = fd_ushort_bswap (8899 ) }, /* Solana testnet peer */
758
+ };
759
+ for ( ulong i = 0UL ; i < 2UL ; i ++ ) fd_ssping_add ( ctx -> ssping , initial_peers [ i ] );
760
+ } else if ( FD_LIKELY ( !strcmp ( tile -> snaprd .cluster , "private" ) ) ) {
761
+ fd_ip4_port_t initial_peers [ 1UL ] = {
762
+ { .addr = FD_IP4_ADDR ( 147 , 28 , 185 , 47 ), .port = fd_ushort_bswap ( 8899 ) } /* A private cluster peer */
763
+ };
764
+ for ( ulong i = 0UL ; i < 1UL ; i ++ ) fd_ssping_add ( ctx -> ssping , initial_peers [ i ] );
765
+ } else if (FD_LIKELY ( !strcmp ( tile -> snaprd .cluster , "mainnet" ) ) ) {
661
766
fd_ip4_port_t initial_peers [ 3UL ] = {
662
- { .addr = FD_IP4_ADDR ( 149 , 255 , 37 , 130 ), .port = 8899 },
663
- { .addr = FD_IP4_ADDR ( 34 , 1 , 238 , 227 ), .port = 8899 },
664
- { .addr = FD_IP4_ADDR ( 34 , 1 , 139 , 131 ), .port = 8899 }
767
+ { .addr = FD_IP4_ADDR ( 149 , 255 , 37 , 130 ), .port = fd_ushort_bswap ( 8899 ) },
768
+ { .addr = FD_IP4_ADDR ( 34 , 1 , 238 , 227 ), .port = fd_ushort_bswap ( 8899 ) },
769
+ { .addr = FD_IP4_ADDR ( 34 , 1 , 139 , 131 ), .port = fd_ushort_bswap ( 8899 ) }
665
770
};
666
771
for ( ulong i = 0UL ; i < 3UL ; i ++ ) fd_ssping_add ( ctx -> ssping , initial_peers [ i ] );
667
- }
668
- else {
669
- FD_LOG_ERR (( "unexpected cluster %s" , tile -> snaprd . cluster ));
772
+ } else {
773
+ FD_LOG_ERR (( "unexpected cluster %s" , tile -> snaprd . cluster ));
774
+ }
670
775
}
671
776
672
777
if ( FD_UNLIKELY ( tile -> out_cnt != 1UL ) ) FD_LOG_ERR (( "tile `" NAME "` has %lu outs, expected 1" , tile -> out_cnt ));
@@ -687,6 +792,8 @@ unprivileged_init( fd_topo_t * topo,
687
792
#define STEM_CALLBACK_SHOULD_SHUTDOWN should_shutdown
688
793
#define STEM_CALLBACK_METRICS_WRITE metrics_write
689
794
#define STEM_CALLBACK_AFTER_CREDIT after_credit
795
+ #define STEM_CALLBACK_BEFORE_FRAG before_frag
796
+ #define STEM_CALLBACK_DURING_FRAG during_frag
690
797
#define STEM_CALLBACK_AFTER_FRAG after_frag
691
798
692
799
#include "../../disco/stem/fd_stem.c"
0 commit comments