From 1ca466e881d53c89bced3a09306356992a775b88 Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Wed, 17 May 2023 09:35:27 +0200 Subject: [PATCH 01/15] Change IdentityProvider trait to use associated type --- dip-template/runtimes/dip-provider/src/lib.rs | 2 +- pallets/pallet-dip-provider/src/lib.rs | 4 ++-- pallets/pallet-dip-provider/src/traits.rs | 21 +++++++++++-------- runtimes/common/src/dip/did.rs | 7 ++++--- 4 files changed, 19 insertions(+), 15 deletions(-) diff --git a/dip-template/runtimes/dip-provider/src/lib.rs b/dip-template/runtimes/dip-provider/src/lib.rs index b986a95e57..5a8625789b 100644 --- a/dip-template/runtimes/dip-provider/src/lib.rs +++ b/dip-template/runtimes/dip-provider/src/lib.rs @@ -534,7 +534,7 @@ impl_runtime_apis! { // TODO: Support generating different versions of the proof, based on the provided parameter impl kilt_runtime_api_dip_provider::DipProvider, Vec>, CompleteMerkleProof>, ()> for Runtime { fn generate_proof(identifier: DidIdentifier, keys: Vec>) -> Result>, ()> { - if let Ok(Some((did_details, _))) = ::IdentityProvider::retrieve(&identifier) { + if let Ok(Some(did_details)) = ::IdentityProvider::retrieve(&identifier) { DidMerkleRootGenerator::::generate_proof(&did_details, keys.iter()) } else { Err(()) diff --git a/pallets/pallet-dip-provider/src/lib.rs b/pallets/pallet-dip-provider/src/lib.rs index c826d191a7..6e722924b6 100644 --- a/pallets/pallet-dip-provider/src/lib.rs +++ b/pallets/pallet-dip-provider/src/lib.rs @@ -52,7 +52,7 @@ pub mod pallet { Output = Self::ProofOutput, >; type IdentityProofDispatcher: IdentityProofDispatcher; - type IdentityProvider: IdentityProvider; + type IdentityProvider: IdentityProvider; type RuntimeEvent: From> + IsType<::RuntimeEvent>; type TxBuilder: TxBuilder; } @@ -99,7 +99,7 @@ pub mod pallet { let destination: MultiLocation = (*destination).try_into().map_err(|_| Error::::BadVersion)?; let action: IdentityProofActionOf = match T::IdentityProvider::retrieve(&identifier) { - Ok(Some((identity, _))) => { + Ok(Some(identity)) => { let identity_proof = T::IdentityProofGenerator::generate_commitment(&identifier, &identity) .map_err(|_| Error::::IdentityProofGeneration)?; Ok(IdentityProofAction::Updated(identifier, identity_proof, ())) diff --git a/pallets/pallet-dip-provider/src/traits.rs b/pallets/pallet-dip-provider/src/traits.rs index fd9b90d046..2f339bed42 100644 --- a/pallets/pallet-dip-provider/src/traits.rs +++ b/pallets/pallet-dip-provider/src/traits.rs @@ -149,35 +149,38 @@ pub mod identity_dispatch { pub use identity_provision::*; pub mod identity_provision { + use sp_std::marker::PhantomData; - pub trait IdentityProvider { + pub trait IdentityProvider { type Error; + type Success; - fn retrieve(identifier: &Identifier) -> Result, Self::Error>; + fn retrieve(identifier: &Identifier) -> Result, Self::Error>; } // Return the `Default` value if `Identity` adn `Details` both implement it. - pub struct DefaultIdentityProvider; + pub struct DefaultIdentityProvider(PhantomData); - impl IdentityProvider for DefaultIdentityProvider + impl IdentityProvider for DefaultIdentityProvider where Identity: Default, - Details: Default, { type Error = (); + type Success = Identity; - fn retrieve(_identifier: &Identifier) -> Result, Self::Error> { - Ok(Some((Identity::default(), Details::default()))) + fn retrieve(_identifier: &Identifier) -> Result, Self::Error> { + Ok(Some(Identity::default())) } } // Always return `None`. Might be useful for tests. pub struct NoneIdentityProvider; - impl IdentityProvider for NoneIdentityProvider { + impl IdentityProvider for NoneIdentityProvider { type Error = (); + type Success = (); - fn retrieve(_identifier: &Identifier) -> Result, Self::Error> { + fn retrieve(_identifier: &Identifier) -> Result, Self::Error> { Ok(None) } } diff --git a/runtimes/common/src/dip/did.rs b/runtimes/common/src/dip/did.rs index e954f008e7..5a1f945d22 100644 --- a/runtimes/common/src/dip/did.rs +++ b/runtimes/common/src/dip/did.rs @@ -22,19 +22,20 @@ use sp_std::marker::PhantomData; pub struct DidIdentityProvider(PhantomData); -impl IdentityProvider, ()> for DidIdentityProvider +impl IdentityProvider for DidIdentityProvider where T: did::Config, { // TODO: Proper error handling type Error = (); + type Success = DidDetails; - fn retrieve(identifier: &T::DidIdentifier) -> Result, ())>, Self::Error> { + fn retrieve(identifier: &T::DidIdentifier) -> Result, Self::Error> { match ( did::Pallet::::get_did(identifier), did::Pallet::::get_deleted_did(identifier), ) { - (Some(details), _) => Ok(Some((details, ()))), + (Some(details), _) => Ok(Some(details)), (_, Some(_)) => Ok(None), _ => Err(()), } From 688fb78aa250a649828d425ec7fc0aac66625bc3 Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Wed, 17 May 2023 11:17:52 +0200 Subject: [PATCH 02/15] Compiling --- Cargo.lock | 4 ++ crates/kilt-dip-support/Cargo.toml | 2 + crates/kilt-dip-support/src/did.rs | 39 ++++++++++++++++ dip-template/runtimes/dip-provider/Cargo.toml | 8 ++++ dip-template/runtimes/dip-provider/src/dip.rs | 14 ++++-- dip-template/runtimes/dip-provider/src/lib.rs | 27 +++++++++++ runtimes/common/Cargo.toml | 6 ++- runtimes/common/src/dip/did.rs | 46 ++++++++++++++++++- runtimes/common/src/dip/merkle.rs | 38 ++++++++------- 9 files changed, 162 insertions(+), 22 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e51576ab80..26f8a5ab69 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2449,17 +2449,20 @@ dependencies = [ "frame-support", "frame-system", "frame-system-rpc-runtime-api", + "kilt-dip-support", "kilt-runtime-api-dip-provider", "pallet-aura", "pallet-authorship", "pallet-balances", "pallet-collator-selection", + "pallet-did-lookup", "pallet-dip-provider", "pallet-session", "pallet-sudo", "pallet-timestamp", "pallet-transaction-payment", "pallet-transaction-payment-rpc-runtime-api", + "pallet-web3-names", "pallet-xcm", "parachain-info", "parity-scale-codec", @@ -4220,6 +4223,7 @@ dependencies = [ "frame-support", "frame-system", "pallet-dip-consumer", + "pallet-dip-provider", "parity-scale-codec", "scale-info", "sp-core", diff --git a/crates/kilt-dip-support/Cargo.toml b/crates/kilt-dip-support/Cargo.toml index ebc86ee9b0..e06e17664e 100644 --- a/crates/kilt-dip-support/Cargo.toml +++ b/crates/kilt-dip-support/Cargo.toml @@ -14,6 +14,7 @@ version.workspace = true # Internal dependencies did.workspace = true pallet-dip-consumer.workspace = true +pallet-dip-provider.workspace = true # Parity dependencies parity-scale-codec = {workspace = true, features = ["derive"]} @@ -32,6 +33,7 @@ default = ["std"] std = [ "did/std", "pallet-dip-consumer/std", + "pallet-dip-provider/std", "parity-scale-codec/std", "scale-info/std", "frame-system/std", diff --git a/crates/kilt-dip-support/src/did.rs b/crates/kilt-dip-support/src/did.rs index 07bd50d2e6..4e425a3460 100644 --- a/crates/kilt-dip-support/src/did.rs +++ b/crates/kilt-dip-support/src/did.rs @@ -22,6 +22,7 @@ use did::{ }; use frame_support::ensure; use pallet_dip_consumer::{identity::IdentityDetails, traits::IdentityProofVerifier}; +use pallet_dip_provider::traits::IdentityProvider; use parity_scale_codec::{Decode, Encode}; use scale_info::TypeInfo; use sp_core::{ConstU64, Get, RuntimeDebug}; @@ -237,3 +238,41 @@ where Ok(did_signing_key) } } + +pub struct CombinedIdentityResult { + pub a: OutputA, + pub b: OutputB, + pub c: OutputC, +} + +pub struct CombineIdentityFrom(PhantomData<(A, B, C)>); + +impl IdentityProvider for CombineIdentityFrom +where + A: IdentityProvider, + B: IdentityProvider, + C: IdentityProvider, +{ + // TODO: Proper error handling + type Error = (); + type Success = CombinedIdentityResult, Option, Option>; + + fn retrieve(identifier: &Identifier) -> Result, Self::Error> { + match ( + A::retrieve(identifier), + B::retrieve(identifier), + C::retrieve(identifier), + ) { + // If no details is returned, return None for the whole result + (Ok(None), Ok(None), Ok(None)) => Ok(None), + // Otherwise, return `Some` or `None` depending on each result + (Ok(ok_a), Ok(ok_b), Ok(ok_c)) => Ok(Some(CombinedIdentityResult { + a: ok_a, + b: ok_b, + c: ok_c, + })), + // If any of them returns an `Err`, return an `Err` + _ => Err(()), + } + } +} diff --git a/dip-template/runtimes/dip-provider/Cargo.toml b/dip-template/runtimes/dip-provider/Cargo.toml index 77647b7d8d..39dc4acc45 100644 --- a/dip-template/runtimes/dip-provider/Cargo.toml +++ b/dip-template/runtimes/dip-provider/Cargo.toml @@ -20,8 +20,11 @@ scale-info = {workspace = true, features = ["derive"]} # DIP did.workspace = true dip-support.workspace = true +kilt-dip-support.workspace = true kilt-runtime-api-dip-provider.workspace = true +pallet-did-lookup.workspace = true pallet-dip-provider.workspace = true +pallet-web3-names.workspace = true runtime-common.workspace = true # Substrate @@ -76,8 +79,11 @@ std = [ "scale-info/std", "did/std", "dip-support/std", + "kilt-dip-support/std", "kilt-runtime-api-dip-provider/std", + "pallet-did-lookup/std", "pallet-dip-provider/std", + "pallet-web3-names/std", "runtime-common/std", "frame-executive/std", "frame-support/std", @@ -119,7 +125,9 @@ std = [ ] runtime-benchmarks = [ "did/runtime-benchmarks", + "pallet-did-lookup/runtime-benchmarks", "pallet-dip-provider/runtime-benchmarks", + "pallet-web3-names/runtime-benchmarks", "runtime-common/runtime-benchmarks", "frame-system/runtime-benchmarks", "frame-support/runtime-benchmarks", diff --git a/dip-template/runtimes/dip-provider/src/dip.rs b/dip-template/runtimes/dip-provider/src/dip.rs index e358eff8a5..f5147b9ef0 100644 --- a/dip-template/runtimes/dip-provider/src/dip.rs +++ b/dip-template/runtimes/dip-provider/src/dip.rs @@ -18,9 +18,13 @@ use did::did_details::DidDetails; use dip_support::IdentityProofAction; +use kilt_dip_support::did::CombinedIdentityResult; +use pallet_did_lookup::linkable_account::LinkableAccountId; use pallet_dip_provider::traits::{TxBuilder, XcmRouterDispatcher}; +use pallet_web3_names::Web3NameOf; use parity_scale_codec::{Decode, Encode}; -use runtime_common::dip::{did::DidIdentityProvider, merkle::DidMerkleRootGenerator}; +use runtime_common::dip::{did::LinkedDidInfoProviderOf, merkle::DidMerkleRootGenerator}; +use sp_std::vec::Vec; use xcm::{latest::MultiLocation, DoubleEncoded}; use crate::{DidIdentifier, Hash, Runtime, RuntimeEvent, XcmRouter}; @@ -55,10 +59,14 @@ impl TxBuilder for ConsumerParachainTxBuilder { impl pallet_dip_provider::Config for Runtime { type Identifier = DidIdentifier; - type Identity = DidDetails; + type Identity = CombinedIdentityResult< + Option>, + Option>, + Option>, + >; type IdentityProofDispatcher = XcmRouterDispatcher; type IdentityProofGenerator = DidMerkleRootGenerator; - type IdentityProvider = DidIdentityProvider; + type IdentityProvider = LinkedDidInfoProviderOf; type ProofOutput = Hash; type RuntimeEvent = RuntimeEvent; type TxBuilder = ConsumerParachainTxBuilder; diff --git a/dip-template/runtimes/dip-provider/src/lib.rs b/dip-template/runtimes/dip-provider/src/lib.rs index 5a8625789b..68883afd37 100644 --- a/dip-template/runtimes/dip-provider/src/lib.rs +++ b/dip-template/runtimes/dip-provider/src/lib.rs @@ -22,6 +22,7 @@ #[cfg(feature = "std")] include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); +use pallet_web3_names::web3_name::AsciiWeb3Name; pub use sp_consensus_aura::sr25519::AuthorityId as AuraId; pub use sp_runtime::{MultiAddress, Perbill, Permill}; @@ -140,6 +141,8 @@ construct_runtime!( // DID Did: did = 40, + DidLookup: pallet_did_lookup = 41, + Web3Names: pallet_web3_names = 42, // DIP DipProvider: pallet_dip_provider = 50, @@ -394,6 +397,30 @@ impl did::Config for Runtime { type WeightInfo = (); } +impl pallet_did_lookup::Config for Runtime { + type Currency = Balances; + type Deposit = ConstU128; + type DidIdentifier = DidIdentifier; + type EnsureOrigin = EnsureDidOrigin; + type OriginSuccess = DidRawOrigin; + type RuntimeEvent = RuntimeEvent; + type WeightInfo = (); +} + +impl pallet_web3_names::Config for Runtime { + type BanOrigin = EnsureRoot; + type Currency = Balances; + type Deposit = ConstU128; + type MaxNameLength = ConstU32<32>; + type MinNameLength = ConstU32<3>; + type OriginSuccess = DidRawOrigin; + type OwnerOrigin = EnsureDidOrigin; + type RuntimeEvent = RuntimeEvent; + type Web3Name = AsciiWeb3Name; + type Web3NameOwner = DidIdentifier; + type WeightInfo = (); +} + impl_runtime_apis! { impl sp_consensus_aura::AuraApi for Runtime { fn slot_duration() -> SlotDuration { diff --git a/runtimes/common/Cargo.toml b/runtimes/common/Cargo.toml index 4b1e03c0a6..c650a681ef 100644 --- a/runtimes/common/Cargo.toml +++ b/runtimes/common/Cargo.toml @@ -27,7 +27,7 @@ ctype.workspace = true delegation = {workspace = true, optional = true} did.workspace = true kilt-dip-support.workspace = true -pallet-did-lookup = {workspace = true, optional = true} +pallet-did-lookup.workspace = true pallet-dip-consumer.workspace = true pallet-dip-provider.workspace = true pallet-inflation = {workspace = true, optional = true} @@ -66,6 +66,7 @@ runtime-benchmarks = [ "attestation/runtime-benchmarks", "ctype/runtime-benchmarks", "did/runtime-benchmarks", + "pallet-did-lookup/runtime-benchmarks", "pallet-dip-consumer/runtime-benchmarks", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", @@ -92,6 +93,7 @@ std = [ "log/std", "pallet-authorship/std", "pallet-balances/std", + "pallet-did-lookup/std", "pallet-dip-consumer/std", "pallet-dip-provider/std", "pallet-membership/std", @@ -119,7 +121,7 @@ try-runtime = [ "kilt-support/try-runtime", "pallet-authorship/try-runtime", "pallet-balances/try-runtime", - "pallet-did-lookup", + "pallet-did-lookup/try-runtime", "pallet-inflation", "pallet-membership/try-runtime", "pallet-transaction-payment/try-runtime", diff --git a/runtimes/common/src/dip/did.rs b/runtimes/common/src/dip/did.rs index 5a1f945d22..89a03cc66a 100644 --- a/runtimes/common/src/dip/did.rs +++ b/runtimes/common/src/dip/did.rs @@ -17,8 +17,11 @@ // If you feel like getting in touch with us, you can do so at info@botlabs.org use did::did_details::DidDetails; +use kilt_dip_support::did::{CombineIdentityFrom, CombinedIdentityResult}; +use pallet_did_lookup::linkable_account::LinkableAccountId; use pallet_dip_provider::traits::IdentityProvider; -use sp_std::marker::PhantomData; +use pallet_web3_names::Web3NameOf; +use sp_std::{marker::PhantomData, vec::Vec}; pub struct DidIdentityProvider(PhantomData); @@ -41,3 +44,44 @@ where } } } + +pub struct DidWeb3NameProvider(PhantomData); + +impl IdentityProvider for DidWeb3NameProvider +where + T: pallet_web3_names::Config, +{ + // TODO: Proper error handling + type Error = (); + type Success = T::Web3Name; + + fn retrieve(identifier: &T::Web3NameOwner) -> Result, Self::Error> { + if let Some(web3_name) = pallet_web3_names::Pallet::::names(identifier) { + Ok(Some(web3_name)) + } else { + Ok(None) + } + } +} + +pub struct DidLinkedAccountsProvider(PhantomData); + +impl IdentityProvider for DidLinkedAccountsProvider +where + T: pallet_did_lookup::Config, +{ + // TODO: Proper error handling + type Error = (); + type Success = Vec; + + fn retrieve(identifier: &T::DidIdentifier) -> Result, Self::Error> { + Ok(Some( + pallet_did_lookup::ConnectedAccounts::::iter_key_prefix(identifier).collect(), + )) + } +} + +pub type LinkedDidInfoProviderOf = + CombineIdentityFrom, DidWeb3NameProvider, DidLinkedAccountsProvider>; +pub type LinkedDidInfoOf = + CombinedIdentityResult>, Option>, Option>>; diff --git a/runtimes/common/src/dip/merkle.rs b/runtimes/common/src/dip/merkle.rs index f92cc96805..7a1bf06e57 100644 --- a/runtimes/common/src/dip/merkle.rs +++ b/runtimes/common/src/dip/merkle.rs @@ -29,6 +29,8 @@ use kilt_dip_support::merkle::{ DidKeyRelationship, KeyDetailsKey, KeyDetailsValue, KeyReferenceKey, KeyReferenceValue, ProofLeaf, }; +use crate::{dip::did::LinkedDidInfoOf, DidIdentifier}; + pub type BlindedValue = Vec; pub type DidMerkleProofOf = MerkleProof, ProofLeaf, ::BlockNumber>>; @@ -43,7 +45,7 @@ pub struct DidMerkleRootGenerator(PhantomData); impl DidMerkleRootGenerator where - T: did::Config, + T: did::Config + pallet_did_lookup::Config + pallet_web3_names::Config, { // Calls the function in the `sp_trie` crate to generate the merkle root given // the provided `DidDetails`. @@ -56,14 +58,16 @@ where // A valid proof will contain a leaf with the key details for each reference // leaf, with multiple reference leaves potentially referring to the same // details leaf, as we already do with out `DidDetails` type. - fn calculate_root_with_db(identity: &DidDetails, db: &mut MemoryDB) -> Result { + fn calculate_root_with_db(identity: &LinkedDidInfoOf, db: &mut MemoryDB) -> Result { + // Fails if the DID details do not exist. + let (Some(did_details), web3_name, linked_accounts) = (&identity.a, &identity.b, &identity.c) else { return Err(()) }; let mut trie = TrieHash::>::default(); let mut trie_builder = TrieDBMutBuilder::>::new(db, &mut trie).build(); // Authentication key let auth_leaf = ProofLeaf::<_, T::BlockNumber>::KeyReference( KeyReferenceKey( - identity.authentication_key, + did_details.authentication_key, DidVerificationKeyRelationship::Authentication.into(), ), KeyReferenceValue, @@ -72,7 +76,7 @@ where .insert(auth_leaf.encoded_key().as_slice(), auth_leaf.encoded_value().as_slice()) .map_err(|_| ())?; // Attestation key, if present - if let Some(att_key_id) = identity.attestation_key { + if let Some(att_key_id) = did_details.attestation_key { let att_leaf = ProofLeaf::<_, T::BlockNumber>::KeyReference( KeyReferenceKey(att_key_id, DidVerificationKeyRelationship::AssertionMethod.into()), KeyReferenceValue, @@ -82,7 +86,7 @@ where .map_err(|_| ())?; }; // Delegation key, if present - if let Some(del_key_id) = identity.delegation_key { + if let Some(del_key_id) = did_details.delegation_key { let del_leaf = ProofLeaf::<_, T::BlockNumber>::KeyReference( KeyReferenceKey(del_key_id, DidVerificationKeyRelationship::CapabilityDelegation.into()), KeyReferenceValue, @@ -92,7 +96,7 @@ where .map_err(|_| ())?; }; // Key agreement keys - identity + did_details .key_agreement_keys .iter() .try_for_each(|id| -> Result<(), ()> { @@ -106,7 +110,7 @@ where Ok(()) })?; // Public keys - identity + did_details .public_keys .iter() .try_for_each(|(id, key_details)| -> Result<(), ()> { @@ -127,39 +131,41 @@ where // IDs. #[allow(clippy::result_unit_err)] pub fn generate_proof<'a, K>( - identity: &DidDetails, + identity: &LinkedDidInfoOf, mut key_ids: K, ) -> Result>, ()> where K: Iterator>, { + let (Some(did_details), web3_name, linked_accounts) = (&identity.a, &identity.b, &identity.c) else { return Err(()) }; + let mut db = MemoryDB::default(); let root = Self::calculate_root_with_db(identity, &mut db)?; #[allow(clippy::type_complexity)] let leaves: BTreeSet, T::BlockNumber>> = key_ids.try_fold(BTreeSet::new(), |mut set, key_id| -> Result<_, ()> { - let key_details = identity.public_keys.get(key_id).ok_or(())?; + let key_details = did_details.public_keys.get(key_id).ok_or(())?; // Adds a key reference leaf for each relationship the key ID is part of. - if *key_id == identity.authentication_key { + if *key_id == did_details.authentication_key { set.insert(ProofLeaf::KeyReference( KeyReferenceKey(*key_id, DidVerificationKeyRelationship::Authentication.into()), KeyReferenceValue, )); } - if Some(*key_id) == identity.attestation_key { + if Some(*key_id) == did_details.attestation_key { set.insert(ProofLeaf::KeyReference( KeyReferenceKey(*key_id, DidVerificationKeyRelationship::AssertionMethod.into()), KeyReferenceValue, )); } - if Some(*key_id) == identity.delegation_key { + if Some(*key_id) == did_details.delegation_key { set.insert(ProofLeaf::KeyReference( KeyReferenceKey(*key_id, DidVerificationKeyRelationship::CapabilityDelegation.into()), KeyReferenceValue, )); } - if identity.key_agreement_keys.contains(key_id) { + if did_details.key_agreement_keys.contains(key_id) { set.insert(ProofLeaf::KeyReference( KeyReferenceKey(*key_id, DidKeyRelationship::Encryption), KeyReferenceValue, @@ -187,15 +193,15 @@ where } } -impl IdentityProofGenerator> for DidMerkleRootGenerator +impl IdentityProofGenerator> for DidMerkleRootGenerator where - T: did::Config, + T: did::Config + pallet_did_lookup::Config + pallet_web3_names::Config, { // TODO: Proper error handling type Error = (); type Output = T::Hash; - fn generate_commitment(_identifier: &T::DidIdentifier, identity: &DidDetails) -> Result { + fn generate_commitment(_identifier: &DidIdentifier, identity: &LinkedDidInfoOf) -> Result { let mut db = MemoryDB::default(); Self::calculate_root_with_db(identity, &mut db) } From b886285b0f4a0ad82287b39f9a0a6f47446a6aea Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Mon, 22 May 2023 09:54:32 +0200 Subject: [PATCH 03/15] Change merkle leaf type to only have a single type for DID keys --- crates/kilt-dip-support/src/merkle.rs | 54 +++--------- runtimes/common/src/dip/merkle.rs | 119 +++++++++++++------------- 2 files changed, 71 insertions(+), 102 deletions(-) diff --git a/crates/kilt-dip-support/src/merkle.rs b/crates/kilt-dip-support/src/merkle.rs index d86e84475a..0885aa6cce 100644 --- a/crates/kilt-dip-support/src/merkle.rs +++ b/crates/kilt-dip-support/src/merkle.rs @@ -22,7 +22,7 @@ use pallet_dip_consumer::{identity::IdentityDetails, traits::IdentityProofVerifi use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; use sp_runtime::BoundedVec; -use sp_std::{collections::btree_map::BTreeMap, fmt::Debug, marker::PhantomData, vec::Vec}; +use sp_std::{fmt::Debug, marker::PhantomData, vec::Vec}; use sp_trie::{verify_trie_proof, LayoutV1}; pub type BlindedValue = Vec; @@ -60,23 +60,16 @@ impl TryFrom for DidVerificationKeyRelationship { } #[derive(Clone, Encode, Decode, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug, TypeInfo)] -pub struct KeyReferenceKey(pub KeyId, pub DidKeyRelationship); -#[derive(Clone, Encode, Decode, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug, TypeInfo)] -pub struct KeyReferenceValue; -#[derive(Clone, Encode, Decode, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug, TypeInfo)] -pub struct KeyDetailsKey(pub KeyId); +pub struct DidKeyMerkleKey(pub KeyId, pub DidKeyRelationship); + #[derive(Clone, Encode, Decode, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug, TypeInfo)] -pub struct KeyDetailsValue(pub DidPublicKeyDetails); +pub struct DidKeyMerkleValue(pub DidPublicKeyDetails); #[derive(Clone, Encode, Decode, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug, TypeInfo)] pub enum ProofLeaf { // The key and value for the leaves of a merkle proof that contain a reference // (by ID) to the key details, provided in a separate leaf. - KeyReference(KeyReferenceKey, KeyReferenceValue), - // The key and value for the leaves of a merkle proof that contain the actual - // details of a DID public key. The key is the ID of the key, and the value is its details, including creation - // block number. - KeyDetails(KeyDetailsKey, KeyDetailsValue), + DidKey(DidKeyMerkleKey, DidKeyMerkleValue), } impl ProofLeaf @@ -85,8 +78,7 @@ where { pub fn encoded_key(&self) -> Vec { match self { - ProofLeaf::KeyReference(key, _) => key.encode(), - ProofLeaf::KeyDetails(key, _) => key.encode(), + ProofLeaf::DidKey(key, _) => key.encode(), } } } @@ -97,8 +89,7 @@ where { pub fn encoded_value(&self) -> Vec { match self { - ProofLeaf::KeyReference(_, value) => value.encode(), - ProofLeaf::KeyDetails(_, value) => value.encode(), + ProofLeaf::DidKey(_, value) => value.encode(), } } } @@ -211,38 +202,17 @@ where // At this point, we know the proof is valid. We just need to map the revealed // leaves to something the consumer can easily operate on. - // Create a map of the revealed public keys - //TODO: Avoid cloning, and use a map of references for the lookup - let public_keys: BTreeMap> = proof - .revealed - .clone() - .into_iter() - .filter_map(|leaf| { - if let ProofLeaf::KeyDetails(KeyDetailsKey(key_id), KeyDetailsValue(key_details)) = leaf { - Some((key_id, key_details)) - } else { - None - } - }) - .collect(); // Create a list of the revealed keys by consuming the provided key reference // leaves, and looking up the full details from the just-built `public_keys` // map. let keys: Vec> = proof .revealed .iter() - .filter_map(|leaf| { - if let ProofLeaf::KeyReference(KeyReferenceKey(key_id, key_relationship), _) = leaf { - // TODO: Better error handling. - let key_details = public_keys - .get(key_id) - .expect("Key ID should be present in the map of revealed public keys."); - Some(ProofEntry { - key: key_details.clone(), - relationship: *key_relationship, - }) - } else { - None + .map(|leaf| { + let ProofLeaf::DidKey(key_id, key_value) = leaf; + ProofEntry { + key: key_value.0.clone(), + relationship: key_id.1, } }) .collect(); diff --git a/runtimes/common/src/dip/merkle.rs b/runtimes/common/src/dip/merkle.rs index 7a1bf06e57..c9dfb96454 100644 --- a/runtimes/common/src/dip/merkle.rs +++ b/runtimes/common/src/dip/merkle.rs @@ -16,18 +16,16 @@ // If you feel like getting in touch with us, you can do so at info@botlabs.org -use did::{did_details::DidDetails, DidVerificationKeyRelationship, KeyIdOf}; +use did::{DidVerificationKeyRelationship, KeyIdOf}; use frame_support::RuntimeDebug; -use kilt_dip_support::merkle::MerkleProof; +use kilt_dip_support::merkle::{DidKeyMerkleKey, DidKeyMerkleValue, MerkleProof}; use pallet_dip_provider::traits::IdentityProofGenerator; use parity_scale_codec::{Decode, Encode}; use scale_info::TypeInfo; use sp_std::{borrow::ToOwned, collections::btree_set::BTreeSet, marker::PhantomData, vec::Vec}; use sp_trie::{generate_trie_proof, LayoutV1, MemoryDB, TrieDBMutBuilder, TrieHash, TrieMut}; -use kilt_dip_support::merkle::{ - DidKeyRelationship, KeyDetailsKey, KeyDetailsValue, KeyReferenceKey, KeyReferenceValue, ProofLeaf, -}; +use kilt_dip_support::merkle::{DidKeyRelationship, ProofLeaf}; use crate::{dip::did::LinkedDidInfoOf, DidIdentifier}; @@ -65,21 +63,30 @@ where let mut trie_builder = TrieDBMutBuilder::>::new(db, &mut trie).build(); // Authentication key - let auth_leaf = ProofLeaf::<_, T::BlockNumber>::KeyReference( - KeyReferenceKey( + // TODO: No panic + let auth_key_details = did_details + .public_keys + .get(&did_details.authentication_key) + .expect("Authentication key should be part of the public keys."); + let auth_leaf = ProofLeaf::<_, T::BlockNumber>::DidKey( + DidKeyMerkleKey( did_details.authentication_key, DidVerificationKeyRelationship::Authentication.into(), ), - KeyReferenceValue, + DidKeyMerkleValue(auth_key_details.clone()), ); trie_builder .insert(auth_leaf.encoded_key().as_slice(), auth_leaf.encoded_value().as_slice()) .map_err(|_| ())?; // Attestation key, if present if let Some(att_key_id) = did_details.attestation_key { - let att_leaf = ProofLeaf::<_, T::BlockNumber>::KeyReference( - KeyReferenceKey(att_key_id, DidVerificationKeyRelationship::AssertionMethod.into()), - KeyReferenceValue, + let att_key_details = did_details + .public_keys + .get(&att_key_id) + .expect("Attestation key should be part of the public keys."); + let att_leaf = ProofLeaf::<_, T::BlockNumber>::DidKey( + DidKeyMerkleKey(att_key_id, DidVerificationKeyRelationship::AssertionMethod.into()), + DidKeyMerkleValue(att_key_details.clone()), ); trie_builder .insert(att_leaf.encoded_key().as_slice(), att_leaf.encoded_value().as_slice()) @@ -87,9 +94,13 @@ where }; // Delegation key, if present if let Some(del_key_id) = did_details.delegation_key { - let del_leaf = ProofLeaf::<_, T::BlockNumber>::KeyReference( - KeyReferenceKey(del_key_id, DidVerificationKeyRelationship::CapabilityDelegation.into()), - KeyReferenceValue, + let del_key_details = did_details + .public_keys + .get(&del_key_id) + .expect("Delegation key should be part of the public keys."); + let del_leaf = ProofLeaf::<_, T::BlockNumber>::DidKey( + DidKeyMerkleKey(del_key_id, DidVerificationKeyRelationship::CapabilityDelegation.into()), + DidKeyMerkleValue(del_key_details.clone()), ); trie_builder .insert(del_leaf.encoded_key().as_slice(), del_leaf.encoded_value().as_slice()) @@ -100,26 +111,19 @@ where .key_agreement_keys .iter() .try_for_each(|id| -> Result<(), ()> { - let enc_leaf = ProofLeaf::<_, T::BlockNumber>::KeyReference( - KeyReferenceKey(*id, DidKeyRelationship::Encryption), - KeyReferenceValue, + let key_agreement_details = did_details + .public_keys + .get(id) + .expect("Key agreement key should be part of the public keys."); + let enc_leaf = ProofLeaf::<_, T::BlockNumber>::DidKey( + DidKeyMerkleKey(*id, DidKeyRelationship::Encryption), + DidKeyMerkleValue(key_agreement_details.clone()), ); trie_builder .insert(enc_leaf.encoded_key().as_slice(), enc_leaf.encoded_value().as_slice()) .map_err(|_| ())?; Ok(()) })?; - // Public keys - did_details - .public_keys - .iter() - .try_for_each(|(id, key_details)| -> Result<(), ()> { - let key_leaf = ProofLeaf::KeyDetails(KeyDetailsKey(*id), KeyDetailsValue(key_details.clone())); - trie_builder - .insert(key_leaf.encoded_key().as_slice(), key_leaf.encoded_value().as_slice()) - .map_err(|_| ())?; - Ok(()) - })?; trie_builder.commit(); Ok(trie_builder.root().to_owned()) } @@ -146,38 +150,33 @@ where let leaves: BTreeSet, T::BlockNumber>> = key_ids.try_fold(BTreeSet::new(), |mut set, key_id| -> Result<_, ()> { let key_details = did_details.public_keys.get(key_id).ok_or(())?; - // Adds a key reference leaf for each relationship the key ID is part of. - if *key_id == did_details.authentication_key { - set.insert(ProofLeaf::KeyReference( - KeyReferenceKey(*key_id, DidVerificationKeyRelationship::Authentication.into()), - KeyReferenceValue, - )); - } - if Some(*key_id) == did_details.attestation_key { - set.insert(ProofLeaf::KeyReference( - KeyReferenceKey(*key_id, DidVerificationKeyRelationship::AssertionMethod.into()), - KeyReferenceValue, - )); - } - if Some(*key_id) == did_details.delegation_key { - set.insert(ProofLeaf::KeyReference( - KeyReferenceKey(*key_id, DidVerificationKeyRelationship::CapabilityDelegation.into()), - KeyReferenceValue, - )); - } - if did_details.key_agreement_keys.contains(key_id) { - set.insert(ProofLeaf::KeyReference( - KeyReferenceKey(*key_id, DidKeyRelationship::Encryption), - KeyReferenceValue, - )); - }; - // Then adds the actual key details to the merkle proof. - // If the same key is specified twice, the old key is simply replaced with a new - // key of the same value. - let key_details_leaf = - ProofLeaf::KeyDetails(KeyDetailsKey(*key_id), KeyDetailsValue(key_details.clone())); - if !set.contains(&key_details_leaf) { - set.insert(key_details_leaf); + // Create the merkle leaf key depending on the relationship of the key to the + // DID document. + let did_key_merkle_key = if *key_id == did_details.authentication_key { + Ok(DidKeyMerkleKey( + *key_id, + DidVerificationKeyRelationship::Authentication.into(), + )) + } else if Some(*key_id) == did_details.attestation_key { + Ok(DidKeyMerkleKey( + *key_id, + DidVerificationKeyRelationship::AssertionMethod.into(), + )) + } else if Some(*key_id) == did_details.delegation_key { + Ok(DidKeyMerkleKey( + *key_id, + DidVerificationKeyRelationship::CapabilityDelegation.into(), + )) + } else if did_details.key_agreement_keys.contains(key_id) { + Ok(DidKeyMerkleKey(*key_id, DidKeyRelationship::Encryption)) + } else { + Err(()) + }?; + // Then adds the actual key details to the merkle leaf. + let did_key_merkle_value = DidKeyMerkleValue(key_details.clone()); + let did_merkle_merkle_leaf = ProofLeaf::DidKey(did_key_merkle_key, did_key_merkle_value); + if !set.contains(&did_merkle_merkle_leaf) { + set.insert(did_merkle_merkle_leaf); } Ok(set) })?; From bc00680fe2e756b88255f810afd5ea0f0173fdd0 Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Mon, 22 May 2023 10:08:36 +0200 Subject: [PATCH 04/15] Compiling and tests passing --- crates/kilt-dip-support/src/did.rs | 42 +++++++++++++++++++ .../nodes/dip-provider/src/chain_spec.rs | 1 + dip-template/runtimes/dip-provider/src/dip.rs | 16 +++---- dip-template/runtimes/xcm-tests/src/tests.rs | 7 +++- runtimes/common/src/dip/merkle.rs | 4 +- 5 files changed, 55 insertions(+), 15 deletions(-) diff --git a/crates/kilt-dip-support/src/did.rs b/crates/kilt-dip-support/src/did.rs index 4e425a3460..f71340515d 100644 --- a/crates/kilt-dip-support/src/did.rs +++ b/crates/kilt-dip-support/src/did.rs @@ -245,6 +245,48 @@ pub struct CombinedIdentityResult { pub c: OutputC, } +impl CombinedIdentityResult +where + OutputB: Default, + OutputC: Default, +{ + pub fn from_a(a: OutputA) -> Self { + Self { + a, + b: OutputB::default(), + c: OutputC::default(), + } + } +} + +impl CombinedIdentityResult +where + OutputA: Default, + OutputC: Default, +{ + pub fn from_b(b: OutputB) -> Self { + Self { + a: OutputA::default(), + b, + c: OutputC::default(), + } + } +} + +impl CombinedIdentityResult +where + OutputA: Default, + OutputB: Default, +{ + pub fn from_c(c: OutputC) -> Self { + Self { + a: OutputA::default(), + b: OutputB::default(), + c, + } + } +} + pub struct CombineIdentityFrom(PhantomData<(A, B, C)>); impl IdentityProvider for CombineIdentityFrom diff --git a/dip-template/nodes/dip-provider/src/chain_spec.rs b/dip-template/nodes/dip-provider/src/chain_spec.rs index 7c323d7be3..af6493f67c 100644 --- a/dip-template/nodes/dip-provider/src/chain_spec.rs +++ b/dip-template/nodes/dip-provider/src/chain_spec.rs @@ -100,6 +100,7 @@ fn testnet_genesis( aura: Default::default(), aura_ext: Default::default(), polkadot_xcm: Default::default(), + did_lookup: Default::default(), } } diff --git a/dip-template/runtimes/dip-provider/src/dip.rs b/dip-template/runtimes/dip-provider/src/dip.rs index f5147b9ef0..a8e7163b73 100644 --- a/dip-template/runtimes/dip-provider/src/dip.rs +++ b/dip-template/runtimes/dip-provider/src/dip.rs @@ -16,15 +16,13 @@ // If you feel like getting in touch with us, you can do so at info@botlabs.org -use did::did_details::DidDetails; use dip_support::IdentityProofAction; -use kilt_dip_support::did::CombinedIdentityResult; -use pallet_did_lookup::linkable_account::LinkableAccountId; use pallet_dip_provider::traits::{TxBuilder, XcmRouterDispatcher}; -use pallet_web3_names::Web3NameOf; use parity_scale_codec::{Decode, Encode}; -use runtime_common::dip::{did::LinkedDidInfoProviderOf, merkle::DidMerkleRootGenerator}; -use sp_std::vec::Vec; +use runtime_common::dip::{ + did::{LinkedDidInfoOf, LinkedDidInfoProviderOf}, + merkle::DidMerkleRootGenerator, +}; use xcm::{latest::MultiLocation, DoubleEncoded}; use crate::{DidIdentifier, Hash, Runtime, RuntimeEvent, XcmRouter}; @@ -59,11 +57,7 @@ impl TxBuilder for ConsumerParachainTxBuilder { impl pallet_dip_provider::Config for Runtime { type Identifier = DidIdentifier; - type Identity = CombinedIdentityResult< - Option>, - Option>, - Option>, - >; + type Identity = LinkedDidInfoOf; type IdentityProofDispatcher = XcmRouterDispatcher; type IdentityProofGenerator = DidMerkleRootGenerator; type IdentityProvider = LinkedDidInfoProviderOf; diff --git a/dip-template/runtimes/xcm-tests/src/tests.rs b/dip-template/runtimes/xcm-tests/src/tests.rs index a868a64ea1..67dfd2076d 100644 --- a/dip-template/runtimes/xcm-tests/src/tests.rs +++ b/dip-template/runtimes/xcm-tests/src/tests.rs @@ -27,7 +27,10 @@ use kilt_dip_support::{ }; use pallet_did_lookup::linkable_account::LinkableAccountId; use parity_scale_codec::Encode; -use runtime_common::dip::merkle::{CompleteMerkleProof, DidMerkleRootGenerator}; +use runtime_common::dip::{ + did::LinkedDidInfoOf, + merkle::{CompleteMerkleProof, DidMerkleRootGenerator}, +}; use sp_core::Pair; use sp_runtime::traits::Zero; use xcm::latest::{ @@ -81,7 +84,7 @@ fn commit_identity() { let call = ConsumerRuntimeCall::DidLookup(pallet_did_lookup::Call::::associate_sender {}); // 3.1 Generate a proof let CompleteMerkleProof { proof, .. } = DidMerkleRootGenerator::::generate_proof( - &did_details, + &LinkedDidInfoOf::from_a(Some(did_details.clone())), [did_details.authentication_key].iter(), ) .expect("Proof generation should not fail"); diff --git a/runtimes/common/src/dip/merkle.rs b/runtimes/common/src/dip/merkle.rs index c9dfb96454..9af324850a 100644 --- a/runtimes/common/src/dip/merkle.rs +++ b/runtimes/common/src/dip/merkle.rs @@ -58,7 +58,7 @@ where // details leaf, as we already do with out `DidDetails` type. fn calculate_root_with_db(identity: &LinkedDidInfoOf, db: &mut MemoryDB) -> Result { // Fails if the DID details do not exist. - let (Some(did_details), web3_name, linked_accounts) = (&identity.a, &identity.b, &identity.c) else { return Err(()) }; + let (Some(did_details), _web3_name, _linked_accounts) = (&identity.a, &identity.b, &identity.c) else { return Err(()) }; let mut trie = TrieHash::>::default(); let mut trie_builder = TrieDBMutBuilder::>::new(db, &mut trie).build(); @@ -141,7 +141,7 @@ where where K: Iterator>, { - let (Some(did_details), web3_name, linked_accounts) = (&identity.a, &identity.b, &identity.c) else { return Err(()) }; + let (Some(did_details), _web3_name, _linked_accounts) = (&identity.a, &identity.b, &identity.c) else { return Err(()) }; let mut db = MemoryDB::default(); let root = Self::calculate_root_with_db(identity, &mut db)?; From 9b94b160c91c25bc3f81614e99a7a16280df6c89 Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Mon, 22 May 2023 10:22:22 +0200 Subject: [PATCH 05/15] Some more refactoring --- dip-template/runtimes/dip-provider/src/dip.rs | 6 +----- pallets/pallet-dip-provider/src/lib.rs | 8 ++++---- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/dip-template/runtimes/dip-provider/src/dip.rs b/dip-template/runtimes/dip-provider/src/dip.rs index a8e7163b73..63740c1352 100644 --- a/dip-template/runtimes/dip-provider/src/dip.rs +++ b/dip-template/runtimes/dip-provider/src/dip.rs @@ -19,10 +19,7 @@ use dip_support::IdentityProofAction; use pallet_dip_provider::traits::{TxBuilder, XcmRouterDispatcher}; use parity_scale_codec::{Decode, Encode}; -use runtime_common::dip::{ - did::{LinkedDidInfoOf, LinkedDidInfoProviderOf}, - merkle::DidMerkleRootGenerator, -}; +use runtime_common::dip::{did::LinkedDidInfoProviderOf, merkle::DidMerkleRootGenerator}; use xcm::{latest::MultiLocation, DoubleEncoded}; use crate::{DidIdentifier, Hash, Runtime, RuntimeEvent, XcmRouter}; @@ -57,7 +54,6 @@ impl TxBuilder for ConsumerParachainTxBuilder { impl pallet_dip_provider::Config for Runtime { type Identifier = DidIdentifier; - type Identity = LinkedDidInfoOf; type IdentityProofDispatcher = XcmRouterDispatcher; type IdentityProofGenerator = DidMerkleRootGenerator; type IdentityProvider = LinkedDidInfoProviderOf; diff --git a/pallets/pallet-dip-provider/src/lib.rs b/pallets/pallet-dip-provider/src/lib.rs index 6e722924b6..f2d94ae594 100644 --- a/pallets/pallet-dip-provider/src/lib.rs +++ b/pallets/pallet-dip-provider/src/lib.rs @@ -37,6 +37,7 @@ pub mod pallet { use crate::traits::{IdentityProofDispatcher, IdentityProofGenerator, IdentityProvider, TxBuilder}; + pub type IdentityOf = <::IdentityProvider as IdentityProvider<::Identifier>>::Success; pub type IdentityProofActionOf = IdentityProofAction<::Identifier, ::ProofOutput>; const STORAGE_VERSION: StorageVersion = StorageVersion::new(0); @@ -44,15 +45,14 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { type Identifier: Parameter; - type Identity; - type ProofOutput: Clone + Eq + Debug; type IdentityProofGenerator: IdentityProofGenerator< Self::Identifier, - Self::Identity, + IdentityOf, Output = Self::ProofOutput, >; type IdentityProofDispatcher: IdentityProofDispatcher; - type IdentityProvider: IdentityProvider; + type IdentityProvider: IdentityProvider; + type ProofOutput: Clone + Eq + Debug; type RuntimeEvent: From> + IsType<::RuntimeEvent>; type TxBuilder: TxBuilder; } From a0013e58cdd63f1a17e5aea870c417680b0a45d4 Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Mon, 22 May 2023 15:49:12 +0200 Subject: [PATCH 06/15] Compiling again --- Cargo.lock | 1 + crates/kilt-dip-support/src/did.rs | 29 +++--- crates/kilt-dip-support/src/merkle.rs | 92 +++++++++---------- dip-template/runtimes/dip-consumer/Cargo.toml | 3 + dip-template/runtimes/dip-consumer/src/dip.rs | 8 +- dip-template/runtimes/dip-consumer/src/lib.rs | 5 +- dip-template/runtimes/dip-provider/src/lib.rs | 4 +- pallets/pallet-web3-names/src/lib.rs | 3 +- pallets/pallet-web3-names/src/web3_name.rs | 28 ++++++ runtimes/common/src/dip/merkle.rs | 16 ++-- 10 files changed, 111 insertions(+), 78 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 26f8a5ab69..3c3e7808e2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2341,6 +2341,7 @@ dependencies = [ "cumulus-primitives-timestamp", "cumulus-primitives-utility", "did", + "dip-provider-runtime-template", "dip-support", "frame-executive", "frame-support", diff --git a/crates/kilt-dip-support/src/did.rs b/crates/kilt-dip-support/src/did.rs index f71340515d..521fcb8dcb 100644 --- a/crates/kilt-dip-support/src/did.rs +++ b/crates/kilt-dip-support/src/did.rs @@ -60,6 +60,7 @@ pub struct MerkleRevealedDidSignatureVerifier< AccountId, MerkleProofEntries, BlockNumberProvider, + Web3Name, const SIGNATURE_VALIDITY: u64, GenesisHashProvider, Hash, @@ -74,6 +75,7 @@ pub struct MerkleRevealedDidSignatureVerifier< AccountId, MerkleProofEntries, BlockNumberProvider, + Web3Name, ConstU64, GenesisHashProvider, Hash, @@ -91,6 +93,7 @@ impl< AccountId, MerkleProofEntries, BlockNumberProvider, + Web3Name, const SIGNATURE_VALIDITY: u64, GenesisHashProvider, Hash, @@ -104,6 +107,7 @@ impl< AccountId, MerkleProofEntries, BlockNumberProvider, + Web3Name, SIGNATURE_VALIDITY, GenesisHashProvider, Hash, @@ -115,7 +119,7 @@ impl< Call: Encode, Digest: Encode, Details: Bump + Encode, - MerkleProofEntries: AsRef<[ProofEntry]>, + MerkleProofEntries: AsRef<[ProofEntry]>, BlockNumberProvider: Get, GenesisHashProvider: Get, Hash: Encode, @@ -163,21 +167,14 @@ impl< ) .encode(); // Only consider verification keys from the set of revealed Merkle leaves. - let mut proof_verification_keys = proof.merkle_entries.as_ref().iter().filter_map( - |ProofEntry { - key: DidPublicKeyDetails { key, .. }, - relationship, - }| { - if let DidPublicKey::PublicVerificationKey(k) = key { - Some(( - k, - DidVerificationKeyRelationship::try_from(*relationship).expect("Should never fail to build a VerificationRelationship from the given DidKeyRelationship because we have already made sure the conditions hold."), - )) - } else { - None - } - }, - ); + let mut proof_verification_keys = proof.merkle_entries.as_ref().iter().filter_map(|proof_entry| { + let ProofEntry::DidKey(relationship, DidPublicKeyDetails { key, .. }) = proof_entry else { return None }; + let DidPublicKey::PublicVerificationKey(k) = key else { return None }; + Some(( + k, + DidVerificationKeyRelationship::try_from(*relationship).expect("Should never fail to build a VerificationRelationship from the given DidKeyRelationship because we have already made sure the conditions hold."), + )) + }); let valid_signing_key = proof_verification_keys.find(|(verification_key, _)| { verification_key .verify_signature(&encoded_payload, &proof.did_signature.signature) diff --git a/crates/kilt-dip-support/src/merkle.rs b/crates/kilt-dip-support/src/merkle.rs index 0885aa6cce..a093e293c4 100644 --- a/crates/kilt-dip-support/src/merkle.rs +++ b/crates/kilt-dip-support/src/merkle.rs @@ -61,35 +61,43 @@ impl TryFrom for DidVerificationKeyRelationship { #[derive(Clone, Encode, Decode, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug, TypeInfo)] pub struct DidKeyMerkleKey(pub KeyId, pub DidKeyRelationship); - #[derive(Clone, Encode, Decode, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug, TypeInfo)] pub struct DidKeyMerkleValue(pub DidPublicKeyDetails); #[derive(Clone, Encode, Decode, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug, TypeInfo)] -pub enum ProofLeaf { +pub struct Web3NameMerkleKey(pub Web3Name); +#[derive(Clone, Encode, Decode, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug, TypeInfo)] +pub struct Web3NameMerkleValue; + +#[derive(Clone, Encode, Decode, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug, TypeInfo)] +pub enum ProofLeaf { // The key and value for the leaves of a merkle proof that contain a reference // (by ID) to the key details, provided in a separate leaf. DidKey(DidKeyMerkleKey, DidKeyMerkleValue), + Web3Name(Web3NameMerkleKey, Web3NameMerkleValue), } -impl ProofLeaf +impl ProofLeaf where KeyId: Encode, + Web3Name: Encode, { pub fn encoded_key(&self) -> Vec { match self { ProofLeaf::DidKey(key, _) => key.encode(), + ProofLeaf::Web3Name(key, _) => key.encode(), } } } -impl ProofLeaf +impl ProofLeaf where BlockNumber: Encode, { pub fn encoded_value(&self) -> Vec { match self { ProofLeaf::DidKey(_, value) => value.encode(), + ProofLeaf::Web3Name(_, value) => value.encode(), } } } @@ -97,52 +105,34 @@ where // TODO: Avoid repetition of the same key if it appears multiple times, e.g., by // having a vector of `DidKeyRelationship` instead. #[derive(Clone, RuntimeDebug, PartialEq, Eq, TypeInfo, MaxEncodedLen, Encode, Decode)] -pub struct ProofEntry { - pub key: DidPublicKeyDetails, - pub relationship: DidKeyRelationship, -} - -#[cfg(feature = "runtime-benchmarks")] -impl Default for ProofEntry -where - BlockNumber: Default, -{ - fn default() -> Self { - Self { - key: DidPublicKeyDetails { - key: did::did_details::DidPublicKey::PublicEncryptionKey(did::did_details::DidEncryptionKey::X25519( - [0u8; 32], - )), - block_number: BlockNumber::default(), - }, - relationship: DidVerificationKeyRelationship::Authentication.into(), - } - } +pub enum ProofEntry { + DidKey(DidKeyRelationship, DidPublicKeyDetails), + Web3Name(Web3Name), } // Contains the list of revealed public keys after a given Merkle proof has been // correctly verified. #[derive(Clone, Debug, PartialEq, Eq, TypeInfo, MaxEncodedLen, Encode, Decode, Default)] -pub struct VerificationResult( - pub BoundedVec, ConstU32>, +pub struct VerificationResult( + pub BoundedVec, ConstU32>, ); -impl TryFrom>> - for VerificationResult +impl TryFrom>> + for VerificationResult { // TODO: Better error handling type Error = (); - fn try_from(value: Vec>) -> Result { + fn try_from(value: Vec>) -> Result { let bounded_inner = value.try_into().map_err(|_| ())?; Ok(Self(bounded_inner)) } } -impl AsRef<[ProofEntry]> - for VerificationResult +impl AsRef<[ProofEntry]> + for VerificationResult { - fn as_ref(&self) -> &[ProofEntry] { + fn as_ref(&self) -> &[ProofEntry] { self.0.as_ref() } } @@ -150,32 +140,42 @@ impl AsRef<[ProofEntry( +pub struct DidMerkleProofVerifier< + Hasher, + AccountId, + KeyId, + BlockNumber, + Details, + Web3Name, + const MAX_REVEALED_LEAVES_COUNT: u32, +>( PhantomData<( Hasher, AccountId, KeyId, BlockNumber, Details, + Web3Name, ConstU32, )>, ); -impl +impl IdentityProofVerifier - for DidMerkleProofVerifier + for DidMerkleProofVerifier where // TODO: Remove `Debug` bound BlockNumber: Encode + Clone + Debug, Hasher: sp_core::Hasher, KeyId: Encode + Clone + Ord + Into, + Web3Name: Encode + Clone, { // TODO: Proper error handling type Error = (); - type Proof = MerkleProof>, ProofLeaf>; + type Proof = MerkleProof>, ProofLeaf>; type IdentityDetails = IdentityDetails; type Submitter = AccountId; - type VerificationResult = VerificationResult; + type VerificationResult = VerificationResult; fn verify_proof_for_call_against_entry( _call: &Call, @@ -202,20 +202,14 @@ where // At this point, we know the proof is valid. We just need to map the revealed // leaves to something the consumer can easily operate on. - // Create a list of the revealed keys by consuming the provided key reference - // leaves, and looking up the full details from the just-built `public_keys` - // map. - let keys: Vec> = proof + let leaves: Vec> = proof .revealed .iter() - .map(|leaf| { - let ProofLeaf::DidKey(key_id, key_value) = leaf; - ProofEntry { - key: key_value.0.clone(), - relationship: key_id.1, - } + .map(|leaf| match leaf { + ProofLeaf::DidKey(key_id, key_value) => ProofEntry::DidKey(key_id.1, key_value.0.clone()), + ProofLeaf::Web3Name(web3_name_id, _) => ProofEntry::Web3Name(web3_name_id.0.clone()), }) .collect(); - keys.try_into() + leaves.try_into() } } diff --git a/dip-template/runtimes/dip-consumer/Cargo.toml b/dip-template/runtimes/dip-consumer/Cargo.toml index de8f00d270..b5a18965ee 100644 --- a/dip-template/runtimes/dip-consumer/Cargo.toml +++ b/dip-template/runtimes/dip-consumer/Cargo.toml @@ -18,6 +18,7 @@ parity-scale-codec = {workspace = true, features = ["derive"]} scale-info = {workspace = true, features = ["derive"]} # DIP +dip-provider-runtime-template.workspace = true dip-support.workspace = true did.workspace = true kilt-dip-support.workspace = true @@ -77,6 +78,7 @@ default = [ std = [ "parity-scale-codec/std", "scale-info/std", + "dip-provider-runtime-template/std", "dip-support/std", "did/std", "kilt-dip-support/std", @@ -125,6 +127,7 @@ std = [ ] runtime-benchmarks = [ + "dip-provider-runtime-template/runtime-benchmarks", "pallet-dip-consumer/runtime-benchmarks", "runtime-common/runtime-benchmarks", "frame-support/runtime-benchmarks", diff --git a/dip-template/runtimes/dip-consumer/src/dip.rs b/dip-template/runtimes/dip-consumer/src/dip.rs index 639ff16e6b..3d2a1f3a11 100644 --- a/dip-template/runtimes/dip-consumer/src/dip.rs +++ b/dip-template/runtimes/dip-consumer/src/dip.rs @@ -17,6 +17,7 @@ // If you feel like getting in touch with us, you can do so at info@botlabs.org use did::{did_details::DidVerificationKey, DidVerificationKeyRelationship, KeyIdOf}; +use dip_provider_runtime_template::Web3Name; use frame_support::traits::Contains; use kilt_dip_support::{ did::{DidSignatureAndCallVerifier, MerkleEntriesAndDidSignature, MerkleRevealedDidSignatureVerifier}, @@ -29,7 +30,8 @@ use sp_std::vec::Vec; use crate::{AccountId, BlockNumber, DidIdentifier, Hash, Hasher, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin}; -pub type MerkleProofVerifier = DidMerkleProofVerifier, BlockNumber, u128, 10>; +pub type MerkleProofVerifier = + DidMerkleProofVerifier, BlockNumber, u128, Web3Name, 10>; pub type MerkleProofVerifierOutputOf = >::VerificationResult; pub type MerkleDidSignatureVerifierOf = MerkleRevealedDidSignatureVerifier< @@ -39,6 +41,7 @@ pub type MerkleDidSignatureVerifierOf = MerkleRevealedDidSignatur AccountId, MerkleProofVerifierOutputOf, BlockNumberProvider, + Web3Name, // Signatures are valid for 50 blocks 50, GenesisProvider, @@ -49,7 +52,8 @@ impl pallet_dip_consumer::Config for Runtime { type DipCallOriginFilter = PreliminaryDipOriginFilter; type Identifier = DidIdentifier; type IdentityDetails = u128; - type Proof = MerkleEntriesAndDidSignature>, ProofLeaf>, BlockNumber>; + type Proof = + MerkleEntriesAndDidSignature>, ProofLeaf>, BlockNumber>; type ProofDigest = Hash; type ProofVerifier = MerkleProofAndDidSignatureVerifier< BlockNumber, diff --git a/dip-template/runtimes/dip-consumer/src/lib.rs b/dip-template/runtimes/dip-consumer/src/lib.rs index 602e4af539..dc18381505 100644 --- a/dip-template/runtimes/dip-consumer/src/lib.rs +++ b/dip-template/runtimes/dip-consumer/src/lib.rs @@ -22,6 +22,7 @@ #[cfg(feature = "std")] include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); +use dip_provider_runtime_template::Web3Name; use kilt_dip_support::merkle::VerificationResult; pub use sp_consensus_aura::sr25519::AuthorityId as AuraId; pub use sp_runtime::{MultiAddress, Perbill, Permill}; @@ -367,8 +368,8 @@ impl pallet_did_lookup::Config for Runtime { type Currency = Balances; type Deposit = ConstU128; type DidIdentifier = DidIdentifier; - type EnsureOrigin = EnsureDipOrigin>; - type OriginSuccess = DipOrigin>; + type EnsureOrigin = EnsureDipOrigin>; + type OriginSuccess = DipOrigin>; type RuntimeEvent = RuntimeEvent; type WeightInfo = (); } diff --git a/dip-template/runtimes/dip-provider/src/lib.rs b/dip-template/runtimes/dip-provider/src/lib.rs index 68883afd37..cb25708c3d 100644 --- a/dip-template/runtimes/dip-provider/src/lib.rs +++ b/dip-template/runtimes/dip-provider/src/lib.rs @@ -407,6 +407,8 @@ impl pallet_did_lookup::Config for Runtime { type WeightInfo = (); } +pub type Web3Name = AsciiWeb3Name; + impl pallet_web3_names::Config for Runtime { type BanOrigin = EnsureRoot; type Currency = Balances; @@ -416,7 +418,7 @@ impl pallet_web3_names::Config for Runtime { type OriginSuccess = DidRawOrigin; type OwnerOrigin = EnsureDidOrigin; type RuntimeEvent = RuntimeEvent; - type Web3Name = AsciiWeb3Name; + type Web3Name = Web3Name; type Web3NameOwner = DidIdentifier; type WeightInfo = (); } diff --git a/pallets/pallet-web3-names/src/lib.rs b/pallets/pallet-web3-names/src/lib.rs index d6ed7c4a18..e08edad9bc 100644 --- a/pallets/pallet-web3-names/src/lib.rs +++ b/pallets/pallet-web3-names/src/lib.rs @@ -122,7 +122,8 @@ pub mod pallet { + Clone + TypeInfo + TryFrom, Error = Error> - + MaxEncodedLen; + + MaxEncodedLen + + Ord; /// The type of a name owner. type Web3NameOwner: Parameter + MaxEncodedLen; /// Weight information for extrinsics in this pallet. diff --git a/pallets/pallet-web3-names/src/web3_name.rs b/pallets/pallet-web3-names/src/web3_name.rs index 37b393a16d..e83e221aa9 100644 --- a/pallets/pallet-web3-names/src/web3_name.rs +++ b/pallets/pallet-web3-names/src/web3_name.rs @@ -82,6 +82,27 @@ impl PartialEq for AsciiWeb3Name { } } +// FIXME: did not find a way to automatically implement this. +impl Eq for AsciiWeb3Name { + fn assert_receiver_is_total_eq(&self) { + self.0.assert_receiver_is_total_eq() + } +} + +// FIXME: did not find a way to automatically implement this. +impl PartialOrd for AsciiWeb3Name { + fn partial_cmp(&self, other: &Self) -> Option { + self.0.as_slice().partial_cmp(other.as_slice()) + } +} + +// FIXME: did not find a way to automatically implement this. +impl Ord for AsciiWeb3Name { + fn cmp(&self, other: &Self) -> sp_std::cmp::Ordering { + self.0.cmp(&other.0) + } +} + // FIXME: did not find a way to automatically implement this. impl Clone for AsciiWeb3Name { fn clone(&self) -> Self { @@ -89,6 +110,13 @@ impl Clone for AsciiWeb3Name { } } +// FIXME: did not find a way to automatically implement this. +impl Default for AsciiWeb3Name { + fn default() -> Self { + Self(BoundedVec::default(), PhantomData) + } +} + /// KILT web3 name ownership details. #[derive(Clone, Encode, Decode, Debug, Eq, PartialEq, TypeInfo, MaxEncodedLen)] pub struct Web3NameOwnership { diff --git a/runtimes/common/src/dip/merkle.rs b/runtimes/common/src/dip/merkle.rs index 9af324850a..e6a7d0be9b 100644 --- a/runtimes/common/src/dip/merkle.rs +++ b/runtimes/common/src/dip/merkle.rs @@ -30,8 +30,10 @@ use kilt_dip_support::merkle::{DidKeyRelationship, ProofLeaf}; use crate::{dip::did::LinkedDidInfoOf, DidIdentifier}; pub type BlindedValue = Vec; -pub type DidMerkleProofOf = - MerkleProof, ProofLeaf, ::BlockNumber>>; +pub type DidMerkleProofOf = MerkleProof< + Vec, + ProofLeaf, ::BlockNumber, ::Web3Name>, +>; #[derive(Encode, Decode, RuntimeDebug, PartialEq, Eq, TypeInfo)] pub struct CompleteMerkleProof { @@ -68,7 +70,7 @@ where .public_keys .get(&did_details.authentication_key) .expect("Authentication key should be part of the public keys."); - let auth_leaf = ProofLeaf::<_, T::BlockNumber>::DidKey( + let auth_leaf = ProofLeaf::<_, _, T::Web3Name>::DidKey( DidKeyMerkleKey( did_details.authentication_key, DidVerificationKeyRelationship::Authentication.into(), @@ -84,7 +86,7 @@ where .public_keys .get(&att_key_id) .expect("Attestation key should be part of the public keys."); - let att_leaf = ProofLeaf::<_, T::BlockNumber>::DidKey( + let att_leaf = ProofLeaf::<_, _, T::Web3Name>::DidKey( DidKeyMerkleKey(att_key_id, DidVerificationKeyRelationship::AssertionMethod.into()), DidKeyMerkleValue(att_key_details.clone()), ); @@ -98,7 +100,7 @@ where .public_keys .get(&del_key_id) .expect("Delegation key should be part of the public keys."); - let del_leaf = ProofLeaf::<_, T::BlockNumber>::DidKey( + let del_leaf = ProofLeaf::<_, _, T::Web3Name>::DidKey( DidKeyMerkleKey(del_key_id, DidVerificationKeyRelationship::CapabilityDelegation.into()), DidKeyMerkleValue(del_key_details.clone()), ); @@ -115,7 +117,7 @@ where .public_keys .get(id) .expect("Key agreement key should be part of the public keys."); - let enc_leaf = ProofLeaf::<_, T::BlockNumber>::DidKey( + let enc_leaf = ProofLeaf::<_, _, T::Web3Name>::DidKey( DidKeyMerkleKey(*id, DidKeyRelationship::Encryption), DidKeyMerkleValue(key_agreement_details.clone()), ); @@ -147,7 +149,7 @@ where let root = Self::calculate_root_with_db(identity, &mut db)?; #[allow(clippy::type_complexity)] - let leaves: BTreeSet, T::BlockNumber>> = + let leaves: BTreeSet, T::BlockNumber, T::Web3Name>> = key_ids.try_fold(BTreeSet::new(), |mut set, key_id| -> Result<_, ()> { let key_details = did_details.public_keys.get(key_id).ok_or(())?; // Create the merkle leaf key depending on the relationship of the key to the From 2c5fa1a7dbcaece3cfcedd2b44e243a0ebc3b52e Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Tue, 23 May 2023 11:58:46 +0200 Subject: [PATCH 07/15] Adjust some types, more clear now --- crates/dip-support/src/lib.rs | 2 +- crates/kilt-dip-support/src/did.rs | 61 +++++----- crates/kilt-dip-support/src/lib.rs | 24 ++-- crates/kilt-dip-support/src/merkle.rs | 115 +++++++++++------- crates/kilt-dip-support/src/traits.rs | 1 - dip-template/runtimes/dip-consumer/src/dip.rs | 6 +- dip-template/runtimes/dip-consumer/src/lib.rs | 7 +- dip-template/runtimes/dip-provider/src/dip.rs | 6 +- dip-template/runtimes/xcm-tests/src/tests.rs | 6 +- pallets/pallet-dip-consumer/src/lib.rs | 22 ++-- pallets/pallet-dip-consumer/src/origin.rs | 4 +- pallets/pallet-dip-consumer/src/traits.rs | 8 +- pallets/pallet-dip-provider/src/lib.rs | 13 +- pallets/pallet-dip-provider/src/traits.rs | 10 +- 14 files changed, 154 insertions(+), 131 deletions(-) diff --git a/crates/dip-support/src/lib.rs b/crates/dip-support/src/lib.rs index bde5dbfee3..31256a1dda 100644 --- a/crates/dip-support/src/lib.rs +++ b/crates/dip-support/src/lib.rs @@ -25,7 +25,7 @@ use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; #[derive(Clone, Eq, PartialEq, Encode, Decode, TypeInfo, MaxEncodedLen, RuntimeDebug)] -pub enum IdentityProofAction { +pub enum IdentityDetailsAction { Updated(Identifier, Proof, Details), Deleted(Identifier), } diff --git a/crates/kilt-dip-support/src/did.rs b/crates/kilt-dip-support/src/did.rs index 521fcb8dcb..ac2bfa33bb 100644 --- a/crates/kilt-dip-support/src/did.rs +++ b/crates/kilt-dip-support/src/did.rs @@ -30,7 +30,7 @@ use sp_runtime::traits::CheckedSub; use sp_std::marker::PhantomData; use crate::{ - merkle::ProofEntry, + merkle::RevealedDidKey, traits::{Bump, DidDipOriginFilter}, }; @@ -41,8 +41,8 @@ pub struct TimeBoundDidSignature { } #[derive(Encode, Decode, RuntimeDebug, Clone, Eq, PartialEq, TypeInfo)] -pub struct MerkleEntriesAndDidSignature { - pub merkle_entries: MerkleEntries, +pub struct MerkleLeavesAndDidSignature { + pub merkle_leaves: MerkleLeaves, pub did_signature: TimeBoundDidSignature, } @@ -54,13 +54,13 @@ pub struct MerkleEntriesAndDidSignature { /// genesis_hash). Additional details can be added to the end of the tuple by /// providing a `SignedExtraProvider`. pub struct MerkleRevealedDidSignatureVerifier< + KeyId, BlockNumber, Digest, Details, AccountId, MerkleProofEntries, BlockNumberProvider, - Web3Name, const SIGNATURE_VALIDITY: u64, GenesisHashProvider, Hash, @@ -69,13 +69,13 @@ pub struct MerkleRevealedDidSignatureVerifier< >( #[allow(clippy::type_complexity)] PhantomData<( + KeyId, BlockNumber, Digest, Details, AccountId, MerkleProofEntries, BlockNumberProvider, - Web3Name, ConstU64, GenesisHashProvider, Hash, @@ -87,13 +87,13 @@ pub struct MerkleRevealedDidSignatureVerifier< impl< Call, Subject, + KeyId, BlockNumber, Digest, Details, AccountId, MerkleProofEntries, BlockNumberProvider, - Web3Name, const SIGNATURE_VALIDITY: u64, GenesisHashProvider, Hash, @@ -101,13 +101,13 @@ impl< SignedExtra, > IdentityProofVerifier for MerkleRevealedDidSignatureVerifier< + KeyId, BlockNumber, Digest, Details, AccountId, MerkleProofEntries, BlockNumberProvider, - Web3Name, SIGNATURE_VALIDITY, GenesisHashProvider, Hash, @@ -119,7 +119,7 @@ impl< Call: Encode, Digest: Encode, Details: Bump + Encode, - MerkleProofEntries: AsRef<[ProofEntry]>, + MerkleProofEntries: AsRef<[RevealedDidKey]>, BlockNumberProvider: Get, GenesisHashProvider: Get, Hash: Encode, @@ -130,7 +130,7 @@ impl< type Error = (); /// The proof must be a list of Merkle leaves that have been previously /// verified by the Merkle proof verifier, and the additional DID signature. - type Proof = MerkleEntriesAndDidSignature; + type Proof = MerkleLeavesAndDidSignature; /// The `Details` that are part of the identity details must implement the /// `Bump` trait. type IdentityDetails = IdentityDetails; @@ -140,11 +140,11 @@ impl< /// the provided signature and its relationship to the DID subject. type VerificationResult = (DidVerificationKey, DidVerificationKeyRelationship); - fn verify_proof_for_call_against_entry( + fn verify_proof_for_call_against_details( call: &Call, _subject: &Subject, submitter: &Self::Submitter, - proof_entry: &mut Self::IdentityDetails, + identity_details: &mut Self::IdentityDetails, proof: &Self::Proof, ) -> Result { let block_number = BlockNumberProvider::get(); @@ -156,36 +156,30 @@ impl< // Signature generated at a future time, not possible to verify. false }; + ensure!(is_signature_fresh, ()); let encoded_payload = ( call, - &proof_entry.details, + &identity_details.details, submitter, &proof.did_signature.block_number, GenesisHashProvider::get(), SignedExtraProvider::get(), ) .encode(); - // Only consider verification keys from the set of revealed Merkle leaves. - let mut proof_verification_keys = proof.merkle_entries.as_ref().iter().filter_map(|proof_entry| { - let ProofEntry::DidKey(relationship, DidPublicKeyDetails { key, .. }) = proof_entry else { return None }; - let DidPublicKey::PublicVerificationKey(k) = key else { return None }; - Some(( - k, - DidVerificationKeyRelationship::try_from(*relationship).expect("Should never fail to build a VerificationRelationship from the given DidKeyRelationship because we have already made sure the conditions hold."), - )) + // Only consider verification keys from the set of revealed keys. + let mut proof_verification_keys = proof.merkle_leaves.as_ref().iter().filter_map(|RevealedDidKey { relationship, details: DidPublicKeyDetails { key, .. }, .. } | { + let DidPublicKey::PublicVerificationKey(key) = key else { return None }; + Some((key, DidVerificationKeyRelationship::try_from(*relationship).expect("Should never fail to build a VerificationRelationship from the given DidKeyRelationship because we have already made sure the conditions hold."))) }); let valid_signing_key = proof_verification_keys.find(|(verification_key, _)| { verification_key .verify_signature(&encoded_payload, &proof.did_signature.signature) .is_ok() }); - if let Some((key, relationship)) = valid_signing_key { - proof_entry.details.bump(); - Ok((key.clone(), relationship)) - } else { - Err(()) - } + let Some((key, relationship)) = valid_signing_key else { return Err(()) }; + identity_details.details.bump(); + Ok((key.clone(), relationship)) } } @@ -221,16 +215,21 @@ where /// `DidSignatureVerifier`. type VerificationResult = DidSignatureVerifier::VerificationResult; - fn verify_proof_for_call_against_entry( + fn verify_proof_for_call_against_details( call: &Call, subject: &Subject, submitter: &Self::Submitter, - proof_entry: &mut Self::IdentityDetails, + identity_details: &mut Self::IdentityDetails, proof: &Self::Proof, ) -> Result { - let did_signing_key = - DidSignatureVerifier::verify_proof_for_call_against_entry(call, subject, submitter, proof_entry, proof) - .map_err(|_| ())?; + let did_signing_key = DidSignatureVerifier::verify_proof_for_call_against_details( + call, + subject, + submitter, + identity_details, + proof, + ) + .map_err(|_| ())?; CallVerifier::check_call_origin_info(call, &did_signing_key).map_err(|_| ())?; Ok(did_signing_key) } diff --git a/crates/kilt-dip-support/src/lib.rs b/crates/kilt-dip-support/src/lib.rs index c2f18ba0f8..103a5c504f 100644 --- a/crates/kilt-dip-support/src/lib.rs +++ b/crates/kilt-dip-support/src/lib.rs @@ -23,7 +23,7 @@ use pallet_dip_consumer::traits::IdentityProofVerifier; use sp_std::marker::PhantomData; -use crate::did::MerkleEntriesAndDidSignature; +use crate::did::MerkleLeavesAndDidSignature; pub mod did; pub mod merkle; @@ -50,7 +50,7 @@ where DidSignatureVerifier: IdentityProofVerifier< Call, Subject, - Proof = MerkleEntriesAndDidSignature, + Proof = MerkleLeavesAndDidSignature, IdentityDetails = MerkleProofVerifier::IdentityDetails, Submitter = MerkleProofVerifier::Submitter, >, @@ -58,34 +58,34 @@ where // FIXME: Better error handling type Error = (); // FIXME: Better type declaration - type Proof = MerkleEntriesAndDidSignature; + type Proof = MerkleLeavesAndDidSignature; type IdentityDetails = DidSignatureVerifier::IdentityDetails; type Submitter = MerkleProofVerifier::Submitter; type VerificationResult = MerkleProofVerifier::VerificationResult; - fn verify_proof_for_call_against_entry( + fn verify_proof_for_call_against_details( call: &Call, subject: &Subject, submitter: &Self::Submitter, - proof_entry: &mut Self::IdentityDetails, + identity_details: &mut Self::IdentityDetails, proof: &Self::Proof, ) -> Result { - let merkle_proof_verification = MerkleProofVerifier::verify_proof_for_call_against_entry( + let merkle_proof_verification = MerkleProofVerifier::verify_proof_for_call_against_details( call, subject, submitter, - proof_entry, - &proof.merkle_entries, + identity_details, + &proof.merkle_leaves, ) .map_err(|_| ())?; - DidSignatureVerifier::verify_proof_for_call_against_entry( + DidSignatureVerifier::verify_proof_for_call_against_details( call, subject, submitter, - proof_entry, + identity_details, // FIXME: Remove `clone()` requirement - &MerkleEntriesAndDidSignature { - merkle_entries: merkle_proof_verification.clone(), + &MerkleLeavesAndDidSignature { + merkle_leaves: merkle_proof_verification.clone(), did_signature: proof.did_signature.clone(), }, ) diff --git a/crates/kilt-dip-support/src/merkle.rs b/crates/kilt-dip-support/src/merkle.rs index a093e293c4..5149edfbba 100644 --- a/crates/kilt-dip-support/src/merkle.rs +++ b/crates/kilt-dip-support/src/merkle.rs @@ -21,7 +21,7 @@ use frame_support::{traits::ConstU32, RuntimeDebug}; use pallet_dip_consumer::{identity::IdentityDetails, traits::IdentityProofVerifier}; use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; -use sp_runtime::BoundedVec; +use sp_runtime::{BoundedVec, SaturatedConversion}; use sp_std::{fmt::Debug, marker::PhantomData, vec::Vec}; use sp_trie::{verify_trie_proof, LayoutV1}; @@ -61,14 +61,39 @@ impl TryFrom for DidVerificationKeyRelationship { #[derive(Clone, Encode, Decode, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug, TypeInfo)] pub struct DidKeyMerkleKey(pub KeyId, pub DidKeyRelationship); + +impl From<(KeyId, DidKeyRelationship)> for DidKeyMerkleKey { + fn from(value: (KeyId, DidKeyRelationship)) -> Self { + Self(value.0, value.1) + } +} + #[derive(Clone, Encode, Decode, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug, TypeInfo)] pub struct DidKeyMerkleValue(pub DidPublicKeyDetails); +impl From> for DidKeyMerkleValue { + fn from(value: DidPublicKeyDetails) -> Self { + Self(value) + } +} + #[derive(Clone, Encode, Decode, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug, TypeInfo)] pub struct Web3NameMerkleKey(pub Web3Name); + +impl From for Web3NameMerkleKey { + fn from(value: Web3Name) -> Self { + Self(value) + } +} #[derive(Clone, Encode, Decode, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug, TypeInfo)] pub struct Web3NameMerkleValue; +impl From<()> for Web3NameMerkleValue { + fn from(_value: ()) -> Self { + Self + } +} + #[derive(Clone, Encode, Decode, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug, TypeInfo)] pub enum ProofLeaf { // The key and value for the leaves of a merkle proof that contain a reference @@ -102,38 +127,24 @@ where } } -// TODO: Avoid repetition of the same key if it appears multiple times, e.g., by -// having a vector of `DidKeyRelationship` instead. -#[derive(Clone, RuntimeDebug, PartialEq, Eq, TypeInfo, MaxEncodedLen, Encode, Decode)] -pub enum ProofEntry { - DidKey(DidKeyRelationship, DidPublicKeyDetails), - Web3Name(Web3Name), +#[derive(Clone, Encode, Decode, PartialEq, MaxEncodedLen, Eq, PartialOrd, Ord, RuntimeDebug, TypeInfo)] +pub struct RevealedDidKey { + pub id: KeyId, + pub relationship: DidKeyRelationship, + pub details: DidPublicKeyDetails, } -// Contains the list of revealed public keys after a given Merkle proof has been -// correctly verified. #[derive(Clone, Debug, PartialEq, Eq, TypeInfo, MaxEncodedLen, Encode, Decode, Default)] -pub struct VerificationResult( - pub BoundedVec, ConstU32>, -); - -impl TryFrom>> - for VerificationResult -{ - // TODO: Better error handling - type Error = (); - - fn try_from(value: Vec>) -> Result { - let bounded_inner = value.try_into().map_err(|_| ())?; - Ok(Self(bounded_inner)) - } +pub struct VerificationResult { + pub did_keys: BoundedVec, ConstU32>, + pub web3_name: Option, } -impl AsRef<[ProofEntry]> - for VerificationResult +impl AsRef<[RevealedDidKey]> + for VerificationResult { - fn as_ref(&self) -> &[ProofEntry] { - self.0.as_ref() + fn as_ref(&self) -> &[RevealedDidKey] { + self.did_keys.as_ref() } } @@ -147,7 +158,7 @@ pub struct DidMerkleProofVerifier< BlockNumber, Details, Web3Name, - const MAX_REVEALED_LEAVES_COUNT: u32, + const MAX_REVEALED_KEYS_COUNT: u32, >( PhantomData<( Hasher, @@ -156,13 +167,13 @@ pub struct DidMerkleProofVerifier< BlockNumber, Details, Web3Name, - ConstU32, + ConstU32, )>, ); -impl +impl IdentityProofVerifier - for DidMerkleProofVerifier + for DidMerkleProofVerifier where // TODO: Remove `Debug` bound BlockNumber: Encode + Clone + Debug, @@ -175,13 +186,13 @@ where type Proof = MerkleProof>, ProofLeaf>; type IdentityDetails = IdentityDetails; type Submitter = AccountId; - type VerificationResult = VerificationResult; + type VerificationResult = VerificationResult; - fn verify_proof_for_call_against_entry( + fn verify_proof_for_call_against_details( _call: &Call, _subject: &Subject, _submitter: &Self::Submitter, - proof_entry: &mut Self::IdentityDetails, + identity_details: &mut Self::IdentityDetails, proof: &Self::Proof, ) -> Result { // TODO: more efficient by removing cloning and/or collecting. @@ -193,7 +204,7 @@ where .map(|leaf| (leaf.encoded_key(), Some(leaf.encoded_value()))) .collect::, Option>)>>(); verify_trie_proof::, _, _, _>( - &proof_entry.digest.clone().into(), + &identity_details.digest.clone().into(), &proof.blinded, &proof_leaves, ) @@ -202,14 +213,30 @@ where // At this point, we know the proof is valid. We just need to map the revealed // leaves to something the consumer can easily operate on. - let leaves: Vec> = proof - .revealed - .iter() - .map(|leaf| match leaf { - ProofLeaf::DidKey(key_id, key_value) => ProofEntry::DidKey(key_id.1, key_value.0.clone()), - ProofLeaf::Web3Name(web3_name_id, _) => ProofEntry::Web3Name(web3_name_id.0.clone()), - }) - .collect(); - leaves.try_into() + let (did_keys, web3_name): ( + BoundedVec, ConstU32>, + Option, + ) = proof.revealed.iter().try_fold( + ( + BoundedVec::with_bounded_capacity(MAX_REVEALED_KEYS_COUNT.saturated_into()), + None, + ), + |(mut keys, web3_name), leaf| match leaf { + ProofLeaf::DidKey(key_id, key_value) => { + keys.try_push(RevealedDidKey { + // TODO: Avoid cloning if possible + id: key_id.0.clone(), + relationship: key_id.1, + details: key_value.0.clone(), + }) + .map_err(|_| ())?; + Ok::<_, ()>((keys, web3_name)) + } + // TODO: Avoid cloning if possible + ProofLeaf::Web3Name(revealed_web3_name, _) => Ok((keys, Some(revealed_web3_name.0.clone()))), + }, + )?; + + Ok(VerificationResult { did_keys, web3_name }) } } diff --git a/crates/kilt-dip-support/src/traits.rs b/crates/kilt-dip-support/src/traits.rs index 56d4dd09b1..66417991e8 100644 --- a/crates/kilt-dip-support/src/traits.rs +++ b/crates/kilt-dip-support/src/traits.rs @@ -34,7 +34,6 @@ impl Bump for T where T: CheckedAdd + Zero + One, { - // FIXME: Better implementation? fn bump(&mut self) { *self = self.checked_add(&Self::one()).unwrap_or_else(Self::zero); } diff --git a/dip-template/runtimes/dip-consumer/src/dip.rs b/dip-template/runtimes/dip-consumer/src/dip.rs index 3d2a1f3a11..2896ee4678 100644 --- a/dip-template/runtimes/dip-consumer/src/dip.rs +++ b/dip-template/runtimes/dip-consumer/src/dip.rs @@ -20,7 +20,7 @@ use did::{did_details::DidVerificationKey, DidVerificationKeyRelationship, KeyId use dip_provider_runtime_template::Web3Name; use frame_support::traits::Contains; use kilt_dip_support::{ - did::{DidSignatureAndCallVerifier, MerkleEntriesAndDidSignature, MerkleRevealedDidSignatureVerifier}, + did::{DidSignatureAndCallVerifier, MerkleLeavesAndDidSignature, MerkleRevealedDidSignatureVerifier}, merkle::{DidMerkleProofVerifier, MerkleProof, ProofLeaf}, traits::{BlockNumberProvider, DidDipOriginFilter, GenesisProvider}, MerkleProofAndDidSignatureVerifier, @@ -35,13 +35,13 @@ pub type MerkleProofVerifier = pub type MerkleProofVerifierOutputOf = >::VerificationResult; pub type MerkleDidSignatureVerifierOf = MerkleRevealedDidSignatureVerifier< + KeyIdOf, BlockNumber, Hash, u128, AccountId, MerkleProofVerifierOutputOf, BlockNumberProvider, - Web3Name, // Signatures are valid for 50 blocks 50, GenesisProvider, @@ -53,7 +53,7 @@ impl pallet_dip_consumer::Config for Runtime { type Identifier = DidIdentifier; type IdentityDetails = u128; type Proof = - MerkleEntriesAndDidSignature>, ProofLeaf>, BlockNumber>; + MerkleLeavesAndDidSignature>, ProofLeaf>, BlockNumber>; type ProofDigest = Hash; type ProofVerifier = MerkleProofAndDidSignatureVerifier< BlockNumber, diff --git a/dip-template/runtimes/dip-consumer/src/lib.rs b/dip-template/runtimes/dip-consumer/src/lib.rs index dc18381505..e10779a8fe 100644 --- a/dip-template/runtimes/dip-consumer/src/lib.rs +++ b/dip-template/runtimes/dip-consumer/src/lib.rs @@ -22,6 +22,7 @@ #[cfg(feature = "std")] include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); +use did::KeyIdOf; use dip_provider_runtime_template::Web3Name; use kilt_dip_support::merkle::VerificationResult; pub use sp_consensus_aura::sr25519::AuthorityId as AuraId; @@ -368,8 +369,10 @@ impl pallet_did_lookup::Config for Runtime { type Currency = Balances; type Deposit = ConstU128; type DidIdentifier = DidIdentifier; - type EnsureOrigin = EnsureDipOrigin>; - type OriginSuccess = DipOrigin>; + type EnsureOrigin = + EnsureDipOrigin, BlockNumber, Web3Name, 10>>; + type OriginSuccess = + DipOrigin, BlockNumber, Web3Name, 10>>; type RuntimeEvent = RuntimeEvent; type WeightInfo = (); } diff --git a/dip-template/runtimes/dip-provider/src/dip.rs b/dip-template/runtimes/dip-provider/src/dip.rs index 63740c1352..97afed38f8 100644 --- a/dip-template/runtimes/dip-provider/src/dip.rs +++ b/dip-template/runtimes/dip-provider/src/dip.rs @@ -16,7 +16,7 @@ // If you feel like getting in touch with us, you can do so at info@botlabs.org -use dip_support::IdentityProofAction; +use dip_support::IdentityDetailsAction; use pallet_dip_provider::traits::{TxBuilder, XcmRouterDispatcher}; use parity_scale_codec::{Decode, Encode}; use runtime_common::dip::{did::LinkedDidInfoProviderOf, merkle::DidMerkleRootGenerator}; @@ -33,7 +33,7 @@ enum ConsumerParachainCalls { #[derive(Encode, Decode)] enum ConsumerParachainDipConsumerCalls { #[codec(index = 0)] - ProcessIdentityAction(IdentityProofAction), + ProcessIdentityAction(IdentityDetailsAction), } pub struct ConsumerParachainTxBuilder; @@ -42,7 +42,7 @@ impl TxBuilder for ConsumerParachainTxBuilder { fn build( _dest: MultiLocation, - action: IdentityProofAction, + action: IdentityDetailsAction, ) -> Result, Self::Error> { let double_encoded: DoubleEncoded<()> = ConsumerParachainCalls::DipConsumer(ConsumerParachainDipConsumerCalls::ProcessIdentityAction(action)) diff --git a/dip-template/runtimes/xcm-tests/src/tests.rs b/dip-template/runtimes/xcm-tests/src/tests.rs index 67dfd2076d..9c4175b92e 100644 --- a/dip-template/runtimes/xcm-tests/src/tests.rs +++ b/dip-template/runtimes/xcm-tests/src/tests.rs @@ -22,7 +22,7 @@ use did::{Did, DidSignature}; use frame_support::{assert_ok, weights::Weight}; use frame_system::RawOrigin; use kilt_dip_support::{ - did::{MerkleEntriesAndDidSignature, TimeBoundDidSignature}, + did::{MerkleLeavesAndDidSignature, TimeBoundDidSignature}, merkle::MerkleProof, }; use pallet_did_lookup::linkable_account::LinkableAccountId; @@ -106,8 +106,8 @@ fn commit_identity() { assert_ok!(DipConsumer::dispatch_as( RawOrigin::Signed(para::consumer::DISPATCHER_ACCOUNT).into(), did.clone(), - MerkleEntriesAndDidSignature { - merkle_entries: MerkleProof { + MerkleLeavesAndDidSignature { + merkle_leaves: MerkleProof { blinded: proof.blinded, revealed: proof.revealed, }, diff --git a/pallets/pallet-dip-consumer/src/lib.rs b/pallets/pallet-dip-consumer/src/lib.rs index f9712bf5a0..61818b6683 100644 --- a/pallets/pallet-dip-consumer/src/lib.rs +++ b/pallets/pallet-dip-consumer/src/lib.rs @@ -37,7 +37,7 @@ pub mod pallet { use parity_scale_codec::MaxEncodedLen; use sp_std::boxed::Box; - use dip_support::IdentityProofAction; + use dip_support::IdentityDetailsAction; use crate::{identity::IdentityDetails, traits::IdentityProofVerifier}; @@ -51,7 +51,7 @@ pub mod pallet { // TODO: Store also additional details received by the provider. #[pallet::storage] #[pallet::getter(fn identity_proofs)] - pub(crate) type IdentityProofs = StorageMap< + pub(crate) type IdentityEntries = StorageMap< _, Twox64Concat, ::Identifier, @@ -134,13 +134,13 @@ pub mod pallet { #[pallet::weight(0)] pub fn process_identity_action( origin: OriginFor, - action: IdentityProofAction, + action: IdentityDetailsAction, ) -> DispatchResult { ensure_sibling_para(::RuntimeOrigin::from(origin))?; let event = match action { - IdentityProofAction::Updated(identifier, proof, _) => { - IdentityProofs::::mutate( + IdentityDetailsAction::Updated(identifier, proof, _) => { + IdentityEntries::::mutate( &identifier, |entry: &mut Option< IdentityDetails<::ProofDigest, ::IdentityDetails>, @@ -148,8 +148,8 @@ pub mod pallet { ); Ok::<_, Error>(Event::::IdentityInfoUpdated(identifier, proof)) } - IdentityProofAction::Deleted(identifier) => { - IdentityProofs::::remove(&identifier); + IdentityDetailsAction::Deleted(identifier) => { + IdentityEntries::::remove(&identifier); Ok::<_, Error>(Event::::IdentityInfoDeleted(identifier)) } }?; @@ -171,18 +171,18 @@ pub mod pallet { let submitter = ensure_signed(origin)?; // TODO: Proper error handling ensure!(T::DipCallOriginFilter::contains(&*call), Error::::Dispatch); - let mut proof_entry = IdentityProofs::::get(&identifier).ok_or(Error::::IdentityNotFound)?; - let proof_verification_result = T::ProofVerifier::verify_proof_for_call_against_entry( + let mut identity_entry = IdentityEntries::::get(&identifier).ok_or(Error::::IdentityNotFound)?; + let proof_verification_result = T::ProofVerifier::verify_proof_for_call_against_details( &*call, &identifier, &submitter, - &mut proof_entry, + &mut identity_entry, &proof, ) .map_err(|_| Error::::InvalidProof)?; // Write the identity info to storage after it has optionally been updated by // the `ProofVerifier`. - IdentityProofs::::mutate(&identifier, |entry| *entry = Some(proof_entry)); + IdentityEntries::::mutate(&identifier, |entry| *entry = Some(identity_entry)); let did_origin = DipOrigin { identifier, account_address: submitter, diff --git a/pallets/pallet-dip-consumer/src/origin.rs b/pallets/pallet-dip-consumer/src/origin.rs index f030044479..415d055e0f 100644 --- a/pallets/pallet-dip-consumer/src/origin.rs +++ b/pallets/pallet-dip-consumer/src/origin.rs @@ -17,6 +17,7 @@ // If you feel like getting in touch with us, you can do so at info@botlabs.org use frame_support::{traits::EnsureOrigin, RuntimeDebug}; +use kilt_support::traits::CallSources; use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; use sp_std::marker::PhantomData; @@ -70,8 +71,7 @@ where } } -impl kilt_support::traits::CallSources - for DipOrigin +impl CallSources for DipOrigin where Identifier: Clone, AccountId: Clone, diff --git a/pallets/pallet-dip-consumer/src/traits.rs b/pallets/pallet-dip-consumer/src/traits.rs index 7f4645f166..63a5c8a831 100644 --- a/pallets/pallet-dip-consumer/src/traits.rs +++ b/pallets/pallet-dip-consumer/src/traits.rs @@ -25,11 +25,11 @@ pub trait IdentityProofVerifier { type Submitter; type VerificationResult; - fn verify_proof_for_call_against_entry( + fn verify_proof_for_call_against_details( call: &Call, subject: &Subject, submitter: &Self::Submitter, - proof_entry: &mut Self::IdentityDetails, + identity_details: &mut Self::IdentityDetails, proof: &Self::Proof, ) -> Result; } @@ -45,11 +45,11 @@ impl IdentityProofVerifier Result { Ok(()) diff --git a/pallets/pallet-dip-provider/src/lib.rs b/pallets/pallet-dip-provider/src/lib.rs index f2d94ae594..a970e22d50 100644 --- a/pallets/pallet-dip-provider/src/lib.rs +++ b/pallets/pallet-dip-provider/src/lib.rs @@ -33,12 +33,12 @@ pub mod pallet { use sp_std::{boxed::Box, fmt::Debug}; use xcm::{latest::prelude::*, VersionedMultiAsset, VersionedMultiLocation}; - use dip_support::IdentityProofAction; + use dip_support::IdentityDetailsAction; use crate::traits::{IdentityProofDispatcher, IdentityProofGenerator, IdentityProvider, TxBuilder}; pub type IdentityOf = <::IdentityProvider as IdentityProvider<::Identifier>>::Success; - pub type IdentityProofActionOf = IdentityProofAction<::Identifier, ::ProofOutput>; + pub type IdentityProofActionOf = IdentityDetailsAction<::Identifier, ::ProofOutput>; const STORAGE_VERSION: StorageVersion = StorageVersion::new(0); @@ -62,11 +62,6 @@ pub mod pallet { #[pallet::storage_version(STORAGE_VERSION)] pub struct Pallet(_); - // #[pallet::storage] - // #[pallet::getter(fn destination_info)] - // pub type DestinationInfos = StorageMap<_, Blake2_128Concat, NetworkId, - // ()>; - #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { @@ -102,9 +97,9 @@ pub mod pallet { Ok(Some(identity)) => { let identity_proof = T::IdentityProofGenerator::generate_commitment(&identifier, &identity) .map_err(|_| Error::::IdentityProofGeneration)?; - Ok(IdentityProofAction::Updated(identifier, identity_proof, ())) + Ok(IdentityDetailsAction::Updated(identifier, identity_proof, ())) } - Ok(None) => Ok(IdentityProofAction::Deleted(identifier)), + Ok(None) => Ok(IdentityDetailsAction::Deleted(identifier)), Err(_) => Err(Error::::IdentityNotFound), }?; // TODO: Add correct version creation based on lookup (?) diff --git a/pallets/pallet-dip-provider/src/traits.rs b/pallets/pallet-dip-provider/src/traits.rs index 2f339bed42..12784472e4 100644 --- a/pallets/pallet-dip-provider/src/traits.rs +++ b/pallets/pallet-dip-provider/src/traits.rs @@ -16,7 +16,7 @@ // If you feel like getting in touch with us, you can do so at info@botlabs.org -use dip_support::IdentityProofAction; +use dip_support::IdentityDetailsAction; use xcm::{latest::prelude::*, DoubleEncoded}; pub use identity_generation::*; @@ -61,7 +61,7 @@ pub mod identity_dispatch { type Error; fn pre_dispatch>( - action: IdentityProofAction, + action: IdentityDetailsAction, asset: MultiAsset, weight: Weight, destination: MultiLocation, @@ -80,7 +80,7 @@ pub mod identity_dispatch { type Error = (); fn pre_dispatch<_B>( - _action: IdentityProofAction, + _action: IdentityDetailsAction, _asset: MultiAsset, _weight: Weight, _destination: MultiLocation, @@ -111,7 +111,7 @@ pub mod identity_dispatch { type Error = SendError; fn pre_dispatch>( - action: IdentityProofAction, + action: IdentityDetailsAction, asset: MultiAsset, weight: Weight, destination: MultiLocation, @@ -193,6 +193,6 @@ pub trait TxBuilder { fn build( dest: MultiLocation, - action: IdentityProofAction, + action: IdentityDetailsAction, ) -> Result, Self::Error>; } From 263dbb1f10ba3977a467cbd4decdafc2739d431d Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Wed, 24 May 2023 09:38:30 +0200 Subject: [PATCH 08/15] Some more refactoring --- Cargo.lock | 1 - dip-template/runtimes/dip-provider/Cargo.toml | 2 -- pallets/pallet-web3-names/src/lib.rs | 3 +-- runtimes/common/src/dip/merkle.rs | 2 ++ 4 files changed, 3 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3c3e7808e2..a137026537 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2450,7 +2450,6 @@ dependencies = [ "frame-support", "frame-system", "frame-system-rpc-runtime-api", - "kilt-dip-support", "kilt-runtime-api-dip-provider", "pallet-aura", "pallet-authorship", diff --git a/dip-template/runtimes/dip-provider/Cargo.toml b/dip-template/runtimes/dip-provider/Cargo.toml index 39dc4acc45..ce1a7582bb 100644 --- a/dip-template/runtimes/dip-provider/Cargo.toml +++ b/dip-template/runtimes/dip-provider/Cargo.toml @@ -20,7 +20,6 @@ scale-info = {workspace = true, features = ["derive"]} # DIP did.workspace = true dip-support.workspace = true -kilt-dip-support.workspace = true kilt-runtime-api-dip-provider.workspace = true pallet-did-lookup.workspace = true pallet-dip-provider.workspace = true @@ -79,7 +78,6 @@ std = [ "scale-info/std", "did/std", "dip-support/std", - "kilt-dip-support/std", "kilt-runtime-api-dip-provider/std", "pallet-did-lookup/std", "pallet-dip-provider/std", diff --git a/pallets/pallet-web3-names/src/lib.rs b/pallets/pallet-web3-names/src/lib.rs index e08edad9bc..d6ed7c4a18 100644 --- a/pallets/pallet-web3-names/src/lib.rs +++ b/pallets/pallet-web3-names/src/lib.rs @@ -122,8 +122,7 @@ pub mod pallet { + Clone + TypeInfo + TryFrom, Error = Error> - + MaxEncodedLen - + Ord; + + MaxEncodedLen; /// The type of a name owner. type Web3NameOwner: Parameter + MaxEncodedLen; /// Weight information for extrinsics in this pallet. diff --git a/runtimes/common/src/dip/merkle.rs b/runtimes/common/src/dip/merkle.rs index e6a7d0be9b..2fe06606ea 100644 --- a/runtimes/common/src/dip/merkle.rs +++ b/runtimes/common/src/dip/merkle.rs @@ -46,6 +46,7 @@ pub struct DidMerkleRootGenerator(PhantomData); impl DidMerkleRootGenerator where T: did::Config + pallet_did_lookup::Config + pallet_web3_names::Config, + ::Web3Name: Ord, { // Calls the function in the `sp_trie` crate to generate the merkle root given // the provided `DidDetails`. @@ -197,6 +198,7 @@ where impl IdentityProofGenerator> for DidMerkleRootGenerator where T: did::Config + pallet_did_lookup::Config + pallet_web3_names::Config, + ::Web3Name: Ord, { // TODO: Proper error handling type Error = (); From 544b1435d5431bea6acbbd975d9b25845f62c4cf Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Wed, 24 May 2023 11:48:04 +0200 Subject: [PATCH 09/15] Compiling again --- crates/kilt-dip-support/src/merkle.rs | 125 +++++++++++++++--- dip-template/runtimes/dip-consumer/src/dip.rs | 9 +- dip-template/runtimes/dip-consumer/src/lib.rs | 15 ++- .../pallet-did-lookup/src/linkable_account.rs | 9 ++ pallets/pallet-web3-names/src/lib.rs | 3 +- runtimes/common/src/dip/merkle.rs | 69 +++++++--- 6 files changed, 189 insertions(+), 41 deletions(-) diff --git a/crates/kilt-dip-support/src/merkle.rs b/crates/kilt-dip-support/src/merkle.rs index 5149edfbba..edaacad9b9 100644 --- a/crates/kilt-dip-support/src/merkle.rs +++ b/crates/kilt-dip-support/src/merkle.rs @@ -95,27 +95,48 @@ impl From<()> for Web3NameMerkleValue { } #[derive(Clone, Encode, Decode, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug, TypeInfo)] -pub enum ProofLeaf { +pub struct LinkedAccountMerkleKey(pub AccountId); + +impl From for LinkedAccountMerkleKey { + fn from(value: AccountId) -> Self { + Self(value) + } +} + +#[derive(Clone, Encode, Decode, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug, TypeInfo)] +pub struct LinkedAccountMerkleValue; + +impl From<()> for LinkedAccountMerkleValue { + fn from(_value: ()) -> Self { + Self + } +} + +#[derive(Clone, Encode, Decode, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug, TypeInfo)] +pub enum ProofLeaf { // The key and value for the leaves of a merkle proof that contain a reference // (by ID) to the key details, provided in a separate leaf. DidKey(DidKeyMerkleKey, DidKeyMerkleValue), Web3Name(Web3NameMerkleKey, Web3NameMerkleValue), + LinkedAccount(LinkedAccountMerkleKey, LinkedAccountMerkleValue), } -impl ProofLeaf +impl ProofLeaf where KeyId: Encode, Web3Name: Encode, + LinkedAccountId: Encode, { pub fn encoded_key(&self) -> Vec { match self { ProofLeaf::DidKey(key, _) => key.encode(), ProofLeaf::Web3Name(key, _) => key.encode(), + ProofLeaf::LinkedAccount(key, _) => key.encode(), } } } -impl ProofLeaf +impl ProofLeaf where BlockNumber: Encode, { @@ -123,6 +144,7 @@ where match self { ProofLeaf::DidKey(_, value) => value.encode(), ProofLeaf::Web3Name(_, value) => value.encode(), + ProofLeaf::LinkedAccount(_, value) => value.encode(), } } } @@ -135,13 +157,35 @@ pub struct RevealedDidKey { } #[derive(Clone, Debug, PartialEq, Eq, TypeInfo, MaxEncodedLen, Encode, Decode, Default)] -pub struct VerificationResult { +pub struct VerificationResult< + KeyId, + BlockNumber, + Web3Name, + LinkedAccountId, + const MAX_REVEALED_KEYS_COUNT: u32, + const MAX_REVEALED_ACCOUNTS_COUNT: u32, +> { pub did_keys: BoundedVec, ConstU32>, pub web3_name: Option, + pub linked_accounts: BoundedVec>, } -impl AsRef<[RevealedDidKey]> - for VerificationResult +impl< + KeyId, + BlockNumber, + Web3Name, + LinkedAccountId, + const MAX_REVEALED_KEYS_COUNT: u32, + const MAX_REVEALED_ACCOUNTS_COUNT: u32, + > AsRef<[RevealedDidKey]> + for VerificationResult< + KeyId, + BlockNumber, + Web3Name, + LinkedAccountId, + MAX_REVEALED_KEYS_COUNT, + MAX_REVEALED_ACCOUNTS_COUNT, + > { fn as_ref(&self) -> &[RevealedDidKey] { self.did_keys.as_ref() @@ -158,8 +202,11 @@ pub struct DidMerkleProofVerifier< BlockNumber, Details, Web3Name, + LinkedAccountId, const MAX_REVEALED_KEYS_COUNT: u32, + const MAX_REVEALED_ACCOUNTS_COUNT: u32, >( + #[allow(clippy::type_complexity)] PhantomData<( Hasher, AccountId, @@ -167,26 +214,56 @@ pub struct DidMerkleProofVerifier< BlockNumber, Details, Web3Name, + LinkedAccountId, ConstU32, + ConstU32, )>, ); -impl - IdentityProofVerifier - for DidMerkleProofVerifier -where +impl< + Call, + Subject, + Hasher, + AccountId, + KeyId, + BlockNumber, + Details, + Web3Name, + LinkedAccountId, + const MAX_REVEALED_KEYS_COUNT: u32, + const MAX_REVEALED_ACCOUNTS_COUNT: u32, + > IdentityProofVerifier + for DidMerkleProofVerifier< + Hasher, + AccountId, + KeyId, + BlockNumber, + Details, + Web3Name, + LinkedAccountId, + MAX_REVEALED_KEYS_COUNT, + MAX_REVEALED_ACCOUNTS_COUNT, + > where // TODO: Remove `Debug` bound BlockNumber: Encode + Clone + Debug, Hasher: sp_core::Hasher, KeyId: Encode + Clone + Ord + Into, + LinkedAccountId: Encode + Clone, Web3Name: Encode + Clone, { // TODO: Proper error handling type Error = (); - type Proof = MerkleProof>, ProofLeaf>; + type Proof = MerkleProof>, ProofLeaf>; type IdentityDetails = IdentityDetails; type Submitter = AccountId; - type VerificationResult = VerificationResult; + type VerificationResult = VerificationResult< + KeyId, + BlockNumber, + Web3Name, + LinkedAccountId, + MAX_REVEALED_KEYS_COUNT, + MAX_REVEALED_ACCOUNTS_COUNT, + >; fn verify_proof_for_call_against_details( _call: &Call, @@ -212,16 +289,18 @@ where // At this point, we know the proof is valid. We just need to map the revealed // leaves to something the consumer can easily operate on. - - let (did_keys, web3_name): ( + #[allow(clippy::type_complexity)] + let (did_keys, web3_name, linked_accounts): ( BoundedVec, ConstU32>, Option, + BoundedVec>, ) = proof.revealed.iter().try_fold( ( BoundedVec::with_bounded_capacity(MAX_REVEALED_KEYS_COUNT.saturated_into()), None, + BoundedVec::with_bounded_capacity(MAX_REVEALED_ACCOUNTS_COUNT.saturated_into()), ), - |(mut keys, web3_name), leaf| match leaf { + |(mut keys, web3_name, mut linked_accounts), leaf| match leaf { ProofLeaf::DidKey(key_id, key_value) => { keys.try_push(RevealedDidKey { // TODO: Avoid cloning if possible @@ -230,13 +309,23 @@ where details: key_value.0.clone(), }) .map_err(|_| ())?; - Ok::<_, ()>((keys, web3_name)) + Ok::<_, ()>((keys, web3_name, linked_accounts)) } // TODO: Avoid cloning if possible - ProofLeaf::Web3Name(revealed_web3_name, _) => Ok((keys, Some(revealed_web3_name.0.clone()))), + ProofLeaf::Web3Name(revealed_web3_name, _) => { + Ok((keys, Some(revealed_web3_name.0.clone()), linked_accounts)) + } + ProofLeaf::LinkedAccount(account_id, _) => { + linked_accounts.try_push(account_id.0.clone()).map_err(|_| ())?; + Ok::<_, ()>((keys, web3_name, linked_accounts)) + } }, )?; - Ok(VerificationResult { did_keys, web3_name }) + Ok(VerificationResult { + did_keys, + web3_name, + linked_accounts, + }) } } diff --git a/dip-template/runtimes/dip-consumer/src/dip.rs b/dip-template/runtimes/dip-consumer/src/dip.rs index 2896ee4678..b629fe5820 100644 --- a/dip-template/runtimes/dip-consumer/src/dip.rs +++ b/dip-template/runtimes/dip-consumer/src/dip.rs @@ -25,13 +25,14 @@ use kilt_dip_support::{ traits::{BlockNumberProvider, DidDipOriginFilter, GenesisProvider}, MerkleProofAndDidSignatureVerifier, }; +use pallet_did_lookup::linkable_account::LinkableAccountId; use pallet_dip_consumer::traits::IdentityProofVerifier; use sp_std::vec::Vec; use crate::{AccountId, BlockNumber, DidIdentifier, Hash, Hasher, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin}; pub type MerkleProofVerifier = - DidMerkleProofVerifier, BlockNumber, u128, Web3Name, 10>; + DidMerkleProofVerifier, BlockNumber, u128, Web3Name, LinkableAccountId, 10, 10>; pub type MerkleProofVerifierOutputOf = >::VerificationResult; pub type MerkleDidSignatureVerifierOf = MerkleRevealedDidSignatureVerifier< @@ -52,8 +53,10 @@ impl pallet_dip_consumer::Config for Runtime { type DipCallOriginFilter = PreliminaryDipOriginFilter; type Identifier = DidIdentifier; type IdentityDetails = u128; - type Proof = - MerkleLeavesAndDidSignature>, ProofLeaf>, BlockNumber>; + type Proof = MerkleLeavesAndDidSignature< + MerkleProof>, ProofLeaf>, + BlockNumber, + >; type ProofDigest = Hash; type ProofVerifier = MerkleProofAndDidSignatureVerifier< BlockNumber, diff --git a/dip-template/runtimes/dip-consumer/src/lib.rs b/dip-template/runtimes/dip-consumer/src/lib.rs index e10779a8fe..03fcfb5dfe 100644 --- a/dip-template/runtimes/dip-consumer/src/lib.rs +++ b/dip-template/runtimes/dip-consumer/src/lib.rs @@ -25,6 +25,7 @@ include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); use did::KeyIdOf; use dip_provider_runtime_template::Web3Name; use kilt_dip_support::merkle::VerificationResult; +use pallet_did_lookup::linkable_account::LinkableAccountId; pub use sp_consensus_aura::sr25519::AuthorityId as AuraId; pub use sp_runtime::{MultiAddress, Perbill, Permill}; @@ -369,10 +370,16 @@ impl pallet_did_lookup::Config for Runtime { type Currency = Balances; type Deposit = ConstU128; type DidIdentifier = DidIdentifier; - type EnsureOrigin = - EnsureDipOrigin, BlockNumber, Web3Name, 10>>; - type OriginSuccess = - DipOrigin, BlockNumber, Web3Name, 10>>; + type EnsureOrigin = EnsureDipOrigin< + DidIdentifier, + AccountId, + VerificationResult, BlockNumber, Web3Name, LinkableAccountId, 10, 10>, + >; + type OriginSuccess = DipOrigin< + DidIdentifier, + AccountId, + VerificationResult, BlockNumber, Web3Name, LinkableAccountId, 10, 10>, + >; type RuntimeEvent = RuntimeEvent; type WeightInfo = (); } diff --git a/pallets/pallet-did-lookup/src/linkable_account.rs b/pallets/pallet-did-lookup/src/linkable_account.rs index 0f2e97b570..4d6ccc6f82 100644 --- a/pallets/pallet-did-lookup/src/linkable_account.rs +++ b/pallets/pallet-did-lookup/src/linkable_account.rs @@ -50,3 +50,12 @@ impl std::fmt::Display for LinkableAccountId { } } } + +// Default implementation required by the DipDidOrigin origin type, only for +// benchmarks. +#[cfg(feature = "runtime-benchmarks")] +impl Default for LinkableAccountId { + fn default() -> Self { + AccountId32::new([0u8; 32]).into() + } +} diff --git a/pallets/pallet-web3-names/src/lib.rs b/pallets/pallet-web3-names/src/lib.rs index d6ed7c4a18..e08edad9bc 100644 --- a/pallets/pallet-web3-names/src/lib.rs +++ b/pallets/pallet-web3-names/src/lib.rs @@ -122,7 +122,8 @@ pub mod pallet { + Clone + TypeInfo + TryFrom, Error = Error> - + MaxEncodedLen; + + MaxEncodedLen + + Ord; /// The type of a name owner. type Web3NameOwner: Parameter + MaxEncodedLen; /// Weight information for extrinsics in this pallet. diff --git a/runtimes/common/src/dip/merkle.rs b/runtimes/common/src/dip/merkle.rs index 2fe06606ea..91963d686e 100644 --- a/runtimes/common/src/dip/merkle.rs +++ b/runtimes/common/src/dip/merkle.rs @@ -19,6 +19,7 @@ use did::{DidVerificationKeyRelationship, KeyIdOf}; use frame_support::RuntimeDebug; use kilt_dip_support::merkle::{DidKeyMerkleKey, DidKeyMerkleValue, MerkleProof}; +use pallet_did_lookup::linkable_account::LinkableAccountId; use pallet_dip_provider::traits::IdentityProofGenerator; use parity_scale_codec::{Decode, Encode}; use scale_info::TypeInfo; @@ -32,7 +33,12 @@ use crate::{dip::did::LinkedDidInfoOf, DidIdentifier}; pub type BlindedValue = Vec; pub type DidMerkleProofOf = MerkleProof< Vec, - ProofLeaf, ::BlockNumber, ::Web3Name>, + ProofLeaf< + KeyIdOf, + ::BlockNumber, + ::Web3Name, + LinkableAccountId, + >, >; #[derive(Encode, Decode, RuntimeDebug, PartialEq, Eq, TypeInfo)] @@ -43,10 +49,16 @@ pub struct CompleteMerkleProof { pub struct DidMerkleRootGenerator(PhantomData); +type ProofLeafOf = ProofLeaf< + KeyIdOf, + ::BlockNumber, + ::Web3Name, + LinkableAccountId, +>; + impl DidMerkleRootGenerator where T: did::Config + pallet_did_lookup::Config + pallet_web3_names::Config, - ::Web3Name: Ord, { // Calls the function in the `sp_trie` crate to generate the merkle root given // the provided `DidDetails`. @@ -61,7 +73,7 @@ where // details leaf, as we already do with out `DidDetails` type. fn calculate_root_with_db(identity: &LinkedDidInfoOf, db: &mut MemoryDB) -> Result { // Fails if the DID details do not exist. - let (Some(did_details), _web3_name, _linked_accounts) = (&identity.a, &identity.b, &identity.c) else { return Err(()) }; + let (Some(did_details), web3_name, linked_accounts) = (&identity.a, &identity.b, &identity.c) else { return Err(()) }; let mut trie = TrieHash::>::default(); let mut trie_builder = TrieDBMutBuilder::>::new(db, &mut trie).build(); @@ -71,7 +83,7 @@ where .public_keys .get(&did_details.authentication_key) .expect("Authentication key should be part of the public keys."); - let auth_leaf = ProofLeaf::<_, _, T::Web3Name>::DidKey( + let auth_leaf = ProofLeafOf::::DidKey( DidKeyMerkleKey( did_details.authentication_key, DidVerificationKeyRelationship::Authentication.into(), @@ -87,9 +99,9 @@ where .public_keys .get(&att_key_id) .expect("Attestation key should be part of the public keys."); - let att_leaf = ProofLeaf::<_, _, T::Web3Name>::DidKey( - DidKeyMerkleKey(att_key_id, DidVerificationKeyRelationship::AssertionMethod.into()), - DidKeyMerkleValue(att_key_details.clone()), + let att_leaf = ProofLeafOf::::DidKey( + (att_key_id, DidVerificationKeyRelationship::AssertionMethod.into()).into(), + att_key_details.clone().into(), ); trie_builder .insert(att_leaf.encoded_key().as_slice(), att_leaf.encoded_value().as_slice()) @@ -101,9 +113,9 @@ where .public_keys .get(&del_key_id) .expect("Delegation key should be part of the public keys."); - let del_leaf = ProofLeaf::<_, _, T::Web3Name>::DidKey( - DidKeyMerkleKey(del_key_id, DidVerificationKeyRelationship::CapabilityDelegation.into()), - DidKeyMerkleValue(del_key_details.clone()), + let del_leaf = ProofLeafOf::::DidKey( + (del_key_id, DidVerificationKeyRelationship::CapabilityDelegation.into()).into(), + del_key_details.clone().into(), ); trie_builder .insert(del_leaf.encoded_key().as_slice(), del_leaf.encoded_value().as_slice()) @@ -118,15 +130,42 @@ where .public_keys .get(id) .expect("Key agreement key should be part of the public keys."); - let enc_leaf = ProofLeaf::<_, _, T::Web3Name>::DidKey( - DidKeyMerkleKey(*id, DidKeyRelationship::Encryption), - DidKeyMerkleValue(key_agreement_details.clone()), + let enc_leaf = ProofLeafOf::::DidKey( + (*id, DidKeyRelationship::Encryption).into(), + key_agreement_details.clone().into(), ); trie_builder .insert(enc_leaf.encoded_key().as_slice(), enc_leaf.encoded_value().as_slice()) .map_err(|_| ())?; Ok(()) })?; + + // Web3name, if present + if let Some(linked_web3_name) = web3_name { + let web3_name_leaf = ProofLeafOf::::Web3Name(linked_web3_name.clone().into(), ().into()); + trie_builder + .insert( + web3_name_leaf.encoded_key().as_slice(), + web3_name_leaf.encoded_value().as_slice(), + ) + .map_err(|_| ())?; + } + + // Linked accounts + if let Some(linked_accounts) = linked_accounts { + linked_accounts + .iter() + .try_for_each(|linked_account| -> Result<(), ()> { + let linked_account_leaf = ProofLeafOf::::LinkedAccount(linked_account.clone().into(), ().into()); + trie_builder + .insert( + linked_account_leaf.encoded_key().as_slice(), + linked_account_leaf.encoded_value().as_slice(), + ) + .map_err(|_| ())?; + Ok(()) + })?; + } trie_builder.commit(); Ok(trie_builder.root().to_owned()) } @@ -144,13 +183,14 @@ where where K: Iterator>, { + // Fails if the DID details do not exist. let (Some(did_details), _web3_name, _linked_accounts) = (&identity.a, &identity.b, &identity.c) else { return Err(()) }; let mut db = MemoryDB::default(); let root = Self::calculate_root_with_db(identity, &mut db)?; #[allow(clippy::type_complexity)] - let leaves: BTreeSet, T::BlockNumber, T::Web3Name>> = + let leaves: BTreeSet, T::BlockNumber, T::Web3Name, LinkableAccountId>> = key_ids.try_fold(BTreeSet::new(), |mut set, key_id| -> Result<_, ()> { let key_details = did_details.public_keys.get(key_id).ok_or(())?; // Create the merkle leaf key depending on the relationship of the key to the @@ -198,7 +238,6 @@ where impl IdentityProofGenerator> for DidMerkleRootGenerator where T: did::Config + pallet_did_lookup::Config + pallet_web3_names::Config, - ::Web3Name: Ord, { // TODO: Proper error handling type Error = (); From 57b7e7307ca33c6c30cdb6991e474eb1837a2d98 Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Wed, 24 May 2023 14:34:28 +0200 Subject: [PATCH 10/15] Compiling again --- dip-template/runtimes/dip-provider/src/lib.rs | 23 +++++-- dip-template/runtimes/xcm-tests/src/tests.rs | 2 + runtime-api/dip-provider/src/lib.rs | 8 +-- runtimes/common/src/dip/merkle.rs | 65 +++++++++++-------- 4 files changed, 58 insertions(+), 40 deletions(-) diff --git a/dip-template/runtimes/dip-provider/src/lib.rs b/dip-template/runtimes/dip-provider/src/lib.rs index cb25708c3d..b7b7e933f6 100644 --- a/dip-template/runtimes/dip-provider/src/lib.rs +++ b/dip-template/runtimes/dip-provider/src/lib.rs @@ -22,7 +22,9 @@ #[cfg(feature = "std")] include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); +use pallet_did_lookup::linkable_account::LinkableAccountId; use pallet_web3_names::web3_name::AsciiWeb3Name; +use parity_scale_codec::{Decode, Encode}; pub use sp_consensus_aura::sr25519::AuthorityId as AuraId; pub use sp_runtime::{MultiAddress, Perbill, Permill}; @@ -423,6 +425,14 @@ impl pallet_web3_names::Config for Runtime { type WeightInfo = (); } +#[derive(Encode, Decode)] +pub struct DipProofRequest { + identifier: DidIdentifier, + keys: Vec>, + accounts: Vec, + should_include_web3_name: bool, +} + impl_runtime_apis! { impl sp_consensus_aura::AuraApi for Runtime { fn slot_duration() -> SlotDuration { @@ -559,15 +569,14 @@ impl_runtime_apis! { } } - // TODO: `keys` could and should be a BTreeSet, but it makes it more complicated for clients to build the type. So we use a Vec, since the keys are deduplicated anyway at proof creation time. // TODO: Support generating different versions of the proof, based on the provided parameter - impl kilt_runtime_api_dip_provider::DipProvider, Vec>, CompleteMerkleProof>, ()> for Runtime { - fn generate_proof(identifier: DidIdentifier, keys: Vec>) -> Result>, ()> { - if let Ok(Some(did_details)) = ::IdentityProvider::retrieve(&identifier) { - DidMerkleRootGenerator::::generate_proof(&did_details, keys.iter()) - } else { - Err(()) + impl kilt_runtime_api_dip_provider::DipProvider>, ()> for Runtime { + fn generate_proof(request: DipProofRequest) -> Result>, ()> { + let Some(linked_did_info) = ::IdentityProvider::retrieve(&request.identifier)? else { return Err(()) }; + if linked_did_info.a.is_none() { + return Err(()); } + DidMerkleRootGenerator::::generate_proof(&linked_did_info, request.keys.iter(), request.should_include_web3_name, request.accounts.iter()) } } } diff --git a/dip-template/runtimes/xcm-tests/src/tests.rs b/dip-template/runtimes/xcm-tests/src/tests.rs index 9c4175b92e..316241c7e5 100644 --- a/dip-template/runtimes/xcm-tests/src/tests.rs +++ b/dip-template/runtimes/xcm-tests/src/tests.rs @@ -86,6 +86,8 @@ fn commit_identity() { let CompleteMerkleProof { proof, .. } = DidMerkleRootGenerator::::generate_proof( &LinkedDidInfoOf::from_a(Some(did_details.clone())), [did_details.authentication_key].iter(), + false, + [].iter(), ) .expect("Proof generation should not fail"); // 3.2 Generate a DID signature diff --git a/runtime-api/dip-provider/src/lib.rs b/runtime-api/dip-provider/src/lib.rs index 2cdcb534c1..b910f734c1 100644 --- a/runtime-api/dip-provider/src/lib.rs +++ b/runtime-api/dip-provider/src/lib.rs @@ -21,13 +21,11 @@ use parity_scale_codec::Codec; sp_api::decl_runtime_apis! { - pub trait DipProvider where - DidIdentifier: Codec, - KeyId: Codec, - KeyIds: Codec + IntoIterator, + pub trait DipProvider where + ProofRequest: Codec, Success: Codec, Error: Codec, { - fn generate_proof(identifier: DidIdentifier, keys: KeyIds) -> Result; + fn generate_proof(request: ProofRequest) -> Result; } } diff --git a/runtimes/common/src/dip/merkle.rs b/runtimes/common/src/dip/merkle.rs index 91963d686e..dbf9b2721c 100644 --- a/runtimes/common/src/dip/merkle.rs +++ b/runtimes/common/src/dip/merkle.rs @@ -23,7 +23,7 @@ use pallet_did_lookup::linkable_account::LinkableAccountId; use pallet_dip_provider::traits::IdentityProofGenerator; use parity_scale_codec::{Decode, Encode}; use scale_info::TypeInfo; -use sp_std::{borrow::ToOwned, collections::btree_set::BTreeSet, marker::PhantomData, vec::Vec}; +use sp_std::{borrow::ToOwned, marker::PhantomData, vec::Vec}; use sp_trie::{generate_trie_proof, LayoutV1, MemoryDB, TrieDBMutBuilder, TrieHash, TrieMut}; use kilt_dip_support::merkle::{DidKeyRelationship, ProofLeaf}; @@ -176,12 +176,15 @@ where // generates a merkle proof which only reveals the details of the provided key // IDs. #[allow(clippy::result_unit_err)] - pub fn generate_proof<'a, K>( + pub fn generate_proof<'a, K, A>( identity: &LinkedDidInfoOf, - mut key_ids: K, + key_ids: K, + should_include_web3_name: bool, + account_ids: A, ) -> Result>, ()> where K: Iterator>, + A: Iterator, { // Fails if the DID details do not exist. let (Some(did_details), _web3_name, _linked_accounts) = (&identity.a, &identity.b, &identity.c) else { return Err(()) }; @@ -189,47 +192,53 @@ where let mut db = MemoryDB::default(); let root = Self::calculate_root_with_db(identity, &mut db)?; - #[allow(clippy::type_complexity)] - let leaves: BTreeSet, T::BlockNumber, T::Web3Name, LinkableAccountId>> = - key_ids.try_fold(BTreeSet::new(), |mut set, key_id| -> Result<_, ()> { + let mut leaves = key_ids + .map(|key_id| -> Result, ()> { let key_details = did_details.public_keys.get(key_id).ok_or(())?; // Create the merkle leaf key depending on the relationship of the key to the // DID document. - let did_key_merkle_key = if *key_id == did_details.authentication_key { - Ok(DidKeyMerkleKey( - *key_id, - DidVerificationKeyRelationship::Authentication.into(), - )) + let did_key_merkle_key: DidKeyMerkleKey> = if *key_id == did_details.authentication_key { + Ok((*key_id, DidVerificationKeyRelationship::Authentication.into()).into()) } else if Some(*key_id) == did_details.attestation_key { - Ok(DidKeyMerkleKey( - *key_id, - DidVerificationKeyRelationship::AssertionMethod.into(), - )) + Ok((*key_id, DidVerificationKeyRelationship::AssertionMethod.into()).into()) } else if Some(*key_id) == did_details.delegation_key { - Ok(DidKeyMerkleKey( - *key_id, - DidVerificationKeyRelationship::CapabilityDelegation.into(), - )) + Ok((*key_id, DidVerificationKeyRelationship::CapabilityDelegation.into()).into()) } else if did_details.key_agreement_keys.contains(key_id) { - Ok(DidKeyMerkleKey(*key_id, DidKeyRelationship::Encryption)) + Ok((*key_id, DidKeyRelationship::Encryption).into()) } else { Err(()) }?; - // Then adds the actual key details to the merkle leaf. - let did_key_merkle_value = DidKeyMerkleValue(key_details.clone()); - let did_merkle_merkle_leaf = ProofLeaf::DidKey(did_key_merkle_key, did_key_merkle_value); - if !set.contains(&did_merkle_merkle_leaf) { - set.insert(did_merkle_merkle_leaf); + Ok(ProofLeaf::DidKey(did_key_merkle_key, key_details.clone().into())) + }) + .chain(account_ids.map(|account_id| -> Result, ()> { + let Some(linked_accounts) = &identity.c else { return Err(()) }; + if linked_accounts.contains(account_id) { + Ok(ProofLeaf::LinkedAccount(account_id.clone().into(), ().into())) + } else { + Err(()) } - Ok(set) - })?; + })) + .collect::, _>>()?; + + match (should_include_web3_name, &identity.b) { + // If web3name should be included and it exists... + (true, Some(web3_name)) => { + leaves.push(ProofLeaf::Web3Name(web3_name.clone().into(), ().into())); + Ok(()) + } + // ...else if web3name should be included and it DOES NOT exist... + (true, None) => Err(()), + // ...else if web3name should NOT be included. + (false, _) => Ok(()), + }?; + let encoded_keys: Vec> = leaves.iter().map(|l| l.encoded_key()).collect(); let proof = generate_trie_proof::, _, _, _>(&db, root, &encoded_keys).map_err(|_| ())?; Ok(CompleteMerkleProof { root, proof: DidMerkleProofOf:: { blinded: proof, - revealed: leaves.into_iter().collect::>(), + revealed: leaves.into_iter().collect(), }, }) } From d86b1e968ac1e4ded9d9bb8d526c27e3e01938c2 Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Wed, 24 May 2023 16:15:34 +0200 Subject: [PATCH 11/15] Tests working, everything's good --- Cargo.lock | 1 + crates/kilt-dip-support/src/did.rs | 12 +++++ dip-template/runtimes/dip-provider/src/lib.rs | 6 +-- dip-template/runtimes/xcm-tests/Cargo.toml | 1 + dip-template/runtimes/xcm-tests/src/para.rs | 47 +++++++++++++++++-- dip-template/runtimes/xcm-tests/src/tests.rs | 34 ++++++++++---- runtimes/common/src/dip/merkle.rs | 29 ++++++------ 7 files changed, 99 insertions(+), 31 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a137026537..d033efc860 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2508,6 +2508,7 @@ dependencies = [ "kilt-support", "pallet-balances", "pallet-did-lookup", + "pallet-web3-names", "parachain-info", "parity-scale-codec", "polkadot-parachain", diff --git a/crates/kilt-dip-support/src/did.rs b/crates/kilt-dip-support/src/did.rs index ac2bfa33bb..c1d37be9a4 100644 --- a/crates/kilt-dip-support/src/did.rs +++ b/crates/kilt-dip-support/src/did.rs @@ -241,6 +241,18 @@ pub struct CombinedIdentityResult { pub c: OutputC, } +impl From<(OutputA, OutputB, OutputC)> + for CombinedIdentityResult +{ + fn from(value: (OutputA, OutputB, OutputC)) -> Self { + Self { + a: value.0, + b: value.1, + c: value.2, + } + } +} + impl CombinedIdentityResult where OutputB: Default, diff --git a/dip-template/runtimes/dip-provider/src/lib.rs b/dip-template/runtimes/dip-provider/src/lib.rs index b7b7e933f6..ce1a98ea3c 100644 --- a/dip-template/runtimes/dip-provider/src/lib.rs +++ b/dip-template/runtimes/dip-provider/src/lib.rs @@ -370,7 +370,7 @@ impl did::DeriveDidCallAuthorizationVerificationKeyRelationship for RuntimeCall parameter_types! { #[derive(Debug, Clone, Eq, PartialEq)] - pub const MaxTotalKeyAgreementKeys: u32 = 1; + pub const MaxTotalKeyAgreementKeys: u32 = 50; } impl did::Config for Runtime { @@ -382,11 +382,11 @@ impl did::Config for Runtime { type FeeCollector = (); type KeyDeposit = ConstU128; type MaxBlocksTxValidity = ConstU32; - type MaxNewKeyAgreementKeys = ConstU32<1>; + type MaxNewKeyAgreementKeys = ConstU32<50>; type MaxNumberOfServicesPerDid = ConstU32<1>; type MaxNumberOfTypesPerService = ConstU32<1>; type MaxNumberOfUrlsPerService = ConstU32<1>; - type MaxPublicKeysPerDid = ConstU32<4>; + type MaxPublicKeysPerDid = ConstU32<53>; type MaxServiceIdLength = ConstU32<100>; type MaxServiceTypeLength = ConstU32<100>; type MaxServiceUrlLength = ConstU32<100>; diff --git a/dip-template/runtimes/xcm-tests/Cargo.toml b/dip-template/runtimes/xcm-tests/Cargo.toml index 6be31a5cb1..ae3b735c77 100644 --- a/dip-template/runtimes/xcm-tests/Cargo.toml +++ b/dip-template/runtimes/xcm-tests/Cargo.toml @@ -21,6 +21,7 @@ kilt-dip-support = { workspace = true, features = ["std"] } kilt-support = { workspace = true, features = ["std"] } pallet-balances = { workspace = true, features = ["std"] } pallet-did-lookup = { workspace = true, features = ["std"] } +pallet-web3-names = { workspace = true, features = ["std"] } parachain-info = { workspace = true, features = ["std"] } parity-scale-codec = {workspace = true, features = ["std", "derive"]} polkadot-parachain = { workspace = true, features = ["std"] } diff --git a/dip-template/runtimes/xcm-tests/src/para.rs b/dip-template/runtimes/xcm-tests/src/para.rs index 77e5f3907f..c671ae0c83 100644 --- a/dip-template/runtimes/xcm-tests/src/para.rs +++ b/dip-template/runtimes/xcm-tests/src/para.rs @@ -25,9 +25,15 @@ pub(super) mod provider { pub(crate) use dip_provider_runtime_template::{DidIdentifier, DmpQueue, Runtime, RuntimeOrigin, XcmpQueue}; use did::did_details::{DidDetails, DidEncryptionKey, DidVerificationKey}; - use dip_provider_runtime_template::{AccountId, System}; + use dip_provider_runtime_template::{AccountId, Balance, BlockNumber, System, Web3Name}; use kilt_support::deposit::Deposit; + use pallet_did_lookup::{linkable_account::LinkableAccountId, ConnectionRecord}; + use pallet_web3_names::web3_name::Web3NameOwnership; use sp_core::{ecdsa, ed25519, sr25519, Pair}; + use sp_runtime::{ + traits::{One, Zero}, + AccountId32, SaturatedConversion, + }; use super::*; @@ -53,9 +59,13 @@ pub(super) mod provider { .unwrap(); details.update_attestation_key(att_key, 0u32).unwrap(); details.update_delegation_key(del_key, 0u32).unwrap(); - details - .add_key_agreement_key(DidEncryptionKey::X25519([100u8; 32]), 0u32) - .unwrap(); + let max_key_agreement_key_count: u8 = + ::MaxTotalKeyAgreementKeys::get().saturated_into(); + (1u8..max_key_agreement_key_count).for_each(|s| { + details + .add_key_agreement_key(DidEncryptionKey::X25519([s; 32]), 0u32) + .unwrap(); + }); details } @@ -74,8 +84,37 @@ pub(super) mod provider { let mut ext = TestExternalities::new(t); let did: DidIdentifier = did_auth_key().public().into(); let details = generate_did_details(); + let acc: AccountId32 = did_auth_key().public().into(); + let web3_name: Web3Name = b"test".to_vec().try_into().unwrap(); ext.execute_with(|| { did::pallet::Did::::insert(&did, details); + pallet_did_lookup::pallet::ConnectedDids::::insert( + LinkableAccountId::from(acc.clone()), + ConnectionRecord { + did: did.clone(), + deposit: Deposit { + amount: Balance::one(), + owner: acc.clone(), + }, + }, + ); + pallet_did_lookup::pallet::ConnectedAccounts::::insert( + &did, + LinkableAccountId::from(acc.clone()), + (), + ); + pallet_web3_names::pallet::Owner::::insert( + &web3_name, + Web3NameOwnership { + claimed_at: BlockNumber::zero(), + owner: did.clone(), + deposit: Deposit { + amount: Balance::one(), + owner: acc.clone(), + }, + }, + ); + pallet_web3_names::pallet::Names::::insert(did, web3_name); System::set_block_number(1); }); ext diff --git a/dip-template/runtimes/xcm-tests/src/tests.rs b/dip-template/runtimes/xcm-tests/src/tests.rs index 316241c7e5..ecefc4e804 100644 --- a/dip-template/runtimes/xcm-tests/src/tests.rs +++ b/dip-template/runtimes/xcm-tests/src/tests.rs @@ -25,12 +25,10 @@ use kilt_dip_support::{ did::{MerkleLeavesAndDidSignature, TimeBoundDidSignature}, merkle::MerkleProof, }; -use pallet_did_lookup::linkable_account::LinkableAccountId; +use pallet_did_lookup::{linkable_account::LinkableAccountId, ConnectedAccounts}; +use pallet_web3_names::Names; use parity_scale_codec::Encode; -use runtime_common::dip::{ - did::LinkedDidInfoOf, - merkle::{CompleteMerkleProof, DidMerkleRootGenerator}, -}; +use runtime_common::dip::merkle::{CompleteMerkleProof, DidMerkleRootGenerator}; use sp_core::Pair; use sp_runtime::traits::Zero; use xcm::latest::{ @@ -53,7 +51,7 @@ fn commit_identity() { let did: DidIdentifier = para::provider::did_auth_key().public().into(); - // 1. Send identity proof from DIP provider to DIP consumer. + // 1. Send identity commitment from DIP provider to DIP consumer. ProviderParachain::execute_with(|| { assert_ok!(DipProvider::commit_identity( RawOrigin::Signed(ProviderAccountId::from([0u8; 32])).into(), @@ -63,7 +61,7 @@ fn commit_identity() { Weight::from_ref_time(4_000), )); }); - // 2. Verify that the proof has made it to the DIP consumer. + // 2. Verify that the commitment has made it to the DIP consumer. ConsumerParachain::execute_with(|| { // 2.1 Verify that there was no XCM error. assert!(!System::events().iter().any(|r| matches!( @@ -81,15 +79,31 @@ fn commit_identity() { let did_details = ProviderParachain::execute_with(|| { Did::get(&did).expect("DID details should be stored on the provider chain.") }); + let web3_name = ProviderParachain::execute_with(|| { + Names::::get(&did).expect("Web3name should be linked to the DID on the provider chain.") + }); + let linked_accounts = ProviderParachain::execute_with(|| { + ConnectedAccounts::::iter_key_prefix(&did).collect::>() + }); let call = ConsumerRuntimeCall::DidLookup(pallet_did_lookup::Call::::associate_sender {}); // 3.1 Generate a proof let CompleteMerkleProof { proof, .. } = DidMerkleRootGenerator::::generate_proof( - &LinkedDidInfoOf::from_a(Some(did_details.clone())), + &( + Some(did_details.clone()), + Some(web3_name), + Some(linked_accounts.clone()), + ) + .into(), [did_details.authentication_key].iter(), - false, - [].iter(), + true, + linked_accounts.iter(), ) .expect("Proof generation should not fail"); + println!( + "Complete merkle proof: {:?}. Size: {:?} bytes", + proof, + proof.encoded_size() + ); // 3.2 Generate a DID signature let genesis_hash = ConsumerParachain::execute_with(|| frame_system::Pallet::::block_hash(BlockNumber::zero())); diff --git a/runtimes/common/src/dip/merkle.rs b/runtimes/common/src/dip/merkle.rs index dbf9b2721c..8c9d6031f2 100644 --- a/runtimes/common/src/dip/merkle.rs +++ b/runtimes/common/src/dip/merkle.rs @@ -140,17 +140,6 @@ where Ok(()) })?; - // Web3name, if present - if let Some(linked_web3_name) = web3_name { - let web3_name_leaf = ProofLeafOf::::Web3Name(linked_web3_name.clone().into(), ().into()); - trie_builder - .insert( - web3_name_leaf.encoded_key().as_slice(), - web3_name_leaf.encoded_value().as_slice(), - ) - .map_err(|_| ())?; - } - // Linked accounts if let Some(linked_accounts) = linked_accounts { linked_accounts @@ -166,6 +155,18 @@ where Ok(()) })?; } + + // Web3name, if present + if let Some(linked_web3_name) = web3_name { + let web3_name_leaf = ProofLeafOf::::Web3Name(linked_web3_name.clone().into(), ().into()); + trie_builder + .insert( + web3_name_leaf.encoded_key().as_slice(), + web3_name_leaf.encoded_value().as_slice(), + ) + .map_err(|_| ())?; + } + trie_builder.commit(); Ok(trie_builder.root().to_owned()) } @@ -187,7 +188,7 @@ where A: Iterator, { // Fails if the DID details do not exist. - let (Some(did_details), _web3_name, _linked_accounts) = (&identity.a, &identity.b, &identity.c) else { return Err(()) }; + let (Some(did_details), linked_web3_name, linked_accounts) = (&identity.a, &identity.b, &identity.c) else { return Err(()) }; let mut db = MemoryDB::default(); let root = Self::calculate_root_with_db(identity, &mut db)?; @@ -211,7 +212,7 @@ where Ok(ProofLeaf::DidKey(did_key_merkle_key, key_details.clone().into())) }) .chain(account_ids.map(|account_id| -> Result, ()> { - let Some(linked_accounts) = &identity.c else { return Err(()) }; + let Some(linked_accounts) = linked_accounts else { return Err(()) }; if linked_accounts.contains(account_id) { Ok(ProofLeaf::LinkedAccount(account_id.clone().into(), ().into())) } else { @@ -220,7 +221,7 @@ where })) .collect::, _>>()?; - match (should_include_web3_name, &identity.b) { + match (should_include_web3_name, linked_web3_name) { // If web3name should be included and it exists... (true, Some(web3_name)) => { leaves.push(ProofLeaf::Web3Name(web3_name.clone().into(), ().into())); From 1f7260df17f90b775703202187d20b47556a23f7 Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Thu, 25 May 2023 09:38:14 +0200 Subject: [PATCH 12/15] Add web3name claiming block number in the identity proof --- crates/kilt-dip-support/src/merkle.rs | 31 +++++++++++++------- dip-template/runtimes/xcm-tests/src/tests.rs | 20 +++++++++---- runtimes/common/src/dip/did.rs | 24 +++++++++------ runtimes/common/src/dip/merkle.rs | 14 ++++++--- 4 files changed, 61 insertions(+), 28 deletions(-) diff --git a/crates/kilt-dip-support/src/merkle.rs b/crates/kilt-dip-support/src/merkle.rs index edaacad9b9..01722d5555 100644 --- a/crates/kilt-dip-support/src/merkle.rs +++ b/crates/kilt-dip-support/src/merkle.rs @@ -86,11 +86,11 @@ impl From for Web3NameMerkleKey { } } #[derive(Clone, Encode, Decode, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug, TypeInfo)] -pub struct Web3NameMerkleValue; +pub struct Web3NameMerkleValue(BlockNumber); -impl From<()> for Web3NameMerkleValue { - fn from(_value: ()) -> Self { - Self +impl From for Web3NameMerkleValue { + fn from(value: BlockNumber) -> Self { + Self(value) } } @@ -117,7 +117,7 @@ pub enum ProofLeaf { // The key and value for the leaves of a merkle proof that contain a reference // (by ID) to the key details, provided in a separate leaf. DidKey(DidKeyMerkleKey, DidKeyMerkleValue), - Web3Name(Web3NameMerkleKey, Web3NameMerkleValue), + Web3Name(Web3NameMerkleKey, Web3NameMerkleValue), LinkedAccount(LinkedAccountMerkleKey, LinkedAccountMerkleValue), } @@ -156,6 +156,12 @@ pub struct RevealedDidKey { pub details: DidPublicKeyDetails, } +#[derive(Clone, Encode, Decode, PartialEq, MaxEncodedLen, Eq, PartialOrd, Ord, RuntimeDebug, TypeInfo)] +pub struct RevealedWeb3Name { + pub web3_name: Web3Name, + pub claimed_at: BlockNumber, +} + #[derive(Clone, Debug, PartialEq, Eq, TypeInfo, MaxEncodedLen, Encode, Decode, Default)] pub struct VerificationResult< KeyId, @@ -166,7 +172,7 @@ pub struct VerificationResult< const MAX_REVEALED_ACCOUNTS_COUNT: u32, > { pub did_keys: BoundedVec, ConstU32>, - pub web3_name: Option, + pub web3_name: Option>, pub linked_accounts: BoundedVec>, } @@ -292,7 +298,7 @@ impl< #[allow(clippy::type_complexity)] let (did_keys, web3_name, linked_accounts): ( BoundedVec, ConstU32>, - Option, + Option>, BoundedVec>, ) = proof.revealed.iter().try_fold( ( @@ -312,9 +318,14 @@ impl< Ok::<_, ()>((keys, web3_name, linked_accounts)) } // TODO: Avoid cloning if possible - ProofLeaf::Web3Name(revealed_web3_name, _) => { - Ok((keys, Some(revealed_web3_name.0.clone()), linked_accounts)) - } + ProofLeaf::Web3Name(revealed_web3_name, details) => Ok(( + keys, + Some(RevealedWeb3Name { + web3_name: revealed_web3_name.0.clone(), + claimed_at: details.0.clone(), + }), + linked_accounts, + )), ProofLeaf::LinkedAccount(account_id, _) => { linked_accounts.try_push(account_id.0.clone()).map_err(|_| ())?; Ok::<_, ()>((keys, web3_name, linked_accounts)) diff --git a/dip-template/runtimes/xcm-tests/src/tests.rs b/dip-template/runtimes/xcm-tests/src/tests.rs index ecefc4e804..9d32b26f63 100644 --- a/dip-template/runtimes/xcm-tests/src/tests.rs +++ b/dip-template/runtimes/xcm-tests/src/tests.rs @@ -26,9 +26,12 @@ use kilt_dip_support::{ merkle::MerkleProof, }; use pallet_did_lookup::{linkable_account::LinkableAccountId, ConnectedAccounts}; -use pallet_web3_names::Names; +use pallet_web3_names::{Names, Owner}; use parity_scale_codec::Encode; -use runtime_common::dip::merkle::{CompleteMerkleProof, DidMerkleRootGenerator}; +use runtime_common::dip::{ + did::Web3OwnershipOf, + merkle::{CompleteMerkleProof, DidMerkleRootGenerator}, +}; use sp_core::Pair; use sp_runtime::traits::Zero; use xcm::latest::{ @@ -79,8 +82,12 @@ fn commit_identity() { let did_details = ProviderParachain::execute_with(|| { Did::get(&did).expect("DID details should be stored on the provider chain.") }); - let web3_name = ProviderParachain::execute_with(|| { - Names::::get(&did).expect("Web3name should be linked to the DID on the provider chain.") + let (web3_name, ownership_details) = ProviderParachain::execute_with(|| { + let web3_name = + Names::::get(&did).expect("Web3name should be linked to the DID on the provider chain."); + let ownership_details = Owner::::get(&web3_name) + .expect("Web3name details should be present for the retrieved web3name."); + (web3_name, ownership_details) }); let linked_accounts = ProviderParachain::execute_with(|| { ConnectedAccounts::::iter_key_prefix(&did).collect::>() @@ -90,7 +97,10 @@ fn commit_identity() { let CompleteMerkleProof { proof, .. } = DidMerkleRootGenerator::::generate_proof( &( Some(did_details.clone()), - Some(web3_name), + Some(Web3OwnershipOf:: { + web3_name, + claimed_at: ownership_details.claimed_at, + }), Some(linked_accounts.clone()), ) .into(), diff --git a/runtimes/common/src/dip/did.rs b/runtimes/common/src/dip/did.rs index 89a03cc66a..cebbf104ce 100644 --- a/runtimes/common/src/dip/did.rs +++ b/runtimes/common/src/dip/did.rs @@ -17,10 +17,12 @@ // If you feel like getting in touch with us, you can do so at info@botlabs.org use did::did_details::DidDetails; -use kilt_dip_support::did::{CombineIdentityFrom, CombinedIdentityResult}; +use kilt_dip_support::{ + did::{CombineIdentityFrom, CombinedIdentityResult}, + merkle::RevealedWeb3Name, +}; use pallet_did_lookup::linkable_account::LinkableAccountId; use pallet_dip_provider::traits::IdentityProvider; -use pallet_web3_names::Web3NameOf; use sp_std::{marker::PhantomData, vec::Vec}; pub struct DidIdentityProvider(PhantomData); @@ -45,6 +47,9 @@ where } } +pub type Web3OwnershipOf = + RevealedWeb3Name<::Web3Name, ::BlockNumber>; + pub struct DidWeb3NameProvider(PhantomData); impl IdentityProvider for DidWeb3NameProvider @@ -53,14 +58,15 @@ where { // TODO: Proper error handling type Error = (); - type Success = T::Web3Name; + type Success = Web3OwnershipOf; fn retrieve(identifier: &T::Web3NameOwner) -> Result, Self::Error> { - if let Some(web3_name) = pallet_web3_names::Pallet::::names(identifier) { - Ok(Some(web3_name)) - } else { - Ok(None) - } + let Some(web3_name) = pallet_web3_names::Pallet::::names(identifier) else { return Ok(None) }; + let Some(details) = pallet_web3_names::Pallet::::owner(&web3_name) else { return Err(()) }; + Ok(Some(Web3OwnershipOf:: { + web3_name, + claimed_at: details.claimed_at, + })) } } @@ -84,4 +90,4 @@ where pub type LinkedDidInfoProviderOf = CombineIdentityFrom, DidWeb3NameProvider, DidLinkedAccountsProvider>; pub type LinkedDidInfoOf = - CombinedIdentityResult>, Option>, Option>>; + CombinedIdentityResult>, Option>, Option>>; diff --git a/runtimes/common/src/dip/merkle.rs b/runtimes/common/src/dip/merkle.rs index 8c9d6031f2..254380b65f 100644 --- a/runtimes/common/src/dip/merkle.rs +++ b/runtimes/common/src/dip/merkle.rs @@ -157,8 +157,11 @@ where } // Web3name, if present - if let Some(linked_web3_name) = web3_name { - let web3_name_leaf = ProofLeafOf::::Web3Name(linked_web3_name.clone().into(), ().into()); + if let Some(web3name_details) = web3_name { + let web3_name_leaf = ProofLeafOf::::Web3Name( + web3name_details.web3_name.clone().into(), + web3name_details.claimed_at.into(), + ); trie_builder .insert( web3_name_leaf.encoded_key().as_slice(), @@ -223,8 +226,11 @@ where match (should_include_web3_name, linked_web3_name) { // If web3name should be included and it exists... - (true, Some(web3_name)) => { - leaves.push(ProofLeaf::Web3Name(web3_name.clone().into(), ().into())); + (true, Some(web3name_details)) => { + leaves.push(ProofLeaf::Web3Name( + web3name_details.web3_name.clone().into(), + web3name_details.claimed_at.into(), + )); Ok(()) } // ...else if web3name should be included and it DOES NOT exist... From 80ac7d50c0f79531e94b3e43f14fdb4767fed0eb Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Thu, 25 May 2023 10:07:49 +0200 Subject: [PATCH 13/15] Add prints to tests to show size difference --- dip-template/runtimes/xcm-tests/src/tests.rs | 25 ++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/dip-template/runtimes/xcm-tests/src/tests.rs b/dip-template/runtimes/xcm-tests/src/tests.rs index 9d32b26f63..facf2862e4 100644 --- a/dip-template/runtimes/xcm-tests/src/tests.rs +++ b/dip-template/runtimes/xcm-tests/src/tests.rs @@ -82,6 +82,10 @@ fn commit_identity() { let did_details = ProviderParachain::execute_with(|| { Did::get(&did).expect("DID details should be stored on the provider chain.") }); + println!( + "Complete DID details encoded size: {:?} bytes", + did_details.encoded_size() + ); let (web3_name, ownership_details) = ProviderParachain::execute_with(|| { let web3_name = Names::::get(&did).expect("Web3name should be linked to the DID on the provider chain."); @@ -89,9 +93,15 @@ fn commit_identity() { .expect("Web3name details should be present for the retrieved web3name."); (web3_name, ownership_details) }); + println!( + "Web3name and ownership size: ({:?}, {:?}) bytes", + web3_name.encoded_size(), + ownership_details.encoded_size(), + ); let linked_accounts = ProviderParachain::execute_with(|| { ConnectedAccounts::::iter_key_prefix(&did).collect::>() }); + println!("Linked accounts size: {:?} bytes", linked_accounts.encoded_size()); let call = ConsumerRuntimeCall::DidLookup(pallet_did_lookup::Call::::associate_sender {}); // 3.1 Generate a proof let CompleteMerkleProof { proof, .. } = DidMerkleRootGenerator::::generate_proof( @@ -104,15 +114,22 @@ fn commit_identity() { Some(linked_accounts.clone()), ) .into(), - [did_details.authentication_key].iter(), + [ + did_details.authentication_key, + did_details.attestation_key.unwrap(), + did_details.delegation_key.unwrap(), + ] + .iter() + .chain(did_details.key_agreement_keys.iter()), true, linked_accounts.iter(), ) .expect("Proof generation should not fail"); println!( - "Complete merkle proof: {:?}. Size: {:?} bytes", - proof, - proof.encoded_size() + "Complete merkle proof size: {:?} bytes. Blinded part: {:?} bytes. Revealed part: {:?} bytes.", + proof.encoded_size(), + proof.blinded.encoded_size(), + proof.revealed.encoded_size() ); // 3.2 Generate a DID signature let genesis_hash = From 20889ef3d4cf8e7c2ee9415b0c94bc953bbc29e4 Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Thu, 25 May 2023 10:41:07 +0200 Subject: [PATCH 14/15] Add FIXME comment --- pallets/pallet-web3-names/src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pallets/pallet-web3-names/src/lib.rs b/pallets/pallet-web3-names/src/lib.rs index e08edad9bc..43ecd1f638 100644 --- a/pallets/pallet-web3-names/src/lib.rs +++ b/pallets/pallet-web3-names/src/lib.rs @@ -115,6 +115,8 @@ pub mod pallet { /// The max encoded length of a name. #[pallet::constant] type MaxNameLength: Get; + // FIXME: Refactor the definition of AsciiWeb3Name so that we don't need to + // require `Ord` here /// The type of a name. type Web3Name: FullCodec + Debug From ff477ec7d2209e3303ba8d18521daca70c7c4545 Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Thu, 25 May 2023 17:45:24 +0200 Subject: [PATCH 15/15] Remove key agreements from proof generation --- dip-template/runtimes/xcm-tests/src/tests.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dip-template/runtimes/xcm-tests/src/tests.rs b/dip-template/runtimes/xcm-tests/src/tests.rs index facf2862e4..3577a3932a 100644 --- a/dip-template/runtimes/xcm-tests/src/tests.rs +++ b/dip-template/runtimes/xcm-tests/src/tests.rs @@ -119,8 +119,7 @@ fn commit_identity() { did_details.attestation_key.unwrap(), did_details.delegation_key.unwrap(), ] - .iter() - .chain(did_details.key_agreement_keys.iter()), + .iter(), true, linked_accounts.iter(), )