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"] }
|
scale-info = { workspace = true, features = ["derive"] }
|
||||||
codec = { workspace = true, features = ["max-encoded-len"] }
|
codec = { workspace = true, features = ["max-encoded-len"] }
|
||||||
num-traits = { workspace = true }
|
num-traits = { workspace = true }
|
||||||
|
log = { workspace = true }
|
||||||
|
|
||||||
frame-benchmarking = { workspace = true, optional = true }
|
frame-benchmarking = { workspace = true, optional = true }
|
||||||
frame-support = { workspace = true }
|
frame-support = { workspace = true }
|
||||||
@ -31,6 +32,7 @@ default = ["std"]
|
|||||||
std = [
|
std = [
|
||||||
"scale-info/std",
|
"scale-info/std",
|
||||||
"codec/std",
|
"codec/std",
|
||||||
|
"log/std",
|
||||||
"num-traits/std",
|
"num-traits/std",
|
||||||
"frame-support/std",
|
"frame-support/std",
|
||||||
"frame-system/std",
|
"frame-system/std",
|
||||||
|
|||||||
@ -22,6 +22,7 @@ pub use ghost_traits::networks::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
mod math;
|
mod math;
|
||||||
|
pub mod migrations;
|
||||||
mod weights;
|
mod weights;
|
||||||
|
|
||||||
pub use crate::weights::WeightInfo;
|
pub use crate::weights::WeightInfo;
|
||||||
@ -35,6 +36,8 @@ mod mock;
|
|||||||
#[cfg(all(feature = "std", test))]
|
#[cfg(all(feature = "std", test))]
|
||||||
mod tests;
|
mod tests;
|
||||||
|
|
||||||
|
const LOG_TARGET: &str = "runtime::ghost-networks";
|
||||||
|
|
||||||
pub type BalanceOf<T> =
|
pub type BalanceOf<T> =
|
||||||
<<T as Config>::Currency as Inspect<<T as frame_system::Config>::AccountId>>::Balance;
|
<<T as Config>::Currency as Inspect<<T as frame_system::Config>::AccountId>>::Balance;
|
||||||
|
|
||||||
@ -123,6 +126,8 @@ where
|
|||||||
pub mod module {
|
pub mod module {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
|
||||||
|
|
||||||
#[pallet::config]
|
#[pallet::config]
|
||||||
pub trait Config: frame_system::Config {
|
pub trait Config: frame_system::Config {
|
||||||
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
|
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.
|
/// The origin required to remove network.
|
||||||
type RemoveOrigin: EnsureOrigin<Self::RuntimeOrigin>;
|
type RemoveOrigin: EnsureOrigin<Self::RuntimeOrigin>;
|
||||||
|
|
||||||
|
#[pallet::constant]
|
||||||
|
type MaxNetworks: Get<u32>;
|
||||||
|
|
||||||
/// Weight information for extrinsics in this module.
|
/// Weight information for extrinsics in this module.
|
||||||
type WeightInfo: WeightInfo;
|
type WeightInfo: WeightInfo;
|
||||||
}
|
}
|
||||||
@ -163,6 +171,8 @@ pub mod module {
|
|||||||
WrongGatekeeperAddress,
|
WrongGatekeeperAddress,
|
||||||
/// Topic name length not 66 or prefix `0x` missed.
|
/// Topic name length not 66 or prefix `0x` missed.
|
||||||
WrongTopicName,
|
WrongTopicName,
|
||||||
|
/// Could not store networks into bounded vector.
|
||||||
|
TooManyNetworks,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pallet::event]
|
#[pallet::event]
|
||||||
@ -243,6 +253,11 @@ pub mod module {
|
|||||||
#[pallet::getter(fn accumulated_commission)]
|
#[pallet::getter(fn accumulated_commission)]
|
||||||
pub type AccumulatedCommission<T: Config> = StorageValue<_, BalanceOf<T>, ValueQuery>;
|
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::storage]
|
||||||
#[pallet::getter(fn networks)]
|
#[pallet::getter(fn networks)]
|
||||||
pub type Networks<T: Config> =
|
pub type Networks<T: Config> =
|
||||||
@ -282,6 +297,7 @@ pub mod module {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[pallet::pallet]
|
#[pallet::pallet]
|
||||||
|
#[pallet::storage_version(STORAGE_VERSION)]
|
||||||
#[pallet::without_storage_info]
|
#[pallet::without_storage_info]
|
||||||
pub struct Pallet<T>(PhantomData<T>);
|
pub struct Pallet<T>(PhantomData<T>);
|
||||||
|
|
||||||
@ -470,12 +486,19 @@ impl<T: Config> Pallet<T> {
|
|||||||
Ok(())
|
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 });
|
Self::deposit_event(Event::<T>::NetworkRegistered { chain_id, network });
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Remove existent network.
|
/// Remove existent network.
|
||||||
pub fn do_remove_network(chain_id: T::NetworkId) -> DispatchResult {
|
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 {
|
Networks::<T>::try_mutate(&chain_id, |maybe_network| -> DispatchResult {
|
||||||
ensure!(maybe_network.is_some(), Error::<T>::NetworkDoesNotExist);
|
ensure!(maybe_network.is_some(), Error::<T>::NetworkDoesNotExist);
|
||||||
*maybe_network = None;
|
*maybe_network = None;
|
||||||
@ -723,10 +746,29 @@ impl<T: Config> NetworkDataBasicHandler for Pallet<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Config> NetworkDataInspectHandler<NetworkData> 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> {
|
fn get(n: &Self::NetworkId) -> Option<NetworkData> {
|
||||||
Networks::<T>::get(n)
|
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)> {
|
fn iter() -> PrefixIterator<(Self::NetworkId, NetworkData)> {
|
||||||
Networks::<T>::iter()
|
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 RegisterOrigin = EnsureSignedBy<RegistererAccount, AccountId>;
|
||||||
type UpdateOrigin = EnsureSignedBy<UpdaterAccount, AccountId>;
|
type UpdateOrigin = EnsureSignedBy<UpdaterAccount, AccountId>;
|
||||||
type RemoveOrigin = EnsureSignedBy<RemoverAccount, AccountId>;
|
type RemoveOrigin = EnsureSignedBy<RemoverAccount, AccountId>;
|
||||||
|
type MaxNetworks = ConstU32<3>;
|
||||||
type WeightInfo = ();
|
type WeightInfo = ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -36,7 +36,8 @@ fn register_and_check_network(chain_id: u32, network: NetworkData) {
|
|||||||
chain_id,
|
chain_id,
|
||||||
network.clone()
|
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]
|
#[test]
|
||||||
@ -44,6 +45,7 @@ fn could_add_network_from_authority() {
|
|||||||
ExtBuilder::build().execute_with(|| {
|
ExtBuilder::build().execute_with(|| {
|
||||||
let (chain_id, network) = prepare_network_data();
|
let (chain_id, network) = prepare_network_data();
|
||||||
assert_eq!(Networks::<Test>::get(chain_id), None);
|
assert_eq!(Networks::<Test>::get(chain_id), None);
|
||||||
|
assert_eq!(NetworkIndexes::<Test>::get(), vec![]);
|
||||||
assert_ok!(GhostNetworks::register_network(
|
assert_ok!(GhostNetworks::register_network(
|
||||||
RuntimeOrigin::signed(RegistererAccount::get()),
|
RuntimeOrigin::signed(RegistererAccount::get()),
|
||||||
chain_id,
|
chain_id,
|
||||||
@ -56,6 +58,7 @@ fn could_add_network_from_authority() {
|
|||||||
},
|
},
|
||||||
));
|
));
|
||||||
assert_eq!(Networks::<Test>::get(chain_id), Some(network));
|
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(|| {
|
ExtBuilder::build().execute_with(|| {
|
||||||
let (chain_id, network) = prepare_network_data();
|
let (chain_id, network) = prepare_network_data();
|
||||||
assert_eq!(Networks::<Test>::get(chain_id), None);
|
assert_eq!(Networks::<Test>::get(chain_id), None);
|
||||||
|
assert_eq!(NetworkIndexes::<Test>::get(), vec![]);
|
||||||
assert_err!(
|
assert_err!(
|
||||||
GhostNetworks::register_network(
|
GhostNetworks::register_network(
|
||||||
RuntimeOrigin::signed(RandomAccount::get()),
|
RuntimeOrigin::signed(RandomAccount::get()),
|
||||||
@ -89,6 +93,7 @@ fn could_not_add_network_from_random_account() {
|
|||||||
DispatchError::BadOrigin
|
DispatchError::BadOrigin
|
||||||
);
|
);
|
||||||
assert_eq!(Networks::<Test>::get(chain_id), None);
|
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,
|
chain_id,
|
||||||
));
|
));
|
||||||
assert_eq!(Networks::<Test>::get(chain_id), None);
|
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
|
DispatchError::BadOrigin
|
||||||
);
|
);
|
||||||
assert_eq!(Networks::<Test>::get(chain_id), Some(network));
|
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
|
crate::Error::<Test>::NetworkDoesNotExist
|
||||||
);
|
);
|
||||||
assert_eq!(Networks::<Test>::get(chain_id), None);
|
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