forked from firedancer-io/radiance
-
Notifications
You must be signed in to change notification settings - Fork 28
Expand file tree
/
Copy pathconfig.example.toml
More file actions
596 lines (483 loc) · 24 KB
/
Copy pathconfig.example.toml
File metadata and controls
596 lines (483 loc) · 24 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
# Mithril Configuration File
# Generate a starter config with: mithril config init
# CLI flags override these values when both are specified.
#
# Quick start:
# 1. Run: mithril config init
# 2. Edit [storage] paths for your setup
# 3. Run: mithril run --config config.toml
#
# Everything else has sensible defaults.
# ============================================================================
# GENERAL SETTINGS
# ============================================================================
# Name of this Mithril instance (used in logs and metrics)
name = "mithril"
# ============================================================================
# [bootstrap] - Startup Mode
# ============================================================================
#
# Controls how Mithril initializes its state on startup.
#
# Modes:
# "auto" - Use existing AccountsDB if valid, otherwise download snapshot.
# If AccountsDB is significantly behind chain tip (>full_threshold
# slots), prompts interactively to continue or rebuild.
# "snapshot" - Rebuild AccountsDB from snapshot. Reuses existing downloaded
# snapshot if within full_threshold slots, otherwise downloads new.
# "new-snapshot" - Always download a fresh snapshot, ignoring all existing data.
# Cleans AccountsDB and snapshot directories before starting.
# "accountsdb" - Require existing valid AccountsDB, fail fast if missing.
#
# The default is "auto" which tries to resume from existing AccountsDB if valid,
# or downloads a fresh snapshot if needed. Use "snapshot" to always check freshness.
[bootstrap]
mode = "auto"
# ============================================================================
# [storage] - Storage Paths
# ============================================================================
#
# Mithril stores data in these locations:
#
# AccountsDB (~500GB)
# In Solana, "accounts" are the fundamental unit of state - every wallet,
# token balance, program, and piece of on-chain data is an account.
# AccountsDB is Mithril's index of all ~500M accounts on the network.
# Heavy random I/O - put this on your FASTEST NVMe.
#
# Snapshots (~100GB)
# Periodic dumps of account state from the network. Mithril downloads
# one on first run to bootstrap AccountsDB.
#
# Shredstore (varies)
# Lightbringer stores received shreds here for block streaming
# and potential repair serving. Size depends on retention settings.
#
# Recommended setup (two NVMe drives):
# /mnt/mithril-accounts/ <- Fast NVMe (~500GB for AccountsDB)
# /mnt/mithril-ledger/ <- Larger NVMe for everything else
# ├── shredstore/
# └── snapshots/
#
# See scripts/disk-setup.sh for automated setup.
[storage]
# AccountsDB - the main account state database (~500GB)
# Put this on your fastest NVMe due to heavy random I/O.
accounts = "/mnt/mithril-accounts"
# Shredstore - Lightbringer stores received shreds here
# Used for block streaming and potential repair serving.
shredstore = "/mnt/mithril-ledger/shredstore"
# Snapshots - downloaded on first run (~100GB for full + incremental)
snapshots = "/mnt/mithril-ledger/snapshots"
# Logs - runtime output for debugging and monitoring
logs = "/mnt/mithril-logs"
# ============================================================================
# [network] - RPC Endpoints
# ============================================================================
#
# Solana RPC endpoints for all cluster access (blocks, leader schedule, etc.)
# Endpoints are listed in PRIORITY ORDER:
# - First endpoint is PRIMARY (used for all calls when healthy)
# - Remaining endpoints are FALLBACKS (used when primary fails)
#
# On hard connectivity errors (connection refused, DNS failure, etc.), Mithril
# automatically fails over to the next endpoint in the list. It periodically
# probes the primary and restores to it when healthy.
[network]
# Solana cluster (required): "mainnet-beta", "testnet", or "devnet"
# This is validated against the RPC's genesis hash to prevent accidentally
# running mainnet state against testnet, or vice versa.
cluster = "mainnet-beta"
# RPC endpoints in priority order (first = primary, rest = fallbacks)
#
# Example with primary + fallback:
# rpc = [
# "https://your-rpc.example.com", # Primary
# "https://api.mainnet-beta.solana.com" # Fallback
# ]
rpc = ["https://api.mainnet-beta.solana.com"]
# ============================================================================
# [block] - Block Source & Streaming
# ============================================================================
#
# Block source configuration. See also [lightbringer] below for sidecar settings.
[block]
# Where to stream new blocks from:
# "rpc" - Fetch blocks via getBlock RPC calls
# "lightbringer" - Stream via Lightbringer sidecar (see [lightbringer] section)
# Uses RPC for catchup, hands off to live stream near tip.
# "turbine" - Native UDP turbine shred receiver.
# Uses RPC for catchup, hands off to reconstructed shreds near tip.
source = "rpc"
# Lightbringer endpoint address (only used when source = "lightbringer")
# lightbringer_endpoint = "localhost:9000"
# Native turbine UDP bind address (only used when source = "turbine").
# turbine_bind_addr = "0.0.0.0:8001"
# Gossip settings for native turbine live under [turbine].
# =========================================================================
# Global Fetch Tuning
# =========================================================================
# These settings control parallel block fetching.
# Tune based on your RPC provider's rate limits.
# Maximum RPC requests per second for block fetching.
# Check your RPC provider's rate limits. Private nodes can go higher.
max_rps = 8
# Maximum concurrent block fetch requests (workers).
# Should generally match max_rps.
max_inflight = 8
# How often to poll for chain tip in CATCHUP mode (milliseconds).
tip_poll_interval_ms = 1000
# Don't fetch within this many slots of the confirmed tip.
# Prevents "slot not available" errors. 32 slots ≈ 13 seconds.
# NOTE: Only applied in CATCHUP mode when gap > catchup_tip_gate_threshold.
tip_safety_margin = 32
# =========================================================================
# Mode Thresholds (Hysteresis)
# =========================================================================
# Mithril uses two modes for block fetching:
#
# CATCHUP: Far from tip - aggressive prefetching, fills buffer to ~100 slots
# NEAR-TIP: Close to tip - JIT scheduling with small lookahead
#
# Hysteresis prevents mode thrashing: different thresholds for entering vs exiting.
# Example: enter near-tip at gap <= 32, exit back to catchup at gap >= 64.
# Enter NEAR-TIP mode when gap to confirmed tip <= this.
near_tip_threshold = 32
# Exit NEAR-TIP mode (back to CATCHUP) when gap >= this.
catchup_threshold = 64
# Only apply tip_safety_margin when gap > this threshold.
# When gap is smaller (transitioning to near-tip), the margin is too restrictive
# and causes "beyond tip" storms. Set high enough to give plenty of headroom.
catchup_tip_gate_threshold = 128
# =========================================================================
# Near-Tip Tuning
# =========================================================================
# These settings only apply in NEAR-TIP mode (when close to chain tip).
# Note: tip_safety_margin is NOT applied in near-tip mode by design.
# Near-tip relies on fast retries for "slot not available" instead of margin.
# How often to poll for chain tip in NEAR-TIP mode (milliseconds).
# Faster than catchup to stay responsive to new slots.
near_tip_poll_interval_ms = 500
# How many slots ahead to schedule in NEAR-TIP mode.
# Provides enough buffer to hide RPC latency (~300ms) behind execution (~100ms).
near_tip_lookahead = 2
# ============================================================================
# [consensus] - Vote-Anchored Consensus
# ============================================================================
#
# Controls how Mithril uses on-chain vote data to verify block correctness.
# The fork choice service accumulates vote stake per slot and determines
# which bank hash has reached 2/3 supermajority.
#
# When using Lightbringer as the block source, the consensus coordinator
# resolves ambiguous slot ranges by finding a valid skip path that chains
# to the vote-confirmed hash. If no valid path exists, the configured
# policy determines behavior.
[consensus]
# Maximum depth (number of slots) the skip-path solver will explore.
# Longer ranges take more memory. 64 covers ~26 seconds of slots.
skip_path_max_depth = 64
# What to do when a Lightbringer slot range cannot be resolved:
# "halt" - Graceful shutdown, write diagnostic artifact (recommended)
# "warn" - Log warning and continue (use only for debugging)
unresolved_policy = "halt"
# Which block source to enforce consensus on:
# "lightbringer" - Only enforce on Lightbringer blocks (RPC blocks are trusted)
# "turbine" - Only enforce on native turbine blocks
# "stream" - Enforce on any live shred-stream path
# "all" - Enforce on all block sources (not yet implemented)
enforce_on_source = "stream"
# ============================================================================
# [turbine] - Native Turbine Receiver (block.source = "turbine")
# ============================================================================
#
# Native turbine mode reconstructs blocks from data shreds inside Mithril.
# RPC remains configured for catchup, tip polling, and repair/fallback paths.
[turbine]
# UDP address where Mithril listens for turbine shreds.
# bind_addr = "0.0.0.0:8001"
# Solana gossip entrypoint used to discover the cluster shred version and
# advertise Mithril's turbine/TVU socket into the turbine tree.
# gossip_entrypoint = "1.2.3.4:8000"
# UDP address where Mithril listens for gossip traffic. Leave empty to let
# the OS choose an available port. Set a fixed port if your firewall/NAT
# needs an explicit rule.
# gossip_bind_addr = "0.0.0.0:65401"
# Optional public IP override. Leave empty to ask the gossip entrypoint's
# IP echo service.
# advertised_ip = "203.0.113.10"
# Optional override. Leave at zero/empty to discover from gossip_entrypoint.
# shred_version = 0
# ============================================================================
# [lightbringer] - Lightbringer Sidecar (block.source = "lightbringer")
# ============================================================================
#
# Lightbringer is a Turbine sidecar that receives and caches shreds,
# streaming assembled blocks to Mithril via gRPC. Lower latency than
# RPC polling.
#
# When enabled, Mithril manages Lightbringer's full lifecycle:
# 1. Generates Lightbringer.toml from these settings
# 2. Spawns the Lightbringer process
# 3. Captures its logs to lightbringer.log in the run directory
# 4. Shuts it down gracefully when Mithril stops
#
# Enabling this automatically sets block.source = "lightbringer" and
# block.lightbringer_endpoint to match grpc_addr below.
#
# Requirements:
# - Lightbringer binary must be available at binary_path
# - A Solana gossip entrypoint is required when enabled
[lightbringer]
# Enable managed Lightbringer sidecar (default: false)
enabled = false
# Path to the Lightbringer binary
binary_path = "./lightbringer"
# Solana gossip entrypoint (REQUIRED when enabled)
# This is the IP:port of a Solana validator or RPC node running gossip.
# gossip_entrypoint = "1.2.3.4:8000"
# Lightbringer's debug HTTP endpoint (for inspecting stored shreds)
rpc_addr = "127.0.0.1:3000"
# Lightbringer's gRPC stream endpoint (Mithril connects here for blocks)
# This value is automatically used as block.lightbringer_endpoint.
grpc_addr = "127.0.0.1:3001"
# Directory where Mithril writes the generated Lightbringer.toml
# Defaults to current working directory.
config_dir = "."
# Optional: InfluxDB metrics for Lightbringer
# (written as [influxdb] section in generated Lightbringer.toml)
# influxdb_host = "http://localhost:8181"
# influxdb_database = "test"
# influxdb_token = "xyz"
# Optional: Block confirmation via Solana RPC
# (written as [block_confirmation] section in generated Lightbringer.toml)
# block_confirmation_rpc_http = "http://localhost:8899"
# block_confirmation_rpc_websocket = "ws://localhost:8899"
# Suppress Lightbringer info/debug log lines (only warn/error). Default: true.
# Set quiet = false to show all info messages.
quiet = true
# ============================================================================
# [rpc] - Mithril RPC Server
# ============================================================================
#
# Mithril exposes a Solana-compatible JSON-RPC interface on all interfaces,
# allowing other tools to query Mithril's account state directly.
#
# Query with: curl http://localhost:8899 -X POST -H "Content-Type: application/json" \
# -d '{"jsonrpc":"2.0","id":1,"method":"getBlockHeight"}'
[rpc]
# Port for Mithril's RPC interface (0 = disabled)
port = 8899
# ============================================================================
# [tuning] - Performance Tuning & Profiling
# ============================================================================
#
# Advanced settings for optimizing Mithril's performance.
# The defaults work well for most deployments.
[tuning]
# Transaction parallelism for block execution.
# Set to 0 for sequential execution, or >0 for parallel workers.
# Recommended: 2x your CPU core count (e.g., 192 for a 96-core machine)
txpar = 24
# Zstd decoder concurrency (defaults to NumCPU)
# zstd_decoder_concurrency = 16
# Snapshot bootstrap I/O tuning.
# These defaults deliberately avoid flooding a single NVMe with hundreds of
# concurrent writes. Increase cautiously on very fast multi-disk systems.
# AppendVec files copied from the snapshot archive concurrently.
snapshot_append_vec_workers = 32
# Workers parsing AppendVecs into account-index entries.
snapshot_index_builder_workers = 64
# Workers enqueueing account-index entries into shard logs.
snapshot_index_committer_workers = 64
# Number of temporary account-index shard logs/SSTs.
snapshot_index_shards = 64
# Optional temp directory for snapshot index shard logs/SST staging.
# This can move tens of GB of temporary write/read churn off the AccountsDB
# disk. On RAM-rich machines, /dev/shm/mithril-snapshot-index is useful.
# Leave empty to stage under storage.accounts.
snapshot_index_temp_dir = ""
# Bound for number of index shards to convert to SSTs at once.
max_concurrent_flushers = 8
# Size in MB for serialized parameter arena (0 to disable)
param_arena_size_mb = 512
# Number of borrowed accounts to preallocate in arena (0 to disable)
borrowed_account_arena_size = 1024
# Enable/disable pool allocator for slices
use_pool = true
# Number of goroutines to store modified accounts at the end of each block
store_accounts_workers = 128
# Approximate maximum retained SBPF program cache size in MiB.
program_cache_max_mb = 1024
# [tuning.pprof] - CPU/Memory Profiling
#
# Usage (assuming port = 6060):
#
# View in browser:
# http://localhost:6060/debug/pprof/
#
# CPU profile (30 sec sample, opens interactive terminal):
# go tool pprof http://localhost:6060/debug/pprof/profile?seconds=30
#
# Heap profile (current memory usage):
# go tool pprof http://localhost:6060/debug/pprof/heap
#
# Alloc profile (total allocations since start):
# go tool pprof http://localhost:6060/debug/pprof/allocs
#
# View goroutines in terminal:
# curl http://localhost:6060/debug/pprof/goroutine?debug=1
#
# View all goroutines with full stack traces:
# curl http://localhost:6060/debug/pprof/goroutine?debug=2
#
[tuning.pprof]
# Port to serve HTTP pprof endpoint (-1 to disable)
# port = 6060
# Filename to write CPU profile (for offline analysis with go tool pprof)
# cpu_profile_path = "/mnt/mithril-data/profiling/cpu.pprof"
# ============================================================================
# [debug] - Debug Logging
# ============================================================================
#
# Options for debugging specific transactions or accounts.
[debug]
# Transaction signatures to enable debug logging for
# transaction_signatures = ["sig1", "sig2"]
# Account pubkeys to enable debug logging of transactions that modify them
# account_writes = ["pubkey1", "pubkey2"]
# Write epoch-boundary reward artifacts, including a JSON comparison of
# local voting rewards against block/RPC data plus a CSV dump of all
# locally calculated rewards.
# dump_epoch_voting_reward_diff = true
# ============================================================================
# [reporting] - Metrics & Reporting
# ============================================================================
[reporting]
# Replay timings (JSONL latency records per block) are automatically written
# to replay_timings.jsonl in each run's log directory.
# ============================================================================
# [snapshot] - Snapshot Download Settings
# ============================================================================
[snapshot]
# -------------------------------------------------------------------------
# Snapshot Storage
# -------------------------------------------------------------------------
# Snapshots are downloaded to the path specified in [storage].snapshots above.
# Maximum snapshots to keep on disk (controls both saving and retention)
# 0 = Stream-only mode (don't save snapshots, saves disk space)
# 1 = Save one snapshot, delete previous before downloading new
# 2+ = Keep N snapshots, delete oldest when limit exceeded
#
# Saved snapshots are valuable for debugging and reproducing issues -
# the dev team can start from a snapshot to investigate problems.
# Set to 0 for stream-only mode (saves disk space but requires re-download
# if interrupted).
max_full_snapshots = 1
# Enable verbose output showing detailed node discovery statistics
verbose = false
# -------------------------------------------------------------------------
# Snapshot Age Threshold
# -------------------------------------------------------------------------
# Maximum age for full snapshots in slots (~100,000 slots ≈ 12 hours at 400ms/slot)
#
# This threshold is used for:
# - Snapshot download: Skip nodes with snapshots older than this
# - Snapshot reuse: In mode=snapshot, reuse existing downloaded snapshot
# if within this age instead of downloading new
# - Stale AccountsDB detection: In mode=auto, prompt user if AccountsDB
# is this far behind the latest available snapshot
full_threshold = 100000
# Maximum age for incremental snapshots (slots)
# Incrementals are always downloaded (they're small and provide latest state)
incremental_threshold = 1000
# Safety margin - warn if snapshot is this close to expiration (slots)
safety_margin_slots = 5000
# -------------------------------------------------------------------------
# Stage 1: Fast Parallel Triage
# Quickly tests many nodes in parallel to eliminate slow ones
# -------------------------------------------------------------------------
# Warmup data before timing (KiB)
stage1_warm_kib = 512
# Size of each measurement window (KiB)
stage1_window_kib = 512
# Number of measurement windows (total data = windows * window_kib)
stage1_windows = 4
# Timeout for stage 1 testing per node (milliseconds)
stage1_timeout_ms = 3000
# Number of concurrent downloads in stage 1 (0 = auto, uses CPU cores)
stage1_concurrency = 0
# -------------------------------------------------------------------------
# Stage 2: Sustained Speed Test
# Tests top candidates from stage 1 with longer downloads
# -------------------------------------------------------------------------
# Number of top candidates from stage 1 to test in stage 2
stage2_top_k = 8
# Warmup duration before measurement (seconds)
# Recommended: 3 seconds for home internet (more variable), 1-2 for datacenter
stage2_warm_sec = 3
# Measurement duration (seconds)
# Recommended: 3 seconds for home internet (more variable), 1-2 for datacenter
stage2_measure_sec = 3
# Minimum speed ratio (collapse if speed drops below this * peak)
stage2_min_ratio = 0.6
# Minimum absolute speed (MB/s, 0 = disabled)
stage2_min_abs_mbs = 0.0
# -------------------------------------------------------------------------
# Node Filtering
# -------------------------------------------------------------------------
# Maximum RTT to consider a node (milliseconds, 0 = disabled)
max_rtt_ms = 200
# TCP connection timeout for pre-check (milliseconds)
tcp_timeout_ms = 1000
# Minimum Solana version required (e.g., "3.0.0", empty = no filter)
# min_node_version = "3.0.0"
# Allowed Solana versions (empty = all versions allowed)
# Example: allowed_node_versions = ["2.2.0", "3.0.0"]
# allowed_node_versions = []
# Snapshot source blacklist. Entries may be full RPC URLs, host:port pairs,
# or bare host/IP values. Matching nodes are skipped before snapshot probing.
node_blacklist = [
# "http://203.0.113.10:8899",
# "198.51.100.24:8899",
# "bad-snapshot-node.example.com",
]
# -------------------------------------------------------------------------
# Performance
# -------------------------------------------------------------------------
# Number of concurrent workers for node evaluation
worker_count = 100
# -------------------------------------------------------------------------
# Fallback Resilience
# -------------------------------------------------------------------------
# Maximum number of ranked snapshot sources to try before giving up
# This is a resilience mechanism - if the #1 fastest node's HTTP endpoint
# is down or snapshot was deleted, we try the next best ranked nodes.
# Set to 0 to try all available nodes.
max_snapshot_url_attempts = 3
# -------------------------------------------------------------------------
# Incremental Snapshot Selection
# -------------------------------------------------------------------------
# Minimum download speed for incremental snapshot sources (MB/s)
# Incrementals are ~1GB, so this filters out nodes that would take too long.
# At 2 MB/s: ~8 minutes for 1GB (acceptable)
# Set to 0 to disable speed filtering.
min_incremental_speed_mbs = 2.0
# ============================================================================
# [log] - Logging Configuration
# ============================================================================
#
# Mithril writes logs to files for easy debugging and sharing.
# Each run creates a new log file with timestamp and run ID.
[log]
# Log directory is set in [storage].logs above
# Log level: "debug" | "info" | "warn" | "error"
level = "info"
# Also write to stdout (set to false for daemon/service mode)
to_stdout = true
# Maximum log file size in MB before rotation (0 = no limit)
max_size_mb = 100
# Delete log files older than this many days (0 = never delete)
max_age_days = 30
# Maximum number of old log files to keep (0 = unlimited)
max_backups = 100