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 {
20
    cumulus_client_parachain_inherent::{MockValidationDataInherentDataProvider, MockXcmConfig},
21
    cumulus_client_service::prepare_node_config,
22
    cumulus_primitives_core::{
23
        relay_chain::well_known_keys as RelayWellKnownKeys, CollectCollationInfo, ParaId,
24
    },
25
    dancebox_runtime::opaque::Block,
26
    node_common::service::node_builder::{ManualSealConfiguration, NodeBuilderConfig, Sealing},
27
    pallet_registrar_runtime_api::RegistrarApi,
28
    parity_scale_codec::{Decode, Encode},
29
    polkadot_cli::ProvideRuntimeApi,
30
    polkadot_parachain_primitives::primitives::HeadData,
31
    polkadot_primitives::UpgradeGoAhead,
32
    sc_client_api::{AuxStore, HeaderBackend},
33
    sc_service::{Configuration, TaskManager},
34
    sc_telemetry::TelemetryHandle,
35
    sp_consensus_slots::Slot,
36
    sp_core::H256,
37
    std::sync::Arc,
38
    tc_service_container_chain_spawner::service::{DevParachainBlockImport, ParachainClient},
39
    tc_service_orchestrator_chain::parachain::NodeConfig,
40
};
41

            
42
mod mocked_relay_keys;
43

            
44
// We use this to detect whether randomness is activated
45
const RANDOMNESS_ACTIVATED_AUX_KEY: &[u8] = b"__DEV_RANDOMNESS_ACTIVATED";
46

            
47
const CONTAINER_CHAINS_EXCLUSION_AUX_KEY: &[u8] = b"__DEV_CONTAINER_CHAINS_EXCLUSION";
48

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

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

            
66
    async fn try_handle_error(
67
        &self,
68
        _identifier: &sp_inherents::InherentIdentifier,
69
        _error: &[u8],
70
    ) -> Option<Result<(), sp_inherents::Error>> {
71
        // The pallet never reports error.
72
        None
73
    }
74
}
75

            
76
/// Build the import queue for the parachain runtime (manual seal).
77
198
fn build_manual_seal_import_queue(
78
198
    _client: Arc<ParachainClient>,
79
198
    block_import: DevParachainBlockImport,
80
198
    config: &Configuration,
81
198
    _telemetry: Option<TelemetryHandle>,
82
198
    task_manager: &TaskManager,
83
198
) -> Result<sc_consensus::DefaultImportQueue<Block>, sc_service::Error> {
84
198
    Ok(sc_consensus_manual_seal::import_queue(
85
198
        Box::new(block_import),
86
198
        &task_manager.spawn_essential_handle(),
87
198
        config.prometheus_registry(),
88
198
    ))
89
198
}
90

            
91
pub const SOFT_DEADLINE_PERCENT: sp_runtime::Percent = sp_runtime::Percent::from_percent(100);
92

            
93
/// Start a node with the given parachain `Configuration` and relay chain `Configuration`.
94
///
95
/// This is the actual implementation that is abstract over the executor and the runtime api.
96
#[sc_tracing::logging::prefix_logs_with("Orchestrator Dev Node")]
97
pub fn start_dev_node(
98
    orchestrator_config: Configuration,
99
    sealing: Sealing,
100
    hwbench: Option<sc_sysinfo::HwBench>,
101
    para_id: ParaId,
102
) -> sc_service::error::Result<TaskManager> {
103
    let parachain_config = prepare_node_config(orchestrator_config);
104

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

            
108
    // This node block import.
109
    let block_import = DevParachainBlockImport::new(node_builder.client.clone());
110
    let import_queue = build_manual_seal_import_queue(
111
        node_builder.client.clone(),
112
        block_import.clone(),
113
        &parachain_config,
114
        node_builder
115
            .telemetry
116
            .as_ref()
117
            .map(|telemetry| telemetry.handle()),
118
        &node_builder.task_manager,
119
    )?;
120

            
121
    // Build a Substrate Network. (not cumulus since it is a dev node, it mocks
122
    // the relaychain)
123
    let mut node_builder = node_builder
124
        .build_substrate_network::<sc_network::NetworkWorker<_, _>>(
125
            &parachain_config,
126
            import_queue,
127
        )?;
128

            
129
    // If we're running a collator dev node we must install manual seal block
130
    // production.
131
    let mut command_sink = None;
132
    let mut xcm_senders = None;
133
    let mut randomness_sender = None;
134
    let mut container_chains_exclusion_sender = None;
135
    if parachain_config.role.is_authority() {
136
        let client = node_builder.client.clone();
137
        let (downward_xcm_sender, downward_xcm_receiver) = flume::bounded::<Vec<u8>>(100);
138
        let (hrmp_xcm_sender, hrmp_xcm_receiver) = flume::bounded::<(ParaId, Vec<u8>)>(100);
139
        // Create channels for mocked parachain candidates.
140
        let (mock_randomness_sender, mock_randomness_receiver) =
141
            flume::bounded::<(bool, Option<[u8; 32]>)>(100);
142
        // Create channels for mocked exclusion of parachains from producing blocks
143
        let (mock_container_chains_exclusion_sender, mock_container_chains_exclusion_receiver) =
144
            flume::bounded::<Vec<ParaId>>(100);
145

            
146
        xcm_senders = Some((downward_xcm_sender, hrmp_xcm_sender));
147
        randomness_sender = Some(mock_randomness_sender);
148
        container_chains_exclusion_sender = Some(mock_container_chains_exclusion_sender);
149

            
150
        command_sink = node_builder.install_manual_seal(ManualSealConfiguration {
151
            block_import,
152
            sealing,
153
            soft_deadline: Some(SOFT_DEADLINE_PERCENT),
154
            select_chain: sc_consensus::LongestChain::new(node_builder.backend.clone()),
155
            consensus_data_provider: Some(Box::new(
156
                tc_consensus::OrchestratorManualSealAuraConsensusDataProvider::new(
157
                    node_builder.client.clone(),
158
                    node_builder.keystore_container.keystore(),
159
                    para_id,
160
                ),
161
            )),
162
7904
            create_inherent_data_providers: move |block: H256, ()| {
163
7904
                let current_para_block = client
164
7904
                    .number(block)
165
7904
                    .expect("Header lookup should succeed")
166
7904
                    .expect("Header passed in as parent should be present in backend.");
167

            
168
7904
                let mut para_ids: Vec<ParaId> = client
169
7904
                    .runtime_api()
170
7904
                    .registered_paras(block)
171
7904
                    .expect("registered_paras runtime API should exist")
172
7904
                    .into_iter()
173
7904
                    .collect();
174

            
175
7904
                let hash = client
176
7904
                    .hash(current_para_block.saturating_sub(1))
177
7904
                    .expect("Hash of the desired block must be present")
178
7904
                    .expect("Hash of the desired block should exist");
179

            
180
7904
                let para_header = client
181
7904
                    .expect_header(hash)
182
7904
                    .expect("Expected parachain header should exist")
183
7904
                    .encode();
184

            
185
7904
                let para_head_data = HeadData(para_header).encode();
186
7904
                let para_head_key = RelayWellKnownKeys::para_head(para_id);
187
7904
                let relay_slot_key = RelayWellKnownKeys::CURRENT_SLOT.to_vec();
188

            
189
7904
                let slot_duration = sc_consensus_aura::standalone::slot_duration_at(
190
7904
                    &*client.clone(),
191
7904
                    block,
192
7904
                ).expect("Slot duration should be set");
193

            
194
7904
                let mut timestamp = 0u64;
195
7904
                TIMESTAMP.with(|x| {
196
7904
                    timestamp = *x.borrow();
197
7904
                });
198

            
199
7904
                timestamp += dancebox_runtime::SLOT_DURATION;
200
7904
                let relay_slot = sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_slot_duration(
201
7904
						timestamp.into(),
202
7904
						slot_duration,
203
                    );
204
7904
                let relay_slot = u64::from(*relay_slot);
205

            
206
7904
                let downward_xcm_receiver = downward_xcm_receiver.clone();
207
7904
                let hrmp_xcm_receiver = hrmp_xcm_receiver.clone();
208

            
209
7904
                let randomness_enabler_messages: Vec<(bool, Option<[u8; 32]>)> = mock_randomness_receiver.drain().collect();
210

            
211
                // If there is a value to be updated, we update it
212
7904
                if let Some((enable_randomness, new_seed)) = randomness_enabler_messages.last() {
213
4
                    let value = client
214
4
                        .get_aux(RANDOMNESS_ACTIVATED_AUX_KEY)
215
4
                        .expect("Should be able to query aux storage; qed").unwrap_or((false, Option::<[u8; 32]>::None).encode());
216
4
                    let (_mock_additional_randomness, mut mock_randomness_seed): (bool, Option<[u8; 32]>) = Decode::decode(&mut value.as_slice()).expect("Boolean non-decodable");
217

            
218
4
                    if let Some(new_seed) = new_seed {
219
2
                        mock_randomness_seed = Some(*new_seed);
220
2
                    }
221

            
222
4
                    client
223
4
                    .insert_aux(
224
4
                        &[(RANDOMNESS_ACTIVATED_AUX_KEY, (enable_randomness, mock_randomness_seed).encode().as_slice())],
225
4
                        &[],
226
4
                    )
227
4
                    .expect("Should be able to write to aux storage; qed");
228
7900
                }
229

            
230
                // We read the value
231
                // If error when reading, we simply put false
232
7904
                let value = client
233
7904
                    .get_aux(RANDOMNESS_ACTIVATED_AUX_KEY)
234
7904
                    .expect("Should be able to query aux storage; qed").unwrap_or((false, Option::<[u8; 32]>::None).encode());
235
7904
                let (mock_additional_randomness, mock_randomness_seed): (bool, Option<[u8; 32]>) = Decode::decode(&mut value.as_slice()).expect("Boolean non-decodable");
236

            
237
7904
                let container_chains_exclusion_messages: Vec<Vec<ParaId>> = mock_container_chains_exclusion_receiver.drain().collect();
238
                // If there is a new set of excluded container chains, we update it
239
7904
                if let Some(mock_excluded_container_chains) = container_chains_exclusion_messages.last() {
240
2
                    client
241
2
                        .insert_aux(
242
2
                            &[(CONTAINER_CHAINS_EXCLUSION_AUX_KEY, mock_excluded_container_chains.encode().as_slice())],
243
2
                            &[],
244
2
                        )
245
2
                        .expect("Should be able to write to aux storage; qed");
246
7902
                }
247
7904
                let new_excluded_container_chains_value = client
248
7904
                    .get_aux(CONTAINER_CHAINS_EXCLUSION_AUX_KEY)
249
7904
                    .expect("Should be able to query aux storage; qed").unwrap_or(Vec::<ParaId>::new().encode());
250
7904
                let mock_excluded_container_chains: Vec<ParaId> = Decode::decode(&mut new_excluded_container_chains_value.as_slice()).expect("Vector non-decodable");
251
15582
                para_ids.retain(|x| !mock_excluded_container_chains.contains(x));
252
7904
                let client_set_aside_for_cidp = client.clone();
253
7904
                let client_for_xcm = client.clone();
254
7904
                async move {
255
7904
                    let mocked_author_noting =
256
7904
                        tp_author_noting_inherent::MockAuthorNotingInherentDataProvider {
257
7904
                            current_para_block,
258
7904
                            relay_offset: 1000,
259
7904
                            relay_blocks_per_para_block: 2,
260
7904
                            para_ids,
261
7904
                            slots_per_para_block: 1,
262
7904
                        };
263
7904
                    let mut additional_keys = mocked_author_noting.get_key_values();
264
                    // Mock only chain 2002 in relay.
265
                    // This will allow any signed origin to deregister chains 2000 and 2001, and register 2002.
266
7904
                    let (registrar_paras_key_2002, para_info_2002) = mocked_relay_keys::get_mocked_registrar_paras(2002.into());
267
7904
                    additional_keys.extend([(para_head_key, para_head_data), (relay_slot_key, Slot::from(relay_slot).encode()), (registrar_paras_key_2002, para_info_2002)]);
268

            
269
7904
                    if mock_additional_randomness {
270
200
                        let mut mock_randomness: [u8; 32] = [0u8; 32];
271
200
                        mock_randomness[..4].copy_from_slice(&current_para_block.to_be_bytes());
272
200
                        if let Some(seed) = mock_randomness_seed {
273
3300
                            for i in 0..32 {
274
3200
                                mock_randomness[i] ^= seed[i];
275
3200
                            }
276
100
                        }
277
200
                        additional_keys.extend([(RelayWellKnownKeys::CURRENT_BLOCK_RANDOMNESS.to_vec(), Some(mock_randomness).encode())]);
278
200
                        log::info!("mokcing randomnessss!!! {}", current_para_block);
279
7704
                    }
280

            
281
7904
                    let current_para_head = client_set_aside_for_cidp
282
7904
                            .header(block)
283
7904
                            .expect("Header lookup should succeed")
284
7904
                            .expect("Header passed in as parent should be present in backend.");
285
7904
                    let should_send_go_ahead = match client_set_aside_for_cidp
286
7904
                            .runtime_api()
287
7904
                            .collect_collation_info(block, &current_para_head)
288
                    {
289
7904
                            Ok(info) => info.new_validation_code.is_some(),
290
                            Err(e) => {
291
                                    log::error!("Failed to collect collation info: {:?}", e);
292
                                    false
293
                            },
294
                    };
295

            
296
7904
                    let time = MockTimestampInherentDataProvider;
297
7904
                    let mocked_parachain = MockValidationDataInherentDataProvider {
298
7904
                        current_para_block,
299
7904
                        current_para_block_head: None,
300
                        relay_offset: 1000,
301
                        relay_blocks_per_para_block: 2,
302
                        para_blocks_per_relay_epoch: 10,
303
7904
                        relay_randomness_config: (),
304
7904
                        xcm_config: MockXcmConfig::new(
305
7904
                            &*client_for_xcm,
306
7904
                            block,
307
7904
                            Default::default(),
308
                        ),
309
7904
                        raw_downward_messages: downward_xcm_receiver.drain().collect(),
310
7904
                        raw_horizontal_messages: hrmp_xcm_receiver.drain().collect(),
311
7904
                        additional_key_values: Some(additional_keys),
312
7904
                        para_id,
313
7904
                        upgrade_go_ahead: should_send_go_ahead.then(|| {
314
2
                            log::info!(
315
2
                                "Detected pending validation code, sending go-ahead signal."
316
                            );
317
2
                            UpgradeGoAhead::GoAhead
318
2
                        }),
319
                    };
320

            
321
7904
                    Ok((time, mocked_parachain, mocked_author_noting))
322
7904
                }
323
7904
            },
324
        })?;
325
    }
326

            
327
    // This node RPC builder.
328
    let rpc_builder = {
329
        let client = node_builder.client.clone();
330
        let transaction_pool = node_builder.transaction_pool.clone();
331

            
332
396
        Box::new(move |_| {
333
396
            let deps = tc_service_orchestrator_chain::parachain::rpc::FullDeps {
334
396
                client: client.clone(),
335
396
                pool: transaction_pool.clone(),
336
396
                command_sink: command_sink.clone(),
337
396
                xcm_senders: xcm_senders.clone(),
338
396
                randomness_sender: randomness_sender.clone(),
339
396
                container_chain_exclusion_sender: container_chains_exclusion_sender.clone(),
340
396
            };
341

            
342
396
            tc_service_orchestrator_chain::parachain::rpc::create_full(deps).map_err(Into::into)
343
396
        })
344
    };
345

            
346
    // We spawn all the common substrate tasks to properly run a node.
347
    let node_builder = node_builder.spawn_common_tasks(parachain_config, rpc_builder)?;
348

            
349
    log::info!("Development Service Ready");
350

            
351
    Ok(node_builder.task_manager)
352
}
353

            
354
/// Can be called for a `Configuration` to check if it is a configuration for
355
/// the orchestrator network.
356
pub trait IdentifyVariant {
357
    /// Returns `true` if this is a configuration for a dev network.
358
    fn is_dev(&self) -> bool;
359
}
360

            
361
impl IdentifyVariant for Box<dyn sc_service::ChainSpec> {
362
198
    fn is_dev(&self) -> bool {
363
198
        self.chain_type() == sc_chain_spec::ChainType::Development
364
198
    }
365
}