Skip to content

Commit

Permalink
chore: add unit tests for DIP components (#609)
Browse files Browse the repository at this point in the history
Partially fixes KILTprotocol/ticket#2562.

## Tests for the DIP provider components

The DIP provider components are tested in this PR. Specifically:

* The `pallet-deposit-storage` pallet main logic.
* The `DepositHooks` hook for deleting an identity commitment when a
deposit is released directly. It used to leave in the Peregrine runtime
but it now lives in `runtime-common` and is generic over the runtime.
This was required for testing the hook logic.
* The `pallet-dip-provider` pallet main logic.
* The `FixedDepositCollectorViaDepositsPallet` hook for reserving and
releasing deposits when identity commitments are deleted. It uses a
different mock than the pallet mock.
* The `generate_proof` and `generate_commitment` functions, along with
the `DidMerkleRootGenerator`.
* The `LinkedDidInfoProvider`.

The PR also contains minor refactoring that was necessary to do proper
mocking of the different pieces of the runtime to test the components
above. The main changes are:

* Move from a multi-module to a single-module approach, where files do
not contain more than a module.
* Move the `DepositHooks` from being Peregrine-specific to being
runtime-agnostic, in `runtime-common`.

**This PR only adds tests for the DIP provider components. The DIP
consumer will be tested in a separate PR.**
  • Loading branch information
ntn-x2 committed Apr 4, 2024
1 parent 4864dfd commit ed0282c
Show file tree
Hide file tree
Showing 42 changed files with 2,909 additions and 481 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

46 changes: 42 additions & 4 deletions crates/kilt-dip-primitives/src/merkle/v0.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,12 @@ pub struct TimeBoundDidSignature<BlockNumber> {
pub(crate) valid_until: BlockNumber,
}

impl<BlockNumber> TimeBoundDidSignature<BlockNumber> {
pub fn new(signature: DidSignature, valid_until: BlockNumber) -> Self {
Self { signature, valid_until }
}
}

#[cfg(feature = "runtime-benchmarks")]
impl<BlockNumber, Context> kilt_support::traits::GetWorstCase<Context> for TimeBoundDidSignature<BlockNumber>
where
Expand Down Expand Up @@ -770,6 +776,38 @@ pub struct DipDidProofWithVerifiedSubjectCommitment<
pub(crate) signature: TimeBoundDidSignature<ConsumerBlockNumber>,
}

impl<
Commitment,
KiltDidKeyId,
KiltAccountId,
KiltBlockNumber,
KiltWeb3Name,
KiltLinkableAccountId,
ConsumerBlockNumber,
>
DipDidProofWithVerifiedSubjectCommitment<
Commitment,
KiltDidKeyId,
KiltAccountId,
KiltBlockNumber,
KiltWeb3Name,
KiltLinkableAccountId,
ConsumerBlockNumber,
>
{
pub fn new(
dip_commitment: Commitment,
dip_proof: DidMerkleProof<KiltDidKeyId, KiltAccountId, KiltBlockNumber, KiltWeb3Name, KiltLinkableAccountId>,
signature: TimeBoundDidSignature<ConsumerBlockNumber>,
) -> Self {
Self {
dip_commitment,
dip_proof,
signature,
}
}
}

impl<
Commitment,
KiltDidKeyId,
Expand Down Expand Up @@ -1164,7 +1202,7 @@ impl<
}

/// Relationship of a key to a DID Document.
#[derive(Clone, Copy, Debug, Encode, Decode, PartialEq, Eq, TypeInfo, MaxEncodedLen)]
#[derive(Clone, Copy, Debug, Encode, Decode, PartialEq, Eq, PartialOrd, Ord, TypeInfo, MaxEncodedLen)]
pub enum DidKeyRelationship {
Encryption,
Verification(DidVerificationKeyRelationship),
Expand Down Expand Up @@ -1275,7 +1313,7 @@ where

/// The details of a DID key after it has been successfully verified in a Merkle
/// proof.
#[derive(Clone, Copy, Debug, Encode, Decode, PartialEq, Eq, TypeInfo, MaxEncodedLen)]
#[derive(Clone, Copy, Debug, Encode, Decode, PartialEq, Eq, PartialOrd, Ord, TypeInfo, MaxEncodedLen)]
pub struct RevealedDidKey<KeyId, BlockNumber, AccountId> {
/// The key ID, according to the provider's definition.
pub id: KeyId,
Expand All @@ -1288,7 +1326,7 @@ pub struct RevealedDidKey<KeyId, BlockNumber, AccountId> {

/// The details of a web3name after it has been successfully verified in a
/// Merkle proof.
#[derive(Clone, Copy, Debug, Encode, Decode, PartialEq, Eq, TypeInfo, MaxEncodedLen)]
#[derive(Clone, Copy, Debug, Encode, Decode, PartialEq, Eq, PartialOrd, Ord, TypeInfo, MaxEncodedLen)]
pub struct RevealedWeb3Name<Web3Name, BlockNumber> {
/// The web3name.
pub web3_name: Web3Name,
Expand All @@ -1299,5 +1337,5 @@ pub struct RevealedWeb3Name<Web3Name, BlockNumber> {

/// The details of an account after it has been successfully verified in a
/// Merkle proof.
#[derive(Clone, Copy, Debug, Encode, Decode, PartialEq, Eq, TypeInfo, MaxEncodedLen)]
#[derive(Clone, Copy, Debug, Encode, Decode, PartialEq, Eq, PartialOrd, Ord, TypeInfo, MaxEncodedLen)]
pub struct RevealedAccountId<AccountId>(pub AccountId);
2 changes: 1 addition & 1 deletion dip-template/runtimes/dip-consumer/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ std = [
"pallet-collator-selection/std",
"parachain-info/std",
"rococo-runtime/std",
"frame-benchmarking/std",
"frame-benchmarking?/std",
"frame-system-benchmarking?/std",
]

Expand Down
2 changes: 1 addition & 1 deletion pallets/did/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1463,7 +1463,7 @@ pub mod pallet {
/// Deletes DID details from storage, including its linked service
/// endpoints, adds the identifier to the blacklisted DIDs and frees the
/// deposit.
pub(crate) fn delete_did(did_subject: DidIdentifierOf<T>, endpoints_to_remove: u32) -> DispatchResult {
pub fn delete_did(did_subject: DidIdentifierOf<T>, endpoints_to_remove: u32) -> DispatchResult {
let current_endpoints_count = DidEndpointsCount::<T>::get(&did_subject);
ensure!(
current_endpoints_count <= endpoints_to_remove,
Expand Down
177 changes: 177 additions & 0 deletions pallets/pallet-deposit-storage/src/deposit/mock.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
// 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 <https://www.gnu.org/licenses/>.

// If you feel like getting in touch with us, you can do so at info@botlabs.org

use frame_support::{
construct_runtime,
sp_runtime::{
testing::H256,
traits::{BlakeTwo256, IdentityLookup},
AccountId32,
},
traits::{ConstU128, ConstU16, ConstU32, ConstU64, Currency, Everything, Get},
};
use frame_system::{mocking::MockBlock, EnsureSigned};
use pallet_dip_provider::{DefaultIdentityCommitmentGenerator, DefaultIdentityProvider, IdentityCommitmentVersion};
use parity_scale_codec::{Decode, Encode, MaxEncodedLen};
use scale_info::TypeInfo;
use sp_runtime::RuntimeDebug;

use crate::{
self as storage_deposit_pallet, DepositEntryOf, DepositKeyOf, FixedDepositCollectorViaDepositsPallet, Pallet,
};

pub(crate) type Balance = u128;

#[derive(Encode, Decode, MaxEncodedLen, TypeInfo, Clone, PartialEq, Eq, RuntimeDebug, Default)]
pub enum DepositNamespaces {
#[default]
ExampleNamespace,
}

impl Get<DepositNamespaces> for DepositNamespaces {
fn get() -> DepositNamespaces {
Self::ExampleNamespace
}
}

construct_runtime!(
pub struct TestRuntime {
System: frame_system,
Balances: pallet_balances,
DipProvider: pallet_dip_provider,
StorageDepositPallet: storage_deposit_pallet,
}
);

pub(crate) const SUBJECT: AccountId32 = AccountId32::new([100u8; 32]);
pub(crate) const SUBMITTER: AccountId32 = AccountId32::new([200u8; 32]);

impl frame_system::Config for TestRuntime {
type AccountData = pallet_balances::AccountData<Balance>;
type AccountId = AccountId32;
type BaseCallFilter = Everything;
type Block = MockBlock<TestRuntime>;
type BlockHashCount = ConstU64<256>;
type BlockLength = ();
type BlockWeights = ();
type DbWeight = ();
type Hash = H256;
type Hashing = BlakeTwo256;
type Lookup = IdentityLookup<Self::AccountId>;
type MaxConsumers = ConstU32<16>;
type Nonce = u64;
type OnKilledAccount = ();
type OnNewAccount = ();
type OnSetCode = ();
type PalletInfo = PalletInfo;
type RuntimeCall = RuntimeCall;
type RuntimeEvent = RuntimeEvent;
type RuntimeOrigin = RuntimeOrigin;
type SS58Prefix = ConstU16<1>;
type SystemWeightInfo = ();
type Version = ();
}

impl pallet_balances::Config for TestRuntime {
type FreezeIdentifier = RuntimeFreezeReason;
type RuntimeHoldReason = RuntimeHoldReason;
type MaxFreezes = ConstU32<50>;
type MaxHolds = ConstU32<50>;
type Balance = Balance;
type DustRemoval = ();
type RuntimeEvent = RuntimeEvent;
type ExistentialDeposit = ConstU128<500>;
type AccountStore = System;
type WeightInfo = ();
type MaxLocks = ConstU32<50>;
type MaxReserves = ConstU32<50>;
type ReserveIdentifier = [u8; 8];
}

pub(crate) type DepositCollectorHook<Runtime> = FixedDepositCollectorViaDepositsPallet<
DepositNamespaces,
ConstU128<1_000>,
(
<Runtime as pallet_dip_provider::Config>::Identifier,
AccountId32,
IdentityCommitmentVersion,
),
>;

impl pallet_dip_provider::Config for TestRuntime {
type CommitOrigin = AccountId32;
type CommitOriginCheck = EnsureSigned<AccountId32>;
type Identifier = AccountId32;
type IdentityCommitmentGenerator = DefaultIdentityCommitmentGenerator<u32>;
type IdentityProvider = DefaultIdentityProvider<u32>;
type ProviderHooks = DepositCollectorHook<Self>;
type RuntimeEvent = RuntimeEvent;
type WeightInfo = ();
}

impl crate::Config for TestRuntime {
type CheckOrigin = EnsureSigned<Self::AccountId>;
type Currency = Balances;
type DepositHooks = ();
type RuntimeEvent = RuntimeEvent;
type RuntimeHoldReason = RuntimeHoldReason;
type MaxKeyLength = ConstU32<256>;
type Namespace = DepositNamespaces;
#[cfg(feature = "runtime-benchmarks")]
type BenchmarkHooks = ();
type WeightInfo = ();
}

#[derive(Default)]
pub(crate) struct ExtBuilder(
Vec<(AccountId32, Balance)>,
Vec<(DepositKeyOf<TestRuntime>, DepositEntryOf<TestRuntime>)>,
);

impl ExtBuilder {
pub(crate) fn with_balances(mut self, balances: Vec<(AccountId32, Balance)>) -> Self {
self.0 = balances;
self
}

pub(crate) fn with_deposits(
mut self,
deposits: Vec<(DepositKeyOf<TestRuntime>, DepositEntryOf<TestRuntime>)>,
) -> Self {
self.1 = deposits;
self
}

pub(crate) fn build(self) -> sp_io::TestExternalities {
let mut ext = sp_io::TestExternalities::default();

ext.execute_with(|| {
for (account, balance) in self.0 {
Balances::make_free_balance_be(&account, balance);
}

for (deposit_key, deposit_entry) in self.1 {
// Add existential deposit + deposit amount.
Balances::make_free_balance_be(&deposit_entry.deposit.owner, 500 + deposit_entry.deposit.amount);
Pallet::<TestRuntime>::add_deposit(DepositNamespaces::get(), deposit_key, deposit_entry).unwrap();
}
});

ext
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ use sp_std::marker::PhantomData;

use crate::{BalanceOf, Config, Error, HoldReason, Pallet};

#[cfg(test)]
mod mock;
#[cfg(test)]
mod tests;

/// Details associated to an on-chain deposit.
#[derive(Clone, Debug, Encode, Decode, Eq, PartialEq, Ord, PartialOrd, TypeInfo, MaxEncodedLen)]
pub struct DepositEntry<AccountId, Balance, Reason> {
Expand Down Expand Up @@ -107,11 +112,12 @@ where
},
reason: HoldReason::Deposit.into(),
};
Pallet::<Runtime>::add_deposit(namespace, key, deposit_entry).map_err(|e| match e {
pallet_error if pallet_error == DispatchError::from(Error::<Runtime>::DepositExisting) => {
Pallet::<Runtime>::add_deposit(namespace, key, deposit_entry).map_err(|e| {
if e == DispatchError::from(Error::<Runtime>::DepositExisting) {
FixedDepositCollectorViaDepositsPalletError::DepositAlreadyTaken
}
_ => {
} else if e == DispatchError::from(Error::<Runtime>::FailedToHold) {
FixedDepositCollectorViaDepositsPalletError::FailedToHold
} else {
log::error!(
"Error {:#?} should not be generated inside `on_identity_committed` hook.",
e
Expand Down Expand Up @@ -140,11 +146,15 @@ where
);
FixedDepositCollectorViaDepositsPalletError::Internal
})?;
Pallet::<Runtime>::remove_deposit(&namespace, &key, None).map_err(|e| match e {
pallet_error if pallet_error == DispatchError::from(Error::<Runtime>::DepositNotFound) => {
// We don't set any expected owner for the deposit on purpose, since this hook
// assumes the dip-provider pallet has performed all the access control logic
// necessary.
Pallet::<Runtime>::remove_deposit(&namespace, &key, None).map_err(|e| {
if e == DispatchError::from(Error::<Runtime>::DepositNotFound) {
FixedDepositCollectorViaDepositsPalletError::DepositNotFound
}
_ => {
} else if e == DispatchError::from(Error::<Runtime>::FailedToRelease) {
FixedDepositCollectorViaDepositsPalletError::FailedToRelease
} else {
log::error!(
"Error {:#?} should not be generated inside `on_commitment_removed` hook.",
e
Expand Down
20 changes: 20 additions & 0 deletions pallets/pallet-deposit-storage/src/deposit/tests/mod.rs
Original file line number Diff line number Diff line change
@@ -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 <https://www.gnu.org/licenses/>.

// If you feel like getting in touch with us, you can do so at info@botlabs.org

mod on_commitment_removed;
mod on_identity_committed;
Loading

0 comments on commit ed0282c

Please sign in to comment.