From bd7a8497b43bb5fe07e505cdd8d99bef967c4674 Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Mon, 20 Jan 2025 10:28:52 +0100 Subject: [PATCH 1/4] Add new methods to DID runtime APIs --- runtime-api/did/src/lib.rs | 11 +++++++-- runtimes/common/src/did/mod.rs | 20 ++++++++++++++++ runtimes/common/src/did/runtime_apis.rs | 28 ++++++++++++++++++++++ runtimes/common/src/lib.rs | 1 + runtimes/peregrine/src/runtime_apis.rs | 32 ++++++++++++++++++++++--- 5 files changed, 87 insertions(+), 5 deletions(-) create mode 100644 runtimes/common/src/did/mod.rs create mode 100644 runtimes/common/src/did/runtime_apis.rs diff --git a/runtime-api/did/src/lib.rs b/runtime-api/did/src/lib.rs index 4f775a5464..85555ed175 100644 --- a/runtime-api/did/src/lib.rs +++ b/runtime-api/did/src/lib.rs @@ -66,14 +66,16 @@ pub type RawDidLinkedInfo; sp_api::decl_runtime_apis! { - #[api_version(3)] - pub trait Did where + #[api_version(4)] + pub trait Did where DidIdentifier: Codec, AccountId: Codec, LinkableAccountId: Codec, BlockNumber: Codec, Key: Codec, Balance: Codec, + LinkedResource: Codec, + RuntimeCall: Codec, { /// Given a web3name this returns: /// * the DID @@ -111,5 +113,10 @@ sp_api::decl_runtime_apis! { /// Allows for batching multiple `query` requests into one. For each requested name, the corresponding vector entry contains either `Some` or `None` depending on the result of each query. #[allow(clippy::type_complexity)] fn batch_query(dids: Vec) -> Vec>>; + + /// Returns the list of linked resources for a given DID that must be deleted before the DID itself can be deleted. + fn linked_resources(did: DidIdentifier) -> Vec; + /// Returns the list of calls that must be executed to delete the linked resources of a given DID, before deleting the DID itself. + fn get_linked_resources_deletion_calls(did: DidIdentifier) -> Vec; } } diff --git a/runtimes/common/src/did/mod.rs b/runtimes/common/src/did/mod.rs new file mode 100644 index 0000000000..923044f900 --- /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 + +pub mod runtime_apis; +pub use runtime_apis::LinkedDidResource; diff --git a/runtimes/common/src/did/runtime_apis.rs b/runtimes/common/src/did/runtime_apis.rs new file mode 100644 index 0000000000..5ae1465ea5 --- /dev/null +++ b/runtimes/common/src/did/runtime_apis.rs @@ -0,0 +1,28 @@ +// 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::{Decode, Encode}; +use scale_info::TypeInfo; + +#[derive(Debug, Encode, Decode, TypeInfo, PartialEq, Eq, PartialOrd, Ord)] +pub enum LinkedDidResource { + Web3Name(Web3Name), + DotName(DotName), + Account(LinkableAccountId), +} diff --git a/runtimes/common/src/lib.rs b/runtimes/common/src/lib.rs index 841cead22b..e68542ee16 100644 --- a/runtimes/common/src/lib.rs +++ b/runtimes/common/src/lib.rs @@ -49,6 +49,7 @@ pub mod authorization; pub mod bonded_coins; pub mod constants; pub mod deposits; +pub mod did; pub mod dip; pub mod dot_names; pub use dot_names::DotName; diff --git a/runtimes/peregrine/src/runtime_apis.rs b/runtimes/peregrine/src/runtime_apis.rs index 8184e101aa..3a94ea2736 100644 --- a/runtimes/peregrine/src/runtime_apis.rs +++ b/runtimes/peregrine/src/runtime_apis.rs @@ -43,6 +43,7 @@ use runtime_common::{ AssetId as BondedAssetId, FixedPoint, FixedPointUnderlyingType, }, constants::SLOT_DURATION, + did::LinkedDidResource, dip::merkle::{CompleteMerkleProof, DidMerkleProofOf, DidMerkleRootGenerator}, errors::PublicCredentialsApiError, AccountId, AuthorityId, Balance, BlockNumber, DidIdentifier, Hash, Nonce, @@ -60,12 +61,15 @@ use sp_version::{ApisVec, RuntimeVersion}; use unique_linking_runtime_api::{AddressResult, NameResult}; use crate::{ - kilt::{DipProofError, DipProofRequest, DotName, NativeAndForeignAssets, UniqueLinkingDeployment}, + kilt::{ + did::DotNamesDeployment, DipProofError, DipProofRequest, DotName, NativeAndForeignAssets, + UniqueLinkingDeployment, + }, parachain::ConsensusHook, xcm::UniversalLocation, AssetSwitchPool1, Aura, Block, BondedCurrencies, BondedFungibles, DotNames, Executive, InherentDataExt, ParachainStaking, ParachainSystem, Runtime, RuntimeCall, RuntimeGenesisConfig, SessionKeys, TransactionPayment, - UniqueLinking, VERSION, + UniqueLinking, Web3Name, VERSION, }; // This is necessary since by default `RUNTIME_API_VERSIONS` generated by @@ -258,7 +262,9 @@ impl_runtime_apis! { LinkableAccountId, Balance, Hash, - BlockNumber + BlockNumber, + LinkedDidResource, + RuntimeCall > for Runtime { fn query_by_web3_name(name: Vec) -> Option> { dids.into_iter().map(Self::query).collect() } + + fn linked_resources(did: DidIdentifier) -> Vec> { + let web3_name = pallet_web3_names::Names::::get(&did); + let dot_name = pallet_web3_names::Names::::get(&did); + let web3_name_accounts = pallet_did_lookup::ConnectedAccounts::::iter_key_prefix(&did); + let dot_name_account = pallet_did_lookup::ConnectedAccounts::::get(&did); + + debug_assert!(dot_name_account.len() <= 1, "Found more than a single linked account to a Dotname."); + + sp_std::iter::once(web3_name.map(LinkedDidResource::Web3Name)) + .chain(sp_std::iter::once(dot_name.map(LinkedDidResource::DotName))) + .chain(web3_name_accounts.map(LinkedDidResource::Account)) + .chain(dot_name_account.map(LinkedDidResource::Account)) + .flatten() + .collect() + } + + fn get_linked_resources_deletion_calls(did: DidIdentifier) -> Vec { + unimplemented!() + } } impl kilt_runtime_api_public_credentials::PublicCredentials, Hash, CredentialEntry::DelegationNodeId>>, PublicCredentialsFilter, PublicCredentialsApiError> for Runtime { From e8384315ae9abb84ef2a5d1623f32fd338fe8f98 Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Mon, 20 Jan 2025 14:37:43 +0100 Subject: [PATCH 2/4] Finalize runtimes --- runtime-api/did/src/lib.rs | 2 +- runtimes/common/src/did/mod.rs | 1 - runtimes/common/src/did/runtime_apis.rs | 8 +++- runtimes/peregrine/src/runtime_apis.rs | 54 +++++++++++++++++-------- runtimes/spiritnet/src/runtime_apis.rs | 51 +++++++++++++++++++++-- 5 files changed, 92 insertions(+), 24 deletions(-) diff --git a/runtime-api/did/src/lib.rs b/runtime-api/did/src/lib.rs index 85555ed175..6814573abd 100644 --- a/runtime-api/did/src/lib.rs +++ b/runtime-api/did/src/lib.rs @@ -117,6 +117,6 @@ sp_api::decl_runtime_apis! { /// Returns the list of linked resources for a given DID that must be deleted before the DID itself can be deleted. fn linked_resources(did: DidIdentifier) -> Vec; /// Returns the list of calls that must be executed to delete the linked resources of a given DID, before deleting the DID itself. - fn get_linked_resources_deletion_calls(did: DidIdentifier) -> Vec; + fn linked_resources_deletion_calls(did: DidIdentifier) -> Vec; } } diff --git a/runtimes/common/src/did/mod.rs b/runtimes/common/src/did/mod.rs index 923044f900..317c7eceb3 100644 --- a/runtimes/common/src/did/mod.rs +++ b/runtimes/common/src/did/mod.rs @@ -17,4 +17,3 @@ // If you feel like getting in touch with us, you can do so at info@botlabs.org pub mod runtime_apis; -pub use runtime_apis::LinkedDidResource; diff --git a/runtimes/common/src/did/runtime_apis.rs b/runtimes/common/src/did/runtime_apis.rs index 5ae1465ea5..eceb76c2bb 100644 --- a/runtimes/common/src/did/runtime_apis.rs +++ b/runtimes/common/src/did/runtime_apis.rs @@ -20,9 +20,15 @@ use pallet_did_lookup::linkable_account::LinkableAccountId; use parity_scale_codec::{Decode, Encode}; use scale_info::TypeInfo; +/// The kind of resources that can be linked to a DID, preventing its deletion. #[derive(Debug, Encode, Decode, TypeInfo, PartialEq, Eq, PartialOrd, Ord)] pub enum LinkedDidResource { + /// A Web3name. Web3Name(Web3Name), + /// A Dotname. DotName(DotName), - Account(LinkableAccountId), + /// An account linked to the DID and resolvable by or to a Web3name. + Web3NameAccount(LinkableAccountId), + /// An account linked to the DID and resolvable by or to a Dotname. + DotNameAccount(LinkableAccountId), } diff --git a/runtimes/peregrine/src/runtime_apis.rs b/runtimes/peregrine/src/runtime_apis.rs index 3a94ea2736..d007d0c38d 100644 --- a/runtimes/peregrine/src/runtime_apis.rs +++ b/runtimes/peregrine/src/runtime_apis.rs @@ -43,7 +43,7 @@ use runtime_common::{ AssetId as BondedAssetId, FixedPoint, FixedPointUnderlyingType, }, constants::SLOT_DURATION, - did::LinkedDidResource, + did::runtime_apis::LinkedDidResource, dip::merkle::{CompleteMerkleProof, DidMerkleProofOf, DidMerkleRootGenerator}, errors::PublicCredentialsApiError, AccountId, AuthorityId, Balance, BlockNumber, DidIdentifier, Hash, Nonce, @@ -56,7 +56,7 @@ use sp_runtime::{ traits::{Block as BlockT, TryConvert}, ApplyExtrinsicResult, KeyTypeId, SaturatedConversion, }; -use sp_std::{prelude::*, str::FromStr, vec::Vec}; +use sp_std::{iter, prelude::*, str::FromStr, vec::Vec}; use sp_version::{ApisVec, RuntimeVersion}; use unique_linking_runtime_api::{AddressResult, NameResult}; @@ -388,23 +388,12 @@ impl_runtime_apis! { } fn linked_resources(did: DidIdentifier) -> Vec> { - let web3_name = pallet_web3_names::Names::::get(&did); - let dot_name = pallet_web3_names::Names::::get(&did); - let web3_name_accounts = pallet_did_lookup::ConnectedAccounts::::iter_key_prefix(&did); - let dot_name_account = pallet_did_lookup::ConnectedAccounts::::get(&did); - - debug_assert!(dot_name_account.len() <= 1, "Found more than a single linked account to a Dotname."); - - sp_std::iter::once(web3_name.map(LinkedDidResource::Web3Name)) - .chain(sp_std::iter::once(dot_name.map(LinkedDidResource::DotName))) - .chain(web3_name_accounts.map(LinkedDidResource::Account)) - .chain(dot_name_account.map(LinkedDidResource::Account)) - .flatten() - .collect() + linked_resources_for_did(&did).collect() } - fn get_linked_resources_deletion_calls(did: DidIdentifier) -> Vec { - unimplemented!() + fn linked_resources_deletion_calls(did: DidIdentifier) -> Vec { + let linked_resources = linked_resources_for_did(&did); + linked_resources.map(map_linked_resource_to_call).collect() } } @@ -705,3 +694,34 @@ impl_runtime_apis! { } } } + +/// Returns an iterator over all linked resources for a given DID. +fn linked_resources_for_did(did: &DidIdentifier) -> impl Iterator> { + let web3_name = pallet_web3_names::Names::::get(did); + let dot_name = pallet_web3_names::Names::::get(did); + let web3_name_accounts = pallet_did_lookup::ConnectedAccounts::::iter_key_prefix(did); + let dot_name_accounts = + pallet_did_lookup::ConnectedAccounts::::iter_key_prefix(did); + + iter::once(web3_name.map(LinkedDidResource::Web3Name)) + .chain(iter::once(dot_name.map(LinkedDidResource::DotName))) + .chain(web3_name_accounts.map(|acc| Some(LinkedDidResource::Web3NameAccount(acc)))) + .chain(dot_name_accounts.map(|acc| Some(LinkedDidResource::DotNameAccount(acc)))) + .flatten() +} + +/// Creates a `RuntimeCall` that, if submitted by the owner DID, +/// would remove the provided linked resource. +fn map_linked_resource_to_call(resource: LinkedDidResource) -> RuntimeCall { + match resource { + LinkedDidResource::Web3Name(_) => RuntimeCall::Web3Names(pallet_web3_names::Call::release_by_owner {}), + + LinkedDidResource::DotName(_) => RuntimeCall::DotNames(pallet_web3_names::Call::release_by_owner {}), + LinkedDidResource::Web3NameAccount(account) => { + RuntimeCall::DidLookup(pallet_did_lookup::Call::remove_account_association { account }) + } + LinkedDidResource::DotNameAccount(account) => { + RuntimeCall::UniqueLinking(pallet_did_lookup::Call::remove_account_association { account }) + } + } +} diff --git a/runtimes/spiritnet/src/runtime_apis.rs b/runtimes/spiritnet/src/runtime_apis.rs index 804f2a5e7e..bb7022aa54 100644 --- a/runtimes/spiritnet/src/runtime_apis.rs +++ b/runtimes/spiritnet/src/runtime_apis.rs @@ -21,7 +21,7 @@ use sp_runtime::{ traits::{Block as BlockT, TryConvert}, ApplyExtrinsicResult, KeyTypeId, }; -use sp_std::vec::Vec; +use sp_std::{iter, vec::Vec}; use sp_version::{ApisVec, RuntimeVersion}; use kilt_runtime_api_did::RawDidLinkedInfo; @@ -36,6 +36,7 @@ use runtime_common::{ assets::{AssetDid, PublicCredentialsFilter}, authorization::AuthorizationId, constants::SLOT_DURATION, + did::runtime_apis::LinkedDidResource, dip::merkle::{CompleteMerkleProof, DidMerkleProofOf, DidMerkleRootGenerator}, errors::PublicCredentialsApiError, AccountId, AuthorityId, Balance, BlockNumber, DidIdentifier, Hash, Nonce, @@ -43,11 +44,11 @@ use runtime_common::{ use unique_linking_runtime_api::{AddressResult, NameResult}; use crate::{ - kilt::{DipProofError, DipProofRequest, DotName, UniqueLinkingDeployment}, + kilt::{did::DotNamesDeployment, DipProofError, DipProofRequest, DotName, UniqueLinkingDeployment}, parachain::ConsensusHook, xcm::UniversalLocation, AssetSwitchPool1, Aura, Block, DotNames, Executive, InherentDataExt, ParachainStaking, ParachainSystem, Runtime, - RuntimeCall, RuntimeGenesisConfig, SessionKeys, TransactionPayment, UniqueLinking, VERSION, + RuntimeCall, RuntimeGenesisConfig, SessionKeys, TransactionPayment, UniqueLinking, Web3Name, VERSION, }; // This is necessary since by default `RUNTIME_API_VERSIONS` generated by @@ -240,7 +241,9 @@ impl_runtime_apis! { LinkableAccountId, Balance, Hash, - BlockNumber + BlockNumber, + LinkedDidResource, + RuntimeCall > for Runtime { fn query_by_web3_name(name: Vec) -> Option> { dids.into_iter().map(Self::query).collect() } + + fn linked_resources(did: DidIdentifier) -> Vec> { + linked_resources_for_did(&did).collect() + } + + fn linked_resources_deletion_calls(did: DidIdentifier) -> Vec { + let linked_resources = linked_resources_for_did(&did); + linked_resources.map(map_linked_resource_to_call).collect() + } } impl kilt_runtime_api_public_credentials::PublicCredentials, Hash, CredentialEntry::DelegationNodeId>>, PublicCredentialsFilter, PublicCredentialsApiError> for Runtime { @@ -512,3 +524,34 @@ impl_runtime_apis! { } } } + +/// Returns an iterator over all linked resources for a given DID. +fn linked_resources_for_did(did: &DidIdentifier) -> impl Iterator> { + let web3_name = pallet_web3_names::Names::::get(did); + let dot_name = pallet_web3_names::Names::::get(did); + let web3_name_accounts = pallet_did_lookup::ConnectedAccounts::::iter_key_prefix(did); + let dot_name_accounts = + pallet_did_lookup::ConnectedAccounts::::iter_key_prefix(did); + + iter::once(web3_name.map(LinkedDidResource::Web3Name)) + .chain(iter::once(dot_name.map(LinkedDidResource::DotName))) + .chain(web3_name_accounts.map(|acc| Some(LinkedDidResource::Web3NameAccount(acc)))) + .chain(dot_name_accounts.map(|acc| Some(LinkedDidResource::DotNameAccount(acc)))) + .flatten() +} + +/// Creates a `RuntimeCall` that, if submitted by the owner DID, +/// would remove the provided linked resource. +fn map_linked_resource_to_call(resource: LinkedDidResource) -> RuntimeCall { + match resource { + LinkedDidResource::Web3Name(_) => RuntimeCall::Web3Names(pallet_web3_names::Call::release_by_owner {}), + + LinkedDidResource::DotName(_) => RuntimeCall::DotNames(pallet_web3_names::Call::release_by_owner {}), + LinkedDidResource::Web3NameAccount(account) => { + RuntimeCall::DidLookup(pallet_did_lookup::Call::remove_account_association { account }) + } + LinkedDidResource::DotNameAccount(account) => { + RuntimeCall::UniqueLinking(pallet_did_lookup::Call::remove_account_association { account }) + } + } +} From 3fe401d20aecb5eb14736dfe17ea21d3f6b8bb9a Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Mon, 20 Jan 2025 14:50:55 +0100 Subject: [PATCH 3/4] Kestrel runtime ready --- runtimes/kestrel/src/lib.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/runtimes/kestrel/src/lib.rs b/runtimes/kestrel/src/lib.rs index cdcae041eb..7db12c6e8c 100644 --- a/runtimes/kestrel/src/lib.rs +++ b/runtimes/kestrel/src/lib.rs @@ -1011,7 +1011,9 @@ impl_runtime_apis! { LinkableAccountId, Balance, Hash, - BlockNumber + BlockNumber, + (), + () > for Runtime { fn query_by_web3_name(name: Vec) -> Option> { dids.into_iter().map(Self::query).collect() } + + // We don't return anything here, since the runtime does not require the resources to be cleaned up. + fn linked_resources(_did: DidIdentifier) -> Vec<()> { + [].into() + } + + // We don't return anything here, since the runtime does not require the resources to be cleaned up. + fn linked_resources_deletion_calls(_did: DidIdentifier) -> Vec<()> { + [].into() + } } impl kilt_runtime_api_public_credentials::PublicCredentials, Hash, public_credentials::CredentialEntry::DelegationNodeId>>, PublicCredentialsFilter, PublicCredentialsApiError> for Runtime { From 2483ab0ffbc17be7999556903b290b261fdbb53d Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Tue, 21 Jan 2025 10:43:41 +0100 Subject: [PATCH 4/4] Fix DIP template runtime --- dip-template/runtimes/dip-provider/src/lib.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/dip-template/runtimes/dip-provider/src/lib.rs b/dip-template/runtimes/dip-provider/src/lib.rs index 15e2596d1d..7333419eef 100644 --- a/dip-template/runtimes/dip-provider/src/lib.rs +++ b/dip-template/runtimes/dip-provider/src/lib.rs @@ -633,7 +633,9 @@ impl_runtime_apis! { LinkableAccountId, Balance, Hash, - BlockNumber + BlockNumber, + (), + () > for Runtime { fn query_by_web3_name(name: Vec) -> Option> { dids.into_iter().map(Self::query).collect() } + + // We don't return anything here, since the runtime does not require the resources to be cleaned up. + fn linked_resources(_did: DidIdentifier) -> Vec<()> { + [].into() + } + + // We don't return anything here, since the runtime does not require the resources to be cleaned up. + fn linked_resources_deletion_calls(_did: DidIdentifier) -> Vec<()> { + [].into() + } } impl kilt_runtime_api_dip_provider::DipProvider>, runtime_api::DipProofError> for Runtime {