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
    /// EXPERIMENTAL: This is meant to be used only if collator is overshooting the PoV size, and
149
    /// building blocks that do not fit in the max_pov_size. It is a percentage of the max_pov_size
150
    /// configuration of the relay-chain.
151
    ///
152
    /// It will be removed once <https://github.com/paritytech/polkadot-sdk/issues/6020> is fixed.
153
    #[arg(long)]
154
    pub experimental_max_pov_percentage: Option<u32>,
155
}
156

            
157
impl std::ops::Deref for RunCmd {
158
    type Target = cumulus_client_cli::RunCmd;
159

            
160
394
    fn deref(&self) -> &Self::Target {
161
394
        &self.base
162
394
    }
163
}
164

            
165
#[derive(Debug, clap::Subcommand)]
166
pub enum KeyCmd {
167
    #[command(flatten)]
168
    BaseCli(sc_cli::KeySubcommand),
169
}
170

            
171
impl KeyCmd {
172
    /// run the key subcommands
173
    pub fn run<C: sc_cli::SubstrateCli>(&self, cli: &C) -> Result<(), sc_cli::Error> {
174
        match self {
175
            KeyCmd::BaseCli(cmd) => cmd.run(cli),
176
        }
177
    }
178
}
179

            
180
#[derive(Debug, clap::Parser)]
181
#[command(
182
    propagate_version = true,
183
    args_conflicts_with_subcommands = true,
184
    subcommand_negates_reqs = true
185
)]
186
pub struct Cli {
187
    #[command(subcommand)]
188
    pub subcommand: Option<Subcommand>,
189

            
190
    #[command(flatten)]
191
    pub run: RunCmd,
192

            
193
    /// Disable automatic hardware benchmarks.
194
    ///
195
    /// By default these benchmarks are automatically ran at startup and measure
196
    /// the CPU speed, the memory bandwidth and the disk speed.
197
    ///
198
    /// The results are then printed out in the logs, and also sent as part of
199
    /// telemetry, if telemetry is enabled.
200
    #[arg(long)]
201
    pub no_hardware_benchmarks: bool,
202

            
203
    /// Optional parachain id that should be used to build chain spec.
204
    #[arg(long)]
205
    pub para_id: Option<u32>,
206

            
207
    /// Extra arguments, `container-args -- relay-args` or `relay-args` if no `--`
208
    #[arg(raw = true)]
209
    extra_args: Vec<String>,
210
}
211

            
212
impl Cli {
213
194
    pub fn relaychain_args(&self) -> &[String] {
214
194
        let (relay_chain_args, _) = self.split_extra_args_at_first_dashdash();
215
194

            
216
194
        relay_chain_args
217
194
    }
218

            
219
    pub fn container_chain_args(&self) -> &[String] {
220
        let (_, container_chain_args) = self.split_extra_args_at_first_dashdash();
221

            
222
        container_chain_args
223
    }
224

            
225
194
    fn split_extra_args_at_first_dashdash(&self) -> (&[String], &[String]) {
226
194
        let index_of_dashdash = self.extra_args.iter().position(|x| *x == "--");
227

            
228
194
        if let Some(i) = index_of_dashdash {
229
            let (container_chain_args, extra_extra) = self.extra_args.split_at(i);
230
            (&extra_extra[1..], container_chain_args)
231
        } else {
232
            // Only relay chain args
233
194
            (&self.extra_args, &[])
234
        }
235
194
    }
236
}
237

            
238
#[derive(Debug)]
239
pub struct RelayChainCli {
240
    /// The actual relay chain cli object.
241
    pub base: polkadot_cli::RunCmd,
242

            
243
    /// Optional chain id that should be passed to the relay chain.
244
    pub chain_id: Option<String>,
245

            
246
    /// The base path that should be used by the relay chain.
247
    pub base_path: PathBuf,
248
}
249

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

            
260
194
        Self {
261
194
            base_path,
262
194
            chain_id,
263
194
            base: clap::Parser::parse_from(relay_chain_args),
264
194
        }
265
194
    }
266
}