pallet_messenger/migrations/
v1_to_v2.rs1#[cfg(not(feature = "std"))]
4extern crate alloc;
5use crate::migrations::v1_to_v2::migrate_channels::migrate_channels;
6use crate::{BalanceOf, Channels as ChannelStorageV1, Config, Pallet};
7#[cfg(not(feature = "std"))]
8use alloc::vec::Vec;
9use core::marker::PhantomData;
10use frame_support::migrations::VersionedMigration;
11use frame_support::pallet_prelude::{Decode, Encode, OptionQuery, TypeInfo};
12use frame_support::traits::UncheckedOnRuntimeUpgrade;
13use frame_support::weights::Weight;
14use frame_support::{Identity, storage_alias};
15use sp_domains::{ChainId, ChannelId};
16use sp_messenger::messages::{Channel as ChannelV1, ChannelState, Nonce};
17
18pub type VersionCheckedMigrateDomainsV1ToV2<T> = VersionedMigration<
19 1,
20 2,
21 VersionUncheckedMigrateV1ToV2<T>,
22 Pallet<T>,
23 <T as frame_system::Config>::DbWeight,
24>;
25
26pub struct VersionUncheckedMigrateV1ToV2<T>(PhantomData<T>);
27impl<T: Config> UncheckedOnRuntimeUpgrade for VersionUncheckedMigrateV1ToV2<T> {
28 fn on_runtime_upgrade() -> Weight {
29 migrate_channels::<T>()
30 }
31}
32
33#[derive(Default, Debug, Encode, Decode, Clone, Copy, Eq, PartialEq, TypeInfo)]
35pub struct FeeModel<Balance> {
36 pub relay_fee: Balance,
38}
39
40#[derive(Default, Debug, Encode, Decode, Clone, Eq, PartialEq, TypeInfo)]
41struct Channel<Balance, AccountId> {
42 pub channel_id: ChannelId,
44 pub state: ChannelState,
46 pub next_inbox_nonce: Nonce,
48 pub next_outbox_nonce: Nonce,
50 pub latest_response_received_message_nonce: Option<Nonce>,
52 pub max_outgoing_messages: u32,
54 pub fee: FeeModel<Balance>,
56 pub maybe_owner: Option<AccountId>,
59 pub channel_reserve_fee: Balance,
61}
62
63impl<Balance, AccountId> From<Channel<Balance, AccountId>> for ChannelV1<Balance, AccountId> {
64 fn from(value: Channel<Balance, AccountId>) -> Self {
65 ChannelV1 {
66 channel_id: value.channel_id,
67 state: value.state,
68 next_inbox_nonce: value.next_inbox_nonce,
69 next_outbox_nonce: value.next_outbox_nonce,
70 latest_response_received_message_nonce: value.latest_response_received_message_nonce,
71 max_outgoing_messages: value.max_outgoing_messages,
72 maybe_owner: value.maybe_owner,
73 channel_reserve_fee: value.channel_reserve_fee,
74 }
75 }
76}
77
78pub(crate) mod migrate_channels {
79 use super::*;
80 use sp_messenger::messages::ChannelStateWithNonce;
81 use sp_runtime::traits::Get;
82
83 #[storage_alias]
84 pub(super) type Channels<T: Config> = StorageDoubleMap<
85 Pallet<T>,
86 Identity,
87 ChainId,
88 Identity,
89 ChannelId,
90 Channel<BalanceOf<T>, <T as frame_system::Config>::AccountId>,
91 OptionQuery,
92 >;
93
94 pub(super) fn migrate_channels<T: Config>() -> Weight {
95 let mut count = 0;
96 Channels::<T>::drain().for_each(|(chain_id, channel_id, channel)| {
97 let channel_v1: ChannelV1<BalanceOf<T>, T::AccountId> = channel.into();
98 ChannelStorageV1::<T>::insert(chain_id, channel_id, channel_v1);
99 count += 1;
100 });
101
102 T::DbWeight::get().reads_writes(count, count)
103 }
104
105 pub(crate) fn get_channel<T: Config>(
106 chain_id: ChainId,
107 channel_id: ChannelId,
108 ) -> Option<ChannelV1<BalanceOf<T>, T::AccountId>> {
109 ChannelStorageV1::<T>::get(chain_id, channel_id).or_else(|| {
110 Channels::<T>::get(chain_id, channel_id).map(|old_channel| old_channel.into())
111 })
112 }
113
114 pub(crate) fn get_channels_and_states<T: Config>()
115 -> Vec<(ChainId, ChannelId, ChannelStateWithNonce)> {
116 let keys: Vec<(ChainId, ChannelId)> = ChannelStorageV1::<T>::iter_keys().collect();
117 keys.into_iter()
118 .filter_map(|(chain_id, channel_id)| {
119 get_channel::<T>(chain_id, channel_id).map(|channel| {
120 let state = channel.state;
121 let state_with_nonce = match state {
122 ChannelState::Initiated => ChannelStateWithNonce::Initiated,
123 ChannelState::Open => ChannelStateWithNonce::Open,
124 ChannelState::Closed => ChannelStateWithNonce::Closed {
125 next_outbox_nonce: channel.next_outbox_nonce,
126 next_inbox_nonce: channel.next_inbox_nonce,
127 },
128 };
129
130 (chain_id, channel_id, state_with_nonce)
131 })
132 })
133 .collect()
134 }
135}
136
137#[cfg(test)]
138mod tests {
139 use super::migrate_channels::Channels;
140 use super::*;
141 use crate::mock::chain_a::{Runtime, new_test_ext};
142 use frame_support::weights::RuntimeDbWeight;
143 use sp_runtime::traits::Get;
144
145 #[test]
146 fn test_channel_migration() {
147 let mut ext = new_test_ext();
148 let chain_id = ChainId::Consensus;
149 let channel_id = ChannelId::zero();
150 let channel = Channel {
151 channel_id,
152 state: ChannelState::Open,
153 next_inbox_nonce: Nonce::zero(),
154 next_outbox_nonce: Nonce::one(),
155 latest_response_received_message_nonce: Some(Nonce::from(100u32)),
156 max_outgoing_messages: 100,
157 fee: FeeModel { relay_fee: 100 },
158 maybe_owner: Some(100u64),
159 channel_reserve_fee: 200,
160 };
161
162 let channel_v1 = ChannelV1 {
163 channel_id,
164 state: ChannelState::Open,
165 next_inbox_nonce: Nonce::zero(),
166 next_outbox_nonce: Nonce::one(),
167 latest_response_received_message_nonce: Some(Nonce::from(100u32)),
168 max_outgoing_messages: 100,
169 maybe_owner: Some(100u64),
170 channel_reserve_fee: 200,
171 };
172
173 ext.execute_with(|| Channels::<Runtime>::insert(chain_id, channel_id, channel));
174
175 ext.commit_all().unwrap();
176
177 ext.execute_with(|| {
178 let weight = migrate_channels::<Runtime>();
179 let channel = ChannelStorageV1::<Runtime>::get(chain_id, channel_id).unwrap();
180 let db_weights: RuntimeDbWeight = <Runtime as frame_system::Config>::DbWeight::get();
181 assert_eq!(weight, db_weights.reads_writes(1, 1),);
182 assert_eq!(channel, channel_v1);
183 })
184 }
185}