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::{cli::BuildSpecCmd, service::Sealing},
19
    std::path::PathBuf,
20
    tc_service_container_chain::cli::ContainerChainRunCmd,
21
};
22

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

            
93
#[derive(Debug, Clone, clap::Args)]
94
pub struct BuildSpecCmdExtraFields {
95
    /// List of container chain chain spec paths to add to genesis.
96
    #[arg(long)]
97
    pub add_container_chain: Option<Vec<String>>,
98

            
99
    /// List of container chain chain spec mocks to add to genesis.
100
    #[arg(long)]
101
2
    pub mock_container_chain: Option<Vec<u32>>,
102

            
103
    /// List of invulnerable collators to write to pallet_invulnerables genesis.
104
    #[arg(long)]
105
    pub invulnerable: Option<Vec<String>>,
106

            
107
    #[arg(long)]
108
    pub parachain_id: Option<u32>,
109
}
110

            
111
pub type BuildSpecCmdCollator = BuildSpecCmd<BuildSpecCmdExtraFields>;
112

            
113
/// Command for exporting the genesis wasm file.
114
#[derive(Debug, clap::Parser)]
115
pub struct ExportGenesisWasmCommand {
116
    /// Output file name or stdout if unspecified.
117
    pub output: Option<PathBuf>,
118

            
119
    /// Write output in binary. Default is to write in hex.
120
    #[arg(short, long)]
121
    pub raw: bool,
122

            
123
    /// The name of the chain for that the genesis wasm file should be exported.
124
    #[arg(long)]
125
    pub chain: Option<String>,
126
}
127

            
128
#[derive(Debug, clap::Parser)]
129
#[group(skip)]
130
pub struct RunCmd {
131
    #[clap(flatten)]
132
    pub base: cumulus_client_cli::RunCmd,
133

            
134
    /// Enable the development service to run without a backing relay chain
135
    #[arg(long)]
136
    pub dev_service: bool,
137

            
138
    /// When blocks should be sealed in the dev service.
139
    ///
140
    /// Options are "instant", "manual", or timer interval in milliseconds
141
    #[arg(long, default_value = "instant")]
142
    pub sealing: Sealing,
143

            
144
    /// Id of the parachain this collator collates for.
145
    #[arg(long)]
146
    pub parachain_id: Option<u32>,
147
}
148

            
149
impl std::ops::Deref for RunCmd {
150
    type Target = cumulus_client_cli::RunCmd;
151

            
152
398
    fn deref(&self) -> &Self::Target {
153
398
        &self.base
154
398
    }
155
}
156

            
157
#[derive(Debug, clap::Subcommand)]
158
pub enum KeyCmd {
159
    #[command(flatten)]
160
    BaseCli(sc_cli::KeySubcommand),
161
}
162

            
163
impl KeyCmd {
164
    /// run the key subcommands
165
    pub fn run<C: sc_cli::SubstrateCli>(&self, cli: &C) -> Result<(), sc_cli::Error> {
166
        match self {
167
            KeyCmd::BaseCli(cmd) => cmd.run(cli),
168
        }
169
    }
170
}
171

            
172
#[derive(Debug, clap::Parser)]
173
#[command(
174
    propagate_version = true,
175
    args_conflicts_with_subcommands = true,
176
    subcommand_negates_reqs = true
177
)]
178
pub struct Cli {
179
    #[command(subcommand)]
180
    pub subcommand: Option<Subcommand>,
181

            
182
    #[command(flatten)]
183
    pub run: RunCmd,
184

            
185
    /// Disable automatic hardware benchmarks.
186
    ///
187
    /// By default these benchmarks are automatically ran at startup and measure
188
    /// the CPU speed, the memory bandwidth and the disk speed.
189
    ///
190
    /// The results are then printed out in the logs, and also sent as part of
191
    /// telemetry, if telemetry is enabled.
192
    #[arg(long)]
193
    pub no_hardware_benchmarks: bool,
194

            
195
    /// Optional parachain id that should be used to build chain spec.
196
    #[arg(long)]
197
    pub para_id: Option<u32>,
198

            
199
    /// Extra arguments, `container-args -- relay-args` or `relay-args` if no `--`
200
    #[arg(raw = true)]
201
    extra_args: Vec<String>,
202
}
203

            
204
impl Cli {
205
196
    pub fn relaychain_args(&self) -> &[String] {
206
196
        let (relay_chain_args, _) = self.split_extra_args_at_first_dashdash();
207
196

            
208
196
        relay_chain_args
209
196
    }
210

            
211
    pub fn container_chain_args(&self) -> &[String] {
212
        let (_, container_chain_args) = self.split_extra_args_at_first_dashdash();
213

            
214
        container_chain_args
215
    }
216

            
217
196
    fn split_extra_args_at_first_dashdash(&self) -> (&[String], &[String]) {
218
196
        let index_of_dashdash = self.extra_args.iter().position(|x| *x == "--");
219

            
220
196
        if let Some(i) = index_of_dashdash {
221
            let (container_chain_args, extra_extra) = self.extra_args.split_at(i);
222
            (&extra_extra[1..], container_chain_args)
223
        } else {
224
            // Only relay chain args
225
196
            (&self.extra_args, &[])
226
        }
227
196
    }
228
}
229

            
230
#[derive(Debug)]
231
pub struct RelayChainCli {
232
    /// The actual relay chain cli object.
233
    pub base: polkadot_cli::RunCmd,
234

            
235
    /// Optional chain id that should be passed to the relay chain.
236
    pub chain_id: Option<String>,
237

            
238
    /// The base path that should be used by the relay chain.
239
    pub base_path: PathBuf,
240

            
241
    /// Is this a tanssi solochain? Used to select default chain spec.
242
    pub solochain: bool,
243
}
244

            
245
impl RelayChainCli {
246
    /// Parse the relay chain CLI parameters using the para chain `Configuration`.
247
196
    pub fn new<'a>(
248
196
        para_config: &sc_service::Configuration,
249
196
        relay_chain_args: impl Iterator<Item = &'a String>,
250
196
    ) -> Self {
251
196
        let extension = crate::chain_spec::Extensions::try_get(&*para_config.chain_spec);
252
196
        let chain_id = extension.map(|e| e.relay_chain.clone());
253
196
        let base_path = para_config.base_path.path().join("polkadot");
254
196

            
255
196
        Self {
256
196
            base_path,
257
196
            chain_id,
258
196
            base: clap::Parser::parse_from(relay_chain_args),
259
196
            solochain: false,
260
196
        }
261
196
    }
262
}