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
//! Code used to run a solochain orchestrator node.
18

            
19
/// Provides an implementation of the [`OrchestratorChainInterface`] from a `RelayChainInterface`,
20
/// which makes sense in case the orchestrator chain is also the relay chain.
21
use {
22
    cumulus_primitives_core::ParaId,
23
    cumulus_relay_chain_interface::call_runtime_api,
24
    dc_orchestrator_chain_interface::{
25
        BlockNumber, ContainerChainGenesisData, DataPreserverAssignment, DataPreserverProfileId,
26
        OrchestratorChainError, OrchestratorChainResult, PHash, PHeader,
27
    },
28
    futures::Stream,
29
    nimbus_primitives::NimbusId,
30
    polkadot_service::Handle,
31
    sp_api::StorageProof,
32
    sp_state_machine::StorageValue,
33
    std::{pin::Pin, sync::Arc},
34
    tc_consensus::{OrchestratorChainInterface, RelayChainInterface},
35
};
36

            
37
/// Builder for a concrete relay chain interface, created from a full node. Builds
38
/// a [`RelayAsOrchestratorChainInterface`] to access relay chain data necessary for parachain operation.
39
///
40
/// The builder takes a [`polkadot_client::Client`]
41
/// that wraps a concrete instance. By using [`polkadot_client::ExecuteWithClient`]
42
/// the builder gets access to this concrete instance and instantiates a [`RelayAsOrchestratorChainInterface`] with it.
43
pub struct RelayAsOrchestratorChainInterfaceBuilder {
44
    pub overseer_handle: Handle,
45
    pub relay_chain_interface: Arc<dyn RelayChainInterface>,
46
}
47

            
48
impl RelayAsOrchestratorChainInterfaceBuilder {
49
    pub fn build(self) -> Arc<dyn OrchestratorChainInterface> {
50
        Arc::new(RelayAsOrchestratorChainInterface::new(
51
            self.overseer_handle,
52
            self.relay_chain_interface,
53
        ))
54
    }
55
}
56

            
57
pub struct RelayAsOrchestratorChainInterface {
58
    pub overseer_handle: Handle,
59
    pub relay_chain_interface: Arc<dyn RelayChainInterface>,
60
}
61

            
62
impl RelayAsOrchestratorChainInterface {
63
    /// Create a new instance of [`RelayAsOrchestratorChainInterface`]
64
    pub fn new(
65
        overseer_handle: Handle,
66
        relay_chain_interface: Arc<dyn RelayChainInterface>,
67
    ) -> Self {
68
        Self {
69
            overseer_handle,
70
            relay_chain_interface,
71
        }
72
    }
73
}
74

            
75
#[async_trait::async_trait]
76
impl OrchestratorChainInterface for RelayAsOrchestratorChainInterface {
77
    async fn get_storage_by_key(
78
        &self,
79
        relay_parent: PHash,
80
        key: &[u8],
81
    ) -> OrchestratorChainResult<Option<StorageValue>> {
82
        self.relay_chain_interface
83
            .get_storage_by_key(relay_parent, key)
84
            .await
85
            .map_err(|e| OrchestratorChainError::Application(Box::new(e)))
86
    }
87

            
88
    async fn prove_read(
89
        &self,
90
        relay_parent: PHash,
91
        relevant_keys: &Vec<Vec<u8>>,
92
    ) -> OrchestratorChainResult<StorageProof> {
93
        self.relay_chain_interface
94
            .prove_read(relay_parent, relevant_keys)
95
            .await
96
            .map_err(|e| OrchestratorChainError::Application(Box::new(e)))
97
    }
98

            
99
    fn overseer_handle(&self) -> OrchestratorChainResult<Handle> {
100
        Ok(self.overseer_handle.clone())
101
    }
102

            
103
    /// Get a stream of import block notifications.
104
    async fn import_notification_stream(
105
        &self,
106
    ) -> OrchestratorChainResult<Pin<Box<dyn Stream<Item = PHeader> + Send>>> {
107
        self.relay_chain_interface
108
            .import_notification_stream()
109
            .await
110
            .map_err(|e| OrchestratorChainError::Application(Box::new(e)))
111
    }
112

            
113
    /// Get a stream of new best block notifications.
114
    async fn new_best_notification_stream(
115
        &self,
116
    ) -> OrchestratorChainResult<Pin<Box<dyn Stream<Item = PHeader> + Send>>> {
117
        self.relay_chain_interface
118
            .new_best_notification_stream()
119
            .await
120
            .map_err(|e| OrchestratorChainError::Application(Box::new(e)))
121
    }
122

            
123
    /// Get a stream of finality notifications.
124
    async fn finality_notification_stream(
125
        &self,
126
    ) -> OrchestratorChainResult<Pin<Box<dyn Stream<Item = PHeader> + Send>>> {
127
        self.relay_chain_interface
128
            .finality_notification_stream()
129
            .await
130
            .map_err(|e| OrchestratorChainError::Application(Box::new(e)))
131
    }
132

            
133
    async fn genesis_data(
134
        &self,
135
        relay_parent: PHash,
136
        para_id: ParaId,
137
    ) -> OrchestratorChainResult<Option<ContainerChainGenesisData>> {
138
        let res: Option<ContainerChainGenesisData> = call_runtime_api(
139
            &self.relay_chain_interface,
140
            "RegistrarApi_genesis_data",
141
            relay_parent,
142
            &para_id,
143
        )
144
        .await
145
        .map_err(|e| OrchestratorChainError::Application(Box::new(e)))?;
146

            
147
        Ok(res)
148
    }
149

            
150
    async fn boot_nodes(
151
        &self,
152
        relay_parent: PHash,
153
        para_id: ParaId,
154
    ) -> OrchestratorChainResult<Vec<Vec<u8>>> {
155
        let res: Vec<Vec<u8>> = call_runtime_api(
156
            &self.relay_chain_interface,
157
            "RegistrarApi_boot_nodes",
158
            relay_parent,
159
            &para_id,
160
        )
161
        .await
162
        .map_err(|e| OrchestratorChainError::Application(Box::new(e)))?;
163

            
164
        Ok(res)
165
    }
166

            
167
    async fn latest_block_number(
168
        &self,
169
        relay_parent: PHash,
170
        para_id: ParaId,
171
    ) -> OrchestratorChainResult<Option<BlockNumber>> {
172
        let res: Option<BlockNumber> = call_runtime_api(
173
            &self.relay_chain_interface,
174
            "AuthorNotingApi_latest_block_number",
175
            relay_parent,
176
            &para_id,
177
        )
178
        .await
179
        .map_err(|e| OrchestratorChainError::Application(Box::new(e)))?;
180

            
181
        Ok(res)
182
    }
183

            
184
    async fn best_block_hash(&self) -> OrchestratorChainResult<PHash> {
185
        self.relay_chain_interface
186
            .best_block_hash()
187
            .await
188
            .map_err(|e| OrchestratorChainError::Application(Box::new(e)))
189
    }
190

            
191
    async fn finalized_block_hash(&self) -> OrchestratorChainResult<PHash> {
192
        self.relay_chain_interface
193
            .finalized_block_hash()
194
            .await
195
            .map_err(|e| OrchestratorChainError::Application(Box::new(e)))
196
    }
197

            
198
    async fn data_preserver_active_assignment(
199
        &self,
200
        orchestrator_parent: PHash,
201
        profile_id: DataPreserverProfileId,
202
    ) -> OrchestratorChainResult<DataPreserverAssignment<ParaId>> {
203
        use {
204
            dc_orchestrator_chain_interface::DataPreserverAssignment as InterfaceAssignment,
205
            pallet_data_preservers_runtime_api::Assignment as RuntimeAssignment,
206
        };
207

            
208
        let assignment: RuntimeAssignment<ParaId> = call_runtime_api(
209
            &self.relay_chain_interface,
210
            "DataPreserversApi_get_active_assignment",
211
            orchestrator_parent,
212
            profile_id,
213
        )
214
        .await
215
        .map_err(|e| OrchestratorChainError::Application(Box::new(e)))?;
216

            
217
        let assignment = match assignment {
218
            RuntimeAssignment::NotAssigned => InterfaceAssignment::NotAssigned,
219
            RuntimeAssignment::Active(para_id) => InterfaceAssignment::Active(para_id),
220
            RuntimeAssignment::Inactive(para_id) => InterfaceAssignment::Inactive(para_id),
221
        };
222

            
223
        Ok(assignment)
224
    }
225

            
226
    async fn check_para_id_assignment(
227
        &self,
228
        relay_parent: PHash,
229
        authority: NimbusId,
230
    ) -> OrchestratorChainResult<Option<ParaId>> {
231
        let res: Option<ParaId> = call_runtime_api(
232
            &self.relay_chain_interface,
233
            "TanssiAuthorityAssignmentApi_check_para_id_assignment",
234
            relay_parent,
235
            &authority,
236
        )
237
        .await
238
        .map_err(|e| OrchestratorChainError::Application(Box::new(e)))?;
239

            
240
        Ok(res)
241
    }
242

            
243
    async fn check_para_id_assignment_next_session(
244
        &self,
245
        relay_parent: PHash,
246
        authority: NimbusId,
247
    ) -> OrchestratorChainResult<Option<ParaId>> {
248
        let res: Option<ParaId> = call_runtime_api(
249
            &self.relay_chain_interface,
250
            "TanssiAuthorityAssignmentApi_check_para_id_assignment_next_session",
251
            relay_parent,
252
            &authority,
253
        )
254
        .await
255
        .map_err(|e| OrchestratorChainError::Application(Box::new(e)))?;
256

            
257
        Ok(res)
258
    }
259
}