Skip to content

Commit ed0282c

Browse files
committed
chore: add unit tests for DIP components (#609)
Partially fixes https://github.com/KILTprotocol/ticket/issues/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.**
1 parent 4864dfd commit ed0282c

42 files changed

Lines changed: 2909 additions & 481 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/kilt-dip-primitives/src/merkle/v0.rs

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,12 @@ pub struct TimeBoundDidSignature<BlockNumber> {
168168
pub(crate) valid_until: BlockNumber,
169169
}
170170

171+
impl<BlockNumber> TimeBoundDidSignature<BlockNumber> {
172+
pub fn new(signature: DidSignature, valid_until: BlockNumber) -> Self {
173+
Self { signature, valid_until }
174+
}
175+
}
176+
171177
#[cfg(feature = "runtime-benchmarks")]
172178
impl<BlockNumber, Context> kilt_support::traits::GetWorstCase<Context> for TimeBoundDidSignature<BlockNumber>
173179
where
@@ -770,6 +776,38 @@ pub struct DipDidProofWithVerifiedSubjectCommitment<
770776
pub(crate) signature: TimeBoundDidSignature<ConsumerBlockNumber>,
771777
}
772778

779+
impl<
780+
Commitment,
781+
KiltDidKeyId,
782+
KiltAccountId,
783+
KiltBlockNumber,
784+
KiltWeb3Name,
785+
KiltLinkableAccountId,
786+
ConsumerBlockNumber,
787+
>
788+
DipDidProofWithVerifiedSubjectCommitment<
789+
Commitment,
790+
KiltDidKeyId,
791+
KiltAccountId,
792+
KiltBlockNumber,
793+
KiltWeb3Name,
794+
KiltLinkableAccountId,
795+
ConsumerBlockNumber,
796+
>
797+
{
798+
pub fn new(
799+
dip_commitment: Commitment,
800+
dip_proof: DidMerkleProof<KiltDidKeyId, KiltAccountId, KiltBlockNumber, KiltWeb3Name, KiltLinkableAccountId>,
801+
signature: TimeBoundDidSignature<ConsumerBlockNumber>,
802+
) -> Self {
803+
Self {
804+
dip_commitment,
805+
dip_proof,
806+
signature,
807+
}
808+
}
809+
}
810+
773811
impl<
774812
Commitment,
775813
KiltDidKeyId,
@@ -1164,7 +1202,7 @@ impl<
11641202
}
11651203

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

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

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

13001338
/// The details of an account after it has been successfully verified in a
13011339
/// Merkle proof.
1302-
#[derive(Clone, Copy, Debug, Encode, Decode, PartialEq, Eq, TypeInfo, MaxEncodedLen)]
1340+
#[derive(Clone, Copy, Debug, Encode, Decode, PartialEq, Eq, PartialOrd, Ord, TypeInfo, MaxEncodedLen)]
13031341
pub struct RevealedAccountId<AccountId>(pub AccountId);

dip-template/runtimes/dip-consumer/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ std = [
112112
"pallet-collator-selection/std",
113113
"parachain-info/std",
114114
"rococo-runtime/std",
115-
"frame-benchmarking/std",
115+
"frame-benchmarking?/std",
116116
"frame-system-benchmarking?/std",
117117
]
118118

pallets/did/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1463,7 +1463,7 @@ pub mod pallet {
14631463
/// Deletes DID details from storage, including its linked service
14641464
/// endpoints, adds the identifier to the blacklisted DIDs and frees the
14651465
/// deposit.
1466-
pub(crate) fn delete_did(did_subject: DidIdentifierOf<T>, endpoints_to_remove: u32) -> DispatchResult {
1466+
pub fn delete_did(did_subject: DidIdentifierOf<T>, endpoints_to_remove: u32) -> DispatchResult {
14671467
let current_endpoints_count = DidEndpointsCount::<T>::get(&did_subject);
14681468
ensure!(
14691469
current_endpoints_count <= endpoints_to_remove,
Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
// KILT Blockchain – https://botlabs.org
2+
// Copyright (C) 2019-2024 BOTLabs GmbH
3+
4+
// The KILT Blockchain is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU General Public License as published by
6+
// the Free Software Foundation, either version 3 of the License, or
7+
// (at your option) any later version.
8+
9+
// The KILT Blockchain is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU General Public License for more details.
13+
14+
// You should have received a copy of the GNU General Public License
15+
// along with this program. If not, see <https://www.gnu.org/licenses/>.
16+
17+
// If you feel like getting in touch with us, you can do so at info@botlabs.org
18+
19+
use frame_support::{
20+
construct_runtime,
21+
sp_runtime::{
22+
testing::H256,
23+
traits::{BlakeTwo256, IdentityLookup},
24+
AccountId32,
25+
},
26+
traits::{ConstU128, ConstU16, ConstU32, ConstU64, Currency, Everything, Get},
27+
};
28+
use frame_system::{mocking::MockBlock, EnsureSigned};
29+
use pallet_dip_provider::{DefaultIdentityCommitmentGenerator, DefaultIdentityProvider, IdentityCommitmentVersion};
30+
use parity_scale_codec::{Decode, Encode, MaxEncodedLen};
31+
use scale_info::TypeInfo;
32+
use sp_runtime::RuntimeDebug;
33+
34+
use crate::{
35+
self as storage_deposit_pallet, DepositEntryOf, DepositKeyOf, FixedDepositCollectorViaDepositsPallet, Pallet,
36+
};
37+
38+
pub(crate) type Balance = u128;
39+
40+
#[derive(Encode, Decode, MaxEncodedLen, TypeInfo, Clone, PartialEq, Eq, RuntimeDebug, Default)]
41+
pub enum DepositNamespaces {
42+
#[default]
43+
ExampleNamespace,
44+
}
45+
46+
impl Get<DepositNamespaces> for DepositNamespaces {
47+
fn get() -> DepositNamespaces {
48+
Self::ExampleNamespace
49+
}
50+
}
51+
52+
construct_runtime!(
53+
pub struct TestRuntime {
54+
System: frame_system,
55+
Balances: pallet_balances,
56+
DipProvider: pallet_dip_provider,
57+
StorageDepositPallet: storage_deposit_pallet,
58+
}
59+
);
60+
61+
pub(crate) const SUBJECT: AccountId32 = AccountId32::new([100u8; 32]);
62+
pub(crate) const SUBMITTER: AccountId32 = AccountId32::new([200u8; 32]);
63+
64+
impl frame_system::Config for TestRuntime {
65+
type AccountData = pallet_balances::AccountData<Balance>;
66+
type AccountId = AccountId32;
67+
type BaseCallFilter = Everything;
68+
type Block = MockBlock<TestRuntime>;
69+
type BlockHashCount = ConstU64<256>;
70+
type BlockLength = ();
71+
type BlockWeights = ();
72+
type DbWeight = ();
73+
type Hash = H256;
74+
type Hashing = BlakeTwo256;
75+
type Lookup = IdentityLookup<Self::AccountId>;
76+
type MaxConsumers = ConstU32<16>;
77+
type Nonce = u64;
78+
type OnKilledAccount = ();
79+
type OnNewAccount = ();
80+
type OnSetCode = ();
81+
type PalletInfo = PalletInfo;
82+
type RuntimeCall = RuntimeCall;
83+
type RuntimeEvent = RuntimeEvent;
84+
type RuntimeOrigin = RuntimeOrigin;
85+
type SS58Prefix = ConstU16<1>;
86+
type SystemWeightInfo = ();
87+
type Version = ();
88+
}
89+
90+
impl pallet_balances::Config for TestRuntime {
91+
type FreezeIdentifier = RuntimeFreezeReason;
92+
type RuntimeHoldReason = RuntimeHoldReason;
93+
type MaxFreezes = ConstU32<50>;
94+
type MaxHolds = ConstU32<50>;
95+
type Balance = Balance;
96+
type DustRemoval = ();
97+
type RuntimeEvent = RuntimeEvent;
98+
type ExistentialDeposit = ConstU128<500>;
99+
type AccountStore = System;
100+
type WeightInfo = ();
101+
type MaxLocks = ConstU32<50>;
102+
type MaxReserves = ConstU32<50>;
103+
type ReserveIdentifier = [u8; 8];
104+
}
105+
106+
pub(crate) type DepositCollectorHook<Runtime> = FixedDepositCollectorViaDepositsPallet<
107+
DepositNamespaces,
108+
ConstU128<1_000>,
109+
(
110+
<Runtime as pallet_dip_provider::Config>::Identifier,
111+
AccountId32,
112+
IdentityCommitmentVersion,
113+
),
114+
>;
115+
116+
impl pallet_dip_provider::Config for TestRuntime {
117+
type CommitOrigin = AccountId32;
118+
type CommitOriginCheck = EnsureSigned<AccountId32>;
119+
type Identifier = AccountId32;
120+
type IdentityCommitmentGenerator = DefaultIdentityCommitmentGenerator<u32>;
121+
type IdentityProvider = DefaultIdentityProvider<u32>;
122+
type ProviderHooks = DepositCollectorHook<Self>;
123+
type RuntimeEvent = RuntimeEvent;
124+
type WeightInfo = ();
125+
}
126+
127+
impl crate::Config for TestRuntime {
128+
type CheckOrigin = EnsureSigned<Self::AccountId>;
129+
type Currency = Balances;
130+
type DepositHooks = ();
131+
type RuntimeEvent = RuntimeEvent;
132+
type RuntimeHoldReason = RuntimeHoldReason;
133+
type MaxKeyLength = ConstU32<256>;
134+
type Namespace = DepositNamespaces;
135+
#[cfg(feature = "runtime-benchmarks")]
136+
type BenchmarkHooks = ();
137+
type WeightInfo = ();
138+
}
139+
140+
#[derive(Default)]
141+
pub(crate) struct ExtBuilder(
142+
Vec<(AccountId32, Balance)>,
143+
Vec<(DepositKeyOf<TestRuntime>, DepositEntryOf<TestRuntime>)>,
144+
);
145+
146+
impl ExtBuilder {
147+
pub(crate) fn with_balances(mut self, balances: Vec<(AccountId32, Balance)>) -> Self {
148+
self.0 = balances;
149+
self
150+
}
151+
152+
pub(crate) fn with_deposits(
153+
mut self,
154+
deposits: Vec<(DepositKeyOf<TestRuntime>, DepositEntryOf<TestRuntime>)>,
155+
) -> Self {
156+
self.1 = deposits;
157+
self
158+
}
159+
160+
pub(crate) fn build(self) -> sp_io::TestExternalities {
161+
let mut ext = sp_io::TestExternalities::default();
162+
163+
ext.execute_with(|| {
164+
for (account, balance) in self.0 {
165+
Balances::make_free_balance_be(&account, balance);
166+
}
167+
168+
for (deposit_key, deposit_entry) in self.1 {
169+
// Add existential deposit + deposit amount.
170+
Balances::make_free_balance_be(&deposit_entry.deposit.owner, 500 + deposit_entry.deposit.amount);
171+
Pallet::<TestRuntime>::add_deposit(DepositNamespaces::get(), deposit_key, deposit_entry).unwrap();
172+
}
173+
});
174+
175+
ext
176+
}
177+
}

pallets/pallet-deposit-storage/src/deposit.rs renamed to pallets/pallet-deposit-storage/src/deposit/mod.rs

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,11 @@ use sp_std::marker::PhantomData;
3232

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

35+
#[cfg(test)]
36+
mod mock;
37+
#[cfg(test)]
38+
mod tests;
39+
3540
/// Details associated to an on-chain deposit.
3641
#[derive(Clone, Debug, Encode, Decode, Eq, PartialEq, Ord, PartialOrd, TypeInfo, MaxEncodedLen)]
3742
pub struct DepositEntry<AccountId, Balance, Reason> {
@@ -107,11 +112,12 @@ where
107112
},
108113
reason: HoldReason::Deposit.into(),
109114
};
110-
Pallet::<Runtime>::add_deposit(namespace, key, deposit_entry).map_err(|e| match e {
111-
pallet_error if pallet_error == DispatchError::from(Error::<Runtime>::DepositExisting) => {
115+
Pallet::<Runtime>::add_deposit(namespace, key, deposit_entry).map_err(|e| {
116+
if e == DispatchError::from(Error::<Runtime>::DepositExisting) {
112117
FixedDepositCollectorViaDepositsPalletError::DepositAlreadyTaken
113-
}
114-
_ => {
118+
} else if e == DispatchError::from(Error::<Runtime>::FailedToHold) {
119+
FixedDepositCollectorViaDepositsPalletError::FailedToHold
120+
} else {
115121
log::error!(
116122
"Error {:#?} should not be generated inside `on_identity_committed` hook.",
117123
e
@@ -140,11 +146,15 @@ where
140146
);
141147
FixedDepositCollectorViaDepositsPalletError::Internal
142148
})?;
143-
Pallet::<Runtime>::remove_deposit(&namespace, &key, None).map_err(|e| match e {
144-
pallet_error if pallet_error == DispatchError::from(Error::<Runtime>::DepositNotFound) => {
149+
// We don't set any expected owner for the deposit on purpose, since this hook
150+
// assumes the dip-provider pallet has performed all the access control logic
151+
// necessary.
152+
Pallet::<Runtime>::remove_deposit(&namespace, &key, None).map_err(|e| {
153+
if e == DispatchError::from(Error::<Runtime>::DepositNotFound) {
145154
FixedDepositCollectorViaDepositsPalletError::DepositNotFound
146-
}
147-
_ => {
155+
} else if e == DispatchError::from(Error::<Runtime>::FailedToRelease) {
156+
FixedDepositCollectorViaDepositsPalletError::FailedToRelease
157+
} else {
148158
log::error!(
149159
"Error {:#?} should not be generated inside `on_commitment_removed` hook.",
150160
e
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// KILT Blockchain – https://botlabs.org
2+
// Copyright (C) 2019-2024 BOTLabs GmbH
3+
4+
// The KILT Blockchain is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU General Public License as published by
6+
// the Free Software Foundation, either version 3 of the License, or
7+
// (at your option) any later version.
8+
9+
// The KILT Blockchain is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU General Public License for more details.
13+
14+
// You should have received a copy of the GNU General Public License
15+
// along with this program. If not, see <https://www.gnu.org/licenses/>.
16+
17+
// If you feel like getting in touch with us, you can do so at info@botlabs.org
18+
19+
mod on_commitment_removed;
20+
mod on_identity_committed;

0 commit comments

Comments
 (0)