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::collections::BTreeSet;
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::{storage_alias, Identity};
15use sp_domains::{ChainId, ChannelId};
16use sp_messenger::messages::{Channel as ChannelV1, ChannelState, Nonce};
17#[cfg(feature = "std")]
18use std::collections::BTreeSet;
19
20pub type VersionCheckedMigrateDomainsV1ToV2<T> = VersionedMigration<
21 1,
22 2,
23 VersionUncheckedMigrateV1ToV2<T>,
24 Pallet<T>,
25 <T as frame_system::Config>::DbWeight,
26>;
27
28pub struct VersionUncheckedMigrateV1ToV2<T>(PhantomData<T>);
29impl<T: Config> UncheckedOnRuntimeUpgrade for VersionUncheckedMigrateV1ToV2<T> {
30 fn on_runtime_upgrade() -> Weight {
31 migrate_channels::<T>()
32 }
33}
34
35#[derive(Default, Debug, Encode, Decode, Clone, Copy, Eq, PartialEq, TypeInfo)]
37pub struct FeeModel<Balance> {
38 pub relay_fee: Balance,
40}
41
42#[derive(Default, Debug, Encode, Decode, Clone, Eq, PartialEq, TypeInfo)]
43struct Channel<Balance, AccountId> {
44 pub channel_id: ChannelId,
46 pub state: ChannelState,
48 pub next_inbox_nonce: Nonce,
50 pub next_outbox_nonce: Nonce,
52 pub latest_response_received_message_nonce: Option<Nonce>,
54 pub max_outgoing_messages: u32,
56 pub fee: FeeModel<Balance>,
58 pub maybe_owner: Option<AccountId>,
61 pub channel_reserve_fee: Balance,
63}
64
65impl<Balance, AccountId> From<Channel<Balance, AccountId>> for ChannelV1<Balance, AccountId> {
66 fn from(value: Channel<Balance, AccountId>) -> Self {
67 ChannelV1 {
68 channel_id: value.channel_id,
69 state: value.state,
70 next_inbox_nonce: value.next_inbox_nonce,
71 next_outbox_nonce: value.next_outbox_nonce,
72 latest_response_received_message_nonce: value.latest_response_received_message_nonce,
73 max_outgoing_messages: value.max_outgoing_messages,
74 maybe_owner: value.maybe_owner,
75 channel_reserve_fee: value.channel_reserve_fee,
76 }
77 }
78}
79
80pub(crate) mod migrate_channels {
81 use super::*;
82 use sp_runtime::traits::Get;
83
84 #[storage_alias]
85 pub(super) type Channels<T: Config> = StorageDoubleMap<
86 Pallet<T>,
87 Identity,
88 ChainId,
89 Identity,
90 ChannelId,
91 Channel<BalanceOf<T>, <T as frame_system::Config>::AccountId>,
92 OptionQuery,
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_open_channels<T: Config>() -> BTreeSet<(ChainId, ChannelId)> {
115 let keys: BTreeSet<(ChainId, ChannelId)> = ChannelStorageV1::<T>::iter_keys().collect();
116 keys.into_iter()
117 .filter(|(chain_id, channel_id)| {
118 get_channel::<T>(*chain_id, *channel_id)
119 .map(|channel| channel.state != ChannelState::Closed)
120 .unwrap_or_default()
121 })
122 .collect()
123 }
124}
125
126#[cfg(test)]
127mod tests {
128 use super::migrate_channels::Channels;
129 use super::*;
130 use crate::mock::chain_a::{new_test_ext, Runtime};
131 use frame_support::weights::RuntimeDbWeight;
132 use sp_runtime::traits::Get;
133
134 #[test]
135 fn test_channel_migration() {
136 let mut ext = new_test_ext();
137 let chain_id = ChainId::Consensus;
138 let channel_id = ChannelId::zero();
139 let channel = Channel {
140 channel_id,
141 state: ChannelState::Open,
142 next_inbox_nonce: Nonce::zero(),
143 next_outbox_nonce: Nonce::one(),
144 latest_response_received_message_nonce: Some(Nonce::from(100u32)),
145 max_outgoing_messages: 100,
146 fee: FeeModel { relay_fee: 100 },
147 maybe_owner: Some(100u64),
148 channel_reserve_fee: 200,
149 };
150
151 let channel_v1 = ChannelV1 {
152 channel_id,
153 state: ChannelState::Open,
154 next_inbox_nonce: Nonce::zero(),
155 next_outbox_nonce: Nonce::one(),
156 latest_response_received_message_nonce: Some(Nonce::from(100u32)),
157 max_outgoing_messages: 100,
158 maybe_owner: Some(100u64),
159 channel_reserve_fee: 200,
160 };
161
162 ext.execute_with(|| Channels::<Runtime>::insert(chain_id, channel_id, channel));
163
164 ext.commit_all().unwrap();
165
166 ext.execute_with(|| {
167 let weight = migrate_channels::<Runtime>();
168 let channel = ChannelStorageV1::<Runtime>::get(chain_id, channel_id).unwrap();
169 let db_weights: RuntimeDbWeight = <Runtime as frame_system::Config>::DbWeight::get();
170 assert_eq!(weight, db_weights.reads_writes(1, 1),);
171 assert_eq!(channel, channel_v1);
172 })
173 }
174}