-
Notifications
You must be signed in to change notification settings - Fork 30
/
Copy pathargs.rs
359 lines (310 loc) · 12.7 KB
/
args.rs
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
//! Katana binary executable.
//!
//! ## Feature Flags
//!
//! - `jemalloc`: Uses [jemallocator](https://github.com/tikv/jemallocator) as the global allocator.
//! This is **not recommended on Windows**. See [here](https://rust-lang.github.io/rfcs/1974-global-allocators.html#jemalloc)
//! for more info.
//! - `jemalloc-prof`: Enables [jemallocator's](https://github.com/tikv/jemallocator) heap profiling
//! and leak detection functionality. See [jemalloc's opt.prof](https://jemalloc.net/jemalloc.3.html#opt.prof)
//! documentation for usage details. This is **not recommended on Windows**. See [here](https://rust-lang.github.io/rfcs/1974-global-allocators.html#jemalloc)
//! for more info.
use std::env;
use std::net::SocketAddr;
use std::path::PathBuf;
use alloy_primitives::U256;
use clap::{Args, Parser, Subcommand};
use clap_complete::Shell;
use common::parse::parse_socket_address;
use katana_core::backend::config::{Environment, StarknetConfig};
use katana_core::constants::{
DEFAULT_ETH_L1_GAS_PRICE, DEFAULT_INVOKE_MAX_STEPS, DEFAULT_SEQUENCER_ADDRESS,
DEFAULT_STRK_L1_GAS_PRICE, DEFAULT_VALIDATE_MAX_STEPS,
};
use katana_core::sequencer::SequencerConfig;
use katana_primitives::block::GasPrices;
use katana_primitives::chain::ChainId;
use katana_primitives::genesis::allocation::DevAllocationsGenerator;
use katana_primitives::genesis::constant::DEFAULT_PREFUNDED_ACCOUNT_BALANCE;
use katana_primitives::genesis::Genesis;
use katana_rpc::config::ServerConfig;
use katana_rpc_api::ApiKind;
use tracing::Subscriber;
use tracing_subscriber::{fmt, EnvFilter};
use url::Url;
use crate::utils::{parse_genesis, parse_seed};
#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
#[command(propagate_version = true)]
pub struct KatanaArgs {
#[arg(long)]
#[arg(help = "Don't print anything on startup.")]
pub silent: bool,
#[arg(long)]
#[arg(conflicts_with = "block_time")]
#[arg(help = "Disable auto and interval mining, and mine on demand instead via an endpoint.")]
pub no_mining: bool,
#[arg(short, long)]
#[arg(value_name = "MILLISECONDS")]
#[arg(help = "Block time in milliseconds for interval mining.")]
pub block_time: Option<u64>,
#[arg(long)]
#[arg(value_name = "PATH")]
#[arg(help = "Directory path of the database to initialize from.")]
#[arg(
long_help = "Directory path of the database to initialize from. The path must either \
be an empty directory or a directory which already contains a previously \
initialized Katana database."
)]
pub db_dir: Option<PathBuf>,
#[arg(long)]
#[arg(value_name = "URL")]
#[arg(help = "The Starknet RPC provider to fork the network from.")]
pub rpc_url: Option<Url>,
#[arg(long)]
pub dev: bool,
#[arg(long)]
#[arg(help = "Output logs in JSON format.")]
pub json_log: bool,
/// Enable Prometheus metrics.
///
/// The metrics will be served at the given interface and port.
#[arg(long, value_name = "SOCKET", value_parser = parse_socket_address, help_heading = "Metrics")]
pub metrics: Option<SocketAddr>,
#[arg(long)]
#[arg(requires = "rpc_url")]
#[arg(value_name = "BLOCK_NUMBER")]
#[arg(help = "Fork the network at a specific block.")]
pub fork_block_number: Option<u64>,
#[cfg(feature = "messaging")]
#[arg(long)]
#[arg(value_name = "PATH")]
#[arg(value_parser = katana_core::service::messaging::MessagingConfig::parse)]
#[arg(help = "Configure the messaging with an other chain.")]
#[arg(
long_help = "Configure the messaging to allow Katana listening/sending messages on a \
settlement chain that can be Ethereum or an other Starknet sequencer. \
The configuration file details and examples can be found here: https://book.dojoengine.org/toolchain/katana/reference#messaging"
)]
pub messaging: Option<katana_core::service::messaging::MessagingConfig>,
#[command(flatten)]
#[command(next_help_heading = "Server options")]
pub server: ServerOptions,
#[command(flatten)]
#[command(next_help_heading = "Starknet options")]
pub starknet: StarknetOptions,
#[command(subcommand)]
pub command: Option<Commands>,
}
#[derive(Debug, Subcommand)]
pub enum Commands {
#[command(about = "Generate shell completion file for specified shell")]
Completions { shell: Shell },
}
#[derive(Debug, Args, Clone)]
pub struct ServerOptions {
#[arg(short, long)]
#[arg(default_value = "7777")]
#[arg(help = "Port number to listen on.")]
pub port: u16,
#[arg(long)]
#[arg(help = "The IP address the server will listen on.")]
pub host: Option<String>,
#[arg(long)]
#[arg(default_value = "100")]
#[arg(help = "Maximum number of concurrent connections allowed.")]
pub max_connections: u32,
#[arg(long)]
#[arg(value_delimiter = ',')]
#[arg(help = "Enables the CORS layer and sets the allowed origins, separated by commas.")]
pub allowed_origins: Option<Vec<String>>,
}
#[derive(Debug, Args, Clone)]
pub struct StarknetOptions {
#[arg(long)]
#[arg(default_value = "0")]
#[arg(help = "Specify the seed for randomness of accounts to be predeployed.")]
pub seed: String,
#[arg(long = "accounts")]
#[arg(value_name = "NUM")]
#[arg(default_value = "10")]
#[arg(help = "Number of pre-funded accounts to generate.")]
pub total_accounts: u16,
#[arg(long)]
#[arg(help = "Disable charging fee when executing transactions.")]
pub disable_fee: bool,
#[arg(long)]
#[arg(help = "Disable validation when executing transactions.")]
pub disable_validate: bool,
#[command(flatten)]
#[command(next_help_heading = "Environment options")]
pub environment: EnvironmentOptions,
#[arg(long)]
#[arg(value_parser = parse_genesis)]
#[arg(conflicts_with_all(["rpc_url", "seed", "total_accounts"]))]
pub genesis: Option<Genesis>,
}
#[derive(Debug, Args, Clone)]
pub struct EnvironmentOptions {
#[arg(long)]
#[arg(help = "The chain ID.")]
#[arg(
long_help = "The chain ID. If a raw hex string (`0x` prefix) is provided, then it'd \
used as the actual chain ID. Otherwise, it's represented as the raw \
ASCII values. It must be a valid Cairo short string."
)]
#[arg(default_value = "SOLIS")]
#[arg(value_parser = ChainId::parse)]
pub chain_id: ChainId,
#[arg(long)]
#[arg(help = "The maximum number of steps available for the account validation logic.")]
#[arg(default_value_t = DEFAULT_VALIDATE_MAX_STEPS)]
pub validate_max_steps: u32,
#[arg(long)]
#[arg(help = "The maximum number of steps available for the account execution logic.")]
#[arg(default_value_t = DEFAULT_INVOKE_MAX_STEPS)]
pub invoke_max_steps: u32,
#[arg(long = "eth-gas-price")]
#[arg(conflicts_with = "genesis")]
#[arg(help = "The L1 ETH gas price. (denominated in wei)")]
#[arg(default_value_t = DEFAULT_ETH_L1_GAS_PRICE)]
pub l1_eth_gas_price: u128,
#[arg(long = "strk-gas-price")]
#[arg(conflicts_with = "genesis")]
#[arg(help = "The L1 STRK gas price. (denominated in fri)")]
#[arg(default_value_t = DEFAULT_STRK_L1_GAS_PRICE)]
pub l1_strk_gas_price: u128,
}
impl KatanaArgs {
pub fn init_logging(&self) -> Result<(), Box<dyn std::error::Error>> {
const DEFAULT_LOG_FILTER: &str = "info,executor=trace,forked_backend=trace,server=debug,\
katana_core=trace,blockifier=off,jsonrpsee_server=off,\
hyper=off,messaging=debug,node=error";
let builder = fmt::Subscriber::builder().with_env_filter(
EnvFilter::try_from_default_env().or(EnvFilter::try_new(DEFAULT_LOG_FILTER))?,
);
let subscriber: Box<dyn Subscriber + Send + Sync> = if self.json_log {
Box::new(builder.json().finish())
} else {
Box::new(builder.finish())
};
Ok(tracing::subscriber::set_global_default(subscriber)?)
}
pub fn sequencer_config(&self) -> SequencerConfig {
SequencerConfig {
block_time: self.block_time,
no_mining: self.no_mining,
#[cfg(feature = "messaging")]
messaging: self.messaging.clone(),
}
}
pub fn server_config(&self) -> ServerConfig {
let mut apis = vec![
ApiKind::Starknet,
ApiKind::Katana,
ApiKind::Torii,
ApiKind::Saya,
ApiKind::Solis,
];
// only enable `katana` API in dev mode
if self.dev {
apis.push(ApiKind::Dev);
}
let rpc_user = env::var("RPC_USER").unwrap_or_else(|_| "userDefault".to_string());
let rpc_password =
env::var("RPC_PASSWORD").unwrap_or_else(|_| "passwordDefault".to_string());
ServerConfig {
apis,
port: self.server.port,
host: self.server.host.clone().unwrap_or("0.0.0.0".into()),
max_connections: self.server.max_connections,
allowed_origins: self.server.allowed_origins.clone(),
rpc_user,
rpc_password,
}
}
pub fn starknet_config(&self) -> StarknetConfig {
let genesis = match self.starknet.genesis.clone() {
Some(genesis) => genesis,
None => {
let gas_prices = GasPrices {
eth: self.starknet.environment.l1_eth_gas_price,
strk: self.starknet.environment.l1_strk_gas_price,
};
let accounts = DevAllocationsGenerator::new(self.starknet.total_accounts)
.with_seed(parse_seed(&self.starknet.seed))
.with_balance(U256::from(DEFAULT_PREFUNDED_ACCOUNT_BALANCE))
.generate();
let mut genesis = Genesis {
gas_prices,
sequencer_address: *DEFAULT_SEQUENCER_ADDRESS,
..Default::default()
};
genesis.extend_allocations(accounts.into_iter().map(|(k, v)| (k, v.into())));
genesis
}
};
StarknetConfig {
disable_fee: self.starknet.disable_fee,
disable_validate: self.starknet.disable_validate,
fork_rpc_url: self.rpc_url.clone(),
fork_block_number: self.fork_block_number,
env: Environment {
chain_id: self.starknet.environment.chain_id,
invoke_max_steps: self.starknet.environment.invoke_max_steps,
validate_max_steps: self.starknet.environment.validate_max_steps,
},
db_dir: self.db_dir.clone(),
genesis,
}
}
}
// #[cfg(test)]
// mod test {
// use super::*;
// #[test]
// fn test_starknet_config_default() {
// let args = KatanaArgs::parse_from(["katana"]);
// let config = args.starknet_config();
// assert!(!config.disable_fee);
// assert!(!config.disable_validate);
// assert_eq!(config.fork_rpc_url, None);
// assert_eq!(config.fork_block_number, None);
// assert_eq!(config.env.chain_id, ChainId::parse("KATANA").unwrap());
// assert_eq!(config.env.invoke_max_steps, DEFAULT_INVOKE_MAX_STEPS);
// assert_eq!(config.env.validate_max_steps, DEFAULT_VALIDATE_MAX_STEPS);
// assert_eq!(config.db_dir, None);
// assert_eq!(config.genesis.gas_prices.eth, DEFAULT_ETH_L1_GAS_PRICE);
// assert_eq!(config.genesis.gas_prices.strk, DEFAULT_STRK_L1_GAS_PRICE);
// assert_eq!(config.genesis.sequencer_address, *DEFAULT_SEQUENCER_ADDRESS);
// }
// #[test]
// fn test_starknet_config_custom() {
// let args = KatanaArgs::parse_from([
// "katana",
// "--disable-fee",
// "--disable-validate",
// "--chain-id",
// "SN_GOERLI",
// "--invoke-max-steps",
// "200",
// "--validate-max-steps",
// "100",
// "--db-dir",
// "/path/to/db",
// "--eth-gas-price",
// "10",
// "--strk-gas-price",
// "20",
// ]);
// let config = args.starknet_config();
// assert!(config.disable_fee);
// assert!(config.disable_validate);
// assert_eq!(config.env.chain_id, ChainId::GOERLI);
// assert_eq!(config.env.invoke_max_steps, 200);
// assert_eq!(config.env.validate_max_steps, 100);
// assert_eq!(config.db_dir, Some(PathBuf::from("/path/to/db")));
// assert_eq!(config.genesis.gas_prices.eth, 10);
// assert_eq!(config.genesis.gas_prices.strk, 20);
// }
// }