Line data Source code
1 : /* The backtest topology exercises offline replay with mocked consensus.
2 :
3 : The smaller topology is:
4 : shred_out replay_execr
5 : backtest-------------->replay------------->execrp
6 : ^ |^ | ^ |
7 : |____________________|| | |________________|
8 : replay_out | | execrp_replay
9 : | |------------------------------>no consumer
10 : no producer------------- stake_out, txsend_out, poh_out
11 : store_replay
12 :
13 : */
14 : #define _GNU_SOURCE
15 : #include "../../firedancer/topology.h"
16 : #include "../../shared/commands/configure/configure.h"
17 : #include "../../shared/commands/run/run.h" /* initialize_workspaces */
18 : #include "../../shared/commands/watch/watch.h"
19 : #include "../../shared/fd_config.h" /* config_t */
20 : #include "../../../disco/topo/fd_topob.h"
21 : #include "../../../util/pod/fd_pod_format.h"
22 : #include "../../../discof/genesis/fd_genesi_tile.h"
23 : #include "../../../discof/replay/fd_replay_tile.h"
24 : #include "../../../discof/restore/utils/fd_ssctrl.h"
25 : #include "../../../discof/restore/utils/fd_ssmsg.h"
26 : #include "../../../discof/tower/fd_tower_tile.h"
27 : #include "../../../discof/replay/fd_execrp.h"
28 : #include "../../../disco/shred/fd_shred_tile.h"
29 : #include "../../../flamenco/capture/fd_capture_ctx.h"
30 : #include "../../../disco/pack/fd_pack_cost.h"
31 : #include "../../../flamenco/progcache/fd_progcache_admin.h"
32 : #include "../../../flamenco/runtime/fd_cost_tracker.h"
33 :
34 : #include <errno.h>
35 : #include <unistd.h>
36 : #include <fcntl.h>
37 :
38 : extern fd_topo_obj_callbacks_t * CALLBACKS[];
39 : fd_topo_run_tile_t fdctl_tile_run( fd_topo_tile_t const * tile );
40 :
41 : void
42 : backtest_cmd_args( int * pargc,
43 : char *** pargv,
44 0 : args_t * args ) {
45 0 : args->backtest.no_watch = fd_env_strip_cmdline_contains( pargc, pargv, "--no-watch" );
46 0 : }
47 :
48 : static void
49 0 : backtest_topo( config_t * config ) {
50 :
51 0 : config->development.sandbox = 0;
52 0 : config->development.no_clone = 1;
53 :
54 0 : config->firedancer.layout.resolv_tile_count = 0;
55 :
56 0 : ulong execrp_tile_cnt = config->firedancer.layout.execrp_tile_count;
57 :
58 0 : int disable_snap_loader = !config->gossip.entrypoints_cnt;
59 0 : int solcap_enabled = strlen( config->capture.solcap_capture )>0;
60 :
61 0 : fd_topo_t * topo = { fd_topob_new( &config->topo, config->name ) };
62 0 : topo->max_page_size = fd_cstr_to_shmem_page_sz( config->hugetlbfs.max_page_size );
63 0 : topo->gigantic_page_threshold = config->hugetlbfs.gigantic_page_threshold_mib << 20;
64 :
65 0 : ulong cpu_idx = 0;
66 :
67 0 : fd_topob_wksp( topo, "metric" );
68 0 : fd_topob_wksp( topo, "metric_in" );
69 0 : fd_topob_tile( topo, "metric", "metric", "metric_in", ULONG_MAX, 0, 0, 0 );
70 :
71 0 : fd_topob_wksp( topo, "backt" );
72 0 : fd_topo_tile_t * backt_tile = fd_topob_tile( topo, "backt", "backt", "metric_in", cpu_idx++, 0, 0, 0 );
73 :
74 0 : fd_topob_wksp( topo, "replay" );
75 0 : fd_topo_tile_t * replay_tile = fd_topob_tile( topo, "replay", "replay", "metric_in", cpu_idx++, 0, 1, 0 );
76 :
77 0 : fd_topo_obj_t * node_info_obj = fd_topob_obj( topo, "node_info", "replay" );
78 0 : fd_topob_tile_uses( topo, replay_tile, node_info_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
79 0 : FD_TEST( fd_pod_insertf_ulong( topo->props, node_info_obj->id, "node_info" ) );
80 :
81 0 : fd_topob_wksp( topo, "accdb" )->core_dump_level = FD_TOPO_CORE_DUMP_LEVEL_FULL;
82 0 : fd_topo_tile_t * accdb_tile = fd_topob_tile( topo, "accdb", "accdb", "metric_in", cpu_idx++, 0, 0, 0 );
83 :
84 0 : fd_topob_wksp( topo, "progcache" );
85 0 : setup_topo_progcache( topo, "progcache",
86 0 : fd_progcache_est_rec_max( config->firedancer.runtime.program_cache.heap_size_mib<<20,
87 0 : config->firedancer.runtime.program_cache.mean_cache_entry_size ),
88 0 : config->firedancer.runtime.max_live_slots,
89 0 : config->firedancer.runtime.program_cache.heap_size_mib<<20 );
90 0 : ulong progcache_obj_id; FD_TEST( (progcache_obj_id = fd_pod_query_ulong( topo->props, "progcache", ULONG_MAX ) )!=ULONG_MAX );
91 0 : fd_topob_tile_uses( topo, replay_tile, &topo->objs[ progcache_obj_id ], FD_SHMEM_JOIN_MODE_READ_WRITE );
92 :
93 0 : fd_topob_wksp( topo, "accdb_data" );
94 0 : fd_topo_obj_t * accdb_obj = setup_topo_accdb( topo, "accdb_data",
95 0 : config->firedancer.accounts.max_accounts,
96 0 : config->firedancer.runtime.max_live_slots,
97 0 : FD_RUNTIME_MAX_WRITABLE_ACCOUNTS_PER_SLOT,
98 0 : 8192UL,
99 0 : 1UL<<35UL,
100 0 : config->firedancer.accounts.cache_size_gib*(1UL<<30UL),
101 0 : config->tiles.bundle.enabled,
102 0 : execrp_tile_cnt+3UL );
103 0 : FD_TEST( fd_pod_insertf_ulong( topo->props, accdb_obj->id, "accdb" ) );
104 :
105 : /**********************************************************************/
106 : /* Add the executor tiles to topo */
107 : /**********************************************************************/
108 0 : fd_topob_wksp( topo, "execrp" );
109 0 : #define FOR(cnt) for( ulong i=0UL; i<cnt; i++ )
110 0 : FOR(execrp_tile_cnt) fd_topob_tile( topo, "execrp", "execrp", "metric_in", cpu_idx++, 0, 0, 0 );
111 :
112 : /**********************************************************************/
113 : /* Add the capture tile to topo */
114 : /**********************************************************************/
115 0 : if( solcap_enabled ) {
116 0 : fd_topob_wksp( topo, "solcap" );
117 0 : fd_topob_tile( topo, "solcap", "solcap", "metric_in", cpu_idx++, 0, 0, 0 );
118 0 : }
119 :
120 0 : fd_topob_wksp( topo, "diag" );
121 0 : fd_topob_tile( topo, "diag", "diag", "metric_in", ULONG_MAX, 0, 0, 0 );
122 :
123 : /**********************************************************************/
124 : /* Add the snapshot tiles to topo */
125 : /**********************************************************************/
126 0 : fd_topo_tile_t * snapin_tile = NULL;
127 0 : if( FD_UNLIKELY( !disable_snap_loader ) ) {
128 0 : fd_topob_wksp( topo, "snapct" );
129 0 : fd_topob_wksp( topo, "snapld" );
130 0 : fd_topob_wksp( topo, "snapdc" );
131 0 : fd_topob_wksp( topo, "snapin" );
132 0 : fd_topob_wksp( topo, "snapwr" );
133 :
134 0 : fd_topo_tile_t * snapct_tile = fd_topob_tile( topo, "snapct", "snapct", "metric_in", cpu_idx++, 0, 0, 0 );
135 0 : fd_topo_tile_t * snapld_tile = fd_topob_tile( topo, "snapld", "snapld", "metric_in", cpu_idx++, 0, 0, 0 );
136 0 : fd_topo_tile_t * snapdc_tile = fd_topob_tile( topo, "snapdc", "snapdc", "metric_in", cpu_idx++, 0, 0, 0 );
137 0 : snapin_tile = fd_topob_tile( topo, "snapin", "snapin", "metric_in", cpu_idx++, 0, 0, 0 );
138 0 : fd_topo_tile_t * snapwr_tile = fd_topob_tile( topo, "snapwr", "snapwr", "metric_in", cpu_idx++, 0, 0, 0 );
139 :
140 0 : snapct_tile->allow_shutdown = 1;
141 0 : snapld_tile->allow_shutdown = 1;
142 0 : snapdc_tile->allow_shutdown = 1;
143 0 : snapin_tile->allow_shutdown = 1;
144 0 : snapwr_tile->allow_shutdown = 1;
145 0 : } else {
146 0 : fd_topob_wksp( topo, "genesi" );
147 0 : fd_topob_tile( topo, "genesi", "genesi", "metric_in", cpu_idx++, 0, 0, 0 )->allow_shutdown = 1;
148 0 : }
149 :
150 : /**********************************************************************/
151 : /* Setup backtest->replay link (repair_out) in topo */
152 : /**********************************************************************/
153 :
154 : /* The repair tile is replaced by the backtest tile for the repair to
155 : replay link. The frag interface is a "slice", ie. entry batch,
156 : which is provided by the backtest tile, which reads in the entry
157 : batches from the CLI-specified source (eg. RocksDB). */
158 :
159 0 : fd_topob_wksp( topo, "repair_out" );
160 0 : fd_topob_link( topo, "repair_out", "repair_out", 65536UL, sizeof(fd_fec_complete_t), 1UL );
161 0 : fd_topob_tile_in( topo, "replay", 0UL, "metric_in", "repair_out", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
162 0 : fd_topob_tile_out( topo, "backt", 0UL, "repair_out", 0UL );
163 :
164 : /**********************************************************************/
165 : /* Setup snapshot links in topo */
166 : /**********************************************************************/
167 0 : if( FD_LIKELY( !disable_snap_loader ) ) {
168 0 : fd_topob_wksp( topo, "snapct_ld" );
169 0 : fd_topob_wksp( topo, "snapld_dc" );
170 0 : fd_topob_wksp( topo, "snapdc_in" );
171 :
172 0 : fd_topob_wksp( topo, "snapin_manif" );
173 0 : fd_topob_wksp( topo, "snapct_repr" );
174 :
175 0 : fd_topob_wksp( topo, "snapin_ct" );
176 0 : fd_topob_wksp( topo, "snapwr_ct" );
177 :
178 0 : fd_topob_link( topo, "snapct_ld", "snapct_ld", 128UL, sizeof(fd_ssctrl_init_t), 1UL );
179 0 : fd_topob_link( topo, "snapld_dc", "snapld_dc", 16384UL, USHORT_MAX, 1UL );
180 0 : fd_topob_link( topo, "snapdc_in", "snapdc_in", 16384UL, USHORT_MAX, 1UL );
181 :
182 0 : fd_topob_link( topo, "snapin_manif", "snapin_manif", 4UL, sizeof(fd_snapshot_manifest_t), 1UL ); /* TODO: Should be depth 1 or 2 but replay backpressures */
183 0 : fd_topob_link( topo, "snapct_repr", "snapct_repr", 128UL, 0UL, 1UL )->permit_no_consumers = 1;
184 :
185 0 : fd_topob_link( topo, "snapin_ct", "snapin_ct", 128UL, 0UL, 1UL );
186 0 : fd_topob_link( topo, "snapwr_ct", "snapwr_ct", 128UL, 0UL, 1UL );
187 :
188 0 : fd_topob_tile_in ( topo, "snapct", 0UL, "metric_in", "snapin_ct", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
189 0 : fd_topob_tile_in ( topo, "snapct", 0UL, "metric_in", "snapwr_ct", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
190 0 : fd_topob_tile_in ( topo, "snapct", 0UL, "metric_in", "snapld_dc", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
191 0 : fd_topob_tile_out( topo, "snapct", 0UL, "snapct_ld", 0UL );
192 0 : fd_topob_tile_out( topo, "snapct", 0UL, "snapct_repr", 0UL );
193 0 : fd_topob_tile_in ( topo, "snapld", 0UL, "metric_in", "snapct_ld", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
194 0 : fd_topob_tile_out( topo, "snapld", 0UL, "snapld_dc", 0UL );
195 0 : fd_topob_tile_in ( topo, "snapdc", 0UL, "metric_in", "snapld_dc", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
196 0 : fd_topob_tile_out( topo, "snapdc", 0UL, "snapdc_in", 0UL );
197 0 : fd_topob_tile_in ( topo, "snapin", 0UL, "metric_in", "snapdc_in", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
198 0 : fd_topob_tile_in ( topo, "snapwr", 0UL, "metric_in", "snapdc_in", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
199 :
200 0 : fd_topob_tile_out( topo, "snapin", 0UL, "snapin_manif", 0UL );
201 0 : fd_topob_tile_in ( topo, "replay", 0UL, "metric_in", "snapin_manif", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
202 :
203 0 : fd_topob_tile_out( topo, "snapin", 0UL, "snapin_ct", 0UL );
204 0 : fd_topob_tile_out( topo, "snapwr", 0UL, "snapwr_ct", 0UL );
205 0 : } else {
206 0 : fd_topob_wksp( topo, "genesi_out" );
207 0 : fd_topob_link( topo, "genesi_out", "genesi_out", 1UL, FD_GENESIS_TILE_MTU, 0UL );
208 0 : fd_topob_tile_out( topo, "genesi", 0UL, "genesi_out", 0UL );
209 0 : fd_topob_tile_in ( topo, "replay", 0UL, "metric_in", "genesi_out", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
210 0 : }
211 :
212 : /**********************************************************************/
213 : /* More backtest->replay links in topo */
214 : /**********************************************************************/
215 :
216 : /* The tower tile is replaced by the backtest tile for the tower to
217 : replay link. The backtest tile simply sends monotonically
218 : increasing rooted slot numbers to the replay tile, once after each
219 : "replayed a full slot" notification received from the replay tile.
220 : This allows the replay tile to advance its watermark, and publish
221 : various data structures. This is an oversimplified barebones mock
222 : of the tower tile. */
223 0 : fd_topob_wksp( topo, "tower_out" );
224 0 : fd_topob_link( topo, "tower_out", "tower_out", 1024UL, sizeof(fd_tower_slot_done_t), 1UL );
225 0 : fd_topob_tile_in( topo, "replay", 0UL, "metric_in", "tower_out", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
226 0 : fd_topob_tile_out( topo, "backt", 0UL, "tower_out", 0UL );
227 :
228 : /**********************************************************************/
229 : /* Setup replay->stake/send/poh links in topo w/o consumers */
230 : /**********************************************************************/
231 0 : fd_topob_wksp( topo, "replay_epoch" );
232 0 : fd_topob_link( topo, "replay_epoch", "replay_epoch", 128UL, FD_EPOCH_OUT_MTU, 1UL );
233 0 : fd_topob_tile_out( topo, "replay", 0UL, "replay_epoch", 0UL );
234 0 : topo->links[ replay_tile->out_link_id[ fd_topo_find_tile_out_link( topo, replay_tile, "replay_epoch", 0 ) ] ].permit_no_consumers = 1;
235 :
236 : /**********************************************************************/
237 : /* Setup replay->backtest link (replay_notif) in topo */
238 : /**********************************************************************/
239 :
240 0 : fd_topob_wksp( topo, "replay_out" );
241 0 : fd_topob_link( topo, "replay_out", "replay_out", 8192UL, sizeof( fd_replay_message_t ), 1UL );
242 0 : fd_topob_tile_out( topo, "replay", 0UL, "replay_out", 0UL );
243 0 : fd_topob_tile_in ( topo, "backt", 0UL, "metric_in", "replay_out", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
244 0 : if( FD_LIKELY( !disable_snap_loader ) ) {
245 0 : fd_topob_tile_in ( topo, "backt", 0UL, "metric_in", "snapin_manif", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
246 0 : } else {
247 0 : fd_topob_tile_in ( topo, "backt", 0UL, "metric_in", "genesi_out", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
248 0 : }
249 :
250 : /**********************************************************************/
251 : /* Setup replay->exec link in topo */
252 : /**********************************************************************/
253 0 : fd_topob_wksp( topo, "replay_execrp" );
254 0 : fd_topob_link( topo, "replay_execrp", "replay_execrp", 16384UL, 2240UL, 1UL );
255 0 : fd_topob_tile_out( topo, "replay", 0UL, "replay_execrp", 0UL );
256 0 : for( ulong i=0UL; i<execrp_tile_cnt; i++ ) {
257 0 : fd_topob_tile_in( topo, "execrp", i, "metric_in", "replay_execrp", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
258 0 : }
259 :
260 : /**********************************************************************/
261 : /* Setup exec->replay links in topo, to send solcap account updates
262 : so that they are serialized, and to notify replay tile that a txn
263 : has been finalized by the exec tile. */
264 : /**********************************************************************/
265 0 : fd_topob_wksp( topo, "execrp_replay" );
266 :
267 0 : FOR(execrp_tile_cnt) fd_topob_link( topo, "execrp_replay", "execrp_replay", 16384UL, sizeof(fd_execrp_task_done_msg_t), 1UL );
268 :
269 0 : FOR(execrp_tile_cnt) fd_topob_tile_out( topo, "execrp", i, "execrp_replay", i );
270 0 : FOR(execrp_tile_cnt) fd_topob_tile_in( topo, "replay", 0UL, "metric_in", "execrp_replay", i, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
271 :
272 : /**********************************************************************/
273 : /* Setup the shared objs used by replay and exec tiles */
274 : /**********************************************************************/
275 :
276 0 : if( FD_UNLIKELY( solcap_enabled ) ) {
277 : /* 32 sections of SOLCAP_WRITE_ACCOUNT_DATA_MTU bytes each ≈ 4MB.
278 : This is done to ideally avoid cache thrashing and allow for all
279 : the links to sit on L3 cache. */
280 0 : fd_topob_link( topo, "cap_repl", "solcap", 32UL, SOLCAP_WRITE_ACCOUNT_DATA_MTU, 1UL );
281 0 : fd_topob_tile_out( topo, "replay", 0UL, "cap_repl", 0UL );
282 0 : fd_topob_tile_in( topo, "solcap", 0UL, "metric_in", "cap_repl", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
283 0 : FOR(execrp_tile_cnt) fd_topob_link( topo, "cap_execrp", "solcap", 32UL, SOLCAP_WRITE_ACCOUNT_DATA_MTU, 1UL );
284 0 : FOR(execrp_tile_cnt) fd_topob_tile_out( topo, "execrp", i, "cap_execrp", i );
285 0 : FOR(execrp_tile_cnt) fd_topob_tile_in( topo, "solcap", 0UL, "metric_in", "cap_execrp", i, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
286 0 : }
287 :
288 0 : fd_topob_wksp( topo, "store" );
289 0 : ulong store_fec_data_max = fd_ulong_if( config->firedancer.development.fixed_fec_sets, 31840UL, 63985UL );
290 0 : fd_topo_obj_t * store_obj = setup_topo_store( topo, "store", config->firedancer.runtime.max_live_slots * FD_SHRED_BLK_MAX, 1, store_fec_data_max );
291 0 : fd_topob_tile_uses( topo, backt_tile, store_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
292 0 : fd_topob_tile_uses( topo, replay_tile, store_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
293 0 : FD_TEST( fd_pod_insertf_ulong( topo->props, store_obj->id, "store" ) );
294 :
295 0 : fd_topob_wksp( topo, "banks" );
296 0 : fd_topo_obj_t * banks_obj = setup_topo_banks( topo, "banks", config->firedancer.runtime.max_live_slots, config->firedancer.runtime.max_fork_width, 0 );
297 0 : fd_topob_tile_uses( topo, replay_tile, banks_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
298 0 : FOR(execrp_tile_cnt) fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "execrp", i ) ], banks_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
299 0 : FD_TEST( fd_pod_insertf_ulong( topo->props, banks_obj->id, "banks" ) );
300 :
301 0 : fd_topob_wksp( topo, "txncache" );
302 0 : fd_topo_obj_t * txncache_obj = setup_topo_txncache( topo, "txncache", config->firedancer.runtime.max_live_slots, FD_PACK_MAX_TXNCACHE_TXN_PER_SLOT );
303 0 : fd_topob_tile_uses( topo, replay_tile, txncache_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
304 0 : if( FD_LIKELY( !disable_snap_loader ) ) fd_topob_tile_uses( topo, snapin_tile, txncache_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
305 0 : for( ulong i=0UL; i<execrp_tile_cnt; i++ ) {
306 0 : fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "execrp", i ) ], txncache_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
307 0 : }
308 0 : FD_TEST( fd_pod_insertf_ulong( topo->props, txncache_obj->id, "txncache" ) );
309 :
310 0 : if( snapin_tile ) fd_topob_tile_uses( topo, snapin_tile, accdb_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
311 0 : fd_topob_tile_uses( topo, accdb_tile, accdb_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
312 0 : fd_topob_tile_uses( topo, replay_tile, accdb_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
313 0 : FOR( execrp_tile_cnt ) fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "execrp", i ) ], accdb_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
314 :
315 0 : for( ulong i=0UL; i<topo->tile_cnt; i++ ) {
316 0 : fd_topo_tile_t * tile = &topo->tiles[ i ];
317 0 : fd_topo_configure_tile( tile, config );
318 :
319 0 : if( !strcmp( tile->name, "replay" ) ) {
320 0 : tile->replay.enable_features_cnt = config->tiles.replay.enable_features_cnt;
321 0 : for( ulong i = 0; i < tile->replay.enable_features_cnt; i++ ) {
322 0 : fd_cstr_ncpy( tile->replay.enable_features[i], config->tiles.replay.enable_features[i], sizeof(tile->replay.enable_features[i]) );
323 0 : }
324 0 : }
325 0 : }
326 :
327 : // fd_topob_auto_layout( topo, 0 );
328 0 : fd_topob_finish( topo, CALLBACKS );
329 0 : }
330 :
331 : static void
332 0 : backtest_cmd_topo( config_t * config ) {
333 0 : backtest_topo( config );
334 0 : }
335 :
336 : extern configure_stage_t fd_cfg_stage_keys;
337 :
338 : static args_t
339 0 : configure_args( void ) {
340 0 : args_t args = {
341 0 : .configure.command = CONFIGURE_CMD_INIT,
342 0 : };
343 :
344 0 : ulong stage_idx = 0UL;
345 0 : args.configure.stages[ stage_idx++ ] = &fd_cfg_stage_hugetlbfs;
346 0 : args.configure.stages[ stage_idx++ ] = &fd_cfg_stage_snapshots;
347 0 : args.configure.stages[ stage_idx++ ] = &fd_cfg_stage_keys;
348 0 : args.configure.stages[ stage_idx++ ] = NULL;
349 :
350 0 : return args;
351 0 : }
352 :
353 : void
354 : backtest_cmd_perm( args_t * args FD_PARAM_UNUSED,
355 : fd_cap_chk_t * chk,
356 0 : config_t const * config ) {
357 0 : args_t c_args = configure_args();
358 0 : configure_cmd_perm( &c_args, chk, config );
359 0 : run_cmd_perm( NULL, chk, config );
360 0 : }
361 :
362 : static void
363 0 : fixup_config( config_t * config ) {
364 :
365 : /* FIXME Unfortunately, the fdctl boot procedure constructs the
366 : topology before parsing command-line arguments. So, here,
367 : we construct the topology again (a third time ... sigh). */
368 0 : backtest_topo( config );
369 0 : }
370 :
371 : static void
372 : backtest_cmd_fn( args_t * args,
373 0 : config_t * config ) {
374 0 : fixup_config( config );
375 0 : args_t c_args = configure_args();
376 0 : configure_cmd_fn( &c_args, config );
377 :
378 0 : initialize_workspaces( config );
379 0 : initialize_stacks( config );
380 0 : initialize_accdb_fd( config );
381 :
382 0 : fd_topo_join_workspaces( &config->topo, FD_SHMEM_JOIN_MODE_READ_WRITE, FD_TOPO_CORE_DUMP_LEVEL_DISABLED );
383 0 : fd_topo_fill( &config->topo );
384 :
385 0 : args_t watch_args;
386 0 : int pipefd[2];
387 0 : if( !args->backtest.no_watch ) {
388 0 : if( FD_UNLIKELY( pipe2( pipefd, O_NONBLOCK ) ) ) FD_LOG_ERR(( "pipe2() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
389 :
390 0 : watch_args.watch.drain_output_fd = pipefd[0];
391 0 : if( FD_UNLIKELY( -1==dup2( pipefd[ 1 ], STDERR_FILENO ) ) ) FD_LOG_ERR(( "dup2() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
392 0 : if( FD_UNLIKELY( -1==close( pipefd[1] ) ) ) FD_LOG_ERR(( "close() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
393 0 : }
394 :
395 0 : fd_topo_run_single_process( &config->topo, 2, config->uid, config->gid, fdctl_tile_run );
396 0 : if( args->backtest.no_watch ) {
397 0 : for(;;) pause();
398 0 : } else {
399 0 : watch_cmd_fn( &watch_args, config );
400 0 : }
401 0 : }
402 :
403 : action_t fd_action_backtest = {
404 : .name = "backtest",
405 : .args = backtest_cmd_args,
406 : .fn = backtest_cmd_fn,
407 : .perm = backtest_cmd_perm,
408 : .topo = backtest_cmd_topo,
409 : .description = "Replay a ledger offline through the replay tile with mocked consensus",
410 : };
|