make networks pallet to be indexed storage map; migrations included
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
This commit is contained in:
parent
5b5e53e6fd
commit
cce2910cf8
@ -11,6 +11,7 @@ repository.workspace = true
|
||||
scale-info = { workspace = true, features = ["derive"] }
|
||||
codec = { workspace = true, features = ["max-encoded-len"] }
|
||||
num-traits = { workspace = true }
|
||||
log = { workspace = true }
|
||||
|
||||
frame-benchmarking = { workspace = true, optional = true }
|
||||
frame-support = { workspace = true }
|
||||
@ -31,6 +32,7 @@ default = ["std"]
|
||||
std = [
|
||||
"scale-info/std",
|
||||
"codec/std",
|
||||
"log/std",
|
||||
"num-traits/std",
|
||||
"frame-support/std",
|
||||
"frame-system/std",
|
||||
|
||||
@ -22,6 +22,7 @@ pub use ghost_traits::networks::{
|
||||
};
|
||||
|
||||
mod math;
|
||||
pub mod migrations;
|
||||
mod weights;
|
||||
|
||||
pub use crate::weights::WeightInfo;
|
||||
@ -35,6 +36,8 @@ mod mock;
|
||||
#[cfg(all(feature = "std", test))]
|
||||
mod tests;
|
||||
|
||||
const LOG_TARGET: &str = "runtime::ghost-networks";
|
||||
|
||||
pub type BalanceOf<T> =
|
||||
<<T as Config>::Currency as Inspect<<T as frame_system::Config>::AccountId>>::Balance;
|
||||
|
||||
@ -123,6 +126,8 @@ where
|
||||
pub mod module {
|
||||
use super::*;
|
||||
|
||||
const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
|
||||
|
||||
#[pallet::config]
|
||||
pub trait Config: frame_system::Config {
|
||||
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
|
||||
@ -149,6 +154,9 @@ pub mod module {
|
||||
/// The origin required to remove network.
|
||||
type RemoveOrigin: EnsureOrigin<Self::RuntimeOrigin>;
|
||||
|
||||
#[pallet::constant]
|
||||
type MaxNetworks: Get<u32>;
|
||||
|
||||
/// Weight information for extrinsics in this module.
|
||||
type WeightInfo: WeightInfo;
|
||||
}
|
||||
@ -163,6 +171,8 @@ pub mod module {
|
||||
WrongGatekeeperAddress,
|
||||
/// Topic name length not 66 or prefix `0x` missed.
|
||||
WrongTopicName,
|
||||
/// Could not store networks into bounded vector.
|
||||
TooManyNetworks,
|
||||
}
|
||||
|
||||
#[pallet::event]
|
||||
@ -243,6 +253,11 @@ pub mod module {
|
||||
#[pallet::getter(fn accumulated_commission)]
|
||||
pub type AccumulatedCommission<T: Config> = StorageValue<_, BalanceOf<T>, ValueQuery>;
|
||||
|
||||
#[pallet::storage]
|
||||
#[pallet::getter(fn network_indexes)]
|
||||
pub type NetworkIndexes<T: Config> =
|
||||
StorageValue<_, BoundedVec<T::NetworkId, T::MaxNetworks>, ValueQuery>;
|
||||
|
||||
#[pallet::storage]
|
||||
#[pallet::getter(fn networks)]
|
||||
pub type Networks<T: Config> =
|
||||
@ -282,6 +297,7 @@ pub mod module {
|
||||
}
|
||||
|
||||
#[pallet::pallet]
|
||||
#[pallet::storage_version(STORAGE_VERSION)]
|
||||
#[pallet::without_storage_info]
|
||||
pub struct Pallet<T>(PhantomData<T>);
|
||||
|
||||
@ -470,12 +486,19 @@ impl<T: Config> Pallet<T> {
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
NetworkIndexes::<T>::try_mutate(|ids| -> DispatchResult {
|
||||
ids.try_push(chain_id)
|
||||
.map_err(|_| Error::<T>::TooManyNetworks)?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
Self::deposit_event(Event::<T>::NetworkRegistered { chain_id, network });
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Remove existent network.
|
||||
pub fn do_remove_network(chain_id: T::NetworkId) -> DispatchResult {
|
||||
NetworkIndexes::<T>::mutate(|ids| ids.retain(|id| id != &chain_id));
|
||||
Networks::<T>::try_mutate(&chain_id, |maybe_network| -> DispatchResult {
|
||||
ensure!(maybe_network.is_some(), Error::<T>::NetworkDoesNotExist);
|
||||
*maybe_network = None;
|
||||
@ -723,10 +746,29 @@ impl<T: Config> NetworkDataBasicHandler for Pallet<T> {
|
||||
}
|
||||
|
||||
impl<T: Config> NetworkDataInspectHandler<NetworkData> for Pallet<T> {
|
||||
fn count() -> u32 {
|
||||
NetworkIndexes::<T>::get().len() as u32
|
||||
}
|
||||
|
||||
fn get(n: &Self::NetworkId) -> Option<NetworkData> {
|
||||
Networks::<T>::get(n)
|
||||
}
|
||||
|
||||
fn next_network_for_block(
|
||||
block_number: impl Into<usize>,
|
||||
) -> Option<(Self::NetworkId, NetworkData)> {
|
||||
let network_indexes = NetworkIndexes::<T>::get();
|
||||
block_number
|
||||
.into()
|
||||
.checked_rem(network_indexes.len())
|
||||
.map(|id| {
|
||||
network_indexes.get(id).copied().and_then(|network_id| {
|
||||
Self::get(&network_id).map(|network_data| (network_id, network_data))
|
||||
})
|
||||
})
|
||||
.flatten()
|
||||
}
|
||||
|
||||
fn iter() -> PrefixIterator<(Self::NetworkId, NetworkData)> {
|
||||
Networks::<T>::iter()
|
||||
}
|
||||
|
||||
9
pallets/networks/src/migrations/mod.rs
Normal file
9
pallets/networks/src/migrations/mod.rs
Normal file
@ -0,0 +1,9 @@
|
||||
pub mod v1;
|
||||
|
||||
pub type MigrateV0ToV1<T> = frame_support::migrations::VersionedMigration<
|
||||
0,
|
||||
1,
|
||||
v1::StoreNetworkIdsIntoBoundedVec<T>,
|
||||
crate::Pallet<T>,
|
||||
<T as frame_system::Config>::DbWeight,
|
||||
>;
|
||||
41
pallets/networks/src/migrations/v1.rs
Normal file
41
pallets/networks/src/migrations/v1.rs
Normal file
@ -0,0 +1,41 @@
|
||||
use frame_support::{
|
||||
traits::{Get, UncheckedOnRuntimeUpgrade},
|
||||
weights::Weight,
|
||||
};
|
||||
use sp_std::marker::PhantomData;
|
||||
|
||||
use crate::{BoundedVec, Config, NetworkIndexes, Networks, Vec, LOG_TARGET};
|
||||
|
||||
pub struct StoreNetworkIdsIntoBoundedVec<T>(PhantomData<T>);
|
||||
impl<T: Config> UncheckedOnRuntimeUpgrade for StoreNetworkIdsIntoBoundedVec<T> {
|
||||
fn on_runtime_upgrade() -> Weight {
|
||||
let mut weight = T::DbWeight::get().reads(1);
|
||||
|
||||
let network_ids: Vec<T::NetworkId> = Networks::<T>::iter_keys().collect();
|
||||
let networks_count = network_ids.len();
|
||||
|
||||
weight = weight.saturating_add(T::DbWeight::get().reads(networks_count as u64));
|
||||
|
||||
let writes = BoundedVec::<T::NetworkId, T::MaxNetworks>::try_from(network_ids)
|
||||
.inspect_err(|err| {
|
||||
log::error!(
|
||||
target: LOG_TARGET,
|
||||
"⛓️ Network ids to bounded_vec migration failed: {:?}",
|
||||
err,
|
||||
)
|
||||
})
|
||||
.ok()
|
||||
.map(|bounded_networks| {
|
||||
NetworkIndexes::<T>::put(bounded_networks);
|
||||
log::info!(
|
||||
target: LOG_TARGET,
|
||||
"⛓️ Network ids to bounded_vec migration success: {} networks moved",
|
||||
networks_count,
|
||||
);
|
||||
1u64
|
||||
})
|
||||
.unwrap_or_default();
|
||||
|
||||
weight.saturating_add(T::DbWeight::get().writes(writes))
|
||||
}
|
||||
}
|
||||
@ -98,6 +98,7 @@ impl ghost_networks::Config for Test {
|
||||
type RegisterOrigin = EnsureSignedBy<RegistererAccount, AccountId>;
|
||||
type UpdateOrigin = EnsureSignedBy<UpdaterAccount, AccountId>;
|
||||
type RemoveOrigin = EnsureSignedBy<RemoverAccount, AccountId>;
|
||||
type MaxNetworks = ConstU32<3>;
|
||||
type WeightInfo = ();
|
||||
}
|
||||
|
||||
|
||||
@ -36,7 +36,8 @@ fn register_and_check_network(chain_id: u32, network: NetworkData) {
|
||||
chain_id,
|
||||
network.clone()
|
||||
));
|
||||
assert_eq!(Networks::<Test>::get(chain_id), Some(network.clone()));
|
||||
assert_eq!(Networks::<Test>::get(chain_id), Some(network));
|
||||
assert_eq!(NetworkIndexes::<Test>::get(), vec![chain_id]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -44,6 +45,7 @@ fn could_add_network_from_authority() {
|
||||
ExtBuilder::build().execute_with(|| {
|
||||
let (chain_id, network) = prepare_network_data();
|
||||
assert_eq!(Networks::<Test>::get(chain_id), None);
|
||||
assert_eq!(NetworkIndexes::<Test>::get(), vec![]);
|
||||
assert_ok!(GhostNetworks::register_network(
|
||||
RuntimeOrigin::signed(RegistererAccount::get()),
|
||||
chain_id,
|
||||
@ -56,6 +58,7 @@ fn could_add_network_from_authority() {
|
||||
},
|
||||
));
|
||||
assert_eq!(Networks::<Test>::get(chain_id), Some(network));
|
||||
assert_eq!(NetworkIndexes::<Test>::get(), vec![chain_id]);
|
||||
});
|
||||
}
|
||||
|
||||
@ -64,6 +67,7 @@ fn could_not_add_network_from_random_account() {
|
||||
ExtBuilder::build().execute_with(|| {
|
||||
let (chain_id, network) = prepare_network_data();
|
||||
assert_eq!(Networks::<Test>::get(chain_id), None);
|
||||
assert_eq!(NetworkIndexes::<Test>::get(), vec![]);
|
||||
assert_err!(
|
||||
GhostNetworks::register_network(
|
||||
RuntimeOrigin::signed(RandomAccount::get()),
|
||||
@ -89,6 +93,7 @@ fn could_not_add_network_from_random_account() {
|
||||
DispatchError::BadOrigin
|
||||
);
|
||||
assert_eq!(Networks::<Test>::get(chain_id), None);
|
||||
assert_eq!(NetworkIndexes::<Test>::get(), vec![]);
|
||||
});
|
||||
}
|
||||
|
||||
@ -1055,6 +1060,7 @@ fn could_remove_network_from_authority_account() {
|
||||
chain_id,
|
||||
));
|
||||
assert_eq!(Networks::<Test>::get(chain_id), None);
|
||||
assert_eq!(NetworkIndexes::<Test>::get(), vec![]);
|
||||
});
|
||||
}
|
||||
|
||||
@ -1079,6 +1085,7 @@ fn could_not_remove_network_from_random_account() {
|
||||
DispatchError::BadOrigin
|
||||
);
|
||||
assert_eq!(Networks::<Test>::get(chain_id), Some(network));
|
||||
assert_eq!(NetworkIndexes::<Test>::get(), vec![chain_id]);
|
||||
});
|
||||
}
|
||||
|
||||
@ -1092,6 +1099,7 @@ fn could_not_remove_non_existent_network() {
|
||||
crate::Error::<Test>::NetworkDoesNotExist
|
||||
);
|
||||
assert_eq!(Networks::<Test>::get(chain_id), None);
|
||||
assert_eq!(NetworkIndexes::<Test>::get(), vec![]);
|
||||
});
|
||||
}
|
||||
|
||||
@ -1898,3 +1906,66 @@ fn check_bridged_inflation_curve_for_big_commissions() {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn migration_from_v0_to_v1_works() {
|
||||
ExtBuilder::build().execute_with(|| {
|
||||
let (chain_id, network) = prepare_network_data();
|
||||
let other_chain_id = chain_id.saturating_add(1);
|
||||
|
||||
assert_eq!(Networks::<Test>::get(chain_id), None);
|
||||
assert_ok!(GhostNetworks::register_network(
|
||||
RuntimeOrigin::signed(RegistererAccount::get()),
|
||||
chain_id,
|
||||
network.clone(),
|
||||
));
|
||||
assert_ok!(GhostNetworks::register_network(
|
||||
RuntimeOrigin::signed(RegistererAccount::get()),
|
||||
other_chain_id,
|
||||
network.clone(),
|
||||
));
|
||||
NetworkIndexes::<Test>::kill();
|
||||
|
||||
assert_eq!(Networks::<Test>::get(chain_id), Some(network.clone()));
|
||||
assert_eq!(Networks::<Test>::get(other_chain_id), Some(network));
|
||||
assert_eq!(NetworkIndexes::<Test>::get(), vec![]);
|
||||
|
||||
type Migrate = crate::migrations::MigrateV0ToV1<Test>;
|
||||
<Migrate as frame_support::traits::OnRuntimeUpgrade>::on_runtime_upgrade();
|
||||
assert_eq!(
|
||||
NetworkIndexes::<Test>::get(),
|
||||
vec![chain_id, other_chain_id]
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn migration_from_v0_to_v1_does_not_run_twice() {
|
||||
ExtBuilder::build().execute_with(|| {
|
||||
StorageVersion::new(1).put::<GhostNetworks>();
|
||||
|
||||
let (chain_id, network) = prepare_network_data();
|
||||
let other_chain_id = chain_id.saturating_add(1);
|
||||
|
||||
assert_eq!(Networks::<Test>::get(chain_id), None);
|
||||
assert_ok!(GhostNetworks::register_network(
|
||||
RuntimeOrigin::signed(RegistererAccount::get()),
|
||||
chain_id,
|
||||
network.clone(),
|
||||
));
|
||||
assert_ok!(GhostNetworks::register_network(
|
||||
RuntimeOrigin::signed(RegistererAccount::get()),
|
||||
other_chain_id,
|
||||
network.clone(),
|
||||
));
|
||||
NetworkIndexes::<Test>::kill();
|
||||
|
||||
assert_eq!(Networks::<Test>::get(chain_id), Some(network.clone()));
|
||||
assert_eq!(Networks::<Test>::get(other_chain_id), Some(network));
|
||||
assert_eq!(NetworkIndexes::<Test>::get(), vec![]);
|
||||
|
||||
type Migrate = crate::migrations::MigrateV0ToV1<Test>;
|
||||
<Migrate as frame_support::traits::OnRuntimeUpgrade>::on_runtime_upgrade();
|
||||
assert_eq!(NetworkIndexes::<Test>::get(), vec![]);
|
||||
});
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user