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

            
43
mod mocked_relay_keys;
44

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

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

            
50
/// Build the import queue for the parachain runtime (manual seal).
51
200
fn build_manual_seal_import_queue(
52
200
    _client: Arc<ParachainClient>,
53
200
    block_import: DevParachainBlockImport,
54
200
    config: &Configuration,
55
200
    _telemetry: Option<TelemetryHandle>,
56
200
    task_manager: &TaskManager,
57
200
) -> Result<sc_consensus::DefaultImportQueue<Block>, sc_service::Error> {
58
200
    Ok(sc_consensus_manual_seal::import_queue(
59
200
        Box::new(block_import),
60
200
        &task_manager.spawn_essential_handle(),
61
200
        config.prometheus_registry(),
62
200
    ))
63
200
}
64

            
65
pub const SOFT_DEADLINE_PERCENT: sp_runtime::Percent = sp_runtime::Percent::from_percent(100);
66

            
67
/// Start a node with the given parachain `Configuration` and relay chain `Configuration`.
68
///
69
/// This is the actual implementation that is abstract over the executor and the runtime api.
70
#[sc_tracing::logging::prefix_logs_with("Orchestrator Dev Node")]
71
pub fn start_dev_node(
72
    orchestrator_config: Configuration,
73
    sealing: Sealing,
74
    hwbench: Option<sc_sysinfo::HwBench>,
75
    para_id: ParaId,
76
) -> sc_service::error::Result<TaskManager> {
77
    let parachain_config = prepare_node_config(orchestrator_config);
78

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

            
82
    // This node block import.
83
    let block_import = DevParachainBlockImport::new(node_builder.client.clone());
84
    let import_queue = build_manual_seal_import_queue(
85
        node_builder.client.clone(),
86
        block_import.clone(),
87
        &parachain_config,
88
        node_builder
89
            .telemetry
90
            .as_ref()
91
            .map(|telemetry| telemetry.handle()),
92
        &node_builder.task_manager,
93
    )?;
94

            
95
    // Build a Substrate Network. (not cumulus since it is a dev node, it mocks
96
    // the relaychain)
97
    let mut node_builder = node_builder
98
        .build_substrate_network::<sc_network::NetworkWorker<_, _>>(
99
            &parachain_config,
100
            import_queue,
101
        )?;
102

            
103
    // If we're running a collator dev node we must install manual seal block
104
    // production.
105
    let mut command_sink = None;
106
    let mut xcm_senders = None;
107
    let mut randomness_sender = None;
108
    let mut container_chains_exclusion_sender = None;
109
    if parachain_config.role.is_authority() {
110
        let client = node_builder.client.clone();
111
        let (downward_xcm_sender, downward_xcm_receiver) = flume::bounded::<Vec<u8>>(100);
112
        let (hrmp_xcm_sender, hrmp_xcm_receiver) = flume::bounded::<(ParaId, Vec<u8>)>(100);
113
        // Create channels for mocked parachain candidates.
114
        let (mock_randomness_sender, mock_randomness_receiver) =
115
            flume::bounded::<(bool, Option<[u8; 32]>)>(100);
116
        // Create channels for mocked exclusion of parachains from producing blocks
117
        let (mock_container_chains_exclusion_sender, mock_container_chains_exclusion_receiver) =
118
            flume::bounded::<Vec<ParaId>>(100);
119

            
120
        xcm_senders = Some((downward_xcm_sender, hrmp_xcm_sender));
121
        randomness_sender = Some(mock_randomness_sender);
122
        container_chains_exclusion_sender = Some(mock_container_chains_exclusion_sender);
123

            
124
        command_sink = node_builder.install_manual_seal(ManualSealConfiguration {
125
            block_import,
126
            sealing,
127
            soft_deadline: Some(SOFT_DEADLINE_PERCENT),
128
            select_chain: sc_consensus::LongestChain::new(node_builder.backend.clone()),
129
            consensus_data_provider: Some(Box::new(
130
                tc_consensus::OrchestratorManualSealAuraConsensusDataProvider::new(
131
                    node_builder.client.clone(),
132
                    node_builder.keystore_container.keystore(),
133
                    para_id,
134
                ),
135
            )),
136
8004
            create_inherent_data_providers: move |block: H256, ()| {
137
8004
                let current_para_block = client
138
8004
                    .number(block)
139
8004
                    .expect("Header lookup should succeed")
140
8004
                    .expect("Header passed in as parent should be present in backend.");
141

            
142
8004
                let mut para_ids: Vec<ParaId> = client
143
8004
                    .runtime_api()
144
8004
                    .registered_paras(block)
145
8004
                    .expect("registered_paras runtime API should exist")
146
8004
                    .into_iter()
147
8004
                    .collect();
148

            
149
8004
                let hash = client
150
8004
                    .hash(current_para_block.saturating_sub(1))
151
8004
                    .expect("Hash of the desired block must be present")
152
8004
                    .expect("Hash of the desired block should exist");
153

            
154
8004
                let para_header = client
155
8004
                    .expect_header(hash)
156
8004
                    .expect("Expected parachain header should exist")
157
8004
                    .encode();
158

            
159
8004
                let para_head_data = HeadData(para_header).encode();
160
8004
                let para_head_key = RelayWellKnownKeys::para_head(para_id);
161
8004
                let relay_slot_key = RelayWellKnownKeys::CURRENT_SLOT.to_vec();
162

            
163
8004
                let slot_duration = sc_consensus_aura::standalone::slot_duration_at(
164
8004
                    &*client.clone(),
165
8004
                    block,
166
8004
                ).expect("Slot duration should be set");
167
8004
                MockTimestampInherentDataProvider::advance_timestamp(
168
8004
                    slot_duration.as_millis(),
169
                );
170

            
171
                // Get the mocked timestamp
172
8004
                let timestamp = MockTimestampInherentDataProvider::load();
173
                // Calculate mocked slot number
174
8004
                let relay_slot = sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_slot_duration(
175
8004
                    timestamp.into(),
176
8004
                    slot_duration,
177
                );
178
8004
                let relay_slot = u64::from(*relay_slot);
179

            
180
8004
                let downward_xcm_receiver = downward_xcm_receiver.clone();
181
8004
                let hrmp_xcm_receiver = hrmp_xcm_receiver.clone();
182

            
183
8004
                let randomness_enabler_messages: Vec<(bool, Option<[u8; 32]>)> = mock_randomness_receiver.drain().collect();
184

            
185
                // If there is a value to be updated, we update it
186
8004
                if let Some((enable_randomness, new_seed)) = randomness_enabler_messages.last() {
187
4
                    let value = client
188
4
                        .get_aux(RANDOMNESS_ACTIVATED_AUX_KEY)
189
4
                        .expect("Should be able to query aux storage; qed").unwrap_or((false, Option::<[u8; 32]>::None).encode());
190
4
                    let (_mock_additional_randomness, mut mock_randomness_seed): (bool, Option<[u8; 32]>) = Decode::decode(&mut value.as_slice()).expect("Boolean non-decodable");
191

            
192
4
                    if let Some(new_seed) = new_seed {
193
2
                        mock_randomness_seed = Some(*new_seed);
194
2
                    }
195

            
196
4
                    client
197
4
                    .insert_aux(
198
4
                        &[(RANDOMNESS_ACTIVATED_AUX_KEY, (enable_randomness, mock_randomness_seed).encode().as_slice())],
199
4
                        &[],
200
4
                    )
201
4
                    .expect("Should be able to write to aux storage; qed");
202
8000
                }
203

            
204
                // We read the value
205
                // If error when reading, we simply put false
206
8004
                let value = client
207
8004
                    .get_aux(RANDOMNESS_ACTIVATED_AUX_KEY)
208
8004
                    .expect("Should be able to query aux storage; qed").unwrap_or((false, Option::<[u8; 32]>::None).encode());
209
8004
                let (mock_additional_randomness, mock_randomness_seed): (bool, Option<[u8; 32]>) = Decode::decode(&mut value.as_slice()).expect("Boolean non-decodable");
210

            
211
8004
                let container_chains_exclusion_messages: Vec<Vec<ParaId>> = mock_container_chains_exclusion_receiver.drain().collect();
212
                // If there is a new set of excluded container chains, we update it
213
8004
                if let Some(mock_excluded_container_chains) = container_chains_exclusion_messages.last() {
214
2
                    client
215
2
                        .insert_aux(
216
2
                            &[(CONTAINER_CHAINS_EXCLUSION_AUX_KEY, mock_excluded_container_chains.encode().as_slice())],
217
2
                            &[],
218
2
                        )
219
2
                        .expect("Should be able to write to aux storage; qed");
220
8002
                }
221
8004
                let new_excluded_container_chains_value = client
222
8004
                    .get_aux(CONTAINER_CHAINS_EXCLUSION_AUX_KEY)
223
8004
                    .expect("Should be able to query aux storage; qed").unwrap_or(Vec::<ParaId>::new().encode());
224
8004
                let mock_excluded_container_chains: Vec<ParaId> = Decode::decode(&mut new_excluded_container_chains_value.as_slice()).expect("Vector non-decodable");
225
15726
                para_ids.retain(|x| !mock_excluded_container_chains.contains(x));
226
8004
                let client_set_aside_for_cidp = client.clone();
227
8004
                let client_for_xcm = client.clone();
228
8004
                async move {
229
8004
                    let mocked_author_noting =
230
8004
                        tp_author_noting_inherent::MockAuthorNotingInherentDataProvider {
231
8004
                            current_para_block,
232
8004
                            relay_offset: 1000,
233
8004
                            relay_blocks_per_para_block: 2,
234
8004
                            para_ids,
235
8004
                            slots_per_para_block: 1,
236
8004
                        };
237
8004
                    let mut additional_keys = mocked_author_noting.get_key_values();
238
                    // Mock only chain 2002 in relay.
239
                    // This will allow any signed origin to deregister chains 2000 and 2001, and register 2002.
240
8004
                    let (registrar_paras_key_2002, para_info_2002) = mocked_relay_keys::get_mocked_registrar_paras(2002.into());
241
8004
                    additional_keys.extend([(para_head_key, para_head_data), (relay_slot_key, Slot::from(relay_slot).encode()), (registrar_paras_key_2002, para_info_2002)]);
242

            
243
8004
                    if mock_additional_randomness {
244
200
                        let mut mock_randomness: [u8; 32] = [0u8; 32];
245
200
                        mock_randomness[..4].copy_from_slice(&current_para_block.to_be_bytes());
246
200
                        if let Some(seed) = mock_randomness_seed {
247
3300
                            for i in 0..32 {
248
3200
                                mock_randomness[i] ^= seed[i];
249
3200
                            }
250
100
                        }
251
200
                        additional_keys.extend([(RelayWellKnownKeys::CURRENT_BLOCK_RANDOMNESS.to_vec(), Some(mock_randomness).encode())]);
252
200
                        log::info!("mokcing randomnessss!!! {}", current_para_block);
253
7804
                    }
254

            
255
8004
                    let current_para_head = client_set_aside_for_cidp
256
8004
                            .header(block)
257
8004
                            .expect("Header lookup should succeed")
258
8004
                            .expect("Header passed in as parent should be present in backend.");
259
8004
                    let should_send_go_ahead = match client_set_aside_for_cidp
260
8004
                            .runtime_api()
261
8004
                            .collect_collation_info(block, &current_para_head)
262
                    {
263
8004
                            Ok(info) => info.new_validation_code.is_some(),
264
                            Err(e) => {
265
                                    log::error!("Failed to collect collation info: {:?}", e);
266
                                    false
267
                            },
268
                    };
269

            
270
8004
                    let time = MockTimestampInherentDataProvider;
271
8004
                    let mocked_parachain = MockValidationDataInherentDataProvider {
272
8004
                        current_para_block,
273
8004
                        current_para_block_head: None,
274
                        relay_offset: 1000,
275
                        relay_blocks_per_para_block: 2,
276
                        para_blocks_per_relay_epoch: 10,
277
8004
                        relay_randomness_config: (),
278
8004
                        xcm_config: MockXcmConfig::new(
279
8004
                            &*client_for_xcm,
280
8004
                            block,
281
8004
                            Default::default(),
282
                        ),
283
8004
                        raw_downward_messages: downward_xcm_receiver.drain().collect(),
284
8004
                        raw_horizontal_messages: hrmp_xcm_receiver.drain().collect(),
285
8004
                        additional_key_values: Some(additional_keys),
286
8004
                        para_id,
287
8004
                        upgrade_go_ahead: should_send_go_ahead.then(|| {
288
2
                            log::info!(
289
2
                                "Detected pending validation code, sending go-ahead signal."
290
                            );
291
2
                            UpgradeGoAhead::GoAhead
292
2
                        }),
293
                    };
294

            
295
8004
                    Ok((time, mocked_parachain, mocked_author_noting))
296
8004
                }
297
8004
            },
298
        })?;
299
    }
300

            
301
    // This node RPC builder.
302
    let rpc_builder = {
303
        let client = node_builder.client.clone();
304
        let transaction_pool = node_builder.transaction_pool.clone();
305

            
306
400
        Box::new(move |_| {
307
400
            let deps = tc_service_orchestrator_chain::parachain::rpc::FullDeps {
308
400
                client: client.clone(),
309
400
                pool: transaction_pool.clone(),
310
400
                command_sink: command_sink.clone(),
311
400
                xcm_senders: xcm_senders.clone(),
312
400
                randomness_sender: randomness_sender.clone(),
313
400
                container_chain_exclusion_sender: container_chains_exclusion_sender.clone(),
314
400
            };
315

            
316
400
            tc_service_orchestrator_chain::parachain::rpc::create_full(deps).map_err(Into::into)
317
400
        })
318
    };
319

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

            
323
    log::info!("Development Service Ready");
324

            
325
    Ok(node_builder.task_manager)
326
}
327

            
328
/// Can be called for a `Configuration` to check if it is a configuration for
329
/// the orchestrator network.
330
pub trait IdentifyVariant {
331
    /// Returns `true` if this is a configuration for a dev network.
332
    fn is_dev(&self) -> bool;
333
}
334

            
335
impl IdentifyVariant for Box<dyn sc_service::ChainSpec> {
336
200
    fn is_dev(&self) -> bool {
337
200
        self.chain_type() == sc_chain_spec::ChainType::Development
338
200
    }
339
}