Line data Source code
1 : #define _GNU_SOURCE
2 :
3 : #include "../../disco/topo/fd_topo.h"
4 : #include "generated/fd_eqvoc_tile_seccomp.h"
5 :
6 : #include "../../choreo/fd_choreo.h"
7 :
8 : #include "../../disco/fd_disco.h"
9 : #include "../../disco/keyguard/fd_keyload.h"
10 : #include "../../disco/shred/fd_stake_ci.h"
11 :
12 : #define SCRATCH_MAX ( 4UL /*KiB*/ << 10 )
13 : #define SCRATCH_DEPTH ( 4UL ) /* 4 scratch frames */
14 :
15 :
16 : struct fd_eqvoc_tile_ctx {
17 : fd_pubkey_t identity_key[1];
18 :
19 : fd_stake_ci_t * stake_ci;
20 : fd_shred_dest_weighted_t * new_dest_ptr;
21 : ulong new_dest_cnt;
22 :
23 : ulong contact_in_idx;
24 : fd_wksp_t * contact_in_mem;
25 : ulong contact_in_chunk0;
26 : ulong contact_in_wmark;
27 :
28 : fd_gossip_duplicate_shred_t duplicate_shred;
29 : uchar duplicate_shred_chunk[FD_EQVOC_PROOF_CHUNK_MAX];
30 :
31 : ulong gossip_in_idx;
32 : fd_wksp_t * gossip_in_mem;
33 : ulong gossip_in_chunk0;
34 : ulong gossip_in_wmark;
35 :
36 : fd_shred_t shred;
37 :
38 : ulong shred_net_in_idx;
39 : fd_wksp_t * shred_net_in_mem;
40 : ulong shred_net_in_chunk0;
41 : ulong shred_net_in_wmark;
42 :
43 : ulong seed;
44 : fd_eqvoc_t * eqvoc;
45 : };
46 : typedef struct fd_eqvoc_tile_ctx fd_eqvoc_tile_ctx_t;
47 :
48 : FD_FN_CONST static inline ulong
49 0 : scratch_align( void ) {
50 0 : return 128UL;
51 0 : }
52 :
53 : FD_FN_PURE static inline ulong
54 0 : loose_footprint( fd_topo_tile_t const * tile FD_PARAM_UNUSED ) {
55 0 : return 0UL;
56 0 : }
57 :
58 : FD_FN_PURE static inline ulong
59 0 : scratch_footprint( fd_topo_tile_t const * tile FD_PARAM_UNUSED ) {
60 : /* clang-format off */
61 0 : ulong l = FD_LAYOUT_INIT;
62 0 : l = FD_LAYOUT_APPEND( l, alignof(fd_eqvoc_tile_ctx_t), sizeof(fd_eqvoc_tile_ctx_t) );
63 0 : l = FD_LAYOUT_APPEND( l, fd_stake_ci_align(), fd_stake_ci_footprint() );
64 0 : l = FD_LAYOUT_APPEND( l, fd_eqvoc_align(), fd_eqvoc_footprint( 1 << 10, 1 << 10 ) );
65 0 : return FD_LAYOUT_FINI( l, scratch_align() );
66 : /* clang-format on */
67 0 : }
68 :
69 : static inline void
70 0 : handle_new_cluster_contact_info( fd_eqvoc_tile_ctx_t * ctx, uchar const * buf, ulong buf_sz ) {
71 0 : ulong const * header = (ulong const *)fd_type_pun_const( buf );
72 :
73 0 : ulong dest_cnt = buf_sz;
74 :
75 0 : if( dest_cnt >= MAX_SHRED_DESTS )
76 0 : FD_LOG_ERR(( "Cluster nodes had %lu destinations, which was more than the max of %lu",
77 0 : dest_cnt,
78 0 : MAX_SHRED_DESTS ));
79 :
80 0 : fd_shred_dest_wire_t const * in_dests = fd_type_pun_const( header );
81 0 : fd_shred_dest_weighted_t * dests = fd_stake_ci_dest_add_init( ctx->stake_ci );
82 :
83 0 : ctx->new_dest_ptr = dests;
84 0 : ctx->new_dest_cnt = dest_cnt;
85 :
86 0 : for( ulong i = 0UL; i < dest_cnt; i++ ) {
87 0 : memcpy( dests[i].pubkey.uc, in_dests[i].pubkey, 32UL );
88 0 : dests[i].ip4 = in_dests[i].ip4_addr;
89 0 : dests[i].port = in_dests[i].udp_port;
90 0 : }
91 0 : }
92 :
93 : static inline void
94 0 : finalize_new_cluster_contact_info( fd_eqvoc_tile_ctx_t * ctx ) {
95 0 : fd_stake_ci_dest_add_fini( ctx->stake_ci, ctx->new_dest_cnt );
96 0 : }
97 :
98 : static void
99 : during_frag( fd_eqvoc_tile_ctx_t * ctx,
100 : ulong in_idx,
101 : ulong seq FD_PARAM_UNUSED,
102 : ulong sig,
103 : ulong chunk,
104 : ulong sz,
105 0 : ulong ctl FD_PARAM_UNUSED ) {
106 :
107 0 : if( FD_UNLIKELY( in_idx == ctx->contact_in_idx ) ) {
108 0 : if( FD_UNLIKELY( chunk < ctx->contact_in_chunk0 || chunk > ctx->contact_in_wmark ) ) {
109 0 : FD_LOG_ERR(( "chunk %lu %lu corrupt, not in range [%lu,%lu]",
110 0 : chunk,
111 0 : sz,
112 0 : ctx->contact_in_chunk0,
113 0 : ctx->contact_in_wmark ));
114 0 : }
115 :
116 0 : uchar const * dcache_entry = fd_chunk_to_laddr_const( ctx->contact_in_mem, chunk );
117 0 : handle_new_cluster_contact_info( ctx, dcache_entry, sz );
118 0 : } else if( FD_UNLIKELY( in_idx == ctx->gossip_in_idx ) ) {
119 0 : uchar * packet = fd_chunk_to_laddr( ctx->gossip_in_mem, chunk );
120 0 : memcpy( &ctx->duplicate_shred, packet, FD_GOSSIP_DUPLICATE_SHRED_FOOTPRINT );
121 0 : memcpy( ctx->duplicate_shred_chunk, packet + FD_GOSSIP_DUPLICATE_SHRED_FOOTPRINT, ctx->duplicate_shred.chunk_len );
122 0 : ctx->duplicate_shred.chunk = ctx->duplicate_shred_chunk;
123 0 : } else if ( FD_UNLIKELY( in_idx == ctx->shred_net_in_idx ) ) {
124 0 : if( FD_UNLIKELY( chunk < ctx->shred_net_in_chunk0 || chunk > ctx->shred_net_in_wmark ) ) {
125 0 : FD_LOG_ERR(( "chunk %lu %lu corrupt, not in range [%lu,%lu]",
126 0 : chunk,
127 0 : sz,
128 0 : ctx->shred_net_in_chunk0,
129 0 : ctx->shred_net_in_wmark ));
130 0 : }
131 :
132 0 : uchar const * packet = fd_chunk_to_laddr_const( ctx->shred_net_in_mem, chunk );
133 0 : fd_shred_t * shred = (fd_shred_t *)( packet + fd_disco_netmux_sig_hdr_sz( sig ) );
134 0 : memcpy( &ctx->shred, shred, sizeof(fd_shred_t) );
135 0 : }
136 0 : }
137 :
138 : static void
139 : after_frag( fd_eqvoc_tile_ctx_t * ctx,
140 : ulong in_idx,
141 : ulong seq,
142 : ulong sig,
143 : ulong sz,
144 : ulong tsorig,
145 : ulong tspub,
146 0 : fd_stem_context_t * stem ) {
147 0 : (void)seq;
148 0 : (void)sig;
149 0 : (void)sz;
150 0 : (void)tsorig;
151 0 : (void)tspub;
152 0 : (void)stem;
153 :
154 0 : if( FD_UNLIKELY( in_idx == ctx->contact_in_idx ) ) {
155 0 : finalize_new_cluster_contact_info( ctx );
156 0 : return;
157 0 : } else if ( FD_UNLIKELY( in_idx == ctx->gossip_in_idx ) ) {
158 : // fd_gossip_duplicate_shred_t * chunk = &ctx->duplicate_shred;
159 : // ulong slot = ctx->duplicate_shred.slot;
160 : // fd_pubkey_t const * from = &chunk->from;
161 :
162 : // fd_eqvoc_proof_t * proof = fd_eqvoc_proof_query( ctx->eqvoc, slot, from );
163 : // if( FD_UNLIKELY( !proof ) ) {
164 :
165 : // if( FD_UNLIKELY( chunk->chunk_index == chunk->num_chunks - 1 ) ) {
166 : // FD_LOG_WARNING(( "received last proof chunk first. unable to determine chunk len. ignoring." ));
167 : // return;
168 : // }
169 :
170 : // proof = fd_eqvoc_proof_insert( ctx->eqvoc, slot, from );
171 : // fd_pubkey_t const * leader = fd_epoch_leaders_get( ctx->eqvoc->leaders, slot );
172 : // fd_eqvoc_proof_init( proof, leader, chunk->wallclock, chunk->num_chunks, chunk->chunk_len, ctx->eqvoc->bmtree_mem );
173 : // }
174 : // fd_eqvoc_proof_chunk_insert( proof, chunk );
175 : // if( FD_UNLIKELY( fd_eqvoc_proof_complete( proof ) ) ) {
176 : // int rc = fd_eqvoc_proof_verify( proof );
177 : // FD_LOG_NOTICE(( "proof verify %d", rc ));
178 : // fd_eqvoc_proof_remove( ctx->eqvoc, &proof->key );
179 : // }
180 :
181 0 : return;
182 0 : }
183 : // } else if ( FD_UNLIKELY( in_idx == ctx->shred_net_in_idx ) ) {
184 : // FD_LOG_NOTICE(( "got shred %lu %u", ctx->shred.slot, ctx->shred.idx ));
185 : // } else {
186 : // FD_LOG_WARNING(( "unexpected in_idx %lu", in_idx ));
187 : // }
188 :
189 0 : }
190 :
191 : static void
192 : privileged_init( fd_topo_t * topo,
193 0 : fd_topo_tile_t * tile ) {
194 0 : void * scratch = fd_topo_obj_laddr( topo, tile->tile_obj_id );
195 :
196 0 : FD_SCRATCH_ALLOC_INIT( l, scratch );
197 0 : fd_eqvoc_tile_ctx_t * ctx = FD_SCRATCH_ALLOC_APPEND( l,
198 0 : alignof( fd_eqvoc_tile_ctx_t ),
199 0 : sizeof( fd_eqvoc_tile_ctx_t ) );
200 :
201 0 : if( FD_UNLIKELY( !strcmp( tile->eqvoc.identity_key_path, "" ) ) )
202 0 : FD_LOG_ERR(( "identity_key_path not set" ));
203 :
204 0 : ctx->identity_key[0] = *(fd_pubkey_t const *)
205 0 : fd_type_pun_const( fd_keyload_load( tile->eqvoc.identity_key_path,
206 0 : /* pubkey only: */ 1 ) );
207 :
208 0 : FD_TEST( fd_rng_secure( &ctx->seed, sizeof(ulong) ) );
209 0 : }
210 :
211 : static void
212 : unprivileged_init( fd_topo_t * topo,
213 0 : fd_topo_tile_t * tile ) {
214 0 : void * scratch = fd_topo_obj_laddr( topo, tile->tile_obj_id );
215 :
216 0 : FD_SCRATCH_ALLOC_INIT( l, scratch );
217 0 : fd_eqvoc_tile_ctx_t * ctx = FD_SCRATCH_ALLOC_APPEND( l, alignof( fd_eqvoc_tile_ctx_t ), sizeof( fd_eqvoc_tile_ctx_t ) );
218 0 : void * stake_ci_mem = FD_SCRATCH_ALLOC_APPEND( l, fd_stake_ci_align(), fd_stake_ci_footprint() );
219 0 : void * eqvoc_mem = FD_SCRATCH_ALLOC_APPEND( l, fd_eqvoc_align(), fd_eqvoc_footprint( 1 << 10, 1 << 10 ) );
220 0 : ulong scratch_top = FD_SCRATCH_ALLOC_FINI( l, scratch_align() );
221 0 : if( FD_UNLIKELY( scratch_top != (ulong)scratch + scratch_footprint( tile ) ) ) {
222 0 : FD_LOG_ERR(( "scratch overflow %lu %lu %lu",
223 0 : scratch_top - (ulong)scratch - scratch_footprint( tile ),
224 0 : scratch_top,
225 0 : (ulong)scratch + scratch_footprint( tile )) );
226 0 : }
227 :
228 0 : ctx->stake_ci = fd_stake_ci_join( fd_stake_ci_new( stake_ci_mem, ctx->identity_key ) );
229 0 : ctx->eqvoc = fd_eqvoc_join( fd_eqvoc_new( eqvoc_mem, 1 << 10, 1 << 10, 0 ) );
230 :
231 0 : ctx->contact_in_idx = fd_topo_find_tile_in_link( topo, tile, "gossip_voter", 0 );
232 0 : FD_TEST( ctx->contact_in_idx != ULONG_MAX );
233 0 : fd_topo_link_t * contact_in_link = &topo->links[tile->in_link_id[ctx->contact_in_idx]];
234 0 : ctx->contact_in_mem = topo->workspaces[topo->objs[contact_in_link->dcache_obj_id].wksp_id].wksp;
235 0 : ctx->contact_in_chunk0 = fd_dcache_compact_chunk0( ctx->contact_in_mem, contact_in_link->dcache );
236 0 : ctx->contact_in_wmark = fd_dcache_compact_wmark( ctx->contact_in_mem, contact_in_link->dcache, contact_in_link->mtu );
237 :
238 0 : ctx->gossip_in_idx = fd_topo_find_tile_in_link( topo, tile, "gossip_eqvoc", 0 );
239 0 : FD_TEST( ctx->gossip_in_idx != ULONG_MAX );
240 0 : fd_topo_link_t * gossip_in_link = &topo->links[tile->in_link_id[ctx->gossip_in_idx]];
241 0 : ctx->gossip_in_mem = topo->workspaces[topo->objs[gossip_in_link->dcache_obj_id].wksp_id].wksp;
242 0 : ctx->gossip_in_chunk0 = fd_dcache_compact_chunk0( ctx->gossip_in_mem, gossip_in_link->dcache );
243 0 : ctx->gossip_in_wmark = fd_dcache_compact_wmark( ctx->gossip_in_mem, gossip_in_link->dcache, gossip_in_link->mtu );
244 :
245 0 : ctx->shred_net_in_idx = fd_topo_find_tile_in_link( topo, tile, "shred_net", 0 );
246 0 : FD_TEST( ctx->shred_net_in_idx != ULONG_MAX );
247 0 : fd_topo_link_t * shred_net_in_link = &topo->links[tile->in_link_id[ctx->shred_net_in_idx]];
248 0 : ctx->shred_net_in_mem = topo->workspaces[topo->objs[shred_net_in_link->dcache_obj_id].wksp_id].wksp;
249 0 : ctx->shred_net_in_chunk0 = fd_dcache_compact_chunk0( ctx->shred_net_in_mem, shred_net_in_link->dcache );
250 0 : ctx->shred_net_in_wmark = fd_dcache_compact_wmark( ctx->shred_net_in_mem, shred_net_in_link->dcache, shred_net_in_link->mtu );
251 0 : }
252 :
253 : static ulong
254 : populate_allowed_seccomp( fd_topo_t const * topo,
255 : fd_topo_tile_t const * tile,
256 : ulong out_cnt,
257 0 : struct sock_filter * out ) {
258 0 : (void)topo;
259 0 : (void)tile;
260 :
261 0 : populate_sock_filter_policy_fd_eqvoc_tile( out_cnt, out, (uint)fd_log_private_logfile_fd() );
262 0 : return sock_filter_policy_fd_eqvoc_tile_instr_cnt;
263 0 : }
264 :
265 : static ulong
266 : populate_allowed_fds( fd_topo_t const * topo,
267 : fd_topo_tile_t const * tile,
268 : ulong out_fds_cnt,
269 0 : int * out_fds ) {
270 0 : (void)topo;
271 0 : (void)tile;
272 :
273 0 : if( FD_UNLIKELY( out_fds_cnt<2UL ) ) FD_LOG_ERR(( "out_fds_cnt %lu", out_fds_cnt ));
274 :
275 0 : ulong out_cnt = 0UL;
276 0 : out_fds[ out_cnt++ ] = 2; /* stderr */
277 0 : if( FD_LIKELY( -1!=fd_log_private_logfile_fd() ) )
278 0 : out_fds[ out_cnt++ ] = fd_log_private_logfile_fd(); /* logfile */
279 0 : return out_cnt;
280 0 : }
281 :
282 0 : #define STEM_BURST (1UL)
283 :
284 0 : #define STEM_CALLBACK_CONTEXT_TYPE fd_eqvoc_tile_ctx_t
285 0 : #define STEM_CALLBACK_CONTEXT_ALIGN alignof(fd_eqvoc_tile_ctx_t)
286 :
287 0 : #define STEM_CALLBACK_DURING_FRAG during_frag
288 0 : #define STEM_CALLBACK_AFTER_FRAG after_frag
289 :
290 : #include "../../disco/stem/fd_stem.c"
291 :
292 : fd_topo_run_tile_t fd_tile_eqvoc = {
293 : .name = "eqvoc",
294 : .loose_footprint = loose_footprint,
295 : .populate_allowed_seccomp = populate_allowed_seccomp,
296 : .populate_allowed_fds = populate_allowed_fds,
297 : .scratch_align = scratch_align,
298 : .scratch_footprint = scratch_footprint,
299 : .privileged_init = privileged_init,
300 : .unprivileged_init = unprivileged_init,
301 : .run = stem_run,
302 : };
|