1use crate::ExternalStorageLocation::GCS;
3use crate::MutableConfigValue;
4use std::cmp::{max, min};
5use std::path::PathBuf;
6use std::sync::atomic::AtomicBool;
7use std::sync::Arc;
8use std::time::Duration;
9use unc_primitives::types::{BlockHeight, BlockHeightDelta, Gas, NumBlocks, NumSeats, ShardId};
10use unc_primitives::version::Version;
11
12pub const TEST_STATE_SYNC_TIMEOUT: u64 = 5;
13
14#[derive(Debug, Copy, Clone, serde::Serialize, serde::Deserialize)]
15pub enum LogSummaryStyle {
16 #[serde(rename = "plain")]
17 Plain,
18 #[serde(rename = "colored")]
19 Colored,
20}
21
22pub const MIN_GC_NUM_EPOCHS_TO_KEEP: u64 = 3;
24
25pub const DEFAULT_GC_NUM_EPOCHS_TO_KEEP: u64 = 5;
27
28pub const DEFAULT_STATE_SYNC_NUM_CONCURRENT_REQUESTS_EXTERNAL: u32 = 25;
30pub const DEFAULT_STATE_SYNC_NUM_CONCURRENT_REQUESTS_ON_CATCHUP_EXTERNAL: u32 = 5;
31
32#[derive(Clone, Debug, serde::Serialize, serde::Deserialize, PartialEq)]
34#[serde(default)]
35pub struct GCConfig {
36 pub gc_blocks_limit: NumBlocks,
39
40 pub gc_fork_clean_step: u64,
43
44 pub gc_num_epochs_to_keep: u64,
46}
47
48impl Default for GCConfig {
49 fn default() -> Self {
50 Self {
51 gc_blocks_limit: 2,
52 gc_fork_clean_step: 100,
53 gc_num_epochs_to_keep: DEFAULT_GC_NUM_EPOCHS_TO_KEEP,
54 }
55 }
56}
57
58impl GCConfig {
59 pub fn gc_num_epochs_to_keep(&self) -> u64 {
60 max(MIN_GC_NUM_EPOCHS_TO_KEEP, self.gc_num_epochs_to_keep)
61 }
62}
63
64fn default_num_concurrent_requests() -> u32 {
65 DEFAULT_STATE_SYNC_NUM_CONCURRENT_REQUESTS_EXTERNAL
66}
67
68fn default_num_concurrent_requests_during_catchup() -> u32 {
69 DEFAULT_STATE_SYNC_NUM_CONCURRENT_REQUESTS_ON_CATCHUP_EXTERNAL
70}
71
72#[derive(serde::Serialize, serde::Deserialize, Clone, Debug)]
73pub struct ExternalStorageConfig {
74 pub location: ExternalStorageLocation,
76 #[serde(default = "default_num_concurrent_requests")]
79 pub num_concurrent_requests: u32,
80 #[serde(default = "default_num_concurrent_requests_during_catchup")]
83 pub num_concurrent_requests_during_catchup: u32,
84}
85
86#[derive(serde::Serialize, serde::Deserialize, Clone, Debug)]
87pub enum ExternalStorageLocation {
88 S3 {
89 bucket: String,
91 region: String,
93 },
94 Filesystem {
95 root_dir: PathBuf,
96 },
97 GCS {
98 bucket: String,
99 },
100}
101
102#[derive(serde::Serialize, serde::Deserialize, Clone, Debug)]
104pub struct DumpConfig {
105 pub location: ExternalStorageLocation,
107 #[serde(skip_serializing_if = "Option::is_none")]
110 pub restart_dump_for_shards: Option<Vec<ShardId>>,
111 #[serde(skip_serializing_if = "Option::is_none")]
114 pub iteration_delay: Option<Duration>,
115 #[serde(skip_serializing_if = "Option::is_none")]
117 pub credentials_file: Option<PathBuf>,
118}
119
120#[derive(serde::Serialize, serde::Deserialize, Clone, Debug)]
122pub enum SyncConfig {
123 Peers,
125 ExternalStorage(ExternalStorageConfig),
127}
128
129impl Default for SyncConfig {
130 fn default() -> Self {
131 Self::Peers
132 }
133}
134
135#[derive(serde::Serialize, serde::Deserialize, Clone, Debug, Default)]
136pub struct StateSyncConfig {
138 #[serde(skip_serializing_if = "Option::is_none")]
139 pub dump: Option<DumpConfig>,
141 #[serde(skip_serializing_if = "SyncConfig::is_default", default = "SyncConfig::default")]
142 pub sync: SyncConfig,
143}
144
145impl SyncConfig {
146 fn is_default(&self) -> bool {
148 matches!(self, Self::Peers)
149 }
150}
151
152#[derive(Clone)]
155pub struct ReshardingHandle {
156 keep_going: Arc<AtomicBool>,
157}
158
159impl ReshardingHandle {
160 pub fn new() -> Self {
161 Self { keep_going: Arc::new(AtomicBool::new(true)) }
162 }
163
164 pub fn get(&self) -> bool {
165 self.keep_going.load(std::sync::atomic::Ordering::Relaxed)
166 }
167
168 pub fn stop(&self) -> () {
169 self.keep_going.store(false, std::sync::atomic::Ordering::Relaxed);
170 }
171}
172
173#[derive(serde::Serialize, serde::Deserialize, Clone, Copy, Debug, PartialEq)]
175#[serde(default)]
176pub struct ReshardingConfig {
177 pub batch_size: bytesize::ByteSize,
181
182 pub batch_delay: Duration,
186
187 pub retry_delay: Duration,
190
191 pub initial_delay: Duration,
194
195 pub max_poll_time: Duration,
199}
200
201impl Default for ReshardingConfig {
202 fn default() -> Self {
203 Self {
206 batch_size: bytesize::ByteSize::kb(500),
207 batch_delay: Duration::from_millis(100),
208 retry_delay: Duration::from_secs(10),
209 initial_delay: Duration::from_secs(0),
210 max_poll_time: Duration::from_secs(2 * 60 * 60), }
215 }
216}
217
218pub fn default_header_sync_initial_timeout() -> Duration {
219 Duration::from_secs(10)
220}
221
222pub fn default_header_sync_progress_timeout() -> Duration {
223 Duration::from_secs(2)
224}
225
226pub fn default_header_sync_stall_ban_timeout() -> Duration {
227 Duration::from_secs(120)
228}
229
230pub fn default_state_sync_timeout() -> Duration {
231 Duration::from_secs(60)
232}
233
234pub fn default_header_sync_expected_height_per_second() -> u64 {
235 10
236}
237
238pub fn default_sync_check_period() -> Duration {
239 Duration::from_secs(10 * 30)
240}
241
242pub fn default_sync_step_period() -> Duration {
243 Duration::from_millis(10 * 30)
244}
245
246pub fn default_sync_height_threshold() -> u64 {
247 1
248}
249
250pub fn default_state_sync() -> Option<StateSyncConfig> {
251 Some(StateSyncConfig {
252 dump: None,
253 sync: SyncConfig::ExternalStorage(ExternalStorageConfig {
254 location: GCS { bucket: "state-parts".to_string() },
255 num_concurrent_requests: DEFAULT_STATE_SYNC_NUM_CONCURRENT_REQUESTS_EXTERNAL,
256 num_concurrent_requests_during_catchup:
257 DEFAULT_STATE_SYNC_NUM_CONCURRENT_REQUESTS_ON_CATCHUP_EXTERNAL,
258 }),
259 })
260}
261
262pub fn default_state_sync_enabled() -> bool {
263 true
264}
265
266pub fn default_view_client_threads() -> usize {
267 4
268}
269
270pub fn default_log_summary_period() -> Duration {
271 Duration::from_secs(10)
272}
273
274pub fn default_view_client_throttle_period() -> Duration {
275 Duration::from_secs(30)
276}
277
278pub fn default_trie_viewer_state_size_limit() -> Option<u64> {
279 Some(50_000)
280}
281
282pub fn default_transaction_pool_size_limit() -> Option<u64> {
283 Some(100_000_000) }
285
286pub fn default_tx_routing_height_horizon() -> BlockHeightDelta {
287 4
288}
289
290pub fn default_enable_multiline_logging() -> Option<bool> {
291 Some(true)
292}
293
294pub fn default_produce_chunk_add_transactions_time_limit() -> Option<Duration> {
295 Some(Duration::from_millis(200))
296}
297
298#[derive(Clone, serde::Serialize)]
300pub struct ClientConfig {
301 pub version: Version,
303 pub chain_id: String,
305 pub rpc_addr: Option<String>,
307 pub expected_shutdown: MutableConfigValue<Option<BlockHeight>>,
309 pub block_production_tracking_delay: Duration,
311 pub min_block_production_delay: Duration,
313 pub max_block_production_delay: Duration,
315 pub max_block_wait_delay: Duration,
317 pub skip_sync_wait: bool,
319 pub sync_check_period: Duration,
321 pub sync_step_period: Duration,
323 pub sync_height_threshold: BlockHeightDelta,
325 pub header_sync_initial_timeout: Duration,
327 pub header_sync_progress_timeout: Duration,
329 pub header_sync_stall_ban_timeout: Duration,
331 pub header_sync_expected_height_per_second: u64,
333 pub state_sync_timeout: Duration,
335 pub min_num_peers: usize,
337 pub log_summary_period: Duration,
339 pub log_summary_style: LogSummaryStyle,
341 pub produce_empty_blocks: bool,
343 pub epoch_length: BlockHeightDelta,
345 pub num_block_producer_seats: NumSeats,
347 pub ttl_account_id_router: Duration,
349 pub block_fetch_horizon: BlockHeightDelta,
351 pub catchup_step_period: Duration,
353 pub chunk_request_retry_period: Duration,
355 pub doosmslug_step_period: Duration,
357 pub block_header_fetch_horizon: BlockHeightDelta,
359 pub gc: GCConfig,
361 pub archive: bool,
363 pub save_trie_changes: bool,
368 pub view_client_threads: usize,
370 pub view_client_throttle_period: Duration,
372 pub trie_viewer_state_size_limit: Option<u64>,
374 pub max_gas_burnt_view: Option<Gas>,
378 pub enable_statistics_export: bool,
380 pub client_background_migration_threads: usize,
382 pub flat_storage_creation_enabled: bool,
384 pub flat_storage_creation_period: Duration,
386 pub state_sync_enabled: bool,
389 pub state_sync: StateSyncConfig,
391 pub transaction_pool_size_limit: Option<u64>,
394 pub enable_multiline_logging: bool,
396 pub resharding_config: MutableConfigValue<ReshardingConfig>,
398 pub tx_routing_height_horizon: BlockHeightDelta,
401 pub produce_chunk_add_transactions_time_limit: MutableConfigValue<Option<Duration>>,
406}
407
408impl ClientConfig {
409 pub fn test(
410 skip_sync_wait: bool,
411 min_block_prod_time: u64,
412 max_block_prod_time: u64,
413 num_block_producer_seats: NumSeats,
414 archive: bool,
415 save_trie_changes: bool,
416 state_sync_enabled: bool,
417 ) -> Self {
418 assert!(
419 archive || save_trie_changes,
420 "Configuration with archive = false and save_trie_changes = false is not supported \
421 because non-archival nodes must save trie changes in order to do do garbage collection."
422 );
423
424 Self {
425 version: Default::default(),
426 chain_id: "unittest".to_string(),
427 rpc_addr: Some("0.0.0.0:3030".to_string()),
428 expected_shutdown: MutableConfigValue::new(None, "expected_shutdown"),
429 block_production_tracking_delay: Duration::from_millis(std::cmp::max(
430 10,
431 min_block_prod_time / 5,
432 )),
433 min_block_production_delay: Duration::from_millis(min_block_prod_time),
434 max_block_production_delay: Duration::from_millis(max_block_prod_time),
435 max_block_wait_delay: Duration::from_millis(3 * min_block_prod_time),
436 skip_sync_wait,
437 sync_check_period: Duration::from_millis(100),
438 sync_step_period: Duration::from_millis(10),
439 sync_height_threshold: 1,
440 header_sync_initial_timeout: Duration::from_secs(10),
441 header_sync_progress_timeout: Duration::from_secs(2),
442 header_sync_stall_ban_timeout: Duration::from_secs(30),
443 state_sync_timeout: Duration::from_secs(TEST_STATE_SYNC_TIMEOUT),
444 header_sync_expected_height_per_second: 1,
445 min_num_peers: 1,
446 log_summary_period: Duration::from_secs(10),
447 produce_empty_blocks: true,
448 epoch_length: 10,
449 num_block_producer_seats,
450 ttl_account_id_router: Duration::from_secs(60 * 60),
451 block_fetch_horizon: 50,
452 catchup_step_period: Duration::from_millis(1),
453 chunk_request_retry_period: min(
454 Duration::from_millis(100),
455 Duration::from_millis(min_block_prod_time / 5),
456 ),
457 doosmslug_step_period: Duration::from_millis(100),
458 block_header_fetch_horizon: 50,
459 gc: GCConfig { gc_blocks_limit: 100, ..GCConfig::default() },
460 archive,
461 save_trie_changes,
462 log_summary_style: LogSummaryStyle::Colored,
463 view_client_threads: 1,
464 view_client_throttle_period: Duration::from_secs(1),
465 trie_viewer_state_size_limit: None,
466 max_gas_burnt_view: None,
467 enable_statistics_export: true,
468 client_background_migration_threads: 1,
469 flat_storage_creation_enabled: true,
470 flat_storage_creation_period: Duration::from_secs(1),
471 state_sync_enabled,
472 state_sync: StateSyncConfig::default(),
473 transaction_pool_size_limit: None,
474 enable_multiline_logging: false,
475 resharding_config: MutableConfigValue::new(
476 ReshardingConfig::default(),
477 "resharding_config",
478 ),
479 tx_routing_height_horizon: 4,
480 produce_chunk_add_transactions_time_limit: MutableConfigValue::new(
481 default_produce_chunk_add_transactions_time_limit(),
482 "produce_chunk_add_transactions_time_limit",
483 ),
484 }
485 }
486}