diff --git a/Cargo.lock b/Cargo.lock index 741ea0e370..0d0eeaafa8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4558,6 +4558,7 @@ dependencies = [ name = "kilt-dip-support" version = "1.12.0-dev" dependencies = [ + "cfg-if", "cumulus-pallet-parachain-system", "cumulus-primitives-core", "did", diff --git a/crates/kilt-dip-support/Cargo.toml b/crates/kilt-dip-support/Cargo.toml index bbebdfa4f2..30262359b2 100644 --- a/crates/kilt-dip-support/Cargo.toml +++ b/crates/kilt-dip-support/Cargo.toml @@ -14,6 +14,7 @@ version.workspace = true # External dependencies hash-db.workspace = true log.workspace = true +cfg-if = "1.0" # Internal dependencies did.workspace = true diff --git a/crates/kilt-dip-support/src/did.rs b/crates/kilt-dip-support/src/did.rs index dfdce46dba..88ec834d0e 100644 --- a/crates/kilt-dip-support/src/did.rs +++ b/crates/kilt-dip-support/src/did.rs @@ -26,7 +26,7 @@ use parity_scale_codec::{Decode, Encode}; use scale_info::TypeInfo; use sp_core::RuntimeDebug; use sp_runtime::traits::CheckedSub; -use sp_std::{marker::PhantomData, vec::Vec}; +use sp_std::vec::Vec; use crate::{ merkle::RevealedDidKey, @@ -86,7 +86,7 @@ impl From for u8 { } } -/// Proof verifier that tries to verify a DID signature over a given payload by +/// Function that tries to verify a DID signature over a given payload by /// using one of the DID keys revealed in the Merkle proof. This verifier is /// typically used in conjunction with a verifier that takes a user-provided /// input Merkle proof, verifies it, and transforms it into a struct that this @@ -110,7 +110,7 @@ impl From for u8 { /// * `RemoteBlockNumber`: Definition of a block number on the provider chain. /// * `CallVerifier`: A type specifying whether the provided `Call` can be /// dispatched with the information provided in the DIP proof. -pub(crate) struct RevealedDidKeysSignatureAndCallVerifier< +pub(crate) fn verify_did_signature_for_call< Call, Submitter, DidLocalDetails, @@ -121,42 +121,15 @@ pub(crate) struct RevealedDidKeysSignatureAndCallVerifier< RemoteBlockNumber, CallVerifier, >( - #[allow(clippy::type_complexity)] - PhantomData<( - Call, - Submitter, - DidLocalDetails, - MerkleProofEntries, - ContextProvider, - RemoteKeyId, - RemoteAccountId, - RemoteBlockNumber, - CallVerifier, - )>, -); - -impl< - Call, - Submitter, - DidLocalDetails, - MerkleProofEntries, - ContextProvider, - RemoteKeyId, - RemoteAccountId, - RemoteBlockNumber, - CallVerifier, - > - RevealedDidKeysSignatureAndCallVerifier< - Call, - Submitter, - DidLocalDetails, - MerkleProofEntries, - ContextProvider, - RemoteKeyId, - RemoteAccountId, - RemoteBlockNumber, - CallVerifier, - > where + call: &Call, + submitter: &Submitter, + local_details: &mut Option, + merkle_revealed_did_signature: RevealedDidKeysAndSignature, +) -> Result< + (DidVerificationKey, DidVerificationKeyRelationship), + RevealedDidKeysSignatureAndCallVerifierError, +> +where Call: Encode, Submitter: Encode, ContextProvider: DidSignatureVerifierContext, @@ -169,144 +142,82 @@ impl< CallVerifier: DipCallOriginFilter, DidVerificationKeyRelationship)>, { - #[cfg(not(feature = "runtime-benchmarks"))] - pub(crate) fn verify_did_signature_for_call( - call: &Call, - submitter: &Submitter, - local_details: &mut Option, - merkle_revealed_did_signature: RevealedDidKeysAndSignature, - ) -> Result< - (DidVerificationKey, DidVerificationKeyRelationship), - RevealedDidKeysSignatureAndCallVerifierError, - > { - use frame_support::ensure; - - let block_number = ContextProvider::current_block_number(); - let is_signature_fresh = if let Some(blocks_ago_from_now) = - block_number.checked_sub(&merkle_revealed_did_signature.did_signature.block_number) - { - // False if the signature is too old. - blocks_ago_from_now <= ContextProvider::SIGNATURE_VALIDITY.into() + cfg_if::cfg_if! { + if #[cfg(feature = "runtime-benchmarks")] { + {} } else { - // Signature generated at a future time, not possible to verify. - false - }; - ensure!( - is_signature_fresh, - RevealedDidKeysSignatureAndCallVerifierError::SignatureNotFresh, - ); - let encoded_payload = ( - call, - &local_details, - submitter, - &merkle_revealed_did_signature.did_signature.block_number, - ContextProvider::genesis_hash(), - ContextProvider::signed_extra(), - ) - .encode(); - // Only consider verification keys from the set of revealed keys. - let proof_verification_keys: Vec<(DidVerificationKey, DidVerificationKeyRelationship)> = merkle_revealed_did_signature.merkle_leaves.borrow().iter().filter_map(|RevealedDidKey { + let block_number = ContextProvider::current_block_number(); + let is_signature_fresh = if let Some(blocks_ago_from_now) = + block_number.checked_sub(&merkle_revealed_did_signature.did_signature.block_number) + { + // False if the signature is too old. + blocks_ago_from_now <= ContextProvider::SIGNATURE_VALIDITY.into() + } else { + // Signature generated at a future time, not possible to verify. + false + }; + frame_support::ensure!( + is_signature_fresh, + RevealedDidKeysSignatureAndCallVerifierError::SignatureNotFresh, + ); + } + } + let encoded_payload = ( + call, + &local_details, + submitter, + &merkle_revealed_did_signature.did_signature.block_number, + ContextProvider::genesis_hash(), + ContextProvider::signed_extra(), + ) + .encode(); + // Only consider verification keys from the set of revealed keys. + let proof_verification_keys: Vec<(DidVerificationKey, DidVerificationKeyRelationship)> = merkle_revealed_did_signature.merkle_leaves.borrow().iter().filter_map(|RevealedDidKey { relationship, details: DidPublicKeyDetails { key, .. }, .. } | { let DidPublicKey::PublicVerificationKey(key) = key else { return None }; if let Ok(vr) = DidVerificationKeyRelationship::try_from(*relationship) { // TODO: Fix this logic to avoid cloning Some(Ok((key.clone(), vr))) } else { - log::error!("Should never fail to build a VerificationRelationship from the given DidKeyRelationship because we have already made sure the conditions hold."); - Some(Err(RevealedDidKeysSignatureAndCallVerifierError::Internal)) + cfg_if::cfg_if! { + if #[cfg(feature = "runtime-benchmarks")] { + None + } else { + log::error!("Should never fail to build a VerificationRelationship from the given DidKeyRelationship because we have already made sure the conditions hold."); + Some(Err(RevealedDidKeysSignatureAndCallVerifierError::Internal)) + } + } } }).collect::>()?; - let valid_signing_key = proof_verification_keys.iter().find(|(verification_key, _)| { - verification_key - .verify_signature(&encoded_payload, &merkle_revealed_did_signature.did_signature.signature) - .is_ok() - }); - let Some((key, relationship)) = valid_signing_key else { - return Err(RevealedDidKeysSignatureAndCallVerifierError::SignatureUnverifiable); - }; - if let Some(details) = local_details { - details.bump(); + let valid_signing_key = proof_verification_keys.iter().find(|(verification_key, _)| { + verification_key + .verify_signature(&encoded_payload, &merkle_revealed_did_signature.did_signature.signature) + .is_ok() + }); + cfg_if::cfg_if! { + if #[cfg(feature = "runtime-benchmarks")] { + let default = ( + DidVerificationKey::Ed25519(sp_core::ed25519::Public::from_raw([0u8; 32])), + DidVerificationKeyRelationship::Authentication, + ); + let (key, relationship) = valid_signing_key.unwrap_or(&default); } else { - *local_details = Some(DidLocalDetails::default()); - }; - CallVerifier::check_call_origin_info(call, &(key.clone(), *relationship)) - .map_err(|_| RevealedDidKeysSignatureAndCallVerifierError::OriginCheckFailed)?; - Ok((key.clone(), *relationship)) + let (key, relationship) = valid_signing_key.ok_or(RevealedDidKeysSignatureAndCallVerifierError::SignatureUnverifiable)?; + } } - #[cfg(feature = "runtime-benchmarks")] - #[allow(clippy::result_unit_err)] - pub(crate) fn verify_did_signature_for_call( - call: &Call, - submitter: &Submitter, - local_details: &mut Option, - merkle_revealed_did_signature: RevealedDidKeysAndSignature, - ) -> Result< - (DidVerificationKey, DidVerificationKeyRelationship), - RevealedDidKeysSignatureAndCallVerifierError, - > { - use sp_core::ed25519; - - let block_number = ContextProvider::current_block_number(); - // Computed but ignored - if let Some(blocks_ago_from_now) = - block_number.checked_sub(&merkle_revealed_did_signature.did_signature.block_number) - { - // False if the signature is too old. - blocks_ago_from_now <= ContextProvider::SIGNATURE_VALIDITY.into() + if let Some(details) = local_details { + details.bump(); + } else { + *local_details = Some(DidLocalDetails::default()); + }; + let res = CallVerifier::check_call_origin_info(call, &(key.clone(), *relationship)); + cfg_if::cfg_if! { + if #[cfg(feature = "runtime-benchmarks")] { + drop(res); } else { - // Signature generated at a future time, not possible to verify. - false - }; - let encoded_payload = ( - call, - &local_details, - submitter, - &merkle_revealed_did_signature.did_signature.block_number, - ContextProvider::genesis_hash(), - ContextProvider::signed_extra(), - ) - .encode(); - // Only consider verification keys from the set of revealed keys. - let proof_verification_keys: Vec<(DidVerificationKey, DidVerificationKeyRelationship)> = - merkle_revealed_did_signature - .merkle_leaves - .borrow() - .iter() - .filter_map( - |RevealedDidKey { - relationship, - details: DidPublicKeyDetails { key, .. }, - .. - }| { - let DidPublicKey::PublicVerificationKey(key) = key else { - return None; - }; - if let Ok(vr) = DidVerificationKeyRelationship::try_from(*relationship) { - Some(Ok((key.clone(), vr))) - } else { - None - } - }, - ) - .collect::>()?; - let valid_signing_key = proof_verification_keys.iter().find(|(verification_key, _)| { - verification_key - .verify_signature(&encoded_payload, &merkle_revealed_did_signature.did_signature.signature) - .is_ok() - }); - let default = ( - DidVerificationKey::Ed25519(ed25519::Public::from_raw([0u8; 32])), - DidVerificationKeyRelationship::Authentication, - ); - let (key, relationship) = valid_signing_key.unwrap_or(&default); - if let Some(details) = local_details { - details.bump(); - } else { - *local_details = Some(DidLocalDetails::default()); - }; - // Ignore the result of this call - let _ = CallVerifier::check_call_origin_info(call, &(key.clone(), *relationship)); - Ok((key.clone(), *relationship)) + res.map_err(|_| RevealedDidKeysSignatureAndCallVerifierError::OriginCheckFailed)?; + } } + Ok((key.clone(), *relationship)) } diff --git a/crates/kilt-dip-support/src/export/child.rs b/crates/kilt-dip-support/src/export/child.rs index 00a897b538..58321c11bb 100644 --- a/crates/kilt-dip-support/src/export/child.rs +++ b/crates/kilt-dip-support/src/export/child.rs @@ -494,12 +494,11 @@ pub mod v0 { use crate::{ did::{ - RevealedDidKeysAndSignature, RevealedDidKeysSignatureAndCallVerifier, - RevealedDidKeysSignatureAndCallVerifierError, + verify_did_signature_for_call, RevealedDidKeysAndSignature, RevealedDidKeysSignatureAndCallVerifierError, }, export::common::v0::{DipMerkleProofAndDidSignature, ParachainRootStateProof}, merkle::{ - DidMerkleProofVerifier, DidMerkleProofVerifierError, RevealedDidMerkleProofLeaf, + verify_dip_merkle_proof, DidMerkleProofVerifierError, RevealedDidMerkleProofLeaf, RevealedDidMerkleProofLeaves, }, state_proofs::{ @@ -776,7 +775,7 @@ pub mod v0 { .map_err(DipChildProviderStateProofVerifierError::IdentityCommitmentMerkleProof)?; // 4. Verify DIP merkle proof. - let proof_leaves = DidMerkleProofVerifier::< + let proof_leaves = verify_dip_merkle_proof::< ProviderDipMerkleHasher, _, _, @@ -785,30 +784,20 @@ pub mod v0 { _, MAX_REVEALED_KEYS_COUNT, MAX_REVEALED_ACCOUNTS_COUNT, - >::verify_dip_merkle_proof(&subject_identity_commitment, proof.did.leaves) + >(&subject_identity_commitment, proof.did.leaves) .map_err(DipChildProviderStateProofVerifierError::DipProof)?; // 5. Verify DID signature. - RevealedDidKeysSignatureAndCallVerifier::< - _, - _, - _, - _, - LocalContextProvider, - _, - _, - _, - LocalDidCallVerifier, - >::verify_did_signature_for_call( - call, - submitter, - identity_details, - RevealedDidKeysAndSignature { - merkle_leaves: proof_leaves.borrow(), - did_signature: proof.did.signature, - }, - ) - .map_err(DipChildProviderStateProofVerifierError::DidSignature)?; + verify_did_signature_for_call::<_, _, _, _, LocalContextProvider, _, _, _, LocalDidCallVerifier>( + call, + submitter, + identity_details, + RevealedDidKeysAndSignature { + merkle_leaves: proof_leaves.borrow(), + did_signature: proof.did.signature, + }, + ) + .map_err(DipChildProviderStateProofVerifierError::DidSignature)?; Ok(proof_leaves) } } diff --git a/crates/kilt-dip-support/src/export/sibling.rs b/crates/kilt-dip-support/src/export/sibling.rs index daf3759881..a67d9da56b 100644 --- a/crates/kilt-dip-support/src/export/sibling.rs +++ b/crates/kilt-dip-support/src/export/sibling.rs @@ -469,9 +469,9 @@ pub mod v0 { use sp_std::borrow::Borrow; use crate::{ - did::{RevealedDidKeysAndSignature, RevealedDidKeysSignatureAndCallVerifier}, + did::{verify_did_signature_for_call, RevealedDidKeysAndSignature}, export::common::v0::{DipMerkleProofAndDidSignature, ParachainRootStateProof}, - merkle::DidMerkleProofVerifier, + merkle::verify_dip_merkle_proof, state_proofs::{parachain::DipIdentityCommitmentProofVerifier, relay_chain::ParachainHeadProofVerifier}, traits::ProviderParachainStorageInfo, }; @@ -741,7 +741,7 @@ pub mod v0 { ProviderLinkedAccountId, MAX_REVEALED_KEYS_COUNT, MAX_REVEALED_ACCOUNTS_COUNT, - > = DidMerkleProofVerifier::< + > = verify_dip_merkle_proof::< ProviderDipMerkleHasher, _, _, @@ -750,30 +750,20 @@ pub mod v0 { _, MAX_REVEALED_KEYS_COUNT, MAX_REVEALED_ACCOUNTS_COUNT, - >::verify_dip_merkle_proof(&subject_identity_commitment, proof.did.leaves) + >(&subject_identity_commitment, proof.did.leaves) .map_err(DipSiblingProviderStateProofVerifierError::DipProof)?; // 4. Verify DID signature. - RevealedDidKeysSignatureAndCallVerifier::< - _, - _, - _, - _, - LocalContextProvider, - _, - _, - _, - LocalDidCallVerifier, - >::verify_did_signature_for_call( - call, - submitter, - identity_details, - RevealedDidKeysAndSignature { - merkle_leaves: proof_leaves.borrow(), - did_signature: proof.did.signature, - }, - ) - .map_err(DipSiblingProviderStateProofVerifierError::DidSignature)?; + verify_did_signature_for_call::<_, _, _, _, LocalContextProvider, _, _, _, LocalDidCallVerifier>( + call, + submitter, + identity_details, + RevealedDidKeysAndSignature { + merkle_leaves: proof_leaves.borrow(), + did_signature: proof.did.signature, + }, + ) + .map_err(DipSiblingProviderStateProofVerifierError::DidSignature)?; Ok(proof_leaves) } diff --git a/crates/kilt-dip-support/src/merkle.rs b/crates/kilt-dip-support/src/merkle.rs index 3fecc5668e..6d744777f8 100644 --- a/crates/kilt-dip-support/src/merkle.rs +++ b/crates/kilt-dip-support/src/merkle.rs @@ -23,7 +23,7 @@ use frame_support::{traits::ConstU32, DefaultNoBound, RuntimeDebug}; use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; use sp_runtime::{BoundedVec, SaturatedConversion}; -use sp_std::{fmt::Debug, marker::PhantomData, vec::Vec}; +use sp_std::{fmt::Debug, vec::Vec}; use sp_trie::{verify_trie_proof, LayoutV1}; /// Type of a Merkle proof containing DID-related information. @@ -279,8 +279,8 @@ impl From for u8 { } } -/// A type that verifies a DIP Merkle proof revealing some leaves representing -/// parts of a KILT DID identity stored on the KILT chain. +/// A function that verifies a DIP Merkle proof revealing some leaves +/// representing parts of a KILT DID identity stored on the KILT chain. /// If cross-chain DID signatures are not required for the specific use case, /// this verifier can also be used on its own, without any DID signature /// verification. @@ -303,7 +303,7 @@ impl From for u8 { /// supported when verifying the Merkle proof. /// * `MAX_REVEALED_ACCOUNTS_COUNT`: The maximum number of linked accounts that /// are supported when verifying the Merkle proof. -pub(crate) struct DidMerkleProofVerifier< +pub(crate) fn verify_dip_merkle_proof< Hasher, KeyId, AccountId, @@ -312,20 +312,14 @@ pub(crate) struct DidMerkleProofVerifier< LinkedAccountId, const MAX_REVEALED_KEYS_COUNT: u32, const MAX_REVEALED_ACCOUNTS_COUNT: u32, ->(#[allow(clippy::type_complexity)] PhantomData<(Hasher, KeyId, AccountId, BlockNumber, Web3Name, LinkedAccountId)>); - -impl< - Hasher, - KeyId, - AccountId, - BlockNumber, - Web3Name, - LinkedAccountId, - const MAX_REVEALED_KEYS_COUNT: u32, - const MAX_REVEALED_ACCOUNTS_COUNT: u32, - > - DidMerkleProofVerifier< - Hasher, +>( + identity_commitment: &Hasher::Out, + proof: DidMerkleProof< + crate::BoundedBlindedValue, + RevealedDidMerkleProofLeaf, + >, +) -> Result< + RevealedDidMerkleProofLeaves< KeyId, AccountId, BlockNumber, @@ -333,7 +327,10 @@ impl< LinkedAccountId, MAX_REVEALED_KEYS_COUNT, MAX_REVEALED_ACCOUNTS_COUNT, - > where + >, + DidMerkleProofVerifierError, +> +where BlockNumber: Encode + Clone, Hasher: sp_core::Hasher, KeyId: Encode + Clone, @@ -341,154 +338,79 @@ impl< LinkedAccountId: Encode + Clone, Web3Name: Encode + Clone, { - #[cfg(not(feature = "runtime-benchmarks"))] - pub(crate) fn verify_dip_merkle_proof( - identity_commitment: &Hasher::Out, - proof: DidMerkleProof< - crate::BoundedBlindedValue, - RevealedDidMerkleProofLeaf, - >, - ) -> Result< - RevealedDidMerkleProofLeaves< - KeyId, - AccountId, - BlockNumber, - Web3Name, - LinkedAccountId, - MAX_REVEALED_KEYS_COUNT, - MAX_REVEALED_ACCOUNTS_COUNT, - >, - DidMerkleProofVerifierError, - > { - // TODO: more efficient by removing cloning and/or collecting. - // Did not find another way of mapping a Vec<(Vec, Vec)> to a - // Vec<(Vec, Option>)>. - let proof_leaves = proof - .revealed - .iter() - .map(|leaf| (leaf.encoded_key(), Some(leaf.encoded_value()))) - .collect::, Option>)>>(); - verify_trie_proof::, _, _, _>(identity_commitment, &proof.blinded, &proof_leaves) - .map_err(|_| DidMerkleProofVerifierError::InvalidMerkleProof)?; - - // 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. - #[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, mut linked_accounts), leaf| match leaf { - RevealedDidMerkleProofLeaf::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(|_| DidMerkleProofVerifierError::TooManyRevealedKeys)?; - Ok::<_, DidMerkleProofVerifierError>((keys, web3_name, linked_accounts)) - } - // TODO: Avoid cloning if possible - RevealedDidMerkleProofLeaf::Web3Name(revealed_web3_name, details) => Ok(( - keys, - Some(RevealedWeb3Name { - web3_name: revealed_web3_name.0.clone(), - claimed_at: details.0.clone(), - }), - linked_accounts, - )), - RevealedDidMerkleProofLeaf::LinkedAccount(account_id, _) => { - linked_accounts - .try_push(account_id.0.clone()) - .map_err(|_| DidMerkleProofVerifierError::TooManyRevealedAccounts)?; - Ok::<_, DidMerkleProofVerifierError>((keys, web3_name, linked_accounts)) - } - }, - )?; - - Ok(RevealedDidMerkleProofLeaves { - did_keys, - web3_name, - linked_accounts, - }) + // TODO: more efficient by removing cloning and/or collecting. + // Did not find another way of mapping a Vec<(Vec, Vec)> to a + // Vec<(Vec, Option>)>. + let proof_leaves = proof + .revealed + .iter() + .map(|leaf| (leaf.encoded_key(), Some(leaf.encoded_value()))) + .collect::, Option>)>>(); + let res = verify_trie_proof::, _, _, _>(identity_commitment, &proof.blinded, &proof_leaves); + cfg_if::cfg_if! { + if #[cfg(feature = "runtime-benchmarks")] { + drop(res); + } else { + res.map_err(|_| DidMerkleProofVerifierError::InvalidMerkleProof)?; + } } - #[cfg(feature = "runtime-benchmarks")] + // 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. #[allow(clippy::type_complexity)] - pub(crate) fn verify_dip_merkle_proof( - identity_commitment: &Hasher::Out, - proof: DidMerkleProof< - crate::BoundedBlindedValue, - RevealedDidMerkleProofLeaf, - >, - ) -> Result< - RevealedDidMerkleProofLeaves< - KeyId, - AccountId, - BlockNumber, - Web3Name, - LinkedAccountId, - MAX_REVEALED_KEYS_COUNT, - MAX_REVEALED_ACCOUNTS_COUNT, - >, - DidMerkleProofVerifierError, - > { - let proof_leaves = proof - .revealed - .iter() - .map(|leaf| (leaf.encoded_key(), Some(leaf.encoded_value()))) - .collect::, Option>)>>(); - // Ignore result - let _ = verify_trie_proof::, _, _, _>(identity_commitment, &proof.blinded, &proof_leaves); - - #[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, mut linked_accounts), leaf| match leaf { - RevealedDidMerkleProofLeaf::DidKey(key_id, key_value) => { - // Ignore error, just discard anything in excess. - let _ = keys.try_push(RevealedDidKey { - id: key_id.0.clone(), - relationship: key_id.1, - details: key_value.0.clone(), - }); - Ok::<_, DidMerkleProofVerifierError>((keys, web3_name, linked_accounts)) + let (did_keys, web3_name, linked_accounts): ( + BoundedVec, ConstU32>, + Option>, + BoundedVec>, + ) = proof.revealed.into_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, mut linked_accounts), leaf| match leaf { + RevealedDidMerkleProofLeaf::DidKey(key_id, key_value) => { + let res = keys.try_push(RevealedDidKey { + id: key_id.0, + relationship: key_id.1, + details: key_value.0, + }); + cfg_if::cfg_if! { + if #[cfg(feature = "runtime-benchmarks")] { + drop(res); + } else { + res.map_err(|_| DidMerkleProofVerifierError::TooManyRevealedKeys)?; + } } - RevealedDidMerkleProofLeaf::Web3Name(revealed_web3_name, details) => Ok(( - keys, - Some(RevealedWeb3Name { - web3_name: revealed_web3_name.0.clone(), - claimed_at: details.0.clone(), - }), - linked_accounts, - )), - RevealedDidMerkleProofLeaf::LinkedAccount(account_id, _) => { - // Ignore error, just discard anything in excess. - let _ = linked_accounts.try_push(account_id.0.clone()); - Ok::<_, DidMerkleProofVerifierError>((keys, web3_name, linked_accounts)) + + Ok::<_, DidMerkleProofVerifierError>((keys, web3_name, linked_accounts)) + } + RevealedDidMerkleProofLeaf::Web3Name(revealed_web3_name, details) => Ok(( + keys, + Some(RevealedWeb3Name { + web3_name: revealed_web3_name.0, + claimed_at: details.0, + }), + linked_accounts, + )), + RevealedDidMerkleProofLeaf::LinkedAccount(account_id, _) => { + let res = linked_accounts.try_push(account_id.0); + cfg_if::cfg_if! { + if #[cfg(feature = "runtime-benchmarks")] { + drop(res); + } else { + res.map_err(|_| DidMerkleProofVerifierError::TooManyRevealedAccounts)?; + } } - }, - )?; - - Ok(RevealedDidMerkleProofLeaves { - did_keys, - web3_name, - linked_accounts, - }) - } + + Ok::<_, DidMerkleProofVerifierError>((keys, web3_name, linked_accounts)) + } + }, + )?; + + Ok(RevealedDidMerkleProofLeaves { + did_keys, + web3_name, + linked_accounts, + }) } diff --git a/crates/kilt-dip-support/src/state_proofs.rs b/crates/kilt-dip-support/src/state_proofs.rs index 58619eb6bb..017470aa6e 100644 --- a/crates/kilt-dip-support/src/state_proofs.rs +++ b/crates/kilt-dip-support/src/state_proofs.rs @@ -187,17 +187,7 @@ pub(super) mod relay_chain { }); Ok(header) } - } - // Relies on the `RelayChainState::state_root_for_block` to retrieve the state - // root for the given block. - impl ParachainHeadProofVerifier - where - RelayChainState: RelayChainStateInfo, - OutputOf: Ord, - RelayChainState::BlockNumber: Copy + Into + TryFrom + HasCompact, - RelayChainState::Key: AsRef<[u8]>, - { /// Given a relaychain state root provided by the `RelayChainState` /// generic type, verify a state proof for the parachain with the /// provided ID. @@ -206,7 +196,10 @@ pub(super) mod relay_chain { para_id: &RelayChainState::ParaId, relay_height: &RelayChainState::BlockNumber, proof: impl IntoIterator>, - ) -> Result, ParachainHeadProofVerifierError> { + ) -> Result, ParachainHeadProofVerifierError> + where + RelayChainState: RelayChainStateInfo, + { let relay_state_root = RelayChainState::state_root_for_block(relay_height) .ok_or(ParachainHeadProofVerifierError::RelaychainStateRootNotFound)?; Self::verify_proof_for_parachain_with_root(para_id, &relay_state_root, proof) @@ -217,7 +210,10 @@ pub(super) mod relay_chain { para_id: &RelayChainState::ParaId, relay_height: &RelayChainState::BlockNumber, proof: impl IntoIterator>, - ) -> Result, ParachainHeadProofVerifierError> { + ) -> Result, ParachainHeadProofVerifierError> + where + RelayChainState: RelayChainStateInfo, + { let relay_state_root = RelayChainState::state_root_for_block(relay_height).unwrap_or_default(); Self::verify_proof_for_parachain_with_root(para_id, &relay_state_root, proof) } @@ -370,7 +366,6 @@ pub(super) mod parachain { /// Given a parachain state root, verify a state proof for the /// commitment of a given subject identifier. #[cfg(not(feature = "runtime-benchmarks"))] - #[allow(clippy::result_unit_err)] pub fn verify_proof_for_identifier( identifier: &ParaInfo::Identifier, state_root: OutputOf, diff --git a/runtimes/common/src/dip/did.rs b/runtimes/common/src/dip/did.rs index 6490684fec..fbbda7a3f1 100644 --- a/runtimes/common/src/dip/did.rs +++ b/runtimes/common/src/dip/did.rs @@ -84,48 +84,15 @@ where type Success = LinkedDidInfoOf; fn retrieve(identifier: &Runtime::Identifier) -> Result { - let did_details = match ( - did::Pallet::::get_did(identifier), - did::Pallet::::get_deleted_did(identifier), - ) { - (Some(details), _) => Ok(details), - (_, Some(_)) => Err(LinkedDidInfoProviderError::DidDeleted), - _ => Err(LinkedDidInfoProviderError::DidNotFound), - }?; - let web3_name_details = if let Some(web3_name) = pallet_web3_names::Pallet::::names(identifier) { - let Some(ownership) = pallet_web3_names::Pallet::::owner(&web3_name) else { - log::error!( - "Inconsistent reverse map pallet_web3_names::owner(web3_name). Cannot find owner for web3name {:#?}", - web3_name - ); - return Err(LinkedDidInfoProviderError::Internal); - }; - Ok(Some(Web3OwnershipOf:: { - web3_name, - claimed_at: ownership.claimed_at, - })) - } else { - Ok(None) - }?; - - // Check if the user has too many linked accounts. If they have more than - // [MAX_LINKED_ACCOUNTS], we throw an error. - let are_linked_accounts_within_limit = - pallet_did_lookup::ConnectedAccounts::::iter_key_prefix(identifier) - .nth(MAX_LINKED_ACCOUNTS.saturated_into()) - .is_none(); - ensure!( - are_linked_accounts_within_limit, - LinkedDidInfoProviderError::TooManyLinkedAccounts + did::Pallet::::get_deleted_did(identifier).is_none(), + LinkedDidInfoProviderError::DidDeleted, ); + let did_details = did::Pallet::::get_did(identifier).ok_or(LinkedDidInfoProviderError::DidNotFound)?; - let linked_accounts = pallet_did_lookup::ConnectedAccounts::::iter_key_prefix(identifier) - .take(MAX_LINKED_ACCOUNTS.saturated_into()) - .collect::>() - .try_into() - // Should never happen since we checked above. - .map_err(|_| LinkedDidInfoProviderError::TooManyLinkedAccounts)?; + let web3_name_details = retrieve_w3n::(identifier)?; + + let linked_accounts = retrieve_linked_accounts::(identifier)?; Ok(LinkedDidInfoOf { did_details, @@ -135,6 +102,59 @@ where } } +fn retrieve_w3n( + identifier: &Runtime::Identifier, +) -> Result>, LinkedDidInfoProviderError> +where + Runtime: did::Config::Identifier> + + pallet_web3_names::Config::Identifier> + + pallet_dip_provider::Config, +{ + let Some(web3_name) = pallet_web3_names::Pallet::::names(identifier) else { + return Ok(None); + }; + + let ownership = pallet_web3_names::Pallet::::owner(&web3_name).ok_or_else(|| { + log::error!( + "Inconsistent reverse map pallet_web3_names::owner(web3_name). Cannot find owner for web3name {:#?}", + web3_name + ); + LinkedDidInfoProviderError::Internal + })?; + + Ok(Some(Web3OwnershipOf:: { + web3_name, + claimed_at: ownership.claimed_at, + })) +} + +fn retrieve_linked_accounts( + identifier: &Runtime::Identifier, +) -> Result>, LinkedDidInfoProviderError> +where + Runtime: did::Config::Identifier> + + pallet_did_lookup::Config::Identifier> + + pallet_dip_provider::Config, +{ + // Check if the user has too many linked accounts. If they have more than + // [MAX_LINKED_ACCOUNTS], we throw an error. + let are_linked_accounts_within_limit = pallet_did_lookup::ConnectedAccounts::::iter_key_prefix(identifier) + .nth(MAX_LINKED_ACCOUNTS.saturated_into()) + .is_none(); + + ensure!( + are_linked_accounts_within_limit, + LinkedDidInfoProviderError::TooManyLinkedAccounts + ); + + pallet_did_lookup::ConnectedAccounts::::iter_key_prefix(identifier) + .take(MAX_LINKED_ACCOUNTS.saturated_into()) + .collect::>() + .try_into() + // Should never happen since we checked above. + .map_err(|_| LinkedDidInfoProviderError::TooManyLinkedAccounts) +} + #[cfg(feature = "runtime-benchmarks")] impl GetWorstCase> for LinkedDidInfoOf