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
//! Service and ServiceFactory implementation. Specialized wrapper over substrate service.
18

            
19
use node_common::timestamp::MockTimestampInherentDataProvider;
20
use {
21
    container_chain_template_simple_runtime::Hash,
22
    container_chain_template_simple_runtime::{opaque::Block, RuntimeApi},
23
    cumulus_client_cli::CollatorOptions,
24
    cumulus_client_consensus_common::ParachainBlockImport as TParachainBlockImport,
25
    cumulus_client_parachain_inherent::{MockValidationDataInherentDataProvider, MockXcmConfig},
26
    cumulus_client_service::{prepare_node_config, ParachainHostFunctions},
27
    cumulus_primitives_core::{
28
        relay_chain::well_known_keys as RelayWellKnownKeys, CollectCollationInfo, ParaId,
29
    },
30
    nimbus_primitives::NimbusId,
31
    node_common::service::node_builder::{
32
        ManualSealConfiguration, NodeBuilder, NodeBuilderConfig, Sealing,
33
    },
34
    parity_scale_codec::Encode,
35
    polkadot_parachain_primitives::primitives::HeadData,
36
    polkadot_primitives::UpgradeGoAhead,
37
    sc_consensus::BasicQueue,
38
    sc_executor::WasmExecutor,
39
    sc_network::NetworkBackend,
40
    sc_service::{Configuration, TFullBackend, TFullClient, TaskManager},
41
    sp_api::ProvideRuntimeApi,
42
    sp_blockchain::HeaderBackend,
43
    sp_consensus_slots::{Slot, SlotDuration},
44
    sp_core::{Pair, H256},
45
    std::{sync::Arc, time::Duration},
46
};
47

            
48
type ParachainExecutor = WasmExecutor<ParachainHostFunctions>;
49
type ParachainClient = TFullClient<Block, RuntimeApi, ParachainExecutor>;
50
type ParachainBackend = TFullBackend<Block>;
51
type ParachainBlockImport = TParachainBlockImport<Block, Arc<ParachainClient>, ParachainBackend>;
52

            
53
pub struct NodeConfig;
54
impl NodeBuilderConfig for NodeConfig {
55
    type Block = Block;
56
    type RuntimeApi = RuntimeApi;
57
    type ParachainExecutor = ParachainExecutor;
58
}
59

            
60
const RELAY_CHAIN_SLOT_DURATION_MILLIS: u64 = 6_000;
61

            
62
80
pub fn import_queue(
63
80
    parachain_config: &Configuration,
64
80
    node_builder: &NodeBuilder<NodeConfig>,
65
80
) -> (ParachainBlockImport, BasicQueue<Block>) {
66
    // The nimbus import queue ONLY checks the signature correctness
67
    // Any other checks corresponding to the author-correctness should be done
68
    // in the runtime
69
80
    let block_import =
70
80
        ParachainBlockImport::new(node_builder.client.clone(), node_builder.backend.clone());
71

            
72
80
    let import_queue = nimbus_consensus::import_queue(
73
80
        node_builder.client.clone(),
74
80
        block_import.clone(),
75
        move |_, _| async move {
76
            let time = sp_timestamp::InherentDataProvider::from_system_time();
77

            
78
            Ok((time,))
79
        },
80
80
        &node_builder.task_manager.spawn_essential_handle(),
81
80
        parachain_config.prometheus_registry(),
82
        false,
83
        false,
84
    )
85
80
    .expect("function never fails");
86

            
87
80
    (block_import, import_queue)
88
80
}
89

            
90
/// Start a node with the given parachain `Configuration` and relay chain `Configuration`.
91
///
92
/// This is the actual implementation that is abstract over the executor and the runtime api.
93
#[sc_tracing::logging::prefix_logs_with("Parachain")]
94
pub async fn start_parachain_node<Net>(
95
    parachain_config: Configuration,
96
    polkadot_config: Configuration,
97
    collator_options: CollatorOptions,
98
    para_id: ParaId,
99
    hwbench: Option<sc_sysinfo::HwBench>,
100
) -> sc_service::error::Result<(TaskManager, Arc<ParachainClient>)>
101
where
102
    Net: NetworkBackend<Block, Hash>,
103
{
104
    let parachain_config = prepare_node_config(parachain_config);
105

            
106
    // Create a `NodeBuilder` which helps setup parachain nodes common systems.
107
    let mut node_builder = NodeConfig::new_builder(&parachain_config, hwbench.clone())?;
108

            
109
    let (_, import_queue) = import_queue(&parachain_config, &node_builder);
110

            
111
    // Relay chain interface
112
    let (relay_chain_interface, _collator_key, start_bootnode_params) = node_builder
113
        .build_relay_chain_interface(&parachain_config, polkadot_config, collator_options.clone())
114
        .await?;
115

            
116
    // Build cumulus network, allowing to access network-related services.
117
    let node_builder = node_builder
118
        .build_cumulus_network::<_, Net>(
119
            &parachain_config,
120
            para_id,
121
            import_queue,
122
            relay_chain_interface.clone(),
123
        )
124
        .await?;
125

            
126
    let rpc_builder = {
127
        let client = node_builder.client.clone();
128
        let transaction_pool = node_builder.transaction_pool.clone();
129

            
130
        Box::new(move |_| {
131
            let deps = crate::rpc::FullDeps {
132
                client: client.clone(),
133
                pool: transaction_pool.clone(),
134
                command_sink: None,
135
                xcm_senders: None,
136
            };
137

            
138
            crate::rpc::create_full(deps).map_err(Into::into)
139
        })
140
    };
141

            
142
    let node_builder = node_builder.spawn_common_tasks(parachain_config, rpc_builder)?;
143

            
144
    let relay_chain_slot_duration = Duration::from_secs(6);
145
    let node_builder = node_builder.start_full_node(
146
        para_id,
147
        relay_chain_interface.clone(),
148
        relay_chain_slot_duration,
149
        start_bootnode_params,
150
    )?;
151

            
152
    Ok((node_builder.task_manager, node_builder.client))
153
}
154

            
155
/// Helper function to generate a crypto pair from seed
156
80
fn get_aura_id_from_seed(seed: &str) -> NimbusId {
157
80
    sp_core::sr25519::Pair::from_string(&format!("//{}", seed), None)
158
80
        .expect("static values are valid; qed")
159
80
        .public()
160
80
        .into()
161
80
}
162

            
163
/// Start a node with the given parachain `Configuration` and relay chain `Configuration`.
164
///
165
/// This is the actual implementation that is abstract over the executor and the runtime api.
166
#[sc_tracing::logging::prefix_logs_with("Parachain Dev Node")]
167
pub async fn start_dev_node(
168
    parachain_config: Configuration,
169
    sealing: Sealing,
170
    para_id: ParaId,
171
    hwbench: Option<sc_sysinfo::HwBench>,
172
) -> sc_service::error::Result<TaskManager> {
173
    let parachain_config = prepare_node_config(parachain_config);
174

            
175
    // Create a `NodeBuilder` which helps setup parachain nodes common systems.
176
    let node_builder = NodeConfig::new_builder(&parachain_config, hwbench.clone())?;
177

            
178
    let (parachain_block_import, import_queue) = import_queue(&parachain_config, &node_builder);
179

            
180
    // Build a Substrate Network. (not cumulus since it is a dev node, it mocks
181
    // the relaychain)
182
    let mut node_builder = node_builder
183
        .build_substrate_network::<sc_network::NetworkWorker<_, _>>(
184
            &parachain_config,
185
            import_queue,
186
        )?;
187

            
188
    let mut command_sink = None;
189
    let mut xcm_senders = None;
190

            
191
    if parachain_config.role.is_authority() {
192
        let client = node_builder.client.clone();
193
        let (downward_xcm_sender, downward_xcm_receiver) = flume::bounded::<Vec<u8>>(100);
194
        let (hrmp_xcm_sender, hrmp_xcm_receiver) = flume::bounded::<(ParaId, Vec<u8>)>(100);
195
        xcm_senders = Some((downward_xcm_sender, hrmp_xcm_sender));
196

            
197
        let authorities = vec![get_aura_id_from_seed("alice")];
198

            
199
        command_sink = node_builder.install_manual_seal(ManualSealConfiguration {
200
            block_import: parachain_block_import,
201
            sealing,
202
            soft_deadline: None,
203
            select_chain: sc_consensus::LongestChain::new(node_builder.backend.clone()),
204
            consensus_data_provider: Some(Box::new(
205
                tc_consensus::ContainerManualSealAuraConsensusDataProvider::new(
206
                    SlotDuration::from_millis(
207
                        container_chain_template_simple_runtime::SLOT_DURATION,
208
                    ),
209
                    authorities.clone(),
210
                ),
211
            )),
212
600
            create_inherent_data_providers: move |block: H256, ()| {
213
600
                MockTimestampInherentDataProvider::advance_timestamp(
214
                    RELAY_CHAIN_SLOT_DURATION_MILLIS,
215
                );
216

            
217
600
                let current_para_block = client
218
600
                    .number(block)
219
600
                    .expect("Header lookup should succeed")
220
600
                    .expect("Header passed in as parent should be present in backend.");
221

            
222
600
                let hash = client
223
600
                    .hash(current_para_block.saturating_sub(1))
224
600
                    .expect("Hash of the desired block must be present")
225
600
                    .expect("Hash of the desired block should exist");
226

            
227
600
                let para_header = client
228
600
                    .expect_header(hash)
229
600
                    .expect("Expected parachain header should exist")
230
600
                    .encode();
231

            
232
600
                let para_head_data: Vec<u8> = HeadData(para_header).encode();
233
600
                let client_set_aside_for_cidp = client.clone();
234
600
                let client_for_xcm = client.clone();
235
600
                let authorities_for_cidp = authorities.clone();
236
600
                let para_head_key = RelayWellKnownKeys::para_head(para_id);
237
600
                let relay_slot_key = RelayWellKnownKeys::CURRENT_SLOT.to_vec();
238

            
239
                // Get the mocked timestamp
240
600
                let timestamp = MockTimestampInherentDataProvider::load();
241
                // Calculate mocked slot number
242
600
                let relay_slot = sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_slot_duration(
243
600
                    timestamp.into(),
244
600
                    SlotDuration::from_millis(RELAY_CHAIN_SLOT_DURATION_MILLIS),
245
                );
246
600
                let relay_slot = u64::from(*relay_slot);
247

            
248
600
                let downward_xcm_receiver = downward_xcm_receiver.clone();
249
600
                let hrmp_xcm_receiver = hrmp_xcm_receiver.clone();
250

            
251
600
                async move {
252
600
                    let mocked_authorities_noting =
253
600
                        ccp_authorities_noting_inherent::MockAuthoritiesNotingInherentDataProvider {
254
600
                            current_para_block,
255
600
                            relay_offset: 1000,
256
600
                            relay_blocks_per_para_block: 2,
257
600
                            orchestrator_para_id: container_chain_template_simple_runtime::genesis_config_presets::ORCHESTRATOR,
258
600
                            container_para_id: para_id,
259
600
                            authorities: authorities_for_cidp,
260
600
                        };
261

            
262
600
                    let mut additional_keys = mocked_authorities_noting.get_key_values();
263
600
                    additional_keys.append(&mut vec![(para_head_key, para_head_data), (relay_slot_key, Slot::from(relay_slot).encode())]);
264

            
265
600
                    let time = MockTimestampInherentDataProvider;
266
600
                    let current_para_head = client_set_aside_for_cidp
267
600
                        .header(block)
268
600
                        .expect("Header lookup should succeed")
269
600
                        .expect("Header passed in as parent should be present in backend.");
270
600
                    let should_send_go_ahead = match client_set_aside_for_cidp
271
600
                        .runtime_api()
272
600
                        .collect_collation_info(block, &current_para_head)
273
                    {
274
600
                        Ok(info) => info.new_validation_code.is_some(),
275
                        Err(e) => {
276
                            log::error!("Failed to collect collation info: {:?}", e);
277
                            false
278
                        }
279
                    };
280

            
281
600
                    let mocked_parachain = MockValidationDataInherentDataProvider {
282
600
                        current_para_block,
283
600
                        current_para_block_head: None,
284
                        relay_offset: 1000,
285
                        relay_blocks_per_para_block: 2,
286
                        // TODO: Recheck
287
                        para_blocks_per_relay_epoch: 10,
288
600
                        relay_randomness_config: (),
289
600
                        xcm_config: MockXcmConfig::new(
290
600
                            &*client_for_xcm,
291
600
                            block,
292
600
                            Default::default(),
293
                        ),
294
600
                        raw_downward_messages: downward_xcm_receiver.drain().collect(),
295
600
                        raw_horizontal_messages: hrmp_xcm_receiver.drain().collect(),
296
600
                        additional_key_values: Some(additional_keys),
297
600
                        para_id,
298
600
                        upgrade_go_ahead: should_send_go_ahead.then(|| {
299
2
                            log::info!(
300
2
                                "Detected pending validation code, sending go-ahead signal."
301
                            );
302
2
                            UpgradeGoAhead::GoAhead
303
2
                        }),
304
                    };
305

            
306
600
                    Ok((time, mocked_parachain, mocked_authorities_noting))
307
600
                }
308
600
            },
309
        })?;
310
    }
311

            
312
    let rpc_builder = {
313
        let client = node_builder.client.clone();
314
        let transaction_pool = node_builder.transaction_pool.clone();
315

            
316
160
        Box::new(move |_| {
317
160
            let deps = crate::rpc::FullDeps {
318
160
                client: client.clone(),
319
160
                pool: transaction_pool.clone(),
320
160
                command_sink: command_sink.clone(),
321
160
                xcm_senders: xcm_senders.clone(),
322
160
            };
323

            
324
160
            crate::rpc::create_full(deps).map_err(Into::into)
325
160
        })
326
    };
327

            
328
    let node_builder = node_builder.spawn_common_tasks(parachain_config, rpc_builder)?;
329

            
330
    log::info!("Development Service Ready");
331

            
332
    Ok(node_builder.task_manager)
333
}