Skip to content
Snippets Groups Projects

upgrade substrate to monthly-2022-01

Merged Éloïs requested to merge elois-upgrade-substrate into master
1 file
+ 3
0
Compare changes
  • Side-by-side
  • Inline
@@ -17,6 +17,7 @@
#![cfg_attr(not(feature = "std"), no_std)]
pub mod traits;
mod types;
#[cfg(test)]
mod mock;
@@ -25,30 +26,40 @@ mod mock;
mod tests;
pub use pallet::*;
pub use types::*;
use crate::traits::*;
use codec::Codec;
use sp_runtime::traits::{AtLeast32BitUnsigned, Zero};
use sp_std::{
collections::{btree_map::BTreeMap, btree_set::BTreeSet},
fmt::Debug,
vec::Vec,
};
use frame_support::traits::{Instance, StorageVersion};
use sp_runtime::traits::AtLeast32BitUnsigned;
use sp_std::{fmt::Debug, vec::Vec};
#[frame_support::pallet]
pub mod pallet {
use super::*;
use frame_support::pallet_prelude::*;
use frame_system::pallet_prelude::*;
use sp_std::collections::{btree_map::BTreeMap, btree_set::BTreeSet};
/// Configure the pallet by specifying the parameters and types on which it depends.
pub trait Config<I: Instance = DefaultInstance>: frame_system::Config {
/// The current storage version.
const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
#[pallet::pallet]
#[pallet::generate_store(pub(super) trait Store)]
#[pallet::storage_version(STORAGE_VERSION)]
pub struct Pallet<T, I = ()>(PhantomData<(T, I)>);
#[pallet::config]
pub trait Config<I: 'static = ()>: frame_system::Config {
/// Origin allowed to add a certification
type AddCertOrigin: EnsureOrigin<(Self::Origin, Self::IdtyIndex, Self::IdtyIndex)>;
#[pallet::constant]
/// Minimum duration between two certifications issued by the same issuer
type CertPeriod: Get<Self::BlockNumber>;
/// Origin allowed to delete a certification
type DelCertOrigin: EnsureOrigin<(Self::Origin, Self::IdtyIndex, Self::IdtyIndex)>;
/// The overarching event type.
type Event: From<Event<Self, I>> + Into<<Self as frame_system::Config>::Event>;
/// Because this pallet emits events, it depends on the runtime's definition of an event.
type Event: From<Event<Self, I>> + IsType<<Self as frame_system::Config>::Event>;
/// A short identity index.
type IdtyIndex: Parameter
+ Member
@@ -59,259 +70,312 @@ pub mod pallet {
+ MaybeSerializeDeserialize
+ Debug
+ MaxEncodedLen;
#[pallet::constant]
/// Maximum number of active certifications by issuer
type MaxByIssuer: Get<u8>;
/// Handler for NewCert event
type OnNewcert: OnNewcert<Self::IdtyIndex>;
/// Handler for Removed event
type OnRemovedCert: OnRemovedCert<Self::IdtyIndex>;
#[pallet::constant]
/// Duration after which a certification is renewable
type RenewablePeriod: Get<Self::BlockNumber>;
type CertRenewablePeriod: Get<Self::BlockNumber>;
#[pallet::constant]
/// Duration of validity of a certification
type ValidityPeriod: Get<Self::BlockNumber>;
}
frame_support::decl_event! {
pub enum Event<T, I=DefaultInstance> where
<T as Config<I>>::IdtyIndex,
{
/// New certification
/// \[issuer, issuer_issued_count, receiver, receiver_received_count\]
NewCert(IdtyIndex,u8, IdtyIndex, u32),
/// Removed certification
/// \[issuer, issuer_issued_count, receiver, receiver_received_count, expiration\]
RemovedCert(IdtyIndex, u8, IdtyIndex, u32, bool),
/// Renewed certification
/// \[issuer, receiver\]
RenewedCert(IdtyIndex, IdtyIndex),
}
}
frame_support::decl_error! {
pub enum Error for Module<T: Config<I>, I: Instance> {
/// An identity must receive certifications before it can issue them.
IdtyMustReceiveCertsBeforeCanIssue,
/// This identity has already issued the maximum number of certifications
IssuedTooManyCert,
/// This certification has already been issued or renewed recently
NotRespectRenewablePeriod,
/// This identity has already issued a certification too recently
NotRespectCertPeriod,
}
}
// STORAGE //
// A value placed in storage that represents the current version of the Balances storage.
// This value is used by the `on_runtime_upgrade` logic to determine whether we run
// storage migration logic. This should match directly with the semantic versions of the Rust crate.
#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug)]
pub enum Releases {
V1_0_0,
}
impl Default for Releases {
fn default() -> Self {
Releases::V1_0_0
}
}
#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug)]
pub struct CertValue<T: Config<I>, I: Instance> {
renewable_on: T::BlockNumber,
removable_on: T::BlockNumber,
phantom: PhantomData<I>,
#[pallet::genesis_config]
pub struct GenesisConfig<T: Config<I>, I: 'static = ()> {
pub certs_by_issuer: BTreeMap<T::IdtyIndex, BTreeSet<T::IdtyIndex>>,
pub phantom: PhantomData<I>,
}
#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug)]
pub struct IdtyCertMeta<T: Config<I>, I: Instance> {
issued_count: u8,
next_issuable_on: T::BlockNumber,
received_count: u32,
phantom: PhantomData<I>,
}
impl<T: Config<I>, I: Instance> Default for IdtyCertMeta<T, I> {
#[cfg(feature = "std")]
impl<T: Config<I>, I: 'static> Default for GenesisConfig<T, I> {
fn default() -> Self {
Self {
issued_count: 0,
next_issuable_on: T::BlockNumber::zero(),
received_count: 0,
phantom: PhantomData,
certs_by_issuer: Default::default(),
phantom: Default::default(),
}
}
}
frame_support::decl_storage! {
trait Store for Module<T: Config<I>, I: Instance=DefaultInstance> as Certification {
/// Storage version of the pallet.
StorageVersion get(fn storage_version): Releases;
/// Certifications by issuer
pub StorageIdtyCertMeta get(fn certs_by_issuer):
map hasher(twox_64_concat) T::IdtyIndex => IdtyCertMeta<T, I> = IdtyCertMeta {
issued_count: 0,
next_issuable_on: T::BlockNumber::zero(),
received_count: 0,
phantom: PhantomData,
};
pub StorageCertsByIssuer get(fn cert):
double_map hasher(identity) T::IdtyIndex, hasher(identity) T::IdtyIndex
=> Option<CertValue<T, I>>;
/// Certifications by receiver
pub StorageCertsByReceiver get(fn certs_by_receiver):
map hasher(twox_64_concat) T::IdtyIndex => Vec<T::IdtyIndex>;
/// Certifications removable on
pub StorageCertsRemovableOn get(fn certs_removable_on):
map hasher(twox_64_concat) T::BlockNumber => Vec<(T::IdtyIndex, T::IdtyIndex)>;
}
add_extra_genesis {
config(phantom): sp_std::marker::PhantomData<I>;
config(certs_by_issuer): BTreeMap<T::IdtyIndex, BTreeSet<T::IdtyIndex>>;
build(|config| {
let mut cert_meta_by_issuer = BTreeMap::<T::IdtyIndex, IdtyCertMeta<T, I>>::new();
let mut certs_by_receiver = BTreeMap::<T::IdtyIndex, Vec<T::IdtyIndex>>::new();
for (issuer, receivers) in &config.certs_by_issuer {
assert!(!receivers.contains(issuer), "Identity cannot tcertify it-self.");
assert!(!receivers.len() >= T::MaxByIssuer::get() as usize, "Identity n°{:?} exceed MaxByIssuer.", issuer);
cert_meta_by_issuer.insert(*issuer, IdtyCertMeta {
#[pallet::genesis_build]
impl<T: Config<I>, I: 'static> GenesisBuild<T, I> for GenesisConfig<T, I> {
fn build(&self) {
let mut cert_meta_by_issuer =
BTreeMap::<T::IdtyIndex, IdtyCertMeta<T::BlockNumber>>::new();
let mut certs_by_receiver = BTreeMap::<T::IdtyIndex, Vec<T::IdtyIndex>>::new();
for (issuer, receivers) in &self.certs_by_issuer {
assert!(
!receivers.contains(issuer),
"Identity cannot certify it-self."
);
assert!(
!receivers.len() >= T::MaxByIssuer::get() as usize,
"Identity n°{:?} exceed MaxByIssuer.",
issuer
);
cert_meta_by_issuer.insert(
*issuer,
IdtyCertMeta {
issued_count: receivers.len() as u8,
next_issuable_on: T::CertPeriod::get(),
received_count: 0,
phantom: PhantomData,
});
for receiver in receivers {
certs_by_receiver.entry(*receiver).or_default().push(*issuer);
}
},
);
for receiver in receivers {
certs_by_receiver
.entry(*receiver)
.or_default()
.push(*issuer);
}
}
<StorageVersion<I>>::put(Releases::V1_0_0);
// Write StorageCertsByReceiver
for (receiver, mut issuers) in certs_by_receiver {
cert_meta_by_issuer.entry(receiver).and_modify(|cert_meta| cert_meta.received_count = issuers.len() as u32);
issuers.sort();
<StorageCertsByReceiver<T, I>>::insert(receiver, issuers);
}
// Write StorageIdtyCertMeta
for (issuer, cert_meta) in cert_meta_by_issuer {
<StorageIdtyCertMeta<T, I>>::insert(issuer, cert_meta);
}
// Write StorageCertsByIssuer && StorageCertsRemovableOn
let mut all_couples = Vec::new();
for (issuer, receivers) in &config.certs_by_issuer {
for receiver in receivers {
all_couples.push((*issuer, *receiver));
<StorageCertsByIssuer<T, I>>::insert(issuer, receiver, CertValue {
renewable_on: T::RenewablePeriod::get(),
// Write StorageCertsByReceiver
for (receiver, mut issuers) in certs_by_receiver {
cert_meta_by_issuer
.entry(receiver)
.and_modify(|cert_meta| cert_meta.received_count = issuers.len() as u32);
issuers.sort();
<StorageCertsByReceiver<T, I>>::insert(receiver, issuers);
}
// Write StorageIdtyCertMeta
for (issuer, cert_meta) in cert_meta_by_issuer {
<StorageIdtyCertMeta<T, I>>::insert(issuer, cert_meta);
}
// Write StorageCertsByIssuer && StorageCertsRemovableOn
let mut all_couples = Vec::new();
for (issuer, receivers) in &self.certs_by_issuer {
for receiver in receivers {
all_couples.push((*issuer, *receiver));
<StorageCertsByIssuer<T, I>>::insert(
issuer,
receiver,
CertValue {
renewable_on: T::CertRenewablePeriod::get(),
removable_on: T::ValidityPeriod::get(),
phantom: PhantomData,
});
}
},
);
}
<StorageCertsRemovableOn<T, I>>::insert(T::ValidityPeriod::get(), all_couples);
});
}
<StorageCertsRemovableOn<T, I>>::insert(T::ValidityPeriod::get(), all_couples);
}
}
// CALLS //
// STORAGE //
frame_support::decl_module! {
pub struct Module<T: Config<I>, I: Instance=DefaultInstance> for enum Call where origin: <T as frame_system::Config>::Origin {
type Error = Error<T, I>;
/// Certifications metada by issuer
#[pallet::storage]
#[pallet::getter(fn idty_cert_meta)]
pub type StorageIdtyCertMeta<T: Config<I>, I: 'static = ()> =
StorageMap<_, Blake2_128Concat, T::IdtyIndex, IdtyCertMeta<T::BlockNumber>, OptionQuery>;
/// Certifications by issuer
#[pallet::storage]
#[pallet::getter(fn cert)]
/// Certifications by issuer
pub(super) type StorageCertsByIssuer<T: Config<I>, I: 'static = ()> = StorageDoubleMap<
_,
Identity,
T::IdtyIndex,
Identity,
T::IdtyIndex,
CertValue<T::BlockNumber>,
OptionQuery,
GetDefault,
ConstU32<4_000_000_000>,
>;
/// Certifications by receiver
#[pallet::storage]
#[pallet::getter(fn certs_by_receiver)]
pub type StorageCertsByReceiver<T: Config<I>, I: 'static = ()> =
StorageMap<_, Blake2_128Concat, T::IdtyIndex, Vec<T::IdtyIndex>, OptionQuery>;
/// Certifications removable on
#[pallet::storage]
#[pallet::getter(fn certs_removable_on)]
pub type StorageCertsRemovableOn<T: Config<I>, I: 'static = ()> = StorageMap<
_,
Blake2_128Concat,
T::BlockNumber,
Vec<(T::IdtyIndex, T::IdtyIndex)>,
OptionQuery,
>;
#[pallet::event]
#[pallet::generate_deposit(pub(super) fn deposit_event)]
pub enum Event<T: Config<I>, I: 'static = ()> {
/// New certification
/// [issuer, issuer_issued_count, receiver, receiver_received_count]
NewCert {
issuer: T::IdtyIndex,
issuer_issued_count: u8,
receiver: T::IdtyIndex,
receiver_received_count: u32,
},
/// Removed certification
/// [issuer, issuer_issued_count, receiver, receiver_received_count, expiration]
RemovedCert {
issuer: T::IdtyIndex,
issuer_issued_count: u8,
receiver: T::IdtyIndex,
receiver_received_count: u32,
expiration: bool,
},
/// Renewed certification
/// [issuer, receiver]
RenewedCert {
issuer: T::IdtyIndex,
receiver: T::IdtyIndex,
},
}
fn deposit_event() = default;
#[pallet::error]
pub enum Error<T, I = ()> {
/// An identity must receive certifications before it can issue them.
IdtyMustReceiveCertsBeforeCanIssue,
/// This identity has already issued the maximum number of certifications
IssuedTooManyCert,
/// This certification has already been issued or renewed recently
NotRespectRenewablePeriod,
/// This identity has already issued a certification too recently
NotRespectCertPeriod,
}
fn on_initialize(n: T::BlockNumber) -> Weight {
Self::prune_certifications(n)
}
#[pallet::hooks]
impl<T: Config<I>, I: 'static> Hooks<BlockNumberFor<T>> for Pallet<T, I> {
fn on_initialize(n: T::BlockNumber) -> Weight {
Self::prune_certifications(n)
}
}
#[weight = 0]
pub fn add_cert(origin, issuer: T::IdtyIndex, receiver: T::IdtyIndex) {
T::AddCertOrigin::ensure_origin((origin, issuer, receiver))?;
frame_support::runtime_print!("add_cert({:?}, {:?}): origin OK", issuer, receiver);
// CALLS //
let block_number = frame_system::pallet::Pallet::<T>::block_number();
#[pallet::call]
impl<T: Config<I>, I: 'static> Pallet<T, I> {
#[pallet::weight(0)]
pub fn add_cert(
origin: OriginFor<T>,
issuer: T::IdtyIndex,
receiver: T::IdtyIndex,
) -> DispatchResultWithPostInfo {
T::AddCertOrigin::ensure_origin((origin, issuer, receiver))?;
frame_support::runtime_print!("add_cert({:?}, {:?}): origin OK", issuer, receiver);
let block_number = frame_system::pallet::Pallet::<T>::block_number();
let (create, issuer_issued_count) = if let Ok(mut issuer_idty_cert_meta) =
<StorageIdtyCertMeta<T, I>>::try_get(issuer)
{
// Verify rules CertPeriod and MaxByIssuer
frame_support::runtime_print!(
"add_cert({:?}, {:?}): Verify rules CertPeriod and MaxByIssuer",
issuer,
receiver
);
if issuer_idty_cert_meta.next_issuable_on > block_number {
return Err(Error::<T, I>::NotRespectCertPeriod.into());
} else if issuer_idty_cert_meta.issued_count >= T::MaxByIssuer::get() {
return Err(Error::<T, I>::IssuedTooManyCert.into());
}
let (create, issuer_issued_count) = if let Ok(mut issuer_idty_cert_meta) = <StorageIdtyCertMeta<T, I>>::try_get(issuer) {
// Verify rules CertPeriod and MaxByIssuer
frame_support::runtime_print!("add_cert({:?}, {:?}): Verify rules CertPeriod and MaxByIssuer", issuer, receiver);
if issuer_idty_cert_meta.next_issuable_on > block_number {
return Err(Error::<T, I>::NotRespectCertPeriod.into());
} else if issuer_idty_cert_meta.issued_count >= T::MaxByIssuer::get() {
return Err(Error::<T, I>::IssuedTooManyCert.into());
// Verify rule CertRenewablePeriod
frame_support::runtime_print!(
"add_cert({:?}, {:?}): Verify rule CertRenewablePeriod",
issuer,
receiver
);
let create = if let Ok(CertValue { renewable_on, .. }) =
<StorageCertsByIssuer<T, I>>::try_get(issuer, receiver)
{
if renewable_on > block_number {
return Err(Error::<T, I>::NotRespectRenewablePeriod.into());
}
// Verify rule RenewablePeriod
frame_support::runtime_print!("add_cert({:?}, {:?}): Verify rule RenewablePeriod", issuer, receiver);
let create = if let Ok(CertValue { renewable_on, .. }) = <StorageCertsByIssuer<T, I>>::try_get(issuer, receiver) {
if renewable_on > block_number {
return Err(Error::<T, I>::NotRespectRenewablePeriod.into());
}
false
} else {
true
};
// Write StorageIdtyCertMeta for issuer
issuer_idty_cert_meta.issued_count = issuer_idty_cert_meta.issued_count.saturating_add(1);
let issuer_issued_count = issuer_idty_cert_meta.issued_count;
issuer_idty_cert_meta.next_issuable_on = block_number + T::CertPeriod::get();
<StorageIdtyCertMeta<T, I>>::insert(issuer, issuer_idty_cert_meta);
(create, issuer_issued_count)
false
} else {
// An identity must receive certifications before it can issue them.
return Err(Error::<T, I>::IdtyMustReceiveCertsBeforeCanIssue.into());
true
};
// Write StorageIdtyCertMeta for receiver
frame_support::runtime_print!("add_cert({:?}, {:?}): Write StorageIdtyCertMeta for receiver", issuer, receiver);
let receiver_received_count = <StorageIdtyCertMeta<T, I>>::mutate_exists(receiver, |cert_meta_opt| {
// Write StorageIdtyCertMeta for issuer
issuer_idty_cert_meta.issued_count =
issuer_idty_cert_meta.issued_count.saturating_add(1);
let issuer_issued_count = issuer_idty_cert_meta.issued_count;
issuer_idty_cert_meta.next_issuable_on = block_number + T::CertPeriod::get();
<StorageIdtyCertMeta<T, I>>::insert(issuer, issuer_idty_cert_meta);
(create, issuer_issued_count)
} else {
// An identity must receive certifications before it can issue them.
return Err(Error::<T, I>::IdtyMustReceiveCertsBeforeCanIssue.into());
};
// Write StorageIdtyCertMeta for receiver
frame_support::runtime_print!(
"add_cert({:?}, {:?}): Write StorageIdtyCertMeta for receiver",
issuer,
receiver
);
let receiver_received_count =
<StorageIdtyCertMeta<T, I>>::mutate_exists(receiver, |cert_meta_opt| {
let cert_meta = cert_meta_opt.get_or_insert(IdtyCertMeta::default());
cert_meta.received_count = cert_meta.received_count.saturating_add(1);
cert_meta.received_count
});
// Write StorageCertsRemovableOn and StorageCertsByIssuer
let cert_value = CertValue {
renewable_on: block_number + T::RenewablePeriod::get(),
removable_on: block_number + T::ValidityPeriod::get(),
phantom: PhantomData,
};
<StorageCertsRemovableOn<T, I>>::append(cert_value.removable_on, (issuer, receiver));
<StorageCertsByIssuer<T, I>>::insert(issuer, receiver, cert_value);
if create {
// Write StorageCertsByReceiver
<StorageCertsByReceiver<T, I>>::mutate_exists(receiver, |issuers_opt| {
let issuers = issuers_opt.get_or_insert(Vec::with_capacity(0));
if let Err(index) = issuers.binary_search(&issuer) {
issuers.insert(index, issuer);
}
});
Self::deposit_event(RawEvent::NewCert(issuer, issuer_issued_count, receiver, receiver_received_count));
T::OnNewcert::on_new_cert(issuer, issuer_issued_count, receiver, receiver_received_count);
} else {
Self::deposit_event(RawEvent::RenewedCert(issuer, receiver));
}
}
#[weight = 0]
pub fn del_cert(origin, issuer: T::IdtyIndex, receiver: T::IdtyIndex) {
T::DelCertOrigin::ensure_origin((origin, issuer, receiver))?;
Self::remove_cert_inner(issuer, receiver, None);
// Write StorageCertsRemovableOn and StorageCertsByIssuer
let cert_value = CertValue {
renewable_on: block_number + T::CertRenewablePeriod::get(),
removable_on: block_number + T::ValidityPeriod::get(),
};
<StorageCertsRemovableOn<T, I>>::append(cert_value.removable_on, (issuer, receiver));
<StorageCertsByIssuer<T, I>>::insert(issuer, receiver, cert_value);
if create {
// Write StorageCertsByReceiver
<StorageCertsByReceiver<T, I>>::mutate_exists(receiver, |issuers_opt| {
let issuers = issuers_opt.get_or_insert(Vec::with_capacity(0));
if let Err(index) = issuers.binary_search(&issuer) {
issuers.insert(index, issuer);
}
});
Self::deposit_event(Event::NewCert {
issuer,
issuer_issued_count,
receiver,
receiver_received_count,
});
T::OnNewcert::on_new_cert(
issuer,
issuer_issued_count,
receiver,
receiver_received_count,
);
} else {
Self::deposit_event(Event::RenewedCert { issuer, receiver });
}
Ok(().into())
}
#[pallet::weight(0)]
pub fn del_cert(
origin: OriginFor<T>,
issuer: T::IdtyIndex,
receiver: T::IdtyIndex,
) -> DispatchResultWithPostInfo {
T::DelCertOrigin::ensure_origin((origin, issuer, receiver))?;
Self::remove_cert_inner(issuer, receiver, None);
Ok(().into())
}
}
// PUBLIC FUNCTIONS //
impl<T: Config<I>, I: Instance> Module<T, I> {
pub fn is_idty_allowed_to_create_cert(idty_index: T::IdtyIndex) -> bool {
if let Ok(cert_meta) = <StorageIdtyCertMeta<T, I>>::try_get(idty_index) {
cert_meta.next_issuable_on <= frame_system::pallet::Pallet::<T>::block_number()
&& cert_meta.issued_count < T::MaxByIssuer::get()
} else {
true
}
}
impl<T: Config<I>, I: Instance> Pallet<T, I> {
pub fn on_idty_removed(idty_index: T::IdtyIndex) -> Weight {
let mut total_weight: Weight = 0;
if let Ok(issuers) = <StorageCertsByReceiver<T, I>>::try_get(idty_index) {
@@ -325,7 +389,7 @@ pub mod pallet {
// INTERNAL FUNCTIONS //
impl<T: Config<I>, I: Instance> Module<T, I> {
impl<T: Config<I>, I: 'static> Pallet<T, I> {
fn prune_certifications(block_number: T::BlockNumber) -> Weight {
let mut total_weight: Weight = 0;
@@ -377,13 +441,13 @@ pub mod pallet {
cert_meta.received_count = cert_meta.received_count.saturating_sub(1);
cert_meta.received_count
});
Self::deposit_event(RawEvent::RemovedCert(
Self::deposit_event(Event::RemovedCert {
issuer,
issuer_issued_count,
receiver,
receiver_received_count,
block_number_opt.is_some(),
));
expiration: block_number_opt.is_some(),
});
total_weight += T::OnRemovedCert::on_removed_cert(
issuer,
issuer_issued_count,
@@ -396,3 +460,15 @@ pub mod pallet {
}
}
}
impl<T: Config<I>, I: 'static> IsIdtyAllowedToCreateCert<T::IdtyIndex> for Pallet<T, I> {
fn is_idty_allowed_to_create_cert(idty_index: T::IdtyIndex) -> bool {
if let Ok(cert_meta) = <StorageIdtyCertMeta<T, I>>::try_get(idty_index) {
use frame_support::traits::Get as _;
cert_meta.next_issuable_on <= frame_system::pallet::Pallet::<T>::block_number()
&& cert_meta.issued_count < T::MaxByIssuer::get()
} else {
true
}
}
}
Loading