pezpallet_node_authorization/
lib.rs1#![cfg_attr(not(feature = "std"), no_std)]
39
40#[cfg(test)]
41#[allow(unexpected_cfgs)]
43mod mock;
44#[cfg(test)]
45mod tests;
46
47pub mod weights;
48
49extern crate alloc;
50
51use alloc::{collections::btree_set::BTreeSet, vec::Vec};
52use frame::{
53 deps::{pezsp_core::OpaquePeerId as PeerId, pezsp_io},
54 prelude::*,
55};
56pub use pezpallet::*;
57pub use weights::WeightInfo;
58
59type AccountIdLookupOf<T> = <<T as pezframe_system::Config>::Lookup as StaticLookup>::Source;
60
61#[frame::pezpallet]
62pub mod pezpallet {
63 use super::*;
64
65 #[pezpallet::pezpallet]
66 #[pezpallet::without_storage_info]
67 pub struct Pezpallet<T>(_);
68
69 #[pezpallet::config]
71 pub trait Config: pezframe_system::Config {
72 #[allow(deprecated)]
74 type RuntimeEvent: From<Event<Self>>
75 + IsType<<Self as pezframe_system::Config>::RuntimeEvent>;
76
77 #[pezpallet::constant]
79 type MaxWellKnownNodes: Get<u32>;
80
81 #[pezpallet::constant]
83 type MaxPeerIdLength: Get<u32>;
84
85 type AddOrigin: EnsureOrigin<Self::RuntimeOrigin>;
87
88 type RemoveOrigin: EnsureOrigin<Self::RuntimeOrigin>;
90
91 type SwapOrigin: EnsureOrigin<Self::RuntimeOrigin>;
93
94 type ResetOrigin: EnsureOrigin<Self::RuntimeOrigin>;
96
97 type WeightInfo: WeightInfo;
99 }
100
101 #[pezpallet::storage]
103 #[pezpallet::getter(fn well_known_nodes)]
104 pub type WellKnownNodes<T> = StorageValue<_, BTreeSet<PeerId>, ValueQuery>;
105
106 #[pezpallet::storage]
108 #[pezpallet::getter(fn owners)]
109 pub type Owners<T: Config> = StorageMap<_, Blake2_128Concat, PeerId, T::AccountId>;
110
111 #[pezpallet::storage]
113 #[pezpallet::getter(fn additional_connection)]
114 pub type AdditionalConnections<T> =
115 StorageMap<_, Blake2_128Concat, PeerId, BTreeSet<PeerId>, ValueQuery>;
116
117 #[pezpallet::genesis_config]
118 #[derive(DefaultNoBound)]
119 pub struct GenesisConfig<T: Config> {
120 pub nodes: Vec<(PeerId, T::AccountId)>,
121 }
122
123 #[pezpallet::genesis_build]
124 impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
125 fn build(&self) {
126 Pezpallet::<T>::initialize_nodes(&self.nodes);
127 }
128 }
129
130 #[pezpallet::event]
131 #[pezpallet::generate_deposit(pub(super) fn deposit_event)]
132 pub enum Event<T: Config> {
133 NodeAdded { peer_id: PeerId, who: T::AccountId },
135 NodeRemoved { peer_id: PeerId },
137 NodeSwapped { removed: PeerId, added: PeerId },
140 NodesReset { nodes: Vec<(PeerId, T::AccountId)> },
142 NodeClaimed { peer_id: PeerId, who: T::AccountId },
144 ClaimRemoved { peer_id: PeerId, who: T::AccountId },
146 NodeTransferred { peer_id: PeerId, target: T::AccountId },
148 ConnectionsAdded { peer_id: PeerId, allowed_connections: Vec<PeerId> },
150 ConnectionsRemoved { peer_id: PeerId, allowed_connections: Vec<PeerId> },
152 }
153
154 #[pezpallet::error]
155 pub enum Error<T> {
156 PeerIdTooLong,
158 TooManyNodes,
160 AlreadyJoined,
162 NotExist,
164 AlreadyClaimed,
166 NotClaimed,
168 NotOwner,
170 PermissionDenied,
172 }
173
174 #[pezpallet::hooks]
175 impl<T: Config> Hooks<BlockNumberFor<T>> for Pezpallet<T> {
176 fn offchain_worker(now: BlockNumberFor<T>) {
179 let network_state = pezsp_io::offchain::network_state();
180 match network_state {
181 Err(_) => log::error!(
182 target: "runtime::node-authorization",
183 "Error: failed to get network state of node at {:?}",
184 now,
185 ),
186 Ok(state) => {
187 let encoded_peer = state.peer_id.0;
188 match Decode::decode(&mut &encoded_peer[..]) {
189 Err(_) => log::error!(
190 target: "runtime::node-authorization",
191 "Error: failed to decode PeerId at {:?}",
192 now,
193 ),
194 Ok(node) => pezsp_io::offchain::set_authorized_nodes(
195 Self::get_authorized_nodes(&PeerId(node)),
196 true,
197 ),
198 }
199 },
200 }
201 }
202 }
203
204 #[pezpallet::call]
205 impl<T: Config> Pezpallet<T> {
206 #[pezpallet::call_index(0)]
213 #[pezpallet::weight((T::WeightInfo::add_well_known_node(), DispatchClass::Operational))]
214 pub fn add_well_known_node(
215 origin: OriginFor<T>,
216 node: PeerId,
217 owner: AccountIdLookupOf<T>,
218 ) -> DispatchResult {
219 T::AddOrigin::ensure_origin(origin)?;
220 let owner = T::Lookup::lookup(owner)?;
221 ensure!(node.0.len() < T::MaxPeerIdLength::get() as usize, Error::<T>::PeerIdTooLong);
222
223 let mut nodes = WellKnownNodes::<T>::get();
224 ensure!(nodes.len() < T::MaxWellKnownNodes::get() as usize, Error::<T>::TooManyNodes);
225 ensure!(!nodes.contains(&node), Error::<T>::AlreadyJoined);
226
227 nodes.insert(node.clone());
228
229 WellKnownNodes::<T>::put(&nodes);
230 <Owners<T>>::insert(&node, &owner);
231
232 Self::deposit_event(Event::NodeAdded { peer_id: node, who: owner });
233 Ok(())
234 }
235
236 #[pezpallet::call_index(1)]
243 #[pezpallet::weight((T::WeightInfo::remove_well_known_node(), DispatchClass::Operational))]
244 pub fn remove_well_known_node(origin: OriginFor<T>, node: PeerId) -> DispatchResult {
245 T::RemoveOrigin::ensure_origin(origin)?;
246 ensure!(node.0.len() < T::MaxPeerIdLength::get() as usize, Error::<T>::PeerIdTooLong);
247
248 let mut nodes = WellKnownNodes::<T>::get();
249 ensure!(nodes.contains(&node), Error::<T>::NotExist);
250
251 nodes.remove(&node);
252
253 WellKnownNodes::<T>::put(&nodes);
254 <Owners<T>>::remove(&node);
255 AdditionalConnections::<T>::remove(&node);
256
257 Self::deposit_event(Event::NodeRemoved { peer_id: node });
258 Ok(())
259 }
260
261 #[pezpallet::call_index(2)]
269 #[pezpallet::weight((T::WeightInfo::swap_well_known_node(), DispatchClass::Operational))]
270 pub fn swap_well_known_node(
271 origin: OriginFor<T>,
272 remove: PeerId,
273 add: PeerId,
274 ) -> DispatchResult {
275 T::SwapOrigin::ensure_origin(origin)?;
276 ensure!(remove.0.len() < T::MaxPeerIdLength::get() as usize, Error::<T>::PeerIdTooLong);
277 ensure!(add.0.len() < T::MaxPeerIdLength::get() as usize, Error::<T>::PeerIdTooLong);
278
279 if remove == add {
280 return Ok(());
281 }
282
283 let mut nodes = WellKnownNodes::<T>::get();
284 ensure!(nodes.contains(&remove), Error::<T>::NotExist);
285 ensure!(!nodes.contains(&add), Error::<T>::AlreadyJoined);
286
287 nodes.remove(&remove);
288 nodes.insert(add.clone());
289
290 WellKnownNodes::<T>::put(&nodes);
291 Owners::<T>::swap(&remove, &add);
292 AdditionalConnections::<T>::swap(&remove, &add);
293
294 Self::deposit_event(Event::NodeSwapped { removed: remove, added: add });
295 Ok(())
296 }
297
298 #[pezpallet::call_index(3)]
306 #[pezpallet::weight((T::WeightInfo::reset_well_known_nodes(), DispatchClass::Operational))]
307 pub fn reset_well_known_nodes(
308 origin: OriginFor<T>,
309 nodes: Vec<(PeerId, T::AccountId)>,
310 ) -> DispatchResult {
311 T::ResetOrigin::ensure_origin(origin)?;
312 ensure!(nodes.len() < T::MaxWellKnownNodes::get() as usize, Error::<T>::TooManyNodes);
313
314 Self::initialize_nodes(&nodes);
315
316 Self::deposit_event(Event::NodesReset { nodes });
317 Ok(())
318 }
319
320 #[pezpallet::call_index(4)]
325 #[pezpallet::weight(T::WeightInfo::claim_node())]
326 pub fn claim_node(origin: OriginFor<T>, node: PeerId) -> DispatchResult {
327 let sender = ensure_signed(origin)?;
328
329 ensure!(node.0.len() < T::MaxPeerIdLength::get() as usize, Error::<T>::PeerIdTooLong);
330 ensure!(!Owners::<T>::contains_key(&node), Error::<T>::AlreadyClaimed);
331
332 Owners::<T>::insert(&node, &sender);
333 Self::deposit_event(Event::NodeClaimed { peer_id: node, who: sender });
334 Ok(())
335 }
336
337 #[pezpallet::call_index(5)]
343 #[pezpallet::weight(T::WeightInfo::remove_claim())]
344 pub fn remove_claim(origin: OriginFor<T>, node: PeerId) -> DispatchResult {
345 let sender = ensure_signed(origin)?;
346
347 ensure!(node.0.len() < T::MaxPeerIdLength::get() as usize, Error::<T>::PeerIdTooLong);
348 let owner = Owners::<T>::get(&node).ok_or(Error::<T>::NotClaimed)?;
349 ensure!(owner == sender, Error::<T>::NotOwner);
350 ensure!(!WellKnownNodes::<T>::get().contains(&node), Error::<T>::PermissionDenied);
351
352 Owners::<T>::remove(&node);
353 AdditionalConnections::<T>::remove(&node);
354
355 Self::deposit_event(Event::ClaimRemoved { peer_id: node, who: sender });
356 Ok(())
357 }
358
359 #[pezpallet::call_index(6)]
364 #[pezpallet::weight(T::WeightInfo::transfer_node())]
365 pub fn transfer_node(
366 origin: OriginFor<T>,
367 node: PeerId,
368 owner: AccountIdLookupOf<T>,
369 ) -> DispatchResult {
370 let sender = ensure_signed(origin)?;
371 let owner = T::Lookup::lookup(owner)?;
372
373 ensure!(node.0.len() < T::MaxPeerIdLength::get() as usize, Error::<T>::PeerIdTooLong);
374 let pre_owner = Owners::<T>::get(&node).ok_or(Error::<T>::NotClaimed)?;
375 ensure!(pre_owner == sender, Error::<T>::NotOwner);
376
377 Owners::<T>::insert(&node, &owner);
378
379 Self::deposit_event(Event::NodeTransferred { peer_id: node, target: owner });
380 Ok(())
381 }
382
383 #[pezpallet::call_index(7)]
388 #[pezpallet::weight(T::WeightInfo::add_connections())]
389 pub fn add_connections(
390 origin: OriginFor<T>,
391 node: PeerId,
392 connections: Vec<PeerId>,
393 ) -> DispatchResult {
394 let sender = ensure_signed(origin)?;
395
396 ensure!(node.0.len() < T::MaxPeerIdLength::get() as usize, Error::<T>::PeerIdTooLong);
397 let owner = Owners::<T>::get(&node).ok_or(Error::<T>::NotClaimed)?;
398 ensure!(owner == sender, Error::<T>::NotOwner);
399
400 let mut nodes = AdditionalConnections::<T>::get(&node);
401
402 for add_node in connections.iter() {
403 if *add_node == node {
404 continue;
405 }
406 nodes.insert(add_node.clone());
407 }
408
409 AdditionalConnections::<T>::insert(&node, nodes);
410
411 Self::deposit_event(Event::ConnectionsAdded {
412 peer_id: node,
413 allowed_connections: connections,
414 });
415 Ok(())
416 }
417
418 #[pezpallet::call_index(8)]
423 #[pezpallet::weight(T::WeightInfo::remove_connections())]
424 pub fn remove_connections(
425 origin: OriginFor<T>,
426 node: PeerId,
427 connections: Vec<PeerId>,
428 ) -> DispatchResult {
429 let sender = ensure_signed(origin)?;
430
431 ensure!(node.0.len() < T::MaxPeerIdLength::get() as usize, Error::<T>::PeerIdTooLong);
432 let owner = Owners::<T>::get(&node).ok_or(Error::<T>::NotClaimed)?;
433 ensure!(owner == sender, Error::<T>::NotOwner);
434
435 let mut nodes = AdditionalConnections::<T>::get(&node);
436
437 for remove_node in connections.iter() {
438 nodes.remove(remove_node);
439 }
440
441 AdditionalConnections::<T>::insert(&node, nodes);
442
443 Self::deposit_event(Event::ConnectionsRemoved {
444 peer_id: node,
445 allowed_connections: connections,
446 });
447 Ok(())
448 }
449 }
450}
451
452impl<T: Config> Pezpallet<T> {
453 fn initialize_nodes(nodes: &Vec<(PeerId, T::AccountId)>) {
454 let peer_ids = nodes.iter().map(|item| item.0.clone()).collect::<BTreeSet<PeerId>>();
455 WellKnownNodes::<T>::put(&peer_ids);
456
457 for (node, who) in nodes.iter() {
458 Owners::<T>::insert(node, who);
459 }
460 }
461
462 fn get_authorized_nodes(node: &PeerId) -> Vec<PeerId> {
463 let mut nodes = AdditionalConnections::<T>::get(node);
464
465 let mut well_known_nodes = WellKnownNodes::<T>::get();
466 if well_known_nodes.contains(node) {
467 well_known_nodes.remove(node);
468 nodes.extend(well_known_nodes);
469 }
470
471 Vec::from_iter(nodes)
472 }
473}