539 lines
18 KiB
Rust
Executable File
539 lines
18 KiB
Rust
Executable File
#![cfg_attr(not(feature = "std"), no_std)]
|
|
#![allow(clippy::large_enum_variant)]
|
|
#![allow(clippy::too_many_arguments)]
|
|
|
|
use frame_support::{
|
|
pallet_prelude::*,
|
|
storage::PrefixIterator, traits::EnsureOrigin,
|
|
};
|
|
use frame_system::pallet_prelude::*;
|
|
use scale_info::TypeInfo;
|
|
use sp_runtime::{
|
|
traits::{AtLeast32BitUnsigned, Member},
|
|
DispatchResult,
|
|
};
|
|
use sp_std::prelude::*;
|
|
|
|
pub use ghost_traits::networks::{
|
|
NetworkDataBasicHandler, NetworkDataInspectHandler,
|
|
NetworkDataMutateHandler,
|
|
};
|
|
|
|
mod weights;
|
|
|
|
pub use module::*;
|
|
pub use crate::weights::WeightInfo;
|
|
|
|
#[cfg(any(feature = "runtime-benchmarks", test))]
|
|
mod benchmarking;
|
|
#[cfg(all(feature = "std", test))]
|
|
mod mock;
|
|
#[cfg(all(feature = "std", test))]
|
|
mod tests;
|
|
|
|
#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)]
|
|
pub enum NetworkType {
|
|
Evm = 0,
|
|
Utxo = 1,
|
|
Undefined = 2,
|
|
}
|
|
|
|
impl Default for NetworkType {
|
|
fn default() -> Self { NetworkType::Evm }
|
|
}
|
|
|
|
#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)]
|
|
pub struct NetworkData {
|
|
pub chain_name: Vec<u8>,
|
|
pub default_endpoint: Vec<u8>,
|
|
pub gatekeeper: Vec<u8>,
|
|
pub topic_name: Vec<u8>,
|
|
pub finality_delay: Option<u64>,
|
|
pub release_delay: Option<u64>,
|
|
pub network_type: NetworkType,
|
|
pub incoming_fee: u32,
|
|
pub outgoing_fee: u32,
|
|
}
|
|
|
|
#[frame_support::pallet]
|
|
pub mod module {
|
|
use super::*;
|
|
|
|
#[pallet::config]
|
|
pub trait Config: frame_system::Config {
|
|
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
|
|
|
|
/// The type used as a unique network id.
|
|
type NetworkId: Parameter
|
|
+ Member
|
|
+ Parameter
|
|
+ AtLeast32BitUnsigned
|
|
+ Default
|
|
+ Copy
|
|
+ Ord
|
|
+ TypeInfo
|
|
+ MaybeSerializeDeserialize
|
|
+ MaxEncodedLen;
|
|
|
|
/// The origin required to register new network.
|
|
type RegisterOrigin: EnsureOrigin<Self::RuntimeOrigin>;
|
|
/// The origin required to update network information.
|
|
type UpdateOrigin: EnsureOrigin<Self::RuntimeOrigin>;
|
|
/// The origin required to remove network.
|
|
type RemoveOrigin: EnsureOrigin<Self::RuntimeOrigin>;
|
|
|
|
/// Weight information for extrinsics in this module.
|
|
type WeightInfo: WeightInfo;
|
|
}
|
|
|
|
#[pallet::error]
|
|
pub enum Error<T> {
|
|
/// Network already registered.
|
|
NetworkAlreadyRegistered,
|
|
/// Network does not exist.
|
|
NetworkDoesNotExist,
|
|
/// Gatekeeper address length not 42 or prefix `0x` missed.
|
|
WrongGatekeeperAddress,
|
|
/// Topic name length not 66 or prefix `0x` missed.
|
|
WrongTopicName,
|
|
}
|
|
|
|
#[pallet::event]
|
|
#[pallet::generate_deposit(pub(crate) fn deposit_event)]
|
|
pub enum Event<T: Config> {
|
|
NetworkRegistered { chain_id: T::NetworkId, network: NetworkData },
|
|
NetworkNameUpdated { chain_id: T::NetworkId, chain_name: Vec<u8> },
|
|
NetworkEndpointUpdated { chain_id: T::NetworkId, default_endpoint: Vec<u8> },
|
|
NetworkFinalityDelayUpdated { chain_id: T::NetworkId, finality_delay: Option<u64> },
|
|
NetworkReleaseDelayUpdated { chain_id: T::NetworkId, release_delay: Option<u64> },
|
|
NetworkTypeUpdated { chain_id: T::NetworkId, network_type: NetworkType },
|
|
NetworkGatekeeperUpdated { chain_id: T::NetworkId, gatekeeper: Vec<u8> },
|
|
NetworkTopicNameUpdated { chain_id: T::NetworkId, topic_name: Vec<u8> },
|
|
NetworkIncomingFeeUpdated { chain_id: T::NetworkId, incoming_fee: u32 },
|
|
NetworkOutgoingFeeUpdated { chain_id: T::NetworkId, outgoing_fee: u32 },
|
|
NetworkRemoved { chain_id: T::NetworkId },
|
|
}
|
|
|
|
#[pallet::storage]
|
|
#[pallet::getter(fn networks)]
|
|
pub type Networks<T: Config> =
|
|
StorageMap<_, Twox64Concat, T::NetworkId, NetworkData, OptionQuery>;
|
|
|
|
#[pallet::genesis_config]
|
|
pub struct GenesisConfig<T: Config> {
|
|
pub networks: Vec<(T::NetworkId, Vec<u8>)>,
|
|
}
|
|
|
|
impl<T: Config> Default for GenesisConfig<T> {
|
|
fn default() -> Self {
|
|
Self { networks: vec![] }
|
|
}
|
|
}
|
|
|
|
#[pallet::genesis_build]
|
|
impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
|
|
fn build(&self) {
|
|
if !self.networks.is_empty() {
|
|
self.networks.iter().for_each(|(chain_id, network_metadata)| {
|
|
let network =
|
|
NetworkData::decode(&mut &network_metadata[..])
|
|
.expect("Error decoding NetworkData");
|
|
Pallet::<T>::do_register_network(chain_id.clone(), network)
|
|
.expect("Error registering network");
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
#[pallet::pallet]
|
|
#[pallet::without_storage_info]
|
|
pub struct Pallet<T>(PhantomData<T>);
|
|
|
|
#[pallet::hooks]
|
|
impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {}
|
|
|
|
#[pallet::call]
|
|
impl<T: Config> Pallet<T> {
|
|
#[pallet::call_index(0)]
|
|
#[pallet::weight(T::WeightInfo::register_network(
|
|
network.chain_name.len() as u32,
|
|
network.default_endpoint.len() as u32,
|
|
))]
|
|
pub fn register_network(
|
|
origin: OriginFor<T>,
|
|
chain_id: T::NetworkId,
|
|
network: NetworkData,
|
|
) -> DispatchResult {
|
|
T::RegisterOrigin::ensure_origin_or_root(origin)?;
|
|
Self::do_register_network(chain_id, network)
|
|
}
|
|
|
|
#[pallet::call_index(1)]
|
|
#[pallet::weight(T::WeightInfo::update_network_name(
|
|
chain_name.len() as u32,
|
|
))]
|
|
pub fn update_network_name(
|
|
origin: OriginFor<T>,
|
|
chain_id: T::NetworkId,
|
|
chain_name: Vec<u8>,
|
|
) -> DispatchResult {
|
|
T::UpdateOrigin::ensure_origin_or_root(origin)?;
|
|
Self::do_update_network_name(
|
|
chain_id,
|
|
chain_name,
|
|
)
|
|
}
|
|
|
|
#[pallet::call_index(2)]
|
|
#[pallet::weight(T::WeightInfo::update_network_endpoint(
|
|
default_endpoint.len() as u32
|
|
))]
|
|
pub fn update_network_endpoint(
|
|
origin: OriginFor<T>,
|
|
chain_id: T::NetworkId,
|
|
default_endpoint: Vec<u8>,
|
|
) -> DispatchResult {
|
|
T::UpdateOrigin::ensure_origin_or_root(origin)?;
|
|
Self::do_update_network_endpoint(
|
|
chain_id,
|
|
default_endpoint,
|
|
)
|
|
}
|
|
|
|
#[pallet::call_index(3)]
|
|
#[pallet::weight(T::WeightInfo::update_network_finality_delay())]
|
|
pub fn update_network_finality_delay(
|
|
origin: OriginFor<T>,
|
|
chain_id: T::NetworkId,
|
|
finality_delay: Option<u64>,
|
|
) -> DispatchResult {
|
|
T::UpdateOrigin::ensure_origin_or_root(origin)?;
|
|
Self::do_update_network_finality_delay(
|
|
chain_id,
|
|
finality_delay,
|
|
)
|
|
}
|
|
|
|
#[pallet::call_index(4)]
|
|
#[pallet::weight(T::WeightInfo::update_network_release_delay())]
|
|
pub fn update_network_release_delay(
|
|
origin: OriginFor<T>,
|
|
chain_id: T::NetworkId,
|
|
release_delay: Option<u64>,
|
|
) -> DispatchResult {
|
|
T::UpdateOrigin::ensure_origin_or_root(origin)?;
|
|
Self::do_update_network_release_delay(
|
|
chain_id,
|
|
release_delay,
|
|
)
|
|
}
|
|
|
|
#[pallet::call_index(5)]
|
|
#[pallet::weight(T::WeightInfo::update_network_type())]
|
|
pub fn update_network_type(
|
|
origin: OriginFor<T>,
|
|
chain_id: T::NetworkId,
|
|
network_type: NetworkType,
|
|
) -> DispatchResult {
|
|
T::UpdateOrigin::ensure_origin_or_root(origin)?;
|
|
Self::do_update_network_type(
|
|
chain_id,
|
|
network_type,
|
|
)
|
|
}
|
|
|
|
#[pallet::call_index(6)]
|
|
#[pallet::weight(T::WeightInfo::update_network_gatekeeper())]
|
|
pub fn update_network_gatekeeper(
|
|
origin: OriginFor<T>,
|
|
chain_id: T::NetworkId,
|
|
gatekeeper: Vec<u8>,
|
|
) -> DispatchResult {
|
|
T::UpdateOrigin::ensure_origin_or_root(origin)?;
|
|
Self::do_update_network_gatekeeper(
|
|
chain_id,
|
|
gatekeeper,
|
|
)
|
|
}
|
|
|
|
#[pallet::call_index(7)]
|
|
#[pallet::weight(T::WeightInfo::update_network_topic_name())]
|
|
pub fn update_network_topic_name(
|
|
origin: OriginFor<T>,
|
|
chain_id: T::NetworkId,
|
|
topic_name: Vec<u8>,
|
|
) -> DispatchResult {
|
|
T::UpdateOrigin::ensure_origin_or_root(origin)?;
|
|
Self::do_update_network_topic_name(
|
|
chain_id,
|
|
topic_name,
|
|
)
|
|
}
|
|
|
|
#[pallet::call_index(8)]
|
|
#[pallet::weight(T::WeightInfo::update_incoming_network_fee())]
|
|
pub fn update_incoming_network_fee(
|
|
origin: OriginFor<T>,
|
|
chain_id: T::NetworkId,
|
|
incoming_fee: u32,
|
|
) -> DispatchResult {
|
|
T::UpdateOrigin::ensure_origin_or_root(origin)?;
|
|
Self::do_update_incoming_network_fee(
|
|
chain_id,
|
|
incoming_fee,
|
|
)
|
|
}
|
|
|
|
#[pallet::call_index(9)]
|
|
#[pallet::weight(T::WeightInfo::update_outgoing_network_fee())]
|
|
pub fn update_outgoing_network_fee(
|
|
origin: OriginFor<T>,
|
|
chain_id: T::NetworkId,
|
|
outgoing_fee: u32,
|
|
) -> DispatchResult {
|
|
T::UpdateOrigin::ensure_origin_or_root(origin)?;
|
|
Self::do_update_outgoing_network_fee(
|
|
chain_id,
|
|
outgoing_fee,
|
|
)
|
|
}
|
|
|
|
#[pallet::call_index(10)]
|
|
#[pallet::weight(T::WeightInfo::remove_network())]
|
|
pub fn remove_network(
|
|
origin: OriginFor<T>,
|
|
chain_id: T::NetworkId,
|
|
) -> DispatchResult {
|
|
T::RemoveOrigin::ensure_origin_or_root(origin)?;
|
|
Self::do_remove_network(chain_id)
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<T: Config> Pallet<T> {
|
|
/// Register a new network.
|
|
pub fn do_register_network(
|
|
chain_id: T::NetworkId,
|
|
network: NetworkData,
|
|
) -> DispatchResult {
|
|
Networks::<T>::try_mutate(&chain_id, |maybe_network| -> DispatchResult {
|
|
ensure!(maybe_network.is_none(), Error::<T>::NetworkAlreadyRegistered);
|
|
*maybe_network = Some(network.clone());
|
|
Ok(())
|
|
})?;
|
|
|
|
Self::deposit_event(Event::<T>::NetworkRegistered { chain_id, network });
|
|
Ok(())
|
|
}
|
|
|
|
/// Remove existent network.
|
|
pub fn do_remove_network(chain_id: T::NetworkId) -> DispatchResult {
|
|
Networks::<T>::try_mutate(&chain_id, |maybe_network| -> DispatchResult {
|
|
ensure!(maybe_network.is_some(), Error::<T>::NetworkDoesNotExist);
|
|
*maybe_network = None;
|
|
Ok(())
|
|
})?;
|
|
|
|
Self::deposit_event(Event::<T>::NetworkRemoved { chain_id });
|
|
Ok(())
|
|
}
|
|
|
|
/// Update existent network name.
|
|
pub fn do_update_network_name(
|
|
chain_id: T::NetworkId,
|
|
chain_name: Vec<u8>,
|
|
) -> DispatchResult {
|
|
Networks::<T>::try_mutate(&chain_id, |maybe_network| -> DispatchResult {
|
|
ensure!(maybe_network.is_some(), Error::<T>::NetworkDoesNotExist);
|
|
let net = maybe_network.as_mut().unwrap();
|
|
net.chain_name = chain_name.clone();
|
|
*maybe_network = Some(net.clone());
|
|
Ok(())
|
|
})?;
|
|
|
|
Self::deposit_event(Event::<T>::NetworkNameUpdated {
|
|
chain_id,
|
|
chain_name,
|
|
});
|
|
Ok(())
|
|
}
|
|
|
|
/// Update existent network default endpoint.
|
|
pub fn do_update_network_endpoint(
|
|
chain_id: T::NetworkId,
|
|
default_endpoint: Vec<u8>,
|
|
) -> DispatchResult {
|
|
Networks::<T>::try_mutate(&chain_id, |maybe_network| -> DispatchResult {
|
|
ensure!(maybe_network.is_some(), Error::<T>::NetworkDoesNotExist);
|
|
let net = maybe_network.as_mut().unwrap();
|
|
net.default_endpoint = default_endpoint.clone();
|
|
*maybe_network = Some(net.clone());
|
|
Ok(())
|
|
})?;
|
|
Self::deposit_event(Event::<T>::NetworkEndpointUpdated {
|
|
chain_id,
|
|
default_endpoint,
|
|
});
|
|
Ok(())
|
|
}
|
|
|
|
/// Update existent network default endpoint.
|
|
pub fn do_update_network_finality_delay(
|
|
chain_id: T::NetworkId,
|
|
finality_delay: Option<u64>,
|
|
) -> DispatchResult {
|
|
Networks::<T>::try_mutate(&chain_id, |maybe_network| -> DispatchResult {
|
|
ensure!(maybe_network.is_some(), Error::<T>::NetworkDoesNotExist);
|
|
let net = maybe_network.as_mut().unwrap();
|
|
net.finality_delay = finality_delay;
|
|
*maybe_network = Some(net.clone());
|
|
Ok(())
|
|
})?;
|
|
Self::deposit_event(Event::<T>::NetworkFinalityDelayUpdated {
|
|
chain_id,
|
|
finality_delay,
|
|
});
|
|
Ok(())
|
|
}
|
|
|
|
/// Update existent network default endpoint.
|
|
pub fn do_update_network_release_delay(
|
|
chain_id: T::NetworkId,
|
|
release_delay: Option<u64>,
|
|
) -> DispatchResult {
|
|
Networks::<T>::try_mutate(&chain_id, |maybe_network| -> DispatchResult {
|
|
ensure!(maybe_network.is_some(), Error::<T>::NetworkDoesNotExist);
|
|
let net = maybe_network.as_mut().unwrap();
|
|
net.release_delay = release_delay;
|
|
*maybe_network = Some(net.clone());
|
|
Ok(())
|
|
})?;
|
|
Self::deposit_event(Event::<T>::NetworkReleaseDelayUpdated {
|
|
chain_id,
|
|
release_delay,
|
|
});
|
|
Ok(())
|
|
}
|
|
|
|
/// Update existent network type.
|
|
pub fn do_update_network_type(
|
|
chain_id: T::NetworkId,
|
|
network_type: NetworkType,
|
|
) -> DispatchResult {
|
|
Networks::<T>::try_mutate(&chain_id, |maybe_network| -> DispatchResult {
|
|
ensure!(maybe_network.is_some(), Error::<T>::NetworkDoesNotExist);
|
|
let net = maybe_network.as_mut().unwrap();
|
|
net.network_type = network_type.clone();
|
|
*maybe_network = Some(net.clone());
|
|
Ok(())
|
|
})?;
|
|
Self::deposit_event(Event::<T>::NetworkTypeUpdated {
|
|
chain_id,
|
|
network_type,
|
|
});
|
|
Ok(())
|
|
}
|
|
|
|
/// Update existent network gatekeeper.
|
|
pub fn do_update_network_gatekeeper(
|
|
chain_id: T::NetworkId,
|
|
gatekeeper: Vec<u8>,
|
|
) -> DispatchResult {
|
|
ensure!(gatekeeper.len() == 42 && gatekeeper[0] == 48 && gatekeeper[1] == 120,
|
|
Error::<T>::WrongGatekeeperAddress);
|
|
Networks::<T>::try_mutate(&chain_id, |maybe_network| -> DispatchResult {
|
|
ensure!(maybe_network.is_some(), Error::<T>::NetworkDoesNotExist);
|
|
let net = maybe_network.as_mut().unwrap();
|
|
net.gatekeeper = gatekeeper.clone();
|
|
*maybe_network = Some(net.clone());
|
|
Ok(())
|
|
})?;
|
|
Self::deposit_event(Event::<T>::NetworkGatekeeperUpdated {
|
|
chain_id,
|
|
gatekeeper,
|
|
});
|
|
Ok(())
|
|
}
|
|
|
|
/// Update existent network gatekeeper's topic name.
|
|
pub fn do_update_network_topic_name(
|
|
chain_id: T::NetworkId,
|
|
topic_name: Vec<u8>,
|
|
) -> DispatchResult {
|
|
ensure!(topic_name.len() == 66 && topic_name[0] == 48 && topic_name[1] == 120,
|
|
Error::<T>::WrongTopicName);
|
|
Networks::<T>::try_mutate(&chain_id, |maybe_network| -> DispatchResult {
|
|
ensure!(maybe_network.is_some(), Error::<T>::NetworkDoesNotExist);
|
|
let net = maybe_network.as_mut().unwrap();
|
|
net.topic_name = topic_name.clone();
|
|
*maybe_network = Some(net.clone());
|
|
Ok(())
|
|
})?;
|
|
Self::deposit_event(Event::<T>::NetworkTopicNameUpdated {
|
|
chain_id,
|
|
topic_name,
|
|
});
|
|
Ok(())
|
|
}
|
|
|
|
pub fn do_update_incoming_network_fee(
|
|
chain_id: T::NetworkId,
|
|
incoming_fee: u32,
|
|
) -> DispatchResult {
|
|
Networks::<T>::try_mutate(&chain_id, |maybe_network| -> DispatchResult {
|
|
ensure!(maybe_network.is_some(), Error::<T>::NetworkDoesNotExist);
|
|
let net = maybe_network.as_mut().unwrap();
|
|
net.incoming_fee = incoming_fee.clone();
|
|
*maybe_network = Some(net.clone());
|
|
Ok(())
|
|
})?;
|
|
Self::deposit_event(Event::<T>::NetworkIncomingFeeUpdated {
|
|
chain_id,
|
|
incoming_fee,
|
|
});
|
|
Ok(())
|
|
}
|
|
|
|
pub fn do_update_outgoing_network_fee(
|
|
chain_id: T::NetworkId,
|
|
outgoing_fee: u32,
|
|
) -> DispatchResult {
|
|
Networks::<T>::try_mutate(&chain_id, |maybe_network| -> DispatchResult {
|
|
ensure!(maybe_network.is_some(), Error::<T>::NetworkDoesNotExist);
|
|
let net = maybe_network.as_mut().unwrap();
|
|
net.outgoing_fee = outgoing_fee.clone();
|
|
*maybe_network = Some(net.clone());
|
|
Ok(())
|
|
})?;
|
|
Self::deposit_event(Event::<T>::NetworkOutgoingFeeUpdated {
|
|
chain_id,
|
|
outgoing_fee,
|
|
});
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
impl<T: Config> NetworkDataBasicHandler for Pallet<T> {
|
|
type NetworkId = T::NetworkId;
|
|
}
|
|
|
|
impl<T: Config> NetworkDataInspectHandler<NetworkData> for Pallet<T> {
|
|
fn get(n: &Self::NetworkId) -> Option<NetworkData> {
|
|
Networks::<T>::get(n)
|
|
}
|
|
|
|
fn iter() -> PrefixIterator<(Self::NetworkId, NetworkData)> {
|
|
Networks::<T>::iter()
|
|
}
|
|
}
|
|
|
|
impl<T: Config> NetworkDataMutateHandler<NetworkData> for Pallet<T> {
|
|
fn register(chain_id: Self::NetworkId, network: NetworkData) -> DispatchResult {
|
|
Self::do_register_network(chain_id, network)
|
|
}
|
|
|
|
fn remove(chain_id: Self::NetworkId) -> DispatchResult {
|
|
Self::do_remove_network(chain_id)
|
|
}
|
|
}
|