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
//! Development Polkadot service. Adapted from `polkadot_service` crate
18
//! and removed un-necessary components which are not required in dev node.
19

            
20
use {
21
    codec::Encode,
22
    jsonrpsee::{
23
        core::RpcResult,
24
        proc_macros::rpc,
25
        types::{
26
            error::{INTERNAL_ERROR_CODE, INTERNAL_ERROR_MSG},
27
            ErrorObjectOwned,
28
        },
29
    },
30
    xcm::latest::prelude::*,
31
};
32

            
33
/// This RPC interface is used to provide methods in dev mode only
34
2100
#[rpc(server)]
35
#[jsonrpsee::core::async_trait]
36
pub trait DevApi {
37
    /// Indicate the mock parachain candidate insertion to be active
38
    #[method(name = "mock_enableParaInherentCandidate")]
39
    async fn enable_para_inherent_candidate(&self) -> RpcResult<()>;
40

            
41
    /// Indicate the mock parachain candidate insertion to be disabled
42
    #[method(name = "mock_disableParaInherentCandidate")]
43
    async fn disable_para_inherent_candidate(&self) -> RpcResult<()>;
44

            
45
    #[method(name = "xcm_injectUpwardMessage")]
46
    async fn inject_upward_message(&self, message: Vec<u8>) -> RpcResult<()>;
47
}
48

            
49
#[derive(Clone)]
50
pub struct DevRpc {
51
    pub mock_para_inherent_channel: flume::Sender<Vec<u8>>,
52
    pub upward_message_channel: flume::Sender<Vec<u8>>,
53
}
54

            
55
#[jsonrpsee::core::async_trait]
56
impl DevApiServer for DevRpc {
57
48
    async fn enable_para_inherent_candidate(&self) -> RpcResult<()> {
58
48
        let mock_para_inherent_channel = self.mock_para_inherent_channel.clone();
59
48
        // Push the message to the shared channel where it will be queued up
60
48
        // to be injected in to an upcoming block.
61
48
        mock_para_inherent_channel
62
48
            .send_async(true.encode())
63
            .await
64
48
            .map_err(|err| internal_err(err.to_string()))?;
65

            
66
48
        Ok(())
67
96
    }
68

            
69
    async fn disable_para_inherent_candidate(&self) -> RpcResult<()> {
70
        let mock_para_inherent_channel = self.mock_para_inherent_channel.clone();
71
        // Push the message to the shared channel where it will be queued up
72
        // to be injected in to an upcoming block.
73
        mock_para_inherent_channel
74
            .send_async(false.encode())
75
            .await
76
            .map_err(|err| internal_err(err.to_string()))?;
77

            
78
        Ok(())
79
    }
80

            
81
6
    async fn inject_upward_message(&self, msg: Vec<u8>) -> RpcResult<()> {
82
6
        let upward_message_channel = self.upward_message_channel.clone();
83
        // If no message is supplied, inject a default one.
84
6
        let msg = if msg.is_empty() {
85
            // Note: Sovereign account of the origin parachain must be funded before injecting the message.
86
            xcm::VersionedXcm::<()>::V5(Xcm(vec![
87
                WithdrawAsset((Here, 10000000000000u128).into()),
88
                BuyExecution {
89
                    fees: (Here, 10000000000000u128).into(),
90
                    weight_limit: Unlimited,
91
                },
92
                DepositAsset {
93
                    assets: AllCounted(1).into(),
94
                    beneficiary: Location::new(
95
                        0,
96
                        [AccountKey20 {
97
                            network: None,
98
                            key: hex_literal::hex!("f24FF3a9CF04c71Dbc94D0b566f7A27B94566cac"),
99
                        }],
100
                    ),
101
                },
102
            ]))
103
            .encode()
104
        } else {
105
6
            msg
106
        };
107

            
108
        // Push the message to the shared channel where it will be queued up
109
        // to be injected in to an upcoming block.
110
6
        upward_message_channel
111
6
            .send_async(msg)
112
            .await
113
6
            .map_err(|err| internal_err(err.to_string()))?;
114

            
115
6
        Ok(())
116
12
    }
117
}
118

            
119
// This bit cribbed from frontier.
120
pub fn internal_err<T: ToString>(message: T) -> ErrorObjectOwned {
121
    ErrorObjectOwned::owned(
122
        INTERNAL_ERROR_CODE,
123
        INTERNAL_ERROR_MSG,
124
        Some(message.to_string()),
125
    )
126
}