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
//! A collection of node-specific RPC methods.
18
//! Substrate provides the `sc-rpc` crate, which defines the core RPC layer
19
//! used by Substrate nodes. This file extends those RPC definitions with
20
//! capabilities that are specific to this project's runtime configuration.
21

            
22
#![warn(missing_docs)]
23

            
24
use {
25
    cumulus_primitives_core::ParaId,
26
    dancebox_runtime::{opaque::Block, AccountId, Index as Nonce},
27
    frame_support::{CloneNoBound, DefaultNoBound},
28
    manual_xcm_rpc::{ManualXcm, ManualXcmApiServer},
29
    polkadot_primitives::Hash,
30
    sc_client_api::{AuxStore, UsageProvider},
31
    sc_consensus_manual_seal::{
32
        rpc::{ManualSeal, ManualSealApiServer},
33
        EngineCommand,
34
    },
35
    sc_rpc::DenyUnsafe,
36
    sc_transaction_pool_api::TransactionPool,
37
    sp_api::ProvideRuntimeApi,
38
    sp_block_builder::BlockBuilder,
39
    sp_blockchain::{Error as BlockChainError, HeaderBackend, HeaderMetadata},
40
    std::{marker::PhantomData, sync::Arc},
41
};
42

            
43
/// A type representing all RPC extensions.
44
pub type RpcExtension = jsonrpsee::RpcModule<()>;
45

            
46
/// Full client dependencies
47
pub struct FullDeps<C, P> {
48
    /// The client instance to use.
49
    pub client: Arc<C>,
50
    /// Transaction pool instance.
51
    pub pool: Arc<P>,
52
    /// Whether to deny unsafe calls
53
    pub deny_unsafe: DenyUnsafe,
54
    /// Manual seal command sink
55
    pub command_sink: Option<futures::channel::mpsc::Sender<EngineCommand<Hash>>>,
56
    /// Channels for manual xcm messages (downward, hrmp)
57
    pub xcm_senders: Option<(flume::Sender<Vec<u8>>, flume::Sender<(ParaId, Vec<u8>)>)>,
58
}
59

            
60
tp_traits::alias!(
61
    /// Test
62
    pub trait SubstrateRpcRuntimeApi<Client : (sp_api::CallApiAt<Block>)>:
63
        sp_api::ConstructRuntimeApi<
64
            Block,
65
            Client,
66
            RuntimeApi:
67
                substrate_frame_rpc_system::AccountNonceApi<Block, AccountId, Nonce>
68
                + BlockBuilder<Block>
69
        > + Send + Sync + 'static
70
);
71

            
72
/// Instantiate all RPC extensions.
73
pub fn create_full<C, P>(
74
    deps: FullDeps<C, P>,
75
) -> Result<RpcExtension, Box<dyn std::error::Error + Send + Sync>>
76
where
77
    C: ProvideRuntimeApi<Block>
78
        + HeaderBackend<Block>
79
        + AuxStore
80
        + HeaderMetadata<Block, Error = BlockChainError>
81
        + Send
82
        + Sync
83
        + UsageProvider<Block>
84
        + 'static,
85
    C::Api: substrate_frame_rpc_system::AccountNonceApi<Block, AccountId, Nonce>,
86
    C::Api: BlockBuilder<Block>,
87
    P: TransactionPool + Sync + Send + 'static,
88
{
89
    use substrate_frame_rpc_system::{System, SystemApiServer};
90

            
91
    let mut module = RpcExtension::new(());
92
    let FullDeps {
93
        client,
94
        pool,
95
        deny_unsafe,
96
        command_sink,
97
        xcm_senders,
98
    } = deps;
99

            
100
    module.merge(System::new(client.clone(), pool, deny_unsafe).into_rpc())?;
101

            
102
    if let Some(command_sink) = command_sink {
103
        module.merge(
104
            // We provide the rpc handler with the sending end of the channel to allow the rpc
105
            // send EngineCommands to the background block authorship task.
106
            ManualSeal::new(command_sink).into_rpc(),
107
        )?;
108
    };
109

            
110
    if let Some((downward_message_channel, hrmp_message_channel)) = xcm_senders {
111
        module.merge(
112
            ManualXcm {
113
                downward_message_channel,
114
                hrmp_message_channel,
115
            }
116
            .into_rpc(),
117
        )?;
118
    }
119

            
120
    Ok(module)
121
}
122

            
123
/// Contains the `GenerateRpcBuilder` trait and defines or re-exports all types it uses.
124
pub mod generate_rpc_builder {
125
    // We re-export types with specific type parameters, no need to be verbose documenting that.
126
    #![allow(missing_docs)]
127

            
128
    pub use {
129
        crate::service::{ContainerChainBackend, ContainerChainClient, MinimalContainerRuntimeApi},
130
        sc_service::{Error as ServiceError, TaskManager},
131
        std::sync::Arc,
132
        substrate_prometheus_endpoint::Registry as PrometheusRegistry,
133
        tc_consensus::ParaId,
134
    };
135

            
136
    // TODO: It would be better to use a container chain types.
137
    pub use dancebox_runtime::{opaque::Block, Hash};
138

            
139
    pub type SyncingService = sc_network_sync::SyncingService<Block>;
140
    pub type TransactionPool<RuntimeApi> =
141
        sc_transaction_pool::FullPool<Block, ContainerChainClient<RuntimeApi>>;
142
    pub type CommandSink =
143
        futures::channel::mpsc::Sender<sc_consensus_manual_seal::EngineCommand<Hash>>;
144
    pub type XcmSenders = (flume::Sender<Vec<u8>>, flume::Sender<(ParaId, Vec<u8>)>);
145
    pub type Network = dyn sc_network::service::traits::NetworkService;
146
    pub type CompleteRpcBuilder = Box<
147
        dyn Fn(
148
            sc_rpc::DenyUnsafe,
149
            sc_rpc::SubscriptionTaskExecutor,
150
        ) -> Result<jsonrpsee::RpcModule<()>, ServiceError>,
151
    >;
152

            
153
    pub struct GenerateRpcBuilderParams<'a, RuntimeApi: MinimalContainerRuntimeApi> {
154
        pub task_manager: &'a TaskManager,
155
        pub container_chain_config: &'a sc_service::Configuration,
156

            
157
        pub client: Arc<ContainerChainClient<RuntimeApi>>,
158
        pub backend: Arc<ContainerChainBackend>,
159
        pub sync_service: Arc<SyncingService>,
160
        pub transaction_pool: Arc<TransactionPool<RuntimeApi>>,
161
        pub prometheus_registry: Option<PrometheusRegistry>,
162
        pub command_sink: Option<CommandSink>,
163
        pub xcm_senders: Option<XcmSenders>,
164
        pub network: Arc<Network>,
165
    }
166

            
167
    pub trait GenerateRpcBuilder<RuntimeApi: MinimalContainerRuntimeApi>:
168
        Clone + Sync + Send
169
    {
170
        fn generate(
171
            &self,
172
            params: GenerateRpcBuilderParams<RuntimeApi>,
173
        ) -> Result<CompleteRpcBuilder, ServiceError>;
174
    }
175
}
176

            
177
/// Generate an rpc builder for simple substrate container chains.
178
#[derive(CloneNoBound, DefaultNoBound)]
179
pub struct GenerateSubstrateRpcBuilder<RuntimeApi>(pub PhantomData<RuntimeApi>);
180
impl<RuntimeApi> GenerateSubstrateRpcBuilder<RuntimeApi> {
181
    /// Creates a new instance.
182
    pub fn new() -> Self {
183
        Self(PhantomData)
184
    }
185
}
186

            
187
mod impl_generate_rpc_builder {
188
    use {super::*, generate_rpc_builder::*};
189

            
190
    impl<
191
            RuntimeApi: MinimalContainerRuntimeApi
192
                + crate::rpc::SubstrateRpcRuntimeApi<ContainerChainClient<RuntimeApi>>,
193
        > GenerateRpcBuilder<RuntimeApi> for GenerateSubstrateRpcBuilder<RuntimeApi>
194
    {
195
        fn generate(
196
            &self,
197
            GenerateRpcBuilderParams {
198
                client,
199
                transaction_pool,
200
                command_sink,
201
                xcm_senders,
202
                ..
203
            }: GenerateRpcBuilderParams<RuntimeApi>,
204
        ) -> Result<CompleteRpcBuilder, ServiceError> {
205
            let client = client.clone();
206
            let transaction_pool = transaction_pool.clone();
207

            
208
            Ok(Box::new(move |deny_unsafe, _| {
209
                let deps = FullDeps {
210
                    client: client.clone(),
211
                    pool: transaction_pool.clone(),
212
                    deny_unsafe,
213
                    command_sink: command_sink.clone(),
214
                    xcm_senders: xcm_senders.clone(),
215
                };
216

            
217
                create_full(deps).map_err(Into::into)
218
            }))
219
        }
220
    }
221
}