Line data Source code
1 : #define _DEFAULT_SOURCE
2 : #include "..//tiles.h"
3 :
4 : #include <sys/socket.h>
5 : #include <netinet/in.h>
6 : #include <netinet/tcp.h>
7 : #include <sys/eventfd.h>
8 : #include <sys/epoll.h>
9 : #include <sys/mman.h>
10 : #include <sys/resource.h>
11 : #include <fcntl.h>
12 : #include "generated/fd_bundle_tile_seccomp.h"
13 :
14 : #include "../keyguard/fd_keyload.h"
15 : #include "../keyguard/fd_keyguard.h"
16 : #include "../keyguard/fd_keyguard_client.h"
17 : #include "../keyguard/fd_keyswitch.h"
18 : #include "../plugin/fd_plugin.h"
19 : #include "../metrics/fd_metrics.h"
20 : #include "../../util/net/fd_ip4.h"
21 :
22 : #include "../verify/fd_verify_tile.h"
23 :
24 : #include <sys/types.h>
25 : #include <netdb.h>
26 : #include <arpa/inet.h>
27 :
28 : typedef struct {
29 : ulong idx;
30 : fd_wksp_t * mem;
31 : ulong chunk0;
32 : ulong wmark;
33 : ulong chunk;
34 : } fd_bundle_out_ctx_t;
35 :
36 : /* fd_bundle_ctx_t is the context object provided to callbacks from the
37 : mux tile, and contains all state needed to progress the tile. */
38 :
39 : typedef struct {
40 : fd_keyguard_client_t keyguard_client[1];
41 :
42 : int identity_switched;
43 : fd_keyswitch_t * keyswitch;
44 : uchar identity_public_key[ 32UL ];
45 :
46 : ulong bundle_id;
47 :
48 : int plugin_initialized;
49 :
50 : char url[ 256 ];
51 : char domain_name[ 256 ];
52 :
53 : void * plugin;
54 :
55 : fd_bundle_out_ctx_t verify_out;
56 : fd_bundle_out_ctx_t plugin_out;
57 :
58 : struct {
59 : ulong txn_received;
60 : ulong bundle_received;
61 : ulong packet_received;
62 : } metrics;
63 : } fd_bundle_ctx_t;
64 :
65 : FD_FN_CONST static inline ulong
66 0 : scratch_align( void ) {
67 0 : return alignof( fd_bundle_ctx_t );
68 0 : }
69 :
70 : FD_FN_PURE static inline ulong
71 0 : scratch_footprint( fd_topo_tile_t const * tile ) {
72 0 : (void)tile;
73 0 : ulong l = FD_LAYOUT_INIT;
74 0 : l = FD_LAYOUT_APPEND( l, alignof( fd_bundle_ctx_t ), sizeof( fd_bundle_ctx_t ) );
75 0 : return FD_LAYOUT_FINI( l, scratch_align() );
76 0 : }
77 :
78 : static inline void
79 0 : during_housekeeping( fd_bundle_ctx_t * ctx ) {
80 0 : if( FD_UNLIKELY( fd_keyswitch_state_query( ctx->keyswitch )==FD_KEYSWITCH_STATE_SWITCH_PENDING ) ) {
81 0 : ctx->identity_switched = 1;
82 0 : fd_memcpy( ctx->identity_public_key, ctx->keyswitch->bytes, 32UL );
83 0 : fd_keyswitch_state( ctx->keyswitch, FD_KEYSWITCH_STATE_COMPLETED );
84 0 : }
85 0 : }
86 :
87 : static inline void
88 0 : metrics_write( fd_bundle_ctx_t * ctx ) {
89 0 : FD_MCNT_SET( BUNDLE, TRANSACTION_RECEIVED, ctx->metrics.txn_received );
90 0 : FD_MCNT_SET( BUNDLE, BUNDLE_RECEIVED, ctx->metrics.bundle_received );
91 0 : FD_MCNT_SET( BUNDLE, PACKET_RECEIVED, ctx->metrics.packet_received );
92 0 : }
93 :
94 : extern void
95 : plugin_bundle_poll( void * plugin,
96 : int reload_identity,
97 : uchar * identity_pubkey,
98 : int * out_type,
99 : uchar * out_block_builder_pubkey,
100 : ulong * out_block_builder_commission,
101 : ulong * out_bundle_len,
102 : uchar * out_data );
103 :
104 : extern void *
105 : plugin_bundle_init( char const * url,
106 : char const * domain_name,
107 : uchar * identity_pubkey );
108 :
109 : static FD_TL fd_bundle_ctx_t * tl_bundle_ctx;
110 :
111 : void
112 : plugin_bundle_sign_challenge( char const * challenge,
113 0 : uchar * out_signature ) {
114 0 : fd_bundle_ctx_t * ctx = tl_bundle_ctx;
115 0 : fd_keyguard_client_sign( ctx->keyguard_client, out_signature, (const uchar *)challenge, 9UL, FD_KEYGUARD_SIGN_TYPE_PUBKEY_CONCAT_ED25519 );
116 0 : }
117 :
118 : struct fd_bundle_msg {
119 : ulong txn_cnt;
120 : fd_txn_p_t txns[ 5 ];
121 : };
122 :
123 : typedef struct fd_bundle_msg fd_bundle_msg_t;
124 :
125 : static inline void
126 : after_credit( fd_bundle_ctx_t * ctx,
127 : fd_stem_context_t * stem,
128 : int * opt_poll_in,
129 0 : int * charge_busy ) {
130 0 : (void)opt_poll_in;
131 :
132 0 : if( FD_UNLIKELY( !ctx->plugin_initialized ) ) {
133 0 : ctx->plugin_initialized = 1;
134 :
135 0 : if( FD_LIKELY( ctx->plugin_out.mem ) ) {
136 0 : fd_plugin_msg_block_engine_update_t * update = (fd_plugin_msg_block_engine_update_t *)fd_chunk_to_laddr( ctx->plugin_out.mem, ctx->plugin_out.chunk );
137 0 : strncpy( update->url, ctx->url, sizeof(update->url) );
138 0 : strncpy( update->name, "jito", sizeof(update->name) );
139 0 : update->status = FD_PLUGIN_MSG_BLOCK_ENGINE_UPDATE_STATUS_DISCONNECTED;
140 :
141 0 : ulong tspub = (ulong)fd_frag_meta_ts_comp( fd_tickcount() );
142 0 : fd_stem_publish( stem, ctx->plugin_out.idx, FD_PLUGIN_MSG_BLOCK_ENGINE_UPDATE, ctx->plugin_out.chunk, sizeof(fd_plugin_msg_block_engine_update_t), 0UL, 0UL, tspub );
143 0 : ctx->plugin_out.chunk = fd_dcache_compact_next( ctx->plugin_out.chunk, sizeof(fd_plugin_msg_block_engine_update_t), ctx->plugin_out.chunk0, ctx->plugin_out.wmark );
144 :
145 0 : return;
146 0 : }
147 0 : }
148 :
149 0 : fd_bundle_msg_t * msg = fd_chunk_to_laddr( ctx->verify_out.mem, ctx->verify_out.chunk );
150 0 : uchar data[ 5UL*(8UL+FD_TXN_MTU) ];
151 :
152 0 : int type;
153 0 : ulong block_builder_commission;
154 0 : uchar block_builder_pubkey[ 32UL ];
155 :
156 0 : plugin_bundle_poll( ctx->plugin, ctx->identity_switched, ctx->identity_public_key, &type, block_builder_pubkey, &block_builder_commission, &msg->txn_cnt, data );
157 0 : ctx->identity_switched = 0;
158 0 : if( FD_LIKELY( !type ) ) return;
159 :
160 0 : *charge_busy = 1;
161 :
162 0 : if( FD_UNLIKELY( type<0 ) ) {
163 0 : if( FD_LIKELY( ctx->plugin_out.mem ) ) {
164 0 : fd_plugin_msg_block_engine_update_t * update = (fd_plugin_msg_block_engine_update_t *)fd_chunk_to_laddr( ctx->plugin_out.mem, ctx->plugin_out.chunk );
165 0 : strncpy( update->url, ctx->url, sizeof(update->url) );
166 0 : strncpy( update->name, "jito", sizeof(update->name) );
167 :
168 0 : switch( type ) {
169 0 : case -1: {
170 0 : update->status = FD_PLUGIN_MSG_BLOCK_ENGINE_UPDATE_STATUS_DISCONNECTED;
171 0 : break;
172 0 : }
173 0 : case -2: {
174 0 : update->status = FD_PLUGIN_MSG_BLOCK_ENGINE_UPDATE_STATUS_CONNECTING;
175 0 : break;
176 0 : }
177 0 : case -3: {
178 0 : update->status = FD_PLUGIN_MSG_BLOCK_ENGINE_UPDATE_STATUS_CONNECTED;
179 0 : break;
180 0 : }
181 0 : default:
182 0 : FD_LOG_ERR(( "invalid plugin_bundle_poll return value %d", type ));
183 0 : }
184 :
185 0 : ulong tspub = (ulong)fd_frag_meta_ts_comp( fd_tickcount() );
186 0 : fd_stem_publish( stem, ctx->plugin_out.idx, FD_PLUGIN_MSG_BLOCK_ENGINE_UPDATE, ctx->plugin_out.chunk, sizeof(fd_plugin_msg_block_engine_update_t), 0UL, 0UL, tspub );
187 0 : ctx->plugin_out.chunk = fd_dcache_compact_next( ctx->plugin_out.chunk, sizeof(fd_plugin_msg_block_engine_update_t), ctx->plugin_out.chunk0, ctx->plugin_out.wmark );
188 0 : }
189 0 : return;
190 0 : }
191 :
192 0 : if( FD_UNLIKELY( !msg->txn_cnt ) ) return;
193 :
194 0 : if( FD_UNLIKELY( msg->txn_cnt>5UL ) ) {
195 0 : FD_LOG_WARNING(( "bundle plugin produced invalid bundle of length %lu", msg->txn_cnt ));
196 0 : return;
197 0 : }
198 0 : if( FD_UNLIKELY( block_builder_commission>100UL ) ) {
199 0 : FD_LOG_WARNING(( "bundle plugin produced invalid commission %lu", block_builder_commission ));
200 0 : return;
201 0 : }
202 :
203 0 : ulong offset = 0UL;
204 0 : for( ulong i=0UL; i<msg->txn_cnt; i++ ) {
205 0 : ulong payload_sz = fd_ulong_load_8( data+offset );
206 0 : if( FD_UNLIKELY( payload_sz>FD_TXN_MTU ) ) {
207 0 : FD_LOG_WARNING(( "bundle plugin produced invalid payload size %lu", payload_sz ));
208 0 : return;
209 0 : }
210 0 : offset += 8UL+payload_sz;
211 0 : }
212 :
213 0 : ctx->metrics.txn_received += msg->txn_cnt;
214 0 : if( FD_LIKELY( type==2 ) ) ctx->metrics.packet_received++;
215 0 : else ctx->metrics.bundle_received++;
216 :
217 : /* Increment, skip 0 on overflow */
218 0 : ctx->bundle_id = fd_ulong_max( ctx->bundle_id+1UL, 1UL );
219 :
220 0 : offset = 0UL;
221 0 : for( ulong i=0UL; i<msg->txn_cnt; i++ ) {
222 0 : ulong payload_sz = fd_ulong_load_8( data+offset );
223 0 : offset += 8UL;
224 0 : uchar const * payload = data+offset;
225 0 : offset += payload_sz;
226 :
227 0 : fd_txn_m_t * txnm = (fd_txn_m_t *)fd_chunk_to_laddr( ctx->verify_out.mem, ctx->verify_out.chunk );
228 :
229 0 : if( FD_LIKELY( type==2 ) ) txnm->block_engine.bundle_id = 0UL;
230 0 : else txnm->block_engine.bundle_id = ctx->bundle_id;
231 :
232 0 : if( FD_LIKELY( i==0UL ) ) {
233 0 : txnm->block_engine.bundle_txn_cnt = msg->txn_cnt;
234 0 : txnm->block_engine.commission = (uchar)block_builder_commission;
235 0 : fd_memcpy( txnm->block_engine.commission_pubkey, block_builder_pubkey, 32UL );
236 0 : } else {
237 0 : txnm->block_engine.bundle_txn_cnt = 0UL;
238 0 : }
239 0 : txnm->payload_sz = (ushort)payload_sz;
240 0 : fd_memcpy( fd_txn_m_payload( txnm ), payload, payload_sz );
241 :
242 0 : ulong footprint = fd_txn_m_realized_footprint( txnm, 0, 0 );
243 :
244 0 : ulong tspub = (ulong)fd_frag_meta_ts_comp( fd_tickcount() );
245 0 : fd_stem_publish( stem, ctx->verify_out.idx, type!=2, ctx->verify_out.chunk, footprint, 0UL, 0UL, tspub );
246 0 : ctx->verify_out.chunk = fd_dcache_compact_next( ctx->verify_out.chunk, footprint, ctx->verify_out.chunk0, ctx->verify_out.wmark );
247 0 : }
248 0 : }
249 :
250 : static void
251 : replace_domain_with_ip( char const * url,
252 : char * domain,
253 0 : char * result ) {
254 0 : const char * protocol_end = strstr( url, "://" );
255 0 : if( FD_UNLIKELY( !protocol_end ) ) FD_LOG_ERR(( "invalid [tiles.bundle.url] `%s`. Must start with `http[s]://`", url ));
256 :
257 0 : char const * domain_start = protocol_end+3UL;
258 : /* Check for a port number */
259 0 : char const * domain_end = strchr( domain_start, ':' );
260 0 : if( FD_LIKELY( !domain_end ) ) domain_end = url + strlen( url );
261 :
262 0 : ulong domain_len = (ulong)(domain_end-domain_start);
263 0 : if( FD_UNLIKELY( domain_len>=256UL ) ) FD_LOG_ERR(( "[tiles.bundle.url] `%s` is too long (%lu>255)", url, domain_len ));
264 0 : strncpy( domain, domain_start, domain_len );
265 0 : domain[ domain_len ] = '\0';
266 :
267 0 : struct addrinfo hints, *res;
268 0 : memset( &hints, 0, sizeof(hints) );
269 0 : hints.ai_family = AF_INET;
270 :
271 0 : int err = getaddrinfo( domain, NULL, &hints, &res );
272 0 : if( FD_UNLIKELY( err ) ) FD_LOG_ERR(( "getaddrinfo `%s` failed (%d-%s)", domain, err, gai_strerror( err ) ));
273 :
274 0 : uint ip_addr = ((struct sockaddr_in *)res->ai_addr)->sin_addr.s_addr;
275 0 : FD_TEST( fd_cstr_printf_check( result, 256, NULL, "%.*s" FD_IP4_ADDR_FMT "%s", (int)(protocol_end-url+3L), url, FD_IP4_ADDR_FMT_ARGS( ip_addr ), domain_end ) );
276 0 : freeaddrinfo(res);
277 0 : }
278 :
279 : static void
280 : privileged_init( fd_topo_t * topo,
281 0 : fd_topo_tile_t * tile ) {
282 0 : void * scratch = fd_topo_obj_laddr( topo, tile->tile_obj_id );
283 :
284 0 : FD_SCRATCH_ALLOC_INIT( l, scratch );
285 0 : fd_bundle_ctx_t * ctx = FD_SCRATCH_ALLOC_APPEND( l, alignof( fd_bundle_ctx_t ), sizeof( fd_bundle_ctx_t ) );
286 :
287 0 : uchar const * public_key = fd_keyload_load( tile->bundle.identity_key_path, 1 /* public key only */ );
288 0 : fd_memcpy( ctx->identity_public_key, public_key, 32UL );
289 :
290 0 : if( FD_UNLIKELY( strlen( tile->bundle.url)<8UL || (strncmp( "https://", tile->bundle.url, 8UL ) && strncmp( "http://", tile->bundle.url, 7UL )) )) FD_LOG_ERR(( "invalid [tiles.bundle.url] `%s`. Must start with `http[s]://`", tile->bundle.url ));
291 :
292 : /* DNS resolution loads files, `resolv.conf` and all kind of rubbish
293 : like that, don't want to allow in the sandbox. */
294 0 : replace_domain_with_ip( tile->bundle.url, ctx->domain_name, ctx->url );
295 0 : if( FD_UNLIKELY( strcmp( tile->bundle.tls_domain_name, "" ) ) ) {
296 0 : strncpy( ctx->domain_name, tile->bundle.tls_domain_name, sizeof(ctx->domain_name) );
297 0 : }
298 0 : }
299 :
300 : static inline fd_bundle_out_ctx_t
301 : out1( fd_topo_t const * topo,
302 : fd_topo_tile_t const * tile,
303 0 : char const * name ) {
304 0 : ulong idx = ULONG_MAX;
305 :
306 0 : for( ulong i=0UL; i<tile->out_cnt; i++ ) {
307 0 : fd_topo_link_t const * link = &topo->links[ tile->out_link_id[ i ] ];
308 0 : if( !strcmp( link->name, name ) ) {
309 0 : if( FD_UNLIKELY( idx!=ULONG_MAX ) ) FD_LOG_ERR(( "tile %s:%lu had multiple output links named %s but expected one", tile->name, tile->kind_id, name ));
310 0 : idx = i;
311 0 : }
312 0 : }
313 :
314 0 : if( FD_UNLIKELY( idx==ULONG_MAX ) ) FD_LOG_ERR(( "tile %s:%lu had no output link named %s", tile->name, tile->kind_id, name ));
315 :
316 0 : void * mem = topo->workspaces[ topo->objs[ topo->links[ tile->out_link_id[ idx ] ].dcache_obj_id ].wksp_id ].wksp;
317 0 : ulong chunk0 = fd_dcache_compact_chunk0( mem, topo->links[ tile->out_link_id[ idx ] ].dcache );
318 0 : ulong wmark = fd_dcache_compact_wmark ( mem, topo->links[ tile->out_link_id[ idx ] ].dcache, topo->links[ tile->out_link_id[ idx ] ].mtu );
319 :
320 0 : return (fd_bundle_out_ctx_t){ .idx = idx, .mem = mem, .chunk0 = chunk0, .wmark = wmark, .chunk = chunk0 };
321 0 : }
322 :
323 : static inline fd_bundle_out_ctx_t
324 : out1opt( fd_topo_t const * topo,
325 : fd_topo_tile_t const * tile,
326 0 : char const * name ) {
327 0 : ulong idx = ULONG_MAX;
328 :
329 0 : for( ulong i=0UL; i<tile->out_cnt; i++ ) {
330 0 : fd_topo_link_t const * link = &topo->links[ tile->out_link_id[ i ] ];
331 0 : if( !strcmp( link->name, name ) ) {
332 0 : if( FD_UNLIKELY( idx!=ULONG_MAX ) ) FD_LOG_ERR(( "tile %s:%lu had multiple output links named %s but expected one", tile->name, tile->kind_id, name ));
333 0 : idx = i;
334 0 : }
335 0 : }
336 :
337 0 : if( FD_UNLIKELY( idx==ULONG_MAX ) ) {
338 0 : return (fd_bundle_out_ctx_t){ .idx = ULONG_MAX, .mem = NULL, .chunk0 = 0UL, .wmark = 0UL, .chunk = 0UL };
339 0 : }
340 :
341 0 : void * mem = topo->workspaces[ topo->objs[ topo->links[ tile->out_link_id[ idx ] ].dcache_obj_id ].wksp_id ].wksp;
342 0 : ulong chunk0 = fd_dcache_compact_chunk0( mem, topo->links[ tile->out_link_id[ idx ] ].dcache );
343 0 : ulong wmark = fd_dcache_compact_wmark ( mem, topo->links[ tile->out_link_id[ idx ] ].dcache, topo->links[ tile->out_link_id[ idx ] ].mtu );
344 :
345 0 : return (fd_bundle_out_ctx_t){ .idx = idx, .mem = mem, .chunk0 = chunk0, .wmark = wmark, .chunk = chunk0 };
346 0 : }
347 :
348 : static void
349 : unprivileged_init( fd_topo_t * topo,
350 0 : fd_topo_tile_t * tile ) {
351 0 : void * scratch = fd_topo_obj_laddr( topo, tile->tile_obj_id );
352 :
353 0 : FD_SCRATCH_ALLOC_INIT( l, scratch );
354 0 : fd_bundle_ctx_t * ctx = FD_SCRATCH_ALLOC_APPEND( l, alignof( fd_bundle_ctx_t ), sizeof( fd_bundle_ctx_t ) );
355 :
356 0 : ulong sign_in_idx = fd_topo_find_tile_in_link( topo, tile, "sign_bundle", tile->kind_id );
357 0 : FD_TEST( sign_in_idx!=ULONG_MAX );
358 0 : fd_topo_link_t * sign_in = &topo->links[ tile->in_link_id[ sign_in_idx ] ];
359 0 : fd_topo_link_t * sign_out = &topo->links[ tile->out_link_id[ 1UL ] ];
360 0 : FD_TEST( !strcmp( sign_out->name, "bundle_sign" ) );
361 :
362 0 : if( FD_UNLIKELY( !fd_keyguard_client_join( fd_keyguard_client_new( ctx->keyguard_client,
363 0 : sign_out->mcache,
364 0 : sign_out->dcache,
365 0 : sign_in->mcache,
366 0 : sign_in->dcache ) ) ) ) {
367 0 : FD_LOG_ERR(( "fd_keyguard_client_join failed" ));
368 0 : }
369 :
370 0 : tl_bundle_ctx = ctx;
371 :
372 0 : ctx->identity_switched = 0;
373 0 : ctx->keyswitch = fd_keyswitch_join( fd_topo_obj_laddr( topo, tile->keyswitch_obj_id ) );
374 0 : FD_TEST( ctx->keyswitch );
375 :
376 0 : ctx->plugin = plugin_bundle_init( ctx->url, ctx->domain_name, ctx->identity_public_key );
377 0 : FD_TEST( ctx->plugin );
378 :
379 0 : ctx->plugin_initialized = 0;
380 0 : ctx->bundle_id = 0UL;
381 :
382 0 : ctx->verify_out = out1( topo, tile, "bundle_verif" );
383 0 : ctx->plugin_out = out1opt( topo, tile, "bundle_plugi" );
384 :
385 0 : memset( &ctx->metrics, 0, sizeof( ctx->metrics ) );
386 :
387 0 : ulong scratch_top = FD_SCRATCH_ALLOC_FINI( l, scratch_align() );
388 0 : if( FD_UNLIKELY( scratch_top > (ulong)scratch + scratch_footprint( tile ) ) )
389 0 : FD_LOG_ERR(( "scratch overflow %lu %lu %lu", scratch_top - (ulong)scratch - scratch_footprint( tile ), scratch_top, (ulong)scratch + scratch_footprint( tile ) ));
390 0 : }
391 :
392 : static ulong
393 : populate_allowed_seccomp( fd_topo_t const * topo,
394 : fd_topo_tile_t const * tile,
395 : ulong out_cnt,
396 0 : struct sock_filter * out ) {
397 0 : (void)topo;
398 0 : (void)tile;
399 :
400 0 : populate_sock_filter_policy_fd_bundle_tile( out_cnt, out, (uint)fd_log_private_logfile_fd() );
401 0 : return sock_filter_policy_fd_bundle_tile_instr_cnt;
402 0 : }
403 :
404 : static ulong
405 : populate_allowed_fds( fd_topo_t const * topo,
406 : fd_topo_tile_t const * tile,
407 : ulong out_fds_cnt,
408 0 : int * out_fds ) {
409 0 : (void)topo;
410 0 : (void)tile;
411 :
412 0 : if( FD_UNLIKELY( out_fds_cnt<2UL ) ) FD_LOG_ERR(( "out_fds_cnt %lu", out_fds_cnt ));
413 :
414 0 : ulong out_cnt = 0UL;
415 0 : out_fds[ out_cnt++ ] = 2; /* stderr */
416 0 : if( FD_LIKELY( -1!=fd_log_private_logfile_fd() ) )
417 0 : out_fds[ out_cnt++ ] = fd_log_private_logfile_fd(); /* logfile */
418 0 : return out_cnt;
419 0 : }
420 :
421 0 : #define STEM_BURST (5UL)
422 :
423 0 : #define STEM_CALLBACK_CONTEXT_TYPE fd_bundle_ctx_t
424 0 : #define STEM_CALLBACK_CONTEXT_ALIGN alignof(fd_bundle_ctx_t)
425 :
426 0 : #define STEM_CALLBACK_DURING_HOUSEKEEPING during_housekeeping
427 0 : #define STEM_CALLBACK_METRICS_WRITE metrics_write
428 0 : #define STEM_CALLBACK_AFTER_CREDIT after_credit
429 :
430 : #include "../../disco/stem/fd_stem.c"
431 :
432 : fd_topo_run_tile_t fd_tile_bundle = {
433 : .name = "bundle",
434 : .rlimit_file_cnt = 4096UL, /* Rust side opens a few files for DNS lookups and things */
435 : .rlimit_address_space = RLIM_INFINITY,
436 : .rlimit_data = RLIM_INFINITY,
437 : .keep_host_networking = 1, /* We need to use the NIC to connect(2) to the block producer endpoint */
438 : .allow_connect = 1, /* We need to use connect(2) to connect to the block producer endpoint */
439 : .populate_allowed_seccomp = populate_allowed_seccomp,
440 : .populate_allowed_fds = populate_allowed_fds,
441 : .scratch_align = scratch_align,
442 : .scratch_footprint = scratch_footprint,
443 : .privileged_init = privileged_init,
444 : .unprivileged_init = unprivileged_init,
445 : .run = stem_run,
446 : };
|