From 54a23a534da9aafb99ab13c3e2c5594d6292625c Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Tue, 11 Jul 2023 10:59:34 +0200 Subject: [PATCH 01/32] Refactor pallet-dip-provider --- pallets/pallet-dip-provider/src/lib.rs | 91 ++++++++++------------- pallets/pallet-dip-provider/src/traits.rs | 71 ++---------------- 2 files changed, 46 insertions(+), 116 deletions(-) diff --git a/pallets/pallet-dip-provider/src/lib.rs b/pallets/pallet-dip-provider/src/lib.rs index 34ca55f400..8af729b79f 100644 --- a/pallets/pallet-dip-provider/src/lib.rs +++ b/pallets/pallet-dip-provider/src/lib.rs @@ -28,17 +28,14 @@ pub use crate::pallet::*; pub mod pallet { use super::*; - use frame_support::{pallet_prelude::*, traits::EnsureOrigin, weights::Weight}; + use frame_support::{pallet_prelude::*, traits::EnsureOrigin}; use frame_system::pallet_prelude::*; - use sp_std::{boxed::Box, fmt::Debug}; - use xcm::{latest::prelude::*, VersionedMultiAsset, VersionedMultiLocation}; + use parity_scale_codec::FullCodec; + use sp_std::fmt::Debug; - use dip_support::IdentityDetailsAction; - - use crate::traits::{IdentityProofDispatcher, IdentityProofGenerator, IdentityProvider, SubmitterInfo, TxBuilder}; + use crate::traits::{IdentityCommitmentGenerator, IdentityProvider, SubmitterInfo}; pub type IdentityOf = <::IdentityProvider as IdentityProvider<::Identifier>>::Success; - pub type IdentityProofActionOf = IdentityDetailsAction<::Identifier, ::ProofOutput>; const STORAGE_VERSION: StorageVersion = StorageVersion::new(0); @@ -46,19 +43,22 @@ pub mod pallet { pub trait Config: frame_system::Config { type CommitOriginCheck: EnsureOrigin; type CommitOrigin: SubmitterInfo; - type Identifier: Parameter; - type IdentityProofGenerator: IdentityProofGenerator< + type Identifier: Parameter + MaxEncodedLen; + type IdentityCommitment: Clone + Eq + Debug + TypeInfo + FullCodec + MaxEncodedLen; + type IdentityCommitmentGenerator: IdentityCommitmentGenerator< Self::Identifier, IdentityOf, - Output = Self::ProofOutput, + Output = Self::IdentityCommitment, >; - type IdentityProofDispatcher: IdentityProofDispatcher; type IdentityProvider: IdentityProvider; - type ProofOutput: Clone + Eq + Debug; type RuntimeEvent: From> + IsType<::RuntimeEvent>; - type TxBuilder: TxBuilder; } + #[pallet::storage] + #[pallet::getter(fn identity_commitments)] + pub(crate) type IdentityCommitments = + StorageMap<_, Twox64Concat, ::Identifier, ::IdentityCommitment>; + #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] #[pallet::storage_version(STORAGE_VERSION)] @@ -67,16 +67,19 @@ pub mod pallet { #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { - IdentityInfoDispatched(IdentityProofActionOf, Box), + IdentityCommitted { + identifier: T::Identifier, + commitment: T::IdentityCommitment, + }, + IdentityDeleted { + identifier: T::Identifier, + }, } #[pallet::error] pub enum Error { - BadVersion, - Dispatch, IdentityNotFound, - IdentityProofGeneration, - Predispatch, + IdentityCommitmentGeneration, } #[pallet::call] @@ -84,43 +87,29 @@ pub mod pallet { #[pallet::call_index(0)] // TODO: Update weight #[pallet::weight(0)] - pub fn commit_identity( - origin: OriginFor, - identifier: T::Identifier, - destination: Box, - asset: Box, - weight: Weight, - ) -> DispatchResult { - let dispatcher = T::CommitOriginCheck::ensure_origin(origin).map(|e| e.submitter())?; - - let destination: MultiLocation = (*destination).try_into().map_err(|_| Error::::BadVersion)?; - let action: IdentityProofActionOf = match T::IdentityProvider::retrieve(&identifier) { - Ok(Some(identity)) => { - let identity_proof = T::IdentityProofGenerator::generate_commitment(&identifier, &identity) - .map_err(|_| Error::::IdentityProofGeneration)?; - Ok(IdentityDetailsAction::Updated(identifier, identity_proof, ())) - } - Ok(None) => Ok(IdentityDetailsAction::Deleted(identifier)), + pub fn commit_identity(origin: OriginFor, identifier: T::Identifier) -> DispatchResult { + // TODO: use dispatcher to get deposit + let _dispatcher = + T::CommitOriginCheck::ensure_origin(origin).map(|e: ::CommitOrigin| e.submitter())?; + + let identity_commitment: Option = match T::IdentityProvider::retrieve(&identifier) { + Ok(Some(identity)) => T::IdentityCommitmentGenerator::generate_commitment(&identifier, &identity) + .map(Some) + .map_err(|_| Error::::IdentityCommitmentGeneration), + Ok(None) => Ok(None), Err(_) => Err(Error::::IdentityNotFound), }?; - // TODO: Add correct version creation based on lookup (?) - - let asset: MultiAsset = (*asset).try_into().map_err(|_| Error::::BadVersion)?; - - let (ticket, _) = T::IdentityProofDispatcher::pre_dispatch::( - action.clone(), - dispatcher, - asset, - weight, - destination, - ) - .map_err(|_| Error::::Predispatch)?; - // TODO: Use returned asset of `pre_dispatch` to charge the tx submitter for the - // fee. - T::IdentityProofDispatcher::dispatch(ticket).map_err(|_| Error::::Dispatch)?; + if let Some(commitment) = identity_commitment { + // TODO: Take deposit (once 0.9.42 PR is merged into develop) + IdentityCommitments::::insert(&identifier, commitment.clone()); + Self::deposit_event(Event::::IdentityCommitted { identifier, commitment }); + } else { + // TODO: Release deposit (once 0.9.42 PR is merged into develop) + IdentityCommitments::::remove(&identifier); + Self::deposit_event(Event::::IdentityDeleted { identifier }); + } - Self::deposit_event(Event::IdentityInfoDispatched(action, Box::new(destination))); Ok(()) } } diff --git a/pallets/pallet-dip-provider/src/traits.rs b/pallets/pallet-dip-provider/src/traits.rs index f5a8836d1f..5f0d137963 100644 --- a/pallets/pallet-dip-provider/src/traits.rs +++ b/pallets/pallet-dip-provider/src/traits.rs @@ -17,26 +17,24 @@ // If you feel like getting in touch with us, you can do so at info@botlabs.org use did::DidRawOrigin; -use dip_support::IdentityDetailsAction; -use xcm::{latest::prelude::*, DoubleEncoded}; pub use identity_generation::*; pub mod identity_generation { use sp_std::marker::PhantomData; - pub trait IdentityProofGenerator { + pub trait IdentityCommitmentGenerator { type Error; type Output; fn generate_commitment(identifier: &Identifier, identity: &Identity) -> Result; } - // Implement the `IdentityProofGenerator` by returning the `Default` value for - // the `Output` type. - pub struct DefaultIdentityProofGenerator(PhantomData); + // Implement the `IdentityCommitmentGenerator` by returning the `Default` value + // for the `Output` type. + pub struct DefaultIdentityCommitmentGenerator(PhantomData); - impl IdentityProofGenerator - for DefaultIdentityProofGenerator + impl IdentityCommitmentGenerator + for DefaultIdentityCommitmentGenerator where Output: Default, { @@ -49,52 +47,6 @@ pub mod identity_generation { } } -pub use identity_dispatch::*; -pub mod identity_dispatch { - use super::*; - - use frame_support::weights::Weight; - - pub trait IdentityProofDispatcher { - type PreDispatchOutput; - type Error; - - fn pre_dispatch>( - action: IdentityDetailsAction, - source: AccountId, - asset: MultiAsset, - weight: Weight, - destination: MultiLocation, - ) -> Result<(Self::PreDispatchOutput, MultiAssets), Self::Error>; - - fn dispatch(pre_output: Self::PreDispatchOutput) -> Result<(), Self::Error>; - } - - // Returns `Ok` without doing anything. - pub struct NullIdentityProofDispatcher; - - impl - IdentityProofDispatcher for NullIdentityProofDispatcher - { - type PreDispatchOutput = (); - type Error = (); - - fn pre_dispatch<_B>( - _action: IdentityDetailsAction, - _source: AccountId, - _asset: MultiAsset, - _weight: Weight, - _destination: MultiLocation, - ) -> Result<((), MultiAssets), Self::Error> { - Ok(((), MultiAssets::default())) - } - - fn dispatch(_pre_output: Self::PreDispatchOutput) -> Result<(), Self::Error> { - Ok(()) - } - } -} - pub use identity_provision::*; pub mod identity_provision { use sp_std::marker::PhantomData; @@ -134,17 +86,6 @@ pub mod identity_provision { } } -// Given a destination and an identity action, creates and encodes the proper -// `Transact` call. -pub trait TxBuilder { - type Error; - - fn build( - dest: MultiLocation, - action: IdentityDetailsAction, - ) -> Result, Self::Error>; -} - pub trait SubmitterInfo { type Submitter; From 25b3cb672ab00114d74c1d42ecde524c891a2308 Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Tue, 11 Jul 2023 11:24:30 +0200 Subject: [PATCH 02/32] Remove unused dependencies from pallet-dip-provider --- Cargo.lock | 2 -- pallets/pallet-dip-provider/Cargo.toml | 4 ---- 2 files changed, 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 759e8c19fd..9fa652abdf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6289,13 +6289,11 @@ name = "pallet-dip-provider" version = "1.11.0-dev" dependencies = [ "did", - "dip-support", "frame-support", "frame-system", "parity-scale-codec", "scale-info", "sp-std", - "xcm", ] [[package]] diff --git a/pallets/pallet-dip-provider/Cargo.toml b/pallets/pallet-dip-provider/Cargo.toml index e87da12329..5e22e357a1 100644 --- a/pallets/pallet-dip-provider/Cargo.toml +++ b/pallets/pallet-dip-provider/Cargo.toml @@ -15,25 +15,21 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] did.workspace = true -dip-support.workspace = true frame-support.workspace = true frame-system.workspace = true parity-scale-codec = {workspace = true, features = ["derive"]} scale-info = {workspace = true, features = ["derive"]} sp-std.workspace = true -xcm.workspace = true [features] default = ["std"] std = [ "did/std", - "dip-support/std", "frame-support/std", "frame-system/std", "parity-scale-codec/std", "scale-info/std", "sp-std/std", - "xcm/std", ] runtime-benchmarks = [ "did/runtime-benchmarks", From c7ef216d0f1f158368eb53f7ef594ca822cec7a3 Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Tue, 11 Jul 2023 13:52:38 +0200 Subject: [PATCH 03/32] mIntroduce state proofs in pallet-dip-consumer --- Cargo.lock | 2 - dip-template/runtimes/dip-consumer/src/dip.rs | 6 +- pallets/pallet-dip-consumer/Cargo.toml | 4 - pallets/pallet-dip-consumer/src/identity.rs | 26 ----- pallets/pallet-dip-consumer/src/lib.rs | 94 +++++-------------- pallets/pallet-dip-consumer/src/traits.rs | 4 +- 6 files changed, 27 insertions(+), 109 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9fa652abdf..a0bca81fe5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6274,8 +6274,6 @@ dependencies = [ name = "pallet-dip-consumer" version = "1.11.0-dev" dependencies = [ - "cumulus-pallet-xcm", - "dip-support", "frame-support", "frame-system", "kilt-support", diff --git a/dip-template/runtimes/dip-consumer/src/dip.rs b/dip-template/runtimes/dip-consumer/src/dip.rs index b629fe5820..9ba29126e2 100644 --- a/dip-template/runtimes/dip-consumer/src/dip.rs +++ b/dip-template/runtimes/dip-consumer/src/dip.rs @@ -52,12 +52,12 @@ pub type MerkleDidSignatureVerifierOf = MerkleRevealedDidSignatur impl pallet_dip_consumer::Config for Runtime { type DipCallOriginFilter = PreliminaryDipOriginFilter; type Identifier = DidIdentifier; - type IdentityDetails = u128; - type Proof = MerkleLeavesAndDidSignature< + type LocalIdentityInfo = u128; + type IdentityProof = MerkleLeavesAndDidSignature< MerkleProof>, ProofLeaf>, BlockNumber, >; - type ProofDigest = Hash; + type IdentityCommitment = Hash; type ProofVerifier = MerkleProofAndDidSignatureVerifier< BlockNumber, MerkleProofVerifier, diff --git a/pallets/pallet-dip-consumer/Cargo.toml b/pallets/pallet-dip-consumer/Cargo.toml index a59f1e8f9d..b681182749 100644 --- a/pallets/pallet-dip-consumer/Cargo.toml +++ b/pallets/pallet-dip-consumer/Cargo.toml @@ -14,8 +14,6 @@ version.workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -cumulus-pallet-xcm.workspace = true -dip-support.workspace = true frame-support.workspace = true frame-system.workspace = true kilt-support.workspace = true @@ -26,8 +24,6 @@ sp-std.workspace = true [features] default = ["std"] std = [ - "cumulus-pallet-xcm/std", - "dip-support/std", "frame-support/std", "frame-system/std", "kilt-support/std", diff --git a/pallets/pallet-dip-consumer/src/identity.rs b/pallets/pallet-dip-consumer/src/identity.rs index eed39f68d4..79e74681a2 100644 --- a/pallets/pallet-dip-consumer/src/identity.rs +++ b/pallets/pallet-dip-consumer/src/identity.rs @@ -15,29 +15,3 @@ // along with this program. If not, see . // If you feel like getting in touch with us, you can do so at info@botlabs.org - -use frame_support::RuntimeDebug; -use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; -use scale_info::TypeInfo; - -/// The identity entry for any given user that uses the DIP protocol. -#[derive(Encode, Decode, MaxEncodedLen, Default, TypeInfo, RuntimeDebug)] -pub struct IdentityDetails { - /// The identity digest information, typically used to verify identity - /// proofs. - pub digest: Digest, - /// The details related to the user, stored in the pallet storage. - pub details: Details, -} - -impl From for IdentityDetails -where - Details: Default, -{ - fn from(value: Digest) -> Self { - Self { - digest: value, - details: Details::default(), - } - } -} diff --git a/pallets/pallet-dip-consumer/src/lib.rs b/pallets/pallet-dip-consumer/src/lib.rs index 61818b6683..ec27c77943 100644 --- a/pallets/pallet-dip-consumer/src/lib.rs +++ b/pallets/pallet-dip-consumer/src/lib.rs @@ -31,15 +31,13 @@ pub use crate::{origin::*, pallet::*}; pub mod pallet { use super::*; - use cumulus_pallet_xcm::ensure_sibling_para; use frame_support::{dispatch::Dispatchable, pallet_prelude::*, traits::Contains, Twox64Concat}; use frame_system::pallet_prelude::*; - use parity_scale_codec::MaxEncodedLen; + use parity_scale_codec::{FullCodec, MaxEncodedLen}; + use scale_info::TypeInfo; use sp_std::boxed::Box; - use dip_support::IdentityDetailsAction; - - use crate::{identity::IdentityDetails, traits::IdentityProofVerifier}; + use crate::traits::IdentityProofVerifier; pub type VerificationResultOf = <::ProofVerifier as IdentityProofVerifier< ::RuntimeCall, @@ -48,15 +46,10 @@ pub mod pallet { const STORAGE_VERSION: StorageVersion = StorageVersion::new(0); - // TODO: Store also additional details received by the provider. #[pallet::storage] #[pallet::getter(fn identity_proofs)] - pub(crate) type IdentityEntries = StorageMap< - _, - Twox64Concat, - ::Identifier, - IdentityDetails<::ProofDigest, ::IdentityDetails>, - >; + pub(crate) type IdentityEntries = + StorageMap<_, Twox64Concat, ::Identifier, ::LocalIdentityInfo>; #[pallet::config] pub trait Config: frame_system::Config { @@ -65,34 +58,27 @@ pub mod pallet { type DipCallOriginFilter: Contains<::RuntimeCall>; /// The identifier of a subject, e.g., a DID. type Identifier: Parameter + MaxEncodedLen; - /// The details stored in this pallet associated with any given subject. - type IdentityDetails: Parameter + MaxEncodedLen + Default; /// The proof users must provide to operate with their higher-level /// identity. Depending on the use cases, this proof can contain /// heterogeneous bits of information that the proof verifier will /// utilize. For instance, a proof could contain both a Merkle proof and /// a DID signature. - type Proof: Parameter; - /// The type of the committed proof digest used as the basis for - /// verifying identity proofs. - type ProofDigest: Parameter + MaxEncodedLen; + type IdentityProof: Parameter; + /// The details stored in this pallet associated with any given subject. + type LocalIdentityInfo: FullCodec + TypeInfo + MaxEncodedLen; /// The logic of the proof verifier, called upon each execution of the /// `dispatch_as` extrinsic. type ProofVerifier: IdentityProofVerifier< ::RuntimeCall, Self::Identifier, - Proof = Self::Proof, - IdentityDetails = IdentityDetails, + Proof = Self::IdentityProof, + IdentityDetails = Self::LocalIdentityInfo, Submitter = ::AccountId, >; /// The overarching runtime call type. type RuntimeCall: Parameter + Dispatchable::RuntimeOrigin>; - /// The overarching event type. - type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// The overarching runtime origin type. - type RuntimeOrigin: From> - + From<::RuntimeOrigin> - + Into::RuntimeOrigin>>; + type RuntimeOrigin: From> + From<::RuntimeOrigin>; } #[pallet::pallet] @@ -100,17 +86,6 @@ pub mod pallet { #[pallet::storage_version(STORAGE_VERSION)] pub struct Pallet(_); - #[pallet::event] - #[pallet::generate_deposit(pub(super) fn deposit_event)] - pub enum Event { - /// The identity information related to a given subject has been - /// deleted. - IdentityInfoDeleted(T::Identifier), - /// The identity information related to a given subject has been updated - /// to a new digest. - IdentityInfoUpdated(T::Identifier, T::ProofDigest), - } - #[pallet::error] pub enum Error { /// An identity with the provided identifier could not be found. @@ -130,59 +105,34 @@ pub mod pallet { // TODO: Benchmarking #[pallet::call] impl Pallet { - #[pallet::call_index(0)] - #[pallet::weight(0)] - pub fn process_identity_action( - origin: OriginFor, - action: IdentityDetailsAction, - ) -> DispatchResult { - ensure_sibling_para(::RuntimeOrigin::from(origin))?; - - let event = match action { - IdentityDetailsAction::Updated(identifier, proof, _) => { - IdentityEntries::::mutate( - &identifier, - |entry: &mut Option< - IdentityDetails<::ProofDigest, ::IdentityDetails>, - >| { *entry = Some(proof.clone().into()) }, - ); - Ok::<_, Error>(Event::::IdentityInfoUpdated(identifier, proof)) - } - IdentityDetailsAction::Deleted(identifier) => { - IdentityEntries::::remove(&identifier); - Ok::<_, Error>(Event::::IdentityInfoDeleted(identifier)) - } - }?; - - Self::deposit_event(event); - - Ok(()) - } - // TODO: Replace with a SignedExtra. - #[pallet::call_index(1)] + #[pallet::call_index(0)] #[pallet::weight(0)] pub fn dispatch_as( origin: OriginFor, identifier: T::Identifier, - proof: T::Proof, + proof: T::IdentityProof, call: Box<::RuntimeCall>, ) -> DispatchResult { + // TODO: Make origin check configurable, and require that it at least returns + // the submitter's account. let submitter = ensure_signed(origin)?; // TODO: Proper error handling ensure!(T::DipCallOriginFilter::contains(&*call), Error::::Dispatch); - let mut identity_entry = IdentityEntries::::get(&identifier).ok_or(Error::::IdentityNotFound)?; + let mut identity_entry = IdentityEntries::::get(&identifier); let proof_verification_result = T::ProofVerifier::verify_proof_for_call_against_details( &*call, &identifier, &submitter, &mut identity_entry, &proof, - ) - .map_err(|_| Error::::InvalidProof)?; + ); // Write the identity info to storage after it has optionally been updated by - // the `ProofVerifier`. - IdentityEntries::::mutate(&identifier, |entry| *entry = Some(identity_entry)); + // the `ProofVerifier`, regardless of whether the proof has been verified or + // not. + IdentityEntries::::mutate(&identifier, |entry| *entry = identity_entry); + // Unwrap the result if `ok`. + let proof_verification_result = proof_verification_result.map_err(|_| Error::::InvalidProof)?; let did_origin = DipOrigin { identifier, account_address: submitter, diff --git a/pallets/pallet-dip-consumer/src/traits.rs b/pallets/pallet-dip-consumer/src/traits.rs index 63a5c8a831..d05424f45e 100644 --- a/pallets/pallet-dip-consumer/src/traits.rs +++ b/pallets/pallet-dip-consumer/src/traits.rs @@ -29,7 +29,7 @@ pub trait IdentityProofVerifier { call: &Call, subject: &Subject, submitter: &Self::Submitter, - identity_details: &mut Self::IdentityDetails, + identity_details: &mut Option, proof: &Self::Proof, ) -> Result; } @@ -49,7 +49,7 @@ impl IdentityProofVerifier, _proof: &Self::Proof, ) -> Result { Ok(()) From 06de83259b41568136074594a91102395abef704 Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Tue, 11 Jul 2023 14:14:01 +0200 Subject: [PATCH 04/32] Temporarly fix kilt-dip-support to compile --- crates/kilt-dip-support/src/did.rs | 27 +- crates/kilt-dip-support/src/lib.rs | 5 +- crates/kilt-dip-support/src/merkle.rs | 134 ++++---- crates/kilt-dip-support/src/xcm.rs | 289 ------------------ dip-template/runtimes/dip-provider/src/lib.rs | 17 +- .../runtimes/dip-provider/src/xcm_config.rs | 130 -------- 6 files changed, 88 insertions(+), 514 deletions(-) delete mode 100644 crates/kilt-dip-support/src/xcm.rs delete mode 100644 dip-template/runtimes/dip-provider/src/xcm_config.rs diff --git a/crates/kilt-dip-support/src/did.rs b/crates/kilt-dip-support/src/did.rs index c1d37be9a4..2652b026fb 100644 --- a/crates/kilt-dip-support/src/did.rs +++ b/crates/kilt-dip-support/src/did.rs @@ -21,7 +21,7 @@ use did::{ DidSignature, DidVerificationKeyRelationship, }; use frame_support::ensure; -use pallet_dip_consumer::{identity::IdentityDetails, traits::IdentityProofVerifier}; +use pallet_dip_consumer::traits::IdentityProofVerifier; use pallet_dip_provider::traits::IdentityProvider; use parity_scale_codec::{Decode, Encode}; use scale_info::TypeInfo; @@ -133,7 +133,7 @@ impl< type Proof = MerkleLeavesAndDidSignature; /// The `Details` that are part of the identity details must implement the /// `Bump` trait. - type IdentityDetails = IdentityDetails; + type IdentityDetails = Details; /// The type of the submitter's accounts. type Submitter = AccountId; /// Successful verifications return the verification key used to validate @@ -144,7 +144,7 @@ impl< call: &Call, _subject: &Subject, submitter: &Self::Submitter, - identity_details: &mut Self::IdentityDetails, + identity_details: &mut Option, proof: &Self::Proof, ) -> Result { let block_number = BlockNumberProvider::get(); @@ -160,7 +160,7 @@ impl< ensure!(is_signature_fresh, ()); let encoded_payload = ( call, - &identity_details.details, + &identity_details, submitter, &proof.did_signature.block_number, GenesisHashProvider::get(), @@ -168,17 +168,18 @@ impl< ) .encode(); // 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 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() }); let Some((key, relationship)) = valid_signing_key else { return Err(()) }; - identity_details.details.bump(); + // TODO: bump details. + // identity_details.bump(); Ok((key.clone(), relationship)) } } @@ -188,9 +189,9 @@ impl< /// the type of key used in the signature. /// Verification bails out early in case of invalid DID signatures. Otherwise, /// the retrieved key and its relationship is passed to the call verifier to do -/// some additional lookups on the call. -/// The `CallVerifier` only performs internal checks, while all input and output -/// types are taken from the provided `DidSignatureVerifier` type. +/// some additional lookups on the call. The `CallVerifier` only performs +/// internal checks, while all input and output types are taken from the +/// provided `DidSignatureVerifier` type. pub struct DidSignatureAndCallVerifier( PhantomData<(DidSignatureVerifier, CallVerifier)>, ); @@ -219,7 +220,7 @@ where call: &Call, subject: &Subject, submitter: &Self::Submitter, - identity_details: &mut Self::IdentityDetails, + identity_details: &mut Option, proof: &Self::Proof, ) -> Result { let did_signing_key = DidSignatureVerifier::verify_proof_for_call_against_details( diff --git a/crates/kilt-dip-support/src/lib.rs b/crates/kilt-dip-support/src/lib.rs index f4c1a05e4a..702c4f62d8 100644 --- a/crates/kilt-dip-support/src/lib.rs +++ b/crates/kilt-dip-support/src/lib.rs @@ -28,11 +28,10 @@ use crate::did::MerkleLeavesAndDidSignature; pub mod did; pub mod merkle; pub mod traits; -pub mod xcm; /// A type that chains a Merkle proof verification with a DID signature /// verification. The required input of this type is a tuple (A, B) where A is -/// the type of input required by the `MerkleProofVerifier` and B is a +/// /// the type of input required by the `MerkleProofVerifier` and B is a /// `DidSignature`. /// The successful output of this type is the output type of the /// `MerkleProofVerifier`, meaning that DID signature verification happens @@ -68,7 +67,7 @@ where call: &Call, subject: &Subject, submitter: &Self::Submitter, - identity_details: &mut Self::IdentityDetails, + identity_details: &mut Option, proof: &Self::Proof, ) -> Result { let merkle_proof_verification = MerkleProofVerifier::verify_proof_for_call_against_details( diff --git a/crates/kilt-dip-support/src/merkle.rs b/crates/kilt-dip-support/src/merkle.rs index 01722d5555..12bf8c7088 100644 --- a/crates/kilt-dip-support/src/merkle.rs +++ b/crates/kilt-dip-support/src/merkle.rs @@ -18,19 +18,18 @@ use did::{did_details::DidPublicKeyDetails, DidVerificationKeyRelationship}; use frame_support::{traits::ConstU32, RuntimeDebug}; -use pallet_dip_consumer::{identity::IdentityDetails, traits::IdentityProofVerifier}; +use pallet_dip_consumer::traits::IdentityProofVerifier; use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; -use sp_runtime::{BoundedVec, SaturatedConversion}; +use sp_runtime::BoundedVec; use sp_std::{fmt::Debug, marker::PhantomData, vec::Vec}; -use sp_trie::{verify_trie_proof, LayoutV1}; pub type BlindedValue = Vec; #[derive(Encode, Decode, RuntimeDebug, Clone, Eq, PartialEq, TypeInfo, Default)] pub struct MerkleProof { pub blinded: BlindedValue, - // TODO: Probably replace with a different data structure for better lookup capabilities + // TODO: Probably replace with a different data structure for better lookupcapabilities pub revealed: Vec, } @@ -260,7 +259,7 @@ impl< // TODO: Proper error handling type Error = (); type Proof = MerkleProof>, ProofLeaf>; - type IdentityDetails = IdentityDetails; + type IdentityDetails = Details; type Submitter = AccountId; type VerificationResult = VerificationResult< KeyId, @@ -275,68 +274,69 @@ impl< _call: &Call, _subject: &Subject, _submitter: &Self::Submitter, - identity_details: &mut Self::IdentityDetails, - proof: &Self::Proof, + _identity_details: &mut Option, + _proof: &Self::Proof, ) -> Result { - // 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_details.digest.clone().into(), - &proof.blinded, - &proof_leaves, - ) - .map_err(|_| ())?; - - // 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 { - 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, linked_accounts)) - } - // TODO: Avoid cloning if possible - 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)) - } - }, - )?; - - Ok(VerificationResult { - did_keys, - web3_name, - linked_accounts, - }) + Err(()) + // // 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_details.digest.clone().into(), + // &proof.blinded, + // &proof_leaves, + // ) + // .map_err(|_| ())?; + + // // 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 { + // 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, linked_accounts)) + // } + // // TODO: Avoid cloning if possible + // 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)) + // } + // }, + // )?; + + // Ok(VerificationResult { + // did_keys, + // web3_name, + // linked_accounts, + // }) } } diff --git a/crates/kilt-dip-support/src/xcm.rs b/crates/kilt-dip-support/src/xcm.rs deleted file mode 100644 index 8a84459242..0000000000 --- a/crates/kilt-dip-support/src/xcm.rs +++ /dev/null @@ -1,289 +0,0 @@ -// KILT Blockchain – https://botlabs.org -// Copyright (C) 2019-2023 BOTLabs GmbH - -// The KILT Blockchain is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// The KILT Blockchain is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -// If you feel like getting in touch with us, you can do so at info@botlabs.org - -use dip_support::IdentityDetailsAction; -use pallet_dip_provider::traits::{IdentityProofDispatcher, TxBuilder}; -use parity_scale_codec::Encode; -use sp_core::Get; -use sp_std::marker::PhantomData; -use xcm::v3::{ - Instruction::{BuyExecution, DepositAsset, DescendOrigin, ExpectOrigin, RefundSurplus, Transact, WithdrawAsset}, - InteriorMultiLocation, - Junction::AccountId32, - Junctions::{Here, X1}, - MultiAsset, - MultiAssetFilter::Wild, - MultiAssets, MultiLocation, OriginKind, SendError, SendXcm, Weight, - WeightLimit::Limited, - WildMultiAsset::All, - Xcm, -}; - -// Dispatcher using a type implementing the `SendXcm` trait. -// It properly encodes the `Transact` operation, then delegates everything else -// to the sender, similarly to what the XCM pallet's `send` extrinsic does. -pub struct XcmRouterIdentityDispatcher( - PhantomData<(Router, UniversalLocationProvider)>, -); - -impl - IdentityProofDispatcher - for XcmRouterIdentityDispatcher -where - Router: SendXcm, - UniversalLocationProvider: Get, - Identifier: Encode, - ProofOutput: Encode, - AccountId: Into<[u8; 32]> + Clone, -{ - type PreDispatchOutput = Router::Ticket; - type Error = SendError; - - fn pre_dispatch>( - action: IdentityDetailsAction, - source: AccountId, - asset: MultiAsset, - weight: Weight, - destination: MultiLocation, - ) -> Result<(Self::PreDispatchOutput, MultiAssets), Self::Error> { - // TODO: Replace with proper error handling - let dest_tx = Builder::build(destination, action) - .map_err(|_| ()) - .expect("Failed to build call"); - - // TODO: Set an error handler and an appendix to refund any leftover funds to - // the provider parachain sovereign account. - let operation = [[ - ExpectOrigin(Some( - Here.into_location() - .reanchored(&destination, UniversalLocationProvider::get()) - .unwrap(), - )), - DescendOrigin(X1(AccountId32 { - network: None, - id: source.clone().into(), - })), - WithdrawAsset(asset.clone().into()), - BuyExecution { - fees: asset, - weight_limit: Limited(weight), - }, - Transact { - origin_kind: OriginKind::Native, - require_weight_at_most: weight, - call: dest_tx, - }, - RefundSurplus, - DepositAsset { - assets: Wild(All), - beneficiary: MultiLocation { - parents: 1, - // Re-anchor the same account junction as seen from the destination. - // TODO: Error handling - interior: Here - .into_location() - .reanchored(&destination, UniversalLocationProvider::get()) - .unwrap() - .pushed_with_interior(AccountId32 { - network: None, - id: source.into(), - }) - .unwrap() - .interior, - }, - }, - ]] - .concat(); - // TODO: Restructure the trait to be able to inject the [Instruction] provider, - // and unit test that. - debug_assert!(barriers::check_expected_dip_instruction_order(&operation).is_ok()); - let op = Xcm(operation); - Router::validate(&mut Some(destination), &mut Some(op)) - } - - fn dispatch(pre_output: Self::PreDispatchOutput) -> Result<(), Self::Error> { - Router::deliver(pre_output).map(|_| ()) - } -} - -pub mod barriers { - use super::*; - - use frame_support::ensure; - use xcm::v3::{Instruction, Junction::Parachain, ParentThen}; - use xcm_executor::traits::ShouldExecute; - - // Must match the order of instructions as produced by the provider's - // implementation of the `IdentityProofDispatcher` trait. - pub(crate) fn check_expected_dip_instruction_order( - instructions: &[Instruction], - ) -> Result<(), ()> { - let mut iter = instructions.iter(); - match ( - iter.next(), - iter.next(), - iter.next(), - iter.next(), - iter.next(), - iter.next(), - iter.next(), - iter.next(), - ) { - ( - // A first instruction different than `DescendOrigin` is needed to distinguish between user-triggered - // and parachain-triggered XCM messages, since also the XCM pallet always preprends user-created XCM - // messages with a `DescendOrigin` instruction. - Some(ExpectOrigin(..)), - // Go down to user level to charge them for the XCM fees. - Some(DescendOrigin(X1(AccountId32 { .. }))), - // Expect the user to first withdraw an asset to pay for the fees. - Some(WithdrawAsset { .. }), - // Buy execution time. - Some(BuyExecution { .. }), - // Although this is irrelevant since `origin_kind` can also be specified by a user, we use - // `OriginKind::Native` here to make clear this is a parachain-dispatched XCM message. - Some(Transact { - origin_kind: OriginKind::Native, - .. - }), - // Any unused weight is refunded. - Some(RefundSurplus), - // Any unused assets are refunded back into the user's account. - Some(DepositAsset { .. }), - // No more instructions are allowed. - None, - ) => Ok(()), - _ => Err(()), - } - } - - // Allows a parachain to descend to an `X1(AccountId32)` junction, withdraw fees - // from their balance, and then carry on with a `Transact`. - // Must be used **ONLY** in conjunction with the `AccountIdJunctionAsParachain` - // origin converter. - pub struct AllowParachainProviderAsSubaccount(PhantomData); - - impl ShouldExecute for AllowParachainProviderAsSubaccount - where - ProviderParaId: Get, - { - fn should_execute( - origin: &MultiLocation, - instructions: &mut [Instruction], - _max_weight: Weight, - _weight_credit: &mut Weight, - ) -> Result<(), ()> { - #[cfg(feature = "std")] - println!( - "AllowParachainProviderAsSubaccount::should_execute(origin = {:?}, instructions = {:?}", - origin, instructions - ); - // Ensure that the origin is a parachain allowed to act as identity provider. - ensure!( - *origin == ParentThen(Parachain(ProviderParaId::get()).into()).into(), - () - ); - check_expected_dip_instruction_order(instructions) - } - } - - // Decorate an existing barrier to add one more check in case all the previous - // barriers fail. - pub struct OkOrElseCheckForParachainProvider(PhantomData<(Barrier, ProviderParaId)>); - - impl ShouldExecute for OkOrElseCheckForParachainProvider - where - Barrier: ShouldExecute, - ProviderParaId: Get, - { - fn should_execute( - origin: &MultiLocation, - instructions: &mut [Instruction], - max_weight: Weight, - weight_credit: &mut Weight, - ) -> Result<(), ()> { - Barrier::should_execute(origin, instructions, max_weight, weight_credit).or_else(|_| { - AllowParachainProviderAsSubaccount::::should_execute( - origin, - instructions, - max_weight, - weight_credit, - ) - }) - } - } - - // Decorate an existing barrier to check for the provider parachain origin only - // in case none of the previous barriers fail. - pub struct ErrOrElseCheckForParachainProvider(PhantomData<(Barrier, ProviderParaId)>); - - impl ShouldExecute for ErrOrElseCheckForParachainProvider - where - Barrier: ShouldExecute, - ProviderParaId: Get, - { - fn should_execute( - origin: &MultiLocation, - instructions: &mut [Instruction], - max_weight: Weight, - weight_credit: &mut Weight, - ) -> Result<(), ()> { - Barrier::should_execute(origin, instructions, max_weight, weight_credit)?; - AllowParachainProviderAsSubaccount::::should_execute( - origin, - instructions, - max_weight, - weight_credit, - ) - } - } -} - -pub mod origins { - use super::*; - - use xcm::v3::{Junction::Parachain, Junctions::X2}; - use xcm_executor::traits::ConvertOrigin; - - pub struct AccountIdJunctionAsParachain( - PhantomData<(ProviderParaId, ParachainOrigin, RuntimeOrigin)>, - ); - - impl ConvertOrigin - for AccountIdJunctionAsParachain - where - ProviderParaId: Get, - ParachainOrigin: From, - RuntimeOrigin: From, - { - fn convert_origin(origin: impl Into, kind: OriginKind) -> Result { - let origin = origin.into(); - let provider_para_id = ProviderParaId::get(); - match (kind, origin) { - ( - OriginKind::Native, - MultiLocation { - parents: 1, - interior: X2(Parachain(para_id), AccountId32 { .. }), - }, - ) if para_id == provider_para_id => Ok(ParachainOrigin::from(provider_para_id).into()), - _ => Err(origin), - } - } - } -} diff --git a/dip-template/runtimes/dip-provider/src/lib.rs b/dip-template/runtimes/dip-provider/src/lib.rs index ce1a98ea3c..29feef88e1 100644 --- a/dip-template/runtimes/dip-provider/src/lib.rs +++ b/dip-template/runtimes/dip-provider/src/lib.rs @@ -75,8 +75,7 @@ pub use sp_runtime::BuildStorage; use sp_version::NativeVersion; mod dip; -mod xcm_config; -pub use crate::{dip::*, xcm_config::*}; +pub use crate::dip::*; pub type AccountId = AccountId32; pub type Address = MultiAddress; @@ -135,16 +134,10 @@ construct_runtime!( Aura: pallet_aura = 23, AuraExt: cumulus_pallet_aura_ext = 24, - // XCM - XcmpQueue: cumulus_pallet_xcmp_queue = 30, - DmpQueue: cumulus_pallet_dmp_queue = 31, - PolkadotXcm: pallet_xcm = 32, - CumulusXcm: cumulus_pallet_xcm = 33, - // DID - Did: did = 40, - DidLookup: pallet_did_lookup = 41, - Web3Names: pallet_web3_names = 42, + Did: did = 30, + DidLookup: pallet_did_lookup = 31, + Web3Names: pallet_web3_names = 32, // DIP DipProvider: pallet_dip_provider = 50, @@ -265,7 +258,7 @@ impl cumulus_pallet_parachain_system::Config for Runtime { type ReservedXcmpWeight = ReservedXcmpWeight; type RuntimeEvent = RuntimeEvent; type SelfParaId = ParachainInfo; - type XcmpMessageHandler = XcmpQueue; + type XcmpMessageHandler = (); } impl pallet_timestamp::Config for Runtime { diff --git a/dip-template/runtimes/dip-provider/src/xcm_config.rs b/dip-template/runtimes/dip-provider/src/xcm_config.rs deleted file mode 100644 index df62925d53..0000000000 --- a/dip-template/runtimes/dip-provider/src/xcm_config.rs +++ /dev/null @@ -1,130 +0,0 @@ -// KILT Blockchain – https://botlabs.org -// Copyright (C) 2019-2023 BOTLabs GmbH - -// The KILT Blockchain is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// The KILT Blockchain is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -// If you feel like getting in touch with us, you can do so at info@botlabs.org - -use cumulus_primitives_utility::ParentAsUmp; -use frame_support::{ - parameter_types, - traits::{ConstU32, Nothing}, - weights::{IdentityFee, Weight}, -}; -use frame_system::EnsureRoot; -use pallet_xcm::TestWeightInfo; -use xcm::v3::prelude::*; -use xcm_builder::{EnsureXcmOrigin, FixedWeightBounds, SignedToAccountId32, UsingComponents}; -use xcm_executor::XcmExecutor; - -use crate::{ - AccountId, AllPalletsWithSystem, Balance, Balances, ParachainInfo, ParachainSystem, Runtime, RuntimeCall, - RuntimeEvent, RuntimeOrigin, XcmpQueue, -}; - -parameter_types! { - pub HereLocation: MultiLocation = Junctions::Here.into(); - pub UnitWeightCost: Weight = Weight::from_ref_time(1_000); - pub UniversalLocation: InteriorMultiLocation = Parachain(ParachainInfo::parachain_id().into()).into(); -} - -pub type XcmRouter = (ParentAsUmp, XcmpQueue); - -pub struct XcmConfig; -impl xcm_executor::Config for XcmConfig { - type AssetClaims = (); - type AssetExchanger = (); - type AssetLocker = (); - type AssetTransactor = (); - type AssetTrap = (); - type Barrier = (); - type CallDispatcher = RuntimeCall; - type FeeManager = (); - type IsReserve = (); - type IsTeleporter = (); - type MaxAssetsIntoHolding = ConstU32<64>; - type MessageExporter = (); - type OriginConverter = (); - type PalletInstancesInfo = AllPalletsWithSystem; - type ResponseHandler = (); - type RuntimeCall = RuntimeCall; - type SafeCallFilter = Nothing; - type SubscriptionService = (); - type UniversalAliases = Nothing; - type UniversalLocation = UniversalLocation; - type Trader = UsingComponents, HereLocation, AccountId, Balances, ()>; - type Weigher = FixedWeightBounds>; - type XcmSender = XcmRouter; -} - -impl cumulus_pallet_xcmp_queue::Config for Runtime { - type ChannelInfo = ParachainSystem; - type ControllerOrigin = EnsureRoot; - type ControllerOriginConverter = (); - type ExecuteOverweightOrigin = EnsureRoot; - type PriceForSiblingDelivery = (); - type RuntimeEvent = RuntimeEvent; - type VersionWrapper = (); - type WeightInfo = (); - type XcmExecutor = XcmExecutor; -} - -impl cumulus_pallet_dmp_queue::Config for Runtime { - type ExecuteOverweightOrigin = EnsureRoot; - type RuntimeEvent = RuntimeEvent; - type XcmExecutor = XcmExecutor; -} - -const MAX_INSTRUCTIONS: u32 = 100; - -parameter_types! { - pub RelayNetwork: Option = None; -} -#[cfg(feature = "runtime-benchmarks")] -parameter_types! { - pub ReachableDest: Option = Some(Parent.into()); -} - -pub type XcmPalletToRemoteLocationConverter = SignedToAccountId32; - -impl pallet_xcm::Config for Runtime { - const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100; - - type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion; - type Currency = Balances; - type CurrencyMatcher = (); - type ExecuteXcmOrigin = EnsureXcmOrigin; - type MaxLockers = ConstU32<8>; - type RuntimeCall = RuntimeCall; - type RuntimeEvent = RuntimeEvent; - type RuntimeOrigin = RuntimeOrigin; - type SendXcmOrigin = EnsureXcmOrigin; - type SovereignAccountOf = (); - type TrustedLockers = (); - type UniversalLocation = UniversalLocation; - type Weigher = FixedWeightBounds>; - type WeightInfo = TestWeightInfo; - type XcmExecuteFilter = Nothing; - type XcmExecutor = XcmExecutor; - type XcmReserveTransferFilter = Nothing; - type XcmRouter = XcmRouter; - type XcmTeleportFilter = Nothing; - #[cfg(feature = "runtime-benchmarks")] - type ReachableDest = ReachableDest; -} - -impl cumulus_pallet_xcm::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type XcmExecutor = XcmExecutor; -} From dda48d6708230d8a6bdd4c7ca4288a35f14b91c5 Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Tue, 11 Jul 2023 14:47:08 +0200 Subject: [PATCH 05/32] Whole project compiling --- Cargo.lock | 61 ---- .../nodes/dip-consumer/src/chain_spec.rs | 1 - .../nodes/dip-provider/src/chain_spec.rs | 1 - dip-template/runtimes/dip-consumer/src/dip.rs | 6 +- dip-template/runtimes/dip-consumer/src/lib.rs | 28 +- .../runtimes/dip-consumer/src/xcm_config.rs | 150 --------- dip-template/runtimes/dip-provider/src/dip.rs | 41 +-- dip-template/runtimes/dip-provider/src/lib.rs | 13 +- dip-template/runtimes/xcm-tests/Cargo.toml | 47 --- dip-template/runtimes/xcm-tests/src/lib.rs | 59 ---- dip-template/runtimes/xcm-tests/src/para.rs | 221 -------------- dip-template/runtimes/xcm-tests/src/relay.rs | 91 ------ dip-template/runtimes/xcm-tests/src/tests.rs | 285 ------------------ runtimes/common/src/dip/merkle.rs | 4 +- 14 files changed, 19 insertions(+), 989 deletions(-) delete mode 100644 dip-template/runtimes/dip-consumer/src/xcm_config.rs delete mode 100644 dip-template/runtimes/xcm-tests/Cargo.toml delete mode 100644 dip-template/runtimes/xcm-tests/src/lib.rs delete mode 100644 dip-template/runtimes/xcm-tests/src/para.rs delete mode 100644 dip-template/runtimes/xcm-tests/src/relay.rs delete mode 100644 dip-template/runtimes/xcm-tests/src/tests.rs diff --git a/Cargo.lock b/Cargo.lock index a0bca81fe5..00fac4c58b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2495,41 +2495,6 @@ dependencies = [ "scale-info", ] -[[package]] -name = "dip-templates-xcm-tests" -version = "1.11.0-dev" -dependencies = [ - "cumulus-pallet-xcmp-queue", - "did", - "dip-consumer-runtime-template", - "dip-provider-runtime-template", - "dip-support", - "frame-support", - "frame-system", - "kilt-dip-support", - "kilt-support", - "pallet-balances", - "pallet-did-lookup", - "pallet-dip-provider", - "pallet-web3-names", - "parachain-info", - "parity-scale-codec", - "polkadot-parachain", - "polkadot-primitives", - "polkadot-runtime-parachains", - "rococo-runtime", - "runtime-common", - "scale-info", - "sp-core", - "sp-io", - "sp-runtime", - "sp-std", - "xcm", - "xcm-builder", - "xcm-emulator", - "xcm-executor", -] - [[package]] name = "directories" version = "4.0.1" @@ -14112,32 +14077,6 @@ dependencies = [ "xcm-executor", ] -[[package]] -name = "xcm-emulator" -version = "0.1.0" -source = "git+https://github.com/shaunxw/xcm-simulator?branch=master#aa13dce47596e150806dfc3af99096dae6ffc65e" -dependencies = [ - "cumulus-pallet-dmp-queue", - "cumulus-pallet-parachain-system", - "cumulus-pallet-xcmp-queue", - "cumulus-primitives-core", - "cumulus-primitives-parachain-inherent", - "cumulus-test-relay-sproof-builder", - "frame-support", - "frame-system", - "parachain-info", - "parity-scale-codec", - "paste", - "polkadot-primitives", - "polkadot-runtime-parachains", - "quote", - "sp-arithmetic", - "sp-io", - "sp-std", - "xcm", - "xcm-executor", -] - [[package]] name = "xcm-executor" version = "0.9.39-1" diff --git a/dip-template/nodes/dip-consumer/src/chain_spec.rs b/dip-template/nodes/dip-consumer/src/chain_spec.rs index 4330bf5c62..d80daa51d2 100644 --- a/dip-template/nodes/dip-consumer/src/chain_spec.rs +++ b/dip-template/nodes/dip-consumer/src/chain_spec.rs @@ -99,7 +99,6 @@ fn testnet_genesis( }, aura: Default::default(), aura_ext: Default::default(), - polkadot_xcm: Default::default(), did_lookup: Default::default(), } } diff --git a/dip-template/nodes/dip-provider/src/chain_spec.rs b/dip-template/nodes/dip-provider/src/chain_spec.rs index af6493f67c..6e162c624e 100644 --- a/dip-template/nodes/dip-provider/src/chain_spec.rs +++ b/dip-template/nodes/dip-provider/src/chain_spec.rs @@ -99,7 +99,6 @@ 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-consumer/src/dip.rs b/dip-template/runtimes/dip-consumer/src/dip.rs index 9ba29126e2..2df1d76d81 100644 --- a/dip-template/runtimes/dip-consumer/src/dip.rs +++ b/dip-template/runtimes/dip-consumer/src/dip.rs @@ -29,7 +29,7 @@ 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}; +use crate::{AccountId, BlockNumber, DidIdentifier, Hash, Hasher, Runtime, RuntimeCall, RuntimeOrigin}; pub type MerkleProofVerifier = DidMerkleProofVerifier, BlockNumber, u128, Web3Name, LinkableAccountId, 10, 10>; @@ -52,19 +52,17 @@ pub type MerkleDidSignatureVerifierOf = MerkleRevealedDidSignatur impl pallet_dip_consumer::Config for Runtime { type DipCallOriginFilter = PreliminaryDipOriginFilter; type Identifier = DidIdentifier; - type LocalIdentityInfo = u128; type IdentityProof = MerkleLeavesAndDidSignature< MerkleProof>, ProofLeaf>, BlockNumber, >; - type IdentityCommitment = Hash; + type LocalIdentityInfo = u128; type ProofVerifier = MerkleProofAndDidSignatureVerifier< BlockNumber, MerkleProofVerifier, DidSignatureAndCallVerifier, DipCallFilter>, >; type RuntimeCall = RuntimeCall; - type RuntimeEvent = RuntimeEvent; type RuntimeOrigin = RuntimeOrigin; } diff --git a/dip-template/runtimes/dip-consumer/src/lib.rs b/dip-template/runtimes/dip-consumer/src/lib.rs index 03fcfb5dfe..9f13ffae5f 100644 --- a/dip-template/runtimes/dip-consumer/src/lib.rs +++ b/dip-template/runtimes/dip-consumer/src/lib.rs @@ -68,8 +68,7 @@ use sp_std::{prelude::*, time::Duration}; use sp_version::RuntimeVersion; mod dip; -mod xcm_config; -pub use crate::{dip::*, xcm_config::*}; +pub use crate::dip::*; #[cfg(any(feature = "std", test))] pub use sp_runtime::BuildStorage; @@ -136,17 +135,11 @@ construct_runtime!( Aura: pallet_aura = 23, AuraExt: cumulus_pallet_aura_ext = 24, - // XCM - XcmpQueue: cumulus_pallet_xcmp_queue = 30, - DmpQueue: cumulus_pallet_dmp_queue = 31, - PolkadotXcm: pallet_xcm = 32, - CumulusXcm: cumulus_pallet_xcm = 33, - // DID lookup - DidLookup: pallet_did_lookup = 40, + DidLookup: pallet_did_lookup = 30, // DIP - DipConsumer: pallet_dip_consumer = 50, + DipConsumer: pallet_dip_consumer = 40, } ); @@ -251,21 +244,16 @@ impl frame_system::Config for Runtime { type Version = Version; } -parameter_types! { - pub const ReservedDmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT.saturating_div(4); - pub const ReservedXcmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT.saturating_div(4); -} - impl cumulus_pallet_parachain_system::Config for Runtime { type CheckAssociatedRelayNumber = RelayNumberStrictlyIncreases; - type DmpMessageHandler = DmpQueue; + type DmpMessageHandler = (); type OnSystemEvent = (); - type OutboundXcmpMessageSource = XcmpQueue; - type ReservedDmpWeight = ReservedDmpWeight; - type ReservedXcmpWeight = ReservedXcmpWeight; + type OutboundXcmpMessageSource = (); + type ReservedDmpWeight = (); + type ReservedXcmpWeight = (); type RuntimeEvent = RuntimeEvent; type SelfParaId = ParachainInfo; - type XcmpMessageHandler = XcmpQueue; + type XcmpMessageHandler = (); } impl pallet_timestamp::Config for Runtime { diff --git a/dip-template/runtimes/dip-consumer/src/xcm_config.rs b/dip-template/runtimes/dip-consumer/src/xcm_config.rs deleted file mode 100644 index 83d2918888..0000000000 --- a/dip-template/runtimes/dip-consumer/src/xcm_config.rs +++ /dev/null @@ -1,150 +0,0 @@ -// KILT Blockchain – https://botlabs.org -// Copyright (C) 2019-2023 BOTLabs GmbH - -// The KILT Blockchain is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// The KILT Blockchain is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -// If you feel like getting in touch with us, you can do so at info@botlabs.org - -use cumulus_primitives_utility::ParentAsUmp; -use frame_support::{ - parameter_types, - traits::{ConstU32, Contains, Nothing}, - weights::{IdentityFee, Weight}, -}; -use frame_system::EnsureRoot; -use kilt_dip_support::xcm::{barriers::OkOrElseCheckForParachainProvider, origins::AccountIdJunctionAsParachain}; -use pallet_xcm::TestWeightInfo; -use xcm::v3::prelude::*; -use xcm_builder::{ - Account32Hash, AllowTopLevelPaidExecutionFrom, CurrencyAdapter, EnsureXcmOrigin, FixedWeightBounds, IsConcrete, - SignedToAccountId32, UsingComponents, -}; -use xcm_executor::XcmExecutor; - -use crate::{ - AccountId, AllPalletsWithSystem, Balance, Balances, ParachainInfo, ParachainSystem, Runtime, RuntimeCall, - RuntimeEvent, RuntimeOrigin, XcmpQueue, -}; - -parameter_types! { - pub HereLocation: MultiLocation = MultiLocation::here(); - pub NoneNetworkId: Option = None; - pub UnitWeightCost: Weight = Weight::from_ref_time(1_000); - pub UniversalLocation: InteriorMultiLocation = Parachain(ParachainInfo::parachain_id().into()).into(); -} - -pub type Barrier = OkOrElseCheckForParachainProvider, ConstU32<2_000>>; -pub type AssetTransactorLocationConverter = Account32Hash; -pub type LocalAssetTransactor = - CurrencyAdapter, AssetTransactorLocationConverter, AccountId, ()>; -pub type XcmRouter = (ParentAsUmp, XcmpQueue); - -pub struct DipTransactSafeCalls; - -impl Contains for DipTransactSafeCalls { - fn contains(t: &RuntimeCall) -> bool { - matches!( - t, - RuntimeCall::DipConsumer(pallet_dip_consumer::Call::process_identity_action { .. }) - ) - } -} - -pub struct XcmConfig; -impl xcm_executor::Config for XcmConfig { - type AssetClaims = (); - type AssetExchanger = (); - type AssetLocker = (); - type AssetTransactor = LocalAssetTransactor; - type AssetTrap = (); - type Barrier = Barrier; - type CallDispatcher = RuntimeCall; - type FeeManager = (); - type IsReserve = (); - type IsTeleporter = (); - type MaxAssetsIntoHolding = ConstU32<64>; - type MessageExporter = (); - type OriginConverter = AccountIdJunctionAsParachain, cumulus_pallet_xcm::Origin, RuntimeOrigin>; - type PalletInstancesInfo = AllPalletsWithSystem; - type ResponseHandler = (); - type RuntimeCall = RuntimeCall; - type SafeCallFilter = DipTransactSafeCalls; - type SubscriptionService = (); - type UniversalAliases = Nothing; - type UniversalLocation = UniversalLocation; - type Trader = UsingComponents, HereLocation, AccountId, Balances, ()>; - type Weigher = FixedWeightBounds>; - type XcmSender = XcmRouter; -} - -impl cumulus_pallet_xcmp_queue::Config for Runtime { - type ChannelInfo = ParachainSystem; - type ControllerOrigin = EnsureRoot; - type ControllerOriginConverter = (); - type ExecuteOverweightOrigin = EnsureRoot; - type PriceForSiblingDelivery = (); - type RuntimeEvent = RuntimeEvent; - type VersionWrapper = (); - type WeightInfo = (); - type XcmExecutor = XcmExecutor; -} - -impl cumulus_pallet_dmp_queue::Config for Runtime { - type ExecuteOverweightOrigin = EnsureRoot; - type RuntimeEvent = RuntimeEvent; - type XcmExecutor = XcmExecutor; -} - -const MAX_INSTRUCTIONS: u32 = 100; - -parameter_types! { - pub RelayNetwork: Option = None; -} -#[cfg(feature = "runtime-benchmarks")] -parameter_types! { - pub ReachableDest: Option = Some(Parent.into()); -} - -pub type XcmPalletToRemoteLocationConverter = SignedToAccountId32; - -impl pallet_xcm::Config for Runtime { - const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100; - - type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion; - type Currency = Balances; - type CurrencyMatcher = (); - type ExecuteXcmOrigin = EnsureXcmOrigin; - type MaxLockers = ConstU32<8>; - type RuntimeCall = RuntimeCall; - type RuntimeEvent = RuntimeEvent; - type RuntimeOrigin = RuntimeOrigin; - type SendXcmOrigin = EnsureXcmOrigin; - type SovereignAccountOf = (); - type TrustedLockers = (); - type UniversalLocation = UniversalLocation; - type Weigher = FixedWeightBounds>; - type WeightInfo = TestWeightInfo; - type XcmExecuteFilter = Nothing; - type XcmExecutor = XcmExecutor; - type XcmReserveTransferFilter = Nothing; - type XcmRouter = XcmRouter; - type XcmTeleportFilter = Nothing; - #[cfg(feature = "runtime-benchmarks")] - type ReachableDest = ReachableDest; -} - -impl cumulus_pallet_xcm::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type XcmExecutor = XcmExecutor; -} diff --git a/dip-template/runtimes/dip-provider/src/dip.rs b/dip-template/runtimes/dip-provider/src/dip.rs index 59b6aedade..108bcbd7f2 100644 --- a/dip-template/runtimes/dip-provider/src/dip.rs +++ b/dip-template/runtimes/dip-provider/src/dip.rs @@ -17,51 +17,16 @@ // If you feel like getting in touch with us, you can do so at info@botlabs.org use did::{DidRawOrigin, EnsureDidOrigin}; -use dip_support::IdentityDetailsAction; -use kilt_dip_support::xcm::XcmRouterIdentityDispatcher; -use pallet_dip_provider::traits::TxBuilder; -use parity_scale_codec::{Decode, Encode}; use runtime_common::dip::{did::LinkedDidInfoProviderOf, merkle::DidMerkleRootGenerator}; -use xcm::{latest::MultiLocation, DoubleEncoded}; -use crate::{AccountId, DidIdentifier, Hash, Runtime, RuntimeEvent, UniversalLocation, XcmRouter}; - -#[derive(Encode, Decode)] -enum ConsumerParachainCalls { - #[codec(index = 50)] - DipConsumer(ConsumerParachainDipConsumerCalls), -} - -#[derive(Encode, Decode)] -enum ConsumerParachainDipConsumerCalls { - #[codec(index = 0)] - ProcessIdentityAction(IdentityDetailsAction), -} - -pub struct ConsumerParachainTxBuilder; -impl TxBuilder for ConsumerParachainTxBuilder { - type Error = (); - - fn build( - _dest: MultiLocation, - action: IdentityDetailsAction, - ) -> Result, Self::Error> { - let double_encoded: DoubleEncoded<()> = - ConsumerParachainCalls::DipConsumer(ConsumerParachainDipConsumerCalls::ProcessIdentityAction(action)) - .encode() - .into(); - Ok(double_encoded) - } -} +use crate::{AccountId, DidIdentifier, Hash, Runtime, RuntimeEvent}; impl pallet_dip_provider::Config for Runtime { type CommitOriginCheck = EnsureDidOrigin; type CommitOrigin = DidRawOrigin; type Identifier = DidIdentifier; - type IdentityProofDispatcher = XcmRouterIdentityDispatcher; - type IdentityProofGenerator = DidMerkleRootGenerator; + type IdentityCommitment = Hash; + type IdentityCommitmentGenerator = DidMerkleRootGenerator; 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 29feef88e1..b1d83b54aa 100644 --- a/dip-template/runtimes/dip-provider/src/lib.rs +++ b/dip-template/runtimes/dip-provider/src/lib.rs @@ -244,18 +244,13 @@ impl frame_system::Config for Runtime { type Version = Version; } -parameter_types! { - pub const ReservedDmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT.saturating_div(4); - pub const ReservedXcmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT.saturating_div(4); -} - impl cumulus_pallet_parachain_system::Config for Runtime { type CheckAssociatedRelayNumber = RelayNumberStrictlyIncreases; - type DmpMessageHandler = DmpQueue; + type DmpMessageHandler = (); type OnSystemEvent = (); - type OutboundXcmpMessageSource = XcmpQueue; - type ReservedDmpWeight = ReservedDmpWeight; - type ReservedXcmpWeight = ReservedXcmpWeight; + type OutboundXcmpMessageSource = (); + type ReservedDmpWeight = (); + type ReservedXcmpWeight = (); type RuntimeEvent = RuntimeEvent; type SelfParaId = ParachainInfo; type XcmpMessageHandler = (); diff --git a/dip-template/runtimes/xcm-tests/Cargo.toml b/dip-template/runtimes/xcm-tests/Cargo.toml deleted file mode 100644 index d922974440..0000000000 --- a/dip-template/runtimes/xcm-tests/Cargo.toml +++ /dev/null @@ -1,47 +0,0 @@ -[package] -authors.workspace = true -documentation.workspace = true -edition.workspace = true -homepage.workspace = true -license-file.workspace = true -readme.workspace = true -repository.workspace = true -version.workspace = true -name = "dip-templates-xcm-tests" -description = "XCM integration tests for the KILT Decentralized Identity Provider (DIP) provider and consumer templates." - -[dependencies] -cumulus-pallet-xcmp-queue = { workspace = true, features = ["std"] } -did = { workspace = true, features = ["std"] } -dip-consumer-runtime-template = { workspace = true, features = ["std"] } -dip-provider-runtime-template = { workspace = true, features = ["std"] } -dip-support = { workspace = true, features = ["std"] } -frame-support = { workspace = true, features = ["std"] } -frame-system = { workspace = true, features = ["std"] } -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-dip-provider = { 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"] } -polkadot-primitives = { workspace = true, features = ["std"] } -polkadot-runtime-parachains = { workspace = true, features = ["std"] } -rococo-runtime = { workspace = true, features = ["std"] } -runtime-common = { workspace = true, features = ["std"] } -scale-info = { workspace = true, features = ["std"] } -sp-core = { workspace = true, features = ["std"] } -sp-io = { workspace = true, features = ["std"] } -sp-runtime = { workspace = true, features = ["std"] } -sp-std = { workspace = true, features = ["std"] } -xcm = { workspace = true, features = ["std"] } -xcm-builder = { workspace = true, features = ["std"] } -xcm-emulator = { git = "https://github.com/shaunxw/xcm-simulator", branch = "master" } -xcm-executor = { workspace = true, features = ["std"] } - -[features] -runtime-benchmarks = [ - "rococo-runtime/runtime-benchmarks" -] diff --git a/dip-template/runtimes/xcm-tests/src/lib.rs b/dip-template/runtimes/xcm-tests/src/lib.rs deleted file mode 100644 index fa1dd5c00f..0000000000 --- a/dip-template/runtimes/xcm-tests/src/lib.rs +++ /dev/null @@ -1,59 +0,0 @@ -// KILT Blockchain – https://botlabs.org -// Copyright (C) 2019-2023 BOTLabs GmbH - -// The KILT Blockchain is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// The KILT Blockchain is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -// If you feel like getting in touch with us, you can do so at info@botlabs.org - -use xcm_emulator::{decl_test_network, decl_test_parachain}; - -use crate::relay::RococoChain; - -mod para; -mod relay; - -#[cfg(test)] -mod tests; - -decl_test_parachain! { - pub struct ProviderParachain { - Runtime = para::provider::Runtime, - RuntimeOrigin = para::provider::RuntimeOrigin, - XcmpMessageHandler = para::provider::XcmpQueue, - DmpMessageHandler = para::provider::DmpQueue, - new_ext = para::provider::para_ext(), - } -} - -decl_test_parachain! { - pub struct ConsumerParachain { - Runtime = para::consumer::Runtime, - RuntimeOrigin = para::consumer::RuntimeOrigin, - XcmpMessageHandler = para::consumer::XcmpQueue, - DmpMessageHandler = para::consumer::DmpQueue, - new_ext = para::consumer::para_ext(), - } -} - -decl_test_network! { - pub struct Network { - relay_chain = RococoChain, - parachains = vec![ - // TODO: Change when and if the macro will allow arbitrary expressions. - // Until then, these have to match the PARA_ID consts in the para submodules. - (2_000, ProviderParachain), - (2_001, ConsumerParachain), - ], - } -} diff --git a/dip-template/runtimes/xcm-tests/src/para.rs b/dip-template/runtimes/xcm-tests/src/para.rs deleted file mode 100644 index a24076fe04..0000000000 --- a/dip-template/runtimes/xcm-tests/src/para.rs +++ /dev/null @@ -1,221 +0,0 @@ -// KILT Blockchain – https://botlabs.org -// Copyright (C) 2019-2023 BOTLabs GmbH - -// The KILT Blockchain is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// The KILT Blockchain is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -// If you feel like getting in touch with us, you can do so at info@botlabs.org - -use crate::{_Messenger, _hrmp_channel_parachain_inherent_data, _process_messages}; -use frame_support::traits::GenesisBuild; -use sp_io::TestExternalities; -use xcm_emulator::decl_test_parachain; - -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, Balance, BlockNumber, System, Web3Name, UNIT}; - 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::*; - - pub const PARA_ID: u32 = 2_000; - pub const DISPATCHER_ACCOUNT: AccountId = AccountId::new([190u8; 32]); - const INITIAL_BALANCE: Balance = 100_000 * UNIT; - - pub(crate) fn did_auth_key() -> ed25519::Pair { - ed25519::Pair::from_seed(&[200u8; 32]) - } - - fn generate_did_details() -> DidDetails { - let auth_key: DidVerificationKey = did_auth_key().public().into(); - let att_key: DidVerificationKey = sr25519::Pair::from_seed(&[100u8; 32]).public().into(); - let del_key: DidVerificationKey = ecdsa::Pair::from_seed(&[101u8; 32]).public().into(); - - let mut details = DidDetails::new( - auth_key, - 0u32, - Deposit { - amount: 1u64.into(), - owner: AccountId::new([1u8; 32]), - }, - ) - .unwrap(); - details.update_attestation_key(att_key, 0u32).unwrap(); - details.update_delegation_key(del_key, 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 - } - - pub(crate) fn para_ext() -> TestExternalities { - let mut t = frame_system::GenesisConfig::default() - .build_storage::() - .unwrap(); - - let parachain_info_config = parachain_info::GenesisConfig { - parachain_id: PARA_ID.into(), - }; - - >::assimilate_storage(¶chain_info_config, &mut t) - .unwrap(); - - pallet_balances::GenesisConfig:: { - balances: vec![(DISPATCHER_ACCOUNT, INITIAL_BALANCE)], - } - .assimilate_storage(&mut t) - .unwrap(); - - 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 - } - - decl_test_parachain! { - pub struct ProviderParachain { - Runtime = Runtime, - RuntimeOrigin = RuntimeOrigin, - XcmpMessageHandler = XcmpQueue, - DmpMessageHandler = DmpQueue, - new_ext = para_ext(), - } - } -} - -pub(super) mod consumer { - pub(crate) use dip_consumer_runtime_template::{ - AccountId, AssetTransactorLocationConverter, Balance, DmpQueue, Runtime, RuntimeOrigin, XcmpQueue, UNIT, - }; - - use dip_consumer_runtime_template::System; - use xcm::v3::{ - Junction::{AccountId32, Parachain}, - Junctions::X2, - ParentThen, - }; - use xcm_executor::traits::Convert; - - use super::*; - - pub const PARA_ID: u32 = 2_001; - pub const DISPATCHER_ACCOUNT: AccountId = AccountId::new([90u8; 32]); - const INITIAL_BALANCE: Balance = 100_000 * UNIT; - - pub(crate) fn provider_dispatcher_account_on_consumer() -> AccountId { - AssetTransactorLocationConverter::convert( - ParentThen(X2( - Parachain(provider::PARA_ID), - AccountId32 { - network: None, - id: provider::DISPATCHER_ACCOUNT.into(), - }, - )) - .into(), - ) - .expect("Conversion of account from provider parachain to consumer parachain should not fail.") - } - - pub(crate) fn para_ext() -> TestExternalities { - let mut t = frame_system::GenesisConfig::default() - .build_storage::() - .unwrap(); - - let parachain_info_config = parachain_info::GenesisConfig { - parachain_id: PARA_ID.into(), - }; - - >::assimilate_storage(¶chain_info_config, &mut t) - .unwrap(); - - pallet_balances::GenesisConfig:: { - balances: vec![ - (provider_dispatcher_account_on_consumer(), INITIAL_BALANCE), - (DISPATCHER_ACCOUNT, INITIAL_BALANCE), - ], - } - .assimilate_storage(&mut t) - .unwrap(); - - let mut ext = TestExternalities::new(t); - ext.execute_with(|| { - System::set_block_number(1); - }); - ext - } - - #[cfg(test)] - pub(crate) use test_utils::*; - - #[cfg(test)] - mod test_utils { - use super::*; - - use polkadot_parachain::primitives::Sibling; - use xcm::v3::Junctions::X1; - use xcm_builder::SiblingParachainConvertsVia; - - pub(crate) fn provider_parachain_account_on_consumer() -> AccountId { - SiblingParachainConvertsVia::::convert( - ParentThen(X1(Parachain(provider::PARA_ID))).into(), - ) - .expect("Conversion of account from provider parachain to consumer parachain should not fail.") - } - } -} diff --git a/dip-template/runtimes/xcm-tests/src/relay.rs b/dip-template/runtimes/xcm-tests/src/relay.rs deleted file mode 100644 index 2f60171149..0000000000 --- a/dip-template/runtimes/xcm-tests/src/relay.rs +++ /dev/null @@ -1,91 +0,0 @@ -// KILT Blockchain – https://botlabs.org -// Copyright (C) 2019-2023 BOTLabs GmbH - -// The KILT Blockchain is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// The KILT Blockchain is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -// If you feel like getting in touch with us, you can do so at info@botlabs.org - -use crate::{_Messenger, _para_ids, _process_messages}; -use frame_support::{traits::GenesisBuild, weights::Weight}; -use polkadot_primitives::{runtime_api::runtime_decl_for_ParachainHost::ParachainHostV4, BlockNumber}; -use polkadot_runtime_parachains::configuration::HostConfiguration; -use rococo_runtime::{xcm_config::XcmConfig, Runtime}; -use sp_io::TestExternalities; -use xcm_emulator::decl_test_relay_chain; - -fn default_parachains_host_configuration() -> HostConfiguration { - use polkadot_primitives::v2::{MAX_CODE_SIZE, MAX_POV_SIZE}; - - HostConfiguration { - minimum_validation_upgrade_delay: 5, - validation_upgrade_cooldown: 10u32, - validation_upgrade_delay: 10, - code_retention_period: 1200, - max_code_size: MAX_CODE_SIZE, - max_pov_size: MAX_POV_SIZE, - max_head_data_size: 32 * 1024, - group_rotation_frequency: 20, - chain_availability_period: 4, - thread_availability_period: 4, - max_upward_queue_count: 8, - max_upward_queue_size: 1024 * 1024, - max_downward_message_size: 1024, - ump_service_total_weight: Weight::from_ref_time(4 * 1_000_000_000), - max_upward_message_size: 50 * 1024, - max_upward_message_num_per_candidate: 5, - hrmp_sender_deposit: 0, - hrmp_recipient_deposit: 0, - hrmp_channel_max_capacity: 8, - hrmp_channel_max_total_size: 8 * 1024, - hrmp_max_parachain_inbound_channels: 4, - hrmp_max_parathread_inbound_channels: 4, - hrmp_channel_max_message_size: 1024 * 1024, - hrmp_max_parachain_outbound_channels: 4, - hrmp_max_parathread_outbound_channels: 4, - hrmp_max_message_num_per_candidate: 5, - dispute_period: 6, - no_show_slots: 2, - n_delay_tranches: 25, - needed_approvals: 2, - relay_vrf_modulo_samples: 2, - zeroth_delay_tranche_width: 0, - ..Default::default() - } -} - -fn relay_ext() -> TestExternalities { - use rococo_runtime::System; - - let mut t = frame_system::GenesisConfig::default() - .build_storage::() - .unwrap(); - - polkadot_runtime_parachains::configuration::GenesisConfig:: { - config: default_parachains_host_configuration(), - } - .assimilate_storage(&mut t) - .unwrap(); - - let mut ext = sp_io::TestExternalities::new(t); - ext.execute_with(|| System::set_block_number(1)); - ext -} - -decl_test_relay_chain! { - pub struct RococoChain { - Runtime = Runtime, - XcmConfig = XcmConfig, - new_ext = relay_ext(), - } -} diff --git a/dip-template/runtimes/xcm-tests/src/tests.rs b/dip-template/runtimes/xcm-tests/src/tests.rs deleted file mode 100644 index c44e45dd33..0000000000 --- a/dip-template/runtimes/xcm-tests/src/tests.rs +++ /dev/null @@ -1,285 +0,0 @@ -// KILT Blockchain – https://botlabs.org -// Copyright (C) 2019-2023 BOTLabs GmbH - -// The KILT Blockchain is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// The KILT Blockchain is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -// If you feel like getting in touch with us, you can do so at info@botlabs.org - -use super::*; - -use did::{Did, DidRawOrigin, DidSignature}; -use dip_support::IdentityDetailsAction; -use frame_support::{assert_ok, weights::Weight}; -use frame_system::RawOrigin; -use kilt_dip_support::{ - did::{MerkleLeavesAndDidSignature, TimeBoundDidSignature}, - merkle::MerkleProof, -}; -use pallet_did_lookup::{linkable_account::LinkableAccountId, ConnectedAccounts}; -use pallet_dip_provider::traits::TxBuilder; -use pallet_web3_names::{Names, Owner}; -use parity_scale_codec::Encode; -use runtime_common::dip::{ - did::Web3OwnershipOf, - merkle::{CompleteMerkleProof, DidMerkleRootGenerator}, -}; -use sp_core::Pair; -use sp_runtime::traits::Zero; -use xcm::{ - v3::{ - Instruction::{BuyExecution, DepositAsset, ExpectOrigin, RefundSurplus, Transact, WithdrawAsset}, - Junction::{AccountId32, Parachain}, - Junctions::{Here, X1}, - MultiAsset, - MultiAssetFilter::Wild, - MultiLocation, OriginKind, ParentThen, - WeightLimit::Limited, - WildMultiAsset::All, - Xcm, - }, - VersionedXcm, -}; -use xcm_emulator::TestExt; - -use cumulus_pallet_xcmp_queue::Event as XcmpEvent; -use dip_consumer_runtime_template::{ - Balances, BlockNumber, DidIdentifier, DidLookup, DipConsumer, Runtime as ConsumerRuntime, - RuntimeCall as ConsumerRuntimeCall, RuntimeEvent, System, -}; -use dip_provider_runtime_template::{ - ConsumerParachainTxBuilder, DipProvider, PolkadotXcm as ProviderXcmPallet, Runtime as ProviderRuntime, - UniversalLocation, -}; - -#[test] -fn commit_identity() { - Network::reset(); - - let did: DidIdentifier = para::provider::did_auth_key().public().into(); - let consumer_location: MultiLocation = ParentThen(X1(Parachain(para::consumer::PARA_ID))).into(); - let asset: MultiAsset = (Here, 1_000_000_000).into(); - let weight = Weight::from_ref_time(4_000); - let provider_parachain_on_consumer_parachain_balance_before = ConsumerParachain::execute_with(|| { - Balances::free_balance(para::consumer::provider_parachain_account_on_consumer()) - }); - let dispatcher_on_consumer_parachain_balance_before = ConsumerParachain::execute_with(|| { - Balances::free_balance(para::consumer::provider_dispatcher_account_on_consumer()) - }); - - // 1. Send identity commitment from DIP provider to DIP consumer. - ProviderParachain::execute_with(|| { - assert_ok!(DipProvider::commit_identity( - DidRawOrigin { - id: did.clone(), - submitter: para::provider::DISPATCHER_ACCOUNT - } - .into(), - did.clone(), - Box::new(consumer_location.into_versioned()), - Box::new(asset.into()), - weight, - )); - }); - // 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!( - r.event, - RuntimeEvent::XcmpQueue(XcmpEvent::Fail { - error: _, - message_hash: _, - weight: _ - }) - ))); - // 2.2 Verify the proof digest was stored correctly. - assert!(DipConsumer::identity_proofs(&did).is_some()); - // 2.3 Verify that the provider parachain sovereign account balance has not - // changed. - let provider_parachain_on_consumer_parachain_balance_after = - Balances::free_balance(para::consumer::provider_parachain_account_on_consumer()); - assert_eq!( - provider_parachain_on_consumer_parachain_balance_before, - provider_parachain_on_consumer_parachain_balance_after - ); - // 2.4 Verify that the dispatcher's account balance on the consumer parachain - // has decreased. - let dispatcher_on_consumer_parachain_balance_after = - Balances::free_balance(para::consumer::provider_dispatcher_account_on_consumer()); - assert!(dispatcher_on_consumer_parachain_balance_after < dispatcher_on_consumer_parachain_balance_before); - }); - // 3. Call an extrinsic on the consumer chain with a valid proof and signature - 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."); - let ownership_details = Owner::::get(&web3_name) - .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( - &( - Some(did_details.clone()), - Some(Web3OwnershipOf:: { - web3_name, - claimed_at: ownership_details.claimed_at, - }), - Some(linked_accounts.clone()), - ) - .into(), - [ - did_details.authentication_key, - did_details.attestation_key.unwrap(), - did_details.delegation_key.unwrap(), - ] - .iter(), - true, - linked_accounts.iter(), - ) - .expect("Proof generation should not fail"); - println!( - "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 = - ConsumerParachain::execute_with(|| frame_system::Pallet::::block_hash(BlockNumber::zero())); - let system_block = ConsumerParachain::execute_with(frame_system::Pallet::::block_number); - let payload = ( - call.clone(), - 0u128, - para::consumer::DISPATCHER_ACCOUNT, - system_block, - genesis_hash, - ); - let signature: DidSignature = para::provider::did_auth_key().sign(&payload.encode()).into(); - // 3.3 Call the `dispatch_as` extrinsic on the consumer chain with the generated - // proof - ConsumerParachain::execute_with(|| { - assert_ok!(DipConsumer::dispatch_as( - RawOrigin::Signed(para::consumer::DISPATCHER_ACCOUNT).into(), - did.clone(), - MerkleLeavesAndDidSignature { - merkle_leaves: MerkleProof { - blinded: proof.blinded, - revealed: proof.revealed, - }, - did_signature: TimeBoundDidSignature { - signature, - block_number: system_block - } - }, - Box::new(call), - )); - // Verify the account -> DID link exists and contains the right information - let linked_did = DidLookup::connected_dids::(para::consumer::DISPATCHER_ACCOUNT.into()) - .map(|link| link.did); - assert_eq!(linked_did, Some(did.clone())); - // Verify that the details of the DID subject have been bumped - let details = DipConsumer::identity_proofs(&did).map(|entry| entry.details); - assert_eq!(details, Some(1u128)); - }); -} - -#[test] -fn user_generated_commit_identity() { - Network::reset(); - - let did: DidIdentifier = para::provider::did_auth_key().public().into(); - let consumer_location: MultiLocation = ParentThen(X1(Parachain(para::consumer::PARA_ID))).into(); - let asset: MultiAsset = (Here, 1_000_000_000).into(); - let weight = Weight::from_ref_time(4_000); - let dest_tx = ConsumerParachainTxBuilder::build(consumer_location, IdentityDetailsAction::Deleted(did.clone())) - .expect("Provider Tx builder should not fail to create the encoded `Transact` call."); - let message = ProviderParachain::execute_with(|| { - Xcm::<()>(vec![ - ExpectOrigin(Some( - Here.into_location() - .reanchored(&consumer_location, UniversalLocation::get()) - .unwrap(), - )), - WithdrawAsset(asset.clone().into()), - BuyExecution { - fees: asset, - weight_limit: Limited(weight), - }, - Transact { - origin_kind: OriginKind::Native, - require_weight_at_most: weight, - call: dest_tx, - }, - RefundSurplus, - DepositAsset { - assets: Wild(All), - beneficiary: MultiLocation { - parents: 1, - interior: Here - .into_location() - .reanchored(&consumer_location, UniversalLocation::get()) - .unwrap() - .pushed_with_interior(AccountId32 { - network: None, - id: para::provider::DISPATCHER_ACCOUNT.into(), - }) - .unwrap() - .interior, - }, - }, - ]) - }); - // 1. Send identity commitment from DIP provider to DIP consumer via a - // user-dispatched XCM call using the XCM pallet (no parachain origin). - ProviderParachain::execute_with(|| { - assert_ok!(ProviderXcmPallet::send( - RawOrigin::Signed(para::provider::DISPATCHER_ACCOUNT).into(), - Box::new(consumer_location.into()), - Box::new(VersionedXcm::from(message)) - )); - }); - // 2. Verify that the commitment has NOT made it to the DIP consumer and must - // have failed, since this was a user-generated XCM message on the provider - // chain using the XCM pallet. - ConsumerParachain::execute_with(|| { - // 2.1 Verify that there was an XCM error. - println!("{:?}", System::events()); - assert!(System::events().iter().any(|r| matches!( - r.event, - RuntimeEvent::XcmpQueue(XcmpEvent::Fail { - error: _, - message_hash: _, - weight: _ - }) - ))); - // 2.2 Verify there is no storage entry in the consumer pallet. - assert!(DipConsumer::identity_proofs(&did).is_none()); - }); -} diff --git a/runtimes/common/src/dip/merkle.rs b/runtimes/common/src/dip/merkle.rs index 254380b65f..c90fc669f5 100644 --- a/runtimes/common/src/dip/merkle.rs +++ b/runtimes/common/src/dip/merkle.rs @@ -20,7 +20,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 pallet_dip_provider::traits::IdentityCommitmentGenerator; use parity_scale_codec::{Decode, Encode}; use scale_info::TypeInfo; use sp_std::{borrow::ToOwned, marker::PhantomData, vec::Vec}; @@ -251,7 +251,7 @@ where } } -impl IdentityProofGenerator> for DidMerkleRootGenerator +impl IdentityCommitmentGenerator> for DidMerkleRootGenerator where T: did::Config + pallet_did_lookup::Config + pallet_web3_names::Config, { From cfe1fb3d6c10d18c23aa33f80a2855825c41d2fd Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Wed, 12 Jul 2023 14:31:54 +0200 Subject: [PATCH 06/32] Add parachain root state proof verifier --- Cargo.lock | 5 ++ Cargo.toml | 1 + crates/kilt-dip-support/Cargo.toml | 16 +++- crates/kilt-dip-support/src/lib.rs | 1 + crates/kilt-dip-support/src/new_stuff.rs | 108 +++++++++++++++++++++++ 5 files changed, 129 insertions(+), 2 deletions(-) create mode 100644 crates/kilt-dip-support/src/new_stuff.rs diff --git a/Cargo.lock b/Cargo.lock index 00fac4c58b..956613fa5d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4189,16 +4189,21 @@ dependencies = [ name = "kilt-dip-support" version = "1.11.0-dev" dependencies = [ + "cumulus-pallet-parachain-system", "did", "dip-support", "frame-support", "frame-system", + "hex-literal", "pallet-dip-consumer", "pallet-dip-provider", "parity-scale-codec", + "polkadot-primitives", "scale-info", "sp-core", + "sp-io", "sp-runtime", + "sp-state-machine", "sp-std", "sp-trie", "xcm", diff --git a/Cargo.toml b/Cargo.toml index 4be4c260c6..4be6a35c65 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -136,6 +136,7 @@ sp-offchain = {git = "https://github.com/paritytech/substrate", default-features sp-runtime = {git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.39"} sp-session = {git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.39"} sp-staking = {git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.39"} +sp-state-machine = {git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.39"} sp-std = {git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.39"} sp-transaction-pool = {git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.39"} sp-trie = {git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.39"} diff --git a/crates/kilt-dip-support/Cargo.toml b/crates/kilt-dip-support/Cargo.toml index b417b44cba..bff0cce096 100644 --- a/crates/kilt-dip-support/Cargo.toml +++ b/crates/kilt-dip-support/Cargo.toml @@ -26,13 +26,22 @@ frame-system.workspace = true frame-support.workspace = true sp-runtime.workspace = true sp-core.workspace = true -sp-trie.workspace = true +sp-state-machine.workspace = true sp-std.workspace = true +sp-trie.workspace = true # Polkadot dependencies +polkadot-primitives.workspace = true xcm.workspace = true xcm-executor.workspace = true +# Cumulus dependencies +cumulus-pallet-parachain-system.workspace = true + +[dev-dependencies] +hex-literal.workspace = true +sp-io.workspace = true + [features] default = ["std"] std = [ @@ -46,9 +55,12 @@ std = [ "frame-support/std", "sp-runtime/std", "sp-core/std", + "sp-state-machine/std", "sp-trie/std", + "polkadot-primitives/std", "sp-std/std", "xcm-executor/std", - "xcm/std" + "xcm/std", + "cumulus-pallet-parachain-system/std", ] runtime-benchmarks = [] diff --git a/crates/kilt-dip-support/src/lib.rs b/crates/kilt-dip-support/src/lib.rs index 702c4f62d8..6aded4d82c 100644 --- a/crates/kilt-dip-support/src/lib.rs +++ b/crates/kilt-dip-support/src/lib.rs @@ -27,6 +27,7 @@ use crate::did::MerkleLeavesAndDidSignature; pub mod did; pub mod merkle; +pub mod new_stuff; pub mod traits; /// A type that chains a Merkle proof verification with a DID signature diff --git a/crates/kilt-dip-support/src/new_stuff.rs b/crates/kilt-dip-support/src/new_stuff.rs new file mode 100644 index 0000000000..3cb6484ba6 --- /dev/null +++ b/crates/kilt-dip-support/src/new_stuff.rs @@ -0,0 +1,108 @@ +use parity_scale_codec::{Decode, HasCompact}; +use sp_core::{Get, U256}; +use sp_runtime::{generic::Header, traits::Hash}; +use sp_state_machine::read_proof_check; +use sp_std::marker::PhantomData; +use sp_trie::StorageProof; + +pub trait RelayChainInfoProvider { + type Key; + type ParaId; + + fn storage_key(para_id: Self::ParaId) -> Self::Key; + fn state_root() -> Hash; +} + +pub struct ParachainHeadProofVerifier( + PhantomData<(RelayHasher, RelayBlockNumber, ParaId, RelayInfoProvider)>, +); + +impl + ParachainHeadProofVerifier +where + RelayHasher: Hash + 'static, + RelayHasher::Output: Ord, + RelayBlockNumber: Copy + Into + TryFrom + HasCompact, + ParaId: Get, + RelayInfoProvider: RelayChainInfoProvider, + RelayInfoProvider::ParaId: From, + RelayInfoProvider::Key: AsRef<[u8]>, +{ + pub fn verify_proof(proof: impl IntoIterator>) -> Result, ()> { + let relay_state_root = RelayInfoProvider::state_root(); + let parachain_storage_key: ::Output>>::Key = + RelayInfoProvider::storage_key(ParaId::get().into()); + let storage_proof = StorageProof::new(proof); + let revealed_leaves = + read_proof_check::(relay_state_root, storage_proof, [¶chain_storage_key].iter()) + .map_err(|_| ())?; + // TODO: Remove at some point + debug_assert!(revealed_leaves.len() == 1); + debug_assert!(revealed_leaves.contains_key(parachain_storage_key.as_ref())); + let Some(Some(encoded_head)) = revealed_leaves.get(parachain_storage_key.as_ref()) else { return Err(()) }; + // TODO: Figure out why RPC call returns 2 bytes in front which we don't need + let mut unwrapped_head = &encoded_head[2..]; + Header::::decode(&mut unwrapped_head).map_err(|_| ()) + } +} + +#[cfg(test)] +mod parachain_head_proof_verifier_tests { + use super::*; + + use hex_literal::hex; + use parity_scale_codec::Encode; + use polkadot_primitives::BlakeTwo256; + use sp_core::{storage::StorageKey, ConstU32, H256}; + + // Polkadot block n: 16_363_919, + // hash 0x18e90e9aa8e3b063f60386ba1b0415111798e72d01de58b1438d620d42f58e39 + struct StaticPolkadotBlockProvider; + + impl RelayChainInfoProvider for StaticPolkadotBlockProvider { + type Key = StorageKey; + type ParaId = u32; + + fn state_root() -> H256 { + hex!("81b75d95075d16005ee0a987a3f061d3011ada919b261e9b02961b9b3725f3fd").into() + } + + fn storage_key(para_id: Self::ParaId) -> Self::Key { + // Adapted from https://github.com/polytope-labs/substrate-ismp/blob/7fb09da6c7b818a98c25c962fee0ddde8e737306/parachain/src/consensus.rs#L369 + // Used for testing. In production this would be generated from the relay + // runtime definition of the `paras` storage map. + let encoded_para_id = para_id.encode(); + let storage_key = [ + frame_support::storage::storage_prefix(b"Paras", b"Heads").as_slice(), + sp_io::hashing::twox_64(&encoded_para_id).as_slice(), + encoded_para_id.as_slice(), + ] + .concat(); + StorageKey(storage_key) + } + } + + #[test] + fn test_spiritnet_head_proof() { + // As of RPC state_getReadProof("0xcd710b30bd2eab0352ddcc26417aa1941b3c252fcb29d88eff4f3de5de4476c32c0cfd6c23b92a7826080000", "0x18e90e9aa8e3b063f60386ba1b0415111798e72d01de58b1438d620d42f58e39") + let spiritnet_head_proof_at_block = [ + hex!("570c0cfd6c23b92a7826080000f102e90265541097fb02782e14f43074f0b00e44ae8e9fe426982323ef1d329739740d37f252ff006d1156941db1bccd58ce3a1cac4f40cad91f692d94e98f501dd70081a129b69a3e2ef7e1ff84ba3d86dab4e95f2c87f6b1055ebd48519c185360eae58f05d1ea08066175726120dcdc6308000000000561757261010170ccfaf3756d1a8dd8ae5c89094199d6d32e5dd9f0920f6fe30f986815b5e701974ea0e0e0a901401f2c72e3dd8dbdf4aa55d59bf3e7021856cdb8038419eb8c").to_vec(), + hex!("80046480186b1513c5112466ada33da3c65558979906ca9fb82510b62f6ea01f550a4807808bc90ded5636f31c8395a315b5f27a1a25a2ceebd36921a518669ce7e52f80e680993c5e952e6e4f72f295ba04951ace9029b23e9a87887b41895c16f77bec42ee80b798b224c5ee3d668519e75ca98504116f645fb969a5e2653a298b0181f9a694").to_vec(), + hex!("80ffff806ecd86e87715a007ee9b216d8a99a604773014260d51f6552b6fbd7c21786d9c80e23ef51809d6c80c01a6e264ff0d298cce01c1addfdbb0789597b9a6b3f3e4fd80c9c5f0f29d777e2cebcdbd06ddf1c2cfa8ee83524b37ace99d8b7a3aeff039b380da013185503cfefa6c9cc88751993f1f2bf4b8fa4918e876f499fb9405e3206c803a89668f636552a0fb93619913dcc46cf3e087363d532b76a345155a44a46b5180c2e7fc654720b7dcc0316ae1591fde4beb8b853a343b7e5e3ee564d2692c2ee280840f9c4ae7c16ae948828bf50faf062264402e6134d2d6144a5e3ecb0a1e1d9c80f93c2be1ef51fb2032445cc7fbc2023b9e3b8cf8c0d832b464ae48a020bfaa8c8010c63537c9bf58d50c8c0e13c154fd88b2f683e13701901bdc64565aa9b756d580f0b60eaf17fb680827e8a8938c717ac943b85ff373c0fc911e06c34a3a30327280ccb29f1efa59fd7c80a730cb88789a5a256b01fee7e83ac9a3c90da330adc7a480c8e57c547edb33d4b712f017f09d2de2e055f18815669c83eef2f7f3e5dcafae80b7b7e7ffc91a7dd4c4902f7f15cd7598d1258a75433ea953565661d114e2dcca80ebc3a2df819c7c2fd1a33eb1d484beaf7b71114d6a6db240d8b07dc10bfdc49b80a71f21aa3fa5d7475bf134d50f25e2515c797d0a4c2e93998888150c1f969ab8801e32613f54e70c95e9b16a14f5797522ef5e2ef7867868ff663e33e8880994ed").to_vec(), + hex!("9e710b30bd2eab0352ddcc26417aa1945fd380d49ebc7ca5c1b751c2badb5e5a326d3ba9e331d8b7c6cf279ed7fd71a8882b6c8038088652f73dc8a22336d10f492f0ef8836beaba0ccfeb0f8fabdc9df1d17e2d807f88402cbbed7fa3307e07044200b572d5e8e12913b41e1923dcb2c0799bc2be804d57e9a8e4934fab698a9db50682052ee9459c666a075d1bfc471da8e5da14da80b9aee043e378f8313e68a6030679ccf3880fa1e7ab19b6244b5c262b7a152f004c5f03c716fb8fff3de61a883bb76adb34a2040080f282bc12648ffb197ffc257edc7ff3a3fdda452daa51091ccbd2dfb91d8aa9518008a0c609ab4888f02c2545c002153297c2641c5a7b4f3d8e25c634e721f80bea80b6617c764df278313c426c46961ccde8ee7a03f9007b74bc8bc6c49d1583cf7d8077b493d45eb153353026cc330307e0753ac41a5cb8e843ceb1efdc46655f33a0808bdaa43fc5dc0e928e2da0ce8ed02096b0b74c61feaba2546980ed9c6174f71d").to_vec(), + hex!("9f0b3c252fcb29d88eff4f3de5de4476c3ffbf8013c601cc93de3437f9d415bd52c48d794b341f218b9d0020a4b646746c24d0ca80348b8e2c39c479a146933297f62b7051df82e92e1bca761432c3e6f64c74033f80220131e7cd7a08b97f8aa06225f7aefbbca8118fb436c07689c552ed3f577145806d974dd9e4db5e407e29f84c4121ccc58f9c6adc3933afc1bcaef52defe77de5801e9e1a21db053de56365fdee57998488ddae7d664c0430da90469dde17936c1f80c5c11751bbfc99a1ad805c58a65b9704e0bad58e694023e9cc57ce6ef84cdb0b8038f6c242700eaea04ffad5c25ca9a9b1cc2af7303655a32eb59e84b6bb927cd3802575469e76e104b0db8b18dbc762b997a78aa666432a44c4b955ced044a4691f80a81408b856272feeec08845af515e27d033efd3ff8b46de6bc706c38e600086a809ee78332c2a38a3918070942421e651e0b9a43e4b8b2c92e87a2552cede73e8380c9d79f411f742cad0c6f2b070aa08703a04cb7db840c3821a6762837dd8d00e9807dcfbc7f2fcc9415e2cb40eef7f718758d76193f325b3f8b7180e3e5e7d6b81e8036252cae6d24a531a151ce1ee223a07bf71cf82a7fdf49090e4ca345d27d68ca80e3f08ef11671f8f1defa66fa2af71e1a871430e9352df9b3f1d427b5a5dabfb280b51d28c9b99030d050fc1578cd23b5506e769b86c8f4ccc6aded4b8d7c1a73b7").to_vec(), + ].to_vec(); + // As of query paras::heads(2_086) at block + // "0x18e90e9aa8e3b063f60386ba1b0415111798e72d01de58b1438d620d42f58e39" + // which results in the key + // "0xcd710b30bd2eab0352ddcc26417aa1941b3c252fcb29d88eff4f3de5de4476c32c0cfd6c23b92a7826080000" + // + let expected_spiritnet_head_at_block = hex!("65541097fb02782e14f43074f0b00e44ae8e9fe426982323ef1d329739740d37f252ff006d1156941db1bccd58ce3a1cac4f40cad91f692d94e98f501dd70081a129b69a3e2ef7e1ff84ba3d86dab4e95f2c87f6b1055ebd48519c185360eae58f05d1ea08066175726120dcdc6308000000000561757261010170ccfaf3756d1a8dd8ae5c89094199d6d32e5dd9f0920f6fe30f986815b5e701974ea0e0e0a901401f2c72e3dd8dbdf4aa55d59bf3e7021856cdb8038419eb8c").to_vec(); + let returned_head = + ParachainHeadProofVerifier::, StaticPolkadotBlockProvider>::verify_proof( + spiritnet_head_proof_at_block, + ) + .expect("Parachain head proof verification should not fail."); + assert!(returned_head.encode() == expected_spiritnet_head_at_block, "Parachain head returned from the state proof verification should not be different than the pre-computed one."); + } +} From 77b2a4805de2c4f9bfe5fd3020c62ff3e37e2df4 Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Wed, 12 Jul 2023 15:38:17 +0200 Subject: [PATCH 07/32] Proof of storage entry for parachain also working --- crates/kilt-dip-support/src/new_stuff.rs | 288 ++++++++++++++++------- 1 file changed, 200 insertions(+), 88 deletions(-) diff --git a/crates/kilt-dip-support/src/new_stuff.rs b/crates/kilt-dip-support/src/new_stuff.rs index 3cb6484ba6..29dc86c047 100644 --- a/crates/kilt-dip-support/src/new_stuff.rs +++ b/crates/kilt-dip-support/src/new_stuff.rs @@ -1,108 +1,220 @@ -use parity_scale_codec::{Decode, HasCompact}; -use sp_core::{Get, U256}; -use sp_runtime::{generic::Header, traits::Hash}; +use parity_scale_codec::Decode; +use sp_runtime::traits::Hash; use sp_state_machine::read_proof_check; use sp_std::marker::PhantomData; use sp_trie::StorageProof; -pub trait RelayChainInfoProvider { - type Key; - type ParaId; +pub mod relay_chain { + use super::*; - fn storage_key(para_id: Self::ParaId) -> Self::Key; - fn state_root() -> Hash; -} + pub trait RelayChainStateInfoProvider { + type Key; + type Hasher: Hash; + type Header; + type ParaId; -pub struct ParachainHeadProofVerifier( - PhantomData<(RelayHasher, RelayBlockNumber, ParaId, RelayInfoProvider)>, -); - -impl - ParachainHeadProofVerifier -where - RelayHasher: Hash + 'static, - RelayHasher::Output: Ord, - RelayBlockNumber: Copy + Into + TryFrom + HasCompact, - ParaId: Get, - RelayInfoProvider: RelayChainInfoProvider, - RelayInfoProvider::ParaId: From, - RelayInfoProvider::Key: AsRef<[u8]>, -{ - pub fn verify_proof(proof: impl IntoIterator>) -> Result, ()> { - let relay_state_root = RelayInfoProvider::state_root(); - let parachain_storage_key: ::Output>>::Key = - RelayInfoProvider::storage_key(ParaId::get().into()); - let storage_proof = StorageProof::new(proof); - let revealed_leaves = - read_proof_check::(relay_state_root, storage_proof, [¶chain_storage_key].iter()) - .map_err(|_| ())?; - // TODO: Remove at some point - debug_assert!(revealed_leaves.len() == 1); - debug_assert!(revealed_leaves.contains_key(parachain_storage_key.as_ref())); - let Some(Some(encoded_head)) = revealed_leaves.get(parachain_storage_key.as_ref()) else { return Err(()) }; - // TODO: Figure out why RPC call returns 2 bytes in front which we don't need - let mut unwrapped_head = &encoded_head[2..]; - Header::::decode(&mut unwrapped_head).map_err(|_| ()) + fn parachain_head_storage_key(para_id: Self::ParaId) -> Self::Key; + fn state_root() -> ::Output; } -} -#[cfg(test)] -mod parachain_head_proof_verifier_tests { - use super::*; + pub struct ParachainHeadProofVerifier(PhantomData); - use hex_literal::hex; - use parity_scale_codec::Encode; - use polkadot_primitives::BlakeTwo256; - use sp_core::{storage::StorageKey, ConstU32, H256}; + impl ParachainHeadProofVerifier + where + RelayInfoProvider: RelayChainStateInfoProvider, + RelayInfoProvider::Hasher: 'static, + ::Output: Ord, + RelayInfoProvider::Header: Decode, + RelayInfoProvider::Key: AsRef<[u8]>, + { + pub fn verify_proof_for_parachain( + para_id: RelayInfoProvider::ParaId, + proof: impl IntoIterator>, + ) -> Result { + let relay_state_root = RelayInfoProvider::state_root(); + let parachain_storage_key = RelayInfoProvider::parachain_head_storage_key(para_id); + let storage_proof = StorageProof::new(proof); + let revealed_leaves = read_proof_check::( + relay_state_root, + storage_proof, + [¶chain_storage_key].iter(), + ) + .map_err(|_| ())?; + // TODO: Remove at some point + debug_assert!(revealed_leaves.len() == 1); + debug_assert!(revealed_leaves.contains_key(parachain_storage_key.as_ref())); + let Some(Some(encoded_head)) = revealed_leaves.get(parachain_storage_key.as_ref()) else { return Err(()) }; + // TODO: Figure out why RPC call returns 2 bytes in front which we don't need + let mut unwrapped_head = &encoded_head[2..]; + RelayInfoProvider::Header::decode(&mut unwrapped_head).map_err(|_| ()) + } + } - // Polkadot block n: 16_363_919, - // hash 0x18e90e9aa8e3b063f60386ba1b0415111798e72d01de58b1438d620d42f58e39 - struct StaticPolkadotBlockProvider; + #[cfg(test)] + mod polkadot_parachain_head_proof_verifier_tests { + use super::*; - impl RelayChainInfoProvider for StaticPolkadotBlockProvider { - type Key = StorageKey; - type ParaId = u32; + use hex_literal::hex; + use parity_scale_codec::Encode; + use polkadot_primitives::BlakeTwo256; + use sp_core::{storage::StorageKey, H256}; + use sp_runtime::generic::Header; - fn state_root() -> H256 { - hex!("81b75d95075d16005ee0a987a3f061d3011ada919b261e9b02961b9b3725f3fd").into() - } + // Polkadot block n: 16_363_919, + // hash 0x18e90e9aa8e3b063f60386ba1b0415111798e72d01de58b1438d620d42f58e39 + struct StaticPolkadotInfoProvider; + + impl RelayChainStateInfoProvider for StaticPolkadotInfoProvider { + type Hasher = BlakeTwo256; + type Header = Header; + type Key = StorageKey; + type ParaId = u32; - fn storage_key(para_id: Self::ParaId) -> Self::Key { - // Adapted from https://github.com/polytope-labs/substrate-ismp/blob/7fb09da6c7b818a98c25c962fee0ddde8e737306/parachain/src/consensus.rs#L369 - // Used for testing. In production this would be generated from the relay - // runtime definition of the `paras` storage map. - let encoded_para_id = para_id.encode(); - let storage_key = [ - frame_support::storage::storage_prefix(b"Paras", b"Heads").as_slice(), - sp_io::hashing::twox_64(&encoded_para_id).as_slice(), - encoded_para_id.as_slice(), - ] - .concat(); - StorageKey(storage_key) + fn parachain_head_storage_key(para_id: Self::ParaId) -> Self::Key { + // Adapted from https://github.com/polytope-labs/substrate-ismp/blob/7fb09da6c7b818a98c25c962fee0ddde8e737306/parachain/src/consensus.rs#L369 + // Used for testing. In production this would be generated from the relay + // runtime definition of the `paras` storage map. + let encoded_para_id = para_id.encode(); + let storage_key = [ + frame_support::storage::storage_prefix(b"Paras", b"Heads").as_slice(), + sp_io::hashing::twox_64(&encoded_para_id).as_slice(), + encoded_para_id.as_slice(), + ] + .concat(); + StorageKey(storage_key) + } + + fn state_root() -> H256 { + hex!("81b75d95075d16005ee0a987a3f061d3011ada919b261e9b02961b9b3725f3fd").into() + } } - } - #[test] - fn test_spiritnet_head_proof() { - // As of RPC state_getReadProof("0xcd710b30bd2eab0352ddcc26417aa1941b3c252fcb29d88eff4f3de5de4476c32c0cfd6c23b92a7826080000", "0x18e90e9aa8e3b063f60386ba1b0415111798e72d01de58b1438d620d42f58e39") - let spiritnet_head_proof_at_block = [ - hex!("570c0cfd6c23b92a7826080000f102e90265541097fb02782e14f43074f0b00e44ae8e9fe426982323ef1d329739740d37f252ff006d1156941db1bccd58ce3a1cac4f40cad91f692d94e98f501dd70081a129b69a3e2ef7e1ff84ba3d86dab4e95f2c87f6b1055ebd48519c185360eae58f05d1ea08066175726120dcdc6308000000000561757261010170ccfaf3756d1a8dd8ae5c89094199d6d32e5dd9f0920f6fe30f986815b5e701974ea0e0e0a901401f2c72e3dd8dbdf4aa55d59bf3e7021856cdb8038419eb8c").to_vec(), - hex!("80046480186b1513c5112466ada33da3c65558979906ca9fb82510b62f6ea01f550a4807808bc90ded5636f31c8395a315b5f27a1a25a2ceebd36921a518669ce7e52f80e680993c5e952e6e4f72f295ba04951ace9029b23e9a87887b41895c16f77bec42ee80b798b224c5ee3d668519e75ca98504116f645fb969a5e2653a298b0181f9a694").to_vec(), - hex!("80ffff806ecd86e87715a007ee9b216d8a99a604773014260d51f6552b6fbd7c21786d9c80e23ef51809d6c80c01a6e264ff0d298cce01c1addfdbb0789597b9a6b3f3e4fd80c9c5f0f29d777e2cebcdbd06ddf1c2cfa8ee83524b37ace99d8b7a3aeff039b380da013185503cfefa6c9cc88751993f1f2bf4b8fa4918e876f499fb9405e3206c803a89668f636552a0fb93619913dcc46cf3e087363d532b76a345155a44a46b5180c2e7fc654720b7dcc0316ae1591fde4beb8b853a343b7e5e3ee564d2692c2ee280840f9c4ae7c16ae948828bf50faf062264402e6134d2d6144a5e3ecb0a1e1d9c80f93c2be1ef51fb2032445cc7fbc2023b9e3b8cf8c0d832b464ae48a020bfaa8c8010c63537c9bf58d50c8c0e13c154fd88b2f683e13701901bdc64565aa9b756d580f0b60eaf17fb680827e8a8938c717ac943b85ff373c0fc911e06c34a3a30327280ccb29f1efa59fd7c80a730cb88789a5a256b01fee7e83ac9a3c90da330adc7a480c8e57c547edb33d4b712f017f09d2de2e055f18815669c83eef2f7f3e5dcafae80b7b7e7ffc91a7dd4c4902f7f15cd7598d1258a75433ea953565661d114e2dcca80ebc3a2df819c7c2fd1a33eb1d484beaf7b71114d6a6db240d8b07dc10bfdc49b80a71f21aa3fa5d7475bf134d50f25e2515c797d0a4c2e93998888150c1f969ab8801e32613f54e70c95e9b16a14f5797522ef5e2ef7867868ff663e33e8880994ed").to_vec(), - hex!("9e710b30bd2eab0352ddcc26417aa1945fd380d49ebc7ca5c1b751c2badb5e5a326d3ba9e331d8b7c6cf279ed7fd71a8882b6c8038088652f73dc8a22336d10f492f0ef8836beaba0ccfeb0f8fabdc9df1d17e2d807f88402cbbed7fa3307e07044200b572d5e8e12913b41e1923dcb2c0799bc2be804d57e9a8e4934fab698a9db50682052ee9459c666a075d1bfc471da8e5da14da80b9aee043e378f8313e68a6030679ccf3880fa1e7ab19b6244b5c262b7a152f004c5f03c716fb8fff3de61a883bb76adb34a2040080f282bc12648ffb197ffc257edc7ff3a3fdda452daa51091ccbd2dfb91d8aa9518008a0c609ab4888f02c2545c002153297c2641c5a7b4f3d8e25c634e721f80bea80b6617c764df278313c426c46961ccde8ee7a03f9007b74bc8bc6c49d1583cf7d8077b493d45eb153353026cc330307e0753ac41a5cb8e843ceb1efdc46655f33a0808bdaa43fc5dc0e928e2da0ce8ed02096b0b74c61feaba2546980ed9c6174f71d").to_vec(), - hex!("9f0b3c252fcb29d88eff4f3de5de4476c3ffbf8013c601cc93de3437f9d415bd52c48d794b341f218b9d0020a4b646746c24d0ca80348b8e2c39c479a146933297f62b7051df82e92e1bca761432c3e6f64c74033f80220131e7cd7a08b97f8aa06225f7aefbbca8118fb436c07689c552ed3f577145806d974dd9e4db5e407e29f84c4121ccc58f9c6adc3933afc1bcaef52defe77de5801e9e1a21db053de56365fdee57998488ddae7d664c0430da90469dde17936c1f80c5c11751bbfc99a1ad805c58a65b9704e0bad58e694023e9cc57ce6ef84cdb0b8038f6c242700eaea04ffad5c25ca9a9b1cc2af7303655a32eb59e84b6bb927cd3802575469e76e104b0db8b18dbc762b997a78aa666432a44c4b955ced044a4691f80a81408b856272feeec08845af515e27d033efd3ff8b46de6bc706c38e600086a809ee78332c2a38a3918070942421e651e0b9a43e4b8b2c92e87a2552cede73e8380c9d79f411f742cad0c6f2b070aa08703a04cb7db840c3821a6762837dd8d00e9807dcfbc7f2fcc9415e2cb40eef7f718758d76193f325b3f8b7180e3e5e7d6b81e8036252cae6d24a531a151ce1ee223a07bf71cf82a7fdf49090e4ca345d27d68ca80e3f08ef11671f8f1defa66fa2af71e1a871430e9352df9b3f1d427b5a5dabfb280b51d28c9b99030d050fc1578cd23b5506e769b86c8f4ccc6aded4b8d7c1a73b7").to_vec(), - ].to_vec(); - // As of query paras::heads(2_086) at block - // "0x18e90e9aa8e3b063f60386ba1b0415111798e72d01de58b1438d620d42f58e39" - // which results in the key - // "0xcd710b30bd2eab0352ddcc26417aa1941b3c252fcb29d88eff4f3de5de4476c32c0cfd6c23b92a7826080000" - // - let expected_spiritnet_head_at_block = hex!("65541097fb02782e14f43074f0b00e44ae8e9fe426982323ef1d329739740d37f252ff006d1156941db1bccd58ce3a1cac4f40cad91f692d94e98f501dd70081a129b69a3e2ef7e1ff84ba3d86dab4e95f2c87f6b1055ebd48519c185360eae58f05d1ea08066175726120dcdc6308000000000561757261010170ccfaf3756d1a8dd8ae5c89094199d6d32e5dd9f0920f6fe30f986815b5e701974ea0e0e0a901401f2c72e3dd8dbdf4aa55d59bf3e7021856cdb8038419eb8c").to_vec(); - let returned_head = - ParachainHeadProofVerifier::, StaticPolkadotBlockProvider>::verify_proof( + #[test] + fn test_spiritnet_head_proof() { + // As of RPC state_getReadProof("0xcd710b30bd2eab0352ddcc26417aa1941b3c252fcb29d88eff4f3de5de4476c32c0cfd6c23b92a7826080000", "0x18e90e9aa8e3b063f60386ba1b0415111798e72d01de58b1438d620d42f58e39") + let spiritnet_head_proof_at_block = [ + hex!("570c0cfd6c23b92a7826080000f102e90265541097fb02782e14f43074f0b00e44ae8e9fe426982323ef1d329739740d37f252ff006d1156941db1bccd58ce3a1cac4f40cad91f692d94e98f501dd70081a129b69a3e2ef7e1ff84ba3d86dab4e95f2c87f6b1055ebd48519c185360eae58f05d1ea08066175726120dcdc6308000000000561757261010170ccfaf3756d1a8dd8ae5c89094199d6d32e5dd9f0920f6fe30f986815b5e701974ea0e0e0a901401f2c72e3dd8dbdf4aa55d59bf3e7021856cdb8038419eb8c").to_vec(), + hex!("80046480186b1513c5112466ada33da3c65558979906ca9fb82510b62f6ea01f550a4807808bc90ded5636f31c8395a315b5f27a1a25a2ceebd36921a518669ce7e52f80e680993c5e952e6e4f72f295ba04951ace9029b23e9a87887b41895c16f77bec42ee80b798b224c5ee3d668519e75ca98504116f645fb969a5e2653a298b0181f9a694").to_vec(), + hex!("80ffff806ecd86e87715a007ee9b216d8a99a604773014260d51f6552b6fbd7c21786d9c80e23ef51809d6c80c01a6e264ff0d298cce01c1addfdbb0789597b9a6b3f3e4fd80c9c5f0f29d777e2cebcdbd06ddf1c2cfa8ee83524b37ace99d8b7a3aeff039b380da013185503cfefa6c9cc88751993f1f2bf4b8fa4918e876f499fb9405e3206c803a89668f636552a0fb93619913dcc46cf3e087363d532b76a345155a44a46b5180c2e7fc654720b7dcc0316ae1591fde4beb8b853a343b7e5e3ee564d2692c2ee280840f9c4ae7c16ae948828bf50faf062264402e6134d2d6144a5e3ecb0a1e1d9c80f93c2be1ef51fb2032445cc7fbc2023b9e3b8cf8c0d832b464ae48a020bfaa8c8010c63537c9bf58d50c8c0e13c154fd88b2f683e13701901bdc64565aa9b756d580f0b60eaf17fb680827e8a8938c717ac943b85ff373c0fc911e06c34a3a30327280ccb29f1efa59fd7c80a730cb88789a5a256b01fee7e83ac9a3c90da330adc7a480c8e57c547edb33d4b712f017f09d2de2e055f18815669c83eef2f7f3e5dcafae80b7b7e7ffc91a7dd4c4902f7f15cd7598d1258a75433ea953565661d114e2dcca80ebc3a2df819c7c2fd1a33eb1d484beaf7b71114d6a6db240d8b07dc10bfdc49b80a71f21aa3fa5d7475bf134d50f25e2515c797d0a4c2e93998888150c1f969ab8801e32613f54e70c95e9b16a14f5797522ef5e2ef7867868ff663e33e8880994ed").to_vec(), + hex!("9e710b30bd2eab0352ddcc26417aa1945fd380d49ebc7ca5c1b751c2badb5e5a326d3ba9e331d8b7c6cf279ed7fd71a8882b6c8038088652f73dc8a22336d10f492f0ef8836beaba0ccfeb0f8fabdc9df1d17e2d807f88402cbbed7fa3307e07044200b572d5e8e12913b41e1923dcb2c0799bc2be804d57e9a8e4934fab698a9db50682052ee9459c666a075d1bfc471da8e5da14da80b9aee043e378f8313e68a6030679ccf3880fa1e7ab19b6244b5c262b7a152f004c5f03c716fb8fff3de61a883bb76adb34a2040080f282bc12648ffb197ffc257edc7ff3a3fdda452daa51091ccbd2dfb91d8aa9518008a0c609ab4888f02c2545c002153297c2641c5a7b4f3d8e25c634e721f80bea80b6617c764df278313c426c46961ccde8ee7a03f9007b74bc8bc6c49d1583cf7d8077b493d45eb153353026cc330307e0753ac41a5cb8e843ceb1efdc46655f33a0808bdaa43fc5dc0e928e2da0ce8ed02096b0b74c61feaba2546980ed9c6174f71d").to_vec(), + hex!("9f0b3c252fcb29d88eff4f3de5de4476c3ffbf8013c601cc93de3437f9d415bd52c48d794b341f218b9d0020a4b646746c24d0ca80348b8e2c39c479a146933297f62b7051df82e92e1bca761432c3e6f64c74033f80220131e7cd7a08b97f8aa06225f7aefbbca8118fb436c07689c552ed3f577145806d974dd9e4db5e407e29f84c4121ccc58f9c6adc3933afc1bcaef52defe77de5801e9e1a21db053de56365fdee57998488ddae7d664c0430da90469dde17936c1f80c5c11751bbfc99a1ad805c58a65b9704e0bad58e694023e9cc57ce6ef84cdb0b8038f6c242700eaea04ffad5c25ca9a9b1cc2af7303655a32eb59e84b6bb927cd3802575469e76e104b0db8b18dbc762b997a78aa666432a44c4b955ced044a4691f80a81408b856272feeec08845af515e27d033efd3ff8b46de6bc706c38e600086a809ee78332c2a38a3918070942421e651e0b9a43e4b8b2c92e87a2552cede73e8380c9d79f411f742cad0c6f2b070aa08703a04cb7db840c3821a6762837dd8d00e9807dcfbc7f2fcc9415e2cb40eef7f718758d76193f325b3f8b7180e3e5e7d6b81e8036252cae6d24a531a151ce1ee223a07bf71cf82a7fdf49090e4ca345d27d68ca80e3f08ef11671f8f1defa66fa2af71e1a871430e9352df9b3f1d427b5a5dabfb280b51d28c9b99030d050fc1578cd23b5506e769b86c8f4ccc6aded4b8d7c1a73b7").to_vec(), + ].to_vec(); + // As of query paras::heads(2_086) at block + // "0x18e90e9aa8e3b063f60386ba1b0415111798e72d01de58b1438d620d42f58e39" which + // results in the key + // "0xcd710b30bd2eab0352ddcc26417aa1941b3c252fcb29d88eff4f3de5de4476c32c0cfd6c23b92a7826080000" + // + let expected_spiritnet_head_at_block = hex!("65541097fb02782e14f43074f0b00e44ae8e9fe426982323ef1d329739740d37f252ff006d1156941db1bccd58ce3a1cac4f40cad91f692d94e98f501dd70081a129b69a3e2ef7e1ff84ba3d86dab4e95f2c87f6b1055ebd48519c185360eae58f05d1ea08066175726120dcdc6308000000000561757261010170ccfaf3756d1a8dd8ae5c89094199d6d32e5dd9f0920f6fe30f986815b5e701974ea0e0e0a901401f2c72e3dd8dbdf4aa55d59bf3e7021856cdb8038419eb8c").to_vec(); + let returned_head = ParachainHeadProofVerifier::::verify_proof_for_parachain( + 2_086, spiritnet_head_proof_at_block, ) .expect("Parachain head proof verification should not fail."); - assert!(returned_head.encode() == expected_spiritnet_head_at_block, "Parachain head returned from the state proof verification should not be different than the pre-computed one."); + assert!(returned_head.encode() == expected_spiritnet_head_at_block, "Parachain head returned from the state proof verification should not be different than the pre-computed one."); + } + } +} + +pub mod parachain { + use super::*; + + pub trait ParachainStateInfoProvider { + type Commitment; + type Key; + type Hasher: Hash; + type Identifier; + + fn dip_subject_storage_key(identifier: Self::Identifier) -> Self::Key; + fn state_root() -> ::Output; + } + + pub struct DipCommitmentValueProofVerifier(PhantomData); + + impl DipCommitmentValueProofVerifier + where + ParaInfoProvider: ParachainStateInfoProvider, + ParaInfoProvider::Hasher: 'static, + ::Output: Ord, + ParaInfoProvider::Commitment: Decode, + ParaInfoProvider::Key: AsRef<[u8]>, + { + pub fn verify_proof_for_identifier( + identifier: ParaInfoProvider::Identifier, + proof: impl IntoIterator>, + ) -> Result { + let parachain_state_root = ParaInfoProvider::state_root(); + let dip_commitment_storage_key = ParaInfoProvider::dip_subject_storage_key(identifier); + let storage_proof = StorageProof::new(proof); + let revealed_leaves = read_proof_check::( + parachain_state_root, + storage_proof, + [&dip_commitment_storage_key].iter(), + ) + .map_err(|_| ())?; + // TODO: Remove at some point + debug_assert!(revealed_leaves.len() == 1); + debug_assert!(revealed_leaves.contains_key(dip_commitment_storage_key.as_ref())); + let Some(Some(encoded_commitment)) = revealed_leaves.get(dip_commitment_storage_key.as_ref()) else { return Err(()) }; + println!("D"); + ParaInfoProvider::Commitment::decode(&mut &encoded_commitment[..]).map_err(|_| ()) + } + } + + #[cfg(test)] + mod spiritnet_test_event_count_value { + use super::*; + + use hex_literal::hex; + use polkadot_primitives::BlakeTwo256; + use sp_core::storage::StorageKey; + + // Spiritnet block n: 4_184_668, + // hash 0x2c0746e7e9ccc6e4d27bcb4118cb6821ae53ae9bf372f4f49ac28d8598f9bed5 + struct StaticSpiritnetInfoProvider; + + // We use the `system::eventCount()` storage entry as a unit test here. + impl ParachainStateInfoProvider for StaticSpiritnetInfoProvider { + // The type of the `eventCount()` storage entry. + type Commitment = u32; + type Hasher = BlakeTwo256; + // Irrelevant for this test here + type Identifier = (); + type Key = StorageKey; + + fn dip_subject_storage_key(_identifier: Self::Identifier) -> Self::Key { + // system::eventCount() raw storage key + let storage_key = hex!("26aa394eea5630e07c48ae0c9558cef70a98fdbe9ce6c55837576c60c7af3850").to_vec(); + StorageKey(storage_key) + } + + fn state_root() -> ::Output { + hex!("94c23fda279cea4a4370e90f1544c8938923dfd4ac201a420c7a26fb0d3caf8c").into() + } + } + + #[test] + fn test_spiritnet_event_count() { + // As of RPC state_getReadProof(" + // 0x26aa394eea5630e07c48ae0c9558cef70a98fdbe9ce6c55837576c60c7af3850", + // "0x2c0746e7e9ccc6e4d27bcb4118cb6821ae53ae9bf372f4f49ac28d8598f9bed5") + let spiritnet_event_count_proof_at_block = [ + hex!("800404645ea5c1b19ab7a04f536c519aca4983ac205cda3f0000000000545e98fdbe9ce6c55837576c60c7af38501005000000").to_vec(), + hex!("80401080481e2bd8085a02c5b58987bce7a69f0b5c7fa651e8e82c5481c94707860be9078067785103d453293707ba847e21df7e35a7a57b8fb929d40465328b6642669fcc").to_vec(), + hex!("80ffff8010623b5a3a9dbc752963d827be0bb855bf3e24258ae09341d5f762e96a836ac180c34b753605e821528756b55b4ddafb742df6e54fbc03ef401d4ebfd6dd4f3e44806f83646e0bf3ca0ac9f2092dea5b0e3caf210cc6b54c3b44a51855a133367a6580b02cde7b1fd3f8d13f698ef6e9daa29b32258d4d97a8947051070a4540aecacd80903d521961849d07ceee132617b8dde96c3ff472f5a9a089d4055ffe7ffd1e988016c29c943c106713bb8f16b776eb7daed005540165696da286cddf6b25d085448019a464010cb746b0589891f72b0eed603d4712b04af46f7bcae724564194801480a305ffe069db7eb21841f75b5939943f62c4abb3a051d530839c5dd935ccbc8a8035d8938b0c856878de1e3fe45a559588b2da52ccf195ab1e3d0aca6ac7bb079d8064019a474a283c19f46ff4652a5e1f636efd4013d3b8a91c49573045c6ff01c0801a191dcb736faddb84889a13c7aa717d260e9b635b30a9eb3907f925a2253d6880f8bc389fc62ca951609bae208b7506bae497623e647424062d1c56cb1f2d2e1c80211a9fb5f8b794f9fbfbdcd4519aa475ecaf9737b4ee513dde275d5fbbe64da080c267d0ead99634e9b9cfbf61a583877e0241ac518e62e909fbb017469de275f780b3059a7226d4b320c25e9b2f8ffe19cf93467e3b306885962c5f34b5671d15fe8092dfba9e30e1bbefab13c792755d06927e6141f7220b7485e5aa40de92401a66").to_vec(), + hex!("9eaa394eea5630e07c48ae0c9558cef7398f8069ef420a0deb5a428c9a08563b28a78874bba09124eecc8d28bf30b0e2ddd310745f04abf5cb34d6244378cddbf18e849d962c000000000736d8e8140100505f0e7b9012096b41c4eb3aaf947f6ea4290800004c5f0684a022a34dd8bfa2baaf44f172b710040180dd3270a03a1a13fc20bcdf24d1aa4ddccc6183db2e2e153b8a68ba8540699a8a80b413dad63538a591f7f2575d287520ee44d7143aa5ec2411969861e1f55a2989804c3f0f541a13980689894db7c60c785dd29e066f213bb29b17aa740682ad7efd8026d3a50544f5c89500745aca2be36cfe076f599c5115192fb9deae227e2710c980bd04b00bf6b42756a06a4fbf05a5231c2094e48182eca95d2cff73ab907592aa").to_vec(), + ].to_vec(); + // As of query system::eventCount() at block + // "0x2c0746e7e9ccc6e4d27bcb4118cb6821ae53ae9bf372f4f49ac28d8598f9bed5" which + // results in the key + // "0x26aa394eea5630e07c48ae0c9558cef70a98fdbe9ce6c55837576c60c7af3850" + let expected_event_count_at_block = 5; + let returned_event_count = + DipCommitmentValueProofVerifier::::verify_proof_for_identifier( + (), + spiritnet_event_count_proof_at_block, + ) + .unwrap(); + assert!(returned_event_count == expected_event_count_at_block, "Spiritnet event count returned from the state proof verification should not be different than the pre-computed one."); + } } } From 4fd3f066d04dedcf68b6f6e0a3f2c7ee49702db0 Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Wed, 12 Jul 2023 16:56:00 +0200 Subject: [PATCH 08/32] Half-way --- crates/kilt-dip-support/src/merkle.rs | 133 ++++++++++---------- crates/kilt-dip-support/src/new_stuff.rs | 83 ++++++++++-- pallets/pallet-dip-consumer/src/identity.rs | 26 ++++ pallets/pallet-dip-consumer/src/traits.rs | 10 +- 4 files changed, 169 insertions(+), 83 deletions(-) diff --git a/crates/kilt-dip-support/src/merkle.rs b/crates/kilt-dip-support/src/merkle.rs index 12bf8c7088..76d41763af 100644 --- a/crates/kilt-dip-support/src/merkle.rs +++ b/crates/kilt-dip-support/src/merkle.rs @@ -18,11 +18,12 @@ use did::{did_details::DidPublicKeyDetails, DidVerificationKeyRelationship}; use frame_support::{traits::ConstU32, RuntimeDebug}; -use pallet_dip_consumer::traits::IdentityProofVerifier; +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}; pub type BlindedValue = Vec; @@ -259,7 +260,7 @@ impl< // TODO: Proper error handling type Error = (); type Proof = MerkleProof>, ProofLeaf>; - type IdentityDetails = Details; + type IdentityDetails = IdentityDetails; type Submitter = AccountId; type VerificationResult = VerificationResult< KeyId, @@ -274,69 +275,69 @@ impl< _call: &Call, _subject: &Subject, _submitter: &Self::Submitter, - _identity_details: &mut Option, - _proof: &Self::Proof, + identity_details: &mut Option, + proof: &Self::Proof, ) -> Result { - Err(()) - // // 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_details.digest.clone().into(), - // &proof.blinded, - // &proof_leaves, - // ) - // .map_err(|_| ())?; - - // // 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 { - // 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, linked_accounts)) - // } - // // TODO: Avoid cloning if possible - // 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)) - // } - // }, - // )?; - - // Ok(VerificationResult { - // 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 Some(identity_details) = identity_details else { return Err(()) }; + verify_trie_proof::, _, _, _>( + &identity_details.digest.clone().into(), + &proof.blinded, + &proof_leaves, + ) + .map_err(|_| ())?; + + // 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 { + 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, linked_accounts)) + } + // TODO: Avoid cloning if possible + 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)) + } + }, + )?; + + Ok(VerificationResult { + did_keys, + web3_name, + linked_accounts, + }) } } diff --git a/crates/kilt-dip-support/src/new_stuff.rs b/crates/kilt-dip-support/src/new_stuff.rs index 29dc86c047..735ccc01fc 100644 --- a/crates/kilt-dip-support/src/new_stuff.rs +++ b/crates/kilt-dip-support/src/new_stuff.rs @@ -1,19 +1,79 @@ -use parity_scale_codec::Decode; -use sp_runtime::traits::Hash; +use pallet_dip_consumer::{identity::IdentityDetails, traits::IdentityProofVerifier}; +use parity_scale_codec::{Decode, HasCompact}; +use sp_core::{Get, U256}; +use sp_runtime::{generic::Header, traits::Hash}; use sp_state_machine::read_proof_check; use sp_std::marker::PhantomData; use sp_trie::StorageProof; +pub struct DipProof { + para_root_proof: Vec>, + dip_commitment_proof: Vec>, + dip_proof: InnerProof, +} + +pub struct StateProofDipVerifier( + PhantomData<(ProviderParaId, RelayInfoProvider, ProviderParaInfoProvider, DipVerifier)>, +); + +impl + IdentityProofVerifier + for StateProofDipVerifier +where + ProviderParaId: Get, + + RelayInfoProvider: relay_chain::RelayChainStateInfoProvider, + RelayInfoProvider::Hasher: 'static, + ::Output: Ord, + RelayInfoProvider::BlockNumber: Copy + Into + TryFrom + HasCompact, + RelayInfoProvider::Key: AsRef<[u8]>, + + ProviderParaInfoProvider: parachain::ParachainStateInfoProvider, + ProviderParaInfoProvider::Hasher: 'static, + ::Output: Ord, + ProviderParaInfoProvider::Commitment: Decode, + ProviderParaInfoProvider::Key: AsRef<[u8]>, + + DipVerifier: IdentityProofVerifier, +{ + type Error = (); + type IdentityDetails = IdentityDetails; + type Proof = DipProof; + type Submitter = DipVerifier::Submitter; + type VerificationResult = DipVerifier::VerificationResult; + + fn verify_proof_for_call_against_details( + call: &Call, + subject: &Subject, + submitter: &Self::Submitter, + identity_details: &mut Option, + proof: &Self::Proof, + ) -> Result { + let provider_parachain_header = + relay_chain::ParachainHeadProofVerifier::::verify_proof_for_parachain( + &ProviderParaId::get(), + proof.para_root_proof, + )?; + let provider_parachain_root_state = provider_parachain_header.state_root; + let subject_identity_commitment = + parachain::DipCommitmentValueProofVerifier::::verify_proof_for_identifier( + subject, + proof.dip_commitment_proof, + )?; + // TODO: Call the third and last step for the DIP merkle verification. + } +} + pub mod relay_chain { use super::*; pub trait RelayChainStateInfoProvider { + type BlockNumber; type Key; type Hasher: Hash; - type Header; type ParaId; - fn parachain_head_storage_key(para_id: Self::ParaId) -> Self::Key; + fn parachain_head_storage_key(para_id: &Self::ParaId) -> Self::Key; fn state_root() -> ::Output; } @@ -24,13 +84,13 @@ pub mod relay_chain { RelayInfoProvider: RelayChainStateInfoProvider, RelayInfoProvider::Hasher: 'static, ::Output: Ord, - RelayInfoProvider::Header: Decode, + RelayInfoProvider::BlockNumber: Copy + Into + TryFrom + HasCompact, RelayInfoProvider::Key: AsRef<[u8]>, { pub fn verify_proof_for_parachain( - para_id: RelayInfoProvider::ParaId, + para_id: &RelayInfoProvider::ParaId, proof: impl IntoIterator>, - ) -> Result { + ) -> Result, ()> { let relay_state_root = RelayInfoProvider::state_root(); let parachain_storage_key = RelayInfoProvider::parachain_head_storage_key(para_id); let storage_proof = StorageProof::new(proof); @@ -46,7 +106,7 @@ pub mod relay_chain { let Some(Some(encoded_head)) = revealed_leaves.get(parachain_storage_key.as_ref()) else { return Err(()) }; // TODO: Figure out why RPC call returns 2 bytes in front which we don't need let mut unwrapped_head = &encoded_head[2..]; - RelayInfoProvider::Header::decode(&mut unwrapped_head).map_err(|_| ()) + Header::decode(&mut unwrapped_head).map_err(|_| ()) } } @@ -58,15 +118,14 @@ pub mod relay_chain { use parity_scale_codec::Encode; use polkadot_primitives::BlakeTwo256; use sp_core::{storage::StorageKey, H256}; - use sp_runtime::generic::Header; // Polkadot block n: 16_363_919, // hash 0x18e90e9aa8e3b063f60386ba1b0415111798e72d01de58b1438d620d42f58e39 struct StaticPolkadotInfoProvider; impl RelayChainStateInfoProvider for StaticPolkadotInfoProvider { + type BlockNumber = u32; type Hasher = BlakeTwo256; - type Header = Header; type Key = StorageKey; type ParaId = u32; @@ -124,7 +183,7 @@ pub mod parachain { type Hasher: Hash; type Identifier; - fn dip_subject_storage_key(identifier: Self::Identifier) -> Self::Key; + fn dip_subject_storage_key(identifier: &Self::Identifier) -> Self::Key; fn state_root() -> ::Output; } @@ -139,7 +198,7 @@ pub mod parachain { ParaInfoProvider::Key: AsRef<[u8]>, { pub fn verify_proof_for_identifier( - identifier: ParaInfoProvider::Identifier, + identifier: &ParaInfoProvider::Identifier, proof: impl IntoIterator>, ) -> Result { let parachain_state_root = ParaInfoProvider::state_root(); diff --git a/pallets/pallet-dip-consumer/src/identity.rs b/pallets/pallet-dip-consumer/src/identity.rs index 79e74681a2..eed39f68d4 100644 --- a/pallets/pallet-dip-consumer/src/identity.rs +++ b/pallets/pallet-dip-consumer/src/identity.rs @@ -15,3 +15,29 @@ // along with this program. If not, see . // If you feel like getting in touch with us, you can do so at info@botlabs.org + +use frame_support::RuntimeDebug; +use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; +use scale_info::TypeInfo; + +/// The identity entry for any given user that uses the DIP protocol. +#[derive(Encode, Decode, MaxEncodedLen, Default, TypeInfo, RuntimeDebug)] +pub struct IdentityDetails { + /// The identity digest information, typically used to verify identity + /// proofs. + pub digest: Digest, + /// The details related to the user, stored in the pallet storage. + pub details: Details, +} + +impl From for IdentityDetails +where + Details: Default, +{ + fn from(value: Digest) -> Self { + Self { + digest: value, + details: Details::default(), + } + } +} diff --git a/pallets/pallet-dip-consumer/src/traits.rs b/pallets/pallet-dip-consumer/src/traits.rs index d05424f45e..f65d89542e 100644 --- a/pallets/pallet-dip-consumer/src/traits.rs +++ b/pallets/pallet-dip-consumer/src/traits.rs @@ -20,8 +20,8 @@ use sp_std::marker::PhantomData; pub trait IdentityProofVerifier { type Error; - type Proof; type IdentityDetails; + type Proof; type Submitter; type VerificationResult; @@ -35,13 +35,13 @@ pub trait IdentityProofVerifier { } // Always returns success. -pub struct SuccessfulProofVerifier(PhantomData<(Proof, ProofEntry, Submitter)>); -impl IdentityProofVerifier - for SuccessfulProofVerifier +pub struct SuccessfulProofVerifier(PhantomData<(IdentityDetails, Proof, Submitter)>); +impl IdentityProofVerifier + for SuccessfulProofVerifier { type Error = (); + type IdentityDetails = IdentityDetails; type Proof = Proof; - type IdentityDetails = ProofEntry; type Submitter = Submitter; type VerificationResult = (); From a9ca939f84c727c367a39c5b82ed906c11148f91 Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Thu, 13 Jul 2023 10:42:12 +0200 Subject: [PATCH 09/32] Before replacing 'read_proof_check' --- Cargo.lock | 2 - crates/kilt-dip-support/Cargo.toml | 10 +-- crates/kilt-dip-support/src/did.rs | 8 ++- crates/kilt-dip-support/src/merkle.rs | 8 +-- crates/kilt-dip-support/src/new_stuff.rs | 73 +++++++++++++++------ pallets/pallet-dip-consumer/src/identity.rs | 2 +- 6 files changed, 64 insertions(+), 39 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 956613fa5d..54ba7867b1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4189,7 +4189,6 @@ dependencies = [ name = "kilt-dip-support" version = "1.11.0-dev" dependencies = [ - "cumulus-pallet-parachain-system", "did", "dip-support", "frame-support", @@ -4198,7 +4197,6 @@ dependencies = [ "pallet-dip-consumer", "pallet-dip-provider", "parity-scale-codec", - "polkadot-primitives", "scale-info", "sp-core", "sp-io", diff --git a/crates/kilt-dip-support/Cargo.toml b/crates/kilt-dip-support/Cargo.toml index bff0cce096..2980a6b0be 100644 --- a/crates/kilt-dip-support/Cargo.toml +++ b/crates/kilt-dip-support/Cargo.toml @@ -31,16 +31,12 @@ sp-std.workspace = true sp-trie.workspace = true # Polkadot dependencies -polkadot-primitives.workspace = true xcm.workspace = true xcm-executor.workspace = true -# Cumulus dependencies -cumulus-pallet-parachain-system.workspace = true - [dev-dependencies] hex-literal.workspace = true -sp-io.workspace = true +sp-io = { workspace = true, features = ["std"] } [features] default = ["std"] @@ -57,10 +53,8 @@ std = [ "sp-core/std", "sp-state-machine/std", "sp-trie/std", - "polkadot-primitives/std", "sp-std/std", "xcm-executor/std", - "xcm/std", - "cumulus-pallet-parachain-system/std", + "xcm/std" ] runtime-benchmarks = [] diff --git a/crates/kilt-dip-support/src/did.rs b/crates/kilt-dip-support/src/did.rs index 2652b026fb..8a076b7178 100644 --- a/crates/kilt-dip-support/src/did.rs +++ b/crates/kilt-dip-support/src/did.rs @@ -118,7 +118,7 @@ impl< BlockNumber: Encode + CheckedSub + Into + PartialOrd + sp_std::fmt::Debug, Call: Encode, Digest: Encode, - Details: Bump + Encode, + Details: Bump + Default + Encode, MerkleProofEntries: AsRef<[RevealedDidKey]>, BlockNumberProvider: Get, GenesisHashProvider: Get, @@ -179,7 +179,11 @@ impl< }); let Some((key, relationship)) = valid_signing_key else { return Err(()) }; // TODO: bump details. - // identity_details.bump(); + if let Some(details) = identity_details { + details.bump(); + } else { + *identity_details = Some(Details::default()); + } Ok((key.clone(), relationship)) } } diff --git a/crates/kilt-dip-support/src/merkle.rs b/crates/kilt-dip-support/src/merkle.rs index 76d41763af..b91784fb69 100644 --- a/crates/kilt-dip-support/src/merkle.rs +++ b/crates/kilt-dip-support/src/merkle.rs @@ -287,12 +287,8 @@ impl< .map(|leaf| (leaf.encoded_key(), Some(leaf.encoded_value()))) .collect::, Option>)>>(); let Some(identity_details) = identity_details else { return Err(()) }; - verify_trie_proof::, _, _, _>( - &identity_details.digest.clone().into(), - &proof.blinded, - &proof_leaves, - ) - .map_err(|_| ())?; + verify_trie_proof::, _, _, _>(&identity_details.digest, &proof.blinded, &proof_leaves) + .map_err(|_| ())?; // 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. diff --git a/crates/kilt-dip-support/src/new_stuff.rs b/crates/kilt-dip-support/src/new_stuff.rs index 735ccc01fc..7e196afaf5 100644 --- a/crates/kilt-dip-support/src/new_stuff.rs +++ b/crates/kilt-dip-support/src/new_stuff.rs @@ -3,22 +3,35 @@ use parity_scale_codec::{Decode, HasCompact}; use sp_core::{Get, U256}; use sp_runtime::{generic::Header, traits::Hash}; use sp_state_machine::read_proof_check; -use sp_std::marker::PhantomData; +use sp_std::{marker::PhantomData, vec::Vec}; use sp_trie::StorageProof; +#[derive(Clone)] pub struct DipProof { para_root_proof: Vec>, dip_commitment_proof: Vec>, dip_proof: InnerProof, } -pub struct StateProofDipVerifier( - PhantomData<(ProviderParaId, RelayInfoProvider, ProviderParaInfoProvider, DipVerifier)>, +pub struct StateProofDipVerifier< + ProviderParaId, + RelayInfoProvider, + ProviderParaInfoProvider, + DipVerifier, + LocalIdentityInfo, +>( + PhantomData<( + ProviderParaId, + RelayInfoProvider, + ProviderParaInfoProvider, + DipVerifier, + LocalIdentityInfo, + )>, ); -impl +impl IdentityProofVerifier - for StateProofDipVerifier + for StateProofDipVerifier where ProviderParaId: Get, @@ -30,14 +43,20 @@ where ProviderParaInfoProvider: parachain::ParachainStateInfoProvider, ProviderParaInfoProvider::Hasher: 'static, - ::Output: Ord, + ::Output: Ord + PartialEq<::Output>, ProviderParaInfoProvider::Commitment: Decode, ProviderParaInfoProvider::Key: AsRef<[u8]>, - DipVerifier: IdentityProofVerifier, + DipVerifier: IdentityProofVerifier< + Call, + Subject, + IdentityDetails = IdentityDetails>, + >, + + LocalIdentityInfo: Clone, { type Error = (); - type IdentityDetails = IdentityDetails; + type IdentityDetails = LocalIdentityInfo; type Proof = DipProof; type Submitter = DipVerifier::Submitter; type VerificationResult = DipVerifier::VerificationResult; @@ -52,15 +71,30 @@ where let provider_parachain_header = relay_chain::ParachainHeadProofVerifier::::verify_proof_for_parachain( &ProviderParaId::get(), - proof.para_root_proof, + proof.para_root_proof.clone(), )?; let provider_parachain_root_state = provider_parachain_header.state_root; + debug_assert!( + ProviderParaInfoProvider::state_root() == provider_parachain_root_state, + "Provided parachain state root and calculated parachain state root do not match." + ); let subject_identity_commitment = parachain::DipCommitmentValueProofVerifier::::verify_proof_for_identifier( subject, - proof.dip_commitment_proof, + proof.dip_commitment_proof.clone(), )?; - // TODO: Call the third and last step for the DIP merkle verification. + let mapped_identity_details = IdentityDetails { + digest: subject_identity_commitment, + details: identity_details.clone(), + }; + DipVerifier::verify_proof_for_call_against_details( + call, + subject, + submitter, + &mut Some(mapped_identity_details), + &proof.dip_proof, + ) + .map_err(|_| ()) } } @@ -101,7 +135,7 @@ pub mod relay_chain { ) .map_err(|_| ())?; // TODO: Remove at some point - debug_assert!(revealed_leaves.len() == 1); + debug_assert!(revealed_leaves.len() == 1usize); debug_assert!(revealed_leaves.contains_key(parachain_storage_key.as_ref())); let Some(Some(encoded_head)) = revealed_leaves.get(parachain_storage_key.as_ref()) else { return Err(()) }; // TODO: Figure out why RPC call returns 2 bytes in front which we don't need @@ -116,8 +150,8 @@ pub mod relay_chain { use hex_literal::hex; use parity_scale_codec::Encode; - use polkadot_primitives::BlakeTwo256; use sp_core::{storage::StorageKey, H256}; + use sp_runtime::traits::BlakeTwo256; // Polkadot block n: 16_363_919, // hash 0x18e90e9aa8e3b063f60386ba1b0415111798e72d01de58b1438d620d42f58e39 @@ -129,7 +163,7 @@ pub mod relay_chain { type Key = StorageKey; type ParaId = u32; - fn parachain_head_storage_key(para_id: Self::ParaId) -> Self::Key { + fn parachain_head_storage_key(para_id: &Self::ParaId) -> Self::Key { // Adapted from https://github.com/polytope-labs/substrate-ismp/blob/7fb09da6c7b818a98c25c962fee0ddde8e737306/parachain/src/consensus.rs#L369 // Used for testing. In production this would be generated from the relay // runtime definition of the `paras` storage map. @@ -165,7 +199,7 @@ pub mod relay_chain { // let expected_spiritnet_head_at_block = hex!("65541097fb02782e14f43074f0b00e44ae8e9fe426982323ef1d329739740d37f252ff006d1156941db1bccd58ce3a1cac4f40cad91f692d94e98f501dd70081a129b69a3e2ef7e1ff84ba3d86dab4e95f2c87f6b1055ebd48519c185360eae58f05d1ea08066175726120dcdc6308000000000561757261010170ccfaf3756d1a8dd8ae5c89094199d6d32e5dd9f0920f6fe30f986815b5e701974ea0e0e0a901401f2c72e3dd8dbdf4aa55d59bf3e7021856cdb8038419eb8c").to_vec(); let returned_head = ParachainHeadProofVerifier::::verify_proof_for_parachain( - 2_086, + &2_086, spiritnet_head_proof_at_block, ) .expect("Parachain head proof verification should not fail."); @@ -211,10 +245,9 @@ pub mod parachain { ) .map_err(|_| ())?; // TODO: Remove at some point - debug_assert!(revealed_leaves.len() == 1); + debug_assert!(revealed_leaves.len() == 1usize); debug_assert!(revealed_leaves.contains_key(dip_commitment_storage_key.as_ref())); let Some(Some(encoded_commitment)) = revealed_leaves.get(dip_commitment_storage_key.as_ref()) else { return Err(()) }; - println!("D"); ParaInfoProvider::Commitment::decode(&mut &encoded_commitment[..]).map_err(|_| ()) } } @@ -224,8 +257,8 @@ pub mod parachain { use super::*; use hex_literal::hex; - use polkadot_primitives::BlakeTwo256; use sp_core::storage::StorageKey; + use sp_runtime::traits::BlakeTwo256; // Spiritnet block n: 4_184_668, // hash 0x2c0746e7e9ccc6e4d27bcb4118cb6821ae53ae9bf372f4f49ac28d8598f9bed5 @@ -240,7 +273,7 @@ pub mod parachain { type Identifier = (); type Key = StorageKey; - fn dip_subject_storage_key(_identifier: Self::Identifier) -> Self::Key { + fn dip_subject_storage_key(_identifier: &Self::Identifier) -> Self::Key { // system::eventCount() raw storage key let storage_key = hex!("26aa394eea5630e07c48ae0c9558cef70a98fdbe9ce6c55837576c60c7af3850").to_vec(); StorageKey(storage_key) @@ -269,7 +302,7 @@ pub mod parachain { let expected_event_count_at_block = 5; let returned_event_count = DipCommitmentValueProofVerifier::::verify_proof_for_identifier( - (), + &(), spiritnet_event_count_proof_at_block, ) .unwrap(); diff --git a/pallets/pallet-dip-consumer/src/identity.rs b/pallets/pallet-dip-consumer/src/identity.rs index eed39f68d4..e6c5f8a596 100644 --- a/pallets/pallet-dip-consumer/src/identity.rs +++ b/pallets/pallet-dip-consumer/src/identity.rs @@ -21,7 +21,7 @@ use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; /// The identity entry for any given user that uses the DIP protocol. -#[derive(Encode, Decode, MaxEncodedLen, Default, TypeInfo, RuntimeDebug)] +#[derive(Encode, Decode, MaxEncodedLen, Default, TypeInfo, RuntimeDebug, Clone)] pub struct IdentityDetails { /// The identity digest information, typically used to verify identity /// proofs. From 81ea88c3ebbf57e620cb4f40ffa1ea2412226338 Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Thu, 13 Jul 2023 10:49:46 +0200 Subject: [PATCH 10/32] Ported the proof verification for no_std --- crates/kilt-dip-support/src/new_stuff.rs | 52 +++++++++++++++++++++--- 1 file changed, 47 insertions(+), 5 deletions(-) diff --git a/crates/kilt-dip-support/src/new_stuff.rs b/crates/kilt-dip-support/src/new_stuff.rs index 7e196afaf5..d6ff1b59ad 100644 --- a/crates/kilt-dip-support/src/new_stuff.rs +++ b/crates/kilt-dip-support/src/new_stuff.rs @@ -1,10 +1,52 @@ use pallet_dip_consumer::{identity::IdentityDetails, traits::IdentityProofVerifier}; -use parity_scale_codec::{Decode, HasCompact}; -use sp_core::{Get, U256}; +use parity_scale_codec::{Codec, Decode, HasCompact}; +use sp_core::{Get, Hasher, U256}; use sp_runtime::{generic::Header, traits::Hash}; -use sp_state_machine::read_proof_check; -use sp_std::{marker::PhantomData, vec::Vec}; -use sp_trie::StorageProof; +use sp_state_machine::{Backend, TrieBackend, TrieBackendBuilder}; +use sp_std::{collections::btree_map::BTreeMap, marker::PhantomData, vec::Vec}; +use sp_trie::{HashDBT, MemoryDB, StorageProof}; + +// Ported from https://github.com/paritytech/substrate/blob/b27c470eaff379f512d1dec052aff5d551ed3b03/primitives/state-machine/src/lib.rs#L1076 +fn read_proof_check(root: H::Out, proof: StorageProof, keys: I) -> Result, Option>>, ()> +where + H: Hasher + 'static, + H::Out: Ord + Codec, + I: IntoIterator, + I::Item: AsRef<[u8]>, +{ + let proving_backend = create_proof_check_backend::(root, proof)?; + let mut result = BTreeMap::new(); + for key in keys.into_iter() { + let value = read_proof_check_on_proving_backend(&proving_backend, key.as_ref())?; + result.insert(key.as_ref().to_vec(), value); + } + Ok(result) +} + +fn read_proof_check_on_proving_backend( + proving_backend: &TrieBackend, H>, + key: &[u8], +) -> Result>, ()> +where + H: Hasher, + H::Out: Ord + Codec, +{ + proving_backend.storage(key).map_err(|_| ()) +} + +fn create_proof_check_backend(root: H::Out, proof: StorageProof) -> Result, H>, ()> +where + H: Hasher, + H::Out: Codec, +{ + let db = proof.into_memory_db(); + + if db.contains(&root, (&[], None)) { + Ok(TrieBackendBuilder::new(db, root).build()) + } else { + Err(()) + } +} #[derive(Clone)] pub struct DipProof { From e8919f12ea5402d7cfbcdf8e4f5f33f1a03c8299 Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Thu, 13 Jul 2023 11:59:55 +0200 Subject: [PATCH 11/32] Refactoring on the way --- Cargo.lock | 25 ++- Cargo.toml | 1 + crates/kilt-dip-support/Cargo.toml | 4 + crates/kilt-dip-support/src/lib.rs | 98 ++++++++- .../src/{new_stuff.rs => state_proofs.rs} | 207 +++++++----------- 5 files changed, 193 insertions(+), 142 deletions(-) rename crates/kilt-dip-support/src/{new_stuff.rs => state_proofs.rs} (76%) diff --git a/Cargo.lock b/Cargo.lock index 54ba7867b1..bb08917c8a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -606,7 +606,7 @@ name = "binary-merkle-tree" version = "4.0.0-dev" source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" dependencies = [ - "hash-db", + "hash-db 0.15.2", "log", ] @@ -3559,6 +3559,12 @@ version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d23bd4e7b5eda0d0f3a307e8b381fdc8ba9000f26fbe912250c0a4cc3956364a" +[[package]] +name = "hash-db" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e7d7786361d7425ae2fe4f9e407eb0efaa0840f5212d109cc018c40c35c6ab4" + [[package]] name = "hash256-std-hasher" version = "0.15.2" @@ -4193,6 +4199,7 @@ dependencies = [ "dip-support", "frame-support", "frame-system", + "hash-db 0.16.0", "hex-literal", "pallet-dip-consumer", "pallet-dip-provider", @@ -5351,7 +5358,7 @@ version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e0c7cba9ce19ac7ffd2053ac9f49843bbd3f4318feedfd74e85c19d5fb0ba66" dependencies = [ - "hash-db", + "hash-db 0.15.2", "hashbrown 0.12.3", ] @@ -9751,7 +9758,7 @@ name = "sc-client-db" version = "0.10.0-dev" source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" dependencies = [ - "hash-db", + "hash-db 0.15.2", "kvdb", "kvdb-memorydb", "kvdb-rocksdb", @@ -11095,7 +11102,7 @@ name = "sp-api" version = "4.0.0-dev" source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" dependencies = [ - "hash-db", + "hash-db 0.15.2", "log", "parity-scale-codec", "sp-api-proc-macro", @@ -11306,7 +11313,7 @@ dependencies = [ "dyn-clonable", "ed25519-zebra", "futures", - "hash-db", + "hash-db 0.15.2", "hash256-std-hasher", "impl-serde", "lazy_static", @@ -11631,7 +11638,7 @@ name = "sp-state-machine" version = "0.13.0" source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" dependencies = [ - "hash-db", + "hash-db 0.15.2", "log", "parity-scale-codec", "parking_lot 0.12.1", @@ -11722,7 +11729,7 @@ version = "7.0.0" source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" dependencies = [ "ahash 0.8.3", - "hash-db", + "hash-db 0.15.2", "hashbrown 0.12.3", "lazy_static", "memory-db", @@ -12652,7 +12659,7 @@ version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3390c0409daaa6027d6681393316f4ccd3ff82e1590a1e4725014e3ae2bf1920" dependencies = [ - "hash-db", + "hash-db 0.15.2", "hashbrown 0.13.2", "log", "rustc-hex", @@ -12665,7 +12672,7 @@ version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a36c5ca3911ed3c9a5416ee6c679042064b93fc637ded67e25f92e68d783891" dependencies = [ - "hash-db", + "hash-db 0.15.2", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 4be6a35c65..02c612b42f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,6 +34,7 @@ bitflags = {version = "1.3.2", default-features = false} clap = "4.1.6" env_logger = "0.10.0" futures = {version = "0.3.21", default-features = false} +hash-db = { version = "0.16.0", default-features = false } hex = {version = "0.4.0", default-features = false} hex-literal = "0.3.4" jsonrpsee = "0.16.2" diff --git a/crates/kilt-dip-support/Cargo.toml b/crates/kilt-dip-support/Cargo.toml index 2980a6b0be..1fb1776956 100644 --- a/crates/kilt-dip-support/Cargo.toml +++ b/crates/kilt-dip-support/Cargo.toml @@ -11,6 +11,9 @@ repository.workspace = true version.workspace = true [dependencies] +# External dependencies +hash-db.workspace = true + # Internal dependencies did.workspace = true dip-support.workspace = true @@ -41,6 +44,7 @@ sp-io = { workspace = true, features = ["std"] } [features] default = ["std"] std = [ + "hash-db/std", "did/std", "dip-support/std", "pallet-dip-consumer/std", diff --git a/crates/kilt-dip-support/src/lib.rs b/crates/kilt-dip-support/src/lib.rs index 6aded4d82c..106ccc7e64 100644 --- a/crates/kilt-dip-support/src/lib.rs +++ b/crates/kilt-dip-support/src/lib.rs @@ -20,16 +20,110 @@ #![cfg_attr(not(feature = "std"), no_std)] -use pallet_dip_consumer::traits::IdentityProofVerifier; +use parity_scale_codec::{Decode, HasCompact}; +use sp_core::{Get, U256}; +use sp_runtime::traits::Hash; use sp_std::marker::PhantomData; +use pallet_dip_consumer::{identity::IdentityDetails, traits::IdentityProofVerifier}; + use crate::did::MerkleLeavesAndDidSignature; pub mod did; pub mod merkle; -pub mod new_stuff; +pub mod state_proofs; pub mod traits; +#[derive(Clone)] +pub struct DipSiblingParachainStateProof { + para_root_proof: Vec>, + dip_commitment_proof: Vec>, + dip_proof: InnerProof, +} + +pub struct StateProofDipVerifier< + ProviderParaId, + RelayInfoProvider, + ProviderParaInfoProvider, + DipVerifier, + LocalIdentityInfo, +>( + PhantomData<( + ProviderParaId, + RelayInfoProvider, + ProviderParaInfoProvider, + DipVerifier, + LocalIdentityInfo, + )>, +); + +impl + IdentityProofVerifier + for StateProofDipVerifier +where + ProviderParaId: Get, + + RelayInfoProvider: state_proofs::relay_chain::RelayChainStateInfoProvider, + RelayInfoProvider::Hasher: 'static, + ::Output: Ord, + RelayInfoProvider::BlockNumber: Copy + Into + TryFrom + HasCompact, + RelayInfoProvider::Key: AsRef<[u8]>, + + ProviderParaInfoProvider: state_proofs::parachain::ParachainStateInfoProvider, + ProviderParaInfoProvider::Hasher: 'static, + ::Output: Ord + PartialEq<::Output>, + ProviderParaInfoProvider::Commitment: Decode, + ProviderParaInfoProvider::Key: AsRef<[u8]>, + + DipVerifier: IdentityProofVerifier< + Call, + Subject, + IdentityDetails = IdentityDetails>, + >, + + LocalIdentityInfo: Clone, +{ + type Error = (); + type IdentityDetails = LocalIdentityInfo; + type Proof = DipSiblingParachainStateProof; + type Submitter = DipVerifier::Submitter; + type VerificationResult = DipVerifier::VerificationResult; + + fn verify_proof_for_call_against_details( + call: &Call, + subject: &Subject, + submitter: &Self::Submitter, + identity_details: &mut Option, + proof: &Self::Proof, + ) -> Result { + let provider_parachain_header = + state_proofs::relay_chain::ParachainHeadProofVerifier::::verify_proof_for_parachain( + &ProviderParaId::get(), + proof.para_root_proof.clone(), + )?; + let provider_parachain_root_state = provider_parachain_header.state_root; + debug_assert!( + ProviderParaInfoProvider::state_root() == provider_parachain_root_state, + "Provided parachain state root and calculated parachain state root do not match." + ); + let subject_identity_commitment = state_proofs::parachain::DipCommitmentValueProofVerifier::< + ProviderParaInfoProvider, + >::verify_proof_for_identifier(subject, proof.dip_commitment_proof.clone())?; + let mapped_identity_details = IdentityDetails { + digest: subject_identity_commitment, + details: identity_details.clone(), + }; + DipVerifier::verify_proof_for_call_against_details( + call, + subject, + submitter, + &mut Some(mapped_identity_details), + &proof.dip_proof, + ) + .map_err(|_| ()) + } +} + /// A type that chains a Merkle proof verification with a DID signature /// verification. The required input of this type is a tuple (A, B) where A is /// /// the type of input required by the `MerkleProofVerifier` and B is a diff --git a/crates/kilt-dip-support/src/new_stuff.rs b/crates/kilt-dip-support/src/state_proofs.rs similarity index 76% rename from crates/kilt-dip-support/src/new_stuff.rs rename to crates/kilt-dip-support/src/state_proofs.rs index d6ff1b59ad..26c47aa57c 100644 --- a/crates/kilt-dip-support/src/new_stuff.rs +++ b/crates/kilt-dip-support/src/state_proofs.rs @@ -1,142 +1,85 @@ -use pallet_dip_consumer::{identity::IdentityDetails, traits::IdentityProofVerifier}; -use parity_scale_codec::{Codec, Decode, HasCompact}; -use sp_core::{Get, Hasher, U256}; +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +use parity_scale_codec::{Decode, HasCompact}; +use sp_core::U256; use sp_runtime::{generic::Header, traits::Hash}; -use sp_state_machine::{Backend, TrieBackend, TrieBackendBuilder}; -use sp_std::{collections::btree_map::BTreeMap, marker::PhantomData, vec::Vec}; -use sp_trie::{HashDBT, MemoryDB, StorageProof}; +use sp_std::{marker::PhantomData, vec::Vec}; +use sp_trie::StorageProof; + +use substrate_no_std_port::read_proof_check; // Ported from https://github.com/paritytech/substrate/blob/b27c470eaff379f512d1dec052aff5d551ed3b03/primitives/state-machine/src/lib.rs#L1076 -fn read_proof_check(root: H::Out, proof: StorageProof, keys: I) -> Result, Option>>, ()> -where - H: Hasher + 'static, - H::Out: Ord + Codec, - I: IntoIterator, - I::Item: AsRef<[u8]>, -{ - let proving_backend = create_proof_check_backend::(root, proof)?; - let mut result = BTreeMap::new(); - for key in keys.into_iter() { - let value = read_proof_check_on_proving_backend(&proving_backend, key.as_ref())?; - result.insert(key.as_ref().to_vec(), value); - } - Ok(result) -} +// Needs to be replaced with its runtime-friendly version when available, or be +// kept up-to-date with upstream. +mod substrate_no_std_port { + use super::*; -fn read_proof_check_on_proving_backend( - proving_backend: &TrieBackend, H>, - key: &[u8], -) -> Result>, ()> -where - H: Hasher, - H::Out: Ord + Codec, -{ - proving_backend.storage(key).map_err(|_| ()) -} + use hash_db::EMPTY_PREFIX; + use parity_scale_codec::Codec; + use sp_core::Hasher; + use sp_state_machine::{Backend, TrieBackend, TrieBackendBuilder}; + use sp_std::collections::btree_map::BTreeMap; + use sp_trie::{HashDBT, MemoryDB}; + + pub(super) fn read_proof_check( + root: H::Out, + proof: StorageProof, + keys: I, + ) -> Result, Option>>, ()> + where + H: Hasher + 'static, + H::Out: Ord + Codec, + I: IntoIterator, + I::Item: AsRef<[u8]>, + { + let proving_backend = create_proof_check_backend::(root, proof)?; + let mut result = BTreeMap::new(); + for key in keys.into_iter() { + let value = read_proof_check_on_proving_backend(&proving_backend, key.as_ref())?; + result.insert(key.as_ref().to_vec(), value); + } + Ok(result) + } -fn create_proof_check_backend(root: H::Out, proof: StorageProof) -> Result, H>, ()> -where - H: Hasher, - H::Out: Codec, -{ - let db = proof.into_memory_db(); - - if db.contains(&root, (&[], None)) { - Ok(TrieBackendBuilder::new(db, root).build()) - } else { - Err(()) + fn read_proof_check_on_proving_backend( + proving_backend: &TrieBackend, H>, + key: &[u8], + ) -> Result>, ()> + where + H: Hasher, + H::Out: Ord + Codec, + { + proving_backend.storage(key).map_err(|_| ()) } -} -#[derive(Clone)] -pub struct DipProof { - para_root_proof: Vec>, - dip_commitment_proof: Vec>, - dip_proof: InnerProof, -} + fn create_proof_check_backend(root: H::Out, proof: StorageProof) -> Result, H>, ()> + where + H: Hasher, + H::Out: Codec, + { + let db = proof.into_memory_db(); -pub struct StateProofDipVerifier< - ProviderParaId, - RelayInfoProvider, - ProviderParaInfoProvider, - DipVerifier, - LocalIdentityInfo, ->( - PhantomData<( - ProviderParaId, - RelayInfoProvider, - ProviderParaInfoProvider, - DipVerifier, - LocalIdentityInfo, - )>, -); - -impl - IdentityProofVerifier - for StateProofDipVerifier -where - ProviderParaId: Get, - - RelayInfoProvider: relay_chain::RelayChainStateInfoProvider, - RelayInfoProvider::Hasher: 'static, - ::Output: Ord, - RelayInfoProvider::BlockNumber: Copy + Into + TryFrom + HasCompact, - RelayInfoProvider::Key: AsRef<[u8]>, - - ProviderParaInfoProvider: parachain::ParachainStateInfoProvider, - ProviderParaInfoProvider::Hasher: 'static, - ::Output: Ord + PartialEq<::Output>, - ProviderParaInfoProvider::Commitment: Decode, - ProviderParaInfoProvider::Key: AsRef<[u8]>, - - DipVerifier: IdentityProofVerifier< - Call, - Subject, - IdentityDetails = IdentityDetails>, - >, - - LocalIdentityInfo: Clone, -{ - type Error = (); - type IdentityDetails = LocalIdentityInfo; - type Proof = DipProof; - type Submitter = DipVerifier::Submitter; - type VerificationResult = DipVerifier::VerificationResult; - - fn verify_proof_for_call_against_details( - call: &Call, - subject: &Subject, - submitter: &Self::Submitter, - identity_details: &mut Option, - proof: &Self::Proof, - ) -> Result { - let provider_parachain_header = - relay_chain::ParachainHeadProofVerifier::::verify_proof_for_parachain( - &ProviderParaId::get(), - proof.para_root_proof.clone(), - )?; - let provider_parachain_root_state = provider_parachain_header.state_root; - debug_assert!( - ProviderParaInfoProvider::state_root() == provider_parachain_root_state, - "Provided parachain state root and calculated parachain state root do not match." - ); - let subject_identity_commitment = - parachain::DipCommitmentValueProofVerifier::::verify_proof_for_identifier( - subject, - proof.dip_commitment_proof.clone(), - )?; - let mapped_identity_details = IdentityDetails { - digest: subject_identity_commitment, - details: identity_details.clone(), - }; - DipVerifier::verify_proof_for_call_against_details( - call, - subject, - submitter, - &mut Some(mapped_identity_details), - &proof.dip_proof, - ) - .map_err(|_| ()) + if db.contains(&root, EMPTY_PREFIX) { + Ok(TrieBackendBuilder::new(db, root).build()) + } else { + Err(()) + } } } @@ -163,6 +106,7 @@ pub mod relay_chain { RelayInfoProvider::BlockNumber: Copy + Into + TryFrom + HasCompact, RelayInfoProvider::Key: AsRef<[u8]>, { + #[allow(clippy::result_unit_err)] pub fn verify_proof_for_parachain( para_id: &RelayInfoProvider::ParaId, proof: impl IntoIterator>, @@ -273,6 +217,7 @@ pub mod parachain { ParaInfoProvider::Commitment: Decode, ParaInfoProvider::Key: AsRef<[u8]>, { + #[allow(clippy::result_unit_err)] pub fn verify_proof_for_identifier( identifier: &ParaInfoProvider::Identifier, proof: impl IntoIterator>, From 8808f149be6b463413fb3727828bbac6df042cc2 Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Thu, 13 Jul 2023 14:16:30 +0200 Subject: [PATCH 12/32] New overarching verifier --- crates/kilt-dip-support/src/did.rs | 4 +- crates/kilt-dip-support/src/lib.rs | 352 +++++++++++++++------- crates/kilt-dip-support/src/merkle.rs | 4 +- pallets/pallet-dip-consumer/src/lib.rs | 2 +- pallets/pallet-dip-consumer/src/traits.rs | 4 +- 5 files changed, 242 insertions(+), 124 deletions(-) diff --git a/crates/kilt-dip-support/src/did.rs b/crates/kilt-dip-support/src/did.rs index 8a076b7178..8765a419ba 100644 --- a/crates/kilt-dip-support/src/did.rs +++ b/crates/kilt-dip-support/src/did.rs @@ -145,7 +145,7 @@ impl< _subject: &Subject, submitter: &Self::Submitter, identity_details: &mut Option, - proof: &Self::Proof, + proof: Self::Proof, ) -> Result { let block_number = BlockNumberProvider::get(); let is_signature_fresh = @@ -225,7 +225,7 @@ where subject: &Subject, submitter: &Self::Submitter, identity_details: &mut Option, - proof: &Self::Proof, + proof: Self::Proof, ) -> Result { let did_signing_key = DidSignatureVerifier::verify_proof_for_call_against_details( call, diff --git a/crates/kilt-dip-support/src/lib.rs b/crates/kilt-dip-support/src/lib.rs index 106ccc7e64..fa9b6cb68e 100644 --- a/crates/kilt-dip-support/src/lib.rs +++ b/crates/kilt-dip-support/src/lib.rs @@ -20,14 +20,28 @@ #![cfg_attr(not(feature = "std"), no_std)] -use parity_scale_codec::{Decode, HasCompact}; -use sp_core::{Get, U256}; -use sp_runtime::traits::Hash; +use frame_support::ensure; +use parity_scale_codec::{Decode, Encode, HasCompact}; +use sp_core::{ConstU32, ConstU64, Get, Hasher, U256}; +use sp_runtime::{ + traits::{CheckedSub, Hash}, + BoundedVec, SaturatedConversion, +}; use sp_std::marker::PhantomData; +use sp_trie::{verify_trie_proof, LayoutV1}; -use pallet_dip_consumer::{identity::IdentityDetails, traits::IdentityProofVerifier}; +use ::did::{ + did_details::{DidPublicKey, DidPublicKeyDetails, DidVerificationKey}, + DidVerificationKeyRelationship, +}; +use pallet_dip_consumer::traits::IdentityProofVerifier; -use crate::did::MerkleLeavesAndDidSignature; +use crate::{ + did::MerkleLeavesAndDidSignature, + merkle::{MerkleProof, ProofLeaf, RevealedDidKey, RevealedWeb3Name, VerificationResult}, + state_proofs::{parachain::ParachainStateInfoProvider, relay_chain::RelayChainStateInfoProvider}, + traits::{Bump, DidDipOriginFilter}, +}; pub mod did; pub mod merkle; @@ -42,149 +56,253 @@ pub struct DipSiblingParachainStateProof { } pub struct StateProofDipVerifier< - ProviderParaId, RelayInfoProvider, - ProviderParaInfoProvider, - DipVerifier, - LocalIdentityInfo, + ParaInfoProvider, + ProviderKeyId, + ProviderParaIdProvider, + ProviderBlockNumber, + ProviderAccountIdentityDetails, + ProviderWeb3Name, + ProviderHasher, + ProviderLinkedAccountId, + ConsumerAccountId, + ConsumerBlockNumber, + ConsumerBlockNumberProvider, + ConsumerGenesisHashProvider, + SignedExtra, + SignedExtraProvider, + CallVerifier, + const MAX_REVEALED_KEYS_COUNT: u32, + const MAX_REVEALED_ACCOUNTS_COUNT: u32, + const SIGNATURE_VALIDITY: u64, >( PhantomData<( - ProviderParaId, RelayInfoProvider, - ProviderParaInfoProvider, - DipVerifier, - LocalIdentityInfo, + ParaInfoProvider, + ProviderKeyId, + ProviderBlockNumber, + ProviderParaIdProvider, + ProviderAccountIdentityDetails, + ProviderWeb3Name, + ProviderHasher, + ProviderLinkedAccountId, + ConsumerAccountId, + ConsumerBlockNumber, + ConsumerBlockNumberProvider, + ConsumerGenesisHashProvider, + SignedExtra, + SignedExtraProvider, + CallVerifier, + ConstU32, + ConstU32, + ConstU64, )>, ); -impl - IdentityProofVerifier - for StateProofDipVerifier -where - ProviderParaId: Get, - - RelayInfoProvider: state_proofs::relay_chain::RelayChainStateInfoProvider, +impl< + Call, + Subject, + RelayInfoProvider, + ParaInfoProvider, + ProviderKeyId, + ProviderBlockNumber, + ProviderParaIdProvider, + ProviderAccountIdentityDetails, + ProviderWeb3Name, + ProviderHasher, + ProviderLinkedAccountId, + ConsumerAccountId, + ConsumerBlockNumber, + ConsumerBlockNumberProvider, + ConsumerGenesisHashProvider, + SignedExtra, + SignedExtraProvider, + CallVerifier, + const MAX_REVEALED_KEYS_COUNT: u32, + const MAX_REVEALED_ACCOUNTS_COUNT: u32, + const SIGNATURE_VALIDITY: u64, + > IdentityProofVerifier + for StateProofDipVerifier< + RelayInfoProvider, + ParaInfoProvider, + ProviderKeyId, + ProviderBlockNumber, + ProviderParaIdProvider, + ProviderAccountIdentityDetails, + ProviderWeb3Name, + ProviderHasher, + ProviderLinkedAccountId, + ConsumerAccountId, + ConsumerBlockNumber, + ConsumerBlockNumberProvider, + ConsumerGenesisHashProvider, + SignedExtra, + SignedExtraProvider, + CallVerifier, + MAX_REVEALED_KEYS_COUNT, + MAX_REVEALED_ACCOUNTS_COUNT, + SIGNATURE_VALIDITY, + > where + RelayInfoProvider: RelayChainStateInfoProvider, RelayInfoProvider::Hasher: 'static, ::Output: Ord, RelayInfoProvider::BlockNumber: Copy + Into + TryFrom + HasCompact, RelayInfoProvider::Key: AsRef<[u8]>, - - ProviderParaInfoProvider: state_proofs::parachain::ParachainStateInfoProvider, - ProviderParaInfoProvider::Hasher: 'static, - ::Output: Ord + PartialEq<::Output>, - ProviderParaInfoProvider::Commitment: Decode, - ProviderParaInfoProvider::Key: AsRef<[u8]>, - - DipVerifier: IdentityProofVerifier< - Call, - Subject, - IdentityDetails = IdentityDetails>, - >, - - LocalIdentityInfo: Clone, + ParaInfoProvider: ParachainStateInfoProvider, + ParaInfoProvider::Hasher: 'static, + ::Output: Ord + Encode + PartialEq<::Output>, + ParaInfoProvider::Commitment: Decode, + ParaInfoProvider::Key: AsRef<[u8]>, + ProviderKeyId: Encode + Clone, + ProviderBlockNumber: Encode + Clone, + ProviderWeb3Name: Encode + Clone, + ProviderLinkedAccountId: Encode + Clone, + ProviderHasher: Hasher, + ProviderParaIdProvider: Get, + Call: Encode, + ConsumerAccountId: Encode, + ProviderAccountIdentityDetails: Encode + Bump + Default, + ConsumerBlockNumber: CheckedSub + Into + Encode, + ConsumerBlockNumberProvider: Get, + ConsumerGenesisHashProvider: Get<::Output>, + SignedExtra: Encode, + SignedExtraProvider: Get, + CallVerifier: DidDipOriginFilter, { + // TODO: Better error handling type Error = (); - type IdentityDetails = LocalIdentityInfo; - type Proof = DipSiblingParachainStateProof; - type Submitter = DipVerifier::Submitter; - type VerificationResult = DipVerifier::VerificationResult; + type IdentityDetails = ProviderAccountIdentityDetails; + type Proof = DipSiblingParachainStateProof< + MerkleLeavesAndDidSignature< + MerkleProof< + Vec>, + ProofLeaf, + >, + ConsumerBlockNumber, + >, + >; + type Submitter = ConsumerAccountId; + type VerificationResult = (DidVerificationKey, DidVerificationKeyRelationship); fn verify_proof_for_call_against_details( call: &Call, subject: &Subject, submitter: &Self::Submitter, identity_details: &mut Option, - proof: &Self::Proof, + proof: Self::Proof, ) -> Result { + let DipSiblingParachainStateProof { + para_root_proof, + dip_commitment_proof, + dip_proof, + } = proof; + // 1. Verify relay chain proof. let provider_parachain_header = state_proofs::relay_chain::ParachainHeadProofVerifier::::verify_proof_for_parachain( - &ProviderParaId::get(), - proof.para_root_proof.clone(), + &ProviderParaIdProvider::get(), + para_root_proof, )?; - let provider_parachain_root_state = provider_parachain_header.state_root; + // 2. Verify parachain state proof. debug_assert!( - ProviderParaInfoProvider::state_root() == provider_parachain_root_state, + ParaInfoProvider::state_root() == provider_parachain_header.state_root, "Provided parachain state root and calculated parachain state root do not match." ); - let subject_identity_commitment = state_proofs::parachain::DipCommitmentValueProofVerifier::< - ProviderParaInfoProvider, - >::verify_proof_for_identifier(subject, proof.dip_commitment_proof.clone())?; - let mapped_identity_details = IdentityDetails { - digest: subject_identity_commitment, - details: identity_details.clone(), - }; - DipVerifier::verify_proof_for_call_against_details( - call, - subject, - submitter, - &mut Some(mapped_identity_details), - &proof.dip_proof, - ) - .map_err(|_| ()) - } -} - -/// A type that chains a Merkle proof verification with a DID signature -/// verification. The required input of this type is a tuple (A, B) where A is -/// /// the type of input required by the `MerkleProofVerifier` and B is a -/// `DidSignature`. -/// The successful output of this type is the output type of the -/// `MerkleProofVerifier`, meaning that DID signature verification happens -/// internally and does not transform the result in any way. -pub struct MerkleProofAndDidSignatureVerifier( - PhantomData<(BlockNumber, MerkleProofVerifier, DidSignatureVerifier)>, -); - -impl IdentityProofVerifier - for MerkleProofAndDidSignatureVerifier -where - BlockNumber: Clone, - MerkleProofVerifier: IdentityProofVerifier, - // TODO: get rid of this if possible - MerkleProofVerifier::VerificationResult: Clone, - DidSignatureVerifier: IdentityProofVerifier< - Call, - Subject, - Proof = MerkleLeavesAndDidSignature, - IdentityDetails = MerkleProofVerifier::IdentityDetails, - Submitter = MerkleProofVerifier::Submitter, - >, -{ - // FIXME: Better error handling - type Error = (); - // FIXME: Better type declaration - type Proof = MerkleLeavesAndDidSignature; - type IdentityDetails = DidSignatureVerifier::IdentityDetails; - type Submitter = MerkleProofVerifier::Submitter; - type VerificationResult = MerkleProofVerifier::VerificationResult; + let subject_identity_commitment = + state_proofs::parachain::DipCommitmentValueProofVerifier::::verify_proof_for_identifier( + subject, + dip_commitment_proof, + )?; - fn verify_proof_for_call_against_details( - call: &Call, - subject: &Subject, - submitter: &Self::Submitter, - identity_details: &mut Option, - proof: &Self::Proof, - ) -> Result { - let merkle_proof_verification = MerkleProofVerifier::verify_proof_for_call_against_details( - call, - subject, - submitter, - identity_details, - &proof.merkle_leaves, + // 3. Verify DIP identity proof (taken from existing implementation). + let proof_leaves = dip_proof + .merkle_leaves + .revealed + .iter() + .map(|leaf| (leaf.encoded_key(), Some(leaf.encoded_value()))) + .collect::, Option>)>>(); + verify_trie_proof::, _, _, _>( + &subject_identity_commitment, + &dip_proof.merkle_leaves.blinded, + &proof_leaves, ) .map_err(|_| ())?; - DidSignatureVerifier::verify_proof_for_call_against_details( + let (did_keys, web3_name, linked_accounts): ( + BoundedVec, ConstU32>, + Option>, + BoundedVec>, + ) = dip_proof.merkle_leaves.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 { + 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, linked_accounts)) + } + // TODO: Avoid cloning if possible + 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)) + } + }, + )?; + let verification_result = VerificationResult { + did_keys, + web3_name, + linked_accounts, + }; + + // 4. Verify DID signature (taken from existing implementation). + let block_number = ConsumerBlockNumberProvider::get(); + let is_signature_fresh = + if let Some(blocks_ago_from_now) = block_number.checked_sub(&dip_proof.did_signature.block_number) { + blocks_ago_from_now.into() <= SIGNATURE_VALIDITY + } else { + false + }; + ensure!(is_signature_fresh, ()); + let encoded_payload = ( call, - subject, + &identity_details, submitter, - identity_details, - // FIXME: Remove `clone()` requirement - &MerkleLeavesAndDidSignature { - merkle_leaves: merkle_proof_verification.clone(), - did_signature: proof.did_signature.clone(), - }, + &dip_proof.did_signature.block_number, + ConsumerGenesisHashProvider::get(), + SignedExtraProvider::get(), ) - .map_err(|_| ())?; - Ok(merkle_proof_verification) + .encode(); + let mut proof_verification_keys = verification_result.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, &dip_proof.did_signature.signature) + .is_ok() + }); + let Some((key, relationship)) = valid_signing_key else { return Err(()) }; + if let Some(details) = identity_details { + details.bump(); + } else { + *identity_details = Some(Self::IdentityDetails::default()); + } + // 4.1 Verify call required relationship + CallVerifier::check_call_origin_info(call, &(key.clone(), relationship)).map_err(|_| ())?; + Ok((key.clone(), relationship)) } } diff --git a/crates/kilt-dip-support/src/merkle.rs b/crates/kilt-dip-support/src/merkle.rs index b91784fb69..f77c78381e 100644 --- a/crates/kilt-dip-support/src/merkle.rs +++ b/crates/kilt-dip-support/src/merkle.rs @@ -86,7 +86,7 @@ impl From for Web3NameMerkleKey { } } #[derive(Clone, Encode, Decode, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug, TypeInfo)] -pub struct Web3NameMerkleValue(BlockNumber); +pub struct Web3NameMerkleValue(pub BlockNumber); impl From for Web3NameMerkleValue { fn from(value: BlockNumber) -> Self { @@ -276,7 +276,7 @@ impl< _subject: &Subject, _submitter: &Self::Submitter, identity_details: &mut Option, - proof: &Self::Proof, + proof: Self::Proof, ) -> Result { // TODO: more efficient by removing cloning and/or collecting. // Did not find another way of mapping a Vec<(Vec, Vec)> to a diff --git a/pallets/pallet-dip-consumer/src/lib.rs b/pallets/pallet-dip-consumer/src/lib.rs index ec27c77943..751dc24184 100644 --- a/pallets/pallet-dip-consumer/src/lib.rs +++ b/pallets/pallet-dip-consumer/src/lib.rs @@ -125,7 +125,7 @@ pub mod pallet { &identifier, &submitter, &mut identity_entry, - &proof, + proof, ); // Write the identity info to storage after it has optionally been updated by // the `ProofVerifier`, regardless of whether the proof has been verified or diff --git a/pallets/pallet-dip-consumer/src/traits.rs b/pallets/pallet-dip-consumer/src/traits.rs index f65d89542e..0b7fa2a85c 100644 --- a/pallets/pallet-dip-consumer/src/traits.rs +++ b/pallets/pallet-dip-consumer/src/traits.rs @@ -30,7 +30,7 @@ pub trait IdentityProofVerifier { subject: &Subject, submitter: &Self::Submitter, identity_details: &mut Option, - proof: &Self::Proof, + proof: Self::Proof, ) -> Result; } @@ -50,7 +50,7 @@ impl IdentityProofVerifier, - _proof: &Self::Proof, + _proof: Self::Proof, ) -> Result { Ok(()) } From 16b1bc9692005b01c3f4e1cc06215246b3e4c1fa Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Thu, 13 Jul 2023 16:49:56 +0200 Subject: [PATCH 13/32] Whole workspace compiling (not run/tested yet) --- Cargo.lock | 2 + crates/kilt-dip-support/Cargo.toml | 12 ++- crates/kilt-dip-support/src/lib.rs | 55 +++++++------ crates/kilt-dip-support/src/state_proofs.rs | 33 ++------ crates/kilt-dip-support/src/traits.rs | 78 ++++++++++++++++++- dip-template/runtimes/dip-consumer/src/dip.rs | 54 +++++++------ pallets/pallet-dip-provider/src/lib.rs | 2 +- 7 files changed, 158 insertions(+), 78 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bb08917c8a..9b302580e7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4195,6 +4195,7 @@ dependencies = [ name = "kilt-dip-support" version = "1.11.0-dev" dependencies = [ + "cumulus-pallet-parachain-system", "did", "dip-support", "frame-support", @@ -4204,6 +4205,7 @@ dependencies = [ "pallet-dip-consumer", "pallet-dip-provider", "parity-scale-codec", + "rococo-runtime", "scale-info", "sp-core", "sp-io", diff --git a/crates/kilt-dip-support/Cargo.toml b/crates/kilt-dip-support/Cargo.toml index 1fb1776956..cbe58dd520 100644 --- a/crates/kilt-dip-support/Cargo.toml +++ b/crates/kilt-dip-support/Cargo.toml @@ -29,14 +29,19 @@ frame-system.workspace = true frame-support.workspace = true sp-runtime.workspace = true sp-core.workspace = true +sp-io.workspace = true sp-state-machine.workspace = true sp-std.workspace = true sp-trie.workspace = true # Polkadot dependencies +rococo-runtime.workspace = true xcm.workspace = true xcm-executor.workspace = true +# Cumulus dependencies +cumulus-pallet-parachain-system.workspace = true + [dev-dependencies] hex-literal.workspace = true sp-io = { workspace = true, features = ["std"] } @@ -55,10 +60,13 @@ std = [ "frame-support/std", "sp-runtime/std", "sp-core/std", + "sp-io/std", "sp-state-machine/std", - "sp-trie/std", "sp-std/std", + "sp-trie/std", + "rococo-runtime/std", + "xcm/std", "xcm-executor/std", - "xcm/std" + "cumulus-pallet-parachain-system/std", ] runtime-benchmarks = [] diff --git a/crates/kilt-dip-support/src/lib.rs b/crates/kilt-dip-support/src/lib.rs index fa9b6cb68e..b57453ace0 100644 --- a/crates/kilt-dip-support/src/lib.rs +++ b/crates/kilt-dip-support/src/lib.rs @@ -22,12 +22,13 @@ use frame_support::ensure; use parity_scale_codec::{Decode, Encode, HasCompact}; -use sp_core::{ConstU32, ConstU64, Get, Hasher, U256}; +use scale_info::TypeInfo; +use sp_core::{ConstU32, ConstU64, Get, Hasher, RuntimeDebug, U256}; use sp_runtime::{ traits::{CheckedSub, Hash}, BoundedVec, SaturatedConversion, }; -use sp_std::marker::PhantomData; +use sp_std::{marker::PhantomData, vec::Vec}; use sp_trie::{verify_trie_proof, LayoutV1}; use ::did::{ @@ -39,8 +40,7 @@ use pallet_dip_consumer::traits::IdentityProofVerifier; use crate::{ did::MerkleLeavesAndDidSignature, merkle::{MerkleProof, ProofLeaf, RevealedDidKey, RevealedWeb3Name, VerificationResult}, - state_proofs::{parachain::ParachainStateInfoProvider, relay_chain::RelayChainStateInfoProvider}, - traits::{Bump, DidDipOriginFilter}, + traits::{Bump, DidDipOriginFilter, ParachainStateInfoProvider, RelayChainStateInfoProvider}, }; pub mod did; @@ -48,7 +48,7 @@ pub mod merkle; pub mod state_proofs; pub mod traits; -#[derive(Clone)] +#[derive(Encode, Decode, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug, TypeInfo, Clone)] pub struct DipSiblingParachainStateProof { para_root_proof: Vec>, dip_commitment_proof: Vec>, @@ -69,19 +69,20 @@ pub struct StateProofDipVerifier< ConsumerBlockNumber, ConsumerBlockNumberProvider, ConsumerGenesisHashProvider, - SignedExtra, - SignedExtraProvider, CallVerifier, const MAX_REVEALED_KEYS_COUNT: u32, const MAX_REVEALED_ACCOUNTS_COUNT: u32, const SIGNATURE_VALIDITY: u64, + SignedExtra = (), + SignedExtraProvider = (), >( + #[allow(clippy::type_complexity)] PhantomData<( RelayInfoProvider, ParaInfoProvider, ProviderKeyId, - ProviderBlockNumber, ProviderParaIdProvider, + ProviderBlockNumber, ProviderAccountIdentityDetails, ProviderWeb3Name, ProviderHasher, @@ -90,12 +91,12 @@ pub struct StateProofDipVerifier< ConsumerBlockNumber, ConsumerBlockNumberProvider, ConsumerGenesisHashProvider, - SignedExtra, - SignedExtraProvider, CallVerifier, ConstU32, ConstU32, ConstU64, + SignedExtra, + SignedExtraProvider, )>, ); @@ -105,8 +106,8 @@ impl< RelayInfoProvider, ParaInfoProvider, ProviderKeyId, - ProviderBlockNumber, ProviderParaIdProvider, + ProviderBlockNumber, ProviderAccountIdentityDetails, ProviderWeb3Name, ProviderHasher, @@ -115,19 +116,19 @@ impl< ConsumerBlockNumber, ConsumerBlockNumberProvider, ConsumerGenesisHashProvider, - SignedExtra, - SignedExtraProvider, CallVerifier, const MAX_REVEALED_KEYS_COUNT: u32, const MAX_REVEALED_ACCOUNTS_COUNT: u32, const SIGNATURE_VALIDITY: u64, + SignedExtra, + SignedExtraProvider, > IdentityProofVerifier for StateProofDipVerifier< RelayInfoProvider, ParaInfoProvider, ProviderKeyId, - ProviderBlockNumber, ProviderParaIdProvider, + ProviderBlockNumber, ProviderAccountIdentityDetails, ProviderWeb3Name, ProviderHasher, @@ -136,12 +137,12 @@ impl< ConsumerBlockNumber, ConsumerBlockNumberProvider, ConsumerGenesisHashProvider, - SignedExtra, - SignedExtraProvider, CallVerifier, MAX_REVEALED_KEYS_COUNT, MAX_REVEALED_ACCOUNTS_COUNT, SIGNATURE_VALIDITY, + SignedExtra, + SignedExtraProvider, > where RelayInfoProvider: RelayChainStateInfoProvider, RelayInfoProvider::Hasher: 'static, @@ -150,7 +151,10 @@ impl< RelayInfoProvider::Key: AsRef<[u8]>, ParaInfoProvider: ParachainStateInfoProvider, ParaInfoProvider::Hasher: 'static, - ::Output: Ord + Encode + PartialEq<::Output>, + ::Output: Ord + + Encode + + PartialEq<::Output> + + From<::Output>, ParaInfoProvider::Commitment: Decode, ParaInfoProvider::Key: AsRef<[u8]>, ProviderKeyId: Encode + Clone, @@ -182,7 +186,14 @@ impl< >, >; type Submitter = ConsumerAccountId; - type VerificationResult = (DidVerificationKey, DidVerificationKeyRelationship); + type VerificationResult = VerificationResult< + ProviderKeyId, + ProviderBlockNumber, + ProviderWeb3Name, + ProviderLinkedAccountId, + MAX_REVEALED_KEYS_COUNT, + MAX_REVEALED_ACCOUNTS_COUNT, + >; fn verify_proof_for_call_against_details( call: &Call, @@ -203,13 +214,10 @@ impl< para_root_proof, )?; // 2. Verify parachain state proof. - debug_assert!( - ParaInfoProvider::state_root() == provider_parachain_header.state_root, - "Provided parachain state root and calculated parachain state root do not match." - ); let subject_identity_commitment = state_proofs::parachain::DipCommitmentValueProofVerifier::::verify_proof_for_identifier( subject, + provider_parachain_header.state_root.into(), dip_commitment_proof, )?; @@ -226,6 +234,7 @@ impl< &proof_leaves, ) .map_err(|_| ())?; + #[allow(clippy::type_complexity)] let (did_keys, web3_name, linked_accounts): ( BoundedVec, ConstU32>, Option>, @@ -303,6 +312,6 @@ impl< } // 4.1 Verify call required relationship CallVerifier::check_call_origin_info(call, &(key.clone(), relationship)).map_err(|_| ())?; - Ok((key.clone(), relationship)) + Ok(verification_result) } } diff --git a/crates/kilt-dip-support/src/state_proofs.rs b/crates/kilt-dip-support/src/state_proofs.rs index 26c47aa57c..8b57b907a9 100644 --- a/crates/kilt-dip-support/src/state_proofs.rs +++ b/crates/kilt-dip-support/src/state_proofs.rs @@ -86,15 +86,7 @@ mod substrate_no_std_port { pub mod relay_chain { use super::*; - pub trait RelayChainStateInfoProvider { - type BlockNumber; - type Key; - type Hasher: Hash; - type ParaId; - - fn parachain_head_storage_key(para_id: &Self::ParaId) -> Self::Key; - fn state_root() -> ::Output; - } + use crate::traits::RelayChainStateInfoProvider; pub struct ParachainHeadProofVerifier(PhantomData); @@ -197,15 +189,7 @@ pub mod relay_chain { pub mod parachain { use super::*; - pub trait ParachainStateInfoProvider { - type Commitment; - type Key; - type Hasher: Hash; - type Identifier; - - fn dip_subject_storage_key(identifier: &Self::Identifier) -> Self::Key; - fn state_root() -> ::Output; - } + use crate::traits::ParachainStateInfoProvider; pub struct DipCommitmentValueProofVerifier(PhantomData); @@ -220,13 +204,13 @@ pub mod parachain { #[allow(clippy::result_unit_err)] pub fn verify_proof_for_identifier( identifier: &ParaInfoProvider::Identifier, + state_root: ::Output, proof: impl IntoIterator>, ) -> Result { - let parachain_state_root = ParaInfoProvider::state_root(); let dip_commitment_storage_key = ParaInfoProvider::dip_subject_storage_key(identifier); let storage_proof = StorageProof::new(proof); let revealed_leaves = read_proof_check::( - parachain_state_root, + state_root, storage_proof, [&dip_commitment_storage_key].iter(), ) @@ -244,7 +228,7 @@ pub mod parachain { use super::*; use hex_literal::hex; - use sp_core::storage::StorageKey; + use sp_core::{storage::StorageKey, H256}; use sp_runtime::traits::BlakeTwo256; // Spiritnet block n: 4_184_668, @@ -265,10 +249,6 @@ pub mod parachain { let storage_key = hex!("26aa394eea5630e07c48ae0c9558cef70a98fdbe9ce6c55837576c60c7af3850").to_vec(); StorageKey(storage_key) } - - fn state_root() -> ::Output { - hex!("94c23fda279cea4a4370e90f1544c8938923dfd4ac201a420c7a26fb0d3caf8c").into() - } } #[test] @@ -282,6 +262,8 @@ pub mod parachain { hex!("80ffff8010623b5a3a9dbc752963d827be0bb855bf3e24258ae09341d5f762e96a836ac180c34b753605e821528756b55b4ddafb742df6e54fbc03ef401d4ebfd6dd4f3e44806f83646e0bf3ca0ac9f2092dea5b0e3caf210cc6b54c3b44a51855a133367a6580b02cde7b1fd3f8d13f698ef6e9daa29b32258d4d97a8947051070a4540aecacd80903d521961849d07ceee132617b8dde96c3ff472f5a9a089d4055ffe7ffd1e988016c29c943c106713bb8f16b776eb7daed005540165696da286cddf6b25d085448019a464010cb746b0589891f72b0eed603d4712b04af46f7bcae724564194801480a305ffe069db7eb21841f75b5939943f62c4abb3a051d530839c5dd935ccbc8a8035d8938b0c856878de1e3fe45a559588b2da52ccf195ab1e3d0aca6ac7bb079d8064019a474a283c19f46ff4652a5e1f636efd4013d3b8a91c49573045c6ff01c0801a191dcb736faddb84889a13c7aa717d260e9b635b30a9eb3907f925a2253d6880f8bc389fc62ca951609bae208b7506bae497623e647424062d1c56cb1f2d2e1c80211a9fb5f8b794f9fbfbdcd4519aa475ecaf9737b4ee513dde275d5fbbe64da080c267d0ead99634e9b9cfbf61a583877e0241ac518e62e909fbb017469de275f780b3059a7226d4b320c25e9b2f8ffe19cf93467e3b306885962c5f34b5671d15fe8092dfba9e30e1bbefab13c792755d06927e6141f7220b7485e5aa40de92401a66").to_vec(), hex!("9eaa394eea5630e07c48ae0c9558cef7398f8069ef420a0deb5a428c9a08563b28a78874bba09124eecc8d28bf30b0e2ddd310745f04abf5cb34d6244378cddbf18e849d962c000000000736d8e8140100505f0e7b9012096b41c4eb3aaf947f6ea4290800004c5f0684a022a34dd8bfa2baaf44f172b710040180dd3270a03a1a13fc20bcdf24d1aa4ddccc6183db2e2e153b8a68ba8540699a8a80b413dad63538a591f7f2575d287520ee44d7143aa5ec2411969861e1f55a2989804c3f0f541a13980689894db7c60c785dd29e066f213bb29b17aa740682ad7efd8026d3a50544f5c89500745aca2be36cfe076f599c5115192fb9deae227e2710c980bd04b00bf6b42756a06a4fbf05a5231c2094e48182eca95d2cff73ab907592aa").to_vec(), ].to_vec(); + let spiritnet_state_root: H256 = + hex!("94c23fda279cea4a4370e90f1544c8938923dfd4ac201a420c7a26fb0d3caf8c").into(); // As of query system::eventCount() at block // "0x2c0746e7e9ccc6e4d27bcb4118cb6821ae53ae9bf372f4f49ac28d8598f9bed5" which // results in the key @@ -290,6 +272,7 @@ pub mod parachain { let returned_event_count = DipCommitmentValueProofVerifier::::verify_proof_for_identifier( &(), + spiritnet_state_root, spiritnet_event_count_proof_at_block, ) .unwrap(); diff --git a/crates/kilt-dip-support/src/traits.rs b/crates/kilt-dip-support/src/traits.rs index 66417991e8..2cd610ea97 100644 --- a/crates/kilt-dip-support/src/traits.rs +++ b/crates/kilt-dip-support/src/traits.rs @@ -16,8 +16,9 @@ // If you feel like getting in touch with us, you can do so at info@botlabs.org -use sp_core::Get; -use sp_runtime::traits::{CheckedAdd, One, Zero}; +use parity_scale_codec::Encode; +use sp_core::{storage::StorageKey, Get}; +use sp_runtime::traits::{BlakeTwo256, CheckedAdd, One, Zero}; use sp_std::marker::PhantomData; // TODO: Switch to the `Incrementable` trait once it's added to the root of @@ -75,3 +76,76 @@ where frame_system::Pallet::::block_number() } } + +pub trait RelayChainStateInfoProvider { + type BlockNumber; + type Key; + type Hasher: sp_runtime::traits::Hash; + type ParaId; + + fn parachain_head_storage_key(para_id: &Self::ParaId) -> Self::Key; + fn state_root() -> ::Output; +} + +pub struct RococoParachainRuntime(PhantomData); + +impl RelayChainStateInfoProvider for RococoParachainRuntime +where + Runtime: cumulus_pallet_parachain_system::Config, +{ + type BlockNumber = u64; + // TODO: This is not exported + type Hasher = BlakeTwo256; + type Key = StorageKey; + type ParaId = u32; + + fn state_root() -> ::Output { + let Some(validation_data) = cumulus_pallet_parachain_system::Pallet::::validation_data() else { panic!("Parent validation data should always be set."); }; + validation_data.relay_parent_storage_root + } + + fn parachain_head_storage_key(para_id: &Self::ParaId) -> Self::Key { + // TODO: It's not possible to access the runtime definition from here. + let encoded_para_id = para_id.encode(); + let storage_key = [ + frame_support::storage::storage_prefix(b"Paras", b"Heads").as_slice(), + sp_io::hashing::twox_64(&encoded_para_id).as_slice(), + encoded_para_id.as_slice(), + ] + .concat(); + StorageKey(storage_key) + } +} + +pub trait ParachainStateInfoProvider { + type Commitment; + type Key; + type Hasher: sp_runtime::traits::Hash; + type Identifier; + + fn dip_subject_storage_key(identifier: &Self::Identifier) -> Self::Key; +} + +pub struct DipProviderParachainRuntime(PhantomData); + +impl ParachainStateInfoProvider for DipProviderParachainRuntime +where + Runtime: pallet_dip_provider::Config, +{ + type Commitment = ::IdentityCommitment; + type Hasher = ::Hashing; + type Identifier = ::Identifier; + type Key = StorageKey; + + fn dip_subject_storage_key(identifier: &Self::Identifier) -> Self::Key { + // TODO: Replace with actual runtime definition + let encoded_identifier = identifier.encode(); + let storage_key = [ + frame_support::storage::storage_prefix(b"DipProvider", b"IdentityCommitments").as_slice(), + sp_io::hashing::twox_64(&encoded_identifier).as_slice(), + encoded_identifier.as_slice(), + ] + .concat(); + StorageKey(storage_key) + } +} diff --git a/dip-template/runtimes/dip-consumer/src/dip.rs b/dip-template/runtimes/dip-consumer/src/dip.rs index 2df1d76d81..71842d7bcb 100644 --- a/dip-template/runtimes/dip-consumer/src/dip.rs +++ b/dip-template/runtimes/dip-consumer/src/dip.rs @@ -17,51 +17,55 @@ // 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 dip_provider_runtime_template::{BlockNumber as ProviderBlockNumber, Web3Name}; use frame_support::traits::Contains; use kilt_dip_support::{ - did::{DidSignatureAndCallVerifier, MerkleLeavesAndDidSignature, MerkleRevealedDidSignatureVerifier}, - merkle::{DidMerkleProofVerifier, MerkleProof, ProofLeaf}, - traits::{BlockNumberProvider, DidDipOriginFilter, GenesisProvider}, - MerkleProofAndDidSignatureVerifier, + did::MerkleLeavesAndDidSignature, + merkle::{MerkleProof, ProofLeaf}, + traits::{ + BlockNumberProvider, DidDipOriginFilter, DipProviderParachainRuntime, GenesisProvider, RococoParachainRuntime, + }, + DipSiblingParachainStateProof, StateProofDipVerifier, }; use pallet_did_lookup::linkable_account::LinkableAccountId; -use pallet_dip_consumer::traits::IdentityProofVerifier; +use sp_core::ConstU32; +use sp_runtime::traits::BlakeTwo256; use sp_std::vec::Vec; -use crate::{AccountId, BlockNumber, DidIdentifier, Hash, Hasher, Runtime, RuntimeCall, RuntimeOrigin}; +use crate::{AccountId, BlockNumber, DidIdentifier, Hash, Runtime, RuntimeCall, RuntimeOrigin}; -pub type MerkleProofVerifier = - DidMerkleProofVerifier, BlockNumber, u128, Web3Name, LinkableAccountId, 10, 10>; -pub type MerkleProofVerifierOutputOf = - >::VerificationResult; -pub type MerkleDidSignatureVerifierOf = MerkleRevealedDidSignatureVerifier< +pub type ProofVerifier = StateProofDipVerifier< + RococoParachainRuntime, + DipProviderParachainRuntime, KeyIdOf, - BlockNumber, - Hash, + ConstU32<2_000>, + ProviderBlockNumber, u128, + Web3Name, + BlakeTwo256, + LinkableAccountId, AccountId, - MerkleProofVerifierOutputOf, + BlockNumber, BlockNumberProvider, + GenesisProvider, + DipCallFilter, + 10, + 10, // Signatures are valid for 50 blocks 50, - GenesisProvider, - Hash, >; impl pallet_dip_consumer::Config for Runtime { type DipCallOriginFilter = PreliminaryDipOriginFilter; type Identifier = DidIdentifier; - type IdentityProof = MerkleLeavesAndDidSignature< - MerkleProof>, ProofLeaf>, - BlockNumber, + type IdentityProof = DipSiblingParachainStateProof< + MerkleLeavesAndDidSignature< + MerkleProof>, ProofLeaf>, + BlockNumber, + >, >; type LocalIdentityInfo = u128; - type ProofVerifier = MerkleProofAndDidSignatureVerifier< - BlockNumber, - MerkleProofVerifier, - DidSignatureAndCallVerifier, DipCallFilter>, - >; + type ProofVerifier = ProofVerifier; type RuntimeCall = RuntimeCall; type RuntimeOrigin = RuntimeOrigin; } diff --git a/pallets/pallet-dip-provider/src/lib.rs b/pallets/pallet-dip-provider/src/lib.rs index 8af729b79f..fd13d11a5a 100644 --- a/pallets/pallet-dip-provider/src/lib.rs +++ b/pallets/pallet-dip-provider/src/lib.rs @@ -56,7 +56,7 @@ pub mod pallet { #[pallet::storage] #[pallet::getter(fn identity_commitments)] - pub(crate) type IdentityCommitments = + pub type IdentityCommitments = StorageMap<_, Twox64Concat, ::Identifier, ::IdentityCommitment>; #[pallet::pallet] From 47481e0d0fbf3ddbadbac8b25d5419d8788c62dc Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Fri, 14 Jul 2023 16:38:14 +0200 Subject: [PATCH 14/32] Keep track of the last 2 relay state roots to allow for proof creation --- Cargo.lock | 2 ++ crates/kilt-dip-support/src/state_proofs.rs | 22 +++++++++++----- crates/kilt-dip-support/src/traits.rs | 10 +++---- pallets/pallet-dip-consumer/Cargo.toml | 5 ++++ pallets/pallet-dip-consumer/src/lib.rs | 29 +++++++++++++++++++++ 5 files changed, 56 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9b302580e7..050375b1ea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6251,11 +6251,13 @@ dependencies = [ name = "pallet-dip-consumer" version = "1.11.0-dev" dependencies = [ + "cumulus-pallet-parachain-system", "frame-support", "frame-system", "kilt-support", "parity-scale-codec", "scale-info", + "sp-core", "sp-std", ] diff --git a/crates/kilt-dip-support/src/state_proofs.rs b/crates/kilt-dip-support/src/state_proofs.rs index 8b57b907a9..47b2a81fd8 100644 --- a/crates/kilt-dip-support/src/state_proofs.rs +++ b/crates/kilt-dip-support/src/state_proofs.rs @@ -103,15 +103,23 @@ pub mod relay_chain { para_id: &RelayInfoProvider::ParaId, proof: impl IntoIterator>, ) -> Result, ()> { - let relay_state_root = RelayInfoProvider::state_root(); + let relay_state_roots = + RelayInfoProvider::valid_state_roots::::Output>>(); let parachain_storage_key = RelayInfoProvider::parachain_head_storage_key(para_id); let storage_proof = StorageProof::new(proof); - let revealed_leaves = read_proof_check::( - relay_state_root, - storage_proof, - [¶chain_storage_key].iter(), - ) - .map_err(|_| ())?; + let revealed_leaves = relay_state_roots + .into_iter() + .find_map( + |root: <::Hasher as Hash>::Output| { + let Ok(revealed_leaves) = read_proof_check::( + root, + storage_proof.clone(), + [¶chain_storage_key].iter(), + ) else { return None }; + Some(revealed_leaves) + }, + ) + .ok_or(())?; // TODO: Remove at some point debug_assert!(revealed_leaves.len() == 1usize); debug_assert!(revealed_leaves.contains_key(parachain_storage_key.as_ref())); diff --git a/crates/kilt-dip-support/src/traits.rs b/crates/kilt-dip-support/src/traits.rs index 2cd610ea97..2b30026f5d 100644 --- a/crates/kilt-dip-support/src/traits.rs +++ b/crates/kilt-dip-support/src/traits.rs @@ -84,14 +84,14 @@ pub trait RelayChainStateInfoProvider { type ParaId; fn parachain_head_storage_key(para_id: &Self::ParaId) -> Self::Key; - fn state_root() -> ::Output; + fn valid_state_roots::Output>>() -> I; } pub struct RococoParachainRuntime(PhantomData); impl RelayChainStateInfoProvider for RococoParachainRuntime where - Runtime: cumulus_pallet_parachain_system::Config, + Runtime: pallet_dip_consumer::Config, { type BlockNumber = u64; // TODO: This is not exported @@ -99,9 +99,9 @@ where type Key = StorageKey; type ParaId = u32; - fn state_root() -> ::Output { - let Some(validation_data) = cumulus_pallet_parachain_system::Pallet::::validation_data() else { panic!("Parent validation data should always be set."); }; - validation_data.relay_parent_storage_root + fn valid_state_roots::Output>>() -> I { + let Some((previous, last, _)) = pallet_dip_consumer::Pallet::::latest_relay_roots() else { return I::from_iter([].into_iter()) }; + I::from_iter([previous, last].into_iter()) } fn parachain_head_storage_key(para_id: &Self::ParaId) -> Self::Key { diff --git a/pallets/pallet-dip-consumer/Cargo.toml b/pallets/pallet-dip-consumer/Cargo.toml index b681182749..e937165d97 100644 --- a/pallets/pallet-dip-consumer/Cargo.toml +++ b/pallets/pallet-dip-consumer/Cargo.toml @@ -14,24 +14,29 @@ version.workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] +cumulus-pallet-parachain-system.workspace = true frame-support.workspace = true frame-system.workspace = true kilt-support.workspace = true parity-scale-codec = {workspace = true, features = ["derive"]} scale-info = {workspace = true, features = ["derive"]} +sp-core.workspace = true sp-std.workspace = true [features] default = ["std"] std = [ + "cumulus-pallet-parachain-system/std", "frame-support/std", "frame-system/std", "kilt-support/std", "parity-scale-codec/std", "scale-info/std", + "sp-core/std", "sp-std/std", ] runtime-benchmarks = [ + "cumulus-pallet-parachain-system/runtime-benchmarks", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", ] diff --git a/pallets/pallet-dip-consumer/src/lib.rs b/pallets/pallet-dip-consumer/src/lib.rs index 751dc24184..9af9713e3e 100644 --- a/pallets/pallet-dip-consumer/src/lib.rs +++ b/pallets/pallet-dip-consumer/src/lib.rs @@ -35,6 +35,7 @@ pub mod pallet { use frame_system::pallet_prelude::*; use parity_scale_codec::{FullCodec, MaxEncodedLen}; use scale_info::TypeInfo; + use sp_core::H256; use sp_std::boxed::Box; use crate::traits::IdentityProofVerifier; @@ -51,6 +52,10 @@ pub mod pallet { pub(crate) type IdentityEntries = StorageMap<_, Twox64Concat, ::Identifier, ::LocalIdentityInfo>; + #[pallet::storage] + #[pallet::getter(fn latest_relay_roots)] + pub(crate) type LatestRelayStateRoots = StorageValue<_, (H256, H256, bool), OptionQuery>; + #[pallet::config] pub trait Config: frame_system::Config { /// Preliminary filter to filter out calls before doing any heavier @@ -96,6 +101,30 @@ pub mod pallet { Dispatch, } + #[pallet::hooks] + impl Hooks> for Pallet + where + T: cumulus_pallet_parachain_system::Config, + { + fn on_initialize(_n: BlockNumberFor) -> Weight { + // Reserve weight to update the last relay state root + ::DbWeight::get().writes(1) + } + fn on_finalize(_n: BlockNumberFor) { + // Called before the validation data is cleaned in the + // parachain_system::on_finalize hook + if let Some(new_validation_data) = cumulus_pallet_parachain_system::Pallet::::validation_data() { + // TODO: Add test cases + let new_entry = match LatestRelayStateRoots::::get() { + Some((first, _, true)) => (first, new_validation_data.relay_parent_storage_root, false), + Some((_, second, false)) => (new_validation_data.relay_parent_storage_root, second, true), + None => (new_validation_data.relay_parent_storage_root, H256::default(), true), + }; + LatestRelayStateRoots::::set(Some(new_entry)); + } + } + } + /// The origin this pallet creates after a user has provided a valid /// identity proof to dispatch other calls. #[pallet::origin] From 50edc7b9b620ea5d384c8146eb0e2c5eba0aeb27 Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Mon, 17 Jul 2023 16:41:57 +0200 Subject: [PATCH 15/32] Compiles --- Cargo.lock | 18 ++- Cargo.toml | 1 + crates/kilt-dip-support/Cargo.toml | 2 + crates/kilt-dip-support/src/lib.rs | 14 ++- crates/kilt-dip-support/src/state_proofs.rs | 33 +++--- crates/kilt-dip-support/src/traits.rs | 14 ++- dip-template/runtimes/dip-consumer/Cargo.toml | 2 + dip-template/runtimes/dip-consumer/src/dip.rs | 7 +- dip-template/runtimes/dip-consumer/src/lib.rs | 1 + pallets/pallet-dip-consumer/Cargo.toml | 3 - pallets/pallet-dip-consumer/src/lib.rs | 29 ----- pallets/pallet-relay-store/Cargo.toml | 42 +++++++ pallets/pallet-relay-store/src/lib.rs | 105 ++++++++++++++++++ pallets/pallet-relay-store/src/relay.rs | 27 +++++ 14 files changed, 238 insertions(+), 60 deletions(-) create mode 100644 pallets/pallet-relay-store/Cargo.toml create mode 100644 pallets/pallet-relay-store/src/lib.rs create mode 100644 pallets/pallet-relay-store/src/relay.rs diff --git a/Cargo.lock b/Cargo.lock index 050375b1ea..aeeb72ad95 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2354,6 +2354,7 @@ dependencies = [ "pallet-collator-selection", "pallet-did-lookup", "pallet-dip-consumer", + "pallet-relay-store", "pallet-session", "pallet-sudo", "pallet-timestamp", @@ -4204,6 +4205,7 @@ dependencies = [ "hex-literal", "pallet-dip-consumer", "pallet-dip-provider", + "pallet-relay-store", "parity-scale-codec", "rococo-runtime", "scale-info", @@ -6251,7 +6253,6 @@ dependencies = [ name = "pallet-dip-consumer" version = "1.11.0-dev" dependencies = [ - "cumulus-pallet-parachain-system", "frame-support", "frame-system", "kilt-support", @@ -6676,6 +6677,21 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-relay-store" +version = "1.11.0-dev" +dependencies = [ + "cumulus-pallet-parachain-system", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-runtime", + "sp-std", +] + [[package]] name = "pallet-scheduler" version = "4.0.0-dev" diff --git a/Cargo.toml b/Cargo.toml index 02c612b42f..92462e74c7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -56,6 +56,7 @@ pallet-dip-consumer = {path = "pallets/pallet-dip-consumer", default-features = pallet-dip-provider = {path = "pallets/pallet-dip-provider", default-features = false} pallet-did-lookup = {path = "pallets/pallet-did-lookup", default-features = false} pallet-inflation = {path = "pallets/pallet-inflation", default-features = false} +pallet-relay-store = {path = "pallets/pallet-relay-store", default-features = false} pallet-web3-names = {path = "pallets/pallet-web3-names", default-features = false} parachain-staking = {path = "pallets/parachain-staking", default-features = false} public-credentials = {path = "pallets/public-credentials", default-features = false} diff --git a/crates/kilt-dip-support/Cargo.toml b/crates/kilt-dip-support/Cargo.toml index cbe58dd520..eb6708a526 100644 --- a/crates/kilt-dip-support/Cargo.toml +++ b/crates/kilt-dip-support/Cargo.toml @@ -19,6 +19,7 @@ did.workspace = true dip-support.workspace = true pallet-dip-consumer.workspace = true pallet-dip-provider.workspace = true +pallet-relay-store.workspace = true # Parity dependencies parity-scale-codec = {workspace = true, features = ["derive"]} @@ -54,6 +55,7 @@ std = [ "dip-support/std", "pallet-dip-consumer/std", "pallet-dip-provider/std", + "pallet-relay-store/std", "parity-scale-codec/std", "scale-info/std", "frame-system/std", diff --git a/crates/kilt-dip-support/src/lib.rs b/crates/kilt-dip-support/src/lib.rs index b57453ace0..73cff2ab8f 100644 --- a/crates/kilt-dip-support/src/lib.rs +++ b/crates/kilt-dip-support/src/lib.rs @@ -49,8 +49,14 @@ pub mod state_proofs; pub mod traits; #[derive(Encode, Decode, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug, TypeInfo, Clone)] -pub struct DipSiblingParachainStateProof { - para_root_proof: Vec>, +pub struct ParaRootProof { + relay_block_hash: RelayBlockHash, + proof: Vec>, +} + +#[derive(Encode, Decode, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug, TypeInfo, Clone)] +pub struct DipSiblingParachainStateProof { + para_root_proof: ParaRootProof, dip_commitment_proof: Vec>, dip_proof: InnerProof, } @@ -177,6 +183,7 @@ impl< type Error = (); type IdentityDetails = ProviderAccountIdentityDetails; type Proof = DipSiblingParachainStateProof< + ::Output, MerkleLeavesAndDidSignature< MerkleProof< Vec>, @@ -211,7 +218,8 @@ impl< let provider_parachain_header = state_proofs::relay_chain::ParachainHeadProofVerifier::::verify_proof_for_parachain( &ProviderParaIdProvider::get(), - para_root_proof, + ¶_root_proof.relay_block_hash, + para_root_proof.proof, )?; // 2. Verify parachain state proof. let subject_identity_commitment = diff --git a/crates/kilt-dip-support/src/state_proofs.rs b/crates/kilt-dip-support/src/state_proofs.rs index 47b2a81fd8..b99cb2543d 100644 --- a/crates/kilt-dip-support/src/state_proofs.rs +++ b/crates/kilt-dip-support/src/state_proofs.rs @@ -101,25 +101,19 @@ pub mod relay_chain { #[allow(clippy::result_unit_err)] pub fn verify_proof_for_parachain( para_id: &RelayInfoProvider::ParaId, + relay_hash: &::Output, proof: impl IntoIterator>, ) -> Result, ()> { - let relay_state_roots = - RelayInfoProvider::valid_state_roots::::Output>>(); + let relay_state_root: <::Hasher as Hash>::Output = + RelayInfoProvider::state_root_for_block(relay_hash).ok_or(())?; let parachain_storage_key = RelayInfoProvider::parachain_head_storage_key(para_id); let storage_proof = StorageProof::new(proof); - let revealed_leaves = relay_state_roots - .into_iter() - .find_map( - |root: <::Hasher as Hash>::Output| { - let Ok(revealed_leaves) = read_proof_check::( - root, - storage_proof.clone(), - [¶chain_storage_key].iter(), - ) else { return None }; - Some(revealed_leaves) - }, - ) - .ok_or(())?; + let revealed_leaves = read_proof_check::( + relay_state_root, + storage_proof, + [¶chain_storage_key].iter(), + ) + .map_err(|_| ())?; // TODO: Remove at some point debug_assert!(revealed_leaves.len() == 1usize); debug_assert!(revealed_leaves.contains_key(parachain_storage_key.as_ref())); @@ -136,7 +130,7 @@ pub mod relay_chain { use hex_literal::hex; use parity_scale_codec::Encode; - use sp_core::{storage::StorageKey, H256}; + use sp_core::storage::StorageKey; use sp_runtime::traits::BlakeTwo256; // Polkadot block n: 16_363_919, @@ -163,8 +157,10 @@ pub mod relay_chain { StorageKey(storage_key) } - fn state_root() -> H256 { - hex!("81b75d95075d16005ee0a987a3f061d3011ada919b261e9b02961b9b3725f3fd").into() + fn state_root_for_block( + _block_hash: &::Output, + ) -> Option<::Output> { + Some(hex!("81b75d95075d16005ee0a987a3f061d3011ada919b261e9b02961b9b3725f3fd").into()) } } @@ -186,6 +182,7 @@ pub mod relay_chain { let expected_spiritnet_head_at_block = hex!("65541097fb02782e14f43074f0b00e44ae8e9fe426982323ef1d329739740d37f252ff006d1156941db1bccd58ce3a1cac4f40cad91f692d94e98f501dd70081a129b69a3e2ef7e1ff84ba3d86dab4e95f2c87f6b1055ebd48519c185360eae58f05d1ea08066175726120dcdc6308000000000561757261010170ccfaf3756d1a8dd8ae5c89094199d6d32e5dd9f0920f6fe30f986815b5e701974ea0e0e0a901401f2c72e3dd8dbdf4aa55d59bf3e7021856cdb8038419eb8c").to_vec(); let returned_head = ParachainHeadProofVerifier::::verify_proof_for_parachain( &2_086, + &hex!("18e90e9aa8e3b063f60386ba1b0415111798e72d01de58b1438d620d42f58e39").into(), spiritnet_head_proof_at_block, ) .expect("Parachain head proof verification should not fail."); diff --git a/crates/kilt-dip-support/src/traits.rs b/crates/kilt-dip-support/src/traits.rs index 2b30026f5d..17abbfa5a3 100644 --- a/crates/kilt-dip-support/src/traits.rs +++ b/crates/kilt-dip-support/src/traits.rs @@ -83,15 +83,17 @@ pub trait RelayChainStateInfoProvider { type Hasher: sp_runtime::traits::Hash; type ParaId; + fn state_root_for_block( + block_hash: &::Output, + ) -> Option<::Output>; fn parachain_head_storage_key(para_id: &Self::ParaId) -> Self::Key; - fn valid_state_roots::Output>>() -> I; } pub struct RococoParachainRuntime(PhantomData); impl RelayChainStateInfoProvider for RococoParachainRuntime where - Runtime: pallet_dip_consumer::Config, + Runtime: pallet_relay_store::Config, { type BlockNumber = u64; // TODO: This is not exported @@ -99,9 +101,11 @@ where type Key = StorageKey; type ParaId = u32; - fn valid_state_roots::Output>>() -> I { - let Some((previous, last, _)) = pallet_dip_consumer::Pallet::::latest_relay_roots() else { return I::from_iter([].into_iter()) }; - I::from_iter([previous, last].into_iter()) + fn state_root_for_block( + block_hash: &::Output, + ) -> Option<::Output> { + pallet_relay_store::Pallet::::latest_relay_head_for_block(block_hash) + .map(|relay_header| relay_header.relay_parent_storage_root) } fn parachain_head_storage_key(para_id: &Self::ParaId) -> Self::Key { diff --git a/dip-template/runtimes/dip-consumer/Cargo.toml b/dip-template/runtimes/dip-consumer/Cargo.toml index b5a18965ee..8c7a9615f5 100644 --- a/dip-template/runtimes/dip-consumer/Cargo.toml +++ b/dip-template/runtimes/dip-consumer/Cargo.toml @@ -24,6 +24,7 @@ did.workspace = true kilt-dip-support.workspace = true pallet-did-lookup.workspace = true pallet-dip-consumer.workspace = true +pallet-relay-store.workspace = true runtime-common.workspace = true # Substrate @@ -84,6 +85,7 @@ std = [ "kilt-dip-support/std", "pallet-did-lookup/std", "pallet-dip-consumer/std", + "pallet-relay-store/std", "runtime-common/std", "frame-executive/std", "frame-support/std", diff --git a/dip-template/runtimes/dip-consumer/src/dip.rs b/dip-template/runtimes/dip-consumer/src/dip.rs index 71842d7bcb..21f0aeb7bd 100644 --- a/dip-template/runtimes/dip-consumer/src/dip.rs +++ b/dip-template/runtimes/dip-consumer/src/dip.rs @@ -28,7 +28,7 @@ use kilt_dip_support::{ DipSiblingParachainStateProof, StateProofDipVerifier, }; use pallet_did_lookup::linkable_account::LinkableAccountId; -use sp_core::ConstU32; +use sp_core::{ConstU32, H256}; use sp_runtime::traits::BlakeTwo256; use sp_std::vec::Vec; @@ -59,6 +59,7 @@ impl pallet_dip_consumer::Config for Runtime { type DipCallOriginFilter = PreliminaryDipOriginFilter; type Identifier = DidIdentifier; type IdentityProof = DipSiblingParachainStateProof< + H256, MerkleLeavesAndDidSignature< MerkleProof>, ProofLeaf>, BlockNumber, @@ -174,3 +175,7 @@ mod dip_call_origin_filter_tests { assert_err!(single_key_relationship(vec![did_lookup_batch_call].iter()), ()); } } + +impl pallet_relay_store::Config for Runtime { + type MaxBlocks = ConstU32<100>; +} diff --git a/dip-template/runtimes/dip-consumer/src/lib.rs b/dip-template/runtimes/dip-consumer/src/lib.rs index 9f13ffae5f..624a1d53d0 100644 --- a/dip-template/runtimes/dip-consumer/src/lib.rs +++ b/dip-template/runtimes/dip-consumer/src/lib.rs @@ -140,6 +140,7 @@ construct_runtime!( // DIP DipConsumer: pallet_dip_consumer = 40, + RelayStore: pallet_relay_store = 41, } ); diff --git a/pallets/pallet-dip-consumer/Cargo.toml b/pallets/pallet-dip-consumer/Cargo.toml index e937165d97..5025ad90dd 100644 --- a/pallets/pallet-dip-consumer/Cargo.toml +++ b/pallets/pallet-dip-consumer/Cargo.toml @@ -14,7 +14,6 @@ version.workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -cumulus-pallet-parachain-system.workspace = true frame-support.workspace = true frame-system.workspace = true kilt-support.workspace = true @@ -26,7 +25,6 @@ sp-std.workspace = true [features] default = ["std"] std = [ - "cumulus-pallet-parachain-system/std", "frame-support/std", "frame-system/std", "kilt-support/std", @@ -36,7 +34,6 @@ std = [ "sp-std/std", ] runtime-benchmarks = [ - "cumulus-pallet-parachain-system/runtime-benchmarks", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", ] diff --git a/pallets/pallet-dip-consumer/src/lib.rs b/pallets/pallet-dip-consumer/src/lib.rs index 9af9713e3e..751dc24184 100644 --- a/pallets/pallet-dip-consumer/src/lib.rs +++ b/pallets/pallet-dip-consumer/src/lib.rs @@ -35,7 +35,6 @@ pub mod pallet { use frame_system::pallet_prelude::*; use parity_scale_codec::{FullCodec, MaxEncodedLen}; use scale_info::TypeInfo; - use sp_core::H256; use sp_std::boxed::Box; use crate::traits::IdentityProofVerifier; @@ -52,10 +51,6 @@ pub mod pallet { pub(crate) type IdentityEntries = StorageMap<_, Twox64Concat, ::Identifier, ::LocalIdentityInfo>; - #[pallet::storage] - #[pallet::getter(fn latest_relay_roots)] - pub(crate) type LatestRelayStateRoots = StorageValue<_, (H256, H256, bool), OptionQuery>; - #[pallet::config] pub trait Config: frame_system::Config { /// Preliminary filter to filter out calls before doing any heavier @@ -101,30 +96,6 @@ pub mod pallet { Dispatch, } - #[pallet::hooks] - impl Hooks> for Pallet - where - T: cumulus_pallet_parachain_system::Config, - { - fn on_initialize(_n: BlockNumberFor) -> Weight { - // Reserve weight to update the last relay state root - ::DbWeight::get().writes(1) - } - fn on_finalize(_n: BlockNumberFor) { - // Called before the validation data is cleaned in the - // parachain_system::on_finalize hook - if let Some(new_validation_data) = cumulus_pallet_parachain_system::Pallet::::validation_data() { - // TODO: Add test cases - let new_entry = match LatestRelayStateRoots::::get() { - Some((first, _, true)) => (first, new_validation_data.relay_parent_storage_root, false), - Some((_, second, false)) => (new_validation_data.relay_parent_storage_root, second, true), - None => (new_validation_data.relay_parent_storage_root, H256::default(), true), - }; - LatestRelayStateRoots::::set(Some(new_entry)); - } - } - } - /// The origin this pallet creates after a user has provided a valid /// identity proof to dispatch other calls. #[pallet::origin] diff --git a/pallets/pallet-relay-store/Cargo.toml b/pallets/pallet-relay-store/Cargo.toml new file mode 100644 index 0000000000..c5398f052f --- /dev/null +++ b/pallets/pallet-relay-store/Cargo.toml @@ -0,0 +1,42 @@ +[package] +authors.workspace = true +description = "Pallet enabling storing finalize relay head data on chain." +documentation.workspace = true +edition.workspace = true +homepage.workspace = true +license-file.workspace = true +name = "pallet-relay-store" +readme.workspace = true +repository.workspace = true +version.workspace = true + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +cumulus-pallet-parachain-system.workspace = true +frame-support.workspace = true +frame-system.workspace = true +log.workspace = true +parity-scale-codec = {workspace = true, features = ["derive"]} +scale-info = {workspace = true, features = ["derive"]} +sp-core.workspace = true +sp-runtime.workspace = true +sp-std.workspace = true + +[features] +default = ["std"] +std = [ + "cumulus-pallet-parachain-system/std", + "frame-support/std", + "frame-system/std", + "parity-scale-codec/std", + "scale-info/std", + "sp-core/std", + "sp-runtime/std", + "sp-std/std", +] +runtime-benchmarks = [ + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", +] diff --git a/pallets/pallet-relay-store/src/lib.rs b/pallets/pallet-relay-store/src/lib.rs new file mode 100644 index 0000000000..1abe4123ab --- /dev/null +++ b/pallets/pallet-relay-store/src/lib.rs @@ -0,0 +1,105 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +// TODO: Pallet description + +#![cfg_attr(not(feature = "std"), no_std)] + +mod relay; + +pub use crate::pallet::*; + +#[frame_support::pallet] +pub mod pallet { + use super::*; + + use frame_support::{ + pallet_prelude::{ValueQuery, *}, + BoundedVec, + }; + use frame_system::pallet_prelude::*; + use sp_core::H256; + + use crate::relay::RelayParentInfo; + + const STORAGE_VERSION: StorageVersion = StorageVersion::new(0); + + #[pallet::storage] + #[pallet::getter(fn latest_relay_head_for_block)] + pub(crate) type LatestRelayHeads = StorageMap<_, Twox64Concat, H256, RelayParentInfo>; + + // TODO: Use a better data structure for lookups + #[pallet::storage] + pub(crate) type LatestBlockHashes = StorageValue<_, BoundedVec, ValueQuery>; + + #[pallet::config] + pub trait Config: frame_system::Config { + #[pallet::constant] + type MaxBlocks: Get; + } + + #[pallet::pallet] + #[pallet::generate_store(pub(super) trait Store)] + #[pallet::storage_version(STORAGE_VERSION)] + pub struct Pallet(_); + + #[pallet::hooks] + impl Hooks> for Pallet + where + T: cumulus_pallet_parachain_system::Config, + { + fn on_initialize(_n: BlockNumberFor) -> Weight { + // Reserve weight to update the last relay state root + ::DbWeight::get().writes(2) + } + fn on_finalize(_n: BlockNumberFor) { + // Called before the validation data is cleaned in the + // parachain_system::on_finalize hook + let Some(new_validation_data) = cumulus_pallet_parachain_system::Pallet::::validation_data() else { return; }; + // Remove old relay block from both storage entries. + let mut latest_block_hashes = LatestBlockHashes::::get(); + if latest_block_hashes.is_full() { + let oldest_block_hash = latest_block_hashes.remove(0); + LatestRelayHeads::::remove(oldest_block_hash); + log::trace!( + "Relay block queue full. Removing oldest block with hash {:#02x?}", + oldest_block_hash + ); + } + // Set the new relay block in storage. + let relay_block_hash = new_validation_data.parent_head.hash(); + log::trace!( + "Adding new relay block hash {:#02x?} with state root {:#02x?} and number {:#02x?}", + relay_block_hash, + new_validation_data.relay_parent_storage_root, + new_validation_data.relay_parent_number, + ); + LatestRelayHeads::::insert( + relay_block_hash, + RelayParentInfo { + relay_parent_number: new_validation_data.relay_parent_number, + relay_parent_storage_root: new_validation_data.relay_parent_storage_root, + }, + ); + latest_block_hashes + .try_push(relay_block_hash) + .expect("Should never fail to push a new object on the BoundedVec of relay block hashes."); + LatestBlockHashes::::set(latest_block_hashes); + } + } +} diff --git a/pallets/pallet-relay-store/src/relay.rs b/pallets/pallet-relay-store/src/relay.rs new file mode 100644 index 0000000000..c18ca6e7d9 --- /dev/null +++ b/pallets/pallet-relay-store/src/relay.rs @@ -0,0 +1,27 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; +use scale_info::TypeInfo; +use sp_core::RuntimeDebug; + +#[derive(PartialEq, Eq, Clone, Encode, Decode, TypeInfo, RuntimeDebug, MaxEncodedLen)] +pub struct RelayParentInfo { + pub relay_parent_number: BlockNumber, + pub relay_parent_storage_root: Hash, +} From f54242803caf455aad8aa1f880d8d36f01afe03a Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Tue, 18 Jul 2023 12:13:02 +0200 Subject: [PATCH 16/32] Use relay block height instead of block hash --- crates/kilt-dip-support/src/lib.rs | 12 +++---- crates/kilt-dip-support/src/state_proofs.rs | 12 +++---- crates/kilt-dip-support/src/traits.rs | 8 ++--- dip-template/runtimes/dip-consumer/src/dip.rs | 4 +-- pallets/pallet-relay-store/src/lib.rs | 34 +++++++++---------- pallets/pallet-relay-store/src/relay.rs | 3 +- 6 files changed, 36 insertions(+), 37 deletions(-) diff --git a/crates/kilt-dip-support/src/lib.rs b/crates/kilt-dip-support/src/lib.rs index 73cff2ab8f..ddd46f8863 100644 --- a/crates/kilt-dip-support/src/lib.rs +++ b/crates/kilt-dip-support/src/lib.rs @@ -49,14 +49,14 @@ pub mod state_proofs; pub mod traits; #[derive(Encode, Decode, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug, TypeInfo, Clone)] -pub struct ParaRootProof { - relay_block_hash: RelayBlockHash, +pub struct ParaRootProof { + relay_block_height: RelayBlockHeight, proof: Vec>, } #[derive(Encode, Decode, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug, TypeInfo, Clone)] -pub struct DipSiblingParachainStateProof { - para_root_proof: ParaRootProof, +pub struct DipSiblingParachainStateProof { + para_root_proof: ParaRootProof, dip_commitment_proof: Vec>, dip_proof: InnerProof, } @@ -183,7 +183,7 @@ impl< type Error = (); type IdentityDetails = ProviderAccountIdentityDetails; type Proof = DipSiblingParachainStateProof< - ::Output, + RelayInfoProvider::BlockNumber, MerkleLeavesAndDidSignature< MerkleProof< Vec>, @@ -218,7 +218,7 @@ impl< let provider_parachain_header = state_proofs::relay_chain::ParachainHeadProofVerifier::::verify_proof_for_parachain( &ProviderParaIdProvider::get(), - ¶_root_proof.relay_block_hash, + ¶_root_proof.relay_block_height, para_root_proof.proof, )?; // 2. Verify parachain state proof. diff --git a/crates/kilt-dip-support/src/state_proofs.rs b/crates/kilt-dip-support/src/state_proofs.rs index b99cb2543d..ca26235591 100644 --- a/crates/kilt-dip-support/src/state_proofs.rs +++ b/crates/kilt-dip-support/src/state_proofs.rs @@ -101,11 +101,11 @@ pub mod relay_chain { #[allow(clippy::result_unit_err)] pub fn verify_proof_for_parachain( para_id: &RelayInfoProvider::ParaId, - relay_hash: &::Output, + relay_height: &RelayInfoProvider::BlockNumber, proof: impl IntoIterator>, ) -> Result, ()> { let relay_state_root: <::Hasher as Hash>::Output = - RelayInfoProvider::state_root_for_block(relay_hash).ok_or(())?; + RelayInfoProvider::state_root_for_block(relay_height).ok_or(())?; let parachain_storage_key = RelayInfoProvider::parachain_head_storage_key(para_id); let storage_proof = StorageProof::new(proof); let revealed_leaves = read_proof_check::( @@ -158,7 +158,7 @@ pub mod relay_chain { } fn state_root_for_block( - _block_hash: &::Output, + _block_height: &Self::BlockNumber, ) -> Option<::Output> { Some(hex!("81b75d95075d16005ee0a987a3f061d3011ada919b261e9b02961b9b3725f3fd").into()) } @@ -175,14 +175,14 @@ pub mod relay_chain { hex!("9f0b3c252fcb29d88eff4f3de5de4476c3ffbf8013c601cc93de3437f9d415bd52c48d794b341f218b9d0020a4b646746c24d0ca80348b8e2c39c479a146933297f62b7051df82e92e1bca761432c3e6f64c74033f80220131e7cd7a08b97f8aa06225f7aefbbca8118fb436c07689c552ed3f577145806d974dd9e4db5e407e29f84c4121ccc58f9c6adc3933afc1bcaef52defe77de5801e9e1a21db053de56365fdee57998488ddae7d664c0430da90469dde17936c1f80c5c11751bbfc99a1ad805c58a65b9704e0bad58e694023e9cc57ce6ef84cdb0b8038f6c242700eaea04ffad5c25ca9a9b1cc2af7303655a32eb59e84b6bb927cd3802575469e76e104b0db8b18dbc762b997a78aa666432a44c4b955ced044a4691f80a81408b856272feeec08845af515e27d033efd3ff8b46de6bc706c38e600086a809ee78332c2a38a3918070942421e651e0b9a43e4b8b2c92e87a2552cede73e8380c9d79f411f742cad0c6f2b070aa08703a04cb7db840c3821a6762837dd8d00e9807dcfbc7f2fcc9415e2cb40eef7f718758d76193f325b3f8b7180e3e5e7d6b81e8036252cae6d24a531a151ce1ee223a07bf71cf82a7fdf49090e4ca345d27d68ca80e3f08ef11671f8f1defa66fa2af71e1a871430e9352df9b3f1d427b5a5dabfb280b51d28c9b99030d050fc1578cd23b5506e769b86c8f4ccc6aded4b8d7c1a73b7").to_vec(), ].to_vec(); // As of query paras::heads(2_086) at block - // "0x18e90e9aa8e3b063f60386ba1b0415111798e72d01de58b1438d620d42f58e39" which - // results in the key + // "0x18e90e9aa8e3b063f60386ba1b0415111798e72d01de58b1438d620d42f58e39" + // (16_363_919) which results in the key // "0xcd710b30bd2eab0352ddcc26417aa1941b3c252fcb29d88eff4f3de5de4476c32c0cfd6c23b92a7826080000" // let expected_spiritnet_head_at_block = hex!("65541097fb02782e14f43074f0b00e44ae8e9fe426982323ef1d329739740d37f252ff006d1156941db1bccd58ce3a1cac4f40cad91f692d94e98f501dd70081a129b69a3e2ef7e1ff84ba3d86dab4e95f2c87f6b1055ebd48519c185360eae58f05d1ea08066175726120dcdc6308000000000561757261010170ccfaf3756d1a8dd8ae5c89094199d6d32e5dd9f0920f6fe30f986815b5e701974ea0e0e0a901401f2c72e3dd8dbdf4aa55d59bf3e7021856cdb8038419eb8c").to_vec(); let returned_head = ParachainHeadProofVerifier::::verify_proof_for_parachain( &2_086, - &hex!("18e90e9aa8e3b063f60386ba1b0415111798e72d01de58b1438d620d42f58e39").into(), + &16_363_919, spiritnet_head_proof_at_block, ) .expect("Parachain head proof verification should not fail."); diff --git a/crates/kilt-dip-support/src/traits.rs b/crates/kilt-dip-support/src/traits.rs index 17abbfa5a3..ee092a3064 100644 --- a/crates/kilt-dip-support/src/traits.rs +++ b/crates/kilt-dip-support/src/traits.rs @@ -84,7 +84,7 @@ pub trait RelayChainStateInfoProvider { type ParaId; fn state_root_for_block( - block_hash: &::Output, + block_height: &Self::BlockNumber, ) -> Option<::Output>; fn parachain_head_storage_key(para_id: &Self::ParaId) -> Self::Key; } @@ -95,16 +95,16 @@ impl RelayChainStateInfoProvider for RococoParachainRuntime where Runtime: pallet_relay_store::Config, { - type BlockNumber = u64; + type BlockNumber = u32; // TODO: This is not exported type Hasher = BlakeTwo256; type Key = StorageKey; type ParaId = u32; fn state_root_for_block( - block_hash: &::Output, + block_height: &Self::BlockNumber, ) -> Option<::Output> { - pallet_relay_store::Pallet::::latest_relay_head_for_block(block_hash) + pallet_relay_store::Pallet::::latest_relay_head_for_block(block_height) .map(|relay_header| relay_header.relay_parent_storage_root) } diff --git a/dip-template/runtimes/dip-consumer/src/dip.rs b/dip-template/runtimes/dip-consumer/src/dip.rs index 21f0aeb7bd..51a86523f4 100644 --- a/dip-template/runtimes/dip-consumer/src/dip.rs +++ b/dip-template/runtimes/dip-consumer/src/dip.rs @@ -28,7 +28,7 @@ use kilt_dip_support::{ DipSiblingParachainStateProof, StateProofDipVerifier, }; use pallet_did_lookup::linkable_account::LinkableAccountId; -use sp_core::{ConstU32, H256}; +use sp_core::ConstU32; use sp_runtime::traits::BlakeTwo256; use sp_std::vec::Vec; @@ -59,7 +59,7 @@ impl pallet_dip_consumer::Config for Runtime { type DipCallOriginFilter = PreliminaryDipOriginFilter; type Identifier = DidIdentifier; type IdentityProof = DipSiblingParachainStateProof< - H256, + u32, MerkleLeavesAndDidSignature< MerkleProof>, ProofLeaf>, BlockNumber, diff --git a/pallets/pallet-relay-store/src/lib.rs b/pallets/pallet-relay-store/src/lib.rs index 1abe4123ab..585e498220 100644 --- a/pallets/pallet-relay-store/src/lib.rs +++ b/pallets/pallet-relay-store/src/lib.rs @@ -41,11 +41,11 @@ pub mod pallet { #[pallet::storage] #[pallet::getter(fn latest_relay_head_for_block)] - pub(crate) type LatestRelayHeads = StorageMap<_, Twox64Concat, H256, RelayParentInfo>; + pub(crate) type LatestRelayHeads = StorageMap<_, Twox64Concat, u32, RelayParentInfo>; // TODO: Use a better data structure for lookups #[pallet::storage] - pub(crate) type LatestBlockHashes = StorageValue<_, BoundedVec, ValueQuery>; + pub(crate) type LatestBlockHeights = StorageValue<_, BoundedVec, ValueQuery>; #[pallet::config] pub trait Config: frame_system::Config { @@ -67,39 +67,39 @@ pub mod pallet { // Reserve weight to update the last relay state root ::DbWeight::get().writes(2) } + fn on_finalize(_n: BlockNumberFor) { // Called before the validation data is cleaned in the // parachain_system::on_finalize hook let Some(new_validation_data) = cumulus_pallet_parachain_system::Pallet::::validation_data() else { return; }; // Remove old relay block from both storage entries. - let mut latest_block_hashes = LatestBlockHashes::::get(); - if latest_block_hashes.is_full() { - let oldest_block_hash = latest_block_hashes.remove(0); - LatestRelayHeads::::remove(oldest_block_hash); + let mut latest_block_heights = LatestBlockHeights::::get(); + if latest_block_heights.is_full() { + let oldest_block_height = latest_block_heights.remove(0); + LatestRelayHeads::::remove(oldest_block_height); log::trace!( - "Relay block queue full. Removing oldest block with hash {:#02x?}", - oldest_block_hash + "Relay block queue full. Removing oldest block at height {:?}", + oldest_block_height ); } // Set the new relay block in storage. - let relay_block_hash = new_validation_data.parent_head.hash(); + let relay_block_height = new_validation_data.relay_parent_number; + // TODO: Replace hardcoded generics with proper definitions. log::trace!( - "Adding new relay block hash {:#02x?} with state root {:#02x?} and number {:#02x?}", - relay_block_hash, + "Adding new relay block with state root {:#02x?} and number {:?}", new_validation_data.relay_parent_storage_root, new_validation_data.relay_parent_number, ); LatestRelayHeads::::insert( - relay_block_hash, + relay_block_height, RelayParentInfo { - relay_parent_number: new_validation_data.relay_parent_number, relay_parent_storage_root: new_validation_data.relay_parent_storage_root, }, ); - latest_block_hashes - .try_push(relay_block_hash) - .expect("Should never fail to push a new object on the BoundedVec of relay block hashes."); - LatestBlockHashes::::set(latest_block_hashes); + latest_block_heights + .try_push(relay_block_height) + .expect("Should never fail to push a new object on the BoundedVec of relay block heights."); + LatestBlockHeights::::set(latest_block_heights); } } } diff --git a/pallets/pallet-relay-store/src/relay.rs b/pallets/pallet-relay-store/src/relay.rs index c18ca6e7d9..9dfaf69f95 100644 --- a/pallets/pallet-relay-store/src/relay.rs +++ b/pallets/pallet-relay-store/src/relay.rs @@ -21,7 +21,6 @@ use scale_info::TypeInfo; use sp_core::RuntimeDebug; #[derive(PartialEq, Eq, Clone, Encode, Decode, TypeInfo, RuntimeDebug, MaxEncodedLen)] -pub struct RelayParentInfo { - pub relay_parent_number: BlockNumber, +pub struct RelayParentInfo { pub relay_parent_storage_root: Hash, } From 318d7650635ff2fd149bb5385c9b84f797715e3f Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Thu, 20 Jul 2023 09:02:11 +0200 Subject: [PATCH 17/32] Cleaning before kilt-dip-support --- Cargo.lock | 12 ------- Cargo.toml | 1 - crates/dip-support/Cargo.toml | 27 ---------------- crates/dip-support/src/lib.rs | 31 ------------------- crates/kilt-dip-support/Cargo.toml | 2 -- dip-template/runtimes/dip-consumer/Cargo.toml | 2 -- dip-template/runtimes/dip-consumer/src/dip.rs | 2 +- dip-template/runtimes/dip-provider/Cargo.toml | 2 -- dip-template/runtimes/dip-provider/src/lib.rs | 2 +- pallets/pallet-relay-store/src/lib.rs | 28 ++++++++++------- 10 files changed, 18 insertions(+), 91 deletions(-) delete mode 100644 crates/dip-support/Cargo.toml delete mode 100644 crates/dip-support/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index aeeb72ad95..5ec62c8ae0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2342,7 +2342,6 @@ dependencies = [ "cumulus-primitives-utility", "did", "dip-provider-runtime-template", - "dip-support", "frame-executive", "frame-support", "frame-system", @@ -2446,7 +2445,6 @@ dependencies = [ "cumulus-primitives-timestamp", "cumulus-primitives-utility", "did", - "dip-support", "frame-executive", "frame-support", "frame-system", @@ -2487,15 +2485,6 @@ dependencies = [ "xcm-executor", ] -[[package]] -name = "dip-support" -version = "1.11.0-dev" -dependencies = [ - "frame-support", - "parity-scale-codec", - "scale-info", -] - [[package]] name = "directories" version = "4.0.1" @@ -4198,7 +4187,6 @@ version = "1.11.0-dev" dependencies = [ "cumulus-pallet-parachain-system", "did", - "dip-support", "frame-support", "frame-system", "hash-db 0.16.0", diff --git a/Cargo.toml b/Cargo.toml index 92462e74c7..defb245517 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -62,7 +62,6 @@ parachain-staking = {path = "pallets/parachain-staking", default-features = fals public-credentials = {path = "pallets/public-credentials", default-features = false} # Internal support (with default disabled) -dip-support = {path = "crates/dip-support", default-features = false} kilt-asset-dids = {path = "crates/assets", default-features = false} kilt-dip-support = {path = "crates/kilt-dip-support", default-features = false} kilt-support = {path = "support", default-features = false} diff --git a/crates/dip-support/Cargo.toml b/crates/dip-support/Cargo.toml deleted file mode 100644 index 276b3929ac..0000000000 --- a/crates/dip-support/Cargo.toml +++ /dev/null @@ -1,27 +0,0 @@ -[package] -authors.workspace = true -description = "Support types, traits, and functions for the KILT Decentralized Identity Provider (DIP) functionality." -documentation.workspace = true -edition.workspace = true -homepage.workspace = true -license-file.workspace = true -name = "dip-support" -readme.workspace = true -repository.workspace = true -version.workspace = true - -[dependencies] -# Parity dependencies -parity-scale-codec = {workspace = true, features = ["derive"]} -scale-info = {workspace = true, features = ["derive"]} - -# Substrate dependencies -frame-support.workspace = true - -[features] -default = ["std"] -std = [ - "parity-scale-codec/std", - "scale-info/std", - "frame-support/std" -] diff --git a/crates/dip-support/src/lib.rs b/crates/dip-support/src/lib.rs deleted file mode 100644 index 31256a1dda..0000000000 --- a/crates/dip-support/src/lib.rs +++ /dev/null @@ -1,31 +0,0 @@ -// KILT Blockchain – https://botlabs.org -// Copyright (C) 2019-2023 BOTLabs GmbH - -// The KILT Blockchain is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// The KILT Blockchain is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -// If you feel like getting in touch with us, you can do so at info@botlabs.org - -// TODO: Crate documentation - -#![cfg_attr(not(feature = "std"), no_std)] - -use frame_support::RuntimeDebug; -use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; -use scale_info::TypeInfo; - -#[derive(Clone, Eq, PartialEq, Encode, Decode, TypeInfo, MaxEncodedLen, RuntimeDebug)] -pub enum IdentityDetailsAction { - Updated(Identifier, Proof, Details), - Deleted(Identifier), -} diff --git a/crates/kilt-dip-support/Cargo.toml b/crates/kilt-dip-support/Cargo.toml index eb6708a526..be6c978edc 100644 --- a/crates/kilt-dip-support/Cargo.toml +++ b/crates/kilt-dip-support/Cargo.toml @@ -16,7 +16,6 @@ hash-db.workspace = true # Internal dependencies did.workspace = true -dip-support.workspace = true pallet-dip-consumer.workspace = true pallet-dip-provider.workspace = true pallet-relay-store.workspace = true @@ -52,7 +51,6 @@ default = ["std"] std = [ "hash-db/std", "did/std", - "dip-support/std", "pallet-dip-consumer/std", "pallet-dip-provider/std", "pallet-relay-store/std", diff --git a/dip-template/runtimes/dip-consumer/Cargo.toml b/dip-template/runtimes/dip-consumer/Cargo.toml index 8c7a9615f5..d92866355f 100644 --- a/dip-template/runtimes/dip-consumer/Cargo.toml +++ b/dip-template/runtimes/dip-consumer/Cargo.toml @@ -19,7 +19,6 @@ 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 pallet-did-lookup.workspace = true @@ -80,7 +79,6 @@ std = [ "parity-scale-codec/std", "scale-info/std", "dip-provider-runtime-template/std", - "dip-support/std", "did/std", "kilt-dip-support/std", "pallet-did-lookup/std", diff --git a/dip-template/runtimes/dip-consumer/src/dip.rs b/dip-template/runtimes/dip-consumer/src/dip.rs index 51a86523f4..d9dc41fa35 100644 --- a/dip-template/runtimes/dip-consumer/src/dip.rs +++ b/dip-template/runtimes/dip-consumer/src/dip.rs @@ -177,5 +177,5 @@ mod dip_call_origin_filter_tests { } impl pallet_relay_store::Config for Runtime { - type MaxBlocks = ConstU32<100>; + type MaxRelayBlocksStored = ConstU32<100>; } diff --git a/dip-template/runtimes/dip-provider/Cargo.toml b/dip-template/runtimes/dip-provider/Cargo.toml index 14fdeb6257..4fe0746226 100644 --- a/dip-template/runtimes/dip-provider/Cargo.toml +++ b/dip-template/runtimes/dip-provider/Cargo.toml @@ -19,7 +19,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 @@ -78,7 +77,6 @@ std = [ "parity-scale-codec/std", "scale-info/std", "did/std", - "dip-support/std", "kilt-dip-support/std", "kilt-runtime-api-dip-provider/std", "pallet-did-lookup/std", diff --git a/dip-template/runtimes/dip-provider/src/lib.rs b/dip-template/runtimes/dip-provider/src/lib.rs index b1d83b54aa..0a24dcb021 100644 --- a/dip-template/runtimes/dip-provider/src/lib.rs +++ b/dip-template/runtimes/dip-provider/src/lib.rs @@ -140,7 +140,7 @@ construct_runtime!( Web3Names: pallet_web3_names = 32, // DIP - DipProvider: pallet_dip_provider = 50, + DipProvider: pallet_dip_provider = 40, } ); diff --git a/pallets/pallet-relay-store/src/lib.rs b/pallets/pallet-relay-store/src/lib.rs index 585e498220..c3b08a99d9 100644 --- a/pallets/pallet-relay-store/src/lib.rs +++ b/pallets/pallet-relay-store/src/lib.rs @@ -28,10 +28,7 @@ pub use crate::pallet::*; pub mod pallet { use super::*; - use frame_support::{ - pallet_prelude::{ValueQuery, *}, - BoundedVec, - }; + use frame_support::{pallet_prelude::*, BoundedVec}; use frame_system::pallet_prelude::*; use sp_core::H256; @@ -43,14 +40,16 @@ pub mod pallet { #[pallet::getter(fn latest_relay_head_for_block)] pub(crate) type LatestRelayHeads = StorageMap<_, Twox64Concat, u32, RelayParentInfo>; - // TODO: Use a better data structure for lookups + // TODO: Replace this with an array once support for const generics is fully + // supported in Substrate. #[pallet::storage] - pub(crate) type LatestBlockHeights = StorageValue<_, BoundedVec, ValueQuery>; + pub(crate) type LatestBlockHeights = + StorageValue<_, BoundedVec, ValueQuery>; #[pallet::config] pub trait Config: frame_system::Config { #[pallet::constant] - type MaxBlocks: Get; + type MaxRelayBlocksStored: Get; } #[pallet::pallet] @@ -65,15 +64,17 @@ pub mod pallet { { fn on_initialize(_n: BlockNumberFor) -> Weight { // Reserve weight to update the last relay state root + // TODO: Replace with benchmarked version of `on_finalize(` ::DbWeight::get().writes(2) } + // TODO: Benchmarks fn on_finalize(_n: BlockNumberFor) { // Called before the validation data is cleaned in the // parachain_system::on_finalize hook let Some(new_validation_data) = cumulus_pallet_parachain_system::Pallet::::validation_data() else { return; }; - // Remove old relay block from both storage entries. let mut latest_block_heights = LatestBlockHeights::::get(); + // Remove old relay block from both storage entries. if latest_block_heights.is_full() { let oldest_block_height = latest_block_heights.remove(0); LatestRelayHeads::::remove(oldest_block_height); @@ -84,7 +85,6 @@ pub mod pallet { } // Set the new relay block in storage. let relay_block_height = new_validation_data.relay_parent_number; - // TODO: Replace hardcoded generics with proper definitions. log::trace!( "Adding new relay block with state root {:#02x?} and number {:?}", new_validation_data.relay_parent_storage_root, @@ -96,9 +96,13 @@ pub mod pallet { relay_parent_storage_root: new_validation_data.relay_parent_storage_root, }, ); - latest_block_heights - .try_push(relay_block_height) - .expect("Should never fail to push a new object on the BoundedVec of relay block heights."); + let push_res = latest_block_heights.try_push(relay_block_height); + if let Err(err) = push_res { + log::error!( + "Pushing a new relay block to the queue should not fail but it did when adding relay block n. {:?}", + err + ); + } LatestBlockHeights::::set(latest_block_heights); } } From 7b67a5724cdcd3188e27e45f24ff31ebfb552307 Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Thu, 20 Jul 2023 14:27:59 +0200 Subject: [PATCH 18/32] On the way there --- crates/kilt-dip-support/src/did.rs | 391 ++++++++------ crates/kilt-dip-support/src/lib.rs | 536 ++++++++++---------- crates/kilt-dip-support/src/merkle.rs | 53 +- crates/kilt-dip-support/src/state_proofs.rs | 214 +++++++- crates/kilt-dip-support/src/traits.rs | 110 ++-- 5 files changed, 742 insertions(+), 562 deletions(-) diff --git a/crates/kilt-dip-support/src/did.rs b/crates/kilt-dip-support/src/did.rs index 8765a419ba..bbdf35ed8a 100644 --- a/crates/kilt-dip-support/src/did.rs +++ b/crates/kilt-dip-support/src/did.rs @@ -16,6 +16,8 @@ // If you feel like getting in touch with us, you can do so at info@botlabs.org +use core::task::Context; + use did::{ did_details::{DidPublicKey, DidPublicKeyDetails, DidVerificationKey}, DidSignature, DidVerificationKeyRelationship, @@ -31,7 +33,7 @@ use sp_std::marker::PhantomData; use crate::{ merkle::RevealedDidKey, - traits::{Bump, DidDipOriginFilter}, + traits::{Bump, DidDipOriginFilter, DidSignatureVerifierContextProvider}, }; #[derive(Encode, Decode, RuntimeDebug, Clone, Eq, PartialEq, TypeInfo)] @@ -46,148 +48,230 @@ pub struct MerkleLeavesAndDidSignature { pub did_signature: TimeBoundDidSignature, } -/// A type that verifies a DID signature over some DID keys revealed by a -/// previously-verified Merkle proof. It requires the `Details` type to -/// implement the `Bump` trait to avoid replay attacks. The basic verification -/// logic verifies that the signature has been generated over the encoded tuple -/// (call, identity details, submitter_address, submission_block_number, -/// 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, +pub struct MerkleDidSignatureVerifier< + Call, + Submitter, + DidLocalDetails, MerkleProofEntries, - BlockNumberProvider, - const SIGNATURE_VALIDITY: u64, - GenesisHashProvider, - Hash, - SignedExtraProvider = (), - SignedExtra = (), + ContextProvider, + RemoteKeyId, + RemoteBlockNumber, >( - #[allow(clippy::type_complexity)] PhantomData<( - KeyId, - BlockNumber, - Digest, - Details, - AccountId, + Call, + Submitter, + DidLocalDetails, MerkleProofEntries, - BlockNumberProvider, - ConstU64, - GenesisHashProvider, - Hash, - SignedExtraProvider, - SignedExtra, + ContextProvider, + RemoteKeyId, + RemoteBlockNumber, )>, ); -impl< +impl + MerkleDidSignatureVerifier< Call, - Subject, - KeyId, - BlockNumber, - Digest, - Details, - AccountId, + Submitter, + DidLocalDetails, MerkleProofEntries, - BlockNumberProvider, - const SIGNATURE_VALIDITY: u64, - GenesisHashProvider, - Hash, - SignedExtraProvider, - SignedExtra, - > IdentityProofVerifier - for MerkleRevealedDidSignatureVerifier< - KeyId, - BlockNumber, - Digest, - Details, - AccountId, - MerkleProofEntries, - BlockNumberProvider, - SIGNATURE_VALIDITY, - GenesisHashProvider, - Hash, - SignedExtraProvider, - SignedExtra, + ContextProvider, + RemoteKeyId, + RemoteBlockNumber, > where - AccountId: Encode, - BlockNumber: Encode + CheckedSub + Into + PartialOrd + sp_std::fmt::Debug, - Call: Encode, - Digest: Encode, - Details: Bump + Default + Encode, - MerkleProofEntries: AsRef<[RevealedDidKey]>, - BlockNumberProvider: Get, - GenesisHashProvider: Get, - Hash: Encode, - SignedExtraProvider: Get, - SignedExtra: Encode, + ContextProvider: DidSignatureVerifierContextProvider, + ContextProvider::BlockNumber: Encode + CheckedSub + PartialOrd, + ContextProvider::Hash: Encode, + ContextProvider::SignedExtra: Encode, + DidLocalDetails: Bump + Default + Encode, + MerkleProofEntries: AsRef<[RevealedDidKey]>, { - // TODO: Error handling - 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 = MerkleLeavesAndDidSignature; - /// The `Details` that are part of the identity details must implement the - /// `Bump` trait. - type IdentityDetails = Details; - /// The type of the submitter's accounts. - type Submitter = AccountId; - /// Successful verifications return the verification key used to validate - /// the provided signature and its relationship to the DID subject. - type VerificationResult = (DidVerificationKey, DidVerificationKeyRelationship); - - fn verify_proof_for_call_against_details( + pub fn verify_did_signature_for_call( call: &Call, - _subject: &Subject, - submitter: &Self::Submitter, - identity_details: &mut Option, - proof: Self::Proof, - ) -> Result { - let block_number = BlockNumberProvider::get(); - let is_signature_fresh = - if let Some(blocks_ago_from_now) = block_number.checked_sub(&proof.did_signature.block_number) { - // False if the signature is too old. - blocks_ago_from_now.into() <= SIGNATURE_VALIDITY - } else { - // Signature generated at a future time, not possible to verify. - false - }; - + submitter: &Submitter, + local_details: &mut Option, + merkle_revealed_did_signature: MerkleLeavesAndDidSignature, + ) -> Result<(DidVerificationKey, DidVerificationKeyRelationship), ()> { + let block_number = ContextProvider::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 + } else { + // Signature generated at a future time, not possible to verify. + false + }; ensure!(is_signature_fresh, ()); let encoded_payload = ( call, - &identity_details, + &local_details, submitter, - &proof.did_signature.block_number, - GenesisHashProvider::get(), - SignedExtraProvider::get(), + &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 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 mut proof_verification_keys = merkle_revealed_did_signature.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) + .verify_signature(&encoded_payload, &merkle_revealed_did_signature.did_signature.signature) .is_ok() }); let Some((key, relationship)) = valid_signing_key else { return Err(()) }; - // TODO: bump details. - if let Some(details) = identity_details { + if let Some(details) = local_details { details.bump(); } else { - *identity_details = Some(Details::default()); + *local_details = Some(DidLocalDetails::default()); } Ok((key.clone(), relationship)) } } +/// A type that verifies a DID signature over some DID keys revealed by a +/// previously-verified Merkle proof. It requires the `Details` type to +/// implement the `Bump` trait to avoid replay attacks. The basic verification +/// logic verifies that the signature has been generated over the encoded tuple +/// (call, identity details, submitter_address, submission_block_number, +/// 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, +// const SIGNATURE_VALIDITY: u64, +// GenesisHashProvider, +// Hash, +// SignedExtraProvider = (), +// SignedExtra = (), +// >( +// #[allow(clippy::type_complexity)] +// PhantomData<( +// KeyId, +// BlockNumber, +// Digest, +// Details, +// AccountId, +// MerkleProofEntries, +// BlockNumberProvider, +// ConstU64, +// GenesisHashProvider, +// Hash, +// SignedExtraProvider, +// SignedExtra, +// )>, +// ); +// impl< +// Call, +// Subject, +// KeyId, +// BlockNumber, +// Digest, +// Details, +// AccountId, +// MerkleProofEntries, +// BlockNumberProvider, +// const SIGNATURE_VALIDITY: u64, +// GenesisHashProvider, +// Hash, +// SignedExtraProvider, +// SignedExtra, +// > IdentityProofVerifier +// for MerkleRevealedDidSignatureVerifier< +// KeyId, +// BlockNumber, +// Digest, +// Details, +// AccountId, +// MerkleProofEntries, +// BlockNumberProvider, +// SIGNATURE_VALIDITY, +// GenesisHashProvider, +// Hash, +// SignedExtraProvider, +// SignedExtra, +// > where +// AccountId: Encode, +// BlockNumber: Encode + CheckedSub + Into + PartialOrd + sp_std::fmt::Debug, +// Call: Encode, +// Digest: Encode, +// Details: Bump + Default + Encode, +// MerkleProofEntries: AsRef<[RevealedDidKey]>, +// BlockNumberProvider: Get, +// GenesisHashProvider: Get, +// Hash: Encode, +// SignedExtraProvider: Get, +// SignedExtra: Encode, +// { +// // TODO: Error handling +// 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 = MerkleLeavesAndDidSignature; +// /// The `Details` that are part of the identity details must implement the +// /// `Bump` trait. +// type IdentityDetails = Details; +// /// The type of the submitter's accounts. +// type Submitter = AccountId; +// /// Successful verifications return the verification key used to validate +// /// the provided signature and its relationship to the DID subject. +// type VerificationResult = (DidVerificationKey, DidVerificationKeyRelationship); + +// fn verify_proof_for_call_against_details( +// call: &Call, +// _subject: &Subject, +// submitter: &Self::Submitter, +// identity_details: &mut Option, +// proof: Self::Proof, +// ) -> Result { +// let block_number = BlockNumberProvider::get(); +// let is_signature_fresh = +// if let Some(blocks_ago_from_now) = block_number.checked_sub(&proof.did_signature.block_number) { +// // False if the signature is too old. +// blocks_ago_from_now.into() <= SIGNATURE_VALIDITY +// } else { +// // Signature generated at a future time, not possible to verify. +// false +// }; + +// ensure!(is_signature_fresh, ()); +// let encoded_payload = ( +// call, +// &identity_details, +// submitter, +// &proof.did_signature.block_number, +// GenesisHashProvider::get(), +// SignedExtraProvider::get(), +// ) +// .encode(); +// // 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() +// }); +// let Some((key, relationship)) = valid_signing_key else { return Err(()) }; +// // TODO: bump details. +// if let Some(details) = identity_details { +// details.bump(); +// } else { +// *identity_details = Some(Details::default()); +// } +// Ok((key.clone(), relationship)) +// } +// } + /// A type that chains a DID signature verification, as provided by /// `MerkleRevealedDidSignatureVerifier`, and a call filtering logic based on /// the type of key used in the signature. @@ -196,49 +280,50 @@ impl< /// some additional lookups on the call. The `CallVerifier` only performs /// internal checks, while all input and output types are taken from the /// provided `DidSignatureVerifier` type. -pub struct DidSignatureAndCallVerifier( - PhantomData<(DidSignatureVerifier, CallVerifier)>, -); +// pub struct DidSignatureAndCallVerifier( +// PhantomData<(DidSignatureVerifier, CallVerifier)>, +// ); -impl IdentityProofVerifier - for DidSignatureAndCallVerifier -where - DidSignatureVerifier: IdentityProofVerifier, - CallVerifier: DidDipOriginFilter, -{ - // FIXME: Better error handling - type Error = (); - /// The input proof is the same accepted by the `DidSignatureVerifier`. - type Proof = DidSignatureVerifier::Proof; - /// The identity details are the same accepted by the - /// `DidSignatureVerifier`. - type IdentityDetails = DidSignatureVerifier::IdentityDetails; - /// The submitter address is the same accepted by the - /// `DidSignatureVerifier`. - type Submitter = DidSignatureVerifier::Submitter; - /// The verification result is the same accepted by the - /// `DidSignatureVerifier`. - type VerificationResult = DidSignatureVerifier::VerificationResult; +// impl +// IdentityProofVerifier +// for DidSignatureAndCallVerifier +// where +// DidSignatureVerifier: IdentityProofVerifier, +// CallVerifier: DidDipOriginFilter, { +// // FIXME: Better error handling +// type Error = (); +// /// The input proof is the same accepted by the `DidSignatureVerifier`. +// type Proof = DidSignatureVerifier::Proof; +// /// The identity details are the same accepted by the +// /// `DidSignatureVerifier`. +// type IdentityDetails = DidSignatureVerifier::IdentityDetails; +// /// The submitter address is the same accepted by the +// /// `DidSignatureVerifier`. +// type Submitter = DidSignatureVerifier::Submitter; +// /// The verification result is the same accepted by the +// /// `DidSignatureVerifier`. +// type VerificationResult = DidSignatureVerifier::VerificationResult; - fn verify_proof_for_call_against_details( - call: &Call, - subject: &Subject, - submitter: &Self::Submitter, - identity_details: &mut Option, - proof: Self::Proof, - ) -> Result { - 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) - } -} +// fn verify_proof_for_call_against_details( +// call: &Call, +// subject: &Subject, +// submitter: &Self::Submitter, +// identity_details: &mut Option, +// proof: Self::Proof, +// ) -> Result { +// 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) +// } +// } pub struct CombinedIdentityResult { pub a: OutputA, diff --git a/crates/kilt-dip-support/src/lib.rs b/crates/kilt-dip-support/src/lib.rs index ddd46f8863..3a257be4f3 100644 --- a/crates/kilt-dip-support/src/lib.rs +++ b/crates/kilt-dip-support/src/lib.rs @@ -37,15 +37,11 @@ use ::did::{ }; use pallet_dip_consumer::traits::IdentityProofVerifier; -use crate::{ - did::MerkleLeavesAndDidSignature, - merkle::{MerkleProof, ProofLeaf, RevealedDidKey, RevealedWeb3Name, VerificationResult}, - traits::{Bump, DidDipOriginFilter, ParachainStateInfoProvider, RelayChainStateInfoProvider}, -}; +use crate::merkle::{MerkleProof, ProofLeaf, RevealedDidKey, RevealedWeb3Name, VerificationResult}; pub mod did; pub mod merkle; -pub mod state_proofs; +// pub mod state_proofs; pub mod traits; #[derive(Encode, Decode, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug, TypeInfo, Clone)] @@ -54,272 +50,270 @@ pub struct ParaRootProof { proof: Vec>, } -#[derive(Encode, Decode, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug, TypeInfo, Clone)] -pub struct DipSiblingParachainStateProof { - para_root_proof: ParaRootProof, - dip_commitment_proof: Vec>, - dip_proof: InnerProof, -} +// pub struct StateProofDipVerifier< +// RelayInfoProvider, +// ParaInfoProvider, +// ProviderKeyId, +// ProviderParaIdProvider, +// ProviderBlockNumber, +// ProviderAccountIdentityDetails, +// ProviderWeb3Name, +// ProviderHasher, +// ProviderLinkedAccountId, +// ConsumerAccountId, +// ConsumerBlockNumber, +// ConsumerBlockNumberProvider, +// ConsumerGenesisHashProvider, +// CallVerifier, +// const MAX_REVEALED_KEYS_COUNT: u32, +// const MAX_REVEALED_ACCOUNTS_COUNT: u32, +// const SIGNATURE_VALIDITY: u64, +// SignedExtra = (), +// SignedExtraProvider = (), +// >( +// #[allow(clippy::type_complexity)] +// PhantomData<( +// RelayInfoProvider, +// ParaInfoProvider, +// ProviderKeyId, +// ProviderParaIdProvider, +// ProviderBlockNumber, +// ProviderAccountIdentityDetails, +// ProviderWeb3Name, +// ProviderHasher, +// ProviderLinkedAccountId, +// ConsumerAccountId, +// ConsumerBlockNumber, +// ConsumerBlockNumberProvider, +// ConsumerGenesisHashProvider, +// CallVerifier, +// ConstU32, +// ConstU32, +// ConstU64, +// SignedExtra, +// SignedExtraProvider, +// )>, +// ); -pub struct StateProofDipVerifier< - RelayInfoProvider, - ParaInfoProvider, - ProviderKeyId, - ProviderParaIdProvider, - ProviderBlockNumber, - ProviderAccountIdentityDetails, - ProviderWeb3Name, - ProviderHasher, - ProviderLinkedAccountId, - ConsumerAccountId, - ConsumerBlockNumber, - ConsumerBlockNumberProvider, - ConsumerGenesisHashProvider, - CallVerifier, - const MAX_REVEALED_KEYS_COUNT: u32, - const MAX_REVEALED_ACCOUNTS_COUNT: u32, - const SIGNATURE_VALIDITY: u64, - SignedExtra = (), - SignedExtraProvider = (), ->( - #[allow(clippy::type_complexity)] - PhantomData<( - RelayInfoProvider, - ParaInfoProvider, - ProviderKeyId, - ProviderParaIdProvider, - ProviderBlockNumber, - ProviderAccountIdentityDetails, - ProviderWeb3Name, - ProviderHasher, - ProviderLinkedAccountId, - ConsumerAccountId, - ConsumerBlockNumber, - ConsumerBlockNumberProvider, - ConsumerGenesisHashProvider, - CallVerifier, - ConstU32, - ConstU32, - ConstU64, - SignedExtra, - SignedExtraProvider, - )>, -); +// impl< +// Call, +// Subject, +// RelayInfoProvider, +// ParaInfoProvider, +// ProviderKeyId, +// ProviderParaIdProvider, +// ProviderBlockNumber, +// ProviderAccountIdentityDetails, +// ProviderWeb3Name, +// ProviderHasher, +// ProviderLinkedAccountId, +// ConsumerAccountId, +// ConsumerBlockNumber, +// ConsumerBlockNumberProvider, +// ConsumerGenesisHashProvider, +// CallVerifier, +// const MAX_REVEALED_KEYS_COUNT: u32, +// const MAX_REVEALED_ACCOUNTS_COUNT: u32, +// const SIGNATURE_VALIDITY: u64, +// SignedExtra, +// SignedExtraProvider, +// > IdentityProofVerifier +// for StateProofDipVerifier< +// RelayInfoProvider, +// ParaInfoProvider, +// ProviderKeyId, +// ProviderParaIdProvider, +// ProviderBlockNumber, +// ProviderAccountIdentityDetails, +// ProviderWeb3Name, +// ProviderHasher, +// ProviderLinkedAccountId, +// ConsumerAccountId, +// ConsumerBlockNumber, +// ConsumerBlockNumberProvider, +// ConsumerGenesisHashProvider, +// CallVerifier, +// MAX_REVEALED_KEYS_COUNT, +// MAX_REVEALED_ACCOUNTS_COUNT, +// SIGNATURE_VALIDITY, +// SignedExtra, +// SignedExtraProvider, +// > where +// RelayInfoProvider: RelayChainStateInfoProvider, +// RelayInfoProvider::Hasher: 'static, +// ::Output: Ord, +// RelayInfoProvider::BlockNumber: Copy + Into + TryFrom + +// HasCompact, RelayInfoProvider::Key: AsRef<[u8]>, +// ParaInfoProvider: ParachainStateInfoProvider, ParaInfoProvider::Hasher: 'static, +// ::Output: Ord +// + Encode +// + PartialEq<::Output> +// + From<::Output>, +// ParaInfoProvider::Commitment: Decode, +// ParaInfoProvider::Key: AsRef<[u8]>, +// ProviderKeyId: Encode + Clone, +// ProviderBlockNumber: Encode + Clone, +// ProviderWeb3Name: Encode + Clone, +// ProviderLinkedAccountId: Encode + Clone, +// ProviderHasher: Hasher, +// ProviderParaIdProvider: Get, +// Call: Encode, +// ConsumerAccountId: Encode, +// ProviderAccountIdentityDetails: Encode + Bump + Default, +// ConsumerBlockNumber: CheckedSub + Into + Encode, +// ConsumerBlockNumberProvider: Get, +// ConsumerGenesisHashProvider: Get<::Output>, +// SignedExtra: Encode, +// SignedExtraProvider: Get, +// CallVerifier: DidDipOriginFilter, { +// // TODO: Better error handling +// type Error = (); +// type IdentityDetails = ProviderAccountIdentityDetails; +// type Proof = DipSiblingParachainStateProof< +// RelayInfoProvider::BlockNumber, +// MerkleLeavesAndDidSignature< +// MerkleProof< +// Vec>, +// ProofLeaf, >, +// ConsumerBlockNumber, +// >, +// >; +// type Submitter = ConsumerAccountId; +// type VerificationResult = VerificationResult< +// ProviderKeyId, +// ProviderBlockNumber, +// ProviderWeb3Name, +// ProviderLinkedAccountId, +// MAX_REVEALED_KEYS_COUNT, +// MAX_REVEALED_ACCOUNTS_COUNT, +// >; -impl< - Call, - Subject, - RelayInfoProvider, - ParaInfoProvider, - ProviderKeyId, - ProviderParaIdProvider, - ProviderBlockNumber, - ProviderAccountIdentityDetails, - ProviderWeb3Name, - ProviderHasher, - ProviderLinkedAccountId, - ConsumerAccountId, - ConsumerBlockNumber, - ConsumerBlockNumberProvider, - ConsumerGenesisHashProvider, - CallVerifier, - const MAX_REVEALED_KEYS_COUNT: u32, - const MAX_REVEALED_ACCOUNTS_COUNT: u32, - const SIGNATURE_VALIDITY: u64, - SignedExtra, - SignedExtraProvider, - > IdentityProofVerifier - for StateProofDipVerifier< - RelayInfoProvider, - ParaInfoProvider, - ProviderKeyId, - ProviderParaIdProvider, - ProviderBlockNumber, - ProviderAccountIdentityDetails, - ProviderWeb3Name, - ProviderHasher, - ProviderLinkedAccountId, - ConsumerAccountId, - ConsumerBlockNumber, - ConsumerBlockNumberProvider, - ConsumerGenesisHashProvider, - CallVerifier, - MAX_REVEALED_KEYS_COUNT, - MAX_REVEALED_ACCOUNTS_COUNT, - SIGNATURE_VALIDITY, - SignedExtra, - SignedExtraProvider, - > where - RelayInfoProvider: RelayChainStateInfoProvider, - RelayInfoProvider::Hasher: 'static, - ::Output: Ord, - RelayInfoProvider::BlockNumber: Copy + Into + TryFrom + HasCompact, - RelayInfoProvider::Key: AsRef<[u8]>, - ParaInfoProvider: ParachainStateInfoProvider, - ParaInfoProvider::Hasher: 'static, - ::Output: Ord - + Encode - + PartialEq<::Output> - + From<::Output>, - ParaInfoProvider::Commitment: Decode, - ParaInfoProvider::Key: AsRef<[u8]>, - ProviderKeyId: Encode + Clone, - ProviderBlockNumber: Encode + Clone, - ProviderWeb3Name: Encode + Clone, - ProviderLinkedAccountId: Encode + Clone, - ProviderHasher: Hasher, - ProviderParaIdProvider: Get, - Call: Encode, - ConsumerAccountId: Encode, - ProviderAccountIdentityDetails: Encode + Bump + Default, - ConsumerBlockNumber: CheckedSub + Into + Encode, - ConsumerBlockNumberProvider: Get, - ConsumerGenesisHashProvider: Get<::Output>, - SignedExtra: Encode, - SignedExtraProvider: Get, - CallVerifier: DidDipOriginFilter, -{ - // TODO: Better error handling - type Error = (); - type IdentityDetails = ProviderAccountIdentityDetails; - type Proof = DipSiblingParachainStateProof< - RelayInfoProvider::BlockNumber, - MerkleLeavesAndDidSignature< - MerkleProof< - Vec>, - ProofLeaf, - >, - ConsumerBlockNumber, - >, - >; - type Submitter = ConsumerAccountId; - type VerificationResult = VerificationResult< - ProviderKeyId, - ProviderBlockNumber, - ProviderWeb3Name, - ProviderLinkedAccountId, - MAX_REVEALED_KEYS_COUNT, - MAX_REVEALED_ACCOUNTS_COUNT, - >; +// fn verify_proof_for_call_against_details( +// call: &Call, +// subject: &Subject, +// submitter: &Self::Submitter, +// identity_details: &mut Option, +// proof: Self::Proof, +// ) -> Result { +// let DipSiblingParachainStateProof { +// para_root_proof, +// dip_commitment_proof, +// dip_proof, +// } = proof; +// // 1. Verify relay chain proof. +// let provider_parachain_header = +// state_proofs::relay_chain::ParachainHeadProofVerifier::::verify_proof_for_parachain( &ProviderParaIdProvider::get(), +// ¶_root_proof.relay_block_height, +// para_root_proof.proof, +// )?; +// // 2. Verify parachain state proof. +// let subject_identity_commitment = +// state_proofs::parachain::DipCommitmentValueProofVerifier::::verify_proof_for_identifier( +// subject, +// provider_parachain_header.state_root.into(), +// dip_commitment_proof, +// )?; - fn verify_proof_for_call_against_details( - call: &Call, - subject: &Subject, - submitter: &Self::Submitter, - identity_details: &mut Option, - proof: Self::Proof, - ) -> Result { - let DipSiblingParachainStateProof { - para_root_proof, - dip_commitment_proof, - dip_proof, - } = proof; - // 1. Verify relay chain proof. - let provider_parachain_header = - state_proofs::relay_chain::ParachainHeadProofVerifier::::verify_proof_for_parachain( - &ProviderParaIdProvider::get(), - ¶_root_proof.relay_block_height, - para_root_proof.proof, - )?; - // 2. Verify parachain state proof. - let subject_identity_commitment = - state_proofs::parachain::DipCommitmentValueProofVerifier::::verify_proof_for_identifier( - subject, - provider_parachain_header.state_root.into(), - dip_commitment_proof, - )?; +// // 3. Verify DIP identity proof (taken from existing implementation). +// let proof_leaves = dip_proof +// .merkle_leaves +// .revealed +// .iter() +// .map(|leaf| (leaf.encoded_key(), Some(leaf.encoded_value()))) +// .collect::, Option>)>>(); +// verify_trie_proof::, _, _, _>( +// &subject_identity_commitment, +// &dip_proof.merkle_leaves.blinded, +// &proof_leaves, +// ) +// .map_err(|_| ())?; +// #[allow(clippy::type_complexity)] +// let (did_keys, web3_name, linked_accounts): ( +// BoundedVec, +// ConstU32>, Option>, BoundedVec>, ) = dip_proof.merkle_leaves.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 { +// 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, linked_accounts)) +// } +// // TODO: Avoid cloning if possible +// 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)) +// } +// }, +// )?; +// let verification_result = VerificationResult { +// did_keys, +// web3_name, +// linked_accounts, +// }; - // 3. Verify DIP identity proof (taken from existing implementation). - let proof_leaves = dip_proof - .merkle_leaves - .revealed - .iter() - .map(|leaf| (leaf.encoded_key(), Some(leaf.encoded_value()))) - .collect::, Option>)>>(); - verify_trie_proof::, _, _, _>( - &subject_identity_commitment, - &dip_proof.merkle_leaves.blinded, - &proof_leaves, - ) - .map_err(|_| ())?; - #[allow(clippy::type_complexity)] - let (did_keys, web3_name, linked_accounts): ( - BoundedVec, ConstU32>, - Option>, - BoundedVec>, - ) = dip_proof.merkle_leaves.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 { - 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, linked_accounts)) - } - // TODO: Avoid cloning if possible - 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)) - } - }, - )?; - let verification_result = VerificationResult { - did_keys, - web3_name, - linked_accounts, - }; - - // 4. Verify DID signature (taken from existing implementation). - let block_number = ConsumerBlockNumberProvider::get(); - let is_signature_fresh = - if let Some(blocks_ago_from_now) = block_number.checked_sub(&dip_proof.did_signature.block_number) { - blocks_ago_from_now.into() <= SIGNATURE_VALIDITY - } else { - false - }; - ensure!(is_signature_fresh, ()); - let encoded_payload = ( - call, - &identity_details, - submitter, - &dip_proof.did_signature.block_number, - ConsumerGenesisHashProvider::get(), - SignedExtraProvider::get(), - ) - .encode(); - let mut proof_verification_keys = verification_result.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, &dip_proof.did_signature.signature) - .is_ok() - }); - let Some((key, relationship)) = valid_signing_key else { return Err(()) }; - if let Some(details) = identity_details { - details.bump(); - } else { - *identity_details = Some(Self::IdentityDetails::default()); - } - // 4.1 Verify call required relationship - CallVerifier::check_call_origin_info(call, &(key.clone(), relationship)).map_err(|_| ())?; - Ok(verification_result) - } -} +// // 4. Verify DID signature (taken from existing implementation). +// let block_number = ConsumerBlockNumberProvider::get(); +// let is_signature_fresh = +// if let Some(blocks_ago_from_now) = +// block_number.checked_sub(&dip_proof.did_signature.block_number) { +// blocks_ago_from_now.into() <= SIGNATURE_VALIDITY +// } else { +// false +// }; +// ensure!(is_signature_fresh, ()); +// let encoded_payload = ( +// call, +// &identity_details, +// submitter, +// &dip_proof.did_signature.block_number, +// ConsumerGenesisHashProvider::get(), +// SignedExtraProvider::get(), +// ) +// .encode(); +// let mut proof_verification_keys = +// verification_result.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, &dip_proof.did_signature.signature) +// .is_ok() +// }); +// let Some((key, relationship)) = valid_signing_key else { return Err(()) }; +// if let Some(details) = identity_details { +// details.bump(); +// } else { +// *identity_details = Some(Self::IdentityDetails::default()); +// } +// // 4.1 Verify call required relationship +// CallVerifier::check_call_origin_info(call, &(key.clone(), +// relationship)).map_err(|_| ())?; Ok(verification_result) +// } +// } diff --git a/crates/kilt-dip-support/src/merkle.rs b/crates/kilt-dip-support/src/merkle.rs index f77c78381e..a24b9a97de 100644 --- a/crates/kilt-dip-support/src/merkle.rs +++ b/crates/kilt-dip-support/src/merkle.rs @@ -203,10 +203,8 @@ impl< /// Can also be used on its own, without any DID signature verification. pub struct DidMerkleProofVerifier< Hasher, - AccountId, KeyId, BlockNumber, - Details, Web3Name, LinkedAccountId, const MAX_REVEALED_KEYS_COUNT: u32, @@ -215,10 +213,8 @@ pub struct DidMerkleProofVerifier< #[allow(clippy::type_complexity)] PhantomData<( Hasher, - AccountId, KeyId, BlockNumber, - Details, Web3Name, LinkedAccountId, ConstU32, @@ -227,57 +223,43 @@ pub struct DidMerkleProofVerifier< ); 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< + > + 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 IdentityDetails = IdentityDetails; - type Submitter = AccountId; - type VerificationResult = VerificationResult< - KeyId, - BlockNumber, - Web3Name, - LinkedAccountId, - MAX_REVEALED_KEYS_COUNT, - MAX_REVEALED_ACCOUNTS_COUNT, - >; - - fn verify_proof_for_call_against_details( - _call: &Call, - _subject: &Subject, - _submitter: &Self::Submitter, - identity_details: &mut Option, - proof: Self::Proof, - ) -> Result { + pub fn verify_dip_merkle_proof( + identity_commitment: &Hasher::Out, + proof: MerkleProof>, ProofLeaf>, + ) -> Result< + VerificationResult< + KeyId, + BlockNumber, + Web3Name, + LinkedAccountId, + MAX_REVEALED_KEYS_COUNT, + MAX_REVEALED_ACCOUNTS_COUNT, + >, + (), + > { // 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>)>. @@ -286,8 +268,7 @@ impl< .iter() .map(|leaf| (leaf.encoded_key(), Some(leaf.encoded_value()))) .collect::, Option>)>>(); - let Some(identity_details) = identity_details else { return Err(()) }; - verify_trie_proof::, _, _, _>(&identity_details.digest, &proof.blinded, &proof_leaves) + verify_trie_proof::, _, _, _>(identity_commitment, &proof.blinded, &proof_leaves) .map_err(|_| ())?; // At this point, we know the proof is valid. We just need to map the revealed diff --git a/crates/kilt-dip-support/src/state_proofs.rs b/crates/kilt-dip-support/src/state_proofs.rs index ca26235591..c7734622ca 100644 --- a/crates/kilt-dip-support/src/state_proofs.rs +++ b/crates/kilt-dip-support/src/state_proofs.rs @@ -16,14 +16,20 @@ // If you feel like getting in touch with us, you can do so at info@botlabs.org +use pallet_dip_consumer::traits::IdentityProofVerifier; use parity_scale_codec::{Decode, HasCompact}; -use sp_core::U256; -use sp_runtime::{generic::Header, traits::Hash}; +use sp_core::{ConstU32, U256}; +use sp_runtime::generic::Header; use sp_std::{marker::PhantomData, vec::Vec}; use sp_trie::StorageProof; use substrate_no_std_port::read_proof_check; +use crate::{ + merkle::MerkleProof, + state_proofs::{parachain::DipCommitmentValueProofVerifier, relay_chain::ParachainHeadProofVerifier}, +}; + // Ported from https://github.com/paritytech/substrate/blob/b27c470eaff379f512d1dec052aff5d551ed3b03/primitives/state-machine/src/lib.rs#L1076 // Needs to be replaced with its runtime-friendly version when available, or be // kept up-to-date with upstream. @@ -83,18 +89,115 @@ mod substrate_no_std_port { } } -pub mod relay_chain { +#[derive(Encode, Decode, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug, TypeInfo, Clone)] +pub struct DipSiblingParachainStateProof { + para_root_proof: ParaRootProof, + dip_commitment_proof: Vec>, + inner: InnerProof, +} + +pub struct DipCommitmentStateProofVerifier< + RelayInfoProvider, + IdentityDetails, + Submitter, + ProviderParaIdProvider, + ParaInfoProvider, + ProviderAccountId, + ProviderKeyId, + ProviderWeb3Name, + ProviderLinkedAccountId, + const MAX_REVEALED_KEYS_COUNT: u32, + const MAX_REVEALED_ACCOUNTS_COUNT: u32, +>( + PhantomData<( + RelayInfoProvider, + IdentityDetails, + Submitter, + ProviderParaIdProvider, + ParaInfoProvider, + ProviderAccountId, + ProviderKeyId, + ProviderWeb3Name, + ProviderLinkedAccountId, + ConstU32, + ConstU32, + )>, +); + +impl + IdentityProofVerifier + for DipCommitmentStateProofVerifier< + IdentityDetails, + Submitter, + RelayInfoProvider, + ProviderParaIdProvider, + ParaInfoProvider, + > where + RelayInfoProvider: RelayChainStateInfoProvider, + RelayInfoProvider::Hasher: 'static, + OutputOf: Ord, + RelayInfoProvider::BlockNumber: Copy + Into + TryFrom + HasCompact, + RelayInfoProvider::Key: AsRef<[u8]>, + ProviderParaIdProvider: Get, + ParaInfoProvider: ParachainStateInfoProvider, + ParaInfoProvider::Hasher: 'static, + OutputOf: Ord, + ParaInfoProvider::Commitment: Decode, + ParaInfoProvider::Key: AsRef<[u8]>, +{ + type Error = (); + type IdentityDetails = IdentityDetails; + type Proof = DipSiblingParachainStateProof; + type Submitter = Submitter; + type VerificationResult = ParaInfoProvider::Commitment; + + fn verify_proof_for_call_against_details( + call: &Call, + subject: &Subject, + submitter: &Self::Submitter, + identity_details: &mut Option, + proof: Self::Proof, + ) -> Result { + let parachain_header = ParachainHeadProofVerifier::< + RelayInfoProvider, + IdentityDetails, + Submitter, + ProviderParaIdProvider, + >::verify_proof_for_parachain( + &ProviderParaIdProvider::get(), + &proof.relay_block_height, + proof.para_root_proof, + )?; + DipCommitmentValueProofVerifier::::verify_proof_for_identifier( + subject, + parachain_header.state_root.into(), + proof.dip_commitment_proof, + ) + } +} + +mod relay_chain { use super::*; - use crate::traits::RelayChainStateInfoProvider; + use sp_core::Get; + + use pallet_dip_consumer::traits::IdentityProofVerifier; - pub struct ParachainHeadProofVerifier(PhantomData); + use crate::{ + traits::{OutputOf, RelayChainStateInfoProvider}, + ParaRootProof, + }; - impl ParachainHeadProofVerifier + pub(super) struct ParachainHeadProofVerifier( + PhantomData<(RelayInfoProvider, IdentityDetails, Submitter, ProviderParaIdProvider)>, + ); + + impl + ParachainHeadProofVerifier where RelayInfoProvider: RelayChainStateInfoProvider, RelayInfoProvider::Hasher: 'static, - ::Output: Ord, + OutputOf: Ord, RelayInfoProvider::BlockNumber: Copy + Into + TryFrom + HasCompact, RelayInfoProvider::Key: AsRef<[u8]>, { @@ -104,8 +207,7 @@ pub mod relay_chain { relay_height: &RelayInfoProvider::BlockNumber, proof: impl IntoIterator>, ) -> Result, ()> { - let relay_state_root: <::Hasher as Hash>::Output = - RelayInfoProvider::state_root_for_block(relay_height).ok_or(())?; + let relay_state_root = RelayInfoProvider::state_root_for_block(relay_height).ok_or(())?; let parachain_storage_key = RelayInfoProvider::parachain_head_storage_key(para_id); let storage_proof = StorageProof::new(proof); let revealed_leaves = read_proof_check::( @@ -115,8 +217,10 @@ pub mod relay_chain { ) .map_err(|_| ())?; // TODO: Remove at some point - debug_assert!(revealed_leaves.len() == 1usize); - debug_assert!(revealed_leaves.contains_key(parachain_storage_key.as_ref())); + { + debug_assert!(revealed_leaves.len() == 1usize); + debug_assert!(revealed_leaves.contains_key(parachain_storage_key.as_ref())); + } let Some(Some(encoded_head)) = revealed_leaves.get(parachain_storage_key.as_ref()) else { return Err(()) }; // TODO: Figure out why RPC call returns 2 bytes in front which we don't need let mut unwrapped_head = &encoded_head[2..]; @@ -124,6 +228,35 @@ pub mod relay_chain { } } + pub struct RococoParachainRuntime(PhantomData); + + impl RelayChainStateInfoProvider for RococoParachainRuntime + where + Runtime: pallet_relay_store::Config, + { + type BlockNumber = u32; + type Hasher = BlakeTwo256; + type Key = StorageKey; + type ParaId = u32; + + fn state_root_for_block(block_height: &Self::BlockNumber) -> Option> { + pallet_relay_store::Pallet::::latest_relay_head_for_block(block_height) + .map(|relay_header| relay_header.relay_parent_storage_root) + } + + fn parachain_head_storage_key(para_id: &Self::ParaId) -> Self::Key { + // TODO: It's not possible to access the runtime definition from here. + let encoded_para_id = para_id.encode(); + let storage_key = [ + frame_support::storage::storage_prefix(b"Paras", b"Heads").as_slice(), + sp_io::hashing::twox_64(&encoded_para_id).as_slice(), + encoded_para_id.as_slice(), + ] + .concat(); + StorageKey(storage_key) + } + } + #[cfg(test)] mod polkadot_parachain_head_proof_verifier_tests { use super::*; @@ -157,9 +290,7 @@ pub mod relay_chain { StorageKey(storage_key) } - fn state_root_for_block( - _block_height: &Self::BlockNumber, - ) -> Option<::Output> { + fn state_root_for_block(_block_height: &Self::BlockNumber) -> Option> { Some(hex!("81b75d95075d16005ee0a987a3f061d3011ada919b261e9b02961b9b3725f3fd").into()) } } @@ -180,36 +311,39 @@ pub mod relay_chain { // "0xcd710b30bd2eab0352ddcc26417aa1941b3c252fcb29d88eff4f3de5de4476c32c0cfd6c23b92a7826080000" // let expected_spiritnet_head_at_block = hex!("65541097fb02782e14f43074f0b00e44ae8e9fe426982323ef1d329739740d37f252ff006d1156941db1bccd58ce3a1cac4f40cad91f692d94e98f501dd70081a129b69a3e2ef7e1ff84ba3d86dab4e95f2c87f6b1055ebd48519c185360eae58f05d1ea08066175726120dcdc6308000000000561757261010170ccfaf3756d1a8dd8ae5c89094199d6d32e5dd9f0920f6fe30f986815b5e701974ea0e0e0a901401f2c72e3dd8dbdf4aa55d59bf3e7021856cdb8038419eb8c").to_vec(); - let returned_head = ParachainHeadProofVerifier::::verify_proof_for_parachain( - &2_086, - &16_363_919, - spiritnet_head_proof_at_block, - ) - .expect("Parachain head proof verification should not fail."); + let returned_head = + ParachainHeadProofVerifier::::verify_proof_for_parachain( + &2_086, + &16_363_919, + spiritnet_head_proof_at_block, + ) + .expect("Parachain head proof verification should not fail."); assert!(returned_head.encode() == expected_spiritnet_head_at_block, "Parachain head returned from the state proof verification should not be different than the pre-computed one."); } } } -pub mod parachain { +mod parachain { + use pallet_dip_consumer::traits::IdentityProofVerifier; + use super::*; - use crate::traits::ParachainStateInfoProvider; + use crate::traits::{OutputOf, ParachainStateInfoProvider}; - pub struct DipCommitmentValueProofVerifier(PhantomData); + pub(super) struct DipCommitmentValueProofVerifier(PhantomData); impl DipCommitmentValueProofVerifier where ParaInfoProvider: ParachainStateInfoProvider, ParaInfoProvider::Hasher: 'static, - ::Output: Ord, + OutputOf: Ord, ParaInfoProvider::Commitment: Decode, ParaInfoProvider::Key: AsRef<[u8]>, { #[allow(clippy::result_unit_err)] pub fn verify_proof_for_identifier( identifier: &ParaInfoProvider::Identifier, - state_root: ::Output, + state_root: OutputOf, proof: impl IntoIterator>, ) -> Result { let dip_commitment_storage_key = ParaInfoProvider::dip_subject_storage_key(identifier); @@ -221,13 +355,39 @@ pub mod parachain { ) .map_err(|_| ())?; // TODO: Remove at some point - debug_assert!(revealed_leaves.len() == 1usize); - debug_assert!(revealed_leaves.contains_key(dip_commitment_storage_key.as_ref())); + { + debug_assert!(revealed_leaves.len() == 1usize); + debug_assert!(revealed_leaves.contains_key(dip_commitment_storage_key.as_ref())); + } let Some(Some(encoded_commitment)) = revealed_leaves.get(dip_commitment_storage_key.as_ref()) else { return Err(()) }; ParaInfoProvider::Commitment::decode(&mut &encoded_commitment[..]).map_err(|_| ()) } } + pub struct DipProviderParachainRuntime(PhantomData); + + impl ParachainStateInfoProvider for DipProviderParachainRuntime + where + Runtime: pallet_dip_provider::Config, + { + type Commitment = ::IdentityCommitment; + type Hasher = ::Hashing; + type Identifier = ::Identifier; + type Key = StorageKey; + + fn dip_subject_storage_key(identifier: &Self::Identifier) -> Self::Key { + // TODO: Replace with actual runtime definition + let encoded_identifier = identifier.encode(); + let storage_key = [ + frame_support::storage::storage_prefix(b"DipProvider", b"IdentityCommitments").as_slice(), + sp_io::hashing::twox_64(&encoded_identifier).as_slice(), + encoded_identifier.as_slice(), + ] + .concat(); + StorageKey(storage_key) + } + } + #[cfg(test)] mod spiritnet_test_event_count_value { use super::*; diff --git a/crates/kilt-dip-support/src/traits.rs b/crates/kilt-dip-support/src/traits.rs index ee092a3064..aabcadfe9b 100644 --- a/crates/kilt-dip-support/src/traits.rs +++ b/crates/kilt-dip-support/src/traits.rs @@ -54,28 +54,7 @@ pub trait DidDipOriginFilter { fn check_call_origin_info(call: &Call, info: &Self::OriginInfo) -> Result; } -pub struct GenesisProvider(PhantomData); - -impl Get for GenesisProvider -where - T: frame_system::Config, - T::BlockNumber: Zero, -{ - fn get() -> T::Hash { - frame_system::Pallet::::block_hash(T::BlockNumber::zero()) - } -} - -pub struct BlockNumberProvider(PhantomData); - -impl Get for BlockNumberProvider -where - T: frame_system::Config, -{ - fn get() -> T::BlockNumber { - frame_system::Pallet::::block_number() - } -} +pub type OutputOf = ::Output; pub trait RelayChainStateInfoProvider { type BlockNumber; @@ -83,44 +62,10 @@ pub trait RelayChainStateInfoProvider { type Hasher: sp_runtime::traits::Hash; type ParaId; - fn state_root_for_block( - block_height: &Self::BlockNumber, - ) -> Option<::Output>; + fn state_root_for_block(block_height: &Self::BlockNumber) -> Option>; fn parachain_head_storage_key(para_id: &Self::ParaId) -> Self::Key; } -pub struct RococoParachainRuntime(PhantomData); - -impl RelayChainStateInfoProvider for RococoParachainRuntime -where - Runtime: pallet_relay_store::Config, -{ - type BlockNumber = u32; - // TODO: This is not exported - type Hasher = BlakeTwo256; - type Key = StorageKey; - type ParaId = u32; - - fn state_root_for_block( - block_height: &Self::BlockNumber, - ) -> Option<::Output> { - pallet_relay_store::Pallet::::latest_relay_head_for_block(block_height) - .map(|relay_header| relay_header.relay_parent_storage_root) - } - - fn parachain_head_storage_key(para_id: &Self::ParaId) -> Self::Key { - // TODO: It's not possible to access the runtime definition from here. - let encoded_para_id = para_id.encode(); - let storage_key = [ - frame_support::storage::storage_prefix(b"Paras", b"Heads").as_slice(), - sp_io::hashing::twox_64(&encoded_para_id).as_slice(), - encoded_para_id.as_slice(), - ] - .concat(); - StorageKey(storage_key) - } -} - pub trait ParachainStateInfoProvider { type Commitment; type Key; @@ -130,26 +75,41 @@ pub trait ParachainStateInfoProvider { fn dip_subject_storage_key(identifier: &Self::Identifier) -> Self::Key; } -pub struct DipProviderParachainRuntime(PhantomData); +pub trait DidSignatureVerifierContextProvider { + const SIGNATURE_VALIDITY: Self::BlockNumber; + + type BlockNumber; + type Hash; + type SignedExtra; + + fn block_number() -> Self::BlockNumber; + fn genesis_hash() -> Self::Hash; + fn signed_extra() -> Option; +} + +pub struct FrameSystemProvider(PhantomData); -impl ParachainStateInfoProvider for DipProviderParachainRuntime +impl DidSignatureVerifierContextProvider + for FrameSystemProvider where - Runtime: pallet_dip_provider::Config, + T: frame_system::Config, + T::BlockNumber: From, { - type Commitment = ::IdentityCommitment; - type Hasher = ::Hashing; - type Identifier = ::Identifier; - type Key = StorageKey; - - fn dip_subject_storage_key(identifier: &Self::Identifier) -> Self::Key { - // TODO: Replace with actual runtime definition - let encoded_identifier = identifier.encode(); - let storage_key = [ - frame_support::storage::storage_prefix(b"DipProvider", b"IdentityCommitments").as_slice(), - sp_io::hashing::twox_64(&encoded_identifier).as_slice(), - encoded_identifier.as_slice(), - ] - .concat(); - StorageKey(storage_key) + const SIGNATURE_VALIDITY: Self::BlockNumber = Self::BlockNumber::from(SIGNATURE_VALIDITY); + + type BlockNumber = T::BlockNumber; + type Hash = T::Hash; + type SignedExtra = (); + + fn block_number() -> Self::BlockNumber { + frame_system::Pallet::::block_number() + } + + fn genesis_hash() -> Self::Hash { + frame_system::Pallet::::block_hash(T::BlockNumber::zero()) + } + + fn signed_extra() -> Option { + None } } From d7dda64cf7a735ffcad345512452054391748a60 Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Thu, 20 Jul 2023 16:45:12 +0200 Subject: [PATCH 19/32] Step n.2 --- crates/kilt-dip-support/src/did.rs | 316 ++------------------ crates/kilt-dip-support/src/lib.rs | 230 +++++++++++++- crates/kilt-dip-support/src/state_proofs.rs | 119 +------- crates/kilt-dip-support/src/traits.rs | 9 +- 4 files changed, 271 insertions(+), 403 deletions(-) diff --git a/crates/kilt-dip-support/src/did.rs b/crates/kilt-dip-support/src/did.rs index bbdf35ed8a..fa6dde6091 100644 --- a/crates/kilt-dip-support/src/did.rs +++ b/crates/kilt-dip-support/src/did.rs @@ -32,7 +32,7 @@ use sp_runtime::traits::CheckedSub; use sp_std::marker::PhantomData; use crate::{ - merkle::RevealedDidKey, + merkle::{DidMerkleProofVerifier, RevealedDidKey}, traits::{Bump, DidDipOriginFilter, DidSignatureVerifierContextProvider}, }; @@ -48,7 +48,7 @@ pub struct MerkleLeavesAndDidSignature { pub did_signature: TimeBoundDidSignature, } -pub struct MerkleDidSignatureVerifier< +pub struct MerkleDidSignatureAndCallVerifier< Call, Submitter, DidLocalDetails, @@ -56,6 +56,7 @@ pub struct MerkleDidSignatureVerifier< ContextProvider, RemoteKeyId, RemoteBlockNumber, + CallVerifier, >( PhantomData<( Call, @@ -65,11 +66,11 @@ pub struct MerkleDidSignatureVerifier< ContextProvider, RemoteKeyId, RemoteBlockNumber, + CallVerifier, )>, ); -impl - MerkleDidSignatureVerifier< +impl< Call, Submitter, DidLocalDetails, @@ -77,13 +78,27 @@ impl + MerkleDidSignatureAndCallVerifier< + Call, + Submitter, + DidLocalDetails, + MerkleProofEntries, + ContextProvider, + RemoteKeyId, + RemoteBlockNumber, + CallVerifier, > where + Call: Encode, + Submitter: Encode, ContextProvider: DidSignatureVerifierContextProvider, - ContextProvider::BlockNumber: Encode + CheckedSub + PartialOrd, + ContextProvider::BlockNumber: Encode + CheckedSub + PartialOrd, ContextProvider::Hash: Encode, ContextProvider::SignedExtra: Encode, DidLocalDetails: Bump + Default + Encode, MerkleProofEntries: AsRef<[RevealedDidKey]>, + CallVerifier: DidDipOriginFilter, { pub fn verify_did_signature_for_call( call: &Call, @@ -115,7 +130,7 @@ impl( -// #[allow(clippy::type_complexity)] -// PhantomData<( -// KeyId, -// BlockNumber, -// Digest, -// Details, -// AccountId, -// MerkleProofEntries, -// BlockNumberProvider, -// ConstU64, -// GenesisHashProvider, -// Hash, -// SignedExtraProvider, -// SignedExtra, -// )>, -// ); -// impl< -// Call, -// Subject, -// KeyId, -// BlockNumber, -// Digest, -// Details, -// AccountId, -// MerkleProofEntries, -// BlockNumberProvider, -// const SIGNATURE_VALIDITY: u64, -// GenesisHashProvider, -// Hash, -// SignedExtraProvider, -// SignedExtra, -// > IdentityProofVerifier -// for MerkleRevealedDidSignatureVerifier< -// KeyId, -// BlockNumber, -// Digest, -// Details, -// AccountId, -// MerkleProofEntries, -// BlockNumberProvider, -// SIGNATURE_VALIDITY, -// GenesisHashProvider, -// Hash, -// SignedExtraProvider, -// SignedExtra, -// > where -// AccountId: Encode, -// BlockNumber: Encode + CheckedSub + Into + PartialOrd + sp_std::fmt::Debug, -// Call: Encode, -// Digest: Encode, -// Details: Bump + Default + Encode, -// MerkleProofEntries: AsRef<[RevealedDidKey]>, -// BlockNumberProvider: Get, -// GenesisHashProvider: Get, -// Hash: Encode, -// SignedExtraProvider: Get, -// SignedExtra: Encode, -// { -// // TODO: Error handling -// 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 = MerkleLeavesAndDidSignature; -// /// The `Details` that are part of the identity details must implement the -// /// `Bump` trait. -// type IdentityDetails = Details; -// /// The type of the submitter's accounts. -// type Submitter = AccountId; -// /// Successful verifications return the verification key used to validate -// /// the provided signature and its relationship to the DID subject. -// type VerificationResult = (DidVerificationKey, DidVerificationKeyRelationship); - -// fn verify_proof_for_call_against_details( -// call: &Call, -// _subject: &Subject, -// submitter: &Self::Submitter, -// identity_details: &mut Option, -// proof: Self::Proof, -// ) -> Result { -// let block_number = BlockNumberProvider::get(); -// let is_signature_fresh = -// if let Some(blocks_ago_from_now) = block_number.checked_sub(&proof.did_signature.block_number) { -// // False if the signature is too old. -// blocks_ago_from_now.into() <= SIGNATURE_VALIDITY -// } else { -// // Signature generated at a future time, not possible to verify. -// false -// }; - -// ensure!(is_signature_fresh, ()); -// let encoded_payload = ( -// call, -// &identity_details, -// submitter, -// &proof.did_signature.block_number, -// GenesisHashProvider::get(), -// SignedExtraProvider::get(), -// ) -// .encode(); -// // 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() -// }); -// let Some((key, relationship)) = valid_signing_key else { return Err(()) }; -// // TODO: bump details. -// if let Some(details) = identity_details { -// details.bump(); -// } else { -// *identity_details = Some(Details::default()); -// } -// Ok((key.clone(), relationship)) -// } -// } - -/// A type that chains a DID signature verification, as provided by -/// `MerkleRevealedDidSignatureVerifier`, and a call filtering logic based on -/// the type of key used in the signature. -/// Verification bails out early in case of invalid DID signatures. Otherwise, -/// the retrieved key and its relationship is passed to the call verifier to do -/// some additional lookups on the call. The `CallVerifier` only performs -/// internal checks, while all input and output types are taken from the -/// provided `DidSignatureVerifier` type. -// pub struct DidSignatureAndCallVerifier( -// PhantomData<(DidSignatureVerifier, CallVerifier)>, -// ); - -// impl -// IdentityProofVerifier -// for DidSignatureAndCallVerifier -// where -// DidSignatureVerifier: IdentityProofVerifier, -// CallVerifier: DidDipOriginFilter, { -// // FIXME: Better error handling -// type Error = (); -// /// The input proof is the same accepted by the `DidSignatureVerifier`. -// type Proof = DidSignatureVerifier::Proof; -// /// The identity details are the same accepted by the -// /// `DidSignatureVerifier`. -// type IdentityDetails = DidSignatureVerifier::IdentityDetails; -// /// The submitter address is the same accepted by the -// /// `DidSignatureVerifier`. -// type Submitter = DidSignatureVerifier::Submitter; -// /// The verification result is the same accepted by the -// /// `DidSignatureVerifier`. -// type VerificationResult = DidSignatureVerifier::VerificationResult; - -// fn verify_proof_for_call_against_details( -// call: &Call, -// subject: &Subject, -// submitter: &Self::Submitter, -// identity_details: &mut Option, -// proof: Self::Proof, -// ) -> Result { -// 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) -// } -// } - -pub struct CombinedIdentityResult { - pub a: OutputA, - pub b: OutputB, - 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, - 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 -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/crates/kilt-dip-support/src/lib.rs b/crates/kilt-dip-support/src/lib.rs index 3a257be4f3..9df639e597 100644 --- a/crates/kilt-dip-support/src/lib.rs +++ b/crates/kilt-dip-support/src/lib.rs @@ -21,6 +21,7 @@ #![cfg_attr(not(feature = "std"), no_std)] use frame_support::ensure; +use pallet_dip_provider::traits::IdentityProvider; use parity_scale_codec::{Decode, Encode, HasCompact}; use scale_info::TypeInfo; use sp_core::{ConstU32, ConstU64, Get, Hasher, RuntimeDebug, U256}; @@ -37,19 +38,244 @@ use ::did::{ }; use pallet_dip_consumer::traits::IdentityProofVerifier; -use crate::merkle::{MerkleProof, ProofLeaf, RevealedDidKey, RevealedWeb3Name, VerificationResult}; +use crate::{ + merkle::{MerkleProof, ProofLeaf, RevealedDidKey, RevealedWeb3Name, VerificationResult}, + traits::{ + Bump, DidDipOriginFilter, DidSignatureVerifierContextProvider, OutputOf, ParachainStateInfoProvider, + RelayChainStateInfoProvider, + }, +}; pub mod did; pub mod merkle; -// pub mod state_proofs; +pub mod state_proofs; pub mod traits; +pub struct CombinedIdentityResult { + pub a: OutputA, + pub b: OutputB, + 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, + 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 +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(()), + } + } +} + +#[derive(Encode, Decode, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug, TypeInfo, Clone)] +pub struct DipStateProof { + para_root_proof: ParaRootProof, + dip_commitment_proof: Vec>, + dip_proof: DipProof, +} + #[derive(Encode, Decode, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug, TypeInfo, Clone)] pub struct ParaRootProof { relay_block_height: RelayBlockHeight, proof: Vec>, } +pub struct StateProofDipIdentifier< + RelayInfoProvider, + ParaInfoProvider, + TxSubmitter, + ProviderDipMerkleHasher, + ProviderDidKeyId, + ProviderBlockNumber, + ProviderWeb3Name, + ProviderLinkedAccountId, + const MAX_REVEALED_KEYS_COUNT: u32, + const MAX_REVEALED_ACCOUNTS_COUNT: u32, + DidLocalDetails, + LocalContextProvider, + LocalDidCallVerifier, +>( + PhantomData<( + RelayInfoProvider, + ParaInfoProvider, + TxSubmitter, + ProviderDipMerkleHasher, + ProviderDidKeyId, + ProviderBlockNumber, + ProviderWeb3Name, + ProviderLinkedAccountId, + DidLocalDetails, + LocalContextProvider, + LocalDidCallVerifier, + )>, +); + +impl< + Call, + Subject, + RelayInfoProvider, + ParaInfoProvider, + TxSubmitter, + ProviderDipMerkleHasher, + ProviderDidKeyId, + ProviderBlockNumber, + ProviderWeb3Name, + ProviderLinkedAccountId, + const MAX_REVEALED_KEYS_COUNT: u32, + const MAX_REVEALED_ACCOUNTS_COUNT: u32, + DidLocalDetails, + LocalContextProvider, + LocalDidCallVerifier, + > IdentityProofVerifier + for StateProofDipIdentifier< + RelayInfoProvider, + ParaInfoProvider, + TxSubmitter, + ProviderDipMerkleHasher, + ProviderDidKeyId, + ProviderBlockNumber, + ProviderWeb3Name, + ProviderLinkedAccountId, + MAX_REVEALED_KEYS_COUNT, + MAX_REVEALED_ACCOUNTS_COUNT, + DidLocalDetails, + LocalContextProvider, + LocalDidCallVerifier, + > where + Call: Encode, + TxSubmitter: Encode, + + RelayInfoProvider: RelayChainStateInfoProvider, + RelayInfoProvider::Hasher: 'static, + OutputOf: Ord, + RelayInfoProvider::BlockNumber: Copy + Into + TryFrom + HasCompact, + RelayInfoProvider::Key: AsRef<[u8]>, + + ParaInfoProvider: ParachainStateInfoProvider, + ParaInfoProvider::Hasher: 'static, + OutputOf: Ord, + ParaInfoProvider::Commitment: Decode, + ParaInfoProvider::Key: AsRef<[u8]>, + + LocalContextProvider: DidSignatureVerifierContextProvider, + LocalContextProvider::BlockNumber: Encode + CheckedSub + PartialOrd, + LocalContextProvider::Hash: Encode, + LocalContextProvider::SignedExtra: Encode, + DidLocalDetails: Bump + Default + Encode, + LocalDidCallVerifier: DidDipOriginFilter, + + ProviderBlockNumber: Encode + Clone, + ProviderDipMerkleHasher: sp_core::Hasher, + ProviderDidKeyId: Encode + Clone + Ord + Into, + ProviderLinkedAccountId: Encode + Clone, + ProviderWeb3Name: Encode + Clone, +{ + type Error = (); + type IdentityDetails = DidLocalDetails; + type Proof = DipStateProof< + RelayInfoProvider::BlockNumber, + MerkleProof< + Vec, + ProofLeaf, + >, + >; + type Submitter = TxSubmitter; + type VerificationResult = VerificationResult< + ProviderDidKeyId, + ProviderBlockNumber, + ProviderWeb3Name, + ProviderLinkedAccountId, + MAX_REVEALED_KEYS_COUNT, + MAX_REVEALED_ACCOUNTS_COUNT, + >; + + fn verify_proof_for_call_against_details( + call: &Call, + subject: &Subject, + submitter: &Self::Submitter, + identity_details: &mut Option, + proof: Self::Proof, + ) -> Result { + Err(()) + } +} + // pub struct StateProofDipVerifier< // RelayInfoProvider, // ParaInfoProvider, diff --git a/crates/kilt-dip-support/src/state_proofs.rs b/crates/kilt-dip-support/src/state_proofs.rs index c7734622ca..7ff07e2a54 100644 --- a/crates/kilt-dip-support/src/state_proofs.rs +++ b/crates/kilt-dip-support/src/state_proofs.rs @@ -89,97 +89,12 @@ mod substrate_no_std_port { } } -#[derive(Encode, Decode, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug, TypeInfo, Clone)] -pub struct DipSiblingParachainStateProof { - para_root_proof: ParaRootProof, - dip_commitment_proof: Vec>, - inner: InnerProof, -} - -pub struct DipCommitmentStateProofVerifier< - RelayInfoProvider, - IdentityDetails, - Submitter, - ProviderParaIdProvider, - ParaInfoProvider, - ProviderAccountId, - ProviderKeyId, - ProviderWeb3Name, - ProviderLinkedAccountId, - const MAX_REVEALED_KEYS_COUNT: u32, - const MAX_REVEALED_ACCOUNTS_COUNT: u32, ->( - PhantomData<( - RelayInfoProvider, - IdentityDetails, - Submitter, - ProviderParaIdProvider, - ParaInfoProvider, - ProviderAccountId, - ProviderKeyId, - ProviderWeb3Name, - ProviderLinkedAccountId, - ConstU32, - ConstU32, - )>, -); - -impl - IdentityProofVerifier - for DipCommitmentStateProofVerifier< - IdentityDetails, - Submitter, - RelayInfoProvider, - ProviderParaIdProvider, - ParaInfoProvider, - > where - RelayInfoProvider: RelayChainStateInfoProvider, - RelayInfoProvider::Hasher: 'static, - OutputOf: Ord, - RelayInfoProvider::BlockNumber: Copy + Into + TryFrom + HasCompact, - RelayInfoProvider::Key: AsRef<[u8]>, - ProviderParaIdProvider: Get, - ParaInfoProvider: ParachainStateInfoProvider, - ParaInfoProvider::Hasher: 'static, - OutputOf: Ord, - ParaInfoProvider::Commitment: Decode, - ParaInfoProvider::Key: AsRef<[u8]>, -{ - type Error = (); - type IdentityDetails = IdentityDetails; - type Proof = DipSiblingParachainStateProof; - type Submitter = Submitter; - type VerificationResult = ParaInfoProvider::Commitment; - - fn verify_proof_for_call_against_details( - call: &Call, - subject: &Subject, - submitter: &Self::Submitter, - identity_details: &mut Option, - proof: Self::Proof, - ) -> Result { - let parachain_header = ParachainHeadProofVerifier::< - RelayInfoProvider, - IdentityDetails, - Submitter, - ProviderParaIdProvider, - >::verify_proof_for_parachain( - &ProviderParaIdProvider::get(), - &proof.relay_block_height, - proof.para_root_proof, - )?; - DipCommitmentValueProofVerifier::::verify_proof_for_identifier( - subject, - parachain_header.state_root.into(), - proof.dip_commitment_proof, - ) - } -} - mod relay_chain { use super::*; - use sp_core::Get; + use parity_scale_codec::Encode; + use sp_core::{storage::StorageKey, Get}; + use sp_runtime::traits::BlakeTwo256; use pallet_dip_consumer::traits::IdentityProofVerifier; @@ -188,12 +103,9 @@ mod relay_chain { ParaRootProof, }; - pub(super) struct ParachainHeadProofVerifier( - PhantomData<(RelayInfoProvider, IdentityDetails, Submitter, ProviderParaIdProvider)>, - ); + pub struct ParachainHeadProofVerifier(PhantomData); - impl - ParachainHeadProofVerifier + impl ParachainHeadProofVerifier where RelayInfoProvider: RelayChainStateInfoProvider, RelayInfoProvider::Hasher: 'static, @@ -311,26 +223,27 @@ mod relay_chain { // "0xcd710b30bd2eab0352ddcc26417aa1941b3c252fcb29d88eff4f3de5de4476c32c0cfd6c23b92a7826080000" // let expected_spiritnet_head_at_block = hex!("65541097fb02782e14f43074f0b00e44ae8e9fe426982323ef1d329739740d37f252ff006d1156941db1bccd58ce3a1cac4f40cad91f692d94e98f501dd70081a129b69a3e2ef7e1ff84ba3d86dab4e95f2c87f6b1055ebd48519c185360eae58f05d1ea08066175726120dcdc6308000000000561757261010170ccfaf3756d1a8dd8ae5c89094199d6d32e5dd9f0920f6fe30f986815b5e701974ea0e0e0a901401f2c72e3dd8dbdf4aa55d59bf3e7021856cdb8038419eb8c").to_vec(); - let returned_head = - ParachainHeadProofVerifier::::verify_proof_for_parachain( - &2_086, - &16_363_919, - spiritnet_head_proof_at_block, - ) - .expect("Parachain head proof verification should not fail."); + let returned_head = ParachainHeadProofVerifier::::verify_proof_for_parachain( + &2_086, + &16_363_919, + spiritnet_head_proof_at_block, + ) + .expect("Parachain head proof verification should not fail."); assert!(returned_head.encode() == expected_spiritnet_head_at_block, "Parachain head returned from the state proof verification should not be different than the pre-computed one."); } } } mod parachain { - use pallet_dip_consumer::traits::IdentityProofVerifier; - use super::*; + use pallet_dip_consumer::traits::IdentityProofVerifier; + use parity_scale_codec::Encode; + use sp_core::storage::StorageKey; + use crate::traits::{OutputOf, ParachainStateInfoProvider}; - pub(super) struct DipCommitmentValueProofVerifier(PhantomData); + pub struct DipCommitmentValueProofVerifier(PhantomData); impl DipCommitmentValueProofVerifier where diff --git a/crates/kilt-dip-support/src/traits.rs b/crates/kilt-dip-support/src/traits.rs index aabcadfe9b..35648e9c09 100644 --- a/crates/kilt-dip-support/src/traits.rs +++ b/crates/kilt-dip-support/src/traits.rs @@ -76,7 +76,7 @@ pub trait ParachainStateInfoProvider { } pub trait DidSignatureVerifierContextProvider { - const SIGNATURE_VALIDITY: Self::BlockNumber; + const SIGNATURE_VALIDITY: u16; type BlockNumber; type Hash; @@ -87,15 +87,14 @@ pub trait DidSignatureVerifierContextProvider { fn signed_extra() -> Option; } -pub struct FrameSystemProvider(PhantomData); +pub struct FrameSystemProvider(PhantomData); -impl DidSignatureVerifierContextProvider +impl DidSignatureVerifierContextProvider for FrameSystemProvider where T: frame_system::Config, - T::BlockNumber: From, { - const SIGNATURE_VALIDITY: Self::BlockNumber = Self::BlockNumber::from(SIGNATURE_VALIDITY); + const SIGNATURE_VALIDITY: u16 = SIGNATURE_VALIDITY; type BlockNumber = T::BlockNumber; type Hash = T::Hash; From 6b94cbf2c74cbc14d42e74ef12bc9131a2063260 Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Fri, 21 Jul 2023 09:01:04 +0200 Subject: [PATCH 20/32] all good --- crates/kilt-dip-support/src/did.rs | 10 +- crates/kilt-dip-support/src/lib.rs | 432 +++++++------------- crates/kilt-dip-support/src/merkle.rs | 8 +- crates/kilt-dip-support/src/state_proofs.rs | 22 +- crates/kilt-dip-support/src/traits.rs | 4 +- 5 files changed, 163 insertions(+), 313 deletions(-) diff --git a/crates/kilt-dip-support/src/did.rs b/crates/kilt-dip-support/src/did.rs index fa6dde6091..63de56c1b6 100644 --- a/crates/kilt-dip-support/src/did.rs +++ b/crates/kilt-dip-support/src/did.rs @@ -16,23 +16,19 @@ // If you feel like getting in touch with us, you can do so at info@botlabs.org -use core::task::Context; - use did::{ did_details::{DidPublicKey, DidPublicKeyDetails, DidVerificationKey}, DidSignature, DidVerificationKeyRelationship, }; use frame_support::ensure; -use pallet_dip_consumer::traits::IdentityProofVerifier; -use pallet_dip_provider::traits::IdentityProvider; use parity_scale_codec::{Decode, Encode}; use scale_info::TypeInfo; -use sp_core::{ConstU64, Get, RuntimeDebug}; +use sp_core::RuntimeDebug; use sp_runtime::traits::CheckedSub; use sp_std::marker::PhantomData; use crate::{ - merkle::{DidMerkleProofVerifier, RevealedDidKey}, + merkle::RevealedDidKey, traits::{Bump, DidDipOriginFilter, DidSignatureVerifierContextProvider}, }; @@ -58,6 +54,7 @@ pub struct MerkleDidSignatureAndCallVerifier< RemoteBlockNumber, CallVerifier, >( + #[allow(clippy::type_complexity)] PhantomData<( Call, Submitter, @@ -100,6 +97,7 @@ impl< MerkleProofEntries: AsRef<[RevealedDidKey]>, CallVerifier: DidDipOriginFilter, { + #[allow(clippy::result_unit_err)] pub fn verify_did_signature_for_call( call: &Call, submitter: &Submitter, diff --git a/crates/kilt-dip-support/src/lib.rs b/crates/kilt-dip-support/src/lib.rs index 9df639e597..cc0a217ba9 100644 --- a/crates/kilt-dip-support/src/lib.rs +++ b/crates/kilt-dip-support/src/lib.rs @@ -24,11 +24,8 @@ use frame_support::ensure; use pallet_dip_provider::traits::IdentityProvider; use parity_scale_codec::{Decode, Encode, HasCompact}; use scale_info::TypeInfo; -use sp_core::{ConstU32, ConstU64, Get, Hasher, RuntimeDebug, U256}; -use sp_runtime::{ - traits::{CheckedSub, Hash}, - BoundedVec, SaturatedConversion, -}; +use sp_core::{ConstU32, Get, RuntimeDebug, U256}; +use sp_runtime::{traits::CheckedSub, BoundedVec, SaturatedConversion}; use sp_std::{marker::PhantomData, vec::Vec}; use sp_trie::{verify_trie_proof, LayoutV1}; @@ -39,6 +36,7 @@ use ::did::{ use pallet_dip_consumer::traits::IdentityProofVerifier; use crate::{ + did::TimeBoundDidSignature, merkle::{MerkleProof, ProofLeaf, RevealedDidKey, RevealedWeb3Name, VerificationResult}, traits::{ Bump, DidDipOriginFilter, DidSignatureVerifierContextProvider, OutputOf, ParachainStateInfoProvider, @@ -143,11 +141,11 @@ where } } -#[derive(Encode, Decode, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug, TypeInfo, Clone)] -pub struct DipStateProof { +#[derive(Encode, Decode, PartialEq, Eq, RuntimeDebug, TypeInfo, Clone)] +pub struct DipStateProof { para_root_proof: ParaRootProof, dip_commitment_proof: Vec>, - dip_proof: DipProof, + dip_proof: DipMerkleProofAndDidSignature, } #[derive(Encode, Decode, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug, TypeInfo, Clone)] @@ -156,8 +154,15 @@ pub struct ParaRootProof { proof: Vec>, } +#[derive(Encode, Decode, PartialEq, Eq, RuntimeDebug, TypeInfo, Clone)] +pub struct DipMerkleProofAndDidSignature { + merkle_proof: MerkleProof, + did_signature: TimeBoundDidSignature, +} + pub struct StateProofDipIdentifier< RelayInfoProvider, + ProviderParaIdProvider, ParaInfoProvider, TxSubmitter, ProviderDipMerkleHasher, @@ -171,8 +176,10 @@ pub struct StateProofDipIdentifier< LocalContextProvider, LocalDidCallVerifier, >( + #[allow(clippy::type_complexity)] PhantomData<( RelayInfoProvider, + ProviderParaIdProvider, ParaInfoProvider, TxSubmitter, ProviderDipMerkleHasher, @@ -190,6 +197,7 @@ impl< Call, Subject, RelayInfoProvider, + ProviderParaIdProvider, ParaInfoProvider, TxSubmitter, ProviderDipMerkleHasher, @@ -205,6 +213,7 @@ impl< > IdentityProofVerifier for StateProofDipIdentifier< RelayInfoProvider, + ProviderParaIdProvider, ParaInfoProvider, TxSubmitter, ProviderDipMerkleHasher, @@ -227,9 +236,11 @@ impl< RelayInfoProvider::BlockNumber: Copy + Into + TryFrom + HasCompact, RelayInfoProvider::Key: AsRef<[u8]>, - ParaInfoProvider: ParachainStateInfoProvider, + ProviderParaIdProvider: Get, + + ParaInfoProvider: ParachainStateInfoProvider, ParaInfoProvider::Hasher: 'static, - OutputOf: Ord, + OutputOf: Ord + From>, ParaInfoProvider::Commitment: Decode, ParaInfoProvider::Key: AsRef<[u8]>, @@ -250,10 +261,9 @@ impl< type IdentityDetails = DidLocalDetails; type Proof = DipStateProof< RelayInfoProvider::BlockNumber, - MerkleProof< - Vec, - ProofLeaf, - >, + Vec>, + ProofLeaf, + LocalContextProvider::BlockNumber, >; type Submitter = TxSubmitter; type VerificationResult = VerificationResult< @@ -272,274 +282,130 @@ impl< identity_details: &mut Option, proof: Self::Proof, ) -> Result { - Err(()) + // 1. Verify relay chain proof. + let provider_parachain_header = + state_proofs::relay_chain::ParachainHeadProofVerifier::::verify_proof_for_parachain( + &ProviderParaIdProvider::get(), + &proof.para_root_proof.relay_block_height, + proof.para_root_proof.proof, + )?; + + // 2. Verify parachain state proof. + let subject_identity_commitment = + state_proofs::parachain::DipCommitmentValueProofVerifier::::verify_proof_for_identifier( + subject, + provider_parachain_header.state_root.into(), + proof.dip_commitment_proof, + )?; + + // 3. Verify DIP identity proof. + let proof_leaves = proof + .dip_proof + .merkle_proof + .revealed + .iter() + .map(|leaf| (leaf.encoded_key(), Some(leaf.encoded_value()))) + .collect::, Option>)>>(); + verify_trie_proof::, _, _, _>( + &subject_identity_commitment, + &proof.dip_proof.merkle_proof.blinded, + &proof_leaves, + ) + .map_err(|_| ())?; + + #[allow(clippy::type_complexity)] + let (did_keys, web3_name, linked_accounts): ( + BoundedVec, ConstU32>, + Option>, + BoundedVec>, + ) = proof.dip_proof.merkle_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 { + 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, linked_accounts)) + } + // TODO: Avoid cloning if possible + 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)) + } + }, + )?; + let verification_result = VerificationResult { + did_keys, + web3_name, + linked_accounts, + }; + + // 4. Verify DID signature. + let block_number = LocalContextProvider::block_number(); + let is_signature_fresh = + if let Some(blocks_ago_from_now) = block_number.checked_sub(&proof.dip_proof.did_signature.block_number) { + blocks_ago_from_now <= LocalContextProvider::SIGNATURE_VALIDITY + } else { + false + }; + ensure!(is_signature_fresh, ()); + let encoded_payload = ( + call, + &identity_details, + submitter, + &proof.dip_proof.did_signature.block_number, + LocalContextProvider::genesis_hash(), + LocalContextProvider::signed_extra(), + ) + .encode(); + + let mut proof_verification_keys = verification_result.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.dip_proof.did_signature.signature) + .is_ok() + }); + let Some((key, relationship)) = valid_signing_key else { return Err(()) }; + if let Some(details) = identity_details { + details.bump(); + } else { + *identity_details = Some(Self::IdentityDetails::default()); + } + + // 4.1 Verify call required relationship + LocalDidCallVerifier::check_call_origin_info(call, &(key.clone(), relationship)).map_err(|_| ())?; + Ok(verification_result) } } - -// pub struct StateProofDipVerifier< -// RelayInfoProvider, -// ParaInfoProvider, -// ProviderKeyId, -// ProviderParaIdProvider, -// ProviderBlockNumber, -// ProviderAccountIdentityDetails, -// ProviderWeb3Name, -// ProviderHasher, -// ProviderLinkedAccountId, -// ConsumerAccountId, -// ConsumerBlockNumber, -// ConsumerBlockNumberProvider, -// ConsumerGenesisHashProvider, -// CallVerifier, -// const MAX_REVEALED_KEYS_COUNT: u32, -// const MAX_REVEALED_ACCOUNTS_COUNT: u32, -// const SIGNATURE_VALIDITY: u64, -// SignedExtra = (), -// SignedExtraProvider = (), -// >( -// #[allow(clippy::type_complexity)] -// PhantomData<( -// RelayInfoProvider, -// ParaInfoProvider, -// ProviderKeyId, -// ProviderParaIdProvider, -// ProviderBlockNumber, -// ProviderAccountIdentityDetails, -// ProviderWeb3Name, -// ProviderHasher, -// ProviderLinkedAccountId, -// ConsumerAccountId, -// ConsumerBlockNumber, -// ConsumerBlockNumberProvider, -// ConsumerGenesisHashProvider, -// CallVerifier, -// ConstU32, -// ConstU32, -// ConstU64, -// SignedExtra, -// SignedExtraProvider, -// )>, -// ); - -// impl< -// Call, -// Subject, -// RelayInfoProvider, -// ParaInfoProvider, -// ProviderKeyId, -// ProviderParaIdProvider, -// ProviderBlockNumber, -// ProviderAccountIdentityDetails, -// ProviderWeb3Name, -// ProviderHasher, -// ProviderLinkedAccountId, -// ConsumerAccountId, -// ConsumerBlockNumber, -// ConsumerBlockNumberProvider, -// ConsumerGenesisHashProvider, -// CallVerifier, -// const MAX_REVEALED_KEYS_COUNT: u32, -// const MAX_REVEALED_ACCOUNTS_COUNT: u32, -// const SIGNATURE_VALIDITY: u64, -// SignedExtra, -// SignedExtraProvider, -// > IdentityProofVerifier -// for StateProofDipVerifier< -// RelayInfoProvider, -// ParaInfoProvider, -// ProviderKeyId, -// ProviderParaIdProvider, -// ProviderBlockNumber, -// ProviderAccountIdentityDetails, -// ProviderWeb3Name, -// ProviderHasher, -// ProviderLinkedAccountId, -// ConsumerAccountId, -// ConsumerBlockNumber, -// ConsumerBlockNumberProvider, -// ConsumerGenesisHashProvider, -// CallVerifier, -// MAX_REVEALED_KEYS_COUNT, -// MAX_REVEALED_ACCOUNTS_COUNT, -// SIGNATURE_VALIDITY, -// SignedExtra, -// SignedExtraProvider, -// > where -// RelayInfoProvider: RelayChainStateInfoProvider, -// RelayInfoProvider::Hasher: 'static, -// ::Output: Ord, -// RelayInfoProvider::BlockNumber: Copy + Into + TryFrom + -// HasCompact, RelayInfoProvider::Key: AsRef<[u8]>, -// ParaInfoProvider: ParachainStateInfoProvider, ParaInfoProvider::Hasher: 'static, -// ::Output: Ord -// + Encode -// + PartialEq<::Output> -// + From<::Output>, -// ParaInfoProvider::Commitment: Decode, -// ParaInfoProvider::Key: AsRef<[u8]>, -// ProviderKeyId: Encode + Clone, -// ProviderBlockNumber: Encode + Clone, -// ProviderWeb3Name: Encode + Clone, -// ProviderLinkedAccountId: Encode + Clone, -// ProviderHasher: Hasher, -// ProviderParaIdProvider: Get, -// Call: Encode, -// ConsumerAccountId: Encode, -// ProviderAccountIdentityDetails: Encode + Bump + Default, -// ConsumerBlockNumber: CheckedSub + Into + Encode, -// ConsumerBlockNumberProvider: Get, -// ConsumerGenesisHashProvider: Get<::Output>, -// SignedExtra: Encode, -// SignedExtraProvider: Get, -// CallVerifier: DidDipOriginFilter, { -// // TODO: Better error handling -// type Error = (); -// type IdentityDetails = ProviderAccountIdentityDetails; -// type Proof = DipSiblingParachainStateProof< -// RelayInfoProvider::BlockNumber, -// MerkleLeavesAndDidSignature< -// MerkleProof< -// Vec>, -// ProofLeaf, >, -// ConsumerBlockNumber, -// >, -// >; -// type Submitter = ConsumerAccountId; -// type VerificationResult = VerificationResult< -// ProviderKeyId, -// ProviderBlockNumber, -// ProviderWeb3Name, -// ProviderLinkedAccountId, -// MAX_REVEALED_KEYS_COUNT, -// MAX_REVEALED_ACCOUNTS_COUNT, -// >; - -// fn verify_proof_for_call_against_details( -// call: &Call, -// subject: &Subject, -// submitter: &Self::Submitter, -// identity_details: &mut Option, -// proof: Self::Proof, -// ) -> Result { -// let DipSiblingParachainStateProof { -// para_root_proof, -// dip_commitment_proof, -// dip_proof, -// } = proof; -// // 1. Verify relay chain proof. -// let provider_parachain_header = -// state_proofs::relay_chain::ParachainHeadProofVerifier::::verify_proof_for_parachain( &ProviderParaIdProvider::get(), -// ¶_root_proof.relay_block_height, -// para_root_proof.proof, -// )?; -// // 2. Verify parachain state proof. -// let subject_identity_commitment = -// state_proofs::parachain::DipCommitmentValueProofVerifier::::verify_proof_for_identifier( -// subject, -// provider_parachain_header.state_root.into(), -// dip_commitment_proof, -// )?; - -// // 3. Verify DIP identity proof (taken from existing implementation). -// let proof_leaves = dip_proof -// .merkle_leaves -// .revealed -// .iter() -// .map(|leaf| (leaf.encoded_key(), Some(leaf.encoded_value()))) -// .collect::, Option>)>>(); -// verify_trie_proof::, _, _, _>( -// &subject_identity_commitment, -// &dip_proof.merkle_leaves.blinded, -// &proof_leaves, -// ) -// .map_err(|_| ())?; -// #[allow(clippy::type_complexity)] -// let (did_keys, web3_name, linked_accounts): ( -// BoundedVec, -// ConstU32>, Option>, BoundedVec>, ) = dip_proof.merkle_leaves.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 { -// 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, linked_accounts)) -// } -// // TODO: Avoid cloning if possible -// 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)) -// } -// }, -// )?; -// let verification_result = VerificationResult { -// did_keys, -// web3_name, -// linked_accounts, -// }; - -// // 4. Verify DID signature (taken from existing implementation). -// let block_number = ConsumerBlockNumberProvider::get(); -// let is_signature_fresh = -// if let Some(blocks_ago_from_now) = -// block_number.checked_sub(&dip_proof.did_signature.block_number) { -// blocks_ago_from_now.into() <= SIGNATURE_VALIDITY -// } else { -// false -// }; -// ensure!(is_signature_fresh, ()); -// let encoded_payload = ( -// call, -// &identity_details, -// submitter, -// &dip_proof.did_signature.block_number, -// ConsumerGenesisHashProvider::get(), -// SignedExtraProvider::get(), -// ) -// .encode(); -// let mut proof_verification_keys = -// verification_result.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, &dip_proof.did_signature.signature) -// .is_ok() -// }); -// let Some((key, relationship)) = valid_signing_key else { return Err(()) }; -// if let Some(details) = identity_details { -// details.bump(); -// } else { -// *identity_details = Some(Self::IdentityDetails::default()); -// } -// // 4.1 Verify call required relationship -// CallVerifier::check_call_origin_info(call, &(key.clone(), -// relationship)).map_err(|_| ())?; Ok(verification_result) -// } -// } diff --git a/crates/kilt-dip-support/src/merkle.rs b/crates/kilt-dip-support/src/merkle.rs index a24b9a97de..9609de7ea6 100644 --- a/crates/kilt-dip-support/src/merkle.rs +++ b/crates/kilt-dip-support/src/merkle.rs @@ -18,7 +18,6 @@ use did::{did_details::DidPublicKeyDetails, DidVerificationKeyRelationship}; 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, SaturatedConversion}; @@ -27,9 +26,9 @@ use sp_trie::{verify_trie_proof, LayoutV1}; pub type BlindedValue = Vec; -#[derive(Encode, Decode, RuntimeDebug, Clone, Eq, PartialEq, TypeInfo, Default)] -pub struct MerkleProof { - pub blinded: BlindedValue, +#[derive(Encode, Decode, RuntimeDebug, Clone, Eq, PartialEq, Default)] +pub struct MerkleProof { + pub blinded: BlindedValues, // TODO: Probably replace with a different data structure for better lookupcapabilities pub revealed: Vec, } @@ -246,6 +245,7 @@ impl< LinkedAccountId: Encode + Clone, Web3Name: Encode + Clone, { + #[allow(clippy::result_unit_err)] pub fn verify_dip_merkle_proof( identity_commitment: &Hasher::Out, proof: MerkleProof>, ProofLeaf>, diff --git a/crates/kilt-dip-support/src/state_proofs.rs b/crates/kilt-dip-support/src/state_proofs.rs index 7ff07e2a54..6e3efa3f81 100644 --- a/crates/kilt-dip-support/src/state_proofs.rs +++ b/crates/kilt-dip-support/src/state_proofs.rs @@ -16,20 +16,14 @@ // If you feel like getting in touch with us, you can do so at info@botlabs.org -use pallet_dip_consumer::traits::IdentityProofVerifier; use parity_scale_codec::{Decode, HasCompact}; -use sp_core::{ConstU32, U256}; +use sp_core::U256; use sp_runtime::generic::Header; use sp_std::{marker::PhantomData, vec::Vec}; use sp_trie::StorageProof; use substrate_no_std_port::read_proof_check; -use crate::{ - merkle::MerkleProof, - state_proofs::{parachain::DipCommitmentValueProofVerifier, relay_chain::ParachainHeadProofVerifier}, -}; - // Ported from https://github.com/paritytech/substrate/blob/b27c470eaff379f512d1dec052aff5d551ed3b03/primitives/state-machine/src/lib.rs#L1076 // Needs to be replaced with its runtime-friendly version when available, or be // kept up-to-date with upstream. @@ -89,19 +83,14 @@ mod substrate_no_std_port { } } -mod relay_chain { +pub(super) mod relay_chain { use super::*; use parity_scale_codec::Encode; - use sp_core::{storage::StorageKey, Get}; + use sp_core::storage::StorageKey; use sp_runtime::traits::BlakeTwo256; - use pallet_dip_consumer::traits::IdentityProofVerifier; - - use crate::{ - traits::{OutputOf, RelayChainStateInfoProvider}, - ParaRootProof, - }; + use crate::traits::{OutputOf, RelayChainStateInfoProvider}; pub struct ParachainHeadProofVerifier(PhantomData); @@ -234,10 +223,9 @@ mod relay_chain { } } -mod parachain { +pub(super) mod parachain { use super::*; - use pallet_dip_consumer::traits::IdentityProofVerifier; use parity_scale_codec::Encode; use sp_core::storage::StorageKey; diff --git a/crates/kilt-dip-support/src/traits.rs b/crates/kilt-dip-support/src/traits.rs index 35648e9c09..0bf259ca99 100644 --- a/crates/kilt-dip-support/src/traits.rs +++ b/crates/kilt-dip-support/src/traits.rs @@ -16,9 +16,7 @@ // If you feel like getting in touch with us, you can do so at info@botlabs.org -use parity_scale_codec::Encode; -use sp_core::{storage::StorageKey, Get}; -use sp_runtime::traits::{BlakeTwo256, CheckedAdd, One, Zero}; +use sp_runtime::traits::{CheckedAdd, One, Zero}; use sp_std::marker::PhantomData; // TODO: Switch to the `Incrementable` trait once it's added to the root of From 622c046f110cceb642d6a380746f4368f150a3d2 Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Fri, 21 Jul 2023 10:27:39 +0200 Subject: [PATCH 21/32] Everything compiling --- crates/kilt-dip-support/src/did.rs | 30 +- crates/kilt-dip-support/src/lib.rs | 289 ++++-------------- crates/kilt-dip-support/src/merkle.rs | 69 ++--- crates/kilt-dip-support/src/state_proofs.rs | 98 +++--- crates/kilt-dip-support/src/traits.rs | 18 +- crates/kilt-dip-support/src/utils.rs | 114 +++++++ dip-template/runtimes/dip-consumer/src/dip.rs | 12 +- dip-template/runtimes/dip-consumer/src/lib.rs | 6 +- runtimes/common/src/dip/merkle.rs | 22 +- 9 files changed, 297 insertions(+), 361 deletions(-) create mode 100644 crates/kilt-dip-support/src/utils.rs diff --git a/crates/kilt-dip-support/src/did.rs b/crates/kilt-dip-support/src/did.rs index 63de56c1b6..2afc7c46da 100644 --- a/crates/kilt-dip-support/src/did.rs +++ b/crates/kilt-dip-support/src/did.rs @@ -29,22 +29,22 @@ use sp_std::marker::PhantomData; use crate::{ merkle::RevealedDidKey, - traits::{Bump, DidDipOriginFilter, DidSignatureVerifierContextProvider}, + traits::{Bump, DidSignatureVerifierContext, DipCallOriginFilter}, }; #[derive(Encode, Decode, RuntimeDebug, Clone, Eq, PartialEq, TypeInfo)] -pub struct TimeBoundDidSignature { - pub signature: DidSignature, - pub block_number: BlockNumber, +pub(crate) struct RevealedDidKeysAndSignature { + pub merkle_leaves: RevealedDidKeys, + pub did_signature: TimeBoundDidSignature, } #[derive(Encode, Decode, RuntimeDebug, Clone, Eq, PartialEq, TypeInfo)] -pub struct MerkleLeavesAndDidSignature { - pub merkle_leaves: MerkleLeaves, - pub did_signature: TimeBoundDidSignature, +pub struct TimeBoundDidSignature { + pub signature: DidSignature, + pub block_number: BlockNumber, } -pub struct MerkleDidSignatureAndCallVerifier< +pub(crate) struct RevealedDidKeysSignatureAndCallVerifier< Call, Submitter, DidLocalDetails, @@ -77,7 +77,7 @@ impl< RemoteBlockNumber, CallVerifier, > - MerkleDidSignatureAndCallVerifier< + RevealedDidKeysSignatureAndCallVerifier< Call, Submitter, DidLocalDetails, @@ -89,20 +89,20 @@ impl< > where Call: Encode, Submitter: Encode, - ContextProvider: DidSignatureVerifierContextProvider, + ContextProvider: DidSignatureVerifierContext, ContextProvider::BlockNumber: Encode + CheckedSub + PartialOrd, ContextProvider::Hash: Encode, ContextProvider::SignedExtra: Encode, DidLocalDetails: Bump + Default + Encode, - MerkleProofEntries: AsRef<[RevealedDidKey]>, - CallVerifier: DidDipOriginFilter, + MerkleProofEntries: sp_std::borrow::Borrow<[RevealedDidKey]>, + CallVerifier: DipCallOriginFilter, { #[allow(clippy::result_unit_err)] - pub fn verify_did_signature_for_call( + pub(crate) fn verify_did_signature_for_call( call: &Call, submitter: &Submitter, local_details: &mut Option, - merkle_revealed_did_signature: MerkleLeavesAndDidSignature, + merkle_revealed_did_signature: RevealedDidKeysAndSignature, ) -> Result<(DidVerificationKey, DidVerificationKeyRelationship), ()> { let block_number = ContextProvider::block_number(); let is_signature_fresh = if let Some(blocks_ago_from_now) = @@ -125,7 +125,7 @@ impl< ) .encode(); // Only consider verification keys from the set of revealed keys. - let mut proof_verification_keys = merkle_revealed_did_signature.merkle_leaves.as_ref().iter().filter_map(|RevealedDidKey { + let mut proof_verification_keys = merkle_revealed_did_signature.merkle_leaves.borrow().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."))) }); diff --git a/crates/kilt-dip-support/src/lib.rs b/crates/kilt-dip-support/src/lib.rs index cc0a217ba9..cd212538fd 100644 --- a/crates/kilt-dip-support/src/lib.rs +++ b/crates/kilt-dip-support/src/lib.rs @@ -20,143 +20,51 @@ #![cfg_attr(not(feature = "std"), no_std)] -use frame_support::ensure; -use pallet_dip_provider::traits::IdentityProvider; use parity_scale_codec::{Decode, Encode, HasCompact}; use scale_info::TypeInfo; -use sp_core::{ConstU32, Get, RuntimeDebug, U256}; -use sp_runtime::{traits::CheckedSub, BoundedVec, SaturatedConversion}; -use sp_std::{marker::PhantomData, vec::Vec}; -use sp_trie::{verify_trie_proof, LayoutV1}; +use sp_core::{Get, RuntimeDebug, U256}; +use sp_runtime::traits::CheckedSub; +use sp_std::{borrow::Borrow, marker::PhantomData, vec::Vec}; -use ::did::{ - did_details::{DidPublicKey, DidPublicKeyDetails, DidVerificationKey}, - DidVerificationKeyRelationship, -}; +use ::did::{did_details::DidVerificationKey, DidVerificationKeyRelationship}; use pallet_dip_consumer::traits::IdentityProofVerifier; use crate::{ - did::TimeBoundDidSignature, - merkle::{MerkleProof, ProofLeaf, RevealedDidKey, RevealedWeb3Name, VerificationResult}, - traits::{ - Bump, DidDipOriginFilter, DidSignatureVerifierContextProvider, OutputOf, ParachainStateInfoProvider, - RelayChainStateInfoProvider, - }, + did::{RevealedDidKeysAndSignature, RevealedDidKeysSignatureAndCallVerifier, TimeBoundDidSignature}, + merkle::{DidMerkleProof, DidMerkleProofVerifier, RevealedDidMerkleProofLeaf, RevealedDidMerkleProofLeaves}, + state_proofs::{parachain::DipIdentityCommitmentProofVerifier, relay_chain::SiblingParachainHeadProofVerifier}, + traits::{Bump, DidSignatureVerifierContext, DipCallOriginFilter, ProviderParachainStateInfo, RelayChainStateInfo}, + utils::OutputOf, }; pub mod did; pub mod merkle; pub mod state_proofs; pub mod traits; - -pub struct CombinedIdentityResult { - pub a: OutputA, - pub b: OutputB, - 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, - 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 -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(()), - } - } -} +pub mod utils; #[derive(Encode, Decode, PartialEq, Eq, RuntimeDebug, TypeInfo, Clone)] -pub struct DipStateProof { - para_root_proof: ParaRootProof, - dip_commitment_proof: Vec>, - dip_proof: DipMerkleProofAndDidSignature, +pub struct SiblingParachainDipStateProof< + RelayBlockHeight, + DipMerkleProofBlindedValues, + DipMerkleProofRevealedLeaf, + DipProviderBlockNumber, +> { + para_state_root: SiblingParachainRootStateProof, + dip_identity_commitment: Vec>, + dip_proof: + DipMerkleProofAndDidSignature, } #[derive(Encode, Decode, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug, TypeInfo, Clone)] -pub struct ParaRootProof { +pub struct SiblingParachainRootStateProof { relay_block_height: RelayBlockHeight, proof: Vec>, } #[derive(Encode, Decode, PartialEq, Eq, RuntimeDebug, TypeInfo, Clone)] pub struct DipMerkleProofAndDidSignature { - merkle_proof: MerkleProof, + merkle_proof: DidMerkleProof, did_signature: TimeBoundDidSignature, } @@ -230,7 +138,7 @@ impl< Call: Encode, TxSubmitter: Encode, - RelayInfoProvider: RelayChainStateInfoProvider, + RelayInfoProvider: RelayChainStateInfo, RelayInfoProvider::Hasher: 'static, OutputOf: Ord, RelayInfoProvider::BlockNumber: Copy + Into + TryFrom + HasCompact, @@ -238,18 +146,18 @@ impl< ProviderParaIdProvider: Get, - ParaInfoProvider: ParachainStateInfoProvider, + ParaInfoProvider: ProviderParachainStateInfo, ParaInfoProvider::Hasher: 'static, OutputOf: Ord + From>, ParaInfoProvider::Commitment: Decode, ParaInfoProvider::Key: AsRef<[u8]>, - LocalContextProvider: DidSignatureVerifierContextProvider, + LocalContextProvider: DidSignatureVerifierContext, LocalContextProvider::BlockNumber: Encode + CheckedSub + PartialOrd, LocalContextProvider::Hash: Encode, LocalContextProvider::SignedExtra: Encode, DidLocalDetails: Bump + Default + Encode, - LocalDidCallVerifier: DidDipOriginFilter, + LocalDidCallVerifier: DipCallOriginFilter, ProviderBlockNumber: Encode + Clone, ProviderDipMerkleHasher: sp_core::Hasher, @@ -259,14 +167,14 @@ impl< { type Error = (); type IdentityDetails = DidLocalDetails; - type Proof = DipStateProof< + type Proof = SiblingParachainDipStateProof< RelayInfoProvider::BlockNumber, Vec>, - ProofLeaf, + RevealedDidMerkleProofLeaf, LocalContextProvider::BlockNumber, >; type Submitter = TxSubmitter; - type VerificationResult = VerificationResult< + type VerificationResult = RevealedDidMerkleProofLeaves< ProviderDidKeyId, ProviderBlockNumber, ProviderWeb3Name, @@ -284,128 +192,51 @@ impl< ) -> Result { // 1. Verify relay chain proof. let provider_parachain_header = - state_proofs::relay_chain::ParachainHeadProofVerifier::::verify_proof_for_parachain( + SiblingParachainHeadProofVerifier::::verify_proof_for_parachain( &ProviderParaIdProvider::get(), - &proof.para_root_proof.relay_block_height, - proof.para_root_proof.proof, + &proof.para_state_root.relay_block_height, + proof.para_state_root.proof, )?; // 2. Verify parachain state proof. let subject_identity_commitment = - state_proofs::parachain::DipCommitmentValueProofVerifier::::verify_proof_for_identifier( + DipIdentityCommitmentProofVerifier::::verify_proof_for_identifier( subject, provider_parachain_header.state_root.into(), - proof.dip_commitment_proof, + proof.dip_identity_commitment, )?; - // 3. Verify DIP identity proof. - let proof_leaves = proof - .dip_proof - .merkle_proof - .revealed - .iter() - .map(|leaf| (leaf.encoded_key(), Some(leaf.encoded_value()))) - .collect::, Option>)>>(); - verify_trie_proof::, _, _, _>( - &subject_identity_commitment, - &proof.dip_proof.merkle_proof.blinded, - &proof_leaves, - ) - .map_err(|_| ())?; - - #[allow(clippy::type_complexity)] - let (did_keys, web3_name, linked_accounts): ( - BoundedVec, ConstU32>, - Option>, - BoundedVec>, - ) = proof.dip_proof.merkle_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 { - 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, linked_accounts)) - } - // TODO: Avoid cloning if possible - 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)) - } - }, - )?; - let verification_result = VerificationResult { - did_keys, - web3_name, - linked_accounts, - }; + // 3. Verify DIP merkle proof. + let proof_leaves = DidMerkleProofVerifier::< + ProviderDipMerkleHasher, + ProviderDidKeyId, + ProviderBlockNumber, + ProviderWeb3Name, + ProviderLinkedAccountId, + MAX_REVEALED_KEYS_COUNT, + MAX_REVEALED_ACCOUNTS_COUNT, + >::verify_dip_merkle_proof(&subject_identity_commitment, proof.dip_proof.merkle_proof)?; // 4. Verify DID signature. - let block_number = LocalContextProvider::block_number(); - let is_signature_fresh = - if let Some(blocks_ago_from_now) = block_number.checked_sub(&proof.dip_proof.did_signature.block_number) { - blocks_ago_from_now <= LocalContextProvider::SIGNATURE_VALIDITY - } else { - false - }; - ensure!(is_signature_fresh, ()); - let encoded_payload = ( + RevealedDidKeysSignatureAndCallVerifier::< + _, + _, + _, + _, + LocalContextProvider, + _, + _, + LocalDidCallVerifier, + >::verify_did_signature_for_call( call, - &identity_details, submitter, - &proof.dip_proof.did_signature.block_number, - LocalContextProvider::genesis_hash(), - LocalContextProvider::signed_extra(), - ) - .encode(); - - let mut proof_verification_keys = verification_result.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.", - ), - )) + identity_details, + RevealedDidKeysAndSignature { + merkle_leaves: proof_leaves.borrow(), + did_signature: proof.dip_proof.did_signature, }, - ); - let valid_signing_key = proof_verification_keys.find(|(verification_key, _)| { - verification_key - .verify_signature(&encoded_payload, &proof.dip_proof.did_signature.signature) - .is_ok() - }); - let Some((key, relationship)) = valid_signing_key else { return Err(()) }; - if let Some(details) = identity_details { - details.bump(); - } else { - *identity_details = Some(Self::IdentityDetails::default()); - } + )?; - // 4.1 Verify call required relationship - LocalDidCallVerifier::check_call_origin_info(call, &(key.clone(), relationship)).map_err(|_| ())?; - Ok(verification_result) + Ok(proof_leaves) } } diff --git a/crates/kilt-dip-support/src/merkle.rs b/crates/kilt-dip-support/src/merkle.rs index 9609de7ea6..e9dba1b420 100644 --- a/crates/kilt-dip-support/src/merkle.rs +++ b/crates/kilt-dip-support/src/merkle.rs @@ -24,12 +24,10 @@ use sp_runtime::{BoundedVec, SaturatedConversion}; use sp_std::{fmt::Debug, marker::PhantomData, vec::Vec}; use sp_trie::{verify_trie_proof, LayoutV1}; -pub type BlindedValue = Vec; - #[derive(Encode, Decode, RuntimeDebug, Clone, Eq, PartialEq, Default)] -pub struct MerkleProof { +pub struct DidMerkleProof { pub blinded: BlindedValues, - // TODO: Probably replace with a different data structure for better lookupcapabilities + // TODO: Probably replace with a different data structure for better lookup capabilities pub revealed: Vec, } @@ -112,7 +110,7 @@ impl From<()> for LinkedAccountMerkleValue { } #[derive(Clone, Encode, Decode, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug, TypeInfo)] -pub enum ProofLeaf { +pub enum RevealedDidMerkleProofLeaf { // 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), @@ -120,7 +118,8 @@ pub enum ProofLeaf { LinkedAccount(LinkedAccountMerkleKey, LinkedAccountMerkleValue), } -impl ProofLeaf +impl + RevealedDidMerkleProofLeaf where KeyId: Encode, Web3Name: Encode, @@ -128,22 +127,23 @@ where { pub fn encoded_key(&self) -> Vec { match self { - ProofLeaf::DidKey(key, _) => key.encode(), - ProofLeaf::Web3Name(key, _) => key.encode(), - ProofLeaf::LinkedAccount(key, _) => key.encode(), + RevealedDidMerkleProofLeaf::DidKey(key, _) => key.encode(), + RevealedDidMerkleProofLeaf::Web3Name(key, _) => key.encode(), + RevealedDidMerkleProofLeaf::LinkedAccount(key, _) => key.encode(), } } } -impl ProofLeaf +impl + RevealedDidMerkleProofLeaf where BlockNumber: Encode, { pub fn encoded_value(&self) -> Vec { match self { - ProofLeaf::DidKey(_, value) => value.encode(), - ProofLeaf::Web3Name(_, value) => value.encode(), - ProofLeaf::LinkedAccount(_, value) => value.encode(), + RevealedDidMerkleProofLeaf::DidKey(_, value) => value.encode(), + RevealedDidMerkleProofLeaf::Web3Name(_, value) => value.encode(), + RevealedDidMerkleProofLeaf::LinkedAccount(_, value) => value.encode(), } } } @@ -162,7 +162,7 @@ pub struct RevealedWeb3Name { } #[derive(Clone, Debug, PartialEq, Eq, TypeInfo, MaxEncodedLen, Encode, Decode, Default)] -pub struct VerificationResult< +pub struct RevealedDidMerkleProofLeaves< KeyId, BlockNumber, Web3Name, @@ -182,8 +182,8 @@ impl< LinkedAccountId, const MAX_REVEALED_KEYS_COUNT: u32, const MAX_REVEALED_ACCOUNTS_COUNT: u32, - > AsRef<[RevealedDidKey]> - for VerificationResult< + > sp_std::borrow::Borrow<[RevealedDidKey]> + for RevealedDidMerkleProofLeaves< KeyId, BlockNumber, Web3Name, @@ -192,15 +192,15 @@ impl< MAX_REVEALED_ACCOUNTS_COUNT, > { - fn as_ref(&self) -> &[RevealedDidKey] { - self.did_keys.as_ref() + fn borrow(&self) -> &[RevealedDidKey] { + self.did_keys.borrow() } } /// A type that verifies a Merkle proof that reveals some leaves representing /// keys in a DID Document. /// Can also be used on its own, without any DID signature verification. -pub struct DidMerkleProofVerifier< +pub(crate) struct DidMerkleProofVerifier< Hasher, KeyId, BlockNumber, @@ -208,18 +208,7 @@ pub struct DidMerkleProofVerifier< LinkedAccountId, const MAX_REVEALED_KEYS_COUNT: u32, const MAX_REVEALED_ACCOUNTS_COUNT: u32, ->( - #[allow(clippy::type_complexity)] - PhantomData<( - Hasher, - KeyId, - BlockNumber, - Web3Name, - LinkedAccountId, - ConstU32, - ConstU32, - )>, -); +>(#[allow(clippy::type_complexity)] PhantomData<(Hasher, KeyId, BlockNumber, Web3Name, LinkedAccountId)>); impl< Hasher, @@ -239,18 +228,18 @@ impl< MAX_REVEALED_KEYS_COUNT, MAX_REVEALED_ACCOUNTS_COUNT, > where - BlockNumber: Encode + Clone + Debug, + BlockNumber: Encode + Clone, Hasher: sp_core::Hasher, - KeyId: Encode + Clone + Ord + Into, + KeyId: Encode + Clone, LinkedAccountId: Encode + Clone, Web3Name: Encode + Clone, { #[allow(clippy::result_unit_err)] - pub fn verify_dip_merkle_proof( + pub(crate) fn verify_dip_merkle_proof( identity_commitment: &Hasher::Out, - proof: MerkleProof>, ProofLeaf>, + proof: DidMerkleProof>, RevealedDidMerkleProofLeaf>, ) -> Result< - VerificationResult< + RevealedDidMerkleProofLeaves< KeyId, BlockNumber, Web3Name, @@ -285,7 +274,7 @@ impl< BoundedVec::with_bounded_capacity(MAX_REVEALED_ACCOUNTS_COUNT.saturated_into()), ), |(mut keys, web3_name, mut linked_accounts), leaf| match leaf { - ProofLeaf::DidKey(key_id, key_value) => { + RevealedDidMerkleProofLeaf::DidKey(key_id, key_value) => { keys.try_push(RevealedDidKey { // TODO: Avoid cloning if possible id: key_id.0.clone(), @@ -296,7 +285,7 @@ impl< Ok::<_, ()>((keys, web3_name, linked_accounts)) } // TODO: Avoid cloning if possible - ProofLeaf::Web3Name(revealed_web3_name, details) => Ok(( + RevealedDidMerkleProofLeaf::Web3Name(revealed_web3_name, details) => Ok(( keys, Some(RevealedWeb3Name { web3_name: revealed_web3_name.0.clone(), @@ -304,14 +293,14 @@ impl< }), linked_accounts, )), - ProofLeaf::LinkedAccount(account_id, _) => { + RevealedDidMerkleProofLeaf::LinkedAccount(account_id, _) => { linked_accounts.try_push(account_id.0.clone()).map_err(|_| ())?; Ok::<_, ()>((keys, web3_name, linked_accounts)) } }, )?; - Ok(VerificationResult { + 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 6e3efa3f81..edaf181636 100644 --- a/crates/kilt-dip-support/src/state_proofs.rs +++ b/crates/kilt-dip-support/src/state_proofs.rs @@ -16,12 +16,14 @@ // If you feel like getting in touch with us, you can do so at info@botlabs.org -use parity_scale_codec::{Decode, HasCompact}; -use sp_core::U256; +use parity_scale_codec::{Decode, Encode, HasCompact}; +use sp_core::{storage::StorageKey, U256}; use sp_runtime::generic::Header; use sp_std::{marker::PhantomData, vec::Vec}; use sp_trie::StorageProof; +use crate::utils::OutputOf; + use substrate_no_std_port::read_proof_check; // Ported from https://github.com/paritytech/substrate/blob/b27c470eaff379f512d1dec052aff5d551ed3b03/primitives/state-machine/src/lib.rs#L1076 @@ -86,32 +88,30 @@ mod substrate_no_std_port { pub(super) mod relay_chain { use super::*; - use parity_scale_codec::Encode; - use sp_core::storage::StorageKey; use sp_runtime::traits::BlakeTwo256; - use crate::traits::{OutputOf, RelayChainStateInfoProvider}; + use crate::traits::RelayChainStateInfo; - pub struct ParachainHeadProofVerifier(PhantomData); + pub struct SiblingParachainHeadProofVerifier(PhantomData); - impl ParachainHeadProofVerifier + impl SiblingParachainHeadProofVerifier where - RelayInfoProvider: RelayChainStateInfoProvider, - RelayInfoProvider::Hasher: 'static, - OutputOf: Ord, - RelayInfoProvider::BlockNumber: Copy + Into + TryFrom + HasCompact, - RelayInfoProvider::Key: AsRef<[u8]>, + RelayChainState: RelayChainStateInfo, + RelayChainState::Hasher: 'static, + OutputOf: Ord, + RelayChainState::BlockNumber: Copy + Into + TryFrom + HasCompact, + RelayChainState::Key: AsRef<[u8]>, { #[allow(clippy::result_unit_err)] pub fn verify_proof_for_parachain( - para_id: &RelayInfoProvider::ParaId, - relay_height: &RelayInfoProvider::BlockNumber, + para_id: &RelayChainState::ParaId, + relay_height: &RelayChainState::BlockNumber, proof: impl IntoIterator>, - ) -> Result, ()> { - let relay_state_root = RelayInfoProvider::state_root_for_block(relay_height).ok_or(())?; - let parachain_storage_key = RelayInfoProvider::parachain_head_storage_key(para_id); + ) -> Result, ()> { + let relay_state_root = RelayChainState::state_root_for_block(relay_height).ok_or(())?; + let parachain_storage_key = RelayChainState::parachain_head_storage_key(para_id); let storage_proof = StorageProof::new(proof); - let revealed_leaves = read_proof_check::( + let revealed_leaves = read_proof_check::( relay_state_root, storage_proof, [¶chain_storage_key].iter(), @@ -129,9 +129,9 @@ pub(super) mod relay_chain { } } - pub struct RococoParachainRuntime(PhantomData); + pub struct RococoStateRootsViaRelayStorePallet(PhantomData); - impl RelayChainStateInfoProvider for RococoParachainRuntime + impl RelayChainStateInfo for RococoStateRootsViaRelayStorePallet where Runtime: pallet_relay_store::Config, { @@ -163,15 +163,13 @@ pub(super) mod relay_chain { use super::*; use hex_literal::hex; - use parity_scale_codec::Encode; - use sp_core::storage::StorageKey; use sp_runtime::traits::BlakeTwo256; // Polkadot block n: 16_363_919, // hash 0x18e90e9aa8e3b063f60386ba1b0415111798e72d01de58b1438d620d42f58e39 struct StaticPolkadotInfoProvider; - impl RelayChainStateInfoProvider for StaticPolkadotInfoProvider { + impl RelayChainStateInfo for StaticPolkadotInfoProvider { type BlockNumber = u32; type Hasher = BlakeTwo256; type Key = StorageKey; @@ -212,12 +210,13 @@ pub(super) mod relay_chain { // "0xcd710b30bd2eab0352ddcc26417aa1941b3c252fcb29d88eff4f3de5de4476c32c0cfd6c23b92a7826080000" // let expected_spiritnet_head_at_block = hex!("65541097fb02782e14f43074f0b00e44ae8e9fe426982323ef1d329739740d37f252ff006d1156941db1bccd58ce3a1cac4f40cad91f692d94e98f501dd70081a129b69a3e2ef7e1ff84ba3d86dab4e95f2c87f6b1055ebd48519c185360eae58f05d1ea08066175726120dcdc6308000000000561757261010170ccfaf3756d1a8dd8ae5c89094199d6d32e5dd9f0920f6fe30f986815b5e701974ea0e0e0a901401f2c72e3dd8dbdf4aa55d59bf3e7021856cdb8038419eb8c").to_vec(); - let returned_head = ParachainHeadProofVerifier::::verify_proof_for_parachain( - &2_086, - &16_363_919, - spiritnet_head_proof_at_block, - ) - .expect("Parachain head proof verification should not fail."); + let returned_head = + SiblingParachainHeadProofVerifier::::verify_proof_for_parachain( + &2_086, + &16_363_919, + spiritnet_head_proof_at_block, + ) + .expect("Parachain head proof verification should not fail."); assert!(returned_head.encode() == expected_spiritnet_head_at_block, "Parachain head returned from the state proof verification should not be different than the pre-computed one."); } } @@ -226,30 +225,27 @@ pub(super) mod relay_chain { pub(super) mod parachain { use super::*; - use parity_scale_codec::Encode; - use sp_core::storage::StorageKey; - - use crate::traits::{OutputOf, ParachainStateInfoProvider}; + use crate::traits::ProviderParachainStateInfo; - pub struct DipCommitmentValueProofVerifier(PhantomData); + pub struct DipIdentityCommitmentProofVerifier(PhantomData); - impl DipCommitmentValueProofVerifier + impl DipIdentityCommitmentProofVerifier where - ParaInfoProvider: ParachainStateInfoProvider, - ParaInfoProvider::Hasher: 'static, - OutputOf: Ord, - ParaInfoProvider::Commitment: Decode, - ParaInfoProvider::Key: AsRef<[u8]>, + ParaInfo: ProviderParachainStateInfo, + ParaInfo::Hasher: 'static, + OutputOf: Ord, + ParaInfo::Commitment: Decode, + ParaInfo::Key: AsRef<[u8]>, { #[allow(clippy::result_unit_err)] pub fn verify_proof_for_identifier( - identifier: &ParaInfoProvider::Identifier, - state_root: OutputOf, + identifier: &ParaInfo::Identifier, + state_root: OutputOf, proof: impl IntoIterator>, - ) -> Result { - let dip_commitment_storage_key = ParaInfoProvider::dip_subject_storage_key(identifier); + ) -> Result { + let dip_commitment_storage_key = ParaInfo::dip_subject_storage_key(identifier); let storage_proof = StorageProof::new(proof); - let revealed_leaves = read_proof_check::( + let revealed_leaves = read_proof_check::( state_root, storage_proof, [&dip_commitment_storage_key].iter(), @@ -261,13 +257,13 @@ pub(super) mod parachain { debug_assert!(revealed_leaves.contains_key(dip_commitment_storage_key.as_ref())); } let Some(Some(encoded_commitment)) = revealed_leaves.get(dip_commitment_storage_key.as_ref()) else { return Err(()) }; - ParaInfoProvider::Commitment::decode(&mut &encoded_commitment[..]).map_err(|_| ()) + ParaInfo::Commitment::decode(&mut &encoded_commitment[..]).map_err(|_| ()) } } - pub struct DipProviderParachainRuntime(PhantomData); + pub struct KiltDipCommitmentsForDipProviderPallet(PhantomData); - impl ParachainStateInfoProvider for DipProviderParachainRuntime + impl ProviderParachainStateInfo for KiltDipCommitmentsForDipProviderPallet where Runtime: pallet_dip_provider::Config, { @@ -294,7 +290,7 @@ pub(super) mod parachain { use super::*; use hex_literal::hex; - use sp_core::{storage::StorageKey, H256}; + use sp_core::H256; use sp_runtime::traits::BlakeTwo256; // Spiritnet block n: 4_184_668, @@ -302,7 +298,7 @@ pub(super) mod parachain { struct StaticSpiritnetInfoProvider; // We use the `system::eventCount()` storage entry as a unit test here. - impl ParachainStateInfoProvider for StaticSpiritnetInfoProvider { + impl ProviderParachainStateInfo for StaticSpiritnetInfoProvider { // The type of the `eventCount()` storage entry. type Commitment = u32; type Hasher = BlakeTwo256; @@ -336,7 +332,7 @@ pub(super) mod parachain { // "0x26aa394eea5630e07c48ae0c9558cef70a98fdbe9ce6c55837576c60c7af3850" let expected_event_count_at_block = 5; let returned_event_count = - DipCommitmentValueProofVerifier::::verify_proof_for_identifier( + DipIdentityCommitmentProofVerifier::::verify_proof_for_identifier( &(), spiritnet_state_root, spiritnet_event_count_proof_at_block, diff --git a/crates/kilt-dip-support/src/traits.rs b/crates/kilt-dip-support/src/traits.rs index 0bf259ca99..8d1f5dd7dd 100644 --- a/crates/kilt-dip-support/src/traits.rs +++ b/crates/kilt-dip-support/src/traits.rs @@ -19,6 +19,8 @@ use sp_runtime::traits::{CheckedAdd, One, Zero}; use sp_std::marker::PhantomData; +use crate::utils::OutputOf; + // TODO: Switch to the `Incrementable` trait once it's added to the root of // `frame_support`. /// A trait for "bumpable" types, i.e., types that have some notion of order of @@ -40,7 +42,7 @@ where /// A trait for types that implement some sort of access control logic on the /// provided input `Call` type. -pub trait DidDipOriginFilter { +pub trait DipCallOriginFilter { /// The error type for cases where the checks fail. type Error; /// The type of additional information required by the type to perform the @@ -52,9 +54,7 @@ pub trait DidDipOriginFilter { fn check_call_origin_info(call: &Call, info: &Self::OriginInfo) -> Result; } -pub type OutputOf = ::Output; - -pub trait RelayChainStateInfoProvider { +pub trait RelayChainStateInfo { type BlockNumber; type Key; type Hasher: sp_runtime::traits::Hash; @@ -64,7 +64,7 @@ pub trait RelayChainStateInfoProvider { fn parachain_head_storage_key(para_id: &Self::ParaId) -> Self::Key; } -pub trait ParachainStateInfoProvider { +pub trait ProviderParachainStateInfo { type Commitment; type Key; type Hasher: sp_runtime::traits::Hash; @@ -73,7 +73,7 @@ pub trait ParachainStateInfoProvider { fn dip_subject_storage_key(identifier: &Self::Identifier) -> Self::Key; } -pub trait DidSignatureVerifierContextProvider { +pub trait DidSignatureVerifierContext { const SIGNATURE_VALIDITY: u16; type BlockNumber; @@ -85,10 +85,10 @@ pub trait DidSignatureVerifierContextProvider { fn signed_extra() -> Option; } -pub struct FrameSystemProvider(PhantomData); +pub struct FrameSystemDidSignatureContext(PhantomData); -impl DidSignatureVerifierContextProvider - for FrameSystemProvider +impl DidSignatureVerifierContext + for FrameSystemDidSignatureContext where T: frame_system::Config, { diff --git a/crates/kilt-dip-support/src/utils.rs b/crates/kilt-dip-support/src/utils.rs new file mode 100644 index 0000000000..85fa1334f9 --- /dev/null +++ b/crates/kilt-dip-support/src/utils.rs @@ -0,0 +1,114 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +use pallet_dip_provider::traits::IdentityProvider; +use sp_std::marker::PhantomData; + +pub struct CombinedIdentityResult { + pub a: OutputA, + pub b: OutputB, + 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, + 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 +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(()), + } + } +} + +pub type OutputOf = ::Output; diff --git a/dip-template/runtimes/dip-consumer/src/dip.rs b/dip-template/runtimes/dip-consumer/src/dip.rs index d9dc41fa35..eea72d0dd0 100644 --- a/dip-template/runtimes/dip-consumer/src/dip.rs +++ b/dip-template/runtimes/dip-consumer/src/dip.rs @@ -20,10 +20,10 @@ use did::{did_details::DidVerificationKey, DidVerificationKeyRelationship, KeyId use dip_provider_runtime_template::{BlockNumber as ProviderBlockNumber, Web3Name}; use frame_support::traits::Contains; use kilt_dip_support::{ - did::MerkleLeavesAndDidSignature, - merkle::{MerkleProof, ProofLeaf}, + did::RevealedDidKeysAndSignature, + merkle::{DidMerkleProof, RevealedDidMerkleProofLeaf}, traits::{ - BlockNumberProvider, DidDipOriginFilter, DipProviderParachainRuntime, GenesisProvider, RococoParachainRuntime, + BlockNumberProvider, DipCallOriginFilter, DipProviderParachainRuntime, GenesisProvider, RococoParachainRuntime, }, DipSiblingParachainStateProof, StateProofDipVerifier, }; @@ -60,8 +60,8 @@ impl pallet_dip_consumer::Config for Runtime { type Identifier = DidIdentifier; type IdentityProof = DipSiblingParachainStateProof< u32, - MerkleLeavesAndDidSignature< - MerkleProof>, ProofLeaf>, + RevealedDidKeysAndSignature< + DidMerkleProof>, RevealedDidMerkleProofLeaf>, BlockNumber, >, >; @@ -119,7 +119,7 @@ fn single_key_relationship<'a>( pub struct DipCallFilter; -impl DidDipOriginFilter for DipCallFilter { +impl DipCallOriginFilter for DipCallFilter { type Error = (); type OriginInfo = (DidVerificationKey, DidVerificationKeyRelationship); type Success = (); diff --git a/dip-template/runtimes/dip-consumer/src/lib.rs b/dip-template/runtimes/dip-consumer/src/lib.rs index 624a1d53d0..12c128f62d 100644 --- a/dip-template/runtimes/dip-consumer/src/lib.rs +++ b/dip-template/runtimes/dip-consumer/src/lib.rs @@ -24,7 +24,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 kilt_dip_support::merkle::RevealedDidMerkleProofLeaves; use pallet_did_lookup::linkable_account::LinkableAccountId; pub use sp_consensus_aura::sr25519::AuthorityId as AuraId; pub use sp_runtime::{MultiAddress, Perbill, Permill}; @@ -362,12 +362,12 @@ impl pallet_did_lookup::Config for Runtime { type EnsureOrigin = EnsureDipOrigin< DidIdentifier, AccountId, - VerificationResult, BlockNumber, Web3Name, LinkableAccountId, 10, 10>, + RevealedDidMerkleProofLeaves, BlockNumber, Web3Name, LinkableAccountId, 10, 10>, >; type OriginSuccess = DipOrigin< DidIdentifier, AccountId, - VerificationResult, BlockNumber, Web3Name, LinkableAccountId, 10, 10>, + RevealedDidMerkleProofLeaves, BlockNumber, Web3Name, LinkableAccountId, 10, 10>, >; type RuntimeEvent = RuntimeEvent; type WeightInfo = (); diff --git a/runtimes/common/src/dip/merkle.rs b/runtimes/common/src/dip/merkle.rs index c90fc669f5..62050e2359 100644 --- a/runtimes/common/src/dip/merkle.rs +++ b/runtimes/common/src/dip/merkle.rs @@ -18,7 +18,7 @@ use did::{DidVerificationKeyRelationship, KeyIdOf}; use frame_support::RuntimeDebug; -use kilt_dip_support::merkle::{DidKeyMerkleKey, DidKeyMerkleValue, MerkleProof}; +use kilt_dip_support::merkle::{DidKeyMerkleKey, DidKeyMerkleValue, DidMerkleProof}; use pallet_did_lookup::linkable_account::LinkableAccountId; use pallet_dip_provider::traits::IdentityCommitmentGenerator; use parity_scale_codec::{Decode, Encode}; @@ -26,14 +26,14 @@ use scale_info::TypeInfo; 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}; +use kilt_dip_support::merkle::{DidKeyRelationship, RevealedDidMerkleProofLeaf}; use crate::{dip::did::LinkedDidInfoOf, DidIdentifier}; pub type BlindedValue = Vec; -pub type DidMerkleProofOf = MerkleProof< +pub type DidMerkleProofOf = DidMerkleProof< Vec, - ProofLeaf< + RevealedDidMerkleProofLeaf< KeyIdOf, ::BlockNumber, ::Web3Name, @@ -49,7 +49,7 @@ pub struct CompleteMerkleProof { pub struct DidMerkleRootGenerator(PhantomData); -type ProofLeafOf = ProofLeaf< +type ProofLeafOf = RevealedDidMerkleProofLeaf< KeyIdOf, ::BlockNumber, ::Web3Name, @@ -212,12 +212,18 @@ where } else { Err(()) }?; - Ok(ProofLeaf::DidKey(did_key_merkle_key, key_details.clone().into())) + Ok(RevealedDidMerkleProofLeaf::DidKey( + did_key_merkle_key, + key_details.clone().into(), + )) }) .chain(account_ids.map(|account_id| -> Result, ()> { let Some(linked_accounts) = linked_accounts else { return Err(()) }; if linked_accounts.contains(account_id) { - Ok(ProofLeaf::LinkedAccount(account_id.clone().into(), ().into())) + Ok(RevealedDidMerkleProofLeaf::LinkedAccount( + account_id.clone().into(), + ().into(), + )) } else { Err(()) } @@ -227,7 +233,7 @@ where match (should_include_web3_name, linked_web3_name) { // If web3name should be included and it exists... (true, Some(web3name_details)) => { - leaves.push(ProofLeaf::Web3Name( + leaves.push(RevealedDidMerkleProofLeaf::Web3Name( web3name_details.web3_name.clone().into(), web3name_details.claimed_at.into(), )); From 2718f9509fe34898ca34e77254290ffde7dfba37 Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Fri, 21 Jul 2023 10:46:11 +0200 Subject: [PATCH 22/32] Still working --- crates/kilt-dip-support/src/lib.rs | 98 +++++++++++---------- crates/kilt-dip-support/src/state_proofs.rs | 2 + crates/kilt-dip-support/src/traits.rs | 1 + 3 files changed, 53 insertions(+), 48 deletions(-) diff --git a/crates/kilt-dip-support/src/lib.rs b/crates/kilt-dip-support/src/lib.rs index cd212538fd..3cbba2c473 100644 --- a/crates/kilt-dip-support/src/lib.rs +++ b/crates/kilt-dip-support/src/lib.rs @@ -33,7 +33,7 @@ use crate::{ did::{RevealedDidKeysAndSignature, RevealedDidKeysSignatureAndCallVerifier, TimeBoundDidSignature}, merkle::{DidMerkleProof, DidMerkleProofVerifier, RevealedDidMerkleProofLeaf, RevealedDidMerkleProofLeaves}, state_proofs::{parachain::DipIdentityCommitmentProofVerifier, relay_chain::SiblingParachainHeadProofVerifier}, - traits::{Bump, DidSignatureVerifierContext, DipCallOriginFilter, ProviderParachainStateInfo, RelayChainStateInfo}, + traits::{Bump, DidSignatureVerifierContext, DipCallOriginFilter}, utils::OutputOf, }; @@ -68,34 +68,32 @@ pub struct DipMerkleProofAndDidSignature { did_signature: TimeBoundDidSignature, } -pub struct StateProofDipIdentifier< - RelayInfoProvider, - ProviderParaIdProvider, - ParaInfoProvider, +pub struct DipSiblingProviderStateProofVerifier< + RelayChainStateInfo, + SiblingProviderParachainId, + SiblingProviderStateInfo, TxSubmitter, ProviderDipMerkleHasher, ProviderDidKeyId, - ProviderBlockNumber, ProviderWeb3Name, ProviderLinkedAccountId, const MAX_REVEALED_KEYS_COUNT: u32, const MAX_REVEALED_ACCOUNTS_COUNT: u32, - DidLocalDetails, + LocalDidDetails, LocalContextProvider, LocalDidCallVerifier, >( #[allow(clippy::type_complexity)] PhantomData<( - RelayInfoProvider, - ProviderParaIdProvider, - ParaInfoProvider, + RelayChainStateInfo, + SiblingProviderParachainId, + SiblingProviderStateInfo, TxSubmitter, ProviderDipMerkleHasher, ProviderDidKeyId, - ProviderBlockNumber, ProviderWeb3Name, ProviderLinkedAccountId, - DidLocalDetails, + LocalDidDetails, LocalContextProvider, LocalDidCallVerifier, )>, @@ -104,79 +102,83 @@ pub struct StateProofDipIdentifier< impl< Call, Subject, - RelayInfoProvider, - ProviderParaIdProvider, - ParaInfoProvider, + RelayChainStateInfo, + SiblingProviderParachainId, + SiblingProviderStateInfo, TxSubmitter, ProviderDipMerkleHasher, ProviderDidKeyId, - ProviderBlockNumber, ProviderWeb3Name, ProviderLinkedAccountId, const MAX_REVEALED_KEYS_COUNT: u32, const MAX_REVEALED_ACCOUNTS_COUNT: u32, - DidLocalDetails, + LocalDidDetails, LocalContextProvider, LocalDidCallVerifier, > IdentityProofVerifier - for StateProofDipIdentifier< - RelayInfoProvider, - ProviderParaIdProvider, - ParaInfoProvider, + for DipSiblingProviderStateProofVerifier< + RelayChainStateInfo, + SiblingProviderParachainId, + SiblingProviderStateInfo, TxSubmitter, ProviderDipMerkleHasher, ProviderDidKeyId, - ProviderBlockNumber, ProviderWeb3Name, ProviderLinkedAccountId, MAX_REVEALED_KEYS_COUNT, MAX_REVEALED_ACCOUNTS_COUNT, - DidLocalDetails, + LocalDidDetails, LocalContextProvider, LocalDidCallVerifier, > where Call: Encode, TxSubmitter: Encode, - RelayInfoProvider: RelayChainStateInfo, - RelayInfoProvider::Hasher: 'static, - OutputOf: Ord, - RelayInfoProvider::BlockNumber: Copy + Into + TryFrom + HasCompact, - RelayInfoProvider::Key: AsRef<[u8]>, + RelayChainStateInfo: traits::RelayChainStateInfo, + RelayChainStateInfo::Hasher: 'static, + OutputOf: Ord, + RelayChainStateInfo::BlockNumber: Copy + Into + TryFrom + HasCompact, + RelayChainStateInfo::Key: AsRef<[u8]>, - ProviderParaIdProvider: Get, + SiblingProviderParachainId: Get, - ParaInfoProvider: ProviderParachainStateInfo, - ParaInfoProvider::Hasher: 'static, - OutputOf: Ord + From>, - ParaInfoProvider::Commitment: Decode, - ParaInfoProvider::Key: AsRef<[u8]>, + SiblingProviderStateInfo: + traits::ProviderParachainStateInfo, + SiblingProviderStateInfo::Hasher: 'static, + OutputOf: Ord + From>, + SiblingProviderStateInfo::BlockNumber: Encode + Clone, + SiblingProviderStateInfo::Commitment: Decode, + SiblingProviderStateInfo::Key: AsRef<[u8]>, LocalContextProvider: DidSignatureVerifierContext, LocalContextProvider::BlockNumber: Encode + CheckedSub + PartialOrd, LocalContextProvider::Hash: Encode, LocalContextProvider::SignedExtra: Encode, - DidLocalDetails: Bump + Default + Encode, + LocalDidDetails: Bump + Default + Encode, LocalDidCallVerifier: DipCallOriginFilter, - ProviderBlockNumber: Encode + Clone, ProviderDipMerkleHasher: sp_core::Hasher, - ProviderDidKeyId: Encode + Clone + Ord + Into, + ProviderDidKeyId: Encode + Clone + Into, ProviderLinkedAccountId: Encode + Clone, ProviderWeb3Name: Encode + Clone, { type Error = (); - type IdentityDetails = DidLocalDetails; + type IdentityDetails = LocalDidDetails; type Proof = SiblingParachainDipStateProof< - RelayInfoProvider::BlockNumber, + RelayChainStateInfo::BlockNumber, Vec>, - RevealedDidMerkleProofLeaf, + RevealedDidMerkleProofLeaf< + ProviderDidKeyId, + SiblingProviderStateInfo::BlockNumber, + ProviderWeb3Name, + ProviderLinkedAccountId, + >, LocalContextProvider::BlockNumber, >; type Submitter = TxSubmitter; type VerificationResult = RevealedDidMerkleProofLeaves< ProviderDidKeyId, - ProviderBlockNumber, + SiblingProviderStateInfo::BlockNumber, ProviderWeb3Name, ProviderLinkedAccountId, MAX_REVEALED_KEYS_COUNT, @@ -192,15 +194,15 @@ impl< ) -> Result { // 1. Verify relay chain proof. let provider_parachain_header = - SiblingParachainHeadProofVerifier::::verify_proof_for_parachain( - &ProviderParaIdProvider::get(), + SiblingParachainHeadProofVerifier::::verify_proof_for_parachain( + &SiblingProviderParachainId::get(), &proof.para_state_root.relay_block_height, proof.para_state_root.proof, )?; // 2. Verify parachain state proof. let subject_identity_commitment = - DipIdentityCommitmentProofVerifier::::verify_proof_for_identifier( + DipIdentityCommitmentProofVerifier::::verify_proof_for_identifier( subject, provider_parachain_header.state_root.into(), proof.dip_identity_commitment, @@ -209,10 +211,10 @@ impl< // 3. Verify DIP merkle proof. let proof_leaves = DidMerkleProofVerifier::< ProviderDipMerkleHasher, - ProviderDidKeyId, - ProviderBlockNumber, - ProviderWeb3Name, - ProviderLinkedAccountId, + _, + _, + _, + _, MAX_REVEALED_KEYS_COUNT, MAX_REVEALED_ACCOUNTS_COUNT, >::verify_dip_merkle_proof(&subject_identity_commitment, proof.dip_proof.merkle_proof)?; diff --git a/crates/kilt-dip-support/src/state_proofs.rs b/crates/kilt-dip-support/src/state_proofs.rs index edaf181636..814b2b55e4 100644 --- a/crates/kilt-dip-support/src/state_proofs.rs +++ b/crates/kilt-dip-support/src/state_proofs.rs @@ -267,6 +267,7 @@ pub(super) mod parachain { where Runtime: pallet_dip_provider::Config, { + type BlockNumber = ::BlockNumber; type Commitment = ::IdentityCommitment; type Hasher = ::Hashing; type Identifier = ::Identifier; @@ -299,6 +300,7 @@ pub(super) mod parachain { // We use the `system::eventCount()` storage entry as a unit test here. impl ProviderParachainStateInfo for StaticSpiritnetInfoProvider { + type BlockNumber = u32; // The type of the `eventCount()` storage entry. type Commitment = u32; type Hasher = BlakeTwo256; diff --git a/crates/kilt-dip-support/src/traits.rs b/crates/kilt-dip-support/src/traits.rs index 8d1f5dd7dd..f2de5cace6 100644 --- a/crates/kilt-dip-support/src/traits.rs +++ b/crates/kilt-dip-support/src/traits.rs @@ -65,6 +65,7 @@ pub trait RelayChainStateInfo { } pub trait ProviderParachainStateInfo { + type BlockNumber; type Commitment; type Key; type Hasher: sp_runtime::traits::Hash; From f00cf334b3adbd88218c6098c941f5ca066c3f80 Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Fri, 21 Jul 2023 11:04:00 +0200 Subject: [PATCH 23/32] Refactor complete --- crates/kilt-dip-support/src/did.rs | 4 +- crates/kilt-dip-support/src/lib.rs | 6 ++- crates/kilt-dip-support/src/merkle.rs | 2 +- dip-template/runtimes/dip-consumer/src/dip.rs | 44 +++++++------------ runtimes/common/src/dip/did.rs | 2 +- 5 files changed, 24 insertions(+), 34 deletions(-) diff --git a/crates/kilt-dip-support/src/did.rs b/crates/kilt-dip-support/src/did.rs index 2afc7c46da..7d17b2a8e9 100644 --- a/crates/kilt-dip-support/src/did.rs +++ b/crates/kilt-dip-support/src/did.rs @@ -90,7 +90,7 @@ impl< Call: Encode, Submitter: Encode, ContextProvider: DidSignatureVerifierContext, - ContextProvider::BlockNumber: Encode + CheckedSub + PartialOrd, + ContextProvider::BlockNumber: Encode + CheckedSub + From + PartialOrd, ContextProvider::Hash: Encode, ContextProvider::SignedExtra: Encode, DidLocalDetails: Bump + Default + Encode, @@ -109,7 +109,7 @@ impl< 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 + blocks_ago_from_now <= ContextProvider::SIGNATURE_VALIDITY.into() } else { // Signature generated at a future time, not possible to verify. false diff --git a/crates/kilt-dip-support/src/lib.rs b/crates/kilt-dip-support/src/lib.rs index 3cbba2c473..12f2023522 100644 --- a/crates/kilt-dip-support/src/lib.rs +++ b/crates/kilt-dip-support/src/lib.rs @@ -151,7 +151,7 @@ impl< SiblingProviderStateInfo::Key: AsRef<[u8]>, LocalContextProvider: DidSignatureVerifierContext, - LocalContextProvider::BlockNumber: Encode + CheckedSub + PartialOrd, + LocalContextProvider::BlockNumber: Encode + CheckedSub + From + PartialOrd, LocalContextProvider::Hash: Encode, LocalContextProvider::SignedExtra: Encode, LocalDidDetails: Bump + Default + Encode, @@ -242,3 +242,7 @@ impl< Ok(proof_leaves) } } + +pub use state_proofs::{ + parachain::KiltDipCommitmentsForDipProviderPallet, relay_chain::RococoStateRootsViaRelayStorePallet, +}; diff --git a/crates/kilt-dip-support/src/merkle.rs b/crates/kilt-dip-support/src/merkle.rs index e9dba1b420..66bebe90eb 100644 --- a/crates/kilt-dip-support/src/merkle.rs +++ b/crates/kilt-dip-support/src/merkle.rs @@ -24,7 +24,7 @@ use sp_runtime::{BoundedVec, SaturatedConversion}; use sp_std::{fmt::Debug, marker::PhantomData, vec::Vec}; use sp_trie::{verify_trie_proof, LayoutV1}; -#[derive(Encode, Decode, RuntimeDebug, Clone, Eq, PartialEq, Default)] +#[derive(Encode, Decode, RuntimeDebug, Clone, Eq, PartialEq, Default, TypeInfo)] pub struct DidMerkleProof { pub blinded: BlindedValues, // TODO: Probably replace with a different data structure for better lookup capabilities diff --git a/dip-template/runtimes/dip-consumer/src/dip.rs b/dip-template/runtimes/dip-consumer/src/dip.rs index eea72d0dd0..78d25919df 100644 --- a/dip-template/runtimes/dip-consumer/src/dip.rs +++ b/dip-template/runtimes/dip-consumer/src/dip.rs @@ -17,54 +17,40 @@ // 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::{BlockNumber as ProviderBlockNumber, Web3Name}; +use dip_provider_runtime_template::{Runtime as ProviderRuntime, Web3Name}; use frame_support::traits::Contains; use kilt_dip_support::{ - did::RevealedDidKeysAndSignature, - merkle::{DidMerkleProof, RevealedDidMerkleProofLeaf}, - traits::{ - BlockNumberProvider, DipCallOriginFilter, DipProviderParachainRuntime, GenesisProvider, RococoParachainRuntime, - }, - DipSiblingParachainStateProof, StateProofDipVerifier, + traits::{DipCallOriginFilter, FrameSystemDidSignatureContext}, + DipSiblingProviderStateProofVerifier, KiltDipCommitmentsForDipProviderPallet, RococoStateRootsViaRelayStorePallet, }; use pallet_did_lookup::linkable_account::LinkableAccountId; +use pallet_dip_consumer::traits::IdentityProofVerifier; use sp_core::ConstU32; use sp_runtime::traits::BlakeTwo256; -use sp_std::vec::Vec; -use crate::{AccountId, BlockNumber, DidIdentifier, Hash, Runtime, RuntimeCall, RuntimeOrigin}; +use crate::{AccountId, DidIdentifier, Runtime, RuntimeCall, RuntimeOrigin}; -pub type ProofVerifier = StateProofDipVerifier< - RococoParachainRuntime, - DipProviderParachainRuntime, - KeyIdOf, +pub type ProofVerifier = DipSiblingProviderStateProofVerifier< + RococoStateRootsViaRelayStorePallet, ConstU32<2_000>, - ProviderBlockNumber, - u128, - Web3Name, + KiltDipCommitmentsForDipProviderPallet, + AccountId, BlakeTwo256, + KeyIdOf, + Web3Name, LinkableAccountId, - AccountId, - BlockNumber, - BlockNumberProvider, - GenesisProvider, - DipCallFilter, 10, 10, + u128, // Signatures are valid for 50 blocks - 50, + FrameSystemDidSignatureContext, + DipCallFilter, >; impl pallet_dip_consumer::Config for Runtime { type DipCallOriginFilter = PreliminaryDipOriginFilter; type Identifier = DidIdentifier; - type IdentityProof = DipSiblingParachainStateProof< - u32, - RevealedDidKeysAndSignature< - DidMerkleProof>, RevealedDidMerkleProofLeaf>, - BlockNumber, - >, - >; + type IdentityProof = >::Proof; type LocalIdentityInfo = u128; type ProofVerifier = ProofVerifier; type RuntimeCall = RuntimeCall; diff --git a/runtimes/common/src/dip/did.rs b/runtimes/common/src/dip/did.rs index cebbf104ce..8929a672cb 100644 --- a/runtimes/common/src/dip/did.rs +++ b/runtimes/common/src/dip/did.rs @@ -18,8 +18,8 @@ use did::did_details::DidDetails; use kilt_dip_support::{ - did::{CombineIdentityFrom, CombinedIdentityResult}, merkle::RevealedWeb3Name, + utils::{CombineIdentityFrom, CombinedIdentityResult}, }; use pallet_did_lookup::linkable_account::LinkableAccountId; use pallet_dip_provider::traits::IdentityProvider; From f91693d027be1ea22eab25670ed2ef2339291505 Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Fri, 21 Jul 2023 11:07:18 +0200 Subject: [PATCH 24/32] Pallet updated --- pallets/pallet-relay-store/src/lib.rs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/pallets/pallet-relay-store/src/lib.rs b/pallets/pallet-relay-store/src/lib.rs index c3b08a99d9..1b3538b1ee 100644 --- a/pallets/pallet-relay-store/src/lib.rs +++ b/pallets/pallet-relay-store/src/lib.rs @@ -90,20 +90,21 @@ pub mod pallet { new_validation_data.relay_parent_storage_root, new_validation_data.relay_parent_number, ); - LatestRelayHeads::::insert( - relay_block_height, - RelayParentInfo { - relay_parent_storage_root: new_validation_data.relay_parent_storage_root, - }, - ); let push_res = latest_block_heights.try_push(relay_block_height); if let Err(err) = push_res { log::error!( "Pushing a new relay block to the queue should not fail but it did when adding relay block n. {:?}", err ); + } else { + LatestBlockHeights::::set(latest_block_heights); + LatestRelayHeads::::insert( + relay_block_height, + RelayParentInfo { + relay_parent_storage_root: new_validation_data.relay_parent_storage_root, + }, + ); } - LatestBlockHeights::::set(latest_block_heights); } } } From d81ac186b70c8d5ab256186f9c96cf65631f569e Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Fri, 21 Jul 2023 11:31:50 +0200 Subject: [PATCH 25/32] Renaming --- crates/kilt-dip-support/src/lib.rs | 11 +++++------ pallets/pallet-relay-store/src/lib.rs | 4 ++-- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/crates/kilt-dip-support/src/lib.rs b/crates/kilt-dip-support/src/lib.rs index 12f2023522..9e1819ed7d 100644 --- a/crates/kilt-dip-support/src/lib.rs +++ b/crates/kilt-dip-support/src/lib.rs @@ -52,8 +52,7 @@ pub struct SiblingParachainDipStateProof< > { para_state_root: SiblingParachainRootStateProof, dip_identity_commitment: Vec>, - dip_proof: - DipMerkleProofAndDidSignature, + did: DipMerkleProofAndDidSignature, } #[derive(Encode, Decode, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug, TypeInfo, Clone)] @@ -64,8 +63,8 @@ pub struct SiblingParachainRootStateProof { #[derive(Encode, Decode, PartialEq, Eq, RuntimeDebug, TypeInfo, Clone)] pub struct DipMerkleProofAndDidSignature { - merkle_proof: DidMerkleProof, - did_signature: TimeBoundDidSignature, + leaves: DidMerkleProof, + signature: TimeBoundDidSignature, } pub struct DipSiblingProviderStateProofVerifier< @@ -217,7 +216,7 @@ impl< _, MAX_REVEALED_KEYS_COUNT, MAX_REVEALED_ACCOUNTS_COUNT, - >::verify_dip_merkle_proof(&subject_identity_commitment, proof.dip_proof.merkle_proof)?; + >::verify_dip_merkle_proof(&subject_identity_commitment, proof.did.leaves)?; // 4. Verify DID signature. RevealedDidKeysSignatureAndCallVerifier::< @@ -235,7 +234,7 @@ impl< identity_details, RevealedDidKeysAndSignature { merkle_leaves: proof_leaves.borrow(), - did_signature: proof.dip_proof.did_signature, + did_signature: proof.did.signature, }, )?; diff --git a/pallets/pallet-relay-store/src/lib.rs b/pallets/pallet-relay-store/src/lib.rs index 1b3538b1ee..d7bdbe8b9c 100644 --- a/pallets/pallet-relay-store/src/lib.rs +++ b/pallets/pallet-relay-store/src/lib.rs @@ -40,8 +40,8 @@ pub mod pallet { #[pallet::getter(fn latest_relay_head_for_block)] pub(crate) type LatestRelayHeads = StorageMap<_, Twox64Concat, u32, RelayParentInfo>; - // TODO: Replace this with an array once support for const generics is fully - // supported in Substrate. + // TODO: Replace this with a fixed-length array once support for const generics + // is fully supported in Substrate. #[pallet::storage] pub(crate) type LatestBlockHeights = StorageValue<_, BoundedVec, ValueQuery>; From 22b577c2c699e9dfb5b33fed6ff17e40f86a45d3 Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Fri, 21 Jul 2023 12:21:02 +0200 Subject: [PATCH 26/32] Change SignedExtra to not be Optional --- crates/kilt-dip-support/src/traits.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/kilt-dip-support/src/traits.rs b/crates/kilt-dip-support/src/traits.rs index f2de5cace6..34a1426eb3 100644 --- a/crates/kilt-dip-support/src/traits.rs +++ b/crates/kilt-dip-support/src/traits.rs @@ -83,7 +83,7 @@ pub trait DidSignatureVerifierContext { fn block_number() -> Self::BlockNumber; fn genesis_hash() -> Self::Hash; - fn signed_extra() -> Option; + fn signed_extra() -> Self::SignedExtra; } pub struct FrameSystemDidSignatureContext(PhantomData); @@ -107,7 +107,7 @@ where frame_system::Pallet::::block_hash(T::BlockNumber::zero()) } - fn signed_extra() -> Option { - None + fn signed_extra() -> Self::SignedExtra { + () } } From 358c095a14a4b0bc2915565560090c87dbe388ae Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Fri, 21 Jul 2023 12:23:58 +0200 Subject: [PATCH 27/32] clippy --- crates/kilt-dip-support/src/traits.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/crates/kilt-dip-support/src/traits.rs b/crates/kilt-dip-support/src/traits.rs index 34a1426eb3..ac65ed945c 100644 --- a/crates/kilt-dip-support/src/traits.rs +++ b/crates/kilt-dip-support/src/traits.rs @@ -107,7 +107,5 @@ where frame_system::Pallet::::block_hash(T::BlockNumber::zero()) } - fn signed_extra() -> Self::SignedExtra { - () - } + fn signed_extra() -> Self::SignedExtra {} } From 6020f80a0c49b544616cba8f0c4aca8fa0226d50 Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Fri, 21 Jul 2023 14:17:08 +0200 Subject: [PATCH 28/32] Remove unnecessary derive --- pallets/pallet-dip-consumer/src/identity.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pallets/pallet-dip-consumer/src/identity.rs b/pallets/pallet-dip-consumer/src/identity.rs index e6c5f8a596..eed39f68d4 100644 --- a/pallets/pallet-dip-consumer/src/identity.rs +++ b/pallets/pallet-dip-consumer/src/identity.rs @@ -21,7 +21,7 @@ use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; /// The identity entry for any given user that uses the DIP protocol. -#[derive(Encode, Decode, MaxEncodedLen, Default, TypeInfo, RuntimeDebug, Clone)] +#[derive(Encode, Decode, MaxEncodedLen, Default, TypeInfo, RuntimeDebug)] pub struct IdentityDetails { /// The identity digest information, typically used to verify identity /// proofs. From 408f5b99d42b4774d10a59c1540c3d0442ecece9 Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Fri, 21 Jul 2023 15:13:20 +0200 Subject: [PATCH 29/32] Remove XCM from templates --- Cargo.lock | 12 ------------ crates/kilt-dip-support/Cargo.toml | 4 +++- dip-template/runtimes/dip-consumer/Cargo.toml | 17 +---------------- dip-template/runtimes/dip-provider/Cargo.toml | 18 +----------------- out.txt | 19 +++++++++++++++++++ runtimes/common/Cargo.toml | 1 + 6 files changed, 25 insertions(+), 46 deletions(-) create mode 100644 out.txt diff --git a/Cargo.lock b/Cargo.lock index 5ec62c8ae0..b068d0ef0f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2335,8 +2335,6 @@ dependencies = [ "cumulus-pallet-aura-ext", "cumulus-pallet-dmp-queue", "cumulus-pallet-parachain-system", - "cumulus-pallet-xcm", - "cumulus-pallet-xcmp-queue", "cumulus-primitives-core", "cumulus-primitives-timestamp", "cumulus-primitives-utility", @@ -2360,7 +2358,6 @@ dependencies = [ "pallet-transaction-payment", "pallet-transaction-payment-rpc-runtime-api", "pallet-utility", - "pallet-xcm", "parachain-info", "parity-scale-codec", "polkadot-parachain", @@ -2378,9 +2375,6 @@ dependencies = [ "sp-transaction-pool", "sp-version", "substrate-wasm-builder", - "xcm", - "xcm-builder", - "xcm-executor", ] [[package]] @@ -2439,8 +2433,6 @@ dependencies = [ "cumulus-pallet-aura-ext", "cumulus-pallet-dmp-queue", "cumulus-pallet-parachain-system", - "cumulus-pallet-xcm", - "cumulus-pallet-xcmp-queue", "cumulus-primitives-core", "cumulus-primitives-timestamp", "cumulus-primitives-utility", @@ -2463,7 +2455,6 @@ dependencies = [ "pallet-transaction-payment", "pallet-transaction-payment-rpc-runtime-api", "pallet-web3-names", - "pallet-xcm", "parachain-info", "parity-scale-codec", "runtime-common", @@ -2480,9 +2471,6 @@ dependencies = [ "sp-transaction-pool", "sp-version", "substrate-wasm-builder", - "xcm", - "xcm-builder", - "xcm-executor", ] [[package]] diff --git a/crates/kilt-dip-support/Cargo.toml b/crates/kilt-dip-support/Cargo.toml index be6c978edc..9290c8b704 100644 --- a/crates/kilt-dip-support/Cargo.toml +++ b/crates/kilt-dip-support/Cargo.toml @@ -69,4 +69,6 @@ std = [ "xcm-executor/std", "cumulus-pallet-parachain-system/std", ] -runtime-benchmarks = [] +runtime-benchmarks = [ + "rococo-runtime/runtime-benchmarks" +] diff --git a/dip-template/runtimes/dip-consumer/Cargo.toml b/dip-template/runtimes/dip-consumer/Cargo.toml index d92866355f..578eeff8a0 100644 --- a/dip-template/runtimes/dip-consumer/Cargo.toml +++ b/dip-template/runtimes/dip-consumer/Cargo.toml @@ -53,18 +53,10 @@ sp-std.workspace = true sp-transaction-pool.workspace = true sp-version.workspace = true -# Polkadot -pallet-xcm.workspace = true -xcm.workspace = true -xcm-builder.workspace = true -xcm-executor.workspace = true - # Cumulus cumulus-pallet-aura-ext.workspace = true cumulus-pallet-dmp-queue.workspace = true cumulus-pallet-parachain-system.workspace = true -cumulus-pallet-xcm.workspace = true -cumulus-pallet-xcmp-queue.workspace = true cumulus-primitives-core.workspace = true cumulus-primitives-timestamp.workspace = true cumulus-primitives-utility.workspace = true @@ -110,15 +102,9 @@ std = [ "sp-std/std", "sp-transaction-pool/std", "sp-version/std", - "pallet-xcm/std", - "xcm/std", - "xcm-builder/std", - "xcm-executor/std", "cumulus-pallet-aura-ext/std", "cumulus-pallet-dmp-queue/std", "cumulus-pallet-parachain-system/std", - "cumulus-pallet-xcm/std", - "cumulus-pallet-xcmp-queue/std", "cumulus-primitives-core/std", "cumulus-primitives-timestamp/std", "cumulus-primitives-utility/std", @@ -128,10 +114,9 @@ std = [ runtime-benchmarks = [ "dip-provider-runtime-template/runtime-benchmarks", + "kilt-dip-support/runtime-benchmarks", "pallet-dip-consumer/runtime-benchmarks", "runtime-common/runtime-benchmarks", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", - "pallet-xcm/runtime-benchmarks", - "xcm-builder/runtime-benchmarks", ] diff --git a/dip-template/runtimes/dip-provider/Cargo.toml b/dip-template/runtimes/dip-provider/Cargo.toml index 4fe0746226..dff25abda3 100644 --- a/dip-template/runtimes/dip-provider/Cargo.toml +++ b/dip-template/runtimes/dip-provider/Cargo.toml @@ -51,18 +51,10 @@ sp-std.workspace = true sp-transaction-pool.workspace = true sp-version.workspace = true -# Polkadot -pallet-xcm.workspace = true -xcm.workspace = true -xcm-builder.workspace = true -xcm-executor.workspace = true - # Cumulus cumulus-pallet-aura-ext.workspace = true cumulus-pallet-dmp-queue.workspace = true cumulus-pallet-parachain-system.workspace = true -cumulus-pallet-xcm.workspace = true -cumulus-pallet-xcmp-queue.workspace = true cumulus-primitives-core.workspace = true cumulus-primitives-timestamp.workspace = true cumulus-primitives-utility.workspace = true @@ -106,15 +98,9 @@ std = [ "sp-std/std", "sp-transaction-pool/std", "sp-version/std", - "pallet-xcm/std", - "xcm/std", - "xcm-builder/std", - "xcm-executor/std", "cumulus-pallet-aura-ext/std", "cumulus-pallet-dmp-queue/std", "cumulus-pallet-parachain-system/std", - "cumulus-pallet-xcm/std", - "cumulus-pallet-xcmp-queue/std", "cumulus-primitives-core/std", "cumulus-primitives-timestamp/std", "cumulus-primitives-utility/std", @@ -129,7 +115,5 @@ runtime-benchmarks = [ "pallet-web3-names/runtime-benchmarks", "runtime-common/runtime-benchmarks", "frame-system/runtime-benchmarks", - "frame-support/runtime-benchmarks", - "pallet-xcm/runtime-benchmarks", - "xcm-builder/runtime-benchmarks" + "frame-support/runtime-benchmarks" ] diff --git a/out.txt b/out.txt new file mode 100644 index 0000000000..f2b36c2be0 --- /dev/null +++ b/out.txt @@ -0,0 +1,19 @@ +pallet-society v4.0.0-dev (https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b8452) +└── rococo-runtime v0.9.39-1 (https://github.com/paritytech/polkadot?branch=release-v0.9.39#c22e1c41) + └── kilt-dip-support v1.11.0-dev (/home/antonio/Developer/kilt-node/crates/kilt-dip-support) + ├── dip-consumer-runtime-template v1.11.0-dev (/home/antonio/Developer/kilt-node/dip-template/runtimes/dip-consumer) + │ └── dip-consumer-node-template v1.11.0-dev (/home/antonio/Developer/kilt-node/dip-template/nodes/dip-consumer) + ├── dip-provider-runtime-template v1.11.0-dev (/home/antonio/Developer/kilt-node/dip-template/runtimes/dip-provider) + │ ├── dip-consumer-runtime-template v1.11.0-dev (/home/antonio/Developer/kilt-node/dip-template/runtimes/dip-consumer) (*) + │ └── dip-provider-node-template v1.11.0-dev (/home/antonio/Developer/kilt-node/dip-template/nodes/dip-provider) + └── runtime-common v1.11.0-dev (/home/antonio/Developer/kilt-node/runtimes/common) + ├── dip-consumer-runtime-template v1.11.0-dev (/home/antonio/Developer/kilt-node/dip-template/runtimes/dip-consumer) (*) + ├── dip-provider-runtime-template v1.11.0-dev (/home/antonio/Developer/kilt-node/dip-template/runtimes/dip-provider) (*) + ├── kilt-parachain v1.11.0-dev (/home/antonio/Developer/kilt-node/nodes/parachain) + ├── mashnet-node v1.11.0-dev (/home/antonio/Developer/kilt-node/nodes/standalone) + ├── mashnet-node-runtime v1.11.0-dev (/home/antonio/Developer/kilt-node/runtimes/standalone) + │ └── mashnet-node v1.11.0-dev (/home/antonio/Developer/kilt-node/nodes/standalone) + ├── peregrine-runtime v1.11.0-dev (/home/antonio/Developer/kilt-node/runtimes/peregrine) + │ └── kilt-parachain v1.11.0-dev (/home/antonio/Developer/kilt-node/nodes/parachain) + └── spiritnet-runtime v1.11.0-dev (/home/antonio/Developer/kilt-node/runtimes/spiritnet) + └── kilt-parachain v1.11.0-dev (/home/antonio/Developer/kilt-node/nodes/parachain) diff --git a/runtimes/common/Cargo.toml b/runtimes/common/Cargo.toml index c650a681ef..e8226c9306 100644 --- a/runtimes/common/Cargo.toml +++ b/runtimes/common/Cargo.toml @@ -70,6 +70,7 @@ runtime-benchmarks = [ "pallet-dip-consumer/runtime-benchmarks", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", + "kilt-dip-support/runtime-benchmarks", "kilt-support/runtime-benchmarks", "pallet-balances/runtime-benchmarks", "pallet-membership/runtime-benchmarks", From 4dfc7a3d8b48fdd783b319960ecae3d221c5f461 Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Fri, 21 Jul 2023 15:42:23 +0200 Subject: [PATCH 30/32] Remove unwanted file --- out.txt | 19 ------------------- 1 file changed, 19 deletions(-) delete mode 100644 out.txt diff --git a/out.txt b/out.txt deleted file mode 100644 index f2b36c2be0..0000000000 --- a/out.txt +++ /dev/null @@ -1,19 +0,0 @@ -pallet-society v4.0.0-dev (https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b8452) -└── rococo-runtime v0.9.39-1 (https://github.com/paritytech/polkadot?branch=release-v0.9.39#c22e1c41) - └── kilt-dip-support v1.11.0-dev (/home/antonio/Developer/kilt-node/crates/kilt-dip-support) - ├── dip-consumer-runtime-template v1.11.0-dev (/home/antonio/Developer/kilt-node/dip-template/runtimes/dip-consumer) - │ └── dip-consumer-node-template v1.11.0-dev (/home/antonio/Developer/kilt-node/dip-template/nodes/dip-consumer) - ├── dip-provider-runtime-template v1.11.0-dev (/home/antonio/Developer/kilt-node/dip-template/runtimes/dip-provider) - │ ├── dip-consumer-runtime-template v1.11.0-dev (/home/antonio/Developer/kilt-node/dip-template/runtimes/dip-consumer) (*) - │ └── dip-provider-node-template v1.11.0-dev (/home/antonio/Developer/kilt-node/dip-template/nodes/dip-provider) - └── runtime-common v1.11.0-dev (/home/antonio/Developer/kilt-node/runtimes/common) - ├── dip-consumer-runtime-template v1.11.0-dev (/home/antonio/Developer/kilt-node/dip-template/runtimes/dip-consumer) (*) - ├── dip-provider-runtime-template v1.11.0-dev (/home/antonio/Developer/kilt-node/dip-template/runtimes/dip-provider) (*) - ├── kilt-parachain v1.11.0-dev (/home/antonio/Developer/kilt-node/nodes/parachain) - ├── mashnet-node v1.11.0-dev (/home/antonio/Developer/kilt-node/nodes/standalone) - ├── mashnet-node-runtime v1.11.0-dev (/home/antonio/Developer/kilt-node/runtimes/standalone) - │ └── mashnet-node v1.11.0-dev (/home/antonio/Developer/kilt-node/nodes/standalone) - ├── peregrine-runtime v1.11.0-dev (/home/antonio/Developer/kilt-node/runtimes/peregrine) - │ └── kilt-parachain v1.11.0-dev (/home/antonio/Developer/kilt-node/nodes/parachain) - └── spiritnet-runtime v1.11.0-dev (/home/antonio/Developer/kilt-node/runtimes/spiritnet) - └── kilt-parachain v1.11.0-dev (/home/antonio/Developer/kilt-node/nodes/parachain) From 9cbbd549c35f2a613dbf5d718b8d9ee574ff24c5 Mon Sep 17 00:00:00 2001 From: Antonio Date: Wed, 23 Aug 2023 11:48:24 +0200 Subject: [PATCH 31/32] feat: add support for relay chain (#553) Builds on the new state proofs by adding support for a relay chain to be a consumer with the new `ChildParachainDipStateProof` and `DipChildProviderStateProofVerifier` types. Some traits and types have also been renamed. The new feature has been tested with a local Rococo 0.9.43 deployment, and can be reproduced by download and compiling our Polkadot fork at the [demo-sub0-23 tag](https://github.com/KILTprotocol/polkadot/tree/demo-sub0-23). This PR also adds the `postit` pallet that was written for the Decoded demo, and uses that instead of the lookup pallet as an example pallet integrating DIP. --- Cargo.lock | 13 + Cargo.toml | 4 +- crates/kilt-dip-support/src/lib.rs | 250 ++++++++++++++++-- crates/kilt-dip-support/src/state_proofs.rs | 107 ++++---- crates/kilt-dip-support/src/traits.rs | 55 +++- .../nodes/dip-consumer/src/chain_spec.rs | 1 - dip-template/pallets/pallet-postit/Cargo.toml | 40 +++ dip-template/pallets/pallet-postit/src/lib.rs | 185 +++++++++++++ .../pallets/pallet-postit/src/post.rs | 55 ++++ .../pallets/pallet-postit/src/traits.rs | 23 ++ dip-template/runtimes/dip-consumer/Cargo.toml | 2 + dip-template/runtimes/dip-consumer/src/dip.rs | 53 +--- dip-template/runtimes/dip-consumer/src/lib.rs | 36 +-- .../dip-consumer/src/origin_adapter.rs | 53 ++++ dip-template/runtimes/dip-provider/src/lib.rs | 3 +- 15 files changed, 727 insertions(+), 153 deletions(-) create mode 100644 dip-template/pallets/pallet-postit/Cargo.toml create mode 100644 dip-template/pallets/pallet-postit/src/lib.rs create mode 100644 dip-template/pallets/pallet-postit/src/post.rs create mode 100644 dip-template/pallets/pallet-postit/src/traits.rs create mode 100644 dip-template/runtimes/dip-consumer/src/origin_adapter.rs diff --git a/Cargo.lock b/Cargo.lock index 4994a89e3d..258fca0c15 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2397,6 +2397,7 @@ dependencies = [ "pallet-collator-selection", "pallet-did-lookup", "pallet-dip-consumer", + "pallet-postit", "pallet-relay-store", "pallet-session", "pallet-sudo", @@ -6772,6 +6773,18 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-postit" +version = "1.12.0-dev" +dependencies = [ + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "sp-runtime", + "sp-std", +] + [[package]] name = "pallet-preimage" version = "4.0.0-dev" diff --git a/Cargo.toml b/Cargo.toml index 1b952718fd..cf103d157b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,7 @@ version = "1.12.0-dev" members = [ "crates/*", "dip-template/nodes/*", + "dip-template/pallets/*", "dip-template/runtimes/*", "nodes/*", "pallets/*", @@ -42,7 +43,7 @@ jsonrpsee = "0.16.2" libsecp256k1 = {version = "0.7", default-features = false} log = "0.4.17" parity-scale-codec = {version = "3.1.5", default-features = false} -scale-info = {version = "2.1.1", default-features = false} +scale-info = {version = "2.7.0", default-features = false} serde = "1.0.144" serde_json = "1.0.85" sha3 = {version = "0.10.0", default-features = false} @@ -72,6 +73,7 @@ runtime-common = {path = "runtimes/common", default-features = false} # Templates dip-consumer-runtime-template = {path = "dip-template/runtimes/dip-consumer", default-features = false} dip-provider-runtime-template = {path = "dip-template/runtimes/dip-provider", default-features = false} +pallet-postit = {path = "dip-template/pallets/pallet-postit", default-features = false} # Internal runtime API (with default disabled) kilt-runtime-api-did = {path = "runtime-api/did", default-features = false} diff --git a/crates/kilt-dip-support/src/lib.rs b/crates/kilt-dip-support/src/lib.rs index 9e1819ed7d..b19daada83 100644 --- a/crates/kilt-dip-support/src/lib.rs +++ b/crates/kilt-dip-support/src/lib.rs @@ -20,10 +20,13 @@ #![cfg_attr(not(feature = "std"), no_std)] -use parity_scale_codec::{Decode, Encode, HasCompact}; +use parity_scale_codec::{Codec, Decode, Encode, HasCompact}; use scale_info::TypeInfo; use sp_core::{Get, RuntimeDebug, U256}; -use sp_runtime::traits::CheckedSub; +use sp_runtime::{ + generic::Header, + traits::{AtLeast32BitUnsigned, CheckedSub, Hash, MaybeDisplay, Member, SimpleBitOps}, +}; use sp_std::{borrow::Borrow, marker::PhantomData, vec::Vec}; use ::did::{did_details::DidVerificationKey, DidVerificationKeyRelationship}; @@ -32,8 +35,11 @@ use pallet_dip_consumer::traits::IdentityProofVerifier; use crate::{ did::{RevealedDidKeysAndSignature, RevealedDidKeysSignatureAndCallVerifier, TimeBoundDidSignature}, merkle::{DidMerkleProof, DidMerkleProofVerifier, RevealedDidMerkleProofLeaf, RevealedDidMerkleProofLeaves}, - state_proofs::{parachain::DipIdentityCommitmentProofVerifier, relay_chain::SiblingParachainHeadProofVerifier}, - traits::{Bump, DidSignatureVerifierContext, DipCallOriginFilter}, + state_proofs::{parachain::DipIdentityCommitmentProofVerifier, relay_chain::ParachainHeadProofVerifier}, + traits::{ + Bump, DidSignatureVerifierContext, DipCallOriginFilter, HistoricalBlockRegistry, ProviderParachainStateInfo, + RelayChainStorageInfo, + }, utils::OutputOf, }; @@ -43,6 +49,8 @@ pub mod state_proofs; pub mod traits; pub mod utils; +pub use state_proofs::relay_chain::RococoStateRootsViaRelayStorePallet; + #[derive(Encode, Decode, PartialEq, Eq, RuntimeDebug, TypeInfo, Clone)] pub struct SiblingParachainDipStateProof< RelayBlockHeight, @@ -50,13 +58,13 @@ pub struct SiblingParachainDipStateProof< DipMerkleProofRevealedLeaf, DipProviderBlockNumber, > { - para_state_root: SiblingParachainRootStateProof, + para_state_root: ParachainRootStateProof, dip_identity_commitment: Vec>, did: DipMerkleProofAndDidSignature, } #[derive(Encode, Decode, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug, TypeInfo, Clone)] -pub struct SiblingParachainRootStateProof { +pub struct ParachainRootStateProof { relay_block_height: RelayBlockHeight, proof: Vec>, } @@ -67,6 +75,7 @@ pub struct DipMerkleProofAndDidSignature { signature: TimeBoundDidSignature, } +#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)] pub struct DipSiblingProviderStateProofVerifier< RelayChainStateInfo, SiblingProviderParachainId, @@ -133,8 +142,7 @@ impl< Call: Encode, TxSubmitter: Encode, - RelayChainStateInfo: traits::RelayChainStateInfo, - RelayChainStateInfo::Hasher: 'static, + RelayChainStateInfo: traits::RelayChainStorageInfo + traits::RelayChainStateInfo, OutputOf: Ord, RelayChainStateInfo::BlockNumber: Copy + Into + TryFrom + HasCompact, RelayChainStateInfo::Key: AsRef<[u8]>, @@ -143,7 +151,6 @@ impl< SiblingProviderStateInfo: traits::ProviderParachainStateInfo, - SiblingProviderStateInfo::Hasher: 'static, OutputOf: Ord + From>, SiblingProviderStateInfo::BlockNumber: Encode + Clone, SiblingProviderStateInfo::Commitment: Decode, @@ -192,12 +199,11 @@ impl< proof: Self::Proof, ) -> Result { // 1. Verify relay chain proof. - let provider_parachain_header = - SiblingParachainHeadProofVerifier::::verify_proof_for_parachain( - &SiblingProviderParachainId::get(), - &proof.para_state_root.relay_block_height, - proof.para_state_root.proof, - )?; + let provider_parachain_header = ParachainHeadProofVerifier::::verify_proof_for_parachain( + &SiblingProviderParachainId::get(), + &proof.para_state_root.relay_block_height, + proof.para_state_root.proof, + )?; // 2. Verify parachain state proof. let subject_identity_commitment = @@ -242,6 +248,214 @@ impl< } } -pub use state_proofs::{ - parachain::KiltDipCommitmentsForDipProviderPallet, relay_chain::RococoStateRootsViaRelayStorePallet, -}; +#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)] +pub struct ChildParachainDipStateProof< + RelayBlockHeight: Copy + Into + TryFrom, + RelayBlockHasher: Hash, + DipMerkleProofBlindedValues, + DipMerkleProofRevealedLeaf, + DipProviderBlockNumber, +> { + para_state_root: ParachainRootStateProof, + relay_header: Header, + dip_identity_commitment: Vec>, + did: DipMerkleProofAndDidSignature, +} + +pub struct DipChildProviderStateProofVerifier< + RelayChainInfo, + SiblingProviderParachainId, + SiblingProviderStateInfo, + TxSubmitter, + ProviderDipMerkleHasher, + ProviderDidKeyId, + ProviderWeb3Name, + ProviderLinkedAccountId, + const MAX_REVEALED_KEYS_COUNT: u32, + const MAX_REVEALED_ACCOUNTS_COUNT: u32, + LocalDidDetails, + LocalContextProvider, + LocalDidCallVerifier, +>( + #[allow(clippy::type_complexity)] + PhantomData<( + RelayChainInfo, + SiblingProviderParachainId, + SiblingProviderStateInfo, + TxSubmitter, + ProviderDipMerkleHasher, + ProviderDidKeyId, + ProviderWeb3Name, + ProviderLinkedAccountId, + LocalDidDetails, + LocalContextProvider, + LocalDidCallVerifier, + )>, +); + +impl< + Call, + Subject, + RelayChainInfo, + SiblingProviderParachainId, + SiblingProviderStateInfo, + TxSubmitter, + ProviderDipMerkleHasher, + ProviderDidKeyId, + ProviderWeb3Name, + ProviderLinkedAccountId, + const MAX_REVEALED_KEYS_COUNT: u32, + const MAX_REVEALED_ACCOUNTS_COUNT: u32, + LocalDidDetails, + LocalContextProvider, + LocalDidCallVerifier, + > IdentityProofVerifier + for DipChildProviderStateProofVerifier< + RelayChainInfo, + SiblingProviderParachainId, + SiblingProviderStateInfo, + TxSubmitter, + ProviderDipMerkleHasher, + ProviderDidKeyId, + ProviderWeb3Name, + ProviderLinkedAccountId, + MAX_REVEALED_KEYS_COUNT, + MAX_REVEALED_ACCOUNTS_COUNT, + LocalDidDetails, + LocalContextProvider, + LocalDidCallVerifier, + > where + Call: Encode, + TxSubmitter: Encode, + + RelayChainInfo: RelayChainStorageInfo + + HistoricalBlockRegistry< + BlockNumber = ::BlockNumber, + Hasher = ::Hasher, + >, + OutputOf<::Hasher>: + Ord + Default + sp_std::hash::Hash + Copy + Member + MaybeDisplay + SimpleBitOps + Codec, + ::BlockNumber: Copy + + Into + + TryFrom + + HasCompact + + Member + + sp_std::hash::Hash + + MaybeDisplay + + AtLeast32BitUnsigned + + Codec, + RelayChainInfo::Key: AsRef<[u8]>, + + SiblingProviderParachainId: Get, + + SiblingProviderStateInfo: + ProviderParachainStateInfo, + OutputOf: Ord + From::Hasher>>, + SiblingProviderStateInfo::BlockNumber: Encode + Clone, + SiblingProviderStateInfo::Commitment: Decode, + SiblingProviderStateInfo::Key: AsRef<[u8]>, + + LocalContextProvider: DidSignatureVerifierContext, + LocalContextProvider::BlockNumber: Encode + CheckedSub + From + PartialOrd, + LocalContextProvider::Hash: Encode, + LocalContextProvider::SignedExtra: Encode, + LocalDidDetails: Bump + Default + Encode, + LocalDidCallVerifier: DipCallOriginFilter, + + ProviderDipMerkleHasher: sp_core::Hasher, + ProviderDidKeyId: Encode + Clone + Into, + ProviderLinkedAccountId: Encode + Clone, + ProviderWeb3Name: Encode + Clone, +{ + type Error = (); + type IdentityDetails = LocalDidDetails; + type Proof = ChildParachainDipStateProof< + ::BlockNumber, + ::Hasher, + Vec>, + RevealedDidMerkleProofLeaf< + ProviderDidKeyId, + SiblingProviderStateInfo::BlockNumber, + ProviderWeb3Name, + ProviderLinkedAccountId, + >, + LocalContextProvider::BlockNumber, + >; + type Submitter = TxSubmitter; + type VerificationResult = RevealedDidMerkleProofLeaves< + ProviderDidKeyId, + SiblingProviderStateInfo::BlockNumber, + ProviderWeb3Name, + ProviderLinkedAccountId, + MAX_REVEALED_KEYS_COUNT, + MAX_REVEALED_ACCOUNTS_COUNT, + >; + + fn verify_proof_for_call_against_details( + call: &Call, + subject: &Subject, + submitter: &Self::Submitter, + identity_details: &mut Option, + proof: Self::Proof, + ) -> Result { + // 1. Retrieve block hash from provider at the proof height + let block_hash_at_height = + RelayChainInfo::block_hash_for(&proof.para_state_root.relay_block_height).ok_or(())?; + + // 1.1 Verify that the provided header hashes to the same block has retrieved + if block_hash_at_height != proof.relay_header.hash() { + return Err(()); + } + // 1.2 If so, extract the state root from the header + let state_root_at_height = proof.relay_header.state_root; + + // FIXME: Compilation error + // 2. Verify relay chain proof + let provider_parachain_header = + ParachainHeadProofVerifier::::verify_proof_for_parachain_with_root( + &SiblingProviderParachainId::get(), + &state_root_at_height, + proof.para_state_root.proof, + )?; + + // 3. Verify parachain state proof. + let subject_identity_commitment = + DipIdentityCommitmentProofVerifier::::verify_proof_for_identifier( + subject, + provider_parachain_header.state_root.into(), + proof.dip_identity_commitment, + )?; + + // 4. Verify DIP merkle proof. + let proof_leaves = DidMerkleProofVerifier::< + ProviderDipMerkleHasher, + _, + _, + _, + _, + MAX_REVEALED_KEYS_COUNT, + MAX_REVEALED_ACCOUNTS_COUNT, + >::verify_dip_merkle_proof(&subject_identity_commitment, proof.did.leaves)?; + + // 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, + }, + )?; + Ok(proof_leaves) + } +} diff --git a/crates/kilt-dip-support/src/state_proofs.rs b/crates/kilt-dip-support/src/state_proofs.rs index 814b2b55e4..0e8bf02562 100644 --- a/crates/kilt-dip-support/src/state_proofs.rs +++ b/crates/kilt-dip-support/src/state_proofs.rs @@ -45,7 +45,7 @@ mod substrate_no_std_port { keys: I, ) -> Result, Option>>, ()> where - H: Hasher + 'static, + H: Hasher, H::Out: Ord + Codec, I: IntoIterator, I::Item: AsRef<[u8]>, @@ -90,33 +90,28 @@ pub(super) mod relay_chain { use sp_runtime::traits::BlakeTwo256; - use crate::traits::RelayChainStateInfo; + use crate::traits::{RelayChainStateInfo, RelayChainStorageInfo}; - pub struct SiblingParachainHeadProofVerifier(PhantomData); + pub struct ParachainHeadProofVerifier(PhantomData); - impl SiblingParachainHeadProofVerifier + // Uses the provided `root` to verify the proof. + impl ParachainHeadProofVerifier where - RelayChainState: RelayChainStateInfo, - RelayChainState::Hasher: 'static, + RelayChainState: RelayChainStorageInfo, OutputOf: Ord, RelayChainState::BlockNumber: Copy + Into + TryFrom + HasCompact, RelayChainState::Key: AsRef<[u8]>, { - #[allow(clippy::result_unit_err)] - pub fn verify_proof_for_parachain( + pub fn verify_proof_for_parachain_with_root( para_id: &RelayChainState::ParaId, - relay_height: &RelayChainState::BlockNumber, + root: &OutputOf<::Hasher>, proof: impl IntoIterator>, ) -> Result, ()> { - let relay_state_root = RelayChainState::state_root_for_block(relay_height).ok_or(())?; let parachain_storage_key = RelayChainState::parachain_head_storage_key(para_id); let storage_proof = StorageProof::new(proof); - let revealed_leaves = read_proof_check::( - relay_state_root, - storage_proof, - [¶chain_storage_key].iter(), - ) - .map_err(|_| ())?; + let revealed_leaves = + read_proof_check::(*root, storage_proof, [¶chain_storage_key].iter()) + .map_err(|_| ())?; // TODO: Remove at some point { debug_assert!(revealed_leaves.len() == 1usize); @@ -129,9 +124,29 @@ pub(super) mod relay_chain { } } + // 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]>, + { + #[allow(clippy::result_unit_err)] + pub fn verify_proof_for_parachain( + para_id: &RelayChainState::ParaId, + relay_height: &RelayChainState::BlockNumber, + proof: impl IntoIterator>, + ) -> Result, ()> { + let relay_state_root = RelayChainState::state_root_for_block(relay_height).ok_or(())?; + Self::verify_proof_for_parachain_with_root(para_id, &relay_state_root, proof) + } + } + pub struct RococoStateRootsViaRelayStorePallet(PhantomData); - impl RelayChainStateInfo for RococoStateRootsViaRelayStorePallet + impl RelayChainStorageInfo for RococoStateRootsViaRelayStorePallet where Runtime: pallet_relay_store::Config, { @@ -140,11 +155,6 @@ pub(super) mod relay_chain { type Key = StorageKey; type ParaId = u32; - fn state_root_for_block(block_height: &Self::BlockNumber) -> Option> { - pallet_relay_store::Pallet::::latest_relay_head_for_block(block_height) - .map(|relay_header| relay_header.relay_parent_storage_root) - } - fn parachain_head_storage_key(para_id: &Self::ParaId) -> Self::Key { // TODO: It's not possible to access the runtime definition from here. let encoded_para_id = para_id.encode(); @@ -158,6 +168,16 @@ pub(super) mod relay_chain { } } + impl RelayChainStateInfo for RococoStateRootsViaRelayStorePallet + where + Runtime: pallet_relay_store::Config, + { + fn state_root_for_block(block_height: &Self::BlockNumber) -> Option> { + pallet_relay_store::Pallet::::latest_relay_head_for_block(block_height) + .map(|relay_header| relay_header.relay_parent_storage_root) + } + } + #[cfg(test)] mod polkadot_parachain_head_proof_verifier_tests { use super::*; @@ -169,7 +189,7 @@ pub(super) mod relay_chain { // hash 0x18e90e9aa8e3b063f60386ba1b0415111798e72d01de58b1438d620d42f58e39 struct StaticPolkadotInfoProvider; - impl RelayChainStateInfo for StaticPolkadotInfoProvider { + impl RelayChainStorageInfo for StaticPolkadotInfoProvider { type BlockNumber = u32; type Hasher = BlakeTwo256; type Key = StorageKey; @@ -188,7 +208,9 @@ pub(super) mod relay_chain { .concat(); StorageKey(storage_key) } + } + impl RelayChainStateInfo for StaticPolkadotInfoProvider { fn state_root_for_block(_block_height: &Self::BlockNumber) -> Option> { Some(hex!("81b75d95075d16005ee0a987a3f061d3011ada919b261e9b02961b9b3725f3fd").into()) } @@ -210,13 +232,12 @@ pub(super) mod relay_chain { // "0xcd710b30bd2eab0352ddcc26417aa1941b3c252fcb29d88eff4f3de5de4476c32c0cfd6c23b92a7826080000" // let expected_spiritnet_head_at_block = hex!("65541097fb02782e14f43074f0b00e44ae8e9fe426982323ef1d329739740d37f252ff006d1156941db1bccd58ce3a1cac4f40cad91f692d94e98f501dd70081a129b69a3e2ef7e1ff84ba3d86dab4e95f2c87f6b1055ebd48519c185360eae58f05d1ea08066175726120dcdc6308000000000561757261010170ccfaf3756d1a8dd8ae5c89094199d6d32e5dd9f0920f6fe30f986815b5e701974ea0e0e0a901401f2c72e3dd8dbdf4aa55d59bf3e7021856cdb8038419eb8c").to_vec(); - let returned_head = - SiblingParachainHeadProofVerifier::::verify_proof_for_parachain( - &2_086, - &16_363_919, - spiritnet_head_proof_at_block, - ) - .expect("Parachain head proof verification should not fail."); + let returned_head = ParachainHeadProofVerifier::::verify_proof_for_parachain( + &2_086, + &16_363_919, + spiritnet_head_proof_at_block, + ) + .expect("Parachain head proof verification should not fail."); assert!(returned_head.encode() == expected_spiritnet_head_at_block, "Parachain head returned from the state proof verification should not be different than the pre-computed one."); } } @@ -232,7 +253,6 @@ pub(super) mod parachain { impl DipIdentityCommitmentProofVerifier where ParaInfo: ProviderParachainStateInfo, - ParaInfo::Hasher: 'static, OutputOf: Ord, ParaInfo::Commitment: Decode, ParaInfo::Key: AsRef<[u8]>, @@ -261,31 +281,6 @@ pub(super) mod parachain { } } - pub struct KiltDipCommitmentsForDipProviderPallet(PhantomData); - - impl ProviderParachainStateInfo for KiltDipCommitmentsForDipProviderPallet - where - Runtime: pallet_dip_provider::Config, - { - type BlockNumber = ::BlockNumber; - type Commitment = ::IdentityCommitment; - type Hasher = ::Hashing; - type Identifier = ::Identifier; - type Key = StorageKey; - - fn dip_subject_storage_key(identifier: &Self::Identifier) -> Self::Key { - // TODO: Replace with actual runtime definition - let encoded_identifier = identifier.encode(); - let storage_key = [ - frame_support::storage::storage_prefix(b"DipProvider", b"IdentityCommitments").as_slice(), - sp_io::hashing::twox_64(&encoded_identifier).as_slice(), - encoded_identifier.as_slice(), - ] - .concat(); - StorageKey(storage_key) - } - } - #[cfg(test)] mod spiritnet_test_event_count_value { use super::*; diff --git a/crates/kilt-dip-support/src/traits.rs b/crates/kilt-dip-support/src/traits.rs index ac65ed945c..2477d82a4f 100644 --- a/crates/kilt-dip-support/src/traits.rs +++ b/crates/kilt-dip-support/src/traits.rs @@ -16,6 +16,7 @@ // If you feel like getting in touch with us, you can do so at info@botlabs.org +use sp_core::storage::StorageKey; use sp_runtime::traits::{CheckedAdd, One, Zero}; use sp_std::marker::PhantomData; @@ -54,16 +55,19 @@ pub trait DipCallOriginFilter { fn check_call_origin_info(call: &Call, info: &Self::OriginInfo) -> Result; } -pub trait RelayChainStateInfo { +pub trait RelayChainStorageInfo { type BlockNumber; - type Key; type Hasher: sp_runtime::traits::Hash; + type Key; type ParaId; - fn state_root_for_block(block_height: &Self::BlockNumber) -> Option>; fn parachain_head_storage_key(para_id: &Self::ParaId) -> Self::Key; } +pub trait RelayChainStateInfo: RelayChainStorageInfo { + fn state_root_for_block(block_height: &Self::BlockNumber) -> Option>; +} + pub trait ProviderParachainStateInfo { type BlockNumber; type Commitment; @@ -74,6 +78,25 @@ pub trait ProviderParachainStateInfo { fn dip_subject_storage_key(identifier: &Self::Identifier) -> Self::Key; } +pub struct ProviderParachainStateInfoViaProviderPallet(PhantomData); + +impl ProviderParachainStateInfo for ProviderParachainStateInfoViaProviderPallet +where + T: pallet_dip_provider::Config, +{ + type BlockNumber = T::BlockNumber; + type Commitment = T::IdentityCommitment; + type Hasher = T::Hashing; + type Identifier = T::Identifier; + type Key = StorageKey; + + fn dip_subject_storage_key(identifier: &Self::Identifier) -> Self::Key { + StorageKey(pallet_dip_provider::IdentityCommitments::::hashed_key_for( + identifier, + )) + } +} + pub trait DidSignatureVerifierContext { const SIGNATURE_VALIDITY: u16; @@ -109,3 +132,29 @@ where fn signed_extra() -> Self::SignedExtra {} } + +pub trait HistoricalBlockRegistry { + type BlockNumber; + type Hasher: sp_runtime::traits::Hash; + + fn block_hash_for(block: &Self::BlockNumber) -> Option>; +} + +impl HistoricalBlockRegistry for T +where + T: frame_system::Config, +{ + type BlockNumber = T::BlockNumber; + type Hasher = T::Hashing; + + fn block_hash_for(block: &Self::BlockNumber) -> Option> { + let retrieved_block = frame_system::Pallet::::block_hash(block); + let default_block_hash_value = ::default(); + + if retrieved_block == default_block_hash_value { + None + } else { + Some(retrieved_block) + } + } +} diff --git a/dip-template/nodes/dip-consumer/src/chain_spec.rs b/dip-template/nodes/dip-consumer/src/chain_spec.rs index d80daa51d2..bfc123f067 100644 --- a/dip-template/nodes/dip-consumer/src/chain_spec.rs +++ b/dip-template/nodes/dip-consumer/src/chain_spec.rs @@ -99,7 +99,6 @@ fn testnet_genesis( }, aura: Default::default(), aura_ext: Default::default(), - did_lookup: Default::default(), } } diff --git a/dip-template/pallets/pallet-postit/Cargo.toml b/dip-template/pallets/pallet-postit/Cargo.toml new file mode 100644 index 0000000000..dbfc82136b --- /dev/null +++ b/dip-template/pallets/pallet-postit/Cargo.toml @@ -0,0 +1,40 @@ +[package] +authors.workspace = true +documentation.workspace = true +edition.workspace = true +homepage.workspace = true +license-file.workspace = true +readme.workspace = true +repository.workspace = true +version.workspace = true +name = "pallet-postit" +description = "Simple pallet to store on-chain comments, replies, and likes." + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +# External dependencies +parity-scale-codec = {workspace = true, features = ["derive"]} +scale-info = {workspace = true, features = ["derive"]} + +#External dependencies +frame-support.workspace = true +frame-system.workspace = true +sp-runtime.workspace = true +sp-std.workspace = true + +[features] +default = ["std"] +runtime-benchmarks = [ + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks" +] +std = [ + "parity-scale-codec/std", + "scale-info/std", + "frame-support/std", + "frame-system/std", + "sp-runtime/std", + "sp-std/std", +] diff --git a/dip-template/pallets/pallet-postit/src/lib.rs b/dip-template/pallets/pallet-postit/src/lib.rs new file mode 100644 index 0000000000..170797f61e --- /dev/null +++ b/dip-template/pallets/pallet-postit/src/lib.rs @@ -0,0 +1,185 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +#![cfg_attr(not(feature = "std"), no_std)] + +pub mod post; +pub mod traits; + +pub use pallet::*; + +#[frame_support::pallet(dev_mode)] +pub mod pallet { + + use super::*; + + use frame_support::{ + pallet_prelude::{DispatchResult, *}, + traits::EnsureOrigin, + BoundedVec, + }; + use frame_system::pallet_prelude::*; + use sp_runtime::traits::Hash; + use sp_std::fmt::Debug; + + use crate::{ + post::{Comment, Post}, + traits::Usernamable, + }; + + const STORAGE_VERSION: StorageVersion = StorageVersion::new(0); + + pub type BoundedTextOf = BoundedVec::MaxTextLength>; + pub type PostOf = Post<::Hash, BoundedTextOf, ::Username>; + pub type CommentOf = Comment<::Hash, BoundedTextOf, ::Username>; + + #[pallet::config] + pub trait Config: frame_system::Config { + type MaxTextLength: Get; + type OriginCheck: EnsureOrigin<::RuntimeOrigin, Success = Self::OriginSuccess>; + type OriginSuccess: Usernamable; + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + type Username: Encode + Decode + TypeInfo + MaxEncodedLen + Clone + PartialEq + Debug + Default; + } + + #[pallet::storage] + #[pallet::getter(fn posts)] + pub type Posts = StorageMap<_, Twox64Concat, ::Hash, PostOf>; + + #[pallet::storage] + #[pallet::getter(fn comments)] + pub type Comments = StorageMap<_, Twox64Concat, ::Hash, CommentOf>; + + #[pallet::pallet] + #[pallet::storage_version(STORAGE_VERSION)] + pub struct Pallet(_); + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + NewPost { + post_id: T::Hash, + author: T::Username, + }, + NewComment { + resource_id: T::Hash, + comment_id: T::Hash, + author: T::Username, + }, + NewLike { + resource_id: T::Hash, + liker: T::Username, + }, + } + + #[pallet::call] + impl Pallet { + #[pallet::call_index(0)] + #[pallet::weight(1_000)] + pub fn post(origin: OriginFor, text: BoundedTextOf) -> DispatchResult { + let success_origin = T::OriginCheck::ensure_origin(origin)?; + let author = success_origin.username().map_err(DispatchError::Other)?; + let post_id = T::Hashing::hash( + (&frame_system::Pallet::::block_number(), &author, &text) + .encode() + .as_slice(), + ); + let post = PostOf::::from_text_and_author(text, author.clone()); + Posts::::insert(post_id, post); + Self::deposit_event(Event::NewPost { post_id, author }); + Ok(()) + } + + #[pallet::call_index(1)] + #[pallet::weight(1_000)] + pub fn comment(origin: OriginFor, resource_id: T::Hash, text: BoundedTextOf) -> DispatchResult { + let success_origin = T::OriginCheck::ensure_origin(origin)?; + let author = success_origin.username().map_err(DispatchError::Other)?; + let comment_id = T::Hashing::hash( + (&frame_system::Pallet::::block_number(), &author, &text) + .encode() + .as_slice(), + ); + Posts::::try_mutate(resource_id, |post| { + if let Some(post) = post { + post.comments + .try_push(comment_id) + .expect("Failed to add comment to post."); + Ok(()) + } else { + Err(()) + } + }) + .or_else(|_| { + Comments::::try_mutate(resource_id, |comment| { + if let Some(comment) = comment { + comment + .details + .comments + .try_push(comment_id) + .expect("Failed to add comment to comment."); + Ok(()) + } else { + Err(()) + } + }) + }) + .map_err(|_| DispatchError::Other("No post or comment with provided ID found."))?; + let comment = CommentOf::::from_post_id_text_and_author(resource_id, text, author.clone()); + Comments::::insert(comment_id, comment); + Self::deposit_event(Event::NewComment { + resource_id, + comment_id, + author, + }); + Ok(()) + } + + #[pallet::call_index(2)] + #[pallet::weight(1_000)] + pub fn like(origin: OriginFor, resource_id: T::Hash) -> DispatchResult { + let success_origin = T::OriginCheck::ensure_origin(origin)?; + let liker = success_origin.username().map_err(DispatchError::Other)?; + Posts::::try_mutate(resource_id, |post| { + if let Some(post) = post { + post.likes.try_push(liker.clone()).expect("Failed to add like to post."); + Ok(()) + } else { + Err(()) + } + }) + .or_else(|_| { + Comments::::try_mutate(resource_id, |comment| { + if let Some(comment) = comment { + comment + .details + .likes + .try_push(liker.clone()) + .expect("Failed to add like to comment."); + Ok(()) + } else { + Err(()) + } + }) + }) + .map_err(|_| DispatchError::Other("No post or comment with provided ID found."))?; + Self::deposit_event(Event::NewLike { resource_id, liker }); + Ok(()) + } + } +} diff --git a/dip-template/pallets/pallet-postit/src/post.rs b/dip-template/pallets/pallet-postit/src/post.rs new file mode 100644 index 0000000000..49fd158fc9 --- /dev/null +++ b/dip-template/pallets/pallet-postit/src/post.rs @@ -0,0 +1,55 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +use frame_support::{traits::ConstU32, BoundedVec}; +use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; +use scale_info::TypeInfo; + +#[derive(Encode, Decode, TypeInfo, MaxEncodedLen, Default)] +pub struct Post { + pub author: Username, + pub text: Text, + pub likes: BoundedVec>, + pub comments: BoundedVec>, +} + +impl Post { + pub(crate) fn from_text_and_author(text: Text, author: Username) -> Self { + Self { + text, + author, + likes: BoundedVec::default(), + comments: BoundedVec::default(), + } + } +} + +#[derive(Encode, Decode, TypeInfo, MaxEncodedLen, Default)] +pub struct Comment { + pub details: Post, + pub in_response_to: Id, +} + +impl Comment { + pub(crate) fn from_post_id_text_and_author(in_response_to: Id, text: Text, author: Username) -> Self { + Self { + in_response_to, + details: Post::from_text_and_author(text, author), + } + } +} diff --git a/dip-template/pallets/pallet-postit/src/traits.rs b/dip-template/pallets/pallet-postit/src/traits.rs new file mode 100644 index 0000000000..8a1d20f580 --- /dev/null +++ b/dip-template/pallets/pallet-postit/src/traits.rs @@ -0,0 +1,23 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +pub trait Usernamable { + type Username; + + fn username(&self) -> Result; +} diff --git a/dip-template/runtimes/dip-consumer/Cargo.toml b/dip-template/runtimes/dip-consumer/Cargo.toml index 578eeff8a0..aae167b098 100644 --- a/dip-template/runtimes/dip-consumer/Cargo.toml +++ b/dip-template/runtimes/dip-consumer/Cargo.toml @@ -23,6 +23,7 @@ did.workspace = true kilt-dip-support.workspace = true pallet-did-lookup.workspace = true pallet-dip-consumer.workspace = true +pallet-postit.workspace = true pallet-relay-store.workspace = true runtime-common.workspace = true @@ -75,6 +76,7 @@ std = [ "kilt-dip-support/std", "pallet-did-lookup/std", "pallet-dip-consumer/std", + "pallet-postit/std", "pallet-relay-store/std", "runtime-common/std", "frame-executive/std", diff --git a/dip-template/runtimes/dip-consumer/src/dip.rs b/dip-template/runtimes/dip-consumer/src/dip.rs index 78d25919df..11b355dd7f 100644 --- a/dip-template/runtimes/dip-consumer/src/dip.rs +++ b/dip-template/runtimes/dip-consumer/src/dip.rs @@ -20,8 +20,8 @@ use did::{did_details::DidVerificationKey, DidVerificationKeyRelationship, KeyId use dip_provider_runtime_template::{Runtime as ProviderRuntime, Web3Name}; use frame_support::traits::Contains; use kilt_dip_support::{ - traits::{DipCallOriginFilter, FrameSystemDidSignatureContext}, - DipSiblingProviderStateProofVerifier, KiltDipCommitmentsForDipProviderPallet, RococoStateRootsViaRelayStorePallet, + traits::{DipCallOriginFilter, FrameSystemDidSignatureContext, ProviderParachainStateInfoViaProviderPallet}, + DipSiblingProviderStateProofVerifier, RococoStateRootsViaRelayStorePallet, }; use pallet_did_lookup::linkable_account::LinkableAccountId; use pallet_dip_consumer::traits::IdentityProofVerifier; @@ -30,10 +30,12 @@ use sp_runtime::traits::BlakeTwo256; use crate::{AccountId, DidIdentifier, Runtime, RuntimeCall, RuntimeOrigin}; +pub type MerkleProofVerifierOutputOf = + >::VerificationResult; pub type ProofVerifier = DipSiblingProviderStateProofVerifier< RococoStateRootsViaRelayStorePallet, ConstU32<2_000>, - KiltDipCommitmentsForDipProviderPallet, + ProviderParachainStateInfoViaProviderPallet, AccountId, BlakeTwo256, KeyIdOf, @@ -63,7 +65,7 @@ impl Contains for PreliminaryDipOriginFilter { fn contains(t: &RuntimeCall) -> bool { matches!( t, - RuntimeCall::DidLookup { .. } + RuntimeCall::PostIt { .. } | RuntimeCall::Utility(pallet_utility::Call::batch { .. }) | RuntimeCall::Utility(pallet_utility::Call::batch_all { .. }) | RuntimeCall::Utility(pallet_utility::Call::force_batch { .. }) @@ -73,7 +75,7 @@ impl Contains for PreliminaryDipOriginFilter { fn derive_verification_key_relationship(call: &RuntimeCall) -> Option { match call { - RuntimeCall::DidLookup { .. } => Some(DidVerificationKeyRelationship::Authentication), + RuntimeCall::PostIt { .. } => Some(DidVerificationKeyRelationship::Authentication), RuntimeCall::Utility(pallet_utility::Call::batch { calls }) => single_key_relationship(calls.iter()).ok(), RuntimeCall::Utility(pallet_utility::Call::batch_all { calls }) => single_key_relationship(calls.iter()).ok(), RuntimeCall::Utility(pallet_utility::Call::force_batch { calls }) => single_key_relationship(calls.iter()).ok(), @@ -121,47 +123,6 @@ impl DipCallOriginFilter for DipCallFilter { } } -#[cfg(test)] -mod dip_call_origin_filter_tests { - use super::*; - - use frame_support::assert_err; - - #[test] - fn test_key_relationship_derivation() { - // Can call DidLookup functions with an authentication key - let did_lookup_call = RuntimeCall::DidLookup(pallet_did_lookup::Call::associate_sender {}); - assert_eq!( - single_key_relationship(vec![did_lookup_call].iter()), - Ok(DidVerificationKeyRelationship::Authentication) - ); - // Can't call System functions with a DID key (hence a DIP origin) - let system_call = RuntimeCall::System(frame_system::Call::remark { remark: vec![] }); - assert_err!(single_key_relationship(vec![system_call].iter()), ()); - // Can't call empty batch with a DID key - let empty_batch_call = RuntimeCall::Utility(pallet_utility::Call::batch_all { calls: vec![] }); - assert_err!(single_key_relationship(vec![empty_batch_call].iter()), ()); - // Can call batch with a DipLookup with an authentication key - let did_lookup_batch_call = RuntimeCall::Utility(pallet_utility::Call::batch_all { - calls: vec![pallet_did_lookup::Call::associate_sender {}.into()], - }); - assert_eq!( - single_key_relationship(vec![did_lookup_batch_call].iter()), - Ok(DidVerificationKeyRelationship::Authentication) - ); - // Can't call a batch with different required keys - let did_lookup_batch_call = RuntimeCall::Utility(pallet_utility::Call::batch_all { - calls: vec![ - // Authentication key - pallet_did_lookup::Call::associate_sender {}.into(), - // No key - frame_system::Call::remark { remark: vec![] }.into(), - ], - }); - assert_err!(single_key_relationship(vec![did_lookup_batch_call].iter()), ()); - } -} - impl pallet_relay_store::Config for Runtime { type MaxRelayBlocksStored = ConstU32<100>; } diff --git a/dip-template/runtimes/dip-consumer/src/lib.rs b/dip-template/runtimes/dip-consumer/src/lib.rs index 2aa417ea22..5a0c38bbd7 100644 --- a/dip-template/runtimes/dip-consumer/src/lib.rs +++ b/dip-template/runtimes/dip-consumer/src/lib.rs @@ -22,10 +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::RevealedDidMerkleProofLeaves; -use pallet_did_lookup::linkable_account::LinkableAccountId; pub use sp_consensus_aura::sr25519::AuthorityId as AuraId; pub use sp_runtime::{MultiAddress, Perbill, Permill}; @@ -51,7 +48,6 @@ use frame_system::{ }; use pallet_balances::AccountData; use pallet_collator_selection::IdentityCollator; -use pallet_dip_consumer::{DipOrigin, EnsureDipOrigin}; use pallet_session::{FindAccountFromAuthorIndex, PeriodicSessions}; use pallet_transaction_payment::{CurrencyAdapter, FeeDetails, RuntimeDispatchInfo}; use sp_api::impl_runtime_apis; @@ -68,7 +64,8 @@ use sp_std::{prelude::*, time::Duration}; use sp_version::RuntimeVersion; mod dip; -pub use crate::dip::*; +mod origin_adapter; +pub use crate::{dip::*, origin_adapter::*}; #[cfg(any(feature = "std", test))] pub use sp_runtime::BuildStorage; @@ -135,8 +132,8 @@ construct_runtime!( Aura: pallet_aura = 23, AuraExt: cumulus_pallet_aura_ext = 24, - // DID lookup - DidLookup: pallet_did_lookup = 30, + // PostIt + PostIt: pallet_postit = 30, // DIP DipConsumer: pallet_dip_consumer = 40, @@ -356,27 +353,12 @@ impl pallet_aura::Config for Runtime { impl cumulus_pallet_aura_ext::Config for Runtime {} -parameter_types! { - pub const LinkDeposit: Balance = UNIT; -} - -impl pallet_did_lookup::Config for Runtime { - type Currency = Balances; - type Deposit = ConstU128; - type DidIdentifier = DidIdentifier; - type EnsureOrigin = EnsureDipOrigin< - DidIdentifier, - AccountId, - RevealedDidMerkleProofLeaves, BlockNumber, Web3Name, LinkableAccountId, 10, 10>, - >; - type OriginSuccess = DipOrigin< - DidIdentifier, - AccountId, - RevealedDidMerkleProofLeaves, BlockNumber, Web3Name, LinkableAccountId, 10, 10>, - >; +impl pallet_postit::Config for Runtime { + type MaxTextLength = ConstU32<160>; + type OriginCheck = EnsureDipOriginAdapter; + type OriginSuccess = DipOriginAdapter; type RuntimeEvent = RuntimeEvent; - type RuntimeHoldReason = RuntimeHoldReason; - type WeightInfo = (); + type Username = Web3Name; } impl_runtime_apis! { diff --git a/dip-template/runtimes/dip-consumer/src/origin_adapter.rs b/dip-template/runtimes/dip-consumer/src/origin_adapter.rs new file mode 100644 index 0000000000..afb428e509 --- /dev/null +++ b/dip-template/runtimes/dip-consumer/src/origin_adapter.rs @@ -0,0 +1,53 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +use crate::{AccountId, DidIdentifier, MerkleProofVerifierOutputOf, RuntimeCall, RuntimeOrigin, Web3Name}; +use frame_support::traits::EnsureOrigin; +use pallet_dip_consumer::{DipOrigin, EnsureDipOrigin}; +use pallet_postit::traits::Usernamable; +use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; +use scale_info::TypeInfo; +use sp_core::RuntimeDebug; + +pub struct EnsureDipOriginAdapter; + +impl EnsureOrigin for EnsureDipOriginAdapter { + type Success = DipOriginAdapter; + + fn try_origin(o: RuntimeOrigin) -> Result { + EnsureDipOrigin::try_origin(o).map(DipOriginAdapter) + } +} + +#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)] +pub struct DipOriginAdapter( + DipOrigin>, +); + +impl Usernamable for DipOriginAdapter { + type Username = Web3Name; + + fn username(&self) -> Result { + self.0 + .details + .web3_name + .as_ref() + .map(|leaf| leaf.web3_name.clone()) + .ok_or("No username for the subject.") + } +} diff --git a/dip-template/runtimes/dip-provider/src/lib.rs b/dip-template/runtimes/dip-provider/src/lib.rs index 010f9d9186..f8b97a98ec 100644 --- a/dip-template/runtimes/dip-provider/src/lib.rs +++ b/dip-template/runtimes/dip-provider/src/lib.rs @@ -188,7 +188,8 @@ register_validate_block! { CheckInherents = CheckInherents, } -pub const SS58_PREFIX: u16 = 100; +// Same as official KILT prefix. +pub const SS58_PREFIX: u16 = 38; const AVERAGE_ON_INITIALIZE_RATIO: Perbill = Perbill::from_percent(5); const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); const MAXIMUM_BLOCK_WEIGHT: Weight = Weight::from_parts( From 9d36356a2ef8132cd9436c110d1f1a6c58c2eeee Mon Sep 17 00:00:00 2001 From: Antonio Date: Wed, 20 Sep 2023 14:09:23 +0100 Subject: [PATCH 32/32] feat: add relaychain support (#563) Minor renaming of few things, that came up when working on the Sub0 2023 demo. --- crates/kilt-dip-support/src/lib.rs | 58 +++++++++---------- .../dip-consumer/src/origin_adapter.rs | 6 ++ 2 files changed, 34 insertions(+), 30 deletions(-) diff --git a/crates/kilt-dip-support/src/lib.rs b/crates/kilt-dip-support/src/lib.rs index b19daada83..c14037fd3b 100644 --- a/crates/kilt-dip-support/src/lib.rs +++ b/crates/kilt-dip-support/src/lib.rs @@ -56,11 +56,11 @@ pub struct SiblingParachainDipStateProof< RelayBlockHeight, DipMerkleProofBlindedValues, DipMerkleProofRevealedLeaf, - DipProviderBlockNumber, + LocalBlockNumber, > { para_state_root: ParachainRootStateProof, dip_identity_commitment: Vec>, - did: DipMerkleProofAndDidSignature, + did: DipMerkleProofAndDidSignature, } #[derive(Encode, Decode, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug, TypeInfo, Clone)] @@ -250,22 +250,21 @@ impl< #[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)] pub struct ChildParachainDipStateProof< - RelayBlockHeight: Copy + Into + TryFrom, - RelayBlockHasher: Hash, + ParentBlockHeight: Copy + Into + TryFrom, + ParentBlockHasher: Hash, DipMerkleProofBlindedValues, DipMerkleProofRevealedLeaf, - DipProviderBlockNumber, > { - para_state_root: ParachainRootStateProof, - relay_header: Header, + para_state_root: ParachainRootStateProof, + relay_header: Header, dip_identity_commitment: Vec>, - did: DipMerkleProofAndDidSignature, + did: DipMerkleProofAndDidSignature, } pub struct DipChildProviderStateProofVerifier< RelayChainInfo, - SiblingProviderParachainId, - SiblingProviderStateInfo, + ChildProviderParachainId, + ChildProviderStateInfo, TxSubmitter, ProviderDipMerkleHasher, ProviderDidKeyId, @@ -280,8 +279,8 @@ pub struct DipChildProviderStateProofVerifier< #[allow(clippy::type_complexity)] PhantomData<( RelayChainInfo, - SiblingProviderParachainId, - SiblingProviderStateInfo, + ChildProviderParachainId, + ChildProviderStateInfo, TxSubmitter, ProviderDipMerkleHasher, ProviderDidKeyId, @@ -297,8 +296,8 @@ impl< Call, Subject, RelayChainInfo, - SiblingProviderParachainId, - SiblingProviderStateInfo, + ChildProviderParachainId, + ChildProviderStateInfo, TxSubmitter, ProviderDipMerkleHasher, ProviderDidKeyId, @@ -312,8 +311,8 @@ impl< > IdentityProofVerifier for DipChildProviderStateProofVerifier< RelayChainInfo, - SiblingProviderParachainId, - SiblingProviderStateInfo, + ChildProviderParachainId, + ChildProviderStateInfo, TxSubmitter, ProviderDipMerkleHasher, ProviderDidKeyId, @@ -346,17 +345,17 @@ impl< + Codec, RelayChainInfo::Key: AsRef<[u8]>, - SiblingProviderParachainId: Get, + ChildProviderParachainId: Get, - SiblingProviderStateInfo: - ProviderParachainStateInfo, - OutputOf: Ord + From::Hasher>>, - SiblingProviderStateInfo::BlockNumber: Encode + Clone, - SiblingProviderStateInfo::Commitment: Decode, - SiblingProviderStateInfo::Key: AsRef<[u8]>, + ChildProviderStateInfo: ProviderParachainStateInfo, + OutputOf: Ord + From::Hasher>>, + ChildProviderStateInfo::BlockNumber: Encode + Clone, + ChildProviderStateInfo::Commitment: Decode, + ChildProviderStateInfo::Key: AsRef<[u8]>, - LocalContextProvider: DidSignatureVerifierContext, - LocalContextProvider::BlockNumber: Encode + CheckedSub + From + PartialOrd, + LocalContextProvider: + DidSignatureVerifierContext::BlockNumber>, + LocalContextProvider::BlockNumber: CheckedSub + From, LocalContextProvider::Hash: Encode, LocalContextProvider::SignedExtra: Encode, LocalDidDetails: Bump + Default + Encode, @@ -375,16 +374,15 @@ impl< Vec>, RevealedDidMerkleProofLeaf< ProviderDidKeyId, - SiblingProviderStateInfo::BlockNumber, + ChildProviderStateInfo::BlockNumber, ProviderWeb3Name, ProviderLinkedAccountId, >, - LocalContextProvider::BlockNumber, >; type Submitter = TxSubmitter; type VerificationResult = RevealedDidMerkleProofLeaves< ProviderDidKeyId, - SiblingProviderStateInfo::BlockNumber, + ChildProviderStateInfo::BlockNumber, ProviderWeb3Name, ProviderLinkedAccountId, MAX_REVEALED_KEYS_COUNT, @@ -413,14 +411,14 @@ impl< // 2. Verify relay chain proof let provider_parachain_header = ParachainHeadProofVerifier::::verify_proof_for_parachain_with_root( - &SiblingProviderParachainId::get(), + &ChildProviderParachainId::get(), &state_root_at_height, proof.para_state_root.proof, )?; // 3. Verify parachain state proof. let subject_identity_commitment = - DipIdentityCommitmentProofVerifier::::verify_proof_for_identifier( + DipIdentityCommitmentProofVerifier::::verify_proof_for_identifier( subject, provider_parachain_header.state_root.into(), proof.dip_identity_commitment, diff --git a/dip-template/runtimes/dip-consumer/src/origin_adapter.rs b/dip-template/runtimes/dip-consumer/src/origin_adapter.rs index afb428e509..b9d008e5c8 100644 --- a/dip-template/runtimes/dip-consumer/src/origin_adapter.rs +++ b/dip-template/runtimes/dip-consumer/src/origin_adapter.rs @@ -32,6 +32,12 @@ impl EnsureOrigin for EnsureDipOriginAdapter { fn try_origin(o: RuntimeOrigin) -> Result { EnsureDipOrigin::try_origin(o).map(DipOriginAdapter) } + + #[cfg(feature = "runtime-benchmarks")] + fn try_successful_origin() -> Result { + // TODO: Replace with actual DIP origin upon benchmarking + Ok(RuntimeOrigin::root()) + } } #[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)]