From e12f452d31073d5ec60678a3fee52617e8d21a7b Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Thu, 9 Jan 2025 16:33:10 +0100 Subject: [PATCH 01/18] WIP --- pallets/did/src/lib.rs | 28 +++++++++++++++++-- pallets/did/src/mock.rs | 1 + pallets/did/src/traits.rs | 57 ++++++++++++++++++++++++++++++++++++++ runtimes/common/src/did.rs | 45 ++++++++++++++++++++++++++++++ runtimes/common/src/lib.rs | 2 ++ 5 files changed, 131 insertions(+), 2 deletions(-) create mode 100644 pallets/did/src/traits.rs create mode 100644 runtimes/common/src/did.rs diff --git a/pallets/did/src/lib.rs b/pallets/did/src/lib.rs index 39ec7a5054..76963539a8 100644 --- a/pallets/did/src/lib.rs +++ b/pallets/did/src/lib.rs @@ -88,6 +88,7 @@ pub mod errors; pub mod migrations; pub mod origin; pub mod service_endpoints; +pub mod traits; #[cfg(test)] mod mock; @@ -171,6 +172,7 @@ pub mod pallet { DidEncryptionKey, DidSignature, DidVerifiableIdentifier, DidVerificationKey, RelationshipDeriveError, }, service_endpoints::{utils as service_endpoints_utils, ServiceEndpointId}, + traits::{DidDeletionHook, DidLifecycleHooks}, }; /// The current storage version. @@ -328,6 +330,8 @@ pub mod pallet { /// Migration manager to handle new created entries type BalanceMigrationManager: BalanceMigrationManager, BalanceOf>; + + type DidLifecycleHooks: DidLifecycleHooks; } #[pallet::pallet] @@ -455,6 +459,9 @@ pub mod pallet { /// The number of service endpoints stored under the DID is larger than /// the number of endpoints to delete. MaxStoredEndpointsCountExceeded, + /// The DID cannot be deleted because other resources are depending on + /// it. + CannotDelete, /// An error that is not supposed to take place, yet it happened. Internal, } @@ -972,7 +979,10 @@ pub mod pallet { /// - Kills: Did entry associated to the DID identifier /// # #[pallet::call_index(10)] - #[pallet::weight(::WeightInfo::delete(*endpoints_to_remove))] + #[pallet::weight({ + let max_hook_weight = <>::DeletionHook as DidDeletionHook>::MAX_WEIGHT; + ::WeightInfo::delete(*endpoints_to_remove).saturating_add(max_hook_weight) + })] pub fn delete(origin: OriginFor, endpoints_to_remove: u32) -> DispatchResult { let source = T::EnsureOrigin::ensure_origin(origin)?; let did_subject = source.subject(); @@ -1002,7 +1012,10 @@ pub mod pallet { /// - Kills: Did entry associated to the DID identifier /// # #[pallet::call_index(11)] - #[pallet::weight(::WeightInfo::reclaim_deposit(*endpoints_to_remove))] + #[pallet::weight({ + let max_hook_weight = <>::DeletionHook as DidDeletionHook>::MAX_WEIGHT; + ::WeightInfo::reclaim_deposit(*endpoints_to_remove).saturating_add(max_hook_weight) + })] pub fn reclaim_deposit( origin: OriginFor, did_subject: DidIdentifierOf, @@ -1491,6 +1504,17 @@ pub mod pallet { /// endpoints, adds the identifier to the blacklisted DIDs and frees the /// deposit. pub fn delete_did(did_subject: DidIdentifierOf, endpoints_to_remove: u32) -> DispatchResult { + let Ok(()) = + <>::DeletionHook as DidDeletionHook>::can_delete( + &did_subject, + ) + else { + return Err(Error::::CannotDelete.into()); + }; + // <>::DidDeletionHook as + // DidDeletionHook>::can_delete( &did_subject, + // )?; + let current_endpoints_count = DidEndpointsCount::::get(&did_subject); ensure!( current_endpoints_count <= endpoints_to_remove, diff --git a/pallets/did/src/mock.rs b/pallets/did/src/mock.rs index db59b5f3fa..dc6d421ac9 100644 --- a/pallets/did/src/mock.rs +++ b/pallets/did/src/mock.rs @@ -175,6 +175,7 @@ impl Config for Test { type MaxNumberOfTypesPerService = MaxNumberOfTypesPerService; type MaxNumberOfUrlsPerService = MaxNumberOfUrlsPerService; type BalanceMigrationManager = (); + type DidLifecycleHooks = (); } parameter_types! { diff --git a/pallets/did/src/traits.rs b/pallets/did/src/traits.rs new file mode 100644 index 0000000000..0efa975010 --- /dev/null +++ b/pallets/did/src/traits.rs @@ -0,0 +1,57 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2024 BOTLabs GmbH + +// The KILT Blockchain 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. + +// The KILT Blockchain 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 this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +use sp_weights::Weight; + +use crate::{Config, DidIdentifierOf}; + +pub trait DidLifecycleHooks +where + T: Config, +{ + type DeletionHook: DidDeletionHook; +} + +impl DidLifecycleHooks for () +where + T: Config, +{ + type DeletionHook = (); +} + +pub trait DidDeletionHook +where + T: Config, +{ + const MAX_WEIGHT: Weight; + + // Return `Ok(())` consuming `MAX_WEIGHT` if the DID can be deleted, or + // `Err(Weight)` with the consumed weight if not. + fn can_delete(did: &DidIdentifierOf) -> Result<(), Weight>; +} + +impl DidDeletionHook for () +where + T: Config, +{ + const MAX_WEIGHT: Weight = Weight::from_parts(0, 0); + + fn can_delete(_did: &DidIdentifierOf) -> Result<(), Weight> { + Ok(()) + } +} diff --git a/runtimes/common/src/did.rs b/runtimes/common/src/did.rs new file mode 100644 index 0000000000..553c69f472 --- /dev/null +++ b/runtimes/common/src/did.rs @@ -0,0 +1,45 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2024 BOTLabs GmbH + +// The KILT Blockchain 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. + +// The KILT Blockchain 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 this program. If not, see . + +use did::DidIdentifierOf; +use sp_std::marker::PhantomData; + +use sp_weights::Weight; + +// If you feel like getting in touch with us, you can do so at info@botlabs.org +pub struct LinkedWeb3NameDeletionHook( + PhantomData, +); + +impl did::traits::DidDeletionHook + for LinkedWeb3NameDeletionHook +where + T: did::Config + pallet_web3_names::Config>, + Web3NameDeployment: 'static, +{ + const MAX_WEIGHT: Weight = Weight::from_parts(READ_WEIGHT_TIME, READ_WEIGHT_SIZE); + + fn can_delete(did: &did::DidIdentifierOf) -> Result<(), Weight> { + if pallet_web3_names::Names::::contains_key(did) { + Ok(()) + } else { + Err(>::MAX_WEIGHT) + } + } +} + +// TODO: Add the other ones, and then implement the trait for a tuple of +// elements, summing up their `MAX_WEIGHT` as the overall `MAX_WEIGHT`. diff --git a/runtimes/common/src/lib.rs b/runtimes/common/src/lib.rs index 841cead22b..c6aadc251d 100644 --- a/runtimes/common/src/lib.rs +++ b/runtimes/common/src/lib.rs @@ -52,7 +52,9 @@ pub mod deposits; pub mod dip; pub mod dot_names; pub use dot_names::DotName; +pub mod did; pub mod errors; +pub use did::LinkedWeb3NameDeletionHook; pub mod fees; pub mod migrations; pub mod pallet_id; From 05ecd6d426e805780e39f86ef7a5b6a29da43560 Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Fri, 10 Jan 2025 10:03:57 +0100 Subject: [PATCH 02/18] Add more trait implementations --- pallets/did/src/traits.rs | 23 +++++++++++++++++++++++ runtimes/common/src/did.rs | 32 +++++++++++++++++++++++++++++--- runtimes/common/src/dip/mock.rs | 1 + 3 files changed, 53 insertions(+), 3 deletions(-) diff --git a/pallets/did/src/traits.rs b/pallets/did/src/traits.rs index 0efa975010..f65c475e02 100644 --- a/pallets/did/src/traits.rs +++ b/pallets/did/src/traits.rs @@ -16,6 +16,7 @@ // If you feel like getting in touch with us, you can do so at info@botlabs.org +use sp_std::marker::PhantomData; use sp_weights::Weight; use crate::{Config, DidIdentifierOf}; @@ -55,3 +56,25 @@ where Ok(()) } } + +/// Implementation of [`did::traits::DidDeletionHook`] that iterates over both +/// components, bailing out early if the first one fails. +pub struct EvaluateAll(PhantomData<(A, B)>); + +impl DidDeletionHook for EvaluateAll +where + T: Config, + A: DidDeletionHook, + B: DidDeletionHook, +{ + const MAX_WEIGHT: Weight = A::MAX_WEIGHT.saturating_add(B::MAX_WEIGHT); + + fn can_delete(did: &DidIdentifierOf) -> Result<(), Weight> { + // If A fails, return the weight consumed by A. + // If A succeeds and B fails, return A's max weight + B consumed weight. + // Else, return Ok. + A::can_delete(did)?; + B::can_delete(did).map_err(|consumed_weight| A::MAX_WEIGHT.saturating_add(consumed_weight))?; + Ok(()) + } +} diff --git a/runtimes/common/src/did.rs b/runtimes/common/src/did.rs index 553c69f472..7d346a8e9c 100644 --- a/runtimes/common/src/did.rs +++ b/runtimes/common/src/did.rs @@ -14,12 +14,13 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +// If you feel like getting in touch with us, you can do so at info@botlabs.org + use did::DidIdentifierOf; use sp_std::marker::PhantomData; use sp_weights::Weight; -// If you feel like getting in touch with us, you can do so at info@botlabs.org pub struct LinkedWeb3NameDeletionHook( PhantomData, ); @@ -41,5 +42,30 @@ where } } -// TODO: Add the other ones, and then implement the trait for a tuple of -// elements, summing up their `MAX_WEIGHT` as the overall `MAX_WEIGHT`. +pub struct LinkedAccountDeletionHook( + PhantomData, +); + +impl + did::traits::DidDeletionHook + for LinkedAccountDeletionHook +where + T: did::Config + pallet_did_lookup::Config>, + AccountLinkingDeployment: 'static, +{ + const MAX_WEIGHT: Weight = Weight::from_parts(READ_WEIGHT_TIME, READ_WEIGHT_SIZE); + + fn can_delete(did: &did::DidIdentifierOf) -> Result<(), Weight> { + // We check whether the prefix iterator for the given DID has at least one + // element (`next == Some`). + let is_any_account_linked = + pallet_did_lookup::ConnectedAccounts::::iter_key_prefix(did) + .next() + .is_some(); + if !is_any_account_linked { + Ok(()) + } else { + Err(>::MAX_WEIGHT) + } + } +} diff --git a/runtimes/common/src/dip/mock.rs b/runtimes/common/src/dip/mock.rs index 74d9fad942..39e6beb601 100644 --- a/runtimes/common/src/dip/mock.rs +++ b/runtimes/common/src/dip/mock.rs @@ -121,6 +121,7 @@ impl did::Config for TestRuntime { type BaseDeposit = ConstU128; type Currency = Balances; type DidIdentifier = DidIdentifier; + type DidLifecycleHooks = (); type EnsureOrigin = EnsureSigned; type Fee = ConstU128; type FeeCollector = (); From 7a2bc97fbb01382a694013e17ae6136d0eb03219 Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Fri, 10 Jan 2025 10:27:55 +0100 Subject: [PATCH 03/18] Implement runtime logic --- runtimes/common/src/did.rs | 20 +++-- runtimes/common/src/lib.rs | 2 +- runtimes/peregrine/src/kilt/did.rs | 32 ++++++-- .../peregrine/src/weights/rocksdb_weights.rs | 75 ++++++++----------- runtimes/spiritnet/src/kilt/did.rs | 32 ++++++-- 5 files changed, 97 insertions(+), 64 deletions(-) diff --git a/runtimes/common/src/did.rs b/runtimes/common/src/did.rs index 7d346a8e9c..086081be24 100644 --- a/runtimes/common/src/did.rs +++ b/runtimes/common/src/did.rs @@ -21,12 +21,14 @@ use sp_std::marker::PhantomData; use sp_weights::Weight; -pub struct LinkedWeb3NameDeletionHook( - PhantomData, -); +pub struct EnsureNoLinkedWeb3NameDeletionHook< + const READ_WEIGHT_TIME: u64, + const READ_WEIGHT_SIZE: u64, + Web3NameDeployment, +>(PhantomData); impl did::traits::DidDeletionHook - for LinkedWeb3NameDeletionHook + for EnsureNoLinkedWeb3NameDeletionHook where T: did::Config + pallet_web3_names::Config>, Web3NameDeployment: 'static, @@ -42,13 +44,15 @@ where } } -pub struct LinkedAccountDeletionHook( - PhantomData, -); +pub struct EnsureNoLinkedAccountDeletionHook< + const READ_WEIGHT_TIME: u64, + const READ_WEIGHT_SIZE: u64, + AccountLinkingDeployment, +>(PhantomData); impl did::traits::DidDeletionHook - for LinkedAccountDeletionHook + for EnsureNoLinkedAccountDeletionHook where T: did::Config + pallet_did_lookup::Config>, AccountLinkingDeployment: 'static, diff --git a/runtimes/common/src/lib.rs b/runtimes/common/src/lib.rs index c6aadc251d..2e3006b079 100644 --- a/runtimes/common/src/lib.rs +++ b/runtimes/common/src/lib.rs @@ -54,7 +54,7 @@ pub mod dot_names; pub use dot_names::DotName; pub mod did; pub mod errors; -pub use did::LinkedWeb3NameDeletionHook; +pub use did::EnsureNoLinkedWeb3NameDeletionHook; pub mod fees; pub mod migrations; pub mod pallet_id; diff --git a/runtimes/peregrine/src/kilt/did.rs b/runtimes/peregrine/src/kilt/did.rs index e81f9b6102..721532d05a 100644 --- a/runtimes/peregrine/src/kilt/did.rs +++ b/runtimes/peregrine/src/kilt/did.rs @@ -17,20 +17,21 @@ // If you feel like getting in touch with us, you can do so at info@botlabs.org use did::{ - DeriveDidCallAuthorizationVerificationKeyRelationship, DeriveDidCallKeyRelationshipResult, DidRawOrigin, - DidVerificationKeyRelationship, EnsureDidOrigin, RelationshipDeriveError, + traits::EvaluateAll, DeriveDidCallAuthorizationVerificationKeyRelationship, DeriveDidCallKeyRelationshipResult, + DidRawOrigin, DidVerificationKeyRelationship, EnsureDidOrigin, RelationshipDeriveError, }; use frame_system::EnsureRoot; use runtime_common::{ constants, + did::EnsureNoLinkedAccountDeletionHook, dot_names::{AllowedDotNameClaimer, AllowedUniqueLinkingAssociator}, - AccountId, DidIdentifier, SendDustAndFeesToTreasury, + AccountId, DidIdentifier, EnsureNoLinkedWeb3NameDeletionHook, SendDustAndFeesToTreasury, }; use sp_core::ConstBool; use crate::{ - weights, Balances, DotNames, Migration, Runtime, RuntimeCall, RuntimeEvent, RuntimeHoldReason, RuntimeOrigin, - UniqueLinking, + weights::{self, rocksdb_weights::constants::RocksDbWeight}, + Balances, DotNames, Migration, Runtime, RuntimeCall, RuntimeEvent, RuntimeHoldReason, RuntimeOrigin, UniqueLinking, }; impl DeriveDidCallAuthorizationVerificationKeyRelationship for RuntimeCall { @@ -86,6 +87,26 @@ impl DeriveDidCallAuthorizationVerificationKeyRelationship for RuntimeCall { } } +pub struct DidLifecycleHooks; + +impl did::traits::DidLifecycleHooks for DidLifecycleHooks { + type DeletionHook = EnsureNoNamesAndNoLinkedAccountsOnDidDeletion; +} + +type EnsureNoWeb3NameOnDeletion = EnsureNoLinkedWeb3NameDeletionHook<{ RocksDbWeight::get().read }, 0, ()>; +type EnsureNoDotNameOnDeletion = + EnsureNoLinkedWeb3NameDeletionHook<{ RocksDbWeight::get().read }, 0, DotNamesDeployment>; +type EnsureNoUsernamesOnDeletion = EvaluateAll; + +type EnsureNoWeb3NameLinkedAccountsOnDeletion = EnsureNoLinkedAccountDeletionHook<{ RocksDbWeight::get().read }, 0, ()>; +type EnsureNoDotNameLinkedAccountOnDeletion = + EnsureNoLinkedWeb3NameDeletionHook<{ RocksDbWeight::get().read }, 0, UniqueLinkingDeployment>; +type EnsureNoLinkedAccountsOnDeletion = + EvaluateAll; + +pub type EnsureNoNamesAndNoLinkedAccountsOnDidDeletion = + EvaluateAll; + impl did::Config for Runtime { type RuntimeEvent = RuntimeEvent; type RuntimeCall = RuntimeCall; @@ -121,6 +142,7 @@ impl did::Config for Runtime { type MaxNumberOfUrlsPerService = constants::did::MaxNumberOfUrlsPerService; type WeightInfo = weights::did::WeightInfo; type BalanceMigrationManager = Migration; + type DidLifecycleHooks = DidLifecycleHooks; } impl pallet_did_lookup::Config for Runtime { diff --git a/runtimes/peregrine/src/weights/rocksdb_weights.rs b/runtimes/peregrine/src/weights/rocksdb_weights.rs index 1a51549073..72bea2f97f 100644 --- a/runtimes/peregrine/src/weights/rocksdb_weights.rs +++ b/runtimes/peregrine/src/weights/rocksdb_weights.rs @@ -1,45 +1,30 @@ -// KILT Blockchain – https://botlabs.org -// Copyright (C) 2019-2024 BOTLabs GmbH -// The KILT Blockchain 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. - -// The KILT Blockchain 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 this program. If not, see . - -// If you feel like getting in touch with us, you can do so at info@botlabs.org - -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION -//! 4.0.0-dev DATE: 2024-03-29 (Y/M/D) -//! HOSTNAME: `eyrie-7`, CPU: `Intel(R) Core(TM) i7-7700 CPU @ 3.60GHz` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 33.0.0 +//! DATE: 2025-01-10 (Y/M/D) +//! HOSTNAME: `rust-2`, CPU: `12th Gen Intel(R) Core(TM) i9-12900K` //! -//! DATABASE: `RocksDb`, RUNTIME: `KILT Spiritnet` -//! BLOCK-NUM: `BlockId::Number(3460187)` +//! DATABASE: `RocksDb`, RUNTIME: `KILT Peregrine Develop` +//! BLOCK-NUM: `BlockId::Number(0)` //! SKIP-WRITE: `false`, SKIP-READ: `false`, WARMUPS: `1` //! STATE-VERSION: `V1`, STATE-CACHE-SIZE: `` -//! WEIGHT-PATH: `runtimes/spiritnet/src/weights/rocksdb_weights.rs` +//! WEIGHT-PATH: `runtimes/peregrine/src/weights/rocksdb_weights.rs` //! METRIC: `Average`, WEIGHT-MUL: `1.1`, WEIGHT-ADD: `0` // Executed Command: -// target/release/kilt-parachain +// target/debug/kilt-parachain // benchmark // storage -// --chain=spiritnet -// --base-path=/home/bird/spiritnet-db/ -// --template-path=.maintain/weight-db-template.hbs +// --chain +// dev +// --template-path +// .maintain/weight-db-template.hbs // --state-version // 1 -// --weight-path=runtimes/spiritnet/src/weights/rocksdb_weights.rs +// --weight-path +// runtimes/peregrine/src/weights/rocksdb_weights.rs // --mul=1.1 -/// Storage DB weights for the `KILT Spiritnet` runtime and `RocksDb`. +/// Storage DB weights for the `KILT Peregrine Develop` runtime and `RocksDb`. pub mod constants { use frame_support::weights::constants; use sp_core::parameter_types; @@ -53,31 +38,31 @@ pub mod constants { /// Calculated by multiplying the *Average* of all values with `1.1` and adding `0`. /// /// Stats nanoseconds: - /// Min, Max: 5_380, 11_860_691 - /// Average: 32_804 - /// Median: 23_288 - /// Std-Dev: 55265.31 + /// Min, Max: 15_180, 14_278_535 + /// Average: 169_414 + /// Median: 20_103 + /// Std-Dev: 1447573.56 /// /// Percentiles nanoseconds: - /// 99th: 278_383 - /// 95th: 57_425 - /// 75th: 30_265 - read: 36_085 * constants::WEIGHT_REF_TIME_PER_NANOS, + /// 99th: 14_278_535 + /// 95th: 27_260 + /// 75th: 23_057 + read: 186_356 * constants::WEIGHT_REF_TIME_PER_NANOS, /// Time to write one storage item. /// Calculated by multiplying the *Average* of all values with `1.1` and adding `0`. /// /// Stats nanoseconds: - /// Min, Max: 19_775, 13_936_221 - /// Average: 74_821 - /// Median: 72_516 - /// Std-Dev: 66500.91 + /// Min, Max: 41_658, 708_109_449 + /// Average: 7_511_596 + /// Median: 129_472 + /// Std-Dev: 71879832.74 /// /// Percentiles nanoseconds: - /// 99th: 113_045 - /// 95th: 95_002 - /// 75th: 81_339 - write: 82_304 * constants::WEIGHT_REF_TIME_PER_NANOS, + /// 99th: 708_109_449 + /// 95th: 190_014 + /// 75th: 155_799 + write: 8_262_756 * constants::WEIGHT_REF_TIME_PER_NANOS, }; } diff --git a/runtimes/spiritnet/src/kilt/did.rs b/runtimes/spiritnet/src/kilt/did.rs index e81f9b6102..721532d05a 100644 --- a/runtimes/spiritnet/src/kilt/did.rs +++ b/runtimes/spiritnet/src/kilt/did.rs @@ -17,20 +17,21 @@ // If you feel like getting in touch with us, you can do so at info@botlabs.org use did::{ - DeriveDidCallAuthorizationVerificationKeyRelationship, DeriveDidCallKeyRelationshipResult, DidRawOrigin, - DidVerificationKeyRelationship, EnsureDidOrigin, RelationshipDeriveError, + traits::EvaluateAll, DeriveDidCallAuthorizationVerificationKeyRelationship, DeriveDidCallKeyRelationshipResult, + DidRawOrigin, DidVerificationKeyRelationship, EnsureDidOrigin, RelationshipDeriveError, }; use frame_system::EnsureRoot; use runtime_common::{ constants, + did::EnsureNoLinkedAccountDeletionHook, dot_names::{AllowedDotNameClaimer, AllowedUniqueLinkingAssociator}, - AccountId, DidIdentifier, SendDustAndFeesToTreasury, + AccountId, DidIdentifier, EnsureNoLinkedWeb3NameDeletionHook, SendDustAndFeesToTreasury, }; use sp_core::ConstBool; use crate::{ - weights, Balances, DotNames, Migration, Runtime, RuntimeCall, RuntimeEvent, RuntimeHoldReason, RuntimeOrigin, - UniqueLinking, + weights::{self, rocksdb_weights::constants::RocksDbWeight}, + Balances, DotNames, Migration, Runtime, RuntimeCall, RuntimeEvent, RuntimeHoldReason, RuntimeOrigin, UniqueLinking, }; impl DeriveDidCallAuthorizationVerificationKeyRelationship for RuntimeCall { @@ -86,6 +87,26 @@ impl DeriveDidCallAuthorizationVerificationKeyRelationship for RuntimeCall { } } +pub struct DidLifecycleHooks; + +impl did::traits::DidLifecycleHooks for DidLifecycleHooks { + type DeletionHook = EnsureNoNamesAndNoLinkedAccountsOnDidDeletion; +} + +type EnsureNoWeb3NameOnDeletion = EnsureNoLinkedWeb3NameDeletionHook<{ RocksDbWeight::get().read }, 0, ()>; +type EnsureNoDotNameOnDeletion = + EnsureNoLinkedWeb3NameDeletionHook<{ RocksDbWeight::get().read }, 0, DotNamesDeployment>; +type EnsureNoUsernamesOnDeletion = EvaluateAll; + +type EnsureNoWeb3NameLinkedAccountsOnDeletion = EnsureNoLinkedAccountDeletionHook<{ RocksDbWeight::get().read }, 0, ()>; +type EnsureNoDotNameLinkedAccountOnDeletion = + EnsureNoLinkedWeb3NameDeletionHook<{ RocksDbWeight::get().read }, 0, UniqueLinkingDeployment>; +type EnsureNoLinkedAccountsOnDeletion = + EvaluateAll; + +pub type EnsureNoNamesAndNoLinkedAccountsOnDidDeletion = + EvaluateAll; + impl did::Config for Runtime { type RuntimeEvent = RuntimeEvent; type RuntimeCall = RuntimeCall; @@ -121,6 +142,7 @@ impl did::Config for Runtime { type MaxNumberOfUrlsPerService = constants::did::MaxNumberOfUrlsPerService; type WeightInfo = weights::did::WeightInfo; type BalanceMigrationManager = Migration; + type DidLifecycleHooks = DidLifecycleHooks; } impl pallet_did_lookup::Config for Runtime { From 038daf08a1706fd54273a4e43cd430468fa5cbb7 Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Fri, 10 Jan 2025 11:31:22 +0100 Subject: [PATCH 04/18] Testing mock in progress --- .../src/{did.rs => did/deletion_hooks/mod.rs} | 3 + .../deletion_hooks/tests/linked_account.rs | 17 ++ .../did/deletion_hooks/tests/linked_name.rs | 17 ++ .../src/did/deletion_hooks/tests/mock.rs | 242 ++++++++++++++++++ .../src/did/deletion_hooks/tests/mod.rs | 21 ++ runtimes/common/src/did/mod.rs | 20 ++ runtimes/common/src/lib.rs | 2 +- 7 files changed, 321 insertions(+), 1 deletion(-) rename runtimes/common/src/{did.rs => did/deletion_hooks/mod.rs} (99%) create mode 100644 runtimes/common/src/did/deletion_hooks/tests/linked_account.rs create mode 100644 runtimes/common/src/did/deletion_hooks/tests/linked_name.rs create mode 100644 runtimes/common/src/did/deletion_hooks/tests/mock.rs create mode 100644 runtimes/common/src/did/deletion_hooks/tests/mod.rs create mode 100644 runtimes/common/src/did/mod.rs diff --git a/runtimes/common/src/did.rs b/runtimes/common/src/did/deletion_hooks/mod.rs similarity index 99% rename from runtimes/common/src/did.rs rename to runtimes/common/src/did/deletion_hooks/mod.rs index 086081be24..7f70d8e09f 100644 --- a/runtimes/common/src/did.rs +++ b/runtimes/common/src/did/deletion_hooks/mod.rs @@ -16,6 +16,9 @@ // If you feel like getting in touch with us, you can do so at info@botlabs.org +#[cfg(test)] +mod tests; + use did::DidIdentifierOf; use sp_std::marker::PhantomData; diff --git a/runtimes/common/src/did/deletion_hooks/tests/linked_account.rs b/runtimes/common/src/did/deletion_hooks/tests/linked_account.rs new file mode 100644 index 0000000000..73b2b1a764 --- /dev/null +++ b/runtimes/common/src/did/deletion_hooks/tests/linked_account.rs @@ -0,0 +1,17 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2024 BOTLabs GmbH + +// The KILT Blockchain 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. + +// The KILT Blockchain 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 this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org diff --git a/runtimes/common/src/did/deletion_hooks/tests/linked_name.rs b/runtimes/common/src/did/deletion_hooks/tests/linked_name.rs new file mode 100644 index 0000000000..73b2b1a764 --- /dev/null +++ b/runtimes/common/src/did/deletion_hooks/tests/linked_name.rs @@ -0,0 +1,17 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2024 BOTLabs GmbH + +// The KILT Blockchain 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. + +// The KILT Blockchain 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 this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org diff --git a/runtimes/common/src/did/deletion_hooks/tests/mock.rs b/runtimes/common/src/did/deletion_hooks/tests/mock.rs new file mode 100644 index 0000000000..fafd67444c --- /dev/null +++ b/runtimes/common/src/did/deletion_hooks/tests/mock.rs @@ -0,0 +1,242 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2024 BOTLabs GmbH + +// The KILT Blockchain 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. + +// The KILT Blockchain 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 this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +use did::{traits::EvaluateAll, DidVerificationKeyRelationship}; +use frame_support::{ + construct_runtime, + dispatch::DispatchResult, + parameter_types, + traits::{ + fungible::{Balanced, Dust, Inspect, InspectHold, Mutate, MutateHold, Unbalanced, UnbalancedHold}, + tokens::{DepositConsequence, Fortitude, Preservation, Provenance, WithdrawConsequence}, + }, +}; +use frame_system::{mocking::MockBlock, EnsureRoot, EnsureSigned}; +use parity_scale_codec::{Decode, Encode}; +use scale_info::TypeInfo; +use sp_core::{ConstBool, ConstU32, ConstU64, H256}; +use sp_runtime::{ + traits::{BlakeTwo256, IdentityLookup}, + AccountId32, DispatchError, +}; + +use crate::{EnsureNoLinkedAccountDeletionHook, EnsureNoLinkedWeb3NameDeletionHook}; + +construct_runtime!( + pub enum TestRuntime + { + System: frame_system, + Did: did, + Web3Names: pallet_web3_names, + LinkedAccounts: pallet_did_lookup, + } +); + +impl frame_system::Config for TestRuntime { + type AccountData = (); + type AccountId = AccountId32; + type BaseCallFilter = (); + type Block = MockBlock; + type BlockHashCount = ConstU64<1>; + type BlockLength = (); + type BlockWeights = (); + type DbWeight = (); + type Hash = H256; + type Hashing = BlakeTwo256; + type Lookup = IdentityLookup; + type MaxConsumers = ConstU32<1>; + type Nonce = u64; + type OnKilledAccount = (); + type OnNewAccount = (); + type OnSetCode = (); + type PalletInfo = PalletInfo; + type RuntimeEvent = (); + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + type RuntimeTask = (); + type SS58Prefix = (); + type SystemWeightInfo = (); + type Version = (); +} + +pub struct MockCurrency; + +impl MutateHold for MockCurrency {} + +impl UnbalancedHold for MockCurrency { + fn set_balance_on_hold(_reason: &Self::Reason, _who: &AccountId32, _amount: Self::Balance) -> DispatchResult { + Ok(()) + } +} + +impl InspectHold for MockCurrency { + type Reason = RuntimeHoldReason; + + fn total_balance_on_hold(_who: &AccountId32) -> Self::Balance { + Self::Balance::default() + } + + fn balance_on_hold(_reason: &Self::Reason, _who: &AccountId32) -> Self::Balance { + Self::Balance::default() + } +} + +impl Mutate for MockCurrency {} + +impl Inspect for MockCurrency { + type Balance = u64; + + fn active_issuance() -> Self::Balance { + Self::Balance::default() + } + + fn balance(_who: &AccountId32) -> Self::Balance { + Self::Balance::default() + } + + fn can_deposit(_who: &AccountId32, _amount: Self::Balance, _provenance: Provenance) -> DepositConsequence { + DepositConsequence::Success + } + + fn can_withdraw(_who: &AccountId32, _amount: Self::Balance) -> WithdrawConsequence { + WithdrawConsequence::Success + } + + fn minimum_balance() -> Self::Balance { + Self::Balance::default() + } + + fn reducible_balance(_who: &AccountId32, _preservation: Preservation, _force: Fortitude) -> Self::Balance { + Self::Balance::default() + } + + fn total_balance(_who: &AccountId32) -> Self::Balance { + Self::Balance::default() + } + + fn total_issuance() -> Self::Balance { + Self::Balance::default() + } +} + +impl Unbalanced for MockCurrency { + fn handle_dust(_dust: Dust) {} + + fn write_balance(_who: &AccountId32, _amount: Self::Balance) -> Result, DispatchError> { + Ok(Some(Self::Balance::default())) + } + + fn set_total_issuance(_amount: Self::Balance) {} +} + +impl Balanced for MockCurrency { + type OnDropDebt = (); + type OnDropCredit = (); +} + +parameter_types! { + #[derive(TypeInfo, Debug, PartialEq, Eq, Clone, Encode, Decode)] + pub const MaxNewKeyAgreementKeys: u32 = 1; + #[derive(TypeInfo, Debug, PartialEq, Eq, Clone, Encode, Decode)] + pub const MaxTotalKeyAgreementKeys: u32 = 1; +} + +impl did::DeriveDidCallAuthorizationVerificationKeyRelationship for RuntimeCall { + fn derive_verification_key_relationship(&self) -> did::DeriveDidCallKeyRelationshipResult { + Ok(DidVerificationKeyRelationship::Authentication) + } + + #[cfg(feature = "runtime-benchmarks")] + fn get_call_for_did_call_benchmark() -> Self { + Self::System(frame_system::Call::remark { + remark: b"test".to_vec(), + }) + } +} + +pub struct DidLifecycleHooks; + +impl did::traits::DidLifecycleHooks for DidLifecycleHooks { + type DeletionHook = + EvaluateAll, EnsureNoLinkedAccountDeletionHook<1, 1, ()>>; +} + +impl did::Config for TestRuntime { + type BalanceMigrationManager = (); + type BaseDeposit = ConstU64<1>; + type Currency = MockCurrency; + type DidIdentifier = AccountId32; + type DidLifecycleHooks = (); + type EnsureOrigin = EnsureSigned; + type Fee = ConstU64<1>; + type FeeCollector = (); + type KeyDeposit = ConstU64<1>; + type MaxBlocksTxValidity = ConstU64<1>; + type MaxNewKeyAgreementKeys = MaxNewKeyAgreementKeys; + type MaxNumberOfServicesPerDid = ConstU32<1>; + type MaxNumberOfTypesPerService = ConstU32<1>; + type MaxNumberOfUrlsPerService = ConstU32<1>; + type MaxPublicKeysPerDid = ConstU32<1>; + type MaxServiceIdLength = ConstU32<1>; + type MaxServiceTypeLength = ConstU32<1>; + type MaxServiceUrlLength = ConstU32<1>; + type MaxTotalKeyAgreementKeys = MaxTotalKeyAgreementKeys; + type OriginSuccess = AccountId32; + type RuntimeCall = RuntimeCall; + type RuntimeEvent = (); + type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeOrigin = RuntimeOrigin; + type ServiceEndpointDeposit = ConstU64<1>; + type WeightInfo = (); +} + +impl pallet_did_lookup::Config for TestRuntime { + type AssociateOrigin = Self::EnsureOrigin; + type BalanceMigrationManager = (); + type Currency = MockCurrency; + type Deposit = ConstU64<1>; + type DidIdentifier = AccountId32; + type EnsureOrigin = EnsureSigned; + type OriginSuccess = AccountId32; + type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeEvent = (); + type UniqueLinkingEnabled = ConstBool; + type WeightInfo = (); +} + +pub type Web3Name = crate::Web3Name<1, 2>; +impl pallet_web3_names::Config for TestRuntime { + type BalanceMigrationManager = (); + type BanOrigin = EnsureRoot; + type ClaimOrigin = Self::OwnerOrigin; + type Currency = MockCurrency; + type Deposit = ConstU64<1>; + type OriginSuccess = AccountId32; + type MaxNameLength = ConstU32<1>; + type MinNameLength = ConstU32<1>; + type OwnerOrigin = EnsureSigned; + type RuntimeEvent = (); + type RuntimeHoldReason = RuntimeHoldReason; + type Web3Name = Web3Name; + type Web3NameOwner = AccountId32; + type WeightInfo = (); + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = (); +} + +// TODO: Add `ExtBuilder` diff --git a/runtimes/common/src/did/deletion_hooks/tests/mod.rs b/runtimes/common/src/did/deletion_hooks/tests/mod.rs new file mode 100644 index 0000000000..7ee25da57a --- /dev/null +++ b/runtimes/common/src/did/deletion_hooks/tests/mod.rs @@ -0,0 +1,21 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2024 BOTLabs GmbH + +// The KILT Blockchain 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. + +// The KILT Blockchain 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 this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +mod linked_account; +mod linked_name; +mod mock; diff --git a/runtimes/common/src/did/mod.rs b/runtimes/common/src/did/mod.rs new file mode 100644 index 0000000000..f51d802733 --- /dev/null +++ b/runtimes/common/src/did/mod.rs @@ -0,0 +1,20 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2024 BOTLabs GmbH + +// The KILT Blockchain 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. + +// The KILT Blockchain 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 this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +mod deletion_hooks; +pub use deletion_hooks::{EnsureNoLinkedAccountDeletionHook, EnsureNoLinkedWeb3NameDeletionHook}; diff --git a/runtimes/common/src/lib.rs b/runtimes/common/src/lib.rs index 2e3006b079..1056374f64 100644 --- a/runtimes/common/src/lib.rs +++ b/runtimes/common/src/lib.rs @@ -53,8 +53,8 @@ pub mod dip; pub mod dot_names; pub use dot_names::DotName; pub mod did; +pub use did::{EnsureNoLinkedAccountDeletionHook, EnsureNoLinkedWeb3NameDeletionHook}; pub mod errors; -pub use did::EnsureNoLinkedWeb3NameDeletionHook; pub mod fees; pub mod migrations; pub mod pallet_id; From a8b507acea275f1570d0c010bda816ef18da43c2 Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Fri, 10 Jan 2025 11:42:40 +0100 Subject: [PATCH 05/18] Move the linked resources check to after we check for DID existence --- pallets/did/src/lib.rs | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/pallets/did/src/lib.rs b/pallets/did/src/lib.rs index 76963539a8..6f632a577d 100644 --- a/pallets/did/src/lib.rs +++ b/pallets/did/src/lib.rs @@ -1504,17 +1504,6 @@ pub mod pallet { /// endpoints, adds the identifier to the blacklisted DIDs and frees the /// deposit. pub fn delete_did(did_subject: DidIdentifierOf, endpoints_to_remove: u32) -> DispatchResult { - let Ok(()) = - <>::DeletionHook as DidDeletionHook>::can_delete( - &did_subject, - ) - else { - return Err(Error::::CannotDelete.into()); - }; - // <>::DidDeletionHook as - // DidDeletionHook>::can_delete( &did_subject, - // )?; - let current_endpoints_count = DidEndpointsCount::::get(&did_subject); ensure!( current_endpoints_count <= endpoints_to_remove, @@ -1536,6 +1525,14 @@ pub mod pallet { // `take` calls `kill` internally let did_entry = Did::::take(&did_subject).ok_or(Error::::NotFound)?; + let Ok(()) = + <>::DeletionHook as DidDeletionHook>::can_delete( + &did_subject, + ) + else { + return Err(Error::::CannotDelete.into()); + }; + DidEndpointsCount::::remove(&did_subject); let is_key_migrated = From d5742a8f2d6aa32f522b910b7e218acec499e484 Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Fri, 10 Jan 2025 13:40:32 +0100 Subject: [PATCH 06/18] Mock complete --- Cargo.lock | 1 + runtimes/common/Cargo.toml | 1 + .../src/did/deletion_hooks/tests/mock.rs | 48 +++++++++++++++++-- 3 files changed, 47 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d44078959c..5bcdfc8cad 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10939,6 +10939,7 @@ dependencies = [ "cumulus-primitives-core", "did", "enum-iterator", + "env_logger 0.10.2", "frame-benchmarking", "frame-support", "frame-system", diff --git a/runtimes/common/Cargo.toml b/runtimes/common/Cargo.toml index d31a31f0c3..48356ddbff 100644 --- a/runtimes/common/Cargo.toml +++ b/runtimes/common/Cargo.toml @@ -13,6 +13,7 @@ version = { workspace = true } [dev-dependencies] did = { workspace = true, features = ["mock", "std"] } enum-iterator = { workspace = true } +env_logger = { workspace = true } kilt-dip-primitives = { workspace = true, features = ["std"] } sp-io = { workspace = true, features = ["std"] } diff --git a/runtimes/common/src/did/deletion_hooks/tests/mock.rs b/runtimes/common/src/did/deletion_hooks/tests/mock.rs index fafd67444c..cc5fd7af8d 100644 --- a/runtimes/common/src/did/deletion_hooks/tests/mock.rs +++ b/runtimes/common/src/did/deletion_hooks/tests/mock.rs @@ -16,7 +16,7 @@ // If you feel like getting in touch with us, you can do so at info@botlabs.org -use did::{traits::EvaluateAll, DidVerificationKeyRelationship}; +use did::{did_details::DidVerificationKey, traits::EvaluateAll, DidVerificationKeyRelationship}; use frame_support::{ construct_runtime, dispatch::DispatchResult, @@ -26,10 +26,11 @@ use frame_support::{ tokens::{DepositConsequence, Fortitude, Preservation, Provenance, WithdrawConsequence}, }, }; -use frame_system::{mocking::MockBlock, EnsureRoot, EnsureSigned}; +use frame_system::{mocking::MockBlock, EnsureRoot, EnsureSigned, RawOrigin}; use parity_scale_codec::{Decode, Encode}; use scale_info::TypeInfo; use sp_core::{ConstBool, ConstU32, ConstU64, H256}; +use sp_io::TestExternalities; use sp_runtime::{ traits::{BlakeTwo256, IdentityLookup}, AccountId32, DispatchError, @@ -239,4 +240,45 @@ impl pallet_web3_names::Config for TestRuntime { type BenchmarkHelper = (); } -// TODO: Add `ExtBuilder` +#[derive(Default)] +pub(super) struct ExtBuilder(Vec<(AccountId32, Option, bool)>); + +impl ExtBuilder { + pub(super) fn with_dids(mut self, did_links: Vec<(AccountId32, Option, bool)>) -> Self { + self.0 = did_links; + self + } + + pub(super) fn build(self) -> TestExternalities { + let _ = env_logger::try_init(); + let mut ext = TestExternalities::default(); + + ext.execute_with(|| { + for (did, maybe_web3_name, should_link_account) in self.0 { + // Store DID. + Did::create_from_account( + RawOrigin::Signed(did.clone()).into(), + DidVerificationKey::Account(did.clone()), + ) + .expect("Failed to create DID."); + + // If specified, link web3name. + if let Some(web3_name) = maybe_web3_name { + Web3Names::claim( + RawOrigin::Signed(did.clone()).into(), + Vec::::from(web3_name.clone()).try_into().unwrap(), + ) + .expect("Failed to link web3name."); + } + + // If specified, link account. + if should_link_account { + LinkedAccounts::associate_sender(RawOrigin::Signed(did.clone()).into()) + .expect("Failed to link account."); + } + } + }); + + ext + } +} From 5d2ec86bf0a6326e069db07c07e5ff302903b950 Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Fri, 10 Jan 2025 14:23:13 +0100 Subject: [PATCH 07/18] Tests completed --- .../lifecycle_hooks/deletion/mod.rs} | 17 +- .../traits/lifecycle_hooks/deletion/tests.rs | 80 +++++++ .../did/src/traits/lifecycle_hooks/mock.rs | 199 ++++++++++++++++++ pallets/did/src/traits/lifecycle_hooks/mod.rs | 41 ++++ pallets/did/src/traits/mod.rs | 20 ++ runtimes/common/src/did/deletion_hooks/mod.rs | 2 +- .../deletion_hooks/tests/linked_account.rs | 71 +++++++ .../src/did/deletion_hooks/tests/mock.rs | 47 ++++- 8 files changed, 453 insertions(+), 24 deletions(-) rename pallets/did/src/{traits.rs => traits/lifecycle_hooks/deletion/mod.rs} (92%) create mode 100644 pallets/did/src/traits/lifecycle_hooks/deletion/tests.rs create mode 100644 pallets/did/src/traits/lifecycle_hooks/mock.rs create mode 100644 pallets/did/src/traits/lifecycle_hooks/mod.rs create mode 100644 pallets/did/src/traits/mod.rs diff --git a/pallets/did/src/traits.rs b/pallets/did/src/traits/lifecycle_hooks/deletion/mod.rs similarity index 92% rename from pallets/did/src/traits.rs rename to pallets/did/src/traits/lifecycle_hooks/deletion/mod.rs index f65c475e02..ea0f0052cc 100644 --- a/pallets/did/src/traits.rs +++ b/pallets/did/src/traits/lifecycle_hooks/deletion/mod.rs @@ -16,25 +16,14 @@ // If you feel like getting in touch with us, you can do so at info@botlabs.org +#[cfg(test)] +mod tests; + use sp_std::marker::PhantomData; use sp_weights::Weight; use crate::{Config, DidIdentifierOf}; -pub trait DidLifecycleHooks -where - T: Config, -{ - type DeletionHook: DidDeletionHook; -} - -impl DidLifecycleHooks for () -where - T: Config, -{ - type DeletionHook = (); -} - pub trait DidDeletionHook where T: Config, diff --git a/pallets/did/src/traits/lifecycle_hooks/deletion/tests.rs b/pallets/did/src/traits/lifecycle_hooks/deletion/tests.rs new file mode 100644 index 0000000000..8d6c9b73d5 --- /dev/null +++ b/pallets/did/src/traits/lifecycle_hooks/deletion/tests.rs @@ -0,0 +1,80 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2024 BOTLabs GmbH + +// The KILT Blockchain 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. + +// The KILT Blockchain 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 this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +use sp_runtime::AccountId32; +use sp_weights::Weight; + +use crate::{ + traits::lifecycle_hooks::{deletion::EvaluateAll, mock::TestRuntime, DidDeletionHook}, + DidIdentifierOf, +}; + +struct False; + +impl DidDeletionHook for False { + const MAX_WEIGHT: Weight = Weight::from_all(10); + + fn can_delete(_did: &DidIdentifierOf) -> Result<(), Weight> { + Err(Weight::from_all(5)) + } +} + +struct True; + +impl DidDeletionHook for True { + const MAX_WEIGHT: Weight = Weight::from_all(20); + + fn can_delete(did: &DidIdentifierOf) -> Result<(), Weight> { + Ok(()) + } +} + +#[test] +fn first_false() { + type TestSubject = EvaluateAll; + + // Max weight is the sum. + assert_eq!(TestSubject::MAX_WEIGHT, Weight::from_all(30)); + // Failure consumes `False`'s weight. + assert_eq!( + TestSubject::can_delete(&AccountId32::new([0u8; 32])), + Err(Weight::from_all(5)) + ); +} + +#[test] +fn second_false() { + type TestSubject = EvaluateAll; + + // Max weight is the sum. + assert_eq!(TestSubject::MAX_WEIGHT, Weight::from_all(30)); + // Failure consumes the sum of `True`'s max weight and `False`'s weight. + assert_eq!( + TestSubject::can_delete(&AccountId32::new([0u8; 32])), + Err(Weight::from_all(25)) + ); +} + +#[test] +fn both_true() { + type TestSubject = EvaluateAll; + + // Max weight is the sum. + assert_eq!(TestSubject::MAX_WEIGHT, Weight::from_all(40)); + assert_eq!(TestSubject::can_delete(&AccountId32::new([0u8; 32])), Ok(())); +} diff --git a/pallets/did/src/traits/lifecycle_hooks/mock.rs b/pallets/did/src/traits/lifecycle_hooks/mock.rs new file mode 100644 index 0000000000..5659f1eae6 --- /dev/null +++ b/pallets/did/src/traits/lifecycle_hooks/mock.rs @@ -0,0 +1,199 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2024 BOTLabs GmbH + +// The KILT Blockchain 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. + +// The KILT Blockchain 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 this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +use frame_support::{ + construct_runtime, + dispatch::DispatchResult, + parameter_types, + traits::{ + fungible::{Balanced, Dust, Inspect, InspectHold, Mutate, MutateHold, Unbalanced, UnbalancedHold}, + tokens::{DepositConsequence, Fortitude, Preservation, Provenance, WithdrawConsequence}, + }, +}; +use frame_system::{mocking::MockBlock, EnsureSigned}; +use parity_scale_codec::{Decode, Encode}; +use scale_info::TypeInfo; +use sp_core::{ConstU32, ConstU64, H256}; +use sp_runtime::{ + traits::{BlakeTwo256, IdentityLookup}, + AccountId32, DispatchError, +}; + +use crate::{ + Config, DeriveDidCallAuthorizationVerificationKeyRelationship, DeriveDidCallKeyRelationshipResult, + DidVerificationKeyRelationship, +}; + +construct_runtime!( + pub enum TestRuntime + { + System: frame_system, + Did: crate, + } +); + +impl frame_system::Config for TestRuntime { + type AccountData = (); + type AccountId = AccountId32; + type BaseCallFilter = (); + type Block = MockBlock; + type BlockHashCount = ConstU64<1>; + type BlockLength = (); + type BlockWeights = (); + type DbWeight = (); + type Hash = H256; + type Hashing = BlakeTwo256; + type Lookup = IdentityLookup; + type MaxConsumers = ConstU32<1>; + type Nonce = u64; + type OnKilledAccount = (); + type OnNewAccount = (); + type OnSetCode = (); + type PalletInfo = PalletInfo; + type RuntimeEvent = (); + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + type RuntimeTask = (); + type SS58Prefix = (); + type SystemWeightInfo = (); + type Version = (); +} + +pub struct MockCurrency; + +impl MutateHold for MockCurrency {} + +impl UnbalancedHold for MockCurrency { + fn set_balance_on_hold(_reason: &Self::Reason, _who: &AccountId32, _amount: Self::Balance) -> DispatchResult { + Ok(()) + } +} + +impl InspectHold for MockCurrency { + type Reason = RuntimeHoldReason; + + fn total_balance_on_hold(_who: &AccountId32) -> Self::Balance { + Self::Balance::default() + } + + fn balance_on_hold(_reason: &Self::Reason, _who: &AccountId32) -> Self::Balance { + Self::Balance::default() + } +} + +impl Mutate for MockCurrency {} + +impl Inspect for MockCurrency { + type Balance = u64; + + fn active_issuance() -> Self::Balance { + Self::Balance::default() + } + + fn balance(_who: &AccountId32) -> Self::Balance { + Self::Balance::default() + } + + fn can_deposit(_who: &AccountId32, _amount: Self::Balance, _provenance: Provenance) -> DepositConsequence { + DepositConsequence::Success + } + + fn can_withdraw(_who: &AccountId32, _amount: Self::Balance) -> WithdrawConsequence { + WithdrawConsequence::Success + } + + fn minimum_balance() -> Self::Balance { + Self::Balance::default() + } + + fn reducible_balance(_who: &AccountId32, _preservation: Preservation, _force: Fortitude) -> Self::Balance { + Self::Balance::default() + } + + fn total_balance(_who: &AccountId32) -> Self::Balance { + Self::Balance::default() + } + + fn total_issuance() -> Self::Balance { + Self::Balance::default() + } +} + +impl Unbalanced for MockCurrency { + fn handle_dust(_dust: Dust) {} + + fn write_balance(_who: &AccountId32, _amount: Self::Balance) -> Result, DispatchError> { + Ok(Some(Self::Balance::default())) + } + + fn set_total_issuance(_amount: Self::Balance) {} +} + +impl Balanced for MockCurrency { + type OnDropDebt = (); + type OnDropCredit = (); +} + +parameter_types! { + #[derive(TypeInfo, Debug, PartialEq, Eq, Clone, Encode, Decode)] + pub const MaxNewKeyAgreementKeys: u32 = 1; + #[derive(TypeInfo, Debug, PartialEq, Eq, Clone, Encode, Decode)] + pub const MaxTotalKeyAgreementKeys: u32 = 1; +} + +impl DeriveDidCallAuthorizationVerificationKeyRelationship for RuntimeCall { + fn derive_verification_key_relationship(&self) -> DeriveDidCallKeyRelationshipResult { + Ok(DidVerificationKeyRelationship::Authentication) + } + + #[cfg(feature = "runtime-benchmarks")] + fn get_call_for_did_call_benchmark() -> Self { + Self::System(frame_system::Call::remark { + remark: b"test".to_vec(), + }) + } +} + +impl Config for TestRuntime { + type BalanceMigrationManager = (); + type BaseDeposit = ConstU64<1>; + type Currency = MockCurrency; + type DidIdentifier = AccountId32; + type DidLifecycleHooks = (); + type EnsureOrigin = EnsureSigned; + type Fee = ConstU64<1>; + type FeeCollector = (); + type KeyDeposit = ConstU64<1>; + type MaxBlocksTxValidity = ConstU64<1>; + type MaxNewKeyAgreementKeys = MaxNewKeyAgreementKeys; + type MaxNumberOfServicesPerDid = ConstU32<1>; + type MaxNumberOfTypesPerService = ConstU32<1>; + type MaxNumberOfUrlsPerService = ConstU32<1>; + type MaxPublicKeysPerDid = ConstU32<1>; + type MaxServiceIdLength = ConstU32<1>; + type MaxServiceTypeLength = ConstU32<1>; + type MaxServiceUrlLength = ConstU32<1>; + type MaxTotalKeyAgreementKeys = MaxTotalKeyAgreementKeys; + type OriginSuccess = AccountId32; + type RuntimeCall = RuntimeCall; + type RuntimeEvent = (); + type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeOrigin = RuntimeOrigin; + type ServiceEndpointDeposit = ConstU64<1>; + type WeightInfo = (); +} diff --git a/pallets/did/src/traits/lifecycle_hooks/mod.rs b/pallets/did/src/traits/lifecycle_hooks/mod.rs new file mode 100644 index 0000000000..f62e7f2cc4 --- /dev/null +++ b/pallets/did/src/traits/lifecycle_hooks/mod.rs @@ -0,0 +1,41 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2024 BOTLabs GmbH + +// The KILT Blockchain 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. + +// The KILT Blockchain 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 this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +pub mod deletion; +pub use deletion::DidDeletionHook; + +// We need this mock since the trait requires the implementation of the did's +// `Config` trait. +#[cfg(test)] +mod mock; + +use crate::Config; + +pub trait DidLifecycleHooks +where + T: Config, +{ + type DeletionHook: DidDeletionHook; +} + +impl DidLifecycleHooks for () +where + T: Config, +{ + type DeletionHook = (); +} diff --git a/pallets/did/src/traits/mod.rs b/pallets/did/src/traits/mod.rs new file mode 100644 index 0000000000..552b58bab6 --- /dev/null +++ b/pallets/did/src/traits/mod.rs @@ -0,0 +1,20 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2024 BOTLabs GmbH + +// The KILT Blockchain 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. + +// The KILT Blockchain 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 this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +mod lifecycle_hooks; +pub use lifecycle_hooks::{deletion, DidDeletionHook, DidLifecycleHooks}; diff --git a/runtimes/common/src/did/deletion_hooks/mod.rs b/runtimes/common/src/did/deletion_hooks/mod.rs index 7f70d8e09f..ba762f8ac7 100644 --- a/runtimes/common/src/did/deletion_hooks/mod.rs +++ b/runtimes/common/src/did/deletion_hooks/mod.rs @@ -39,7 +39,7 @@ where const MAX_WEIGHT: Weight = Weight::from_parts(READ_WEIGHT_TIME, READ_WEIGHT_SIZE); fn can_delete(did: &did::DidIdentifierOf) -> Result<(), Weight> { - if pallet_web3_names::Names::::contains_key(did) { + if !pallet_web3_names::Names::::contains_key(did) { Ok(()) } else { Err(>::MAX_WEIGHT) diff --git a/runtimes/common/src/did/deletion_hooks/tests/linked_account.rs b/runtimes/common/src/did/deletion_hooks/tests/linked_account.rs index 73b2b1a764..e81090b24f 100644 --- a/runtimes/common/src/did/deletion_hooks/tests/linked_account.rs +++ b/runtimes/common/src/did/deletion_hooks/tests/linked_account.rs @@ -15,3 +15,74 @@ // along with this program. If not, see . // If you feel like getting in touch with us, you can do so at info@botlabs.org + +use frame_support::{assert_noop, assert_ok}; +use frame_system::RawOrigin; + +use crate::did::deletion_hooks::tests::mock::{Did, ExtBuilder, TestRuntime, DID}; + +#[test] +fn test_delete_with_no_dangling_resources() { + ExtBuilder::default() + .with_dids(vec![(DID, None, false)]) + .build() + .execute_with(|| { + assert_ok!(Did::delete(RawOrigin::Signed(DID).into(), 0)); + }); +} + +#[test] +fn test_delete_with_dangling_web3_name() { + ExtBuilder::default() + .with_dids(vec![(DID, Some(b"t".to_vec().try_into().unwrap()), false)]) + .build() + .execute_with(|| { + assert_noop!( + Did::delete(RawOrigin::Signed(DID).into(), 0), + did::Error::::CannotDelete + ); + }); +} + +#[test] +fn test_delete_with_dangling_linked_account() { + ExtBuilder::default() + .with_dids(vec![(DID, None, true)]) + .build() + .execute_with(|| { + assert_noop!( + Did::delete(RawOrigin::Signed(DID).into(), 0), + did::Error::::CannotDelete + ); + }); +} + +// If someone tries to re-delete a delete DID with dangling resources, they get +// a `NotFound` error. +#[test] +fn test_delete_with_no_did_and_dangling_web3_name() { + ExtBuilder::default() + .with_dangling_dids(vec![(DID, Some(b"t".to_vec().try_into().unwrap()), false)]) + .build() + .execute_with(|| { + assert_noop!( + Did::delete(RawOrigin::Signed(DID).into(), 0), + did::Error::::NotFound + ); + }); +} + +// If someone tries to re-delete a delete DID with dangling resources, they get +// a `NotFound` error. +#[test] +fn test_delete_with_no_did_and_dangling_linked_account() { + ExtBuilder::default() + .with_dangling_dids(vec![(DID, None, true)]) + .build() + .execute_with(|| { + assert_noop!( + Did::delete(RawOrigin::Signed(DID).into(), 0), + did::Error::::NotFound + ); + }); +} diff --git a/runtimes/common/src/did/deletion_hooks/tests/mock.rs b/runtimes/common/src/did/deletion_hooks/tests/mock.rs index cc5fd7af8d..7dfcac11b2 100644 --- a/runtimes/common/src/did/deletion_hooks/tests/mock.rs +++ b/runtimes/common/src/did/deletion_hooks/tests/mock.rs @@ -16,7 +16,7 @@ // If you feel like getting in touch with us, you can do so at info@botlabs.org -use did::{did_details::DidVerificationKey, traits::EvaluateAll, DidVerificationKeyRelationship}; +use did::{did_details::DidVerificationKey, traits::deletion::EvaluateAll, DidVerificationKeyRelationship}; use frame_support::{ construct_runtime, dispatch::DispatchResult, @@ -170,6 +170,8 @@ impl did::DeriveDidCallAuthorizationVerificationKeyRelationship for RuntimeCall } } +pub(super) const DID: AccountId32 = AccountId32::new([100u8; 32]); + pub struct DidLifecycleHooks; impl did::traits::DidLifecycleHooks for DidLifecycleHooks { @@ -179,14 +181,14 @@ impl did::traits::DidLifecycleHooks for DidLifecycleHooks { impl did::Config for TestRuntime { type BalanceMigrationManager = (); - type BaseDeposit = ConstU64<1>; + type BaseDeposit = ConstU64<0>; type Currency = MockCurrency; type DidIdentifier = AccountId32; - type DidLifecycleHooks = (); + type DidLifecycleHooks = DidLifecycleHooks; type EnsureOrigin = EnsureSigned; - type Fee = ConstU64<1>; + type Fee = ConstU64<0>; type FeeCollector = (); - type KeyDeposit = ConstU64<1>; + type KeyDeposit = ConstU64<0>; type MaxBlocksTxValidity = ConstU64<1>; type MaxNewKeyAgreementKeys = MaxNewKeyAgreementKeys; type MaxNumberOfServicesPerDid = ConstU32<1>; @@ -202,7 +204,7 @@ impl did::Config for TestRuntime { type RuntimeEvent = (); type RuntimeHoldReason = RuntimeHoldReason; type RuntimeOrigin = RuntimeOrigin; - type ServiceEndpointDeposit = ConstU64<1>; + type ServiceEndpointDeposit = ConstU64<0>; type WeightInfo = (); } @@ -210,7 +212,7 @@ impl pallet_did_lookup::Config for TestRuntime { type AssociateOrigin = Self::EnsureOrigin; type BalanceMigrationManager = (); type Currency = MockCurrency; - type Deposit = ConstU64<1>; + type Deposit = ConstU64<0>; type DidIdentifier = AccountId32; type EnsureOrigin = EnsureSigned; type OriginSuccess = AccountId32; @@ -226,7 +228,7 @@ impl pallet_web3_names::Config for TestRuntime { type BanOrigin = EnsureRoot; type ClaimOrigin = Self::OwnerOrigin; type Currency = MockCurrency; - type Deposit = ConstU64<1>; + type Deposit = ConstU64<0>; type OriginSuccess = AccountId32; type MaxNameLength = ConstU32<1>; type MinNameLength = ConstU32<1>; @@ -241,7 +243,10 @@ impl pallet_web3_names::Config for TestRuntime { } #[derive(Default)] -pub(super) struct ExtBuilder(Vec<(AccountId32, Option, bool)>); +pub(super) struct ExtBuilder( + Vec<(AccountId32, Option, bool)>, + Vec<(AccountId32, Option, bool)>, +); impl ExtBuilder { pub(super) fn with_dids(mut self, did_links: Vec<(AccountId32, Option, bool)>) -> Self { @@ -249,6 +254,11 @@ impl ExtBuilder { self } + pub(super) fn with_dangling_dids(mut self, dangling_dids: Vec<(AccountId32, Option, bool)>) -> Self { + self.1 = dangling_dids; + self + } + pub(super) fn build(self) -> TestExternalities { let _ = env_logger::try_init(); let mut ext = TestExternalities::default(); @@ -277,6 +287,25 @@ impl ExtBuilder { .expect("Failed to link account."); } } + + for (did, maybe_web3_name, should_link_account) in self.1 { + // Cannot write the same DID as both linked and dangling. + assert!(!did::Did::::contains_key(&did)); + if maybe_web3_name.is_none() && !should_link_account { + panic!("One of web3name or linked account must be set."); + } + if let Some(web3_name) = maybe_web3_name { + Web3Names::claim( + RawOrigin::Signed(did.clone()).into(), + Vec::::from(web3_name.clone()).try_into().unwrap(), + ) + .expect("Failed to set dangling web3name."); + } + if should_link_account { + LinkedAccounts::associate_sender(RawOrigin::Signed(did.clone()).into()) + .expect("Failed to set dangling account."); + } + } }); ext From b10765614bbefb375fed461a1176cc69a065710c Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Fri, 10 Jan 2025 14:30:46 +0100 Subject: [PATCH 08/18] Fmt --- runtimes/peregrine/src/weights/rocksdb_weights.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/runtimes/peregrine/src/weights/rocksdb_weights.rs b/runtimes/peregrine/src/weights/rocksdb_weights.rs index 72bea2f97f..f267cf42d7 100644 --- a/runtimes/peregrine/src/weights/rocksdb_weights.rs +++ b/runtimes/peregrine/src/weights/rocksdb_weights.rs @@ -1,6 +1,5 @@ - -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 33.0.0 -//! DATE: 2025-01-10 (Y/M/D) +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION +//! 33.0.0 DATE: 2025-01-10 (Y/M/D) //! HOSTNAME: `rust-2`, CPU: `12th Gen Intel(R) Core(TM) i9-12900K` //! //! DATABASE: `RocksDb`, RUNTIME: `KILT Peregrine Develop` From 3b4784c72f4a368fdf70a0ac22f505689619a8ca Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Mon, 13 Jan 2025 09:13:02 +0100 Subject: [PATCH 09/18] Codebase adjustments --- pallets/did/src/lib.rs | 8 +- .../traits/lifecycle_hooks/deletion/mod.rs | 4 +- .../traits/lifecycle_hooks/deletion/tests.rs | 11 +-- .../deletion_hooks/tests/linked_account.rs | 88 ------------------- .../did/deletion_hooks/tests/linked_name.rs | 17 ---- .../src/did/deletion_hooks/tests/mock.rs | 4 +- .../src/did/deletion_hooks/tests/mod.rs | 75 +++++++++++++++- runtimes/peregrine/src/kilt/did.rs | 15 ++-- .../peregrine/src/weights/rocksdb_weights.rs | 74 ++++++++++------ runtimes/spiritnet/src/kilt/did.rs | 11 +-- 10 files changed, 146 insertions(+), 161 deletions(-) delete mode 100644 runtimes/common/src/did/deletion_hooks/tests/linked_account.rs delete mode 100644 runtimes/common/src/did/deletion_hooks/tests/linked_name.rs diff --git a/pallets/did/src/lib.rs b/pallets/did/src/lib.rs index 6f632a577d..bc937f5559 100644 --- a/pallets/did/src/lib.rs +++ b/pallets/did/src/lib.rs @@ -1525,13 +1525,13 @@ pub mod pallet { // `take` calls `kill` internally let did_entry = Did::::take(&did_subject).ok_or(Error::::NotFound)?; - let Ok(()) = + ensure!( <>::DeletionHook as DidDeletionHook>::can_delete( &did_subject, ) - else { - return Err(Error::::CannotDelete.into()); - }; + .is_ok(), + Error::::CannotDelete + ); DidEndpointsCount::::remove(&did_subject); diff --git a/pallets/did/src/traits/lifecycle_hooks/deletion/mod.rs b/pallets/did/src/traits/lifecycle_hooks/deletion/mod.rs index ea0f0052cc..8e32bde3d2 100644 --- a/pallets/did/src/traits/lifecycle_hooks/deletion/mod.rs +++ b/pallets/did/src/traits/lifecycle_hooks/deletion/mod.rs @@ -48,9 +48,9 @@ where /// Implementation of [`did::traits::DidDeletionHook`] that iterates over both /// components, bailing out early if the first one fails. -pub struct EvaluateAll(PhantomData<(A, B)>); +pub struct RequireBoth(PhantomData<(A, B)>); -impl DidDeletionHook for EvaluateAll +impl DidDeletionHook for RequireBoth where T: Config, A: DidDeletionHook, diff --git a/pallets/did/src/traits/lifecycle_hooks/deletion/tests.rs b/pallets/did/src/traits/lifecycle_hooks/deletion/tests.rs index 8d6c9b73d5..c21d4427f9 100644 --- a/pallets/did/src/traits/lifecycle_hooks/deletion/tests.rs +++ b/pallets/did/src/traits/lifecycle_hooks/deletion/tests.rs @@ -20,7 +20,7 @@ use sp_runtime::AccountId32; use sp_weights::Weight; use crate::{ - traits::lifecycle_hooks::{deletion::EvaluateAll, mock::TestRuntime, DidDeletionHook}, + traits::lifecycle_hooks::{deletion::RequireBoth, mock::TestRuntime, DidDeletionHook}, DidIdentifierOf, }; @@ -39,14 +39,14 @@ struct True; impl DidDeletionHook for True { const MAX_WEIGHT: Weight = Weight::from_all(20); - fn can_delete(did: &DidIdentifierOf) -> Result<(), Weight> { + fn can_delete(_did: &DidIdentifierOf) -> Result<(), Weight> { Ok(()) } } #[test] fn first_false() { - type TestSubject = EvaluateAll; + type TestSubject = RequireBoth; // Max weight is the sum. assert_eq!(TestSubject::MAX_WEIGHT, Weight::from_all(30)); @@ -59,7 +59,7 @@ fn first_false() { #[test] fn second_false() { - type TestSubject = EvaluateAll; + type TestSubject = RequireBoth; // Max weight is the sum. assert_eq!(TestSubject::MAX_WEIGHT, Weight::from_all(30)); @@ -72,9 +72,10 @@ fn second_false() { #[test] fn both_true() { - type TestSubject = EvaluateAll; + type TestSubject = RequireBoth; // Max weight is the sum. assert_eq!(TestSubject::MAX_WEIGHT, Weight::from_all(40)); + // Overall result is `Ok`. assert_eq!(TestSubject::can_delete(&AccountId32::new([0u8; 32])), Ok(())); } diff --git a/runtimes/common/src/did/deletion_hooks/tests/linked_account.rs b/runtimes/common/src/did/deletion_hooks/tests/linked_account.rs deleted file mode 100644 index e81090b24f..0000000000 --- a/runtimes/common/src/did/deletion_hooks/tests/linked_account.rs +++ /dev/null @@ -1,88 +0,0 @@ -// KILT Blockchain – https://botlabs.org -// Copyright (C) 2019-2024 BOTLabs GmbH - -// The KILT Blockchain 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. - -// The KILT Blockchain 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 this program. If not, see . - -// If you feel like getting in touch with us, you can do so at info@botlabs.org - -use frame_support::{assert_noop, assert_ok}; -use frame_system::RawOrigin; - -use crate::did::deletion_hooks::tests::mock::{Did, ExtBuilder, TestRuntime, DID}; - -#[test] -fn test_delete_with_no_dangling_resources() { - ExtBuilder::default() - .with_dids(vec![(DID, None, false)]) - .build() - .execute_with(|| { - assert_ok!(Did::delete(RawOrigin::Signed(DID).into(), 0)); - }); -} - -#[test] -fn test_delete_with_dangling_web3_name() { - ExtBuilder::default() - .with_dids(vec![(DID, Some(b"t".to_vec().try_into().unwrap()), false)]) - .build() - .execute_with(|| { - assert_noop!( - Did::delete(RawOrigin::Signed(DID).into(), 0), - did::Error::::CannotDelete - ); - }); -} - -#[test] -fn test_delete_with_dangling_linked_account() { - ExtBuilder::default() - .with_dids(vec![(DID, None, true)]) - .build() - .execute_with(|| { - assert_noop!( - Did::delete(RawOrigin::Signed(DID).into(), 0), - did::Error::::CannotDelete - ); - }); -} - -// If someone tries to re-delete a delete DID with dangling resources, they get -// a `NotFound` error. -#[test] -fn test_delete_with_no_did_and_dangling_web3_name() { - ExtBuilder::default() - .with_dangling_dids(vec![(DID, Some(b"t".to_vec().try_into().unwrap()), false)]) - .build() - .execute_with(|| { - assert_noop!( - Did::delete(RawOrigin::Signed(DID).into(), 0), - did::Error::::NotFound - ); - }); -} - -// If someone tries to re-delete a delete DID with dangling resources, they get -// a `NotFound` error. -#[test] -fn test_delete_with_no_did_and_dangling_linked_account() { - ExtBuilder::default() - .with_dangling_dids(vec![(DID, None, true)]) - .build() - .execute_with(|| { - assert_noop!( - Did::delete(RawOrigin::Signed(DID).into(), 0), - did::Error::::NotFound - ); - }); -} diff --git a/runtimes/common/src/did/deletion_hooks/tests/linked_name.rs b/runtimes/common/src/did/deletion_hooks/tests/linked_name.rs deleted file mode 100644 index 73b2b1a764..0000000000 --- a/runtimes/common/src/did/deletion_hooks/tests/linked_name.rs +++ /dev/null @@ -1,17 +0,0 @@ -// KILT Blockchain – https://botlabs.org -// Copyright (C) 2019-2024 BOTLabs GmbH - -// The KILT Blockchain 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. - -// The KILT Blockchain 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 this program. If not, see . - -// If you feel like getting in touch with us, you can do so at info@botlabs.org diff --git a/runtimes/common/src/did/deletion_hooks/tests/mock.rs b/runtimes/common/src/did/deletion_hooks/tests/mock.rs index 7dfcac11b2..d8d496b31b 100644 --- a/runtimes/common/src/did/deletion_hooks/tests/mock.rs +++ b/runtimes/common/src/did/deletion_hooks/tests/mock.rs @@ -16,7 +16,7 @@ // If you feel like getting in touch with us, you can do so at info@botlabs.org -use did::{did_details::DidVerificationKey, traits::deletion::EvaluateAll, DidVerificationKeyRelationship}; +use did::{did_details::DidVerificationKey, traits::deletion::RequireBoth, DidVerificationKeyRelationship}; use frame_support::{ construct_runtime, dispatch::DispatchResult, @@ -176,7 +176,7 @@ pub struct DidLifecycleHooks; impl did::traits::DidLifecycleHooks for DidLifecycleHooks { type DeletionHook = - EvaluateAll, EnsureNoLinkedAccountDeletionHook<1, 1, ()>>; + RequireBoth, EnsureNoLinkedAccountDeletionHook<1, 1, ()>>; } impl did::Config for TestRuntime { diff --git a/runtimes/common/src/did/deletion_hooks/tests/mod.rs b/runtimes/common/src/did/deletion_hooks/tests/mod.rs index 7ee25da57a..99b2b0a033 100644 --- a/runtimes/common/src/did/deletion_hooks/tests/mod.rs +++ b/runtimes/common/src/did/deletion_hooks/tests/mod.rs @@ -16,6 +16,77 @@ // If you feel like getting in touch with us, you can do so at info@botlabs.org -mod linked_account; -mod linked_name; mod mock; + +use frame_support::{assert_noop, assert_ok}; +use frame_system::RawOrigin; + +use crate::did::deletion_hooks::tests::mock::{Did, ExtBuilder, TestRuntime, DID}; + +#[test] +fn test_delete_with_no_dangling_resources() { + ExtBuilder::default() + .with_dids(vec![(DID, None, false)]) + .build() + .execute_with(|| { + assert_ok!(Did::delete(RawOrigin::Signed(DID).into(), 0)); + }); +} + +#[test] +fn test_delete_with_dangling_web3_name() { + ExtBuilder::default() + .with_dids(vec![(DID, Some(b"t".to_vec().try_into().unwrap()), false)]) + .build() + .execute_with(|| { + assert_noop!( + Did::delete(RawOrigin::Signed(DID).into(), 0), + did::Error::::CannotDelete + ); + }); +} + +#[test] +fn test_delete_with_dangling_linked_account() { + ExtBuilder::default() + .with_dids(vec![(DID, None, true)]) + .build() + .execute_with(|| { + assert_noop!( + Did::delete(RawOrigin::Signed(DID).into(), 0), + did::Error::::CannotDelete + ); + }); +} + +// If someone tries to re-delete a delete DID with dangling resources, they get +// a `NotFound` error. We are testing that we always check for DID existence +// before we check for linked resources. +#[test] +fn test_delete_with_no_did_and_dangling_web3_name() { + ExtBuilder::default() + .with_dangling_dids(vec![(DID, Some(b"t".to_vec().try_into().unwrap()), false)]) + .build() + .execute_with(|| { + assert_noop!( + Did::delete(RawOrigin::Signed(DID).into(), 0), + did::Error::::NotFound + ); + }); +} + +// If someone tries to re-delete a delete DID with dangling resources, they get +// a `NotFound` error. We are testing that we always check for DID existence +// before we check for linked resources. +#[test] +fn test_delete_with_no_did_and_dangling_linked_account() { + ExtBuilder::default() + .with_dangling_dids(vec![(DID, None, true)]) + .build() + .execute_with(|| { + assert_noop!( + Did::delete(RawOrigin::Signed(DID).into(), 0), + did::Error::::NotFound + ); + }); +} diff --git a/runtimes/peregrine/src/kilt/did.rs b/runtimes/peregrine/src/kilt/did.rs index 721532d05a..1d095045fa 100644 --- a/runtimes/peregrine/src/kilt/did.rs +++ b/runtimes/peregrine/src/kilt/did.rs @@ -17,15 +17,16 @@ // If you feel like getting in touch with us, you can do so at info@botlabs.org use did::{ - traits::EvaluateAll, DeriveDidCallAuthorizationVerificationKeyRelationship, DeriveDidCallKeyRelationshipResult, - DidRawOrigin, DidVerificationKeyRelationship, EnsureDidOrigin, RelationshipDeriveError, + traits::deletion::RequireBoth, DeriveDidCallAuthorizationVerificationKeyRelationship, + DeriveDidCallKeyRelationshipResult, DidRawOrigin, DidVerificationKeyRelationship, EnsureDidOrigin, + RelationshipDeriveError, }; use frame_system::EnsureRoot; use runtime_common::{ constants, - did::EnsureNoLinkedAccountDeletionHook, dot_names::{AllowedDotNameClaimer, AllowedUniqueLinkingAssociator}, - AccountId, DidIdentifier, EnsureNoLinkedWeb3NameDeletionHook, SendDustAndFeesToTreasury, + AccountId, DidIdentifier, EnsureNoLinkedAccountDeletionHook, EnsureNoLinkedWeb3NameDeletionHook, + SendDustAndFeesToTreasury, }; use sp_core::ConstBool; @@ -96,16 +97,16 @@ impl did::traits::DidLifecycleHooks for DidLifecycleHooks { type EnsureNoWeb3NameOnDeletion = EnsureNoLinkedWeb3NameDeletionHook<{ RocksDbWeight::get().read }, 0, ()>; type EnsureNoDotNameOnDeletion = EnsureNoLinkedWeb3NameDeletionHook<{ RocksDbWeight::get().read }, 0, DotNamesDeployment>; -type EnsureNoUsernamesOnDeletion = EvaluateAll; +type EnsureNoUsernamesOnDeletion = RequireBoth; type EnsureNoWeb3NameLinkedAccountsOnDeletion = EnsureNoLinkedAccountDeletionHook<{ RocksDbWeight::get().read }, 0, ()>; type EnsureNoDotNameLinkedAccountOnDeletion = EnsureNoLinkedWeb3NameDeletionHook<{ RocksDbWeight::get().read }, 0, UniqueLinkingDeployment>; type EnsureNoLinkedAccountsOnDeletion = - EvaluateAll; + RequireBoth; pub type EnsureNoNamesAndNoLinkedAccountsOnDidDeletion = - EvaluateAll; + RequireBoth; impl did::Config for Runtime { type RuntimeEvent = RuntimeEvent; diff --git a/runtimes/peregrine/src/weights/rocksdb_weights.rs b/runtimes/peregrine/src/weights/rocksdb_weights.rs index f267cf42d7..1a51549073 100644 --- a/runtimes/peregrine/src/weights/rocksdb_weights.rs +++ b/runtimes/peregrine/src/weights/rocksdb_weights.rs @@ -1,29 +1,45 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2024 BOTLabs GmbH + +// The KILT Blockchain 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. + +// The KILT Blockchain 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 this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION -//! 33.0.0 DATE: 2025-01-10 (Y/M/D) -//! HOSTNAME: `rust-2`, CPU: `12th Gen Intel(R) Core(TM) i9-12900K` +//! 4.0.0-dev DATE: 2024-03-29 (Y/M/D) +//! HOSTNAME: `eyrie-7`, CPU: `Intel(R) Core(TM) i7-7700 CPU @ 3.60GHz` //! -//! DATABASE: `RocksDb`, RUNTIME: `KILT Peregrine Develop` -//! BLOCK-NUM: `BlockId::Number(0)` +//! DATABASE: `RocksDb`, RUNTIME: `KILT Spiritnet` +//! BLOCK-NUM: `BlockId::Number(3460187)` //! SKIP-WRITE: `false`, SKIP-READ: `false`, WARMUPS: `1` //! STATE-VERSION: `V1`, STATE-CACHE-SIZE: `` -//! WEIGHT-PATH: `runtimes/peregrine/src/weights/rocksdb_weights.rs` +//! WEIGHT-PATH: `runtimes/spiritnet/src/weights/rocksdb_weights.rs` //! METRIC: `Average`, WEIGHT-MUL: `1.1`, WEIGHT-ADD: `0` // Executed Command: -// target/debug/kilt-parachain +// target/release/kilt-parachain // benchmark // storage -// --chain -// dev -// --template-path -// .maintain/weight-db-template.hbs +// --chain=spiritnet +// --base-path=/home/bird/spiritnet-db/ +// --template-path=.maintain/weight-db-template.hbs // --state-version // 1 -// --weight-path -// runtimes/peregrine/src/weights/rocksdb_weights.rs +// --weight-path=runtimes/spiritnet/src/weights/rocksdb_weights.rs // --mul=1.1 -/// Storage DB weights for the `KILT Peregrine Develop` runtime and `RocksDb`. +/// Storage DB weights for the `KILT Spiritnet` runtime and `RocksDb`. pub mod constants { use frame_support::weights::constants; use sp_core::parameter_types; @@ -37,31 +53,31 @@ pub mod constants { /// Calculated by multiplying the *Average* of all values with `1.1` and adding `0`. /// /// Stats nanoseconds: - /// Min, Max: 15_180, 14_278_535 - /// Average: 169_414 - /// Median: 20_103 - /// Std-Dev: 1447573.56 + /// Min, Max: 5_380, 11_860_691 + /// Average: 32_804 + /// Median: 23_288 + /// Std-Dev: 55265.31 /// /// Percentiles nanoseconds: - /// 99th: 14_278_535 - /// 95th: 27_260 - /// 75th: 23_057 - read: 186_356 * constants::WEIGHT_REF_TIME_PER_NANOS, + /// 99th: 278_383 + /// 95th: 57_425 + /// 75th: 30_265 + read: 36_085 * constants::WEIGHT_REF_TIME_PER_NANOS, /// Time to write one storage item. /// Calculated by multiplying the *Average* of all values with `1.1` and adding `0`. /// /// Stats nanoseconds: - /// Min, Max: 41_658, 708_109_449 - /// Average: 7_511_596 - /// Median: 129_472 - /// Std-Dev: 71879832.74 + /// Min, Max: 19_775, 13_936_221 + /// Average: 74_821 + /// Median: 72_516 + /// Std-Dev: 66500.91 /// /// Percentiles nanoseconds: - /// 99th: 708_109_449 - /// 95th: 190_014 - /// 75th: 155_799 - write: 8_262_756 * constants::WEIGHT_REF_TIME_PER_NANOS, + /// 99th: 113_045 + /// 95th: 95_002 + /// 75th: 81_339 + write: 82_304 * constants::WEIGHT_REF_TIME_PER_NANOS, }; } diff --git a/runtimes/spiritnet/src/kilt/did.rs b/runtimes/spiritnet/src/kilt/did.rs index 721532d05a..9f4796010a 100644 --- a/runtimes/spiritnet/src/kilt/did.rs +++ b/runtimes/spiritnet/src/kilt/did.rs @@ -17,8 +17,9 @@ // If you feel like getting in touch with us, you can do so at info@botlabs.org use did::{ - traits::EvaluateAll, DeriveDidCallAuthorizationVerificationKeyRelationship, DeriveDidCallKeyRelationshipResult, - DidRawOrigin, DidVerificationKeyRelationship, EnsureDidOrigin, RelationshipDeriveError, + traits::deletion::RequireBoth, DeriveDidCallAuthorizationVerificationKeyRelationship, + DeriveDidCallKeyRelationshipResult, DidRawOrigin, DidVerificationKeyRelationship, EnsureDidOrigin, + RelationshipDeriveError, }; use frame_system::EnsureRoot; use runtime_common::{ @@ -96,16 +97,16 @@ impl did::traits::DidLifecycleHooks for DidLifecycleHooks { type EnsureNoWeb3NameOnDeletion = EnsureNoLinkedWeb3NameDeletionHook<{ RocksDbWeight::get().read }, 0, ()>; type EnsureNoDotNameOnDeletion = EnsureNoLinkedWeb3NameDeletionHook<{ RocksDbWeight::get().read }, 0, DotNamesDeployment>; -type EnsureNoUsernamesOnDeletion = EvaluateAll; +type EnsureNoUsernamesOnDeletion = RequireBoth; type EnsureNoWeb3NameLinkedAccountsOnDeletion = EnsureNoLinkedAccountDeletionHook<{ RocksDbWeight::get().read }, 0, ()>; type EnsureNoDotNameLinkedAccountOnDeletion = EnsureNoLinkedWeb3NameDeletionHook<{ RocksDbWeight::get().read }, 0, UniqueLinkingDeployment>; type EnsureNoLinkedAccountsOnDeletion = - EvaluateAll; + RequireBoth; pub type EnsureNoNamesAndNoLinkedAccountsOnDidDeletion = - EvaluateAll; + RequireBoth; impl did::Config for Runtime { type RuntimeEvent = RuntimeEvent; From 6df985ef0b3463b0f1478658c1b7c56ca7d6174c Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Mon, 13 Jan 2025 09:37:40 +0100 Subject: [PATCH 10/18] Move MockCurrency to its own module --- Cargo.lock | 1 + dip-template/runtimes/dip-provider/src/lib.rs | 1 + .../did/src/traits/lifecycle_hooks/mock.rs | 90 +------------- pallets/pallet-asset-switch/Cargo.toml | 1 + .../src/xcm/trade/xcm_fee_asset/mock.rs | 69 +---------- .../src/xcm/transfer/mock.rs | 66 +--------- pallets/pallet-migration/src/mock.rs | 1 + .../src/did/deletion_hooks/tests/mock.rs | 94 +------------- runtimes/kestrel/src/lib.rs | 1 + support/src/test_utils.rs | 116 +++++++++++++++++- 10 files changed, 137 insertions(+), 303 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5bcdfc8cad..865b768a5f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6917,6 +6917,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", + "kilt-support", "log", "pallet-balances", "parity-scale-codec", diff --git a/dip-template/runtimes/dip-provider/src/lib.rs b/dip-template/runtimes/dip-provider/src/lib.rs index c471152d64..15e2596d1d 100644 --- a/dip-template/runtimes/dip-provider/src/lib.rs +++ b/dip-template/runtimes/dip-provider/src/lib.rs @@ -401,6 +401,7 @@ impl did::Config for Runtime { type BaseDeposit = ConstU128; type Currency = Balances; type DidIdentifier = DidIdentifier; + type DidLifecycleHooks = (); type EnsureOrigin = EnsureDidOrigin; type Fee = ConstU128; type FeeCollector = (); diff --git a/pallets/did/src/traits/lifecycle_hooks/mock.rs b/pallets/did/src/traits/lifecycle_hooks/mock.rs index 5659f1eae6..f7ea154934 100644 --- a/pallets/did/src/traits/lifecycle_hooks/mock.rs +++ b/pallets/did/src/traits/lifecycle_hooks/mock.rs @@ -16,22 +16,15 @@ // If you feel like getting in touch with us, you can do so at info@botlabs.org -use frame_support::{ - construct_runtime, - dispatch::DispatchResult, - parameter_types, - traits::{ - fungible::{Balanced, Dust, Inspect, InspectHold, Mutate, MutateHold, Unbalanced, UnbalancedHold}, - tokens::{DepositConsequence, Fortitude, Preservation, Provenance, WithdrawConsequence}, - }, -}; +use frame_support::{construct_runtime, parameter_types}; use frame_system::{mocking::MockBlock, EnsureSigned}; +use kilt_support::test_utils::MockCurrency; use parity_scale_codec::{Decode, Encode}; use scale_info::TypeInfo; use sp_core::{ConstU32, ConstU64, H256}; use sp_runtime::{ traits::{BlakeTwo256, IdentityLookup}, - AccountId32, DispatchError, + AccountId32, }; use crate::{ @@ -74,81 +67,6 @@ impl frame_system::Config for TestRuntime { type Version = (); } -pub struct MockCurrency; - -impl MutateHold for MockCurrency {} - -impl UnbalancedHold for MockCurrency { - fn set_balance_on_hold(_reason: &Self::Reason, _who: &AccountId32, _amount: Self::Balance) -> DispatchResult { - Ok(()) - } -} - -impl InspectHold for MockCurrency { - type Reason = RuntimeHoldReason; - - fn total_balance_on_hold(_who: &AccountId32) -> Self::Balance { - Self::Balance::default() - } - - fn balance_on_hold(_reason: &Self::Reason, _who: &AccountId32) -> Self::Balance { - Self::Balance::default() - } -} - -impl Mutate for MockCurrency {} - -impl Inspect for MockCurrency { - type Balance = u64; - - fn active_issuance() -> Self::Balance { - Self::Balance::default() - } - - fn balance(_who: &AccountId32) -> Self::Balance { - Self::Balance::default() - } - - fn can_deposit(_who: &AccountId32, _amount: Self::Balance, _provenance: Provenance) -> DepositConsequence { - DepositConsequence::Success - } - - fn can_withdraw(_who: &AccountId32, _amount: Self::Balance) -> WithdrawConsequence { - WithdrawConsequence::Success - } - - fn minimum_balance() -> Self::Balance { - Self::Balance::default() - } - - fn reducible_balance(_who: &AccountId32, _preservation: Preservation, _force: Fortitude) -> Self::Balance { - Self::Balance::default() - } - - fn total_balance(_who: &AccountId32) -> Self::Balance { - Self::Balance::default() - } - - fn total_issuance() -> Self::Balance { - Self::Balance::default() - } -} - -impl Unbalanced for MockCurrency { - fn handle_dust(_dust: Dust) {} - - fn write_balance(_who: &AccountId32, _amount: Self::Balance) -> Result, DispatchError> { - Ok(Some(Self::Balance::default())) - } - - fn set_total_issuance(_amount: Self::Balance) {} -} - -impl Balanced for MockCurrency { - type OnDropDebt = (); - type OnDropCredit = (); -} - parameter_types! { #[derive(TypeInfo, Debug, PartialEq, Eq, Clone, Encode, Decode)] pub const MaxNewKeyAgreementKeys: u32 = 1; @@ -172,7 +90,7 @@ impl DeriveDidCallAuthorizationVerificationKeyRelationship for RuntimeCall { impl Config for TestRuntime { type BalanceMigrationManager = (); type BaseDeposit = ConstU64<1>; - type Currency = MockCurrency; + type Currency = MockCurrency; type DidIdentifier = AccountId32; type DidLifecycleHooks = (); type EnsureOrigin = EnsureSigned; diff --git a/pallets/pallet-asset-switch/Cargo.toml b/pallets/pallet-asset-switch/Cargo.toml index ace29bacf2..b0a2e8501d 100644 --- a/pallets/pallet-asset-switch/Cargo.toml +++ b/pallets/pallet-asset-switch/Cargo.toml @@ -15,6 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dev-dependencies] env_logger = { workspace = true } +kilt-support = { workspace = true, features = ["std"] } pallet-balances = { workspace = true, features = ["std"] } sp-keystore = { workspace = true } diff --git a/pallets/pallet-asset-switch/src/xcm/trade/xcm_fee_asset/mock.rs b/pallets/pallet-asset-switch/src/xcm/trade/xcm_fee_asset/mock.rs index 3054b0bf52..8cbb9f6cdf 100644 --- a/pallets/pallet-asset-switch/src/xcm/trade/xcm_fee_asset/mock.rs +++ b/pallets/pallet-asset-switch/src/xcm/trade/xcm_fee_asset/mock.rs @@ -16,22 +16,13 @@ // If you feel like getting in touch with us, you can do so at info@botlabs.org -use frame_support::{ - construct_runtime, parameter_types, - traits::{ - fungible::Dust, - tokens::{ - fungible::{Inspect as InspectFungible, Mutate as MutateFungible, Unbalanced as UnbalancedFungible}, - DepositConsequence, Fortitude, Preservation, Provenance, WithdrawConsequence, - }, - Everything, - }, -}; +use frame_support::{construct_runtime, parameter_types, traits::Everything}; use frame_system::{mocking::MockBlock, EnsureRoot, EnsureSigned}; +use kilt_support::test_utils::MockCurrency; use sp_core::{ConstU16, ConstU32, ConstU64, H256}; use sp_runtime::{ traits::{BlakeTwo256, IdentityLookup}, - AccountId32, DispatchError, + AccountId32, }; use xcm::v4::{InteriorLocation, Junctions::Here}; @@ -71,58 +62,6 @@ impl frame_system::Config for MockRuntime { type Version = (); } -// Currency is not used in this XCM component tests, so we mock the entire -// currency system. -pub struct MockCurrency; - -impl MutateFungible for MockCurrency {} - -impl InspectFungible for MockCurrency { - type Balance = u64; - - fn active_issuance() -> Self::Balance { - Self::Balance::default() - } - - fn balance(_who: &AccountId32) -> Self::Balance { - Self::Balance::default() - } - - fn can_deposit(_who: &AccountId32, _amount: Self::Balance, _provenance: Provenance) -> DepositConsequence { - DepositConsequence::Success - } - - fn can_withdraw(_who: &AccountId32, _amount: Self::Balance) -> WithdrawConsequence { - WithdrawConsequence::Success - } - - fn minimum_balance() -> Self::Balance { - Self::Balance::default() - } - - fn reducible_balance(_who: &AccountId32, _preservation: Preservation, _force: Fortitude) -> Self::Balance { - Self::Balance::default() - } - - fn total_balance(_who: &AccountId32) -> Self::Balance { - Self::Balance::default() - } - - fn total_issuance() -> Self::Balance { - Self::Balance::default() - } -} - -impl UnbalancedFungible for MockCurrency { - fn handle_dust(_dust: Dust) {} - - fn write_balance(_who: &AccountId32, _amount: Self::Balance) -> Result, DispatchError> { - Ok(Some(Self::Balance::default())) - } - - fn set_total_issuance(_amount: Self::Balance) {} -} - parameter_types! { pub const UniversalLocation: InteriorLocation = Here; } @@ -131,7 +70,7 @@ impl crate::Config for MockRuntime { type AccountIdConverter = (); type AssetTransactor = (); type FeeOrigin = EnsureRoot; - type LocalCurrency = MockCurrency; + type LocalCurrency = MockCurrency; type PauseOrigin = EnsureRoot; type RuntimeEvent = RuntimeEvent; type SubmitterOrigin = EnsureSigned; diff --git a/pallets/pallet-asset-switch/src/xcm/transfer/mock.rs b/pallets/pallet-asset-switch/src/xcm/transfer/mock.rs index 22101e6882..1e43deb732 100644 --- a/pallets/pallet-asset-switch/src/xcm/transfer/mock.rs +++ b/pallets/pallet-asset-switch/src/xcm/transfer/mock.rs @@ -16,20 +16,14 @@ // If you feel like getting in touch with us, you can do so at info@botlabs.org -use frame_support::{ - construct_runtime, parameter_types, - traits::{ - fungible::{Dust, Inspect as InspectFungible, Mutate as MutateFungible, Unbalanced as UnbalancedFungible}, - tokens::{DepositConsequence, Fortitude, Preservation, Provenance, WithdrawConsequence}, - Everything, - }, -}; +use frame_support::{construct_runtime, parameter_types, traits::Everything}; use frame_system::{mocking::MockBlock, EnsureRoot, EnsureSigned}; +use kilt_support::test_utils::MockCurrency; use pallet_balances::AccountData; use sp_core::{ConstU16, ConstU32, ConstU64, H256}; use sp_runtime::{ traits::{BlakeTwo256, IdentityLookup}, - AccountId32, DispatchError, + AccountId32, }; use xcm::v4::{InteriorLocation, Junctions::Here}; @@ -69,58 +63,6 @@ impl frame_system::Config for MockRuntime { type Version = (); } -// Currency is not used in this XCM component tests, so we mock the entire -// currency system. -pub struct MockCurrency; - -impl MutateFungible for MockCurrency {} - -impl InspectFungible for MockCurrency { - type Balance = u64; - - fn active_issuance() -> Self::Balance { - Self::Balance::default() - } - - fn balance(_who: &AccountId32) -> Self::Balance { - Self::Balance::default() - } - - fn can_deposit(_who: &AccountId32, _amount: Self::Balance, _provenance: Provenance) -> DepositConsequence { - DepositConsequence::Success - } - - fn can_withdraw(_who: &AccountId32, _amount: Self::Balance) -> WithdrawConsequence { - WithdrawConsequence::Success - } - - fn minimum_balance() -> Self::Balance { - Self::Balance::default() - } - - fn reducible_balance(_who: &AccountId32, _preservation: Preservation, _force: Fortitude) -> Self::Balance { - Self::Balance::default() - } - - fn total_balance(_who: &AccountId32) -> Self::Balance { - Self::Balance::default() - } - - fn total_issuance() -> Self::Balance { - Self::Balance::default() - } -} - -impl UnbalancedFungible for MockCurrency { - fn handle_dust(_dust: Dust) {} - - fn write_balance(_who: &AccountId32, _amount: Self::Balance) -> Result, DispatchError> { - Ok(Some(Self::Balance::default())) - } - - fn set_total_issuance(_amount: Self::Balance) {} -} - parameter_types! { pub const UniversalLocation: InteriorLocation = Here; } @@ -129,7 +71,7 @@ impl crate::Config for MockRuntime { type AccountIdConverter = (); type AssetTransactor = (); type FeeOrigin = EnsureRoot; - type LocalCurrency = MockCurrency; + type LocalCurrency = MockCurrency; type PauseOrigin = EnsureRoot; type RuntimeEvent = RuntimeEvent; type SubmitterOrigin = EnsureSigned; diff --git a/pallets/pallet-migration/src/mock.rs b/pallets/pallet-migration/src/mock.rs index 7e658653be..28bad00579 100644 --- a/pallets/pallet-migration/src/mock.rs +++ b/pallets/pallet-migration/src/mock.rs @@ -272,6 +272,7 @@ impl did::Config for Test { type MaxNumberOfTypesPerService = MaxNumberOfTypesPerService; type MaxNumberOfUrlsPerService = MaxNumberOfUrlsPerService; type BalanceMigrationManager = Migration; + type DidLifecycleHooks = (); } parameter_types! { diff --git a/runtimes/common/src/did/deletion_hooks/tests/mock.rs b/runtimes/common/src/did/deletion_hooks/tests/mock.rs index d8d496b31b..e70ff17022 100644 --- a/runtimes/common/src/did/deletion_hooks/tests/mock.rs +++ b/runtimes/common/src/did/deletion_hooks/tests/mock.rs @@ -17,23 +17,16 @@ // If you feel like getting in touch with us, you can do so at info@botlabs.org use did::{did_details::DidVerificationKey, traits::deletion::RequireBoth, DidVerificationKeyRelationship}; -use frame_support::{ - construct_runtime, - dispatch::DispatchResult, - parameter_types, - traits::{ - fungible::{Balanced, Dust, Inspect, InspectHold, Mutate, MutateHold, Unbalanced, UnbalancedHold}, - tokens::{DepositConsequence, Fortitude, Preservation, Provenance, WithdrawConsequence}, - }, -}; +use frame_support::{construct_runtime, parameter_types}; use frame_system::{mocking::MockBlock, EnsureRoot, EnsureSigned, RawOrigin}; +use kilt_support::test_utils::MockCurrency; use parity_scale_codec::{Decode, Encode}; use scale_info::TypeInfo; use sp_core::{ConstBool, ConstU32, ConstU64, H256}; use sp_io::TestExternalities; use sp_runtime::{ traits::{BlakeTwo256, IdentityLookup}, - AccountId32, DispatchError, + AccountId32, }; use crate::{EnsureNoLinkedAccountDeletionHook, EnsureNoLinkedWeb3NameDeletionHook}; @@ -75,81 +68,6 @@ impl frame_system::Config for TestRuntime { type Version = (); } -pub struct MockCurrency; - -impl MutateHold for MockCurrency {} - -impl UnbalancedHold for MockCurrency { - fn set_balance_on_hold(_reason: &Self::Reason, _who: &AccountId32, _amount: Self::Balance) -> DispatchResult { - Ok(()) - } -} - -impl InspectHold for MockCurrency { - type Reason = RuntimeHoldReason; - - fn total_balance_on_hold(_who: &AccountId32) -> Self::Balance { - Self::Balance::default() - } - - fn balance_on_hold(_reason: &Self::Reason, _who: &AccountId32) -> Self::Balance { - Self::Balance::default() - } -} - -impl Mutate for MockCurrency {} - -impl Inspect for MockCurrency { - type Balance = u64; - - fn active_issuance() -> Self::Balance { - Self::Balance::default() - } - - fn balance(_who: &AccountId32) -> Self::Balance { - Self::Balance::default() - } - - fn can_deposit(_who: &AccountId32, _amount: Self::Balance, _provenance: Provenance) -> DepositConsequence { - DepositConsequence::Success - } - - fn can_withdraw(_who: &AccountId32, _amount: Self::Balance) -> WithdrawConsequence { - WithdrawConsequence::Success - } - - fn minimum_balance() -> Self::Balance { - Self::Balance::default() - } - - fn reducible_balance(_who: &AccountId32, _preservation: Preservation, _force: Fortitude) -> Self::Balance { - Self::Balance::default() - } - - fn total_balance(_who: &AccountId32) -> Self::Balance { - Self::Balance::default() - } - - fn total_issuance() -> Self::Balance { - Self::Balance::default() - } -} - -impl Unbalanced for MockCurrency { - fn handle_dust(_dust: Dust) {} - - fn write_balance(_who: &AccountId32, _amount: Self::Balance) -> Result, DispatchError> { - Ok(Some(Self::Balance::default())) - } - - fn set_total_issuance(_amount: Self::Balance) {} -} - -impl Balanced for MockCurrency { - type OnDropDebt = (); - type OnDropCredit = (); -} - parameter_types! { #[derive(TypeInfo, Debug, PartialEq, Eq, Clone, Encode, Decode)] pub const MaxNewKeyAgreementKeys: u32 = 1; @@ -182,7 +100,7 @@ impl did::traits::DidLifecycleHooks for DidLifecycleHooks { impl did::Config for TestRuntime { type BalanceMigrationManager = (); type BaseDeposit = ConstU64<0>; - type Currency = MockCurrency; + type Currency = MockCurrency; type DidIdentifier = AccountId32; type DidLifecycleHooks = DidLifecycleHooks; type EnsureOrigin = EnsureSigned; @@ -211,7 +129,7 @@ impl did::Config for TestRuntime { impl pallet_did_lookup::Config for TestRuntime { type AssociateOrigin = Self::EnsureOrigin; type BalanceMigrationManager = (); - type Currency = MockCurrency; + type Currency = MockCurrency; type Deposit = ConstU64<0>; type DidIdentifier = AccountId32; type EnsureOrigin = EnsureSigned; @@ -227,7 +145,7 @@ impl pallet_web3_names::Config for TestRuntime { type BalanceMigrationManager = (); type BanOrigin = EnsureRoot; type ClaimOrigin = Self::OwnerOrigin; - type Currency = MockCurrency; + type Currency = MockCurrency; type Deposit = ConstU64<0>; type OriginSuccess = AccountId32; type MaxNameLength = ConstU32<1>; diff --git a/runtimes/kestrel/src/lib.rs b/runtimes/kestrel/src/lib.rs index 8c6ec5a26e..f3122b84b5 100644 --- a/runtimes/kestrel/src/lib.rs +++ b/runtimes/kestrel/src/lib.rs @@ -423,6 +423,7 @@ impl did::Config for Runtime { type MaxNumberOfUrlsPerService = MaxNumberOfUrlsPerService; type WeightInfo = (); type BalanceMigrationManager = (); + type DidLifecycleHooks = (); } impl pallet_did_lookup::Config for Runtime { diff --git a/support/src/test_utils.rs b/support/src/test_utils.rs index 49418b7f3f..4640b03360 100644 --- a/support/src/test_utils.rs +++ b/support/src/test_utils.rs @@ -16,11 +16,123 @@ // If you feel like getting in touch with us, you can do so at info@botlabs.org -use scale_info::prelude::string::String; -use sp_runtime::TryRuntimeError; +use frame_support::traits::{ + fungible::{Balanced, Dust, Inspect, InspectHold, Mutate, MutateHold, Unbalanced, UnbalancedHold}, + tokens::{Balance as BalanceT, DepositConsequence, Fortitude, Preservation, Provenance, WithdrawConsequence}, +}; +use parity_scale_codec::Encode; +use scale_info::{prelude::string::String, TypeInfo}; +use sp_runtime::{DispatchError, DispatchResult, TryRuntimeError}; +use sp_std::marker::PhantomData; /// Logs the error message and returns "Sanity test error" pub fn log_and_return_error_message(error_message: String) -> TryRuntimeError { log::error!("{}", error_message); TryRuntimeError::Other("Test") } + +// Mock currency that implements all required traits, allowing test runtimes to +// not include the actual `pallet_balances` pallet. This mock currency is useful +// for mocks in which a `Currency` is required but not relevant for the goal of +// the tests. +pub struct MockCurrency(PhantomData<(Balance, RuntimeHoldReason)>); + +impl MutateHold for MockCurrency +where + Balance: BalanceT, + RuntimeHoldReason: Encode + TypeInfo + 'static, +{ +} + +impl UnbalancedHold for MockCurrency +where + Balance: BalanceT, + RuntimeHoldReason: Encode + TypeInfo + 'static, +{ + fn set_balance_on_hold(_reason: &Self::Reason, _who: &AccountId, _amount: Self::Balance) -> DispatchResult { + Ok(()) + } +} + +impl InspectHold for MockCurrency +where + Balance: BalanceT, + RuntimeHoldReason: Encode + TypeInfo + 'static, +{ + type Reason = RuntimeHoldReason; + + fn total_balance_on_hold(_who: &AccountId) -> Self::Balance { + Self::Balance::default() + } + + fn balance_on_hold(_reason: &Self::Reason, _who: &AccountId) -> Self::Balance { + Self::Balance::default() + } +} + +impl Mutate for MockCurrency +where + AccountId: Eq, + Balance: BalanceT, +{ +} + +impl Inspect for MockCurrency +where + Balance: BalanceT, +{ + type Balance = Balance; + + fn active_issuance() -> Self::Balance { + Self::Balance::default() + } + + fn balance(_who: &AccountId) -> Self::Balance { + Self::Balance::default() + } + + fn can_deposit(_who: &AccountId, _amount: Self::Balance, _provenance: Provenance) -> DepositConsequence { + DepositConsequence::Success + } + + fn can_withdraw(_who: &AccountId, _amount: Self::Balance) -> WithdrawConsequence { + WithdrawConsequence::Success + } + + fn minimum_balance() -> Self::Balance { + Self::Balance::default() + } + + fn reducible_balance(_who: &AccountId, _preservation: Preservation, _force: Fortitude) -> Self::Balance { + Self::Balance::default() + } + + fn total_balance(_who: &AccountId) -> Self::Balance { + Self::Balance::default() + } + + fn total_issuance() -> Self::Balance { + Self::Balance::default() + } +} + +impl Unbalanced for MockCurrency +where + Balance: BalanceT, +{ + fn handle_dust(_dust: Dust) {} + + fn write_balance(_who: &AccountId, _amount: Self::Balance) -> Result, DispatchError> { + Ok(Some(Self::Balance::default())) + } + + fn set_total_issuance(_amount: Self::Balance) {} +} + +impl Balanced for MockCurrency +where + Balance: BalanceT, +{ + type OnDropDebt = (); + type OnDropCredit = (); +} From cd3e9acddaa194296210cc5f9748aab64ed561a4 Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Mon, 13 Jan 2025 09:58:02 +0100 Subject: [PATCH 11/18] Last changes --- pallets/did/src/lib.rs | 9 +++++++-- .../traits/lifecycle_hooks/deletion/mod.rs | 19 +++++++++++++------ .../traits/lifecycle_hooks/deletion/tests.rs | 3 +++ pallets/did/src/traits/lifecycle_hooks/mod.rs | 2 ++ runtimes/common/src/did/deletion_hooks/mod.rs | 10 ++++++++++ runtimes/kestrel/src/lib.rs | 1 + runtimes/peregrine/src/kilt/did.rs | 7 +++++++ runtimes/spiritnet/src/kilt/did.rs | 7 +++++++ 8 files changed, 50 insertions(+), 8 deletions(-) diff --git a/pallets/did/src/lib.rs b/pallets/did/src/lib.rs index bc937f5559..913847d719 100644 --- a/pallets/did/src/lib.rs +++ b/pallets/did/src/lib.rs @@ -331,6 +331,8 @@ pub mod pallet { /// Migration manager to handle new created entries type BalanceMigrationManager: BalanceMigrationManager, BalanceOf>; + /// Runtime-injected logic to be called at each stage of a DID's + /// lifecycle. type DidLifecycleHooks: DidLifecycleHooks; } @@ -459,8 +461,8 @@ pub mod pallet { /// The number of service endpoints stored under the DID is larger than /// the number of endpoints to delete. MaxStoredEndpointsCountExceeded, - /// The DID cannot be deleted because other resources are depending on - /// it. + /// The DID cannot be deleted because the runtime logic returned an + /// error. CannotDelete, /// An error that is not supposed to take place, yet it happened. Internal, @@ -1525,6 +1527,9 @@ pub mod pallet { // `take` calls `kill` internally let did_entry = Did::::take(&did_subject).ok_or(Error::::NotFound)?; + // Make sure this check happens after the line where we check if a DID exists, + // else we would start getting `CannotDelete` errors when we should be getting + // `NotFound`. ensure!( <>::DeletionHook as DidDeletionHook>::can_delete( &did_subject, diff --git a/pallets/did/src/traits/lifecycle_hooks/deletion/mod.rs b/pallets/did/src/traits/lifecycle_hooks/deletion/mod.rs index 8e32bde3d2..c872be2e11 100644 --- a/pallets/did/src/traits/lifecycle_hooks/deletion/mod.rs +++ b/pallets/did/src/traits/lifecycle_hooks/deletion/mod.rs @@ -24,14 +24,18 @@ use sp_weights::Weight; use crate::{Config, DidIdentifierOf}; +/// Runtime logic evaluated by the DID pallet upon deleting an existing DID. pub trait DidDeletionHook where T: Config, { + /// The statically computed maximum weight the implementation will consume + /// to verify if a DID can be deleted. const MAX_WEIGHT: Weight; - // Return `Ok(())` consuming `MAX_WEIGHT` if the DID can be deleted, or - // `Err(Weight)` with the consumed weight if not. + /// Return whether the DID can be deleted (`Ok(())`), or not. In case of + /// error, the consumed weight (less than or equal to `MAX_WEIGHT`) is + /// returned. fn can_delete(did: &DidIdentifierOf) -> Result<(), Weight>; } @@ -47,7 +51,8 @@ where } /// Implementation of [`did::traits::DidDeletionHook`] that iterates over both -/// components, bailing out early if the first one fails. +/// components, bailing out early if the first one fails. The `MAX_WEIGHT` is +/// the sum of both components. pub struct RequireBoth(PhantomData<(A, B)>); impl DidDeletionHook for RequireBoth @@ -58,11 +63,13 @@ where { const MAX_WEIGHT: Weight = A::MAX_WEIGHT.saturating_add(B::MAX_WEIGHT); + /// In case of failure, the returned weight is either the weight consumed by + /// the first component, or the sum of the first component's maximum weight + /// and the weight consumed by the second component. fn can_delete(did: &DidIdentifierOf) -> Result<(), Weight> { - // If A fails, return the weight consumed by A. - // If A succeeds and B fails, return A's max weight + B consumed weight. - // Else, return Ok. + // Bail out early with A's weight if A fails. A::can_delete(did)?; + // Bail out early with A's max weight + B's if B fails. B::can_delete(did).map_err(|consumed_weight| A::MAX_WEIGHT.saturating_add(consumed_weight))?; Ok(()) } diff --git a/pallets/did/src/traits/lifecycle_hooks/deletion/tests.rs b/pallets/did/src/traits/lifecycle_hooks/deletion/tests.rs index c21d4427f9..b2d2b42b67 100644 --- a/pallets/did/src/traits/lifecycle_hooks/deletion/tests.rs +++ b/pallets/did/src/traits/lifecycle_hooks/deletion/tests.rs @@ -16,6 +16,9 @@ // If you feel like getting in touch with us, you can do so at info@botlabs.org +//! Test module for the `RequireBoth` type. It verifies that the type works as +//! expected in case of failure of one of its components. + use sp_runtime::AccountId32; use sp_weights::Weight; diff --git a/pallets/did/src/traits/lifecycle_hooks/mod.rs b/pallets/did/src/traits/lifecycle_hooks/mod.rs index f62e7f2cc4..d6da3547ac 100644 --- a/pallets/did/src/traits/lifecycle_hooks/mod.rs +++ b/pallets/did/src/traits/lifecycle_hooks/mod.rs @@ -26,10 +26,12 @@ mod mock; use crate::Config; +/// A collection of hooks invoked during DID operations. pub trait DidLifecycleHooks where T: Config, { + /// Hook called when a DID deletion is requested by an authorized entity. type DeletionHook: DidDeletionHook; } diff --git a/runtimes/common/src/did/deletion_hooks/mod.rs b/runtimes/common/src/did/deletion_hooks/mod.rs index ba762f8ac7..9c1d515fa1 100644 --- a/runtimes/common/src/did/deletion_hooks/mod.rs +++ b/runtimes/common/src/did/deletion_hooks/mod.rs @@ -24,6 +24,11 @@ use sp_std::marker::PhantomData; use sp_weights::Weight; +/// Implementation of the [`did::traits::DidDeletionHook`] trait that makes sure +/// there is no resource linked to the DID in the provided web3name pallet +/// deployment. +/// +/// The returned worst-case weight is the same weight provided to this type. pub struct EnsureNoLinkedWeb3NameDeletionHook< const READ_WEIGHT_TIME: u64, const READ_WEIGHT_SIZE: u64, @@ -47,6 +52,11 @@ where } } +/// Implementation of the [`did::traits::DidDeletionHook`] trait that makes sure +/// there is no resource linked to the DID in the provided did_lookup pallet +/// deployment. +/// +/// The returned worst-case weight is the same weight provided to this type. pub struct EnsureNoLinkedAccountDeletionHook< const READ_WEIGHT_TIME: u64, const READ_WEIGHT_SIZE: u64, diff --git a/runtimes/kestrel/src/lib.rs b/runtimes/kestrel/src/lib.rs index f3122b84b5..3b4e66bda3 100644 --- a/runtimes/kestrel/src/lib.rs +++ b/runtimes/kestrel/src/lib.rs @@ -423,6 +423,7 @@ impl did::Config for Runtime { type MaxNumberOfUrlsPerService = MaxNumberOfUrlsPerService; type WeightInfo = (); type BalanceMigrationManager = (); + // This differs from the implementation of the other runtimes. type DidLifecycleHooks = (); } diff --git a/runtimes/peregrine/src/kilt/did.rs b/runtimes/peregrine/src/kilt/did.rs index 1d095045fa..483eb7f466 100644 --- a/runtimes/peregrine/src/kilt/did.rs +++ b/runtimes/peregrine/src/kilt/did.rs @@ -94,17 +94,24 @@ impl did::traits::DidLifecycleHooks for DidLifecycleHooks { type DeletionHook = EnsureNoNamesAndNoLinkedAccountsOnDidDeletion; } +/// Ensure there is no Web3Name linked to a DID. type EnsureNoWeb3NameOnDeletion = EnsureNoLinkedWeb3NameDeletionHook<{ RocksDbWeight::get().read }, 0, ()>; +/// Ensure there is no Dotname linked to a DID. type EnsureNoDotNameOnDeletion = EnsureNoLinkedWeb3NameDeletionHook<{ RocksDbWeight::get().read }, 0, DotNamesDeployment>; +/// Ensure there is neither a Web3Name nor a Dotname linked to a DID. type EnsureNoUsernamesOnDeletion = RequireBoth; +/// Ensure there is no linked account (for a web3name) to a DID. type EnsureNoWeb3NameLinkedAccountsOnDeletion = EnsureNoLinkedAccountDeletionHook<{ RocksDbWeight::get().read }, 0, ()>; +/// Ensure there is no unique linked account (for a dotname) to a DID. type EnsureNoDotNameLinkedAccountOnDeletion = EnsureNoLinkedWeb3NameDeletionHook<{ RocksDbWeight::get().read }, 0, UniqueLinkingDeployment>; +/// Ensure there is no account linked for both the DID's Web3Name and DotName. type EnsureNoLinkedAccountsOnDeletion = RequireBoth; +/// Ensure there is no trace of names nor linked accounts for the DID. pub type EnsureNoNamesAndNoLinkedAccountsOnDidDeletion = RequireBoth; diff --git a/runtimes/spiritnet/src/kilt/did.rs b/runtimes/spiritnet/src/kilt/did.rs index 9f4796010a..3140013e76 100644 --- a/runtimes/spiritnet/src/kilt/did.rs +++ b/runtimes/spiritnet/src/kilt/did.rs @@ -94,17 +94,24 @@ impl did::traits::DidLifecycleHooks for DidLifecycleHooks { type DeletionHook = EnsureNoNamesAndNoLinkedAccountsOnDidDeletion; } +/// Ensure there is no Web3Name linked to a DID. type EnsureNoWeb3NameOnDeletion = EnsureNoLinkedWeb3NameDeletionHook<{ RocksDbWeight::get().read }, 0, ()>; +/// Ensure there is no Dotname linked to a DID. type EnsureNoDotNameOnDeletion = EnsureNoLinkedWeb3NameDeletionHook<{ RocksDbWeight::get().read }, 0, DotNamesDeployment>; +/// Ensure there is neither a Web3Name nor a Dotname linked to a DID. type EnsureNoUsernamesOnDeletion = RequireBoth; +/// Ensure there is no linked account (for a web3name) to a DID. type EnsureNoWeb3NameLinkedAccountsOnDeletion = EnsureNoLinkedAccountDeletionHook<{ RocksDbWeight::get().read }, 0, ()>; +/// Ensure there is no unique linked account (for a dotname) to a DID. type EnsureNoDotNameLinkedAccountOnDeletion = EnsureNoLinkedWeb3NameDeletionHook<{ RocksDbWeight::get().read }, 0, UniqueLinkingDeployment>; +/// Ensure there is no account linked for both the DID's Web3Name and DotName. type EnsureNoLinkedAccountsOnDeletion = RequireBoth; +/// Ensure there is no trace of names nor linked accounts for the DID. pub type EnsureNoNamesAndNoLinkedAccountsOnDidDeletion = RequireBoth; From 61badeb813496e9e67427fb64c1336918f84f44e Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Mon, 13 Jan 2025 10:18:44 +0100 Subject: [PATCH 12/18] Fix block weights --- runtimes/common/src/did/deletion_hooks/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/runtimes/common/src/did/deletion_hooks/mod.rs b/runtimes/common/src/did/deletion_hooks/mod.rs index 9c1d515fa1..d6ac948c9e 100644 --- a/runtimes/common/src/did/deletion_hooks/mod.rs +++ b/runtimes/common/src/did/deletion_hooks/mod.rs @@ -36,7 +36,7 @@ pub struct EnsureNoLinkedWeb3NameDeletionHook< >(PhantomData); impl did::traits::DidDeletionHook - for EnsureNoLinkedWeb3NameDeletionHook + for EnsureNoLinkedWeb3NameDeletionHook where T: did::Config + pallet_web3_names::Config>, Web3NameDeployment: 'static, @@ -65,7 +65,7 @@ pub struct EnsureNoLinkedAccountDeletionHook< impl did::traits::DidDeletionHook - for EnsureNoLinkedAccountDeletionHook + for EnsureNoLinkedAccountDeletionHook where T: did::Config + pallet_did_lookup::Config>, AccountLinkingDeployment: 'static, From c919948fff78d1bfa7284989a0f6900195211ef5 Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Mon, 13 Jan 2025 10:36:50 +0100 Subject: [PATCH 13/18] Fix weights --- runtimes/peregrine/src/kilt/did.rs | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/runtimes/peregrine/src/kilt/did.rs b/runtimes/peregrine/src/kilt/did.rs index 483eb7f466..9d52a62431 100644 --- a/runtimes/peregrine/src/kilt/did.rs +++ b/runtimes/peregrine/src/kilt/did.rs @@ -94,19 +94,37 @@ impl did::traits::DidLifecycleHooks for DidLifecycleHooks { type DeletionHook = EnsureNoNamesAndNoLinkedAccountsOnDidDeletion; } +// Worst case taken from the weight values of reading a single storage item as +// computed in the peregrine weight file. +// TODO: Replace this with a properly benchmarked value after adding a storage +// read benchmark to the web3name pallet. +const WORST_CASE_WEB3_NAME_STORAGE_READ_SIZE: u64 = 500; /// Ensure there is no Web3Name linked to a DID. -type EnsureNoWeb3NameOnDeletion = EnsureNoLinkedWeb3NameDeletionHook<{ RocksDbWeight::get().read }, 0, ()>; +type EnsureNoWeb3NameOnDeletion = + EnsureNoLinkedWeb3NameDeletionHook<{ RocksDbWeight::get().read }, WORST_CASE_WEB3_NAME_STORAGE_READ_SIZE, ()>; /// Ensure there is no Dotname linked to a DID. -type EnsureNoDotNameOnDeletion = - EnsureNoLinkedWeb3NameDeletionHook<{ RocksDbWeight::get().read }, 0, DotNamesDeployment>; +type EnsureNoDotNameOnDeletion = EnsureNoLinkedWeb3NameDeletionHook< + { RocksDbWeight::get().read }, + WORST_CASE_WEB3_NAME_STORAGE_READ_SIZE, + DotNamesDeployment, +>; /// Ensure there is neither a Web3Name nor a Dotname linked to a DID. type EnsureNoUsernamesOnDeletion = RequireBoth; +// Worst case taken from the weight values of reading a single storage item as +// computed in the peregrine weight file. +// TODO: Replace this with a properly benchmarked value after adding a storage +// read benchmark to the account linking pallet. +const WORST_CASE_LINKING_STORAGE_READ_SIZE: u64 = 1_000; /// Ensure there is no linked account (for a web3name) to a DID. -type EnsureNoWeb3NameLinkedAccountsOnDeletion = EnsureNoLinkedAccountDeletionHook<{ RocksDbWeight::get().read }, 0, ()>; +type EnsureNoWeb3NameLinkedAccountsOnDeletion = + EnsureNoLinkedAccountDeletionHook<{ RocksDbWeight::get().read }, WORST_CASE_LINKING_STORAGE_READ_SIZE, ()>; /// Ensure there is no unique linked account (for a dotname) to a DID. -type EnsureNoDotNameLinkedAccountOnDeletion = - EnsureNoLinkedWeb3NameDeletionHook<{ RocksDbWeight::get().read }, 0, UniqueLinkingDeployment>; +type EnsureNoDotNameLinkedAccountOnDeletion = EnsureNoLinkedWeb3NameDeletionHook< + { RocksDbWeight::get().read }, + WORST_CASE_LINKING_STORAGE_READ_SIZE, + UniqueLinkingDeployment, +>; /// Ensure there is no account linked for both the DID's Web3Name and DotName. type EnsureNoLinkedAccountsOnDeletion = RequireBoth; From 97ef63bdfde1a2c313078e27236319eee088b809 Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Mon, 13 Jan 2025 14:23:09 +0100 Subject: [PATCH 14/18] Fix broken cargo doc --- pallets/did/src/traits/lifecycle_hooks/deletion/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pallets/did/src/traits/lifecycle_hooks/deletion/mod.rs b/pallets/did/src/traits/lifecycle_hooks/deletion/mod.rs index c872be2e11..ef91931d65 100644 --- a/pallets/did/src/traits/lifecycle_hooks/deletion/mod.rs +++ b/pallets/did/src/traits/lifecycle_hooks/deletion/mod.rs @@ -50,7 +50,7 @@ where } } -/// Implementation of [`did::traits::DidDeletionHook`] that iterates over both +/// Implementation of [`DidDeletionHook`] that iterates over both /// components, bailing out early if the first one fails. The `MAX_WEIGHT` is /// the sum of both components. pub struct RequireBoth(PhantomData<(A, B)>); From 72fc198d24b84e19b7d04a1da0134742f0f2b9d4 Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Tue, 14 Jan 2025 10:40:30 +0100 Subject: [PATCH 15/18] Adjust read weight size + unit tests --- .../did/src/traits/lifecycle_hooks/mock.rs | 2 +- .../src/xcm/trade/xcm_fee_asset/mock.rs | 2 +- .../src/xcm/transfer/mock.rs | 2 +- runtimes/common/Cargo.toml | 1 + .../src/did/deletion_hooks/tests/mock.rs | 2 +- .../peregrine/src/kilt/{did.rs => did/mod.rs} | 27 ++-- .../peregrine/src/kilt/did/tests/did_hooks.rs | 49 ++++++++ runtimes/peregrine/src/kilt/did/tests/mod.rs | 19 +++ .../spiritnet/src/kilt/{did.rs => did/mod.rs} | 35 +++++- .../spiritnet/src/kilt/did/tests/did_hooks.rs | 49 ++++++++ runtimes/spiritnet/src/kilt/did/tests/mod.rs | 19 +++ support/src/mock.rs | 113 ++++++++++++++++- support/src/test_utils.rs | 116 +----------------- 13 files changed, 300 insertions(+), 136 deletions(-) rename runtimes/peregrine/src/kilt/{did.rs => did/mod.rs} (92%) create mode 100644 runtimes/peregrine/src/kilt/did/tests/did_hooks.rs create mode 100644 runtimes/peregrine/src/kilt/did/tests/mod.rs rename runtimes/spiritnet/src/kilt/{did.rs => did/mod.rs} (87%) create mode 100644 runtimes/spiritnet/src/kilt/did/tests/did_hooks.rs create mode 100644 runtimes/spiritnet/src/kilt/did/tests/mod.rs diff --git a/pallets/did/src/traits/lifecycle_hooks/mock.rs b/pallets/did/src/traits/lifecycle_hooks/mock.rs index f7ea154934..73a2761c84 100644 --- a/pallets/did/src/traits/lifecycle_hooks/mock.rs +++ b/pallets/did/src/traits/lifecycle_hooks/mock.rs @@ -18,7 +18,7 @@ use frame_support::{construct_runtime, parameter_types}; use frame_system::{mocking::MockBlock, EnsureSigned}; -use kilt_support::test_utils::MockCurrency; +use kilt_support::mock::MockCurrency; use parity_scale_codec::{Decode, Encode}; use scale_info::TypeInfo; use sp_core::{ConstU32, ConstU64, H256}; diff --git a/pallets/pallet-asset-switch/src/xcm/trade/xcm_fee_asset/mock.rs b/pallets/pallet-asset-switch/src/xcm/trade/xcm_fee_asset/mock.rs index 8cbb9f6cdf..82b596b63d 100644 --- a/pallets/pallet-asset-switch/src/xcm/trade/xcm_fee_asset/mock.rs +++ b/pallets/pallet-asset-switch/src/xcm/trade/xcm_fee_asset/mock.rs @@ -18,7 +18,7 @@ use frame_support::{construct_runtime, parameter_types, traits::Everything}; use frame_system::{mocking::MockBlock, EnsureRoot, EnsureSigned}; -use kilt_support::test_utils::MockCurrency; +use kilt_support::mock::MockCurrency; use sp_core::{ConstU16, ConstU32, ConstU64, H256}; use sp_runtime::{ traits::{BlakeTwo256, IdentityLookup}, diff --git a/pallets/pallet-asset-switch/src/xcm/transfer/mock.rs b/pallets/pallet-asset-switch/src/xcm/transfer/mock.rs index 1e43deb732..87d9b933e0 100644 --- a/pallets/pallet-asset-switch/src/xcm/transfer/mock.rs +++ b/pallets/pallet-asset-switch/src/xcm/transfer/mock.rs @@ -18,7 +18,7 @@ use frame_support::{construct_runtime, parameter_types, traits::Everything}; use frame_system::{mocking::MockBlock, EnsureRoot, EnsureSigned}; -use kilt_support::test_utils::MockCurrency; +use kilt_support::mock::MockCurrency; use pallet_balances::AccountData; use sp_core::{ConstU16, ConstU32, ConstU64, H256}; use sp_runtime::{ diff --git a/runtimes/common/Cargo.toml b/runtimes/common/Cargo.toml index 48356ddbff..c3865c2802 100644 --- a/runtimes/common/Cargo.toml +++ b/runtimes/common/Cargo.toml @@ -15,6 +15,7 @@ did = { workspace = true, features = ["mock", "std"] } enum-iterator = { workspace = true } env_logger = { workspace = true } kilt-dip-primitives = { workspace = true, features = ["std"] } +kilt-support = { workspace = true, features = ["mock", "std"] } sp-io = { workspace = true, features = ["std"] } [dependencies] diff --git a/runtimes/common/src/did/deletion_hooks/tests/mock.rs b/runtimes/common/src/did/deletion_hooks/tests/mock.rs index e70ff17022..6caca884e3 100644 --- a/runtimes/common/src/did/deletion_hooks/tests/mock.rs +++ b/runtimes/common/src/did/deletion_hooks/tests/mock.rs @@ -19,7 +19,7 @@ use did::{did_details::DidVerificationKey, traits::deletion::RequireBoth, DidVerificationKeyRelationship}; use frame_support::{construct_runtime, parameter_types}; use frame_system::{mocking::MockBlock, EnsureRoot, EnsureSigned, RawOrigin}; -use kilt_support::test_utils::MockCurrency; +use kilt_support::mock::MockCurrency; use parity_scale_codec::{Decode, Encode}; use scale_info::TypeInfo; use sp_core::{ConstBool, ConstU32, ConstU64, H256}; diff --git a/runtimes/peregrine/src/kilt/did.rs b/runtimes/peregrine/src/kilt/did/mod.rs similarity index 92% rename from runtimes/peregrine/src/kilt/did.rs rename to runtimes/peregrine/src/kilt/did/mod.rs index 9d52a62431..e2aaed4198 100644 --- a/runtimes/peregrine/src/kilt/did.rs +++ b/runtimes/peregrine/src/kilt/did/mod.rs @@ -35,6 +35,9 @@ use crate::{ Balances, DotNames, Migration, Runtime, RuntimeCall, RuntimeEvent, RuntimeHoldReason, RuntimeOrigin, UniqueLinking, }; +#[cfg(test)] +mod tests; + impl DeriveDidCallAuthorizationVerificationKeyRelationship for RuntimeCall { fn derive_verification_key_relationship(&self) -> DeriveDidCallKeyRelationshipResult { /// ensure that all calls have the same VerificationKeyRelationship @@ -94,28 +97,30 @@ impl did::traits::DidLifecycleHooks for DidLifecycleHooks { type DeletionHook = EnsureNoNamesAndNoLinkedAccountsOnDidDeletion; } -// Worst case taken from the weight values of reading a single storage item as -// computed in the peregrine weight file. -// TODO: Replace this with a properly benchmarked value after adding a storage -// read benchmark to the web3name pallet. -const WORST_CASE_WEB3_NAME_STORAGE_READ_SIZE: u64 = 500; +// Read size is given by the `MaxEncodedLen`: https://substrate.stackexchange.com/a/11843/1795. +// Since the trait is not `const`, we have unit tests that make sure the +// `max_encoded_len()` function matches this const. +const WORST_CASE_WEB3_NAME_STORAGE_READ_SIZE: u64 = 33; /// Ensure there is no Web3Name linked to a DID. type EnsureNoWeb3NameOnDeletion = EnsureNoLinkedWeb3NameDeletionHook<{ RocksDbWeight::get().read }, WORST_CASE_WEB3_NAME_STORAGE_READ_SIZE, ()>; +// Read size is given by the `MaxEncodedLen`: https://substrate.stackexchange.com/a/11843/1795. +// Since the trait is not `const`, we have unit tests that make sure the +// `max_encoded_len()` function matches this const. +const WORST_CASE_DOT_NAME_STORAGE_READ_SIZE: u64 = 33; /// Ensure there is no Dotname linked to a DID. type EnsureNoDotNameOnDeletion = EnsureNoLinkedWeb3NameDeletionHook< { RocksDbWeight::get().read }, - WORST_CASE_WEB3_NAME_STORAGE_READ_SIZE, + WORST_CASE_DOT_NAME_STORAGE_READ_SIZE, DotNamesDeployment, >; /// Ensure there is neither a Web3Name nor a Dotname linked to a DID. type EnsureNoUsernamesOnDeletion = RequireBoth; -// Worst case taken from the weight values of reading a single storage item as -// computed in the peregrine weight file. -// TODO: Replace this with a properly benchmarked value after adding a storage -// read benchmark to the account linking pallet. -const WORST_CASE_LINKING_STORAGE_READ_SIZE: u64 = 1_000; +// Read size is given by the `MaxEncodedLen`: https://substrate.stackexchange.com/a/11843/1795. +// Since the trait is not `const`, we have unit tests that make sure the +// `max_encoded_len()` function matches this const. +const WORST_CASE_LINKING_STORAGE_READ_SIZE: u64 = 33; /// Ensure there is no linked account (for a web3name) to a DID. type EnsureNoWeb3NameLinkedAccountsOnDeletion = EnsureNoLinkedAccountDeletionHook<{ RocksDbWeight::get().read }, WORST_CASE_LINKING_STORAGE_READ_SIZE, ()>; diff --git a/runtimes/peregrine/src/kilt/did/tests/did_hooks.rs b/runtimes/peregrine/src/kilt/did/tests/did_hooks.rs new file mode 100644 index 0000000000..cb5bd6f37d --- /dev/null +++ b/runtimes/peregrine/src/kilt/did/tests/did_hooks.rs @@ -0,0 +1,49 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2024 BOTLabs GmbH + +// The KILT Blockchain 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. + +// The KILT Blockchain 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 this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +use pallet_did_lookup::linkable_account::LinkableAccountId; +use parity_scale_codec::MaxEncodedLen; + +use crate::{ + kilt::did::{ + WORST_CASE_DOT_NAME_STORAGE_READ_SIZE, WORST_CASE_LINKING_STORAGE_READ_SIZE, + WORST_CASE_WEB3_NAME_STORAGE_READ_SIZE, + }, + DotName, Web3Name, +}; + +#[test] +fn test_worst_case_web3_name_storage_read() { + assert_eq!( + Web3Name::max_encoded_len() as u64, + WORST_CASE_WEB3_NAME_STORAGE_READ_SIZE + ); +} + +#[test] +fn test_worst_case_dot_name_storage_read() { + assert_eq!(DotName::max_encoded_len() as u64, WORST_CASE_DOT_NAME_STORAGE_READ_SIZE); +} + +#[test] +fn test_worst_case_web3_name_linked_account_storage_read() { + assert_eq!( + LinkableAccountId::max_encoded_len() as u64, + WORST_CASE_LINKING_STORAGE_READ_SIZE + ); +} diff --git a/runtimes/peregrine/src/kilt/did/tests/mod.rs b/runtimes/peregrine/src/kilt/did/tests/mod.rs new file mode 100644 index 0000000000..8a23678070 --- /dev/null +++ b/runtimes/peregrine/src/kilt/did/tests/mod.rs @@ -0,0 +1,19 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2024 BOTLabs GmbH + +// The KILT Blockchain 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. + +// The KILT Blockchain 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 this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +mod did_hooks; diff --git a/runtimes/spiritnet/src/kilt/did.rs b/runtimes/spiritnet/src/kilt/did/mod.rs similarity index 87% rename from runtimes/spiritnet/src/kilt/did.rs rename to runtimes/spiritnet/src/kilt/did/mod.rs index 3140013e76..292e3414cc 100644 --- a/runtimes/spiritnet/src/kilt/did.rs +++ b/runtimes/spiritnet/src/kilt/did/mod.rs @@ -35,6 +35,9 @@ use crate::{ Balances, DotNames, Migration, Runtime, RuntimeCall, RuntimeEvent, RuntimeHoldReason, RuntimeOrigin, UniqueLinking, }; +#[cfg(test)] +mod tests; + impl DeriveDidCallAuthorizationVerificationKeyRelationship for RuntimeCall { fn derive_verification_key_relationship(&self) -> DeriveDidCallKeyRelationshipResult { /// ensure that all calls have the same VerificationKeyRelationship @@ -94,19 +97,39 @@ impl did::traits::DidLifecycleHooks for DidLifecycleHooks { type DeletionHook = EnsureNoNamesAndNoLinkedAccountsOnDidDeletion; } +// Read size is given by the `MaxEncodedLen`: https://substrate.stackexchange.com/a/11843/1795. +// Since the trait is not `const`, we have unit tests that make sure the +// `max_encoded_len()` function matches this const. +const WORST_CASE_WEB3_NAME_STORAGE_READ_SIZE: u64 = 33; /// Ensure there is no Web3Name linked to a DID. -type EnsureNoWeb3NameOnDeletion = EnsureNoLinkedWeb3NameDeletionHook<{ RocksDbWeight::get().read }, 0, ()>; +type EnsureNoWeb3NameOnDeletion = + EnsureNoLinkedWeb3NameDeletionHook<{ RocksDbWeight::get().read }, WORST_CASE_WEB3_NAME_STORAGE_READ_SIZE, ()>; +// Read size is given by the `MaxEncodedLen`: https://substrate.stackexchange.com/a/11843/1795. +// Since the trait is not `const`, we have unit tests that make sure the +// `max_encoded_len()` function matches this const. +const WORST_CASE_DOT_NAME_STORAGE_READ_SIZE: u64 = 33; /// Ensure there is no Dotname linked to a DID. -type EnsureNoDotNameOnDeletion = - EnsureNoLinkedWeb3NameDeletionHook<{ RocksDbWeight::get().read }, 0, DotNamesDeployment>; +type EnsureNoDotNameOnDeletion = EnsureNoLinkedWeb3NameDeletionHook< + { RocksDbWeight::get().read }, + WORST_CASE_DOT_NAME_STORAGE_READ_SIZE, + DotNamesDeployment, +>; /// Ensure there is neither a Web3Name nor a Dotname linked to a DID. type EnsureNoUsernamesOnDeletion = RequireBoth; +// Read size is given by the `MaxEncodedLen`: https://substrate.stackexchange.com/a/11843/1795. +// Since the trait is not `const`, we have unit tests that make sure the +// `max_encoded_len()` function matches this const. +const WORST_CASE_LINKING_STORAGE_READ_SIZE: u64 = 33; /// Ensure there is no linked account (for a web3name) to a DID. -type EnsureNoWeb3NameLinkedAccountsOnDeletion = EnsureNoLinkedAccountDeletionHook<{ RocksDbWeight::get().read }, 0, ()>; +type EnsureNoWeb3NameLinkedAccountsOnDeletion = + EnsureNoLinkedAccountDeletionHook<{ RocksDbWeight::get().read }, WORST_CASE_LINKING_STORAGE_READ_SIZE, ()>; /// Ensure there is no unique linked account (for a dotname) to a DID. -type EnsureNoDotNameLinkedAccountOnDeletion = - EnsureNoLinkedWeb3NameDeletionHook<{ RocksDbWeight::get().read }, 0, UniqueLinkingDeployment>; +type EnsureNoDotNameLinkedAccountOnDeletion = EnsureNoLinkedWeb3NameDeletionHook< + { RocksDbWeight::get().read }, + WORST_CASE_LINKING_STORAGE_READ_SIZE, + UniqueLinkingDeployment, +>; /// Ensure there is no account linked for both the DID's Web3Name and DotName. type EnsureNoLinkedAccountsOnDeletion = RequireBoth; diff --git a/runtimes/spiritnet/src/kilt/did/tests/did_hooks.rs b/runtimes/spiritnet/src/kilt/did/tests/did_hooks.rs new file mode 100644 index 0000000000..cb5bd6f37d --- /dev/null +++ b/runtimes/spiritnet/src/kilt/did/tests/did_hooks.rs @@ -0,0 +1,49 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2024 BOTLabs GmbH + +// The KILT Blockchain 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. + +// The KILT Blockchain 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 this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +use pallet_did_lookup::linkable_account::LinkableAccountId; +use parity_scale_codec::MaxEncodedLen; + +use crate::{ + kilt::did::{ + WORST_CASE_DOT_NAME_STORAGE_READ_SIZE, WORST_CASE_LINKING_STORAGE_READ_SIZE, + WORST_CASE_WEB3_NAME_STORAGE_READ_SIZE, + }, + DotName, Web3Name, +}; + +#[test] +fn test_worst_case_web3_name_storage_read() { + assert_eq!( + Web3Name::max_encoded_len() as u64, + WORST_CASE_WEB3_NAME_STORAGE_READ_SIZE + ); +} + +#[test] +fn test_worst_case_dot_name_storage_read() { + assert_eq!(DotName::max_encoded_len() as u64, WORST_CASE_DOT_NAME_STORAGE_READ_SIZE); +} + +#[test] +fn test_worst_case_web3_name_linked_account_storage_read() { + assert_eq!( + LinkableAccountId::max_encoded_len() as u64, + WORST_CASE_LINKING_STORAGE_READ_SIZE + ); +} diff --git a/runtimes/spiritnet/src/kilt/did/tests/mod.rs b/runtimes/spiritnet/src/kilt/did/tests/mod.rs new file mode 100644 index 0000000000..8a23678070 --- /dev/null +++ b/runtimes/spiritnet/src/kilt/did/tests/mod.rs @@ -0,0 +1,19 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2024 BOTLabs GmbH + +// The KILT Blockchain 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. + +// The KILT Blockchain 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 this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +mod did_hooks; diff --git a/support/src/mock.rs b/support/src/mock.rs index 2f71f31abd..cc571a389e 100644 --- a/support/src/mock.rs +++ b/support/src/mock.rs @@ -18,10 +18,15 @@ //! This module contains utilities for testing. +use frame_support::traits::{ + fungible::{Balanced, Dust, Inspect, InspectHold, Mutate, MutateHold, Unbalanced, UnbalancedHold}, + tokens::{Balance as BalanceT, DepositConsequence, Fortitude, Preservation, Provenance, WithdrawConsequence}, +}; use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; use sp_core::sr25519; -use sp_runtime::AccountId32; +use sp_runtime::{AccountId32, DispatchError, DispatchResult}; +use sp_std::marker::PhantomData; /// This pallet only contains an origin which supports separated sender and /// subject. @@ -171,3 +176,109 @@ impl AsRef<[u8]> for SubjectId { self.0.as_ref() } } + +// Mock currency that implements all required traits, allowing test runtimes to +// not include the actual `pallet_balances` pallet. This mock currency is useful +// for mocks in which a `Currency` is required but not relevant for the goal of +// the tests. +pub struct MockCurrency(PhantomData<(Balance, RuntimeHoldReason)>); + +impl MutateHold for MockCurrency +where + Balance: BalanceT, + RuntimeHoldReason: Encode + TypeInfo + 'static, +{ +} + +impl UnbalancedHold for MockCurrency +where + Balance: BalanceT, + RuntimeHoldReason: Encode + TypeInfo + 'static, +{ + fn set_balance_on_hold(_reason: &Self::Reason, _who: &AccountId, _amount: Self::Balance) -> DispatchResult { + Ok(()) + } +} + +impl InspectHold for MockCurrency +where + Balance: BalanceT, + RuntimeHoldReason: Encode + TypeInfo + 'static, +{ + type Reason = RuntimeHoldReason; + + fn total_balance_on_hold(_who: &AccountId) -> Self::Balance { + Self::Balance::default() + } + + fn balance_on_hold(_reason: &Self::Reason, _who: &AccountId) -> Self::Balance { + Self::Balance::default() + } +} + +impl Mutate for MockCurrency +where + AccountId: Eq, + Balance: BalanceT, +{ +} + +impl Inspect for MockCurrency +where + Balance: BalanceT, +{ + type Balance = Balance; + + fn active_issuance() -> Self::Balance { + Self::Balance::default() + } + + fn balance(_who: &AccountId) -> Self::Balance { + Self::Balance::default() + } + + fn can_deposit(_who: &AccountId, _amount: Self::Balance, _provenance: Provenance) -> DepositConsequence { + DepositConsequence::Success + } + + fn can_withdraw(_who: &AccountId, _amount: Self::Balance) -> WithdrawConsequence { + WithdrawConsequence::Success + } + + fn minimum_balance() -> Self::Balance { + Self::Balance::default() + } + + fn reducible_balance(_who: &AccountId, _preservation: Preservation, _force: Fortitude) -> Self::Balance { + Self::Balance::default() + } + + fn total_balance(_who: &AccountId) -> Self::Balance { + Self::Balance::default() + } + + fn total_issuance() -> Self::Balance { + Self::Balance::default() + } +} + +impl Unbalanced for MockCurrency +where + Balance: BalanceT, +{ + fn handle_dust(_dust: Dust) {} + + fn write_balance(_who: &AccountId, _amount: Self::Balance) -> Result, DispatchError> { + Ok(Some(Self::Balance::default())) + } + + fn set_total_issuance(_amount: Self::Balance) {} +} + +impl Balanced for MockCurrency +where + Balance: BalanceT, +{ + type OnDropDebt = (); + type OnDropCredit = (); +} diff --git a/support/src/test_utils.rs b/support/src/test_utils.rs index 4640b03360..49418b7f3f 100644 --- a/support/src/test_utils.rs +++ b/support/src/test_utils.rs @@ -16,123 +16,11 @@ // If you feel like getting in touch with us, you can do so at info@botlabs.org -use frame_support::traits::{ - fungible::{Balanced, Dust, Inspect, InspectHold, Mutate, MutateHold, Unbalanced, UnbalancedHold}, - tokens::{Balance as BalanceT, DepositConsequence, Fortitude, Preservation, Provenance, WithdrawConsequence}, -}; -use parity_scale_codec::Encode; -use scale_info::{prelude::string::String, TypeInfo}; -use sp_runtime::{DispatchError, DispatchResult, TryRuntimeError}; -use sp_std::marker::PhantomData; +use scale_info::prelude::string::String; +use sp_runtime::TryRuntimeError; /// Logs the error message and returns "Sanity test error" pub fn log_and_return_error_message(error_message: String) -> TryRuntimeError { log::error!("{}", error_message); TryRuntimeError::Other("Test") } - -// Mock currency that implements all required traits, allowing test runtimes to -// not include the actual `pallet_balances` pallet. This mock currency is useful -// for mocks in which a `Currency` is required but not relevant for the goal of -// the tests. -pub struct MockCurrency(PhantomData<(Balance, RuntimeHoldReason)>); - -impl MutateHold for MockCurrency -where - Balance: BalanceT, - RuntimeHoldReason: Encode + TypeInfo + 'static, -{ -} - -impl UnbalancedHold for MockCurrency -where - Balance: BalanceT, - RuntimeHoldReason: Encode + TypeInfo + 'static, -{ - fn set_balance_on_hold(_reason: &Self::Reason, _who: &AccountId, _amount: Self::Balance) -> DispatchResult { - Ok(()) - } -} - -impl InspectHold for MockCurrency -where - Balance: BalanceT, - RuntimeHoldReason: Encode + TypeInfo + 'static, -{ - type Reason = RuntimeHoldReason; - - fn total_balance_on_hold(_who: &AccountId) -> Self::Balance { - Self::Balance::default() - } - - fn balance_on_hold(_reason: &Self::Reason, _who: &AccountId) -> Self::Balance { - Self::Balance::default() - } -} - -impl Mutate for MockCurrency -where - AccountId: Eq, - Balance: BalanceT, -{ -} - -impl Inspect for MockCurrency -where - Balance: BalanceT, -{ - type Balance = Balance; - - fn active_issuance() -> Self::Balance { - Self::Balance::default() - } - - fn balance(_who: &AccountId) -> Self::Balance { - Self::Balance::default() - } - - fn can_deposit(_who: &AccountId, _amount: Self::Balance, _provenance: Provenance) -> DepositConsequence { - DepositConsequence::Success - } - - fn can_withdraw(_who: &AccountId, _amount: Self::Balance) -> WithdrawConsequence { - WithdrawConsequence::Success - } - - fn minimum_balance() -> Self::Balance { - Self::Balance::default() - } - - fn reducible_balance(_who: &AccountId, _preservation: Preservation, _force: Fortitude) -> Self::Balance { - Self::Balance::default() - } - - fn total_balance(_who: &AccountId) -> Self::Balance { - Self::Balance::default() - } - - fn total_issuance() -> Self::Balance { - Self::Balance::default() - } -} - -impl Unbalanced for MockCurrency -where - Balance: BalanceT, -{ - fn handle_dust(_dust: Dust) {} - - fn write_balance(_who: &AccountId, _amount: Self::Balance) -> Result, DispatchError> { - Ok(Some(Self::Balance::default())) - } - - fn set_total_issuance(_amount: Self::Balance) {} -} - -impl Balanced for MockCurrency -where - Balance: BalanceT, -{ - type OnDropDebt = (); - type OnDropCredit = (); -} From 8b47e0c72135a22406473568943aa7045306afea Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Wed, 15 Jan 2025 10:51:30 +0100 Subject: [PATCH 16/18] Rename test structs --- .../src/traits/lifecycle_hooks/deletion/tests.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/pallets/did/src/traits/lifecycle_hooks/deletion/tests.rs b/pallets/did/src/traits/lifecycle_hooks/deletion/tests.rs index b2d2b42b67..067a8a5403 100644 --- a/pallets/did/src/traits/lifecycle_hooks/deletion/tests.rs +++ b/pallets/did/src/traits/lifecycle_hooks/deletion/tests.rs @@ -27,9 +27,9 @@ use crate::{ DidIdentifierOf, }; -struct False; +struct AlwaysDeny; -impl DidDeletionHook for False { +impl DidDeletionHook for AlwaysDeny { const MAX_WEIGHT: Weight = Weight::from_all(10); fn can_delete(_did: &DidIdentifierOf) -> Result<(), Weight> { @@ -37,9 +37,9 @@ impl DidDeletionHook for False { } } -struct True; +struct AlwaysAllow; -impl DidDeletionHook for True { +impl DidDeletionHook for AlwaysAllow { const MAX_WEIGHT: Weight = Weight::from_all(20); fn can_delete(_did: &DidIdentifierOf) -> Result<(), Weight> { @@ -49,7 +49,7 @@ impl DidDeletionHook for True { #[test] fn first_false() { - type TestSubject = RequireBoth; + type TestSubject = RequireBoth; // Max weight is the sum. assert_eq!(TestSubject::MAX_WEIGHT, Weight::from_all(30)); @@ -62,7 +62,7 @@ fn first_false() { #[test] fn second_false() { - type TestSubject = RequireBoth; + type TestSubject = RequireBoth; // Max weight is the sum. assert_eq!(TestSubject::MAX_WEIGHT, Weight::from_all(30)); @@ -75,7 +75,7 @@ fn second_false() { #[test] fn both_true() { - type TestSubject = RequireBoth; + type TestSubject = RequireBoth; // Max weight is the sum. assert_eq!(TestSubject::MAX_WEIGHT, Weight::from_all(40)); From f178c82e18668ed97eb552ec736572915c67bbfd Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Wed, 15 Jan 2025 10:51:57 +0100 Subject: [PATCH 17/18] Upgrade to docstring --- support/src/mock.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/support/src/mock.rs b/support/src/mock.rs index cc571a389e..9a2f1977a9 100644 --- a/support/src/mock.rs +++ b/support/src/mock.rs @@ -177,10 +177,10 @@ impl AsRef<[u8]> for SubjectId { } } -// Mock currency that implements all required traits, allowing test runtimes to -// not include the actual `pallet_balances` pallet. This mock currency is useful -// for mocks in which a `Currency` is required but not relevant for the goal of -// the tests. +/// Mock currency that implements all required traits, allowing test runtimes to +/// not include the actual `pallet_balances` pallet. This mock currency is +/// useful for mocks in which a `Currency` is required but not relevant for the +/// goal of the tests. pub struct MockCurrency(PhantomData<(Balance, RuntimeHoldReason)>); impl MutateHold for MockCurrency From 3efbafbaec763c784dc06ddc0ce66ea5162d6962 Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Wed, 15 Jan 2025 10:53:17 +0100 Subject: [PATCH 18/18] Replace tuple struct with regular one --- .../common/src/did/deletion_hooks/tests/mock.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/runtimes/common/src/did/deletion_hooks/tests/mock.rs b/runtimes/common/src/did/deletion_hooks/tests/mock.rs index 6caca884e3..fa2e63526f 100644 --- a/runtimes/common/src/did/deletion_hooks/tests/mock.rs +++ b/runtimes/common/src/did/deletion_hooks/tests/mock.rs @@ -161,19 +161,19 @@ impl pallet_web3_names::Config for TestRuntime { } #[derive(Default)] -pub(super) struct ExtBuilder( - Vec<(AccountId32, Option, bool)>, - Vec<(AccountId32, Option, bool)>, -); +pub(super) struct ExtBuilder { + dids: Vec<(AccountId32, Option, bool)>, + dangling_dids: Vec<(AccountId32, Option, bool)>, +} impl ExtBuilder { pub(super) fn with_dids(mut self, did_links: Vec<(AccountId32, Option, bool)>) -> Self { - self.0 = did_links; + self.dids = did_links; self } pub(super) fn with_dangling_dids(mut self, dangling_dids: Vec<(AccountId32, Option, bool)>) -> Self { - self.1 = dangling_dids; + self.dangling_dids = dangling_dids; self } @@ -182,7 +182,7 @@ impl ExtBuilder { let mut ext = TestExternalities::default(); ext.execute_with(|| { - for (did, maybe_web3_name, should_link_account) in self.0 { + for (did, maybe_web3_name, should_link_account) in self.dids { // Store DID. Did::create_from_account( RawOrigin::Signed(did.clone()).into(), @@ -206,7 +206,7 @@ impl ExtBuilder { } } - for (did, maybe_web3_name, should_link_account) in self.1 { + for (did, maybe_web3_name, should_link_account) in self.dangling_dids { // Cannot write the same DID as both linked and dangling. assert!(!did::Did::::contains_key(&did)); if maybe_web3_name.is_none() && !should_link_account {