cross_domain_message_gossip/
aux_schema.rs1use parity_scale_codec::{Decode, Encode};
4use sc_client_api::backend::AuxStore;
5use sp_blockchain::{Error as ClientError, Info, Result as ClientResult};
6use sp_core::H256;
7use sp_core::bytes::to_hex;
8use sp_messenger::messages::{ChainId, ChannelId, ChannelState, Nonce};
9use sp_messenger::{ChannelNonce, XdmId};
10use sp_runtime::traits::{Block as BlockT, NumberFor};
11use subspace_runtime_primitives::BlockNumber;
12
13const CHANNEL_DETAIL: &[u8] = b"channel_detail";
14
15fn channel_detail_key(
16 src_chain_id: ChainId,
17 self_chain_id: ChainId,
18 channel_id: ChannelId,
19) -> Vec<u8> {
20 (CHANNEL_DETAIL, src_chain_id, self_chain_id, channel_id).encode()
21}
22
23fn load_decode<Backend: AuxStore, T: Decode>(
24 backend: &Backend,
25 key: &[u8],
26) -> ClientResult<Option<T>> {
27 match backend.get_aux(key)? {
28 None => Ok(None),
29 Some(t) => T::decode(&mut &t[..])
30 .map_err(|e| {
31 ClientError::Backend(format!("Relayer DB is corrupted. Decode error: {e}"))
32 })
33 .map(Some),
34 }
35}
36
37#[derive(Debug, Encode, Decode, Clone)]
39pub struct ChannelDetail {
40 pub block_number: BlockNumber,
42 pub block_hash: H256,
44 pub state_root: H256,
46 pub channel_id: ChannelId,
48 pub state: ChannelState,
50 pub next_inbox_nonce: Nonce,
52 pub next_outbox_nonce: Nonce,
54 pub latest_response_received_message_nonce: Option<Nonce>,
56}
57
58pub fn get_channel_state<Backend>(
60 backend: &Backend,
61 src_chain_id: ChainId,
62 self_chain_id: ChainId,
63 channel_id: ChannelId,
64) -> ClientResult<Option<ChannelDetail>>
65where
66 Backend: AuxStore,
67{
68 load_decode(
69 backend,
70 channel_detail_key(src_chain_id, self_chain_id, channel_id).as_slice(),
71 )
72}
73
74pub fn set_channel_state<Backend>(
76 backend: &Backend,
77 src_chain_id: ChainId,
78 self_chain_id: ChainId,
79 channel_detail: ChannelDetail,
80) -> ClientResult<()>
81where
82 Backend: AuxStore,
83{
84 backend.insert_aux(
85 &[(
86 channel_detail_key(src_chain_id, self_chain_id, channel_detail.channel_id).as_slice(),
87 channel_detail.encode().as_slice(),
88 )],
89 vec![],
90 )
91}
92
93mod xdm_keys {
94 use parity_scale_codec::Encode;
95 use sp_domains::{ChainId, ChannelId};
96 use sp_messenger::XdmId;
97 use sp_messenger::messages::MessageKey;
98
99 const XDM: &[u8] = b"xdm";
100 const XDM_RELAY: &[u8] = b"relay_msg";
101 const XDM_RELAY_RESPONSE: &[u8] = b"relay_msg_response";
102 const XDM_LAST_CLEANUP_NONCE: &[u8] = b"xdm_last_cleanup_nonce";
103
104 pub(super) fn get_key_for_xdm_id(prefix: &[u8], xdm_id: XdmId) -> Vec<u8> {
105 match xdm_id {
106 XdmId::RelayMessage(id) => get_key_for_xdm_relay(prefix, id),
107 XdmId::RelayResponseMessage(id) => get_key_for_xdm_relay_response(prefix, id),
108 }
109 }
110
111 pub(super) fn get_key_for_last_cleanup_relay_nonce(
112 prefix: &[u8],
113 chain_id: ChainId,
114 channel_id: ChannelId,
115 ) -> Vec<u8> {
116 (
117 prefix,
118 XDM,
119 XDM_RELAY,
120 XDM_LAST_CLEANUP_NONCE,
121 chain_id,
122 channel_id,
123 )
124 .encode()
125 }
126
127 pub(super) fn get_key_for_last_cleanup_relay_response_nonce(
128 prefix: &[u8],
129 chain_id: ChainId,
130 channel_id: ChannelId,
131 ) -> Vec<u8> {
132 (
133 prefix,
134 XDM,
135 XDM_RELAY_RESPONSE,
136 XDM_LAST_CLEANUP_NONCE,
137 chain_id,
138 channel_id,
139 )
140 .encode()
141 }
142
143 pub(super) fn get_key_for_xdm_relay(prefix: &[u8], id: MessageKey) -> Vec<u8> {
144 (prefix, XDM, XDM_RELAY, id).encode()
145 }
146
147 pub(super) fn get_key_for_xdm_relay_response(prefix: &[u8], id: MessageKey) -> Vec<u8> {
148 (prefix, XDM, XDM_RELAY_RESPONSE, id).encode()
149 }
150}
151
152#[derive(Debug, Encode, Decode, Clone)]
153pub struct BlockId<Block: BlockT> {
154 pub number: NumberFor<Block>,
155 pub hash: Block::Hash,
156}
157
158impl<Block: BlockT> From<Info<Block>> for BlockId<Block> {
159 fn from(value: Info<Block>) -> Self {
160 BlockId {
161 number: value.best_number,
162 hash: value.best_hash,
163 }
164 }
165}
166
167pub fn set_xdm_message_processed_at<Backend, Block>(
169 backend: &Backend,
170 prefix: &[u8],
171 xdm_id: XdmId,
172 block_id: BlockId<Block>,
173) -> ClientResult<()>
174where
175 Backend: AuxStore,
176 Block: BlockT,
177{
178 let key = xdm_keys::get_key_for_xdm_id(prefix, xdm_id);
179 backend.insert_aux(&[(key.as_slice(), block_id.encode().as_slice())], vec![])
180}
181
182pub fn get_xdm_processed_block_number<Backend, Block>(
184 backend: &Backend,
185 prefix: &[u8],
186 xdm_id: XdmId,
187) -> ClientResult<Option<BlockId<Block>>>
188where
189 Backend: AuxStore,
190 Block: BlockT,
191{
192 load_decode(
193 backend,
194 xdm_keys::get_key_for_xdm_id(prefix, xdm_id).as_slice(),
195 )
196}
197
198pub fn cleanup_chain_channel_storages<Backend>(
200 backend: &Backend,
201 prefix: &[u8],
202 chain_id: ChainId,
203 channel_id: ChannelId,
204 channel_nonce: ChannelNonce,
205) -> ClientResult<()>
206where
207 Backend: AuxStore,
208{
209 let mut to_insert = vec![];
210 let mut to_delete = vec![];
211 if let Some(latest_relay_nonce) = channel_nonce.relay_msg_nonce {
212 let last_cleanup_relay_nonce_key =
213 xdm_keys::get_key_for_last_cleanup_relay_nonce(prefix, chain_id, channel_id);
214 let last_cleaned_up_nonce =
215 load_decode::<_, Nonce>(backend, last_cleanup_relay_nonce_key.as_slice())?;
216
217 let mut from_nonce = match last_cleaned_up_nonce {
218 None => Nonce::zero(),
219 Some(last_nonce) => last_nonce.saturating_add(Nonce::one()),
220 };
221
222 tracing::debug!(
223 "[{:?}]Cleaning Relay xdm keys for {:?} channel: {:?} from: {:?} to: {:?}",
224 to_hex(prefix, false),
225 chain_id,
226 channel_id,
227 from_nonce,
228 latest_relay_nonce
229 );
230
231 while from_nonce <= latest_relay_nonce {
232 to_delete.push(xdm_keys::get_key_for_xdm_relay(
233 prefix,
234 (chain_id, channel_id, from_nonce),
235 ));
236 from_nonce = from_nonce.saturating_add(Nonce::one());
237 }
238
239 to_insert.push((last_cleanup_relay_nonce_key, latest_relay_nonce.encode()));
240 }
241
242 if let Some(latest_relay_response_nonce) = channel_nonce.relay_response_msg_nonce {
243 let last_cleanup_relay_response_nonce_key =
244 xdm_keys::get_key_for_last_cleanup_relay_response_nonce(prefix, chain_id, channel_id);
245 let last_cleaned_up_nonce =
246 load_decode::<_, Nonce>(backend, last_cleanup_relay_response_nonce_key.as_slice())?;
247
248 let mut from_nonce = match last_cleaned_up_nonce {
249 None => Nonce::zero(),
250 Some(last_nonce) => last_nonce.saturating_add(Nonce::one()),
251 };
252
253 tracing::debug!(
254 "[{:?}]Cleaning Relay response xdm keys for {:?} channel: {:?} from: {:?} to: {:?}",
255 to_hex(prefix, false),
256 chain_id,
257 channel_id,
258 from_nonce,
259 latest_relay_response_nonce
260 );
261
262 while from_nonce <= latest_relay_response_nonce {
263 to_delete.push(xdm_keys::get_key_for_xdm_relay_response(
264 prefix,
265 (chain_id, channel_id, from_nonce),
266 ));
267 from_nonce = from_nonce.saturating_add(Nonce::one());
268 }
269
270 to_insert.push((
271 last_cleanup_relay_response_nonce_key,
272 latest_relay_response_nonce.encode(),
273 ));
274 }
275
276 backend.insert_aux(
277 &to_insert
278 .iter()
279 .map(|(k, v)| (k.as_slice(), v.as_slice()))
280 .collect::<Vec<_>>(),
281 &to_delete.iter().map(|k| k.as_slice()).collect::<Vec<_>>(),
282 )
283}