1use cumulus_primitives_core::ParaId;
18use cumulus_primitives_core::XcmpMessageFormat;
19use jsonrpsee::{
20 core::RpcResult,
21 proc_macros::rpc,
22 types::{
23 error::{INTERNAL_ERROR_CODE, INTERNAL_ERROR_MSG},
24 ErrorObjectOwned,
25 },
26};
27use parity_scale_codec::Encode;
28use xcm::opaque::lts::Weight;
29use xcm::v5::prelude::*;
30use xcm_primitives::DEFAULT_PROOF_SIZE;
31
32#[rpc(server)]
34#[jsonrpsee::core::async_trait]
35pub trait DevApi {
36 #[method(name = "xcm_injectDownwardMessage")]
40 async fn inject_downward_message(&self, message: Vec<u8>) -> RpcResult<()>;
41
42 #[method(name = "xcm_injectHrmpMessage")]
54 async fn inject_hrmp_message(&self, sender: ParaId, message: Vec<u8>) -> RpcResult<()>;
55
56 #[method(name = "test_skipRelayBlocks")]
58 async fn skip_relay_blocks(&self, n: u32) -> RpcResult<()>;
59}
60
61pub struct DevRpc {
62 pub downward_message_channel: flume::Sender<Vec<u8>>,
63 pub hrmp_message_channel: flume::Sender<(ParaId, Vec<u8>)>,
64 pub additional_relay_offset: std::sync::Arc<std::sync::atomic::AtomicU32>,
65}
66
67#[jsonrpsee::core::async_trait]
68impl DevApiServer for DevRpc {
69 async fn inject_downward_message(&self, msg: Vec<u8>) -> RpcResult<()> {
70 let downward_message_channel = self.downward_message_channel.clone();
71 let msg = if msg.is_empty() {
73 xcm::VersionedXcm::<()>::V5(Xcm(vec![
74 ReserveAssetDeposited((Parent, 10000000000000u128).into()),
75 ClearOrigin,
76 BuyExecution {
77 fees: (Parent, 10000000000000u128).into(),
78 weight_limit: Limited(Weight::from_parts(
79 10_000_000_000u64,
80 DEFAULT_PROOF_SIZE,
81 )),
82 },
83 DepositAsset {
84 assets: AllCounted(1).into(),
85 beneficiary: Location::new(
86 0,
87 [AccountKey20 {
88 network: None,
89 key: hex_literal::hex!("f24FF3a9CF04c71Dbc94D0b566f7A27B94566cac"),
90 }],
91 ),
92 },
93 ]))
94 .encode()
95 } else {
96 msg
97 };
98
99 downward_message_channel
102 .send_async(msg)
103 .await
104 .map_err(|err| internal_err(err.to_string()))?;
105
106 Ok(())
107 }
108
109 async fn inject_hrmp_message(&self, sender: ParaId, msg: Vec<u8>) -> RpcResult<()> {
110 let hrmp_message_channel = self.hrmp_message_channel.clone();
111
112 let msg = if msg.is_empty() {
114 let mut mes = XcmpMessageFormat::ConcatenatedVersionedXcm.encode();
115 mes.append(
116 &mut (xcm::VersionedXcm::<()>::V5(Xcm(vec![
117 ReserveAssetDeposited(
118 ((Parent, Parachain(sender.into())), 10000000000000u128).into(),
119 ),
120 ClearOrigin,
121 BuyExecution {
122 fees: ((Parent, Parachain(sender.into())), 10000000000000u128).into(),
123 weight_limit: Limited(Weight::from_parts(
124 10_000_000_000u64,
125 DEFAULT_PROOF_SIZE,
126 )),
127 },
128 DepositAsset {
129 assets: AllCounted(1).into(),
130 beneficiary: Location::new(
131 0,
132 [AccountKey20 {
133 network: None,
134 key: hex_literal::hex!("f24FF3a9CF04c71Dbc94D0b566f7A27B94566cac"),
135 }],
136 ),
137 },
138 ]))
139 .encode()),
140 );
141 mes
142 } else {
143 msg
144 };
145
146 hrmp_message_channel
149 .send_async((sender, msg))
150 .await
151 .map_err(|err| internal_err(err.to_string()))?;
152
153 Ok(())
154 }
155
156 async fn skip_relay_blocks(&self, n: u32) -> RpcResult<()> {
157 self.additional_relay_offset
158 .fetch_add(n, std::sync::atomic::Ordering::SeqCst);
159 Ok(())
160 }
161}
162
163pub fn internal_err<T: ToString>(message: T) -> ErrorObjectOwned {
165 ErrorObjectOwned::owned(
166 INTERNAL_ERROR_CODE,
167 INTERNAL_ERROR_MSG,
168 Some(message.to_string()),
169 )
170}