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
#[allow(deprecated)]
20
use {
21
    container_chain_template_simple_runtime::{opaque::Block, RuntimeApi},
22
    cumulus_client_cli::CollatorOptions,
23
    cumulus_client_consensus_common::ParachainBlockImport as TParachainBlockImport,
24
    cumulus_client_parachain_inherent::{MockValidationDataInherentDataProvider, MockXcmConfig},
25
    cumulus_client_service::{prepare_node_config, ParachainHostFunctions},
26
    cumulus_primitives_core::{relay_chain::well_known_keys as RelayWellKnownKeys, ParaId},
27
    nimbus_primitives::NimbusId,
28
    node_common::service::ManualSealConfiguration,
29
    node_common::service::Sealing,
30
    node_common::service::{NodeBuilder, NodeBuilderConfig},
31
    parity_scale_codec::Encode,
32
    polkadot_parachain_primitives::primitives::HeadData,
33
    sc_consensus::BasicQueue,
34
    sc_executor::WasmExecutor,
35
    sc_service::{Configuration, TFullBackend, TFullClient, TaskManager},
36
    sp_blockchain::HeaderBackend,
37
    sp_consensus_slots::{Slot, SlotDuration},
38
    sp_core::Pair,
39
    sp_core::H256,
40
    std::{sync::Arc, time::Duration},
41
};
42

            
43
type ParachainExecutor = WasmExecutor<ParachainHostFunctions>;
44
type ParachainClient = TFullClient<Block, RuntimeApi, ParachainExecutor>;
45
type ParachainBackend = TFullBackend<Block>;
46
type ParachainBlockImport = TParachainBlockImport<Block, Arc<ParachainClient>, ParachainBackend>;
47

            
48
pub struct NodeConfig;
49
impl NodeBuilderConfig for NodeConfig {
50
    type Block = Block;
51
    type RuntimeApi = RuntimeApi;
52
    type ParachainExecutor = ParachainExecutor;
53
}
54

            
55
thread_local!(static TIMESTAMP: std::cell::RefCell<u64> = const { std::cell::RefCell::new(0) });
56

            
57
/// Provide a mock duration starting at 0 in millisecond for timestamp inherent.
58
/// Each call will increment timestamp by slot_duration making Aura think time has passed.
59
struct MockTimestampInherentDataProvider;
60
#[async_trait::async_trait]
61
impl sp_inherents::InherentDataProvider for MockTimestampInherentDataProvider {
62
    async fn provide_inherent_data(
63
        &self,
64
        inherent_data: &mut sp_inherents::InherentData,
65
528
    ) -> Result<(), sp_inherents::Error> {
66
528
        TIMESTAMP.with(|x| {
67
528
            *x.borrow_mut() += container_chain_template_simple_runtime::SLOT_DURATION;
68
528
            inherent_data.put_data(sp_timestamp::INHERENT_IDENTIFIER, &*x.borrow())
69
528
        })
70
1056
    }
71

            
72
    async fn try_handle_error(
73
        &self,
74
        _identifier: &sp_inherents::InherentIdentifier,
75
        _error: &[u8],
76
    ) -> Option<Result<(), sp_inherents::Error>> {
77
        // The pallet never reports error.
78
        None
79
    }
80
}
81

            
82
64
pub fn import_queue(
83
64
    parachain_config: &Configuration,
84
64
    node_builder: &NodeBuilder<NodeConfig>,
85
64
) -> (ParachainBlockImport, BasicQueue<Block>) {
86
64
    // The nimbus import queue ONLY checks the signature correctness
87
64
    // Any other checks corresponding to the author-correctness should be done
88
64
    // in the runtime
89
64
    let block_import =
90
64
        ParachainBlockImport::new(node_builder.client.clone(), node_builder.backend.clone());
91
64

            
92
64
    let import_queue = nimbus_consensus::import_queue(
93
64
        node_builder.client.clone(),
94
64
        block_import.clone(),
95
64
        move |_, _| async move {
96
            let time = sp_timestamp::InherentDataProvider::from_system_time();
97

            
98
            Ok((time,))
99
64
        },
100
64
        &node_builder.task_manager.spawn_essential_handle(),
101
64
        parachain_config.prometheus_registry(),
102
64
        false,
103
64
    )
104
64
    .expect("function never fails");
105
64

            
106
64
    (block_import, import_queue)
107
64
}
108

            
109
/// Start a node with the given parachain `Configuration` and relay chain `Configuration`.
110
///
111
/// This is the actual implementation that is abstract over the executor and the runtime api.
112
#[sc_tracing::logging::prefix_logs_with("Parachain")]
113
pub async fn start_parachain_node(
114
    parachain_config: Configuration,
115
    polkadot_config: Configuration,
116
    collator_options: CollatorOptions,
117
    para_id: ParaId,
118
    hwbench: Option<sc_sysinfo::HwBench>,
119
) -> sc_service::error::Result<(TaskManager, Arc<ParachainClient>)> {
120
    let parachain_config = prepare_node_config(parachain_config);
121

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

            
125
    let (_, import_queue) = import_queue(&parachain_config, &node_builder);
126

            
127
    // Relay chain interface
128
    let (relay_chain_interface, _collator_key) = node_builder
129
        .build_relay_chain_interface(&parachain_config, polkadot_config, collator_options.clone())
130
        .await?;
131

            
132
    // Build cumulus network, allowing to access network-related services.
133
    let node_builder = node_builder
134
        .build_cumulus_network::<_, sc_network::NetworkWorker<_, _>>(
135
            &parachain_config,
136
            para_id,
137
            import_queue,
138
            relay_chain_interface.clone(),
139
        )
140
        .await?;
141

            
142
    let rpc_builder = {
143
        let client = node_builder.client.clone();
144
        let transaction_pool = node_builder.transaction_pool.clone();
145

            
146
        Box::new(move |deny_unsafe, _| {
147
            let deps = crate::rpc::FullDeps {
148
                client: client.clone(),
149
                pool: transaction_pool.clone(),
150
                deny_unsafe,
151
                command_sink: None,
152
                xcm_senders: None,
153
            };
154

            
155
            crate::rpc::create_full(deps).map_err(Into::into)
156
        })
157
    };
158

            
159
    let node_builder = node_builder.spawn_common_tasks(parachain_config, rpc_builder)?;
160

            
161
    let relay_chain_slot_duration = Duration::from_secs(6);
162
    let node_builder = node_builder.start_full_node(
163
        para_id,
164
        relay_chain_interface.clone(),
165
        relay_chain_slot_duration,
166
    )?;
167

            
168
    node_builder.network.start_network.start_network();
169

            
170
    Ok((node_builder.task_manager, node_builder.client))
171
}
172

            
173
/// Helper function to generate a crypto pair from seed
174
64
fn get_aura_id_from_seed(seed: &str) -> NimbusId {
175
64
    sp_core::sr25519::Pair::from_string(&format!("//{}", seed), None)
176
64
        .expect("static values are valid; qed")
177
64
        .public()
178
64
        .into()
179
64
}
180

            
181
/// Start a node with the given parachain `Configuration` and relay chain `Configuration`.
182
///
183
/// This is the actual implementation that is abstract over the executor and the runtime api.
184
#[sc_tracing::logging::prefix_logs_with("Parachain Dev Node")]
185
pub async fn start_dev_node(
186
    parachain_config: Configuration,
187
    sealing: Sealing,
188
    para_id: ParaId,
189
    hwbench: Option<sc_sysinfo::HwBench>,
190
) -> sc_service::error::Result<TaskManager> {
191
    let parachain_config = prepare_node_config(parachain_config);
192

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

            
196
    let (parachain_block_import, import_queue) = import_queue(&parachain_config, &node_builder);
197

            
198
    // Build a Substrate Network. (not cumulus since it is a dev node, it mocks
199
    // the relaychain)
200
    let mut node_builder = node_builder
201
        .build_substrate_network::<sc_network::NetworkWorker<_, _>>(
202
            &parachain_config,
203
            import_queue,
204
        )?;
205

            
206
    let mut command_sink = None;
207
    let mut xcm_senders = None;
208

            
209
    if parachain_config.role.is_authority() {
210
        let client = node_builder.client.clone();
211
        let (downward_xcm_sender, downward_xcm_receiver) = flume::bounded::<Vec<u8>>(100);
212
        let (hrmp_xcm_sender, hrmp_xcm_receiver) = flume::bounded::<(ParaId, Vec<u8>)>(100);
213
        xcm_senders = Some((downward_xcm_sender, hrmp_xcm_sender));
214

            
215
        let authorities = vec![get_aura_id_from_seed("alice")];
216

            
217
        command_sink = node_builder.install_manual_seal(ManualSealConfiguration {
218
            block_import: parachain_block_import,
219
            sealing,
220
            soft_deadline: None,
221
            select_chain: sc_consensus::LongestChain::new(node_builder.backend.clone()),
222
            consensus_data_provider: Some(Box::new(
223
                tc_consensus::ContainerManualSealAuraConsensusDataProvider::new(
224
                    SlotDuration::from_millis(
225
                        container_chain_template_simple_runtime::SLOT_DURATION,
226
                    ),
227
                    authorities.clone(),
228
                ),
229
            )),
230
528
            create_inherent_data_providers: move |block: H256, ()| {
231
528
                let current_para_block = client
232
528
                    .number(block)
233
528
                    .expect("Header lookup should succeed")
234
528
                    .expect("Header passed in as parent should be present in backend.");
235
528

            
236
528
                let hash = client
237
528
                    .hash(current_para_block.saturating_sub(1))
238
528
                    .expect("Hash of the desired block must be present")
239
528
                    .expect("Hash of the desired block should exist");
240
528

            
241
528
                let para_header = client
242
528
                    .expect_header(hash)
243
528
                    .expect("Expected parachain header should exist")
244
528
                    .encode();
245
528

            
246
528
                let para_head_data: Vec<u8> = HeadData(para_header).encode();
247
528
                let client_for_xcm = client.clone();
248
528
                let authorities_for_cidp = authorities.clone();
249
528
                let para_head_key = RelayWellKnownKeys::para_head(para_id);
250
528
                let relay_slot_key = RelayWellKnownKeys::CURRENT_SLOT.to_vec();
251
528
                let slot_duration = container_chain_template_simple_runtime::SLOT_DURATION;
252
528

            
253
528
                let mut timestamp = 0u64;
254
528
                TIMESTAMP.with(|x| {
255
528
                    timestamp = x.clone().take();
256
528
                });
257
528

            
258
528
                timestamp += slot_duration;
259
528

            
260
528
                let relay_slot = sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_slot_duration(
261
528
						timestamp.into(),
262
528
						SlotDuration::from_millis(slot_duration),
263
528
                    );
264
528
                let relay_slot = u64::from(*relay_slot);
265
528

            
266
528
                let downward_xcm_receiver = downward_xcm_receiver.clone();
267
528
                let hrmp_xcm_receiver = hrmp_xcm_receiver.clone();
268

            
269
528
                async move {
270
528
                    let mocked_authorities_noting =
271
528
                        ccp_authorities_noting_inherent::MockAuthoritiesNotingInherentDataProvider {
272
528
                            current_para_block,
273
528
                            relay_offset: 1000,
274
528
                            relay_blocks_per_para_block: 2,
275
528
                            orchestrator_para_id: crate::chain_spec::ORCHESTRATOR,
276
528
                            container_para_id: para_id,
277
528
                            authorities: authorities_for_cidp
278
528
                    };
279
528

            
280
528
                    let mut additional_keys = mocked_authorities_noting.get_key_values();
281
528
                    additional_keys.append(&mut vec![(para_head_key, para_head_data), (relay_slot_key, Slot::from(relay_slot).encode())]);
282
528

            
283
528
                    let time = MockTimestampInherentDataProvider;
284
528
                    let mocked_parachain = MockValidationDataInherentDataProvider {
285
528
                        current_para_block,
286
528
                        current_para_block_head: None,
287
528
                        relay_offset: 1000,
288
528
                        relay_blocks_per_para_block: 2,
289
528
                        // TODO: Recheck
290
528
                        para_blocks_per_relay_epoch: 10,
291
528
                        relay_randomness_config: (),
292
528
                        xcm_config: MockXcmConfig::new(
293
528
                            &*client_for_xcm,
294
528
                            block,
295
528
                            Default::default(),
296
528
                        ),
297
528
                        raw_downward_messages: downward_xcm_receiver.drain().collect(),
298
528
                        raw_horizontal_messages: hrmp_xcm_receiver.drain().collect(),
299
528
                        additional_key_values: Some(additional_keys),
300
528
                        para_id,
301
528
                    };
302
528

            
303
528
                    Ok((time, mocked_parachain, mocked_authorities_noting))
304
528
                }
305
528
            },
306
        })?;
307
    }
308

            
309
    let rpc_builder = {
310
        let client = node_builder.client.clone();
311
        let transaction_pool = node_builder.transaction_pool.clone();
312

            
313
128
        Box::new(move |deny_unsafe, _| {
314
128
            let deps = crate::rpc::FullDeps {
315
128
                client: client.clone(),
316
128
                pool: transaction_pool.clone(),
317
128
                deny_unsafe,
318
128
                command_sink: command_sink.clone(),
319
128
                xcm_senders: xcm_senders.clone(),
320
128
            };
321
128

            
322
128
            crate::rpc::create_full(deps).map_err(Into::into)
323
128
        })
324
    };
325

            
326
    let node_builder = node_builder.spawn_common_tasks(parachain_config, rpc_builder)?;
327

            
328
    log::info!("Development Service Ready");
329

            
330
    node_builder.network.start_network.start_network();
331

            
332
    Ok(node_builder.task_manager)
333
}