Skip to main content

miden_node_utils/
clap.rs

1//! Public module for share clap pieces to reduce duplication
2
3use std::num::{NonZeroU32, NonZeroU64};
4use std::time::Duration;
5
6#[cfg(feature = "rocksdb")]
7mod rocksdb;
8#[cfg(feature = "rocksdb")]
9pub use rocksdb::*;
10
11const DEFAULT_REQUEST_TIMEOUT: Duration = Duration::from_secs(10);
12const TEST_REQUEST_TIMEOUT: Duration = Duration::from_secs(5);
13const DEFAULT_MAX_CONNECTION_AGE: Duration = Duration::from_mins(30);
14const DEFAULT_REPLENISH_N_PER_SECOND_PER_IP: NonZeroU64 = NonZeroU64::new(16).unwrap();
15const DEFAULT_BURST_SIZE: NonZeroU32 = NonZeroU32::new(128).unwrap();
16const DEFAULT_MAX_CONCURRENT_CONNECTIONS: u64 = 1_000;
17
18// Formats a Duration into a human-readable string for display in clap help text
19// and yields a &'static str by _leaking_ the string deliberately.
20pub fn duration_to_human_readable_string(duration: Duration) -> &'static str {
21    Box::new(humantime::format_duration(duration).to_string()).leak()
22}
23
24#[derive(clap::Args, Copy, Clone, Debug, PartialEq, Eq)]
25pub struct GrpcOptionsInternal {
26    /// Maximum duration a gRPC request is allocated before being dropped by the server.
27    ///
28    /// This may occur if the server is overloaded or due to an internal bug.
29    #[arg(
30        long = "grpc.timeout",
31        default_value = duration_to_human_readable_string(DEFAULT_REQUEST_TIMEOUT),
32        value_parser = humantime::parse_duration,
33        value_name = "DURATION"
34    )]
35    pub request_timeout: Duration,
36}
37
38impl Default for GrpcOptionsInternal {
39    fn default() -> Self {
40        Self { request_timeout: DEFAULT_REQUEST_TIMEOUT }
41    }
42}
43
44impl From<GrpcOptionsExternal> for GrpcOptionsInternal {
45    fn from(value: GrpcOptionsExternal) -> Self {
46        let GrpcOptionsExternal { request_timeout, .. } = value;
47        Self { request_timeout }
48    }
49}
50
51impl GrpcOptionsInternal {
52    pub fn test() -> Self {
53        GrpcOptionsExternal::test().into()
54    }
55    pub fn bench() -> Self {
56        GrpcOptionsExternal::bench().into()
57    }
58}
59
60#[derive(clap::Args, Copy, Clone, Debug, PartialEq, Eq)]
61pub struct GrpcOptionsExternal {
62    /// Maximum duration a gRPC request is allocated before being dropped by the server.
63    ///
64    /// This may occur if the server is overloaded or due to an internal bug.
65    #[arg(
66        long = "grpc.timeout",
67        default_value = duration_to_human_readable_string(DEFAULT_REQUEST_TIMEOUT),
68        value_parser = humantime::parse_duration,
69        value_name = "DURATION"
70    )]
71    pub request_timeout: Duration,
72
73    /// Maximum duration of a connection before we drop it on the server side irrespective of
74    /// activity.
75    #[arg(
76        long = "grpc.max_connection_age",
77        default_value = duration_to_human_readable_string(DEFAULT_MAX_CONNECTION_AGE),
78        value_parser = humantime::parse_duration,
79        value_name = "MAX_CONNECTION_AGE"
80    )]
81    pub max_connection_age: Duration,
82
83    /// Number of connections to be served before the "API tokens" need to be replenished
84    /// per IP address.
85    #[arg(
86        long = "grpc.burst_size",
87        default_value_t = DEFAULT_BURST_SIZE,
88        value_name = "BURST_SIZE"
89    )]
90    pub burst_size: NonZeroU32,
91
92    /// Number of request credits replenished per second per IP.
93    #[arg(
94        long = "grpc.replenish_n_per_second",
95        default_value_t = DEFAULT_REPLENISH_N_PER_SECOND_PER_IP,
96        value_name = "DEFAULT_REPLENISH_N_PER_SECOND"
97    )]
98    pub replenish_n_per_second_per_ip: NonZeroU64,
99
100    /// Maximum number of concurrent connections accepted by the server.
101    #[arg(
102        long = "grpc.max_concurrent_connections",
103        default_value_t = DEFAULT_MAX_CONCURRENT_CONNECTIONS,
104        value_name = "MAX_CONCURRENT_CONNECTIONS"
105    )]
106    pub max_concurrent_connections: u64,
107}
108
109impl Default for GrpcOptionsExternal {
110    fn default() -> Self {
111        Self {
112            request_timeout: DEFAULT_REQUEST_TIMEOUT,
113            max_connection_age: DEFAULT_MAX_CONNECTION_AGE,
114            burst_size: DEFAULT_BURST_SIZE,
115            replenish_n_per_second_per_ip: DEFAULT_REPLENISH_N_PER_SECOND_PER_IP,
116            max_concurrent_connections: DEFAULT_MAX_CONCURRENT_CONNECTIONS,
117        }
118    }
119}
120
121impl GrpcOptionsExternal {
122    pub fn test() -> Self {
123        Self {
124            request_timeout: TEST_REQUEST_TIMEOUT,
125            ..Default::default()
126        }
127    }
128
129    /// Return a gRPC config for benchmarking.
130    pub fn bench() -> Self {
131        Self {
132            request_timeout: Duration::from_hours(24),
133            max_connection_age: Duration::from_hours(24),
134            burst_size: NonZeroU32::new(100_000).unwrap(),
135            replenish_n_per_second_per_ip: NonZeroU64::new(100_000).unwrap(),
136            max_concurrent_connections: u64::MAX,
137        }
138    }
139}
140
141/// Collection of per usage storage backend configurations.
142///
143/// Note: Currently only contains `rocksdb` related configuration.
144#[derive(clap::Args, Clone, Debug, Default, PartialEq, Eq)]
145pub struct StorageOptions {
146    #[cfg(feature = "rocksdb")]
147    #[clap(flatten)]
148    pub account_tree: AccountTreeRocksDbOptions,
149    #[cfg(feature = "rocksdb")]
150    #[clap(flatten)]
151    pub nullifier_tree: NullifierTreeRocksDbOptions,
152}
153
154impl StorageOptions {
155    /// Benchmark setup.
156    ///
157    /// These values were determined during development of `LargeSmt`
158    pub fn bench() -> Self {
159        #[cfg(feature = "rocksdb")]
160        {
161            let account_tree = AccountTreeRocksDbOptions {
162                max_open_fds: self::rocksdb::BENCH_ROCKSDB_MAX_OPEN_FDS,
163                cache_size_in_bytes: self::rocksdb::DEFAULT_ROCKSDB_CACHE_SIZE,
164            };
165            let nullifier_tree = NullifierTreeRocksDbOptions {
166                max_open_fds: BENCH_ROCKSDB_MAX_OPEN_FDS,
167                cache_size_in_bytes: DEFAULT_ROCKSDB_CACHE_SIZE,
168            };
169            Self { account_tree, nullifier_tree }
170        }
171        #[cfg(not(feature = "rocksdb"))]
172        Self::default()
173    }
174}