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 codec::Encode;
21
use jsonrpsee::{
22
    core::RpcResult,
23
    proc_macros::rpc,
24
    types::{
25
        error::{INTERNAL_ERROR_CODE, INTERNAL_ERROR_MSG},
26
        ErrorObjectOwned,
27
    },
28
};
29
use xcm::latest::prelude::*;
30

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

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

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

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

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

            
64
35
        Ok(())
65
70
    }
66

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

            
76
        Ok(())
77
    }
78

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

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

            
113
7
        Ok(())
114
14
    }
115
}
116

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