1
// Copyright (C) Moondance Labs Ltd.
2
// This file is part of Tanssi.
3

            
4
// Tanssi is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8

            
9
// Tanssi is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13

            
14
// You should have received a copy of the GNU General Public License
15
// along with Tanssi.  If not, see <http://www.gnu.org/licenses/>.
16

            
17
use {
18
    node_common::service::Sealing,
19
    sc_cli::{CliConfiguration, NodeKeyParams, SharedParams},
20
    std::path::PathBuf,
21
    tc_service_container_chain::cli::ContainerChainRunCmd,
22
};
23

            
24
/// Sub-commands supported by the collator.
25
#[derive(Debug, clap::Subcommand)]
26
#[allow(clippy::large_enum_variant)]
27
pub enum Subcommand {
28
    /// Build a chain specification.
29
    BuildSpec(BuildSpecCmd),
30

            
31
    /// Validate blocks.
32
    CheckBlock(sc_cli::CheckBlockCmd),
33

            
34
    /// Export blocks.
35
    ExportBlocks(sc_cli::ExportBlocksCmd),
36

            
37
    /// Export the state of a given block into a chain spec.
38
    ExportState(sc_cli::ExportStateCmd),
39

            
40
    /// Import blocks.
41
    ImportBlocks(sc_cli::ImportBlocksCmd),
42

            
43
    /// Revert the chain to a previous state.
44
    Revert(sc_cli::RevertCmd),
45

            
46
    /// Remove the whole chain.
47
    PurgeChain(cumulus_client_cli::PurgeChainCmd),
48

            
49
    /// Export the genesis state of the parachain.
50
    #[command(alias = "export-genesis-state")]
51
    ExportGenesisHead(cumulus_client_cli::ExportGenesisHeadCommand),
52

            
53
    /// Export the genesis wasm of the parachain.
54
    ExportGenesisWasm(ExportGenesisWasmCommand),
55

            
56
    /// Sub-commands concerned with benchmarking.
57
    /// The pallet benchmarking moved to the `pallet` sub-command.
58
    #[command(subcommand)]
59
    Benchmark(frame_benchmarking_cli::BenchmarkCmd),
60

            
61
    /// Key management cli utilities
62
    #[command(subcommand)]
63
    Key(KeyCmd),
64

            
65
    /// Precompile the WASM runtime into native code
66
    PrecompileWasm(sc_cli::PrecompileWasmCmd),
67

            
68
    /// Solochain collator mode
69
    SoloChain(SoloChainCmd),
70
}
71

            
72
/// The `build-spec` command used to build a specification.
73
#[derive(Debug, clap::Parser)]
74
#[group(skip)]
75
pub struct SoloChainCmd {
76
    #[command(flatten)]
77
    pub run: ContainerChainRunCmd,
78

            
79
    /// Disable automatic hardware benchmarks.
80
    ///
81
    /// By default these benchmarks are automatically ran at startup and measure
82
    /// the CPU speed, the memory bandwidth and the disk speed.
83
    ///
84
    /// The results are then printed out in the logs, and also sent as part of
85
    /// telemetry, if telemetry is enabled.
86
    #[arg(long)]
87
    pub no_hardware_benchmarks: bool,
88

            
89
    /// Relay chain arguments
90
    #[arg(raw = true)]
91
    pub relay_chain_args: Vec<String>,
92
}
93

            
94
/// The `build-spec` command used to build a specification.
95
#[derive(Debug, Clone, clap::Parser)]
96
#[group(skip)]
97
pub struct BuildSpecCmd {
98
    #[clap(flatten)]
99
    pub base: sc_cli::BuildSpecCmd,
100

            
101
    /// Id of the parachain this spec is for. Note that this overrides the `--chain` param.
102
    #[arg(long)]
103
    pub parachain_id: Option<u32>,
104

            
105
    /// List of container chain chain spec paths to add to genesis.
106
    #[arg(long)]
107
    pub add_container_chain: Option<Vec<String>>,
108

            
109
    /// List of container chain chain spec mocks to add to genesis.
110
    #[arg(long)]
111
2
    pub mock_container_chain: Option<Vec<u32>>,
112

            
113
    /// List of invulnerable collators to write to pallet_invulnerables genesis.
114
    #[arg(long)]
115
    pub invulnerable: Option<Vec<String>>,
116
}
117

            
118
impl CliConfiguration for BuildSpecCmd {
119
48
    fn shared_params(&self) -> &SharedParams {
120
48
        &self.base.shared_params
121
48
    }
122

            
123
4
    fn node_key_params(&self) -> Option<&NodeKeyParams> {
124
4
        Some(&self.base.node_key_params)
125
4
    }
126
}
127

            
128
/// Command for exporting the genesis wasm file.
129
#[derive(Debug, clap::Parser)]
130
pub struct ExportGenesisWasmCommand {
131
    /// Output file name or stdout if unspecified.
132
    pub output: Option<PathBuf>,
133

            
134
    /// Write output in binary. Default is to write in hex.
135
    #[arg(short, long)]
136
    pub raw: bool,
137

            
138
    /// The name of the chain for that the genesis wasm file should be exported.
139
    #[arg(long)]
140
    pub chain: Option<String>,
141
}
142

            
143
#[derive(Debug, clap::Parser)]
144
#[group(skip)]
145
pub struct RunCmd {
146
    #[clap(flatten)]
147
    pub base: cumulus_client_cli::RunCmd,
148

            
149
    /// Enable the development service to run without a backing relay chain
150
    #[arg(long)]
151
    pub dev_service: bool,
152

            
153
    /// When blocks should be sealed in the dev service.
154
    ///
155
    /// Options are "instant", "manual", or timer interval in milliseconds
156
    #[arg(long, default_value = "instant")]
157
    pub sealing: Sealing,
158

            
159
    /// Id of the parachain this collator collates for.
160
    #[arg(long)]
161
    pub parachain_id: Option<u32>,
162
}
163

            
164
impl std::ops::Deref for RunCmd {
165
    type Target = cumulus_client_cli::RunCmd;
166

            
167
362
    fn deref(&self) -> &Self::Target {
168
362
        &self.base
169
362
    }
170
}
171

            
172
#[derive(Debug, clap::Subcommand)]
173
pub enum KeyCmd {
174
    #[command(flatten)]
175
    BaseCli(sc_cli::KeySubcommand),
176
}
177

            
178
impl KeyCmd {
179
    /// run the key subcommands
180
    pub fn run<C: sc_cli::SubstrateCli>(&self, cli: &C) -> Result<(), sc_cli::Error> {
181
        match self {
182
            KeyCmd::BaseCli(cmd) => cmd.run(cli),
183
        }
184
    }
185
}
186

            
187
#[derive(Debug, clap::Parser)]
188
#[command(
189
    propagate_version = true,
190
    args_conflicts_with_subcommands = true,
191
    subcommand_negates_reqs = true
192
)]
193
pub struct Cli {
194
    #[command(subcommand)]
195
    pub subcommand: Option<Subcommand>,
196

            
197
    #[command(flatten)]
198
    pub run: RunCmd,
199

            
200
    /// Disable automatic hardware benchmarks.
201
    ///
202
    /// By default these benchmarks are automatically ran at startup and measure
203
    /// the CPU speed, the memory bandwidth and the disk speed.
204
    ///
205
    /// The results are then printed out in the logs, and also sent as part of
206
    /// telemetry, if telemetry is enabled.
207
    #[arg(long)]
208
    pub no_hardware_benchmarks: bool,
209

            
210
    /// Optional parachain id that should be used to build chain spec.
211
    #[arg(long)]
212
    pub para_id: Option<u32>,
213

            
214
    /// Extra arguments, `container-args -- relay-args` or `relay-args` if no `--`
215
    #[arg(raw = true)]
216
    extra_args: Vec<String>,
217
}
218

            
219
impl Cli {
220
178
    pub fn relaychain_args(&self) -> &[String] {
221
178
        let (relay_chain_args, _) = self.split_extra_args_at_first_dashdash();
222
178

            
223
178
        relay_chain_args
224
178
    }
225

            
226
    pub fn container_chain_args(&self) -> &[String] {
227
        let (_, container_chain_args) = self.split_extra_args_at_first_dashdash();
228

            
229
        container_chain_args
230
    }
231

            
232
178
    fn split_extra_args_at_first_dashdash(&self) -> (&[String], &[String]) {
233
178
        let index_of_dashdash = self.extra_args.iter().position(|x| *x == "--");
234

            
235
178
        if let Some(i) = index_of_dashdash {
236
            let (container_chain_args, extra_extra) = self.extra_args.split_at(i);
237
            (&extra_extra[1..], container_chain_args)
238
        } else {
239
            // Only relay chain args
240
178
            (&self.extra_args, &[])
241
        }
242
178
    }
243
}
244

            
245
#[derive(Debug)]
246
pub struct RelayChainCli {
247
    /// The actual relay chain cli object.
248
    pub base: polkadot_cli::RunCmd,
249

            
250
    /// Optional chain id that should be passed to the relay chain.
251
    pub chain_id: Option<String>,
252

            
253
    /// The base path that should be used by the relay chain.
254
    pub base_path: PathBuf,
255
}
256

            
257
impl RelayChainCli {
258
    /// Parse the relay chain CLI parameters using the para chain `Configuration`.
259
178
    pub fn new<'a>(
260
178
        para_config: &sc_service::Configuration,
261
178
        relay_chain_args: impl Iterator<Item = &'a String>,
262
178
    ) -> Self {
263
178
        let extension = crate::chain_spec::Extensions::try_get(&*para_config.chain_spec);
264
178
        let chain_id = extension.map(|e| e.relay_chain.clone());
265
178
        let base_path = para_config.base_path.path().join("polkadot");
266
178

            
267
178
        Self {
268
178
            base_path,
269
178
            chain_id,
270
178
            base: clap::Parser::parse_from(relay_chain_args),
271
178
        }
272
178
    }
273
}