// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Polkadot. // Polkadot is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // Polkadot is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . //! Mocking utilities for testing. use crate::traits::Registrar; use frame_support::{ dispatch::{DispatchError, DispatchResult}, weights::Weight, }; use parity_scale_codec::{Decode, Encode}; use primitives::{HeadData, Id as ParaId, ValidationCode}; use sp_runtime::{traits::SaturatedConversion, Permill}; use std::{cell::RefCell, collections::HashMap}; thread_local! { static OPERATIONS: RefCell> = RefCell::new(Vec::new()); static PARACHAINS: RefCell> = RefCell::new(Vec::new()); static PARATHREADS: RefCell> = RefCell::new(Vec::new()); static LOCKS: RefCell> = RefCell::new(HashMap::new()); static MANAGERS: RefCell>> = RefCell::new(HashMap::new()); } pub struct TestRegistrar(sp_std::marker::PhantomData); impl Registrar for TestRegistrar { type AccountId = T::AccountId; fn manager_of(id: ParaId) -> Option { MANAGERS.with(|x| x.borrow().get(&id).and_then(|v| T::AccountId::decode(&mut &v[..]).ok())) } fn parachains() -> Vec { PARACHAINS.with(|x| x.borrow().clone()) } fn is_parathread(id: ParaId) -> bool { PARATHREADS.with(|x| x.borrow().binary_search(&id).is_ok()) } fn apply_lock(id: ParaId) { LOCKS.with(|x| x.borrow_mut().insert(id, true)); } fn remove_lock(id: ParaId) { LOCKS.with(|x| x.borrow_mut().insert(id, false)); } fn register( manager: Self::AccountId, id: ParaId, _genesis_head: HeadData, _validation_code: ValidationCode, ) -> DispatchResult { // Should not be parachain. PARACHAINS.with(|x| { let parachains = x.borrow_mut(); match parachains.binary_search(&id) { Ok(_) => Err(DispatchError::Other("Already Parachain")), Err(_) => Ok(()), } })?; // Should not be parathread, then make it. PARATHREADS.with(|x| { let mut parathreads = x.borrow_mut(); match parathreads.binary_search(&id) { Ok(_) => Err(DispatchError::Other("Already Parathread")), Err(i) => { parathreads.insert(i, id); Ok(()) }, } })?; MANAGERS.with(|x| x.borrow_mut().insert(id, manager.encode())); Ok(()) } fn deregister(id: ParaId) -> DispatchResult { // Should not be parachain. PARACHAINS.with(|x| { let parachains = x.borrow_mut(); match parachains.binary_search(&id) { Ok(_) => Err(DispatchError::Other("cannot deregister parachain")), Err(_) => Ok(()), } })?; // Remove from parathread. PARATHREADS.with(|x| { let mut parathreads = x.borrow_mut(); match parathreads.binary_search(&id) { Ok(i) => { parathreads.remove(i); Ok(()) }, Err(_) => Err(DispatchError::Other("not parathread, so cannot `deregister`")), } })?; MANAGERS.with(|x| x.borrow_mut().remove(&id)); Ok(()) } fn make_parachain(id: ParaId) -> DispatchResult { PARATHREADS.with(|x| { let mut parathreads = x.borrow_mut(); match parathreads.binary_search(&id) { Ok(i) => { parathreads.remove(i); Ok(()) }, Err(_) => Err(DispatchError::Other("not parathread, so cannot `make_parachain`")), } })?; PARACHAINS.with(|x| { let mut parachains = x.borrow_mut(); match parachains.binary_search(&id) { Ok(_) => Err(DispatchError::Other("already parachain, so cannot `make_parachain`")), Err(i) => { parachains.insert(i, id); Ok(()) }, } })?; OPERATIONS.with(|x| { x.borrow_mut().push(( id, frame_system::Pallet::::block_number().saturated_into(), true, )) }); Ok(()) } fn make_parathread(id: ParaId) -> DispatchResult { PARACHAINS.with(|x| { let mut parachains = x.borrow_mut(); match parachains.binary_search(&id) { Ok(i) => { parachains.remove(i); Ok(()) }, Err(_) => Err(DispatchError::Other("not parachain, so cannot `make_parathread`")), } })?; PARATHREADS.with(|x| { let mut parathreads = x.borrow_mut(); match parathreads.binary_search(&id) { Ok(_) => Err(DispatchError::Other("already parathread, so cannot `make_parathread`")), Err(i) => { parathreads.insert(i, id); Ok(()) }, } })?; OPERATIONS.with(|x| { x.borrow_mut().push(( id, frame_system::Pallet::::block_number().saturated_into(), false, )) }); Ok(()) } #[cfg(test)] fn worst_head_data() -> HeadData { vec![0u8; 1000].into() } #[cfg(test)] fn worst_validation_code() -> ValidationCode { let validation_code = vec![0u8; 1000]; validation_code.into() } #[cfg(test)] fn execute_pending_transitions() {} } impl TestRegistrar { pub fn operations() -> Vec<(ParaId, T::BlockNumber, bool)> { OPERATIONS .with(|x| x.borrow().iter().map(|(p, b, c)| (*p, (*b).into(), *c)).collect::>()) } #[allow(dead_code)] pub fn parachains() -> Vec { PARACHAINS.with(|x| x.borrow().clone()) } #[allow(dead_code)] pub fn parathreads() -> Vec { PARATHREADS.with(|x| x.borrow().clone()) } #[allow(dead_code)] pub fn clear_storage() { OPERATIONS.with(|x| x.borrow_mut().clear()); PARACHAINS.with(|x| x.borrow_mut().clear()); PARATHREADS.with(|x| x.borrow_mut().clear()); MANAGERS.with(|x| x.borrow_mut().clear()); } } /// A very dumb implementation of `EstimateNextSessionRotation`. At the moment of writing, this /// is more to satisfy type requirements rather than to test anything. pub struct TestNextSessionRotation; impl frame_support::traits::EstimateNextSessionRotation for TestNextSessionRotation { fn average_session_length() -> u32 { 10 } fn estimate_current_session_progress(_now: u32) -> (Option, Weight) { (None, Weight::zero()) } fn estimate_next_session_rotation(_now: u32) -> (Option, Weight) { (None, Weight::zero()) } }