Newer
Older
// Copyright 2021 Axiom-Team
//
// This file is part of Substrate-Libre-Currency.
//
// Substrate-Libre-Currency is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, version 3 of the License.
//
// Substrate-Libre-Currency 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with Substrate-Libre-Currency. If not, see <https://www.gnu.org/licenses/>.
#![cfg_attr(not(feature = "std"), no_std)]
#![allow(clippy::type_complexity)]
//pub mod traits;
mod types;
#[cfg(test)]
mod mock;
#[cfg(test)]
mod tests;
/*#[cfg(feature = "runtime-benchmarks")]
mod benchmarking;*/
pub use pallet::*;
pub use types::*;
use frame_support::pallet_prelude::*;
use frame_system::pallet_prelude::BlockNumberFor;
use frame_system::RawOrigin;
use pallet_certification::traits::SetNextIssuableOn;
use pallet_identity::{IdtyEvent, IdtyStatus};
use sp_membership::traits::IsInPendingMemberships;
use sp_runtime::traits::IsMember;
type IdtyIndex = u32;
#[frame_support::pallet]
pub mod pallet {
use super::*;
use frame_support::dispatch::UnfilteredDispatchable;
use frame_support::traits::StorageVersion;
use sp_std::vec::Vec;
/// 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)]
// CONFIG //
#[pallet::config]
+ pallet_certification::Config<I, IdtyIndex = IdtyIndex>
+ pallet_identity::Config<IdtyIndex = IdtyIndex>
+ pallet_membership::Config<I, IdtyId = IdtyIndex>
{
type FirstIssuableOn: Get<Self::BlockNumber>;
type IsSubWot: Get<bool>;
type MinCertForMembership: Get<u32>;
// STORAGE //
#[pallet::storage]
#[pallet::getter(fn wot_diffs)]
pub(super) type WotDiffs<T: Config<I>, I: 'static = ()> =
StorageValue<_, Vec<WotDiff>, ValueQuery>;
// HOOKS //
#[pallet::hooks]
impl<T: Config<I>, I: 'static> Hooks<BlockNumberFor<T>> for Pallet<T, I> {
fn on_initialize(_: T::BlockNumber) -> Weight {
0
}
fn on_finalize(block_number: T::BlockNumber) {
const OFFCHAIN_WOT_DIFFS_KEY: &[u8] = b"ocw/wot-diffs/";
let diffs = WotDiffs::<T, I>::take();
let key = block_number.using_encoded(|encoded_block_number| {
OFFCHAIN_WOT_DIFFS_KEY
.iter()
.chain(encoded_block_number)
.copied()
.collect::<Vec<u8>>()
});
sp_io::offchain_index::set(&key, &diffs.encode());
}
}
// INTERNAL FUNCTIONS //
pub(super) fn do_apply_first_issuable_on(idty_index: IdtyIndex) {
let block_number = frame_system::pallet::Pallet::<T>::block_number();
pallet_certification::Pallet::<T, I>::set_next_issuable_on(
idty_index,
block_number + T::FirstIssuableOn::get(),
);
}
pub(super) fn dispath_idty_call(idty_call: pallet_identity::Call<T>) -> bool {
if !T::IsSubWot::get() {
if let Err(e) = idty_call.dispatch_bypass_filter(RawOrigin::Root.into()) {
println!("fail to dispatch idty call: {:?}", e)
impl<AccountId, T: Config<I>, I: 'static> pallet_identity::traits::EnsureIdtyCallAllowed<T>
for Pallet<T, I>
T: frame_system::Config<AccountId = AccountId>
+ pallet_membership::Config<I, MetaData = MembershipMetaData<AccountId>>,
fn can_create_identity(creator: IdtyIndex) -> bool {
let cert_meta = pallet_certification::Pallet::<T, I>::idty_cert_meta(creator);
cert_meta.received_count >= T::MinCertForCreateIdtyRight::get()
&& cert_meta.next_issuable_on <= frame_system::pallet::Pallet::<T>::block_number()
&& cert_meta.issued_count < T::MaxByIssuer::get()
fn can_confirm_identity(idty_index: IdtyIndex, owner_key: AccountId) -> bool {
pallet_membership::Pallet::<T, I>::force_request_membership(
RawOrigin::Root.into(),
idty_index,
}
fn can_validate_identity(idty_index: IdtyIndex) -> bool {
pallet_membership::Pallet::<T, I>::claim_membership(
RawOrigin::Root.into(),
Some(idty_index),
)
.is_ok()
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
impl<T: Config<I>, I: 'static> pallet_certification::traits::IsCertAllowed<IdtyIndex>
for Pallet<T, I>
{
fn is_cert_allowed(issuer: IdtyIndex, receiver: IdtyIndex) -> bool {
if let Some(issuer_data) = pallet_identity::Pallet::<T>::identity(issuer) {
if issuer_data.status != IdtyStatus::Validated {
return false;
}
if let Some(receiver_data) = pallet_identity::Pallet::<T>::identity(receiver) {
match receiver_data.status {
IdtyStatus::ConfirmedByOwner => true,
IdtyStatus::Created => false,
IdtyStatus::Validated => {
pallet_membership::Pallet::<T, I>::is_member(&receiver)
|| pallet_membership::Pallet::<T, I>::is_in_pending_memberships(
receiver,
)
}
}
} else {
// Receiver not found
false
}
} else {
// Issuer not found
false
}
}
}
impl<T: Config<I>, I: 'static> sp_membership::traits::IsIdtyAllowedToRenewMembership<IdtyIndex>
for Pallet<T, I>
{
fn is_idty_allowed_to_renew_membership(idty_index: &IdtyIndex) -> bool {
if let Some(idty_value) = pallet_identity::Pallet::<T>::identity(idty_index) {
idty_value.status == IdtyStatus::Validated
} else {
false
}
}
}
impl<T: Config<I>, I: 'static> sp_membership::traits::IsIdtyAllowedToRequestMembership<IdtyIndex>
for Pallet<T, I>
{
fn is_idty_allowed_to_request_membership(idty_index: &IdtyIndex) -> bool {
if let Some(idty_value) = pallet_identity::Pallet::<T>::identity(idty_index) {
T::IsSubWot::get() && idty_value.status == IdtyStatus::Validated
} else {
false
}
}
}
impl<T: Config<I>, I: 'static, MetaData> sp_membership::traits::OnEvent<IdtyIndex, MetaData>
for Pallet<T, I>
where
T: pallet_membership::Config<I, MetaData = MetaData>,
{
fn on_event(membership_event: &sp_membership::Event<IdtyIndex, MetaData>) -> Weight {
sp_membership::Event::<IdtyIndex, MetaData>::MembershipAcquired(idty_index, _) => {
if !T::IsSubWot::get() {
WotDiffs::<T, I>::append(WotDiff::AddNode(*idty_index));
}
}
sp_membership::Event::<IdtyIndex, MetaData>::MembershipExpired(idty_index)
| sp_membership::Event::<IdtyIndex, MetaData>::MembershipRevoked(idty_index) => {
Self::dispath_idty_call(pallet_identity::Call::remove_identity {
if !T::IsSubWot::get() {
WotDiffs::<T, I>::append(WotDiff::DisableNode(*idty_index));
}
sp_membership::Event::<IdtyIndex, MetaData>::MembershipRenewed(_) => {}
sp_membership::Event::<IdtyIndex, MetaData>::MembershipRequested(idty_index) => {
let idty_cert_meta =
pallet_certification::Pallet::<T, I>::idty_cert_meta(idty_index);
let received_count = idty_cert_meta.received_count;
// TODO insert `receiver` in distance queue if received_count >= MinCertForMembership
if received_count >= T::MinCertForMembership::get() as u32 {
// TODO insert `receiver` in distance queue
if Self::dispath_idty_call(pallet_identity::Call::validate_identity {
idty_index: *idty_index,
}) && received_count == T::MinReceivedCertToBeAbleToIssueCert::get()
{
Self::do_apply_first_issuable_on(*idty_index);
sp_membership::Event::<IdtyIndex, MetaData>::PendingMembershipExpired(idty_index) => {
Self::dispath_idty_call(pallet_identity::Call::remove_identity {
idty_index: *idty_index,
}
}
0
}
}
impl<T: Config<I>, I: 'static> pallet_identity::traits::OnIdtyChange<T> for Pallet<T, I> {
fn on_idty_change(idty_index: IdtyIndex, idty_event: IdtyEvent<T>) -> Weight {
match idty_event {
IdtyEvent::Created { creator } => {
if let Err(e) = <pallet_certification::Pallet<T, I>>::force_add_cert(
frame_system::Origin::<T>::Root.into(),
creator,
idty_index,
) {
sp_std::if_std! {
println!("fail to force add cert: {:?}", e)
}
}
}
IdtyEvent::Confirmed => {}
IdtyEvent::Validated => {}
IdtyEvent::Removed => {}
}
0
}
}
impl<T: Config<I>, I: 'static> pallet_certification::traits::OnNewcert<IdtyIndex> for Pallet<T, I> {
issuer: IdtyIndex,
receiver: IdtyIndex,
receiver_received_count: u32,
) -> Weight {
if pallet_membership::Pallet::<T, I>::is_member(&receiver) {
if receiver_received_count == T::MinReceivedCertToBeAbleToIssueCert::get() {
Self::do_apply_first_issuable_on(receiver);
}
if T::IsSubWot::get() {
WotDiffs::<T, I>::append(WotDiff::AddLink(issuer, receiver));
}
} else if pallet_membership::Pallet::<T, I>::is_in_pending_memberships(receiver)
&& receiver_received_count >= T::MinCertForMembership::get()
if T::IsSubWot::get() {
if let Err(e) = pallet_membership::Pallet::<T, I>::claim_membership(
RawOrigin::Root.into(),
println!("fail to claim membership: {:?}", e)
}
}
} else {
// TODO insert `receiver` in distance queue
Self::dispath_idty_call(pallet_identity::Call::validate_identity {
idty_index: receiver,
});
for issuer in pallet_certification::Pallet::<T, I>::certs_by_receiver(receiver) {
WotDiffs::<T, I>::append(WotDiff::AddLink(issuer, receiver));
}
if receiver_received_count == T::MinReceivedCertToBeAbleToIssueCert::get() {
Self::do_apply_first_issuable_on(receiver);
}
}
0
}
}
impl<T: Config<I>, I: 'static> pallet_certification::traits::OnRemovedCert<IdtyIndex>
for Pallet<T, I>
{
fn on_removed_cert(
issuer: IdtyIndex,
receiver: IdtyIndex,
receiver_received_count: u32,
_expiration: bool,
) -> Weight {
if receiver_received_count < T::MinCertForMembership::get()
&& pallet_membership::Pallet::<T, I>::is_member(&receiver)
{
// Revoke receiver membership and disable their identity
if let Err(e) = pallet_membership::Pallet::<T, I>::revoke_membership(
) {
sp_std::if_std! {
println!("fail to revoke membership: {:?}", e)
if !T::IsSubWot::get() {
WotDiffs::<T, I>::append(WotDiff::DelLink(issuer, receiver));
}