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
    crate::cli::RelayChainCli,
19
    parity_scale_codec::Encode,
20
    sc_chain_spec::construct_genesis_block,
21
    sc_cli::{
22
        ChainSpec, CliConfiguration, DefaultConfigurationValues, ImportParams, KeystoreParams,
23
        NetworkParams, Result, SharedParams, SubstrateCli,
24
    },
25
    sc_service::config::{BasePath, PrometheusConfig},
26
    sp_runtime::{
27
        traits::{Block as BlockT, Get, Hash as HashT, Header as HeaderT},
28
        StateVersion,
29
    },
30
    std::result::Result as StdResult,
31
};
32

            
33
/// Generate the genesis block from a given ChainSpec.
34
pub fn generate_genesis_block<Block: BlockT>(
35
    chain_spec: &dyn ChainSpec,
36
    genesis_state_version: StateVersion,
37
) -> StdResult<Block, String> {
38
    let storage = chain_spec.build_storage()?;
39

            
40
    let child_roots = storage.children_default.iter().map(|(sk, child_content)| {
41
        let state_root = <<<Block as BlockT>::Header as HeaderT>::Hashing as HashT>::trie_root(
42
            child_content.data.clone().into_iter().collect(),
43
            genesis_state_version,
44
        );
45
        (sk.clone(), state_root.encode())
46
    });
47
    let state_root = <<<Block as BlockT>::Header as HeaderT>::Hashing as HashT>::trie_root(
48
        storage.top.clone().into_iter().chain(child_roots).collect(),
49
        genesis_state_version,
50
    );
51

            
52
    Ok(construct_genesis_block(state_root, genesis_state_version))
53
}
54

            
55
impl<N: Get<&'static str>> DefaultConfigurationValues for RelayChainCli<N> {
56
    fn p2p_listen_port() -> u16 {
57
        30334
58
    }
59

            
60
    fn rpc_listen_port() -> u16 {
61
        9945
62
    }
63

            
64
    fn prometheus_listen_port() -> u16 {
65
        9616
66
    }
67
}
68

            
69
impl<N: Get<&'static str>> CliConfiguration<Self> for RelayChainCli<N> {
70
    fn shared_params(&self) -> &SharedParams {
71
        self.base.base.shared_params()
72
    }
73

            
74
    fn import_params(&self) -> Option<&ImportParams> {
75
        self.base.base.import_params()
76
    }
77

            
78
    fn network_params(&self) -> Option<&NetworkParams> {
79
        self.base.base.network_params()
80
    }
81

            
82
    fn keystore_params(&self) -> Option<&KeystoreParams> {
83
        self.base.base.keystore_params()
84
    }
85

            
86
    fn base_path(&self) -> Result<Option<BasePath>> {
87
        Ok(self
88
            .shared_params()
89
            .base_path()?
90
            .or_else(|| Some(self.base_path.clone().into())))
91
    }
92

            
93
    fn rpc_addr(&self, default_listen_port: u16) -> Result<Option<Vec<sc_cli::RpcEndpoint>>> {
94
        self.base.base.rpc_addr(default_listen_port)
95
    }
96

            
97
    fn prometheus_config(
98
        &self,
99
        default_listen_port: u16,
100
        chain_spec: &Box<dyn ChainSpec>,
101
    ) -> Result<Option<PrometheusConfig>> {
102
        self.base
103
            .base
104
            .prometheus_config(default_listen_port, chain_spec)
105
    }
106

            
107
    fn init<F>(&self, _support_url: &String, _impl_version: &String, _logger_hook: F) -> Result<()>
108
    where
109
        F: FnOnce(&mut sc_cli::LoggerBuilder),
110
    {
111
        unreachable!("PolkadotCli is never initialized; qed");
112
    }
113

            
114
    fn chain_id(&self, is_dev: bool) -> Result<String> {
115
        let chain_id = self.base.base.chain_id(is_dev)?;
116

            
117
        Ok(if chain_id.is_empty() {
118
            self.chain_id.clone().unwrap_or_default()
119
        } else {
120
            chain_id
121
        })
122
    }
123

            
124
    fn role(&self, is_dev: bool) -> Result<sc_service::Role> {
125
        self.base.base.role(is_dev)
126
    }
127

            
128
    fn transaction_pool(&self, is_dev: bool) -> Result<sc_service::config::TransactionPoolOptions> {
129
        self.base.base.transaction_pool(is_dev)
130
    }
131

            
132
    fn trie_cache_maximum_size(&self) -> Result<Option<usize>> {
133
        self.base.base.trie_cache_maximum_size()
134
    }
135

            
136
    fn rpc_methods(&self) -> Result<sc_service::config::RpcMethods> {
137
        self.base.base.rpc_methods()
138
    }
139

            
140
    fn rpc_max_connections(&self) -> Result<u32> {
141
        self.base.base.rpc_max_connections()
142
    }
143

            
144
    fn rpc_cors(&self, is_dev: bool) -> Result<Option<Vec<String>>> {
145
        self.base.base.rpc_cors(is_dev)
146
    }
147

            
148
    fn default_heap_pages(&self) -> Result<Option<u64>> {
149
        self.base.base.default_heap_pages()
150
    }
151

            
152
    fn force_authoring(&self) -> Result<bool> {
153
        self.base.base.force_authoring()
154
    }
155

            
156
    fn disable_grandpa(&self) -> Result<bool> {
157
        self.base.base.disable_grandpa()
158
    }
159

            
160
    fn max_runtime_instances(&self) -> Result<Option<usize>> {
161
        self.base.base.max_runtime_instances()
162
    }
163

            
164
    fn announce_block(&self) -> Result<bool> {
165
        self.base.base.announce_block()
166
    }
167

            
168
    fn telemetry_endpoints(
169
        &self,
170
        chain_spec: &Box<dyn ChainSpec>,
171
    ) -> Result<Option<sc_telemetry::TelemetryEndpoints>> {
172
        self.base.base.telemetry_endpoints(chain_spec)
173
    }
174

            
175
    fn node_name(&self) -> Result<String> {
176
        self.base.base.node_name()
177
    }
178
}
179

            
180
impl<N: Get<&'static str>> SubstrateCli for RelayChainCli<N> {
181
    fn impl_version() -> String {
182
        option_env!("SUBSTRATE_CLI_IMPL_VERSION")
183
            .unwrap_or("Unknown version")
184
            .into()
185
    }
186

            
187
    fn author() -> String {
188
        option_env!("CARGO_PKG_AUTHORS")
189
            .unwrap_or("Unknown authors")
190
            .into()
191
    }
192

            
193
    fn support_url() -> String {
194
        "https://github.com/paritytech/cumulus/issues/new".into()
195
    }
196

            
197
    fn copyright_start_year() -> i32 {
198
        2020
199
    }
200

            
201
    fn load_spec(&self, id: &str) -> std::result::Result<Box<dyn sc_service::ChainSpec>, String> {
202
        polkadot_cli::Cli::from_iter([Self::executable_name()].iter()).load_spec(id)
203
    }
204

            
205
    fn impl_name() -> String {
206
        format!("Container Chain {} Node", N::get())
207
    }
208

            
209
    fn description() -> String {
210
        format!(
211
            "Container Chain {} Node\n\nThe command-line arguments provided first will be \
212
        passed to the parachain node, while the arguments provided after -- will be passed \
213
        to the relay chain node.\n\n\
214
        {} <parachain-args> -- <relay-chain-args>",
215
            N::get(),
216
            RelayChainCli::<N>::executable_name()
217
        )
218
    }
219
}