pallet_transporter/
migrations.rs1use crate::{Config, Pallet};
4use core::marker::PhantomData;
5use frame_support::migrations::VersionedMigration;
6use frame_support::traits::UncheckedOnRuntimeUpgrade;
7use frame_support::weights::Weight;
8
9pub type VersionCheckedMigrateTransporterV0ToV1<T> = VersionedMigration<
12 0,
13 1,
14 VersionUncheckedMigrateV0ToV1<T>,
15 Pallet<T>,
16 <T as frame_system::Config>::DbWeight,
17>;
18
19pub struct VersionUncheckedMigrateV0ToV1<T>(PhantomData<T>);
20impl<T: Config> UncheckedOnRuntimeUpgrade for VersionUncheckedMigrateV0ToV1<T> {
21 fn on_runtime_upgrade() -> Weight {
22 seed_all_domains_supply::seed::<T>()
23 }
24}
25
26mod seed_all_domains_supply {
27 use crate::{
28 AllDomainsSupply, BalanceOf, CancelledTransfers, Config, DomainBalances,
29 UnconfirmedTransfers,
30 };
31 use frame_support::traits::{Defensive, Get};
32 use frame_support::weights::Weight;
33 use sp_runtime::traits::{CheckedAdd, Zero};
34
35 pub(super) fn seed<T: Config>() -> Weight {
36 if !T::SelfChainId::get().is_consensus_chain() {
39 return Weight::zero();
40 }
41
42 let mut reads: u64 = 0;
43 let mut total = BalanceOf::<T>::zero();
44 for value in DomainBalances::<T>::iter_values() {
45 reads += 1;
46 total = total.checked_add(&value).defensive_unwrap_or(total);
47 }
48 for value in UnconfirmedTransfers::<T>::iter_values() {
49 reads += 1;
50 total = total.checked_add(&value).defensive_unwrap_or(total);
51 }
52 for value in CancelledTransfers::<T>::iter_values() {
53 reads += 1;
54 total = total.checked_add(&value).defensive_unwrap_or(total);
55 }
56
57 AllDomainsSupply::<T>::put(total);
58
59 let base_weight = T::DbWeight::get().reads_writes(1, 1);
61 base_weight.saturating_add(T::DbWeight::get().reads(reads))
62 }
63}
64
65#[cfg(test)]
66mod tests {
67 use super::VersionCheckedMigrateTransporterV0ToV1;
68 use super::seed_all_domains_supply::seed;
69 use crate::mock::consensus::{ConsensusMockRuntime, new_test_ext as new_consensus_test_ext};
70 use crate::mock::{MockRuntime, assert_all_domains_supply_reconciles, new_test_ext};
71 use crate::{
72 AllDomainsSupply, CancelledTransfers, DomainBalances, Pallet, UnconfirmedTransfers,
73 };
74 use frame_support::traits::{GetStorageVersion, OnRuntimeUpgrade, StorageVersion};
75 use sp_domains::DomainId;
76 use sp_messenger::messages::ChainId;
77
78 #[test]
79 fn seed_migration_sets_aggregate_from_existing_storage() {
80 new_consensus_test_ext().execute_with(|| {
81 let domain = DomainId::new(0);
82 DomainBalances::<ConsensusMockRuntime>::insert(domain, 500u64);
83 UnconfirmedTransfers::<ConsensusMockRuntime>::insert(
84 ChainId::Consensus,
85 ChainId::Domain(domain),
86 70u64,
87 );
88 CancelledTransfers::<ConsensusMockRuntime>::insert(
89 ChainId::Domain(domain),
90 ChainId::Consensus,
91 5u64,
92 );
93 assert_eq!(AllDomainsSupply::<ConsensusMockRuntime>::get(), 0);
95
96 seed::<ConsensusMockRuntime>();
97
98 assert_eq!(Pallet::<ConsensusMockRuntime>::all_domains_supply(), 575);
99 assert_all_domains_supply_reconciles::<ConsensusMockRuntime>();
100 });
101 }
102
103 #[test]
104 fn seed_migration_sums_multiple_entries_across_maps() {
105 new_consensus_test_ext().execute_with(|| {
106 DomainBalances::<ConsensusMockRuntime>::insert(DomainId::new(0), 100u64);
107 DomainBalances::<ConsensusMockRuntime>::insert(DomainId::new(1), 200u64);
108 DomainBalances::<ConsensusMockRuntime>::insert(DomainId::new(2), 300u64);
109 UnconfirmedTransfers::<ConsensusMockRuntime>::insert(
110 ChainId::Consensus,
111 ChainId::Domain(DomainId::new(0)),
112 10u64,
113 );
114 UnconfirmedTransfers::<ConsensusMockRuntime>::insert(
115 ChainId::Consensus,
116 ChainId::Domain(DomainId::new(1)),
117 20u64,
118 );
119 CancelledTransfers::<ConsensusMockRuntime>::insert(
120 ChainId::Domain(DomainId::new(0)),
121 ChainId::Consensus,
122 1u64,
123 );
124 CancelledTransfers::<ConsensusMockRuntime>::insert(
125 ChainId::Domain(DomainId::new(1)),
126 ChainId::Consensus,
127 2u64,
128 );
129
130 seed::<ConsensusMockRuntime>();
131
132 assert_eq!(Pallet::<ConsensusMockRuntime>::all_domains_supply(), 633);
133 assert_all_domains_supply_reconciles::<ConsensusMockRuntime>();
134 });
135 }
136
137 #[test]
138 fn seed_migration_with_empty_maps_is_zero() {
139 new_consensus_test_ext().execute_with(|| {
140 seed::<ConsensusMockRuntime>();
141 assert_eq!(Pallet::<ConsensusMockRuntime>::all_domains_supply(), 0);
142 assert_all_domains_supply_reconciles::<ConsensusMockRuntime>();
143 });
144 }
145
146 #[test]
147 fn seed_migration_is_noop_on_domains() {
148 new_test_ext().execute_with(|| {
149 DomainBalances::<MockRuntime>::insert(DomainId::new(0), 500u64);
151 UnconfirmedTransfers::<MockRuntime>::insert(
152 ChainId::Consensus,
153 ChainId::Domain(DomainId::new(0)),
154 70u64,
155 );
156
157 seed::<MockRuntime>();
158
159 assert_eq!(Pallet::<MockRuntime>::all_domains_supply(), 0);
160 });
161 }
162
163 #[test]
164 fn versioned_migration_seeds_once_and_is_idempotent() {
165 new_consensus_test_ext().execute_with(|| {
166 StorageVersion::new(0).put::<Pallet<ConsensusMockRuntime>>();
168 DomainBalances::<ConsensusMockRuntime>::insert(DomainId::new(0), 500u64);
169 UnconfirmedTransfers::<ConsensusMockRuntime>::insert(
170 ChainId::Consensus,
171 ChainId::Domain(DomainId::new(0)),
172 70u64,
173 );
174 CancelledTransfers::<ConsensusMockRuntime>::insert(
175 ChainId::Domain(DomainId::new(0)),
176 ChainId::Consensus,
177 5u64,
178 );
179
180 <VersionCheckedMigrateTransporterV0ToV1<ConsensusMockRuntime> as OnRuntimeUpgrade>::on_runtime_upgrade();
181 assert_eq!(Pallet::<ConsensusMockRuntime>::all_domains_supply(), 575);
182 assert_eq!(
183 Pallet::<ConsensusMockRuntime>::on_chain_storage_version(),
184 StorageVersion::new(1)
185 );
186
187 DomainBalances::<ConsensusMockRuntime>::insert(DomainId::new(1), 1_000u64);
189 <VersionCheckedMigrateTransporterV0ToV1<ConsensusMockRuntime> as OnRuntimeUpgrade>::on_runtime_upgrade();
190 assert_eq!(
191 Pallet::<ConsensusMockRuntime>::all_domains_supply(),
192 575,
193 "migration must be idempotent (version-gated)"
194 );
195 });
196 }
197}