From dfddc69cccbc55cbb6a13f5fd545203e10a2d822 Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Mon, 7 Aug 2023 16:30:35 +0200 Subject: [PATCH 01/14] Add initial logic for relaychain consumer --- crates/kilt-dip-support/src/lib.rs | 8 +++--- crates/kilt-dip-support/src/state_proofs.rs | 32 +++++++++++++++++++-- crates/kilt-dip-support/src/traits.rs | 26 +++++++++++++++++ 3 files changed, 60 insertions(+), 6 deletions(-) diff --git a/crates/kilt-dip-support/src/lib.rs b/crates/kilt-dip-support/src/lib.rs index 9e1819ed7d..176662bcc4 100644 --- a/crates/kilt-dip-support/src/lib.rs +++ b/crates/kilt-dip-support/src/lib.rs @@ -43,6 +43,10 @@ pub mod state_proofs; pub mod traits; pub mod utils; +pub use state_proofs::{ + parachain::KiltDipCommitmentsForDipProviderPallet, relay_chain::RococoStateRootsViaRelayStorePallet, +}; + #[derive(Encode, Decode, PartialEq, Eq, RuntimeDebug, TypeInfo, Clone)] pub struct SiblingParachainDipStateProof< RelayBlockHeight, @@ -241,7 +245,3 @@ impl< Ok(proof_leaves) } } - -pub use state_proofs::{ - parachain::KiltDipCommitmentsForDipProviderPallet, relay_chain::RococoStateRootsViaRelayStorePallet, -}; diff --git a/crates/kilt-dip-support/src/state_proofs.rs b/crates/kilt-dip-support/src/state_proofs.rs index 814b2b55e4..ec04f0799e 100644 --- a/crates/kilt-dip-support/src/state_proofs.rs +++ b/crates/kilt-dip-support/src/state_proofs.rs @@ -88,9 +88,11 @@ mod substrate_no_std_port { pub(super) mod relay_chain { use super::*; - use sp_runtime::traits::BlakeTwo256; + use frame_support::ensure; + use parity_scale_codec::Codec; + use sp_runtime::traits::{AtLeast32BitUnsigned, BlakeTwo256, MaybeDisplay, Member, SimpleBitOps}; - use crate::traits::RelayChainStateInfo; + use crate::traits::{self, RelayChainStateInfo}; pub struct SiblingParachainHeadProofVerifier(PhantomData); @@ -220,6 +222,32 @@ pub(super) mod relay_chain { 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 struct PastStateRootProvider(PhantomData); + + impl PastStateRootProvider + where + HistoryProvider: traits::HistoryProvider, + HistoryProvider::BlockNumber: Member + + sp_std::hash::Hash + + Copy + + MaybeDisplay + + AtLeast32BitUnsigned + + Codec + + Into + + TryFrom, + ::Output: + Default + sp_std::hash::Hash + Copy + Member + MaybeDisplay + SimpleBitOps + Codec, + { + pub fn verify_past_state( + block_number: HistoryProvider::BlockNumber, + header: Header, + ) -> Result<::Output, ()> { + let block_hash = HistoryProvider::block_hash_for(&block_number).ok_or(())?; + ensure!(block_hash == header.hash(), ()); + Ok(header.state_root) + } + } } pub(super) mod parachain { diff --git a/crates/kilt-dip-support/src/traits.rs b/crates/kilt-dip-support/src/traits.rs index ac65ed945c..1e4763d8c9 100644 --- a/crates/kilt-dip-support/src/traits.rs +++ b/crates/kilt-dip-support/src/traits.rs @@ -109,3 +109,29 @@ where fn signed_extra() -> Self::SignedExtra {} } + +pub trait HistoryProvider { + type BlockNumber; + type Hasher: sp_runtime::traits::Hash; + + fn block_hash_for(block: &Self::BlockNumber) -> Option<::Output>; +} + +impl HistoryProvider for T +where + T: frame_system::Config, +{ + type BlockNumber = T::BlockNumber; + type Hasher = T::Hashing; + + fn block_hash_for(block: &Self::BlockNumber) -> Option<::Output> { + let default_block_hash_value = ::default(); + let retrieved_block = frame_system::Pallet::::block_hash(block); + + if retrieved_block == default_block_hash_value { + None + } else { + Some(retrieved_block) + } + } +} From 759bbe86b8ac34a36355b94caba0df1dd667c035 Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Tue, 8 Aug 2023 09:34:01 +0200 Subject: [PATCH 02/14] Add unit tests for block history provider --- crates/kilt-dip-support/src/state_proofs.rs | 82 +++++++++++++++++++++ crates/kilt-dip-support/src/traits.rs | 2 +- 2 files changed, 83 insertions(+), 1 deletion(-) diff --git a/crates/kilt-dip-support/src/state_proofs.rs b/crates/kilt-dip-support/src/state_proofs.rs index ec04f0799e..882b6b06f6 100644 --- a/crates/kilt-dip-support/src/state_proofs.rs +++ b/crates/kilt-dip-support/src/state_proofs.rs @@ -248,6 +248,88 @@ pub(super) mod relay_chain { Ok(header.state_root) } } + + #[cfg(test)] + mod past_state_root_provider_tests { + use super::*; + + use hex_literal::hex; + use sp_runtime::{Digest, DigestItem}; + + use crate::traits::HistoryProvider; + + const BLOCK_NUMBER: u64 = 4_362_970; + + struct SpiritnetStaticBlockProvider; + + impl HistoryProvider for SpiritnetStaticBlockProvider { + type BlockNumber = u64; + type Hasher = BlakeTwo256; + + fn block_hash_for(block: &Self::BlockNumber) -> Option<::Output> { + if block == &BLOCK_NUMBER { + Some(hex!("b9700ad2c2cad8ba5bf1affb98c377e9ba4f28ceaecc22285f636a3971a7c3f4").into()) + } else { + None + } + } + } + + #[test] + fn test_correct_block_verification() { + let header_at_block = Header:: { + digest: Digest { + logs: vec![ + DigestItem::PreRuntime(*b"aura", hex!("9ad3660800000000").to_vec()), + DigestItem::Seal(*b"aura", hex!("066a1734615150b91a99779f770a47a47e91680cf0dbc97fea08d10b0bad19066eaccd401394589b84e346145713e98ae709fd52933871d2383640bd76c3158b").to_vec()) + ] + }, + extrinsics_root: hex!("5031bb2622631dc5da356f9023a5b751c837854de0de9af746942e7594c051f8").into(), + number: BLOCK_NUMBER, + parent_hash: hex!("bd5f86c2de02153751ebbe12986103f9b7a809fda03d4564495de83fd37280d0").into(), + state_root: hex!("5963f41159ad1ff28f6617cf9519f48a5ca9927ffa98c692d3841ab702006c4d").into() + }; + let state_root = + PastStateRootProvider::::verify_past_state(BLOCK_NUMBER, header_at_block) + .expect("State verification should not fail."); + assert_eq!( + state_root, + hex!("5963f41159ad1ff28f6617cf9519f48a5ca9927ffa98c692d3841ab702006c4d").into() + ); + } + + #[test] + fn test_invalid_block_verification() { + let invalid_header_at_block = Header:: { + digest: Digest { + logs: vec![ + DigestItem::PreRuntime(*b"aura", hex!("9ad3660800000000").to_vec()), + DigestItem::Seal(*b"aura", hex!("066a1734615150b91a99779f770a47a47e91680cf0dbc97fea08d10b0bad19066eaccd401394589b84e346145713e98ae709fd52933871d2383640bd76c3158b").to_vec()) + ] + }, + extrinsics_root: hex!("5031bb2622631dc5da356f9023a5b751c837854de0de9af746942e7594c051f8").into(), + number: BLOCK_NUMBER, + parent_hash: hex!("bd5f86c2de02153751ebbe12986103f9b7a809fda03d4564495de83fd37280d0").into(), + // Changed the last byte from 0x4d to 0x4c. + state_root: hex!("5963f41159ad1ff28f6617cf9519f48a5ca9927ffa98c692d3841ab702006c4c").into() + }; + let state_root = PastStateRootProvider::::verify_past_state( + BLOCK_NUMBER, + invalid_header_at_block, + ); + assert_eq!(state_root, Err(())); + } + + #[test] + fn test_block_not_found() { + let non_existing_block_number = 1; + let state_root = PastStateRootProvider::::verify_past_state( + non_existing_block_number, + Header::::new_from_number(non_existing_block_number), + ); + assert_eq!(state_root, Err(())); + } + } } pub(super) mod parachain { diff --git a/crates/kilt-dip-support/src/traits.rs b/crates/kilt-dip-support/src/traits.rs index 1e4763d8c9..29003f0a8b 100644 --- a/crates/kilt-dip-support/src/traits.rs +++ b/crates/kilt-dip-support/src/traits.rs @@ -125,8 +125,8 @@ where type Hasher = T::Hashing; fn block_hash_for(block: &Self::BlockNumber) -> Option<::Output> { - let default_block_hash_value = ::default(); let retrieved_block = frame_system::Pallet::::block_hash(block); + let default_block_hash_value = ::default(); if retrieved_block == default_block_hash_value { None From 8afe7919be11aa1ceb3c767339f4543ae8599aac Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Tue, 8 Aug 2023 15:45:12 +0200 Subject: [PATCH 03/14] Ongoing compilation error --- crates/kilt-dip-support/src/lib.rs | 199 +++++++++++++++++++- crates/kilt-dip-support/src/state_proofs.rs | 47 +++-- crates/kilt-dip-support/src/traits.rs | 16 +- 3 files changed, 238 insertions(+), 24 deletions(-) diff --git a/crates/kilt-dip-support/src/lib.rs b/crates/kilt-dip-support/src/lib.rs index 176662bcc4..ab44cbe2da 100644 --- a/crates/kilt-dip-support/src/lib.rs +++ b/crates/kilt-dip-support/src/lib.rs @@ -23,7 +23,10 @@ use parity_scale_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::{CheckedSub, Hash}, +}; use sp_std::{borrow::Borrow, marker::PhantomData, vec::Vec}; use ::did::{did_details::DidVerificationKey, DidVerificationKeyRelationship}; @@ -33,7 +36,7 @@ use crate::{ did::{RevealedDidKeysAndSignature, RevealedDidKeysSignatureAndCallVerifier, TimeBoundDidSignature}, merkle::{DidMerkleProof, DidMerkleProofVerifier, RevealedDidMerkleProofLeaf, RevealedDidMerkleProofLeaves}, state_proofs::{parachain::DipIdentityCommitmentProofVerifier, relay_chain::SiblingParachainHeadProofVerifier}, - traits::{Bump, DidSignatureVerifierContext, DipCallOriginFilter}, + traits::{Bump, DidSignatureVerifierContext, DipCallOriginFilter, RelayChainStorageInfo}, utils::OutputOf, }; @@ -54,13 +57,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>, } @@ -137,7 +140,7 @@ impl< Call: Encode, TxSubmitter: Encode, - RelayChainStateInfo: traits::RelayChainStateInfo, + RelayChainStateInfo: traits::RelayChainStorageInfo + traits::RelayChainStateInfo, RelayChainStateInfo::Hasher: 'static, OutputOf: Ord, RelayChainStateInfo::BlockNumber: Copy + Into + TryFrom + HasCompact, @@ -245,3 +248,189 @@ impl< Ok(proof_leaves) } } + +pub struct ChildParachainDipStateProof< + RelayBlockHeight: Copy + Into + TryFrom, + RelayBlockHasher: Hash, + DipMerkleProofBlindedValues, + DipMerkleProofRevealedLeaf, + DipProviderBlockNumber, +> { + para_state_root: ParachainRootStateProof, + header: Header, + dip_identity_commitment: Vec>, + did: DipMerkleProofAndDidSignature, +} + +pub struct DipChildProviderStateProofVerifier< + RelayChainStateInfo, + 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<( + RelayChainStateInfo, + SiblingProviderParachainId, + SiblingProviderStateInfo, + TxSubmitter, + ProviderDipMerkleHasher, + ProviderDidKeyId, + ProviderWeb3Name, + ProviderLinkedAccountId, + LocalDidDetails, + LocalContextProvider, + LocalDidCallVerifier, + )>, +); + +impl< + Call, + Subject, + RelayChainStateInfo, + 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< + RelayChainStateInfo, + SiblingProviderParachainId, + SiblingProviderStateInfo, + TxSubmitter, + ProviderDipMerkleHasher, + ProviderDidKeyId, + ProviderWeb3Name, + ProviderLinkedAccountId, + MAX_REVEALED_KEYS_COUNT, + MAX_REVEALED_ACCOUNTS_COUNT, + LocalDidDetails, + LocalContextProvider, + LocalDidCallVerifier, + > where + Call: Encode, + TxSubmitter: Encode, + + RelayChainStateInfo: traits::RelayChainStorageInfo + traits::HistoryProvider, + RelayChainStateInfo::Hasher: 'static, + OutputOf: Ord, + RelayChainStateInfo::BlockNumber: Copy + Into + TryFrom + HasCompact, + RelayChainStateInfo::Key: AsRef<[u8]>, + + SiblingProviderParachainId: Get, + + 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 + 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< + RelayChainStateInfo::BlockNumber, + RelayChainStateInfo::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 proof block hash from provider + let state_root_at_block = + RelayChainStateInfo::block_hash_for(&proof.para_state_root.relay_block_height).ok_or(())?; + + struct StaticRootProvider(PhantomData<(BlockNumber, Hasher, StorageInfo)>); + + impl traits::RelayChainStorageInfo + for StaticRootProvider + where + StorageInfo: RelayChainStorageInfo, + { + type Key = StorageInfo::Key; + type ParaId = StorageInfo::ParaId; + + fn parachain_head_storage_key(para_id: &Self::ParaId) -> Self::Key { + StorageInfo::parachain_head_storage_key(para_id) + } + } + impl traits::RelayChainStateInfo + for StaticRootProvider + where + Hasher: Hash, + { + type BlockNumber = BlockNumber; + type Hasher = Hasher; + type LookupInfo = OutputOf; + + fn state_root_for_block( + _block_height: &Self::BlockNumber, + lookup_info: &Self::LookupInfo, + ) -> Option> { + Some(*lookup_info) + } + } + + // FIXME: Compilation error + // 2. Verify relay chain proof + let provider_parachain_header = SiblingParachainHeadProofVerifier::< + StaticRootProvider, + >::verify_proof_for_parachain( + &SiblingProviderParachainId::get(), + &proof.para_state_root.relay_block_height, + proof.para_state_root.proof, + )?; + Err(()) + } +} diff --git a/crates/kilt-dip-support/src/state_proofs.rs b/crates/kilt-dip-support/src/state_proofs.rs index 882b6b06f6..149ad1d725 100644 --- a/crates/kilt-dip-support/src/state_proofs.rs +++ b/crates/kilt-dip-support/src/state_proofs.rs @@ -92,13 +92,13 @@ pub(super) mod relay_chain { use parity_scale_codec::Codec; use sp_runtime::traits::{AtLeast32BitUnsigned, BlakeTwo256, MaybeDisplay, Member, SimpleBitOps}; - use crate::traits::{self, RelayChainStateInfo}; + use crate::traits::{self, RelayChainStateInfo, RelayChainStorageInfo}; pub struct SiblingParachainHeadProofVerifier(PhantomData); impl SiblingParachainHeadProofVerifier where - RelayChainState: RelayChainStateInfo, + RelayChainState: RelayChainStorageInfo + RelayChainStateInfo, RelayChainState::Hasher: 'static, OutputOf: Ord, RelayChainState::BlockNumber: Copy + Into + TryFrom + HasCompact, @@ -110,7 +110,7 @@ pub(super) mod relay_chain { relay_height: &RelayChainState::BlockNumber, proof: impl IntoIterator>, ) -> Result, ()> { - let relay_state_root = RelayChainState::state_root_for_block(relay_height).ok_or(())?; + 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::( @@ -133,20 +133,13 @@ pub(super) mod relay_chain { pub struct RococoStateRootsViaRelayStorePallet(PhantomData); - impl RelayChainStateInfo for RococoStateRootsViaRelayStorePallet + impl RelayChainStorageInfo for RococoStateRootsViaRelayStorePallet 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(); @@ -160,6 +153,23 @@ pub(super) mod relay_chain { } } + impl RelayChainStateInfo for RococoStateRootsViaRelayStorePallet + where + Runtime: pallet_relay_store::Config, + { + type BlockNumber = u32; + type Hasher = BlakeTwo256; + type LookupInfo = (); + + fn state_root_for_block( + block_height: &Self::BlockNumber, + _lookup_info: &Self::LookupInfo, + ) -> 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::*; @@ -171,9 +181,7 @@ pub(super) mod relay_chain { // hash 0x18e90e9aa8e3b063f60386ba1b0415111798e72d01de58b1438d620d42f58e39 struct StaticPolkadotInfoProvider; - impl RelayChainStateInfo for StaticPolkadotInfoProvider { - type BlockNumber = u32; - type Hasher = BlakeTwo256; + impl RelayChainStorageInfo for StaticPolkadotInfoProvider { type Key = StorageKey; type ParaId = u32; @@ -190,8 +198,17 @@ pub(super) mod relay_chain { .concat(); StorageKey(storage_key) } + } + + impl RelayChainStateInfo for StaticPolkadotInfoProvider { + type BlockNumber = u32; + type Hasher = BlakeTwo256; + type LookupInfo = (); - fn state_root_for_block(_block_height: &Self::BlockNumber) -> Option> { + fn state_root_for_block( + _block_height: &Self::BlockNumber, + _lookup_info: &Self::LookupInfo, + ) -> Option> { Some(hex!("81b75d95075d16005ee0a987a3f061d3011ada919b261e9b02961b9b3725f3fd").into()) } } diff --git a/crates/kilt-dip-support/src/traits.rs b/crates/kilt-dip-support/src/traits.rs index 29003f0a8b..b9a015271d 100644 --- a/crates/kilt-dip-support/src/traits.rs +++ b/crates/kilt-dip-support/src/traits.rs @@ -54,16 +54,24 @@ pub trait DipCallOriginFilter { fn check_call_origin_info(call: &Call, info: &Self::OriginInfo) -> Result; } -pub trait RelayChainStateInfo { - type BlockNumber; +pub trait RelayChainStorageInfo { type Key; - type Hasher: sp_runtime::traits::Hash; 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 { + type BlockNumber; + type Hasher: sp_runtime::traits::Hash; + type LookupInfo; + + fn state_root_for_block( + block_height: &Self::BlockNumber, + lookup_info: &Self::LookupInfo, + ) -> Option>; +} + pub trait ProviderParachainStateInfo { type BlockNumber; type Commitment; From 48b8a0d273957497ce8d6fd2a8e49e6d4a07b24e Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Tue, 8 Aug 2023 16:56:57 +0200 Subject: [PATCH 04/14] Compilation ok --- crates/kilt-dip-support/src/lib.rs | 149 ++++++++++++-------- crates/kilt-dip-support/src/state_proofs.rs | 147 +++---------------- crates/kilt-dip-support/src/traits.rs | 6 +- 3 files changed, 108 insertions(+), 194 deletions(-) diff --git a/crates/kilt-dip-support/src/lib.rs b/crates/kilt-dip-support/src/lib.rs index ab44cbe2da..49cb6b732b 100644 --- a/crates/kilt-dip-support/src/lib.rs +++ b/crates/kilt-dip-support/src/lib.rs @@ -20,12 +20,12 @@ #![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::{ generic::Header, - traits::{CheckedSub, Hash}, + traits::{AtLeast32BitUnsigned, CheckedSub, Hash, MaybeDisplay, Member, SimpleBitOps}, }; use sp_std::{borrow::Borrow, marker::PhantomData, vec::Vec}; @@ -36,7 +36,10 @@ use crate::{ did::{RevealedDidKeysAndSignature, RevealedDidKeysSignatureAndCallVerifier, TimeBoundDidSignature}, merkle::{DidMerkleProof, DidMerkleProofVerifier, RevealedDidMerkleProofLeaf, RevealedDidMerkleProofLeaves}, state_proofs::{parachain::DipIdentityCommitmentProofVerifier, relay_chain::SiblingParachainHeadProofVerifier}, - traits::{Bump, DidSignatureVerifierContext, DipCallOriginFilter, RelayChainStorageInfo}, + traits::{ + Bump, DidSignatureVerifierContext, DipCallOriginFilter, HistoryProvider, ProviderParachainStateInfo, + RelayChainStateInfo, RelayChainStorageInfo, + }, utils::OutputOf, }; @@ -140,7 +143,7 @@ impl< Call: Encode, TxSubmitter: Encode, - RelayChainStateInfo: traits::RelayChainStorageInfo + traits::RelayChainStateInfo, + RelayChainStateInfo: traits::RelayChainStorageInfo + traits::RelayChainStateInfo, RelayChainStateInfo::Hasher: 'static, OutputOf: Ord, RelayChainStateInfo::BlockNumber: Copy + Into + TryFrom + HasCompact, @@ -263,7 +266,7 @@ pub struct ChildParachainDipStateProof< } pub struct DipChildProviderStateProofVerifier< - RelayChainStateInfo, + RelayChainInfo, SiblingProviderParachainId, SiblingProviderStateInfo, TxSubmitter, @@ -279,7 +282,7 @@ pub struct DipChildProviderStateProofVerifier< >( #[allow(clippy::type_complexity)] PhantomData<( - RelayChainStateInfo, + RelayChainInfo, SiblingProviderParachainId, SiblingProviderStateInfo, TxSubmitter, @@ -296,7 +299,7 @@ pub struct DipChildProviderStateProofVerifier< impl< Call, Subject, - RelayChainStateInfo, + RelayChainInfo, SiblingProviderParachainId, SiblingProviderStateInfo, TxSubmitter, @@ -311,7 +314,7 @@ impl< LocalDidCallVerifier, > IdentityProofVerifier for DipChildProviderStateProofVerifier< - RelayChainStateInfo, + RelayChainInfo, SiblingProviderParachainId, SiblingProviderStateInfo, TxSubmitter, @@ -328,18 +331,32 @@ impl< Call: Encode, TxSubmitter: Encode, - RelayChainStateInfo: traits::RelayChainStorageInfo + traits::HistoryProvider, - RelayChainStateInfo::Hasher: 'static, - OutputOf: Ord, - RelayChainStateInfo::BlockNumber: Copy + Into + TryFrom + HasCompact, - RelayChainStateInfo::Key: AsRef<[u8]>, - - SiblingProviderParachainId: Get, + RelayChainInfo: RelayChainStorageInfo + + RelayChainStateInfo + + HistoryProvider< + BlockNumber = ::BlockNumber, + Hasher = ::Hasher, + >, + ::Hasher: 'static, + 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: - traits::ProviderParachainStateInfo, + ProviderParachainStateInfo, SiblingProviderStateInfo::Hasher: 'static, - OutputOf: Ord + From>, + OutputOf: Ord + From::Hasher>>, SiblingProviderStateInfo::BlockNumber: Encode + Clone, SiblingProviderStateInfo::Commitment: Decode, SiblingProviderStateInfo::Key: AsRef<[u8]>, @@ -359,8 +376,8 @@ impl< type Error = (); type IdentityDetails = LocalDidDetails; type Proof = ChildParachainDipStateProof< - RelayChainStateInfo::BlockNumber, - RelayChainStateInfo::Hasher, + ::BlockNumber, + ::Hasher, Vec>, RevealedDidMerkleProofLeaf< ProviderDidKeyId, @@ -387,50 +404,64 @@ impl< identity_details: &mut Option, proof: Self::Proof, ) -> Result { - // 1. Retrieve proof block hash from provider - let state_root_at_block = - RelayChainStateInfo::block_hash_for(&proof.para_state_root.relay_block_height).ok_or(())?; - - struct StaticRootProvider(PhantomData<(BlockNumber, Hasher, StorageInfo)>); - - impl traits::RelayChainStorageInfo - for StaticRootProvider - where - StorageInfo: RelayChainStorageInfo, - { - type Key = StorageInfo::Key; - type ParaId = StorageInfo::ParaId; - - fn parachain_head_storage_key(para_id: &Self::ParaId) -> Self::Key { - StorageInfo::parachain_head_storage_key(para_id) - } - } - impl traits::RelayChainStateInfo - for StaticRootProvider - where - Hasher: Hash, - { - type BlockNumber = BlockNumber; - type Hasher = Hasher; - type LookupInfo = OutputOf; - - fn state_root_for_block( - _block_height: &Self::BlockNumber, - lookup_info: &Self::LookupInfo, - ) -> Option> { - Some(*lookup_info) - } + // 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.header.hash() { + return Err(()); } + // 1.2 If so, extract the state root from the header + let state_root_at_height = proof.header.state_root; // FIXME: Compilation error // 2. Verify relay chain proof - let provider_parachain_header = SiblingParachainHeadProofVerifier::< - StaticRootProvider, - >::verify_proof_for_parachain( - &SiblingProviderParachainId::get(), - &proof.para_state_root.relay_block_height, - proof.para_state_root.proof, + let provider_parachain_header = + SiblingParachainHeadProofVerifier::::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, + }, )?; - Err(()) + Ok(proof_leaves) } } diff --git a/crates/kilt-dip-support/src/state_proofs.rs b/crates/kilt-dip-support/src/state_proofs.rs index 149ad1d725..5cee2fa468 100644 --- a/crates/kilt-dip-support/src/state_proofs.rs +++ b/crates/kilt-dip-support/src/state_proofs.rs @@ -88,17 +88,15 @@ mod substrate_no_std_port { pub(super) mod relay_chain { use super::*; - use frame_support::ensure; - use parity_scale_codec::Codec; - use sp_runtime::traits::{AtLeast32BitUnsigned, BlakeTwo256, MaybeDisplay, Member, SimpleBitOps}; + use sp_runtime::traits::BlakeTwo256; - use crate::traits::{self, RelayChainStateInfo, RelayChainStorageInfo}; + use crate::traits::{RelayChainStateInfo, RelayChainStorageInfo}; pub struct SiblingParachainHeadProofVerifier(PhantomData); impl SiblingParachainHeadProofVerifier where - RelayChainState: RelayChainStorageInfo + RelayChainStateInfo, + RelayChainState: RelayChainStorageInfo + RelayChainStateInfo, RelayChainState::Hasher: 'static, OutputOf: Ord, RelayChainState::BlockNumber: Copy + Into + TryFrom + HasCompact, @@ -110,15 +108,20 @@ pub(super) mod relay_chain { relay_height: &RelayChainState::BlockNumber, proof: impl IntoIterator>, ) -> Result, ()> { - let relay_state_root = RelayChainState::state_root_for_block(relay_height, &()).ok_or(())?; + 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(crate) fn verify_proof_for_parachain_with_root( + para_id: &RelayChainState::ParaId, + root: &OutputOf<::Hasher>, + proof: impl IntoIterator>, + ) -> Result, ()> { 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); @@ -159,12 +162,8 @@ pub(super) mod relay_chain { { type BlockNumber = u32; type Hasher = BlakeTwo256; - type LookupInfo = (); - fn state_root_for_block( - block_height: &Self::BlockNumber, - _lookup_info: &Self::LookupInfo, - ) -> Option> { + 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) } @@ -203,12 +202,8 @@ pub(super) mod relay_chain { impl RelayChainStateInfo for StaticPolkadotInfoProvider { type BlockNumber = u32; type Hasher = BlakeTwo256; - type LookupInfo = (); - fn state_root_for_block( - _block_height: &Self::BlockNumber, - _lookup_info: &Self::LookupInfo, - ) -> Option> { + fn state_root_for_block(_block_height: &Self::BlockNumber) -> Option> { Some(hex!("81b75d95075d16005ee0a987a3f061d3011ada919b261e9b02961b9b3725f3fd").into()) } } @@ -239,114 +234,6 @@ pub(super) mod relay_chain { 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 struct PastStateRootProvider(PhantomData); - - impl PastStateRootProvider - where - HistoryProvider: traits::HistoryProvider, - HistoryProvider::BlockNumber: Member - + sp_std::hash::Hash - + Copy - + MaybeDisplay - + AtLeast32BitUnsigned - + Codec - + Into - + TryFrom, - ::Output: - Default + sp_std::hash::Hash + Copy + Member + MaybeDisplay + SimpleBitOps + Codec, - { - pub fn verify_past_state( - block_number: HistoryProvider::BlockNumber, - header: Header, - ) -> Result<::Output, ()> { - let block_hash = HistoryProvider::block_hash_for(&block_number).ok_or(())?; - ensure!(block_hash == header.hash(), ()); - Ok(header.state_root) - } - } - - #[cfg(test)] - mod past_state_root_provider_tests { - use super::*; - - use hex_literal::hex; - use sp_runtime::{Digest, DigestItem}; - - use crate::traits::HistoryProvider; - - const BLOCK_NUMBER: u64 = 4_362_970; - - struct SpiritnetStaticBlockProvider; - - impl HistoryProvider for SpiritnetStaticBlockProvider { - type BlockNumber = u64; - type Hasher = BlakeTwo256; - - fn block_hash_for(block: &Self::BlockNumber) -> Option<::Output> { - if block == &BLOCK_NUMBER { - Some(hex!("b9700ad2c2cad8ba5bf1affb98c377e9ba4f28ceaecc22285f636a3971a7c3f4").into()) - } else { - None - } - } - } - - #[test] - fn test_correct_block_verification() { - let header_at_block = Header:: { - digest: Digest { - logs: vec![ - DigestItem::PreRuntime(*b"aura", hex!("9ad3660800000000").to_vec()), - DigestItem::Seal(*b"aura", hex!("066a1734615150b91a99779f770a47a47e91680cf0dbc97fea08d10b0bad19066eaccd401394589b84e346145713e98ae709fd52933871d2383640bd76c3158b").to_vec()) - ] - }, - extrinsics_root: hex!("5031bb2622631dc5da356f9023a5b751c837854de0de9af746942e7594c051f8").into(), - number: BLOCK_NUMBER, - parent_hash: hex!("bd5f86c2de02153751ebbe12986103f9b7a809fda03d4564495de83fd37280d0").into(), - state_root: hex!("5963f41159ad1ff28f6617cf9519f48a5ca9927ffa98c692d3841ab702006c4d").into() - }; - let state_root = - PastStateRootProvider::::verify_past_state(BLOCK_NUMBER, header_at_block) - .expect("State verification should not fail."); - assert_eq!( - state_root, - hex!("5963f41159ad1ff28f6617cf9519f48a5ca9927ffa98c692d3841ab702006c4d").into() - ); - } - - #[test] - fn test_invalid_block_verification() { - let invalid_header_at_block = Header:: { - digest: Digest { - logs: vec![ - DigestItem::PreRuntime(*b"aura", hex!("9ad3660800000000").to_vec()), - DigestItem::Seal(*b"aura", hex!("066a1734615150b91a99779f770a47a47e91680cf0dbc97fea08d10b0bad19066eaccd401394589b84e346145713e98ae709fd52933871d2383640bd76c3158b").to_vec()) - ] - }, - extrinsics_root: hex!("5031bb2622631dc5da356f9023a5b751c837854de0de9af746942e7594c051f8").into(), - number: BLOCK_NUMBER, - parent_hash: hex!("bd5f86c2de02153751ebbe12986103f9b7a809fda03d4564495de83fd37280d0").into(), - // Changed the last byte from 0x4d to 0x4c. - state_root: hex!("5963f41159ad1ff28f6617cf9519f48a5ca9927ffa98c692d3841ab702006c4c").into() - }; - let state_root = PastStateRootProvider::::verify_past_state( - BLOCK_NUMBER, - invalid_header_at_block, - ); - assert_eq!(state_root, Err(())); - } - - #[test] - fn test_block_not_found() { - let non_existing_block_number = 1; - let state_root = PastStateRootProvider::::verify_past_state( - non_existing_block_number, - Header::::new_from_number(non_existing_block_number), - ); - assert_eq!(state_root, Err(())); - } - } } pub(super) mod parachain { diff --git a/crates/kilt-dip-support/src/traits.rs b/crates/kilt-dip-support/src/traits.rs index b9a015271d..a0e8e33413 100644 --- a/crates/kilt-dip-support/src/traits.rs +++ b/crates/kilt-dip-support/src/traits.rs @@ -64,12 +64,8 @@ pub trait RelayChainStorageInfo { pub trait RelayChainStateInfo { type BlockNumber; type Hasher: sp_runtime::traits::Hash; - type LookupInfo; - fn state_root_for_block( - block_height: &Self::BlockNumber, - lookup_info: &Self::LookupInfo, - ) -> Option>; + fn state_root_for_block(block_height: &Self::BlockNumber) -> Option>; } pub trait ProviderParachainStateInfo { From df0daffd9a148e759d841967da4c7a432105f3e7 Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Tue, 8 Aug 2023 17:09:50 +0200 Subject: [PATCH 05/14] Reduce trait requirementrs --- crates/kilt-dip-support/src/lib.rs | 19 ++++---- crates/kilt-dip-support/src/state_proofs.rs | 49 ++++++++++++--------- crates/kilt-dip-support/src/traits.rs | 7 ++- 3 files changed, 40 insertions(+), 35 deletions(-) diff --git a/crates/kilt-dip-support/src/lib.rs b/crates/kilt-dip-support/src/lib.rs index 49cb6b732b..dc659da743 100644 --- a/crates/kilt-dip-support/src/lib.rs +++ b/crates/kilt-dip-support/src/lib.rs @@ -38,7 +38,7 @@ use crate::{ state_proofs::{parachain::DipIdentityCommitmentProofVerifier, relay_chain::SiblingParachainHeadProofVerifier}, traits::{ Bump, DidSignatureVerifierContext, DipCallOriginFilter, HistoryProvider, ProviderParachainStateInfo, - RelayChainStateInfo, RelayChainStorageInfo, + RelayChainStorageInfo, }, utils::OutputOf, }; @@ -332,15 +332,14 @@ impl< TxSubmitter: Encode, RelayChainInfo: RelayChainStorageInfo - + RelayChainStateInfo + HistoryProvider< - BlockNumber = ::BlockNumber, - Hasher = ::Hasher, + BlockNumber = ::BlockNumber, + Hasher = ::Hasher, >, - ::Hasher: 'static, - OutputOf<::Hasher>: + ::Hasher: 'static, + OutputOf<::Hasher>: Ord + Default + sp_std::hash::Hash + Copy + Member + MaybeDisplay + SimpleBitOps + Codec, - ::BlockNumber: Copy + ::BlockNumber: Copy + Into + TryFrom + HasCompact @@ -356,7 +355,7 @@ impl< SiblingProviderStateInfo: ProviderParachainStateInfo, SiblingProviderStateInfo::Hasher: 'static, - OutputOf: Ord + From::Hasher>>, + OutputOf: Ord + From::Hasher>>, SiblingProviderStateInfo::BlockNumber: Encode + Clone, SiblingProviderStateInfo::Commitment: Decode, SiblingProviderStateInfo::Key: AsRef<[u8]>, @@ -376,8 +375,8 @@ impl< type Error = (); type IdentityDetails = LocalDidDetails; type Proof = ChildParachainDipStateProof< - ::BlockNumber, - ::Hasher, + ::BlockNumber, + ::Hasher, Vec>, RevealedDidMerkleProofLeaf< ProviderDidKeyId, diff --git a/crates/kilt-dip-support/src/state_proofs.rs b/crates/kilt-dip-support/src/state_proofs.rs index 5cee2fa468..72aa50517c 100644 --- a/crates/kilt-dip-support/src/state_proofs.rs +++ b/crates/kilt-dip-support/src/state_proofs.rs @@ -86,35 +86,25 @@ mod substrate_no_std_port { } pub(super) mod relay_chain { - use super::*; - use sp_runtime::traits::BlakeTwo256; + use super::*; + use crate::traits::{RelayChainStateInfo, RelayChainStorageInfo}; pub struct SiblingParachainHeadProofVerifier(PhantomData); impl SiblingParachainHeadProofVerifier where - RelayChainState: RelayChainStorageInfo + RelayChainStateInfo, + RelayChainState: RelayChainStorageInfo, 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: &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(crate) fn verify_proof_for_parachain_with_root( + pub fn verify_proof_for_parachain_with_root( para_id: &RelayChainState::ParaId, - root: &OutputOf<::Hasher>, + root: &OutputOf<::Hasher>, proof: impl IntoIterator>, ) -> Result, ()> { let parachain_storage_key = RelayChainState::parachain_head_storage_key(para_id); @@ -134,12 +124,33 @@ pub(super) mod relay_chain { } } + impl SiblingParachainHeadProofVerifier + where + RelayChainState: RelayChainStorageInfo + 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: &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 RelayChainStorageInfo for RococoStateRootsViaRelayStorePallet where Runtime: pallet_relay_store::Config, { + type BlockNumber = u32; + type Hasher = BlakeTwo256; type Key = StorageKey; type ParaId = u32; @@ -160,9 +171,6 @@ pub(super) mod relay_chain { where Runtime: pallet_relay_store::Config, { - type BlockNumber = u32; - type Hasher = BlakeTwo256; - 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) @@ -181,6 +189,8 @@ pub(super) mod relay_chain { struct StaticPolkadotInfoProvider; impl RelayChainStorageInfo for StaticPolkadotInfoProvider { + type BlockNumber = u32; + type Hasher = BlakeTwo256; type Key = StorageKey; type ParaId = u32; @@ -200,9 +210,6 @@ pub(super) mod relay_chain { } impl RelayChainStateInfo for StaticPolkadotInfoProvider { - type BlockNumber = u32; - type Hasher = BlakeTwo256; - fn state_root_for_block(_block_height: &Self::BlockNumber) -> Option> { Some(hex!("81b75d95075d16005ee0a987a3f061d3011ada919b261e9b02961b9b3725f3fd").into()) } diff --git a/crates/kilt-dip-support/src/traits.rs b/crates/kilt-dip-support/src/traits.rs index a0e8e33413..1fbe999c49 100644 --- a/crates/kilt-dip-support/src/traits.rs +++ b/crates/kilt-dip-support/src/traits.rs @@ -55,16 +55,15 @@ pub trait DipCallOriginFilter { } pub trait RelayChainStorageInfo { + type BlockNumber; + type Hasher: sp_runtime::traits::Hash; type Key; type ParaId; fn parachain_head_storage_key(para_id: &Self::ParaId) -> Self::Key; } -pub trait RelayChainStateInfo { - type BlockNumber; - type Hasher: sp_runtime::traits::Hash; - +pub trait RelayChainStateInfo: RelayChainStorageInfo { fn state_root_for_block(block_height: &Self::BlockNumber) -> Option>; } From 88234d2ea553eb265dcd40e73c66c52347bff529 Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Wed, 9 Aug 2023 08:24:24 +0200 Subject: [PATCH 06/14] Remove unused trait bounds --- crates/kilt-dip-support/src/lib.rs | 19 +++++--------- crates/kilt-dip-support/src/state_proofs.rs | 29 ++++++++++----------- crates/kilt-dip-support/src/traits.rs | 4 +-- 3 files changed, 23 insertions(+), 29 deletions(-) diff --git a/crates/kilt-dip-support/src/lib.rs b/crates/kilt-dip-support/src/lib.rs index dc659da743..ae88370ee1 100644 --- a/crates/kilt-dip-support/src/lib.rs +++ b/crates/kilt-dip-support/src/lib.rs @@ -35,7 +35,7 @@ use pallet_dip_consumer::traits::IdentityProofVerifier; use crate::{ did::{RevealedDidKeysAndSignature, RevealedDidKeysSignatureAndCallVerifier, TimeBoundDidSignature}, merkle::{DidMerkleProof, DidMerkleProofVerifier, RevealedDidMerkleProofLeaf, RevealedDidMerkleProofLeaves}, - state_proofs::{parachain::DipIdentityCommitmentProofVerifier, relay_chain::SiblingParachainHeadProofVerifier}, + state_proofs::{parachain::DipIdentityCommitmentProofVerifier, relay_chain::ParachainHeadProofVerifier}, traits::{ Bump, DidSignatureVerifierContext, DipCallOriginFilter, HistoryProvider, ProviderParachainStateInfo, RelayChainStorageInfo, @@ -144,7 +144,6 @@ impl< TxSubmitter: Encode, RelayChainStateInfo: traits::RelayChainStorageInfo + traits::RelayChainStateInfo, - RelayChainStateInfo::Hasher: 'static, OutputOf: Ord, RelayChainStateInfo::BlockNumber: Copy + Into + TryFrom + HasCompact, RelayChainStateInfo::Key: AsRef<[u8]>, @@ -153,7 +152,6 @@ impl< SiblingProviderStateInfo: traits::ProviderParachainStateInfo, - SiblingProviderStateInfo::Hasher: 'static, OutputOf: Ord + From>, SiblingProviderStateInfo::BlockNumber: Encode + Clone, SiblingProviderStateInfo::Commitment: Decode, @@ -202,12 +200,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 = @@ -336,7 +333,6 @@ impl< BlockNumber = ::BlockNumber, Hasher = ::Hasher, >, - ::Hasher: 'static, OutputOf<::Hasher>: Ord + Default + sp_std::hash::Hash + Copy + Member + MaybeDisplay + SimpleBitOps + Codec, ::BlockNumber: Copy @@ -354,7 +350,6 @@ impl< SiblingProviderStateInfo: ProviderParachainStateInfo, - SiblingProviderStateInfo::Hasher: 'static, OutputOf: Ord + From::Hasher>>, SiblingProviderStateInfo::BlockNumber: Encode + Clone, SiblingProviderStateInfo::Commitment: Decode, @@ -417,7 +412,7 @@ impl< // FIXME: Compilation error // 2. Verify relay chain proof let provider_parachain_header = - SiblingParachainHeadProofVerifier::::verify_proof_for_parachain_with_root( + ParachainHeadProofVerifier::::verify_proof_for_parachain_with_root( &SiblingProviderParachainId::get(), &state_root_at_height, proof.para_state_root.proof, diff --git a/crates/kilt-dip-support/src/state_proofs.rs b/crates/kilt-dip-support/src/state_proofs.rs index 72aa50517c..c46712a3a1 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]>, @@ -92,12 +92,12 @@ pub(super) mod relay_chain { 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: RelayChainStorageInfo, - RelayChainState::Hasher: 'static, OutputOf: Ord, RelayChainState::BlockNumber: Copy + Into + TryFrom + HasCompact, RelayChainState::Key: AsRef<[u8]>, @@ -124,10 +124,11 @@ pub(super) mod relay_chain { } } - impl SiblingParachainHeadProofVerifier + // Relies on the `RelayChainState::state_root_for_block` to retrieve the state + // root for the given block. + impl ParachainHeadProofVerifier where - RelayChainState: RelayChainStorageInfo + RelayChainStateInfo, - RelayChainState::Hasher: 'static, + RelayChainState: RelayChainStateInfo, OutputOf: Ord, RelayChainState::BlockNumber: Copy + Into + TryFrom + HasCompact, RelayChainState::Key: AsRef<[u8]>, @@ -231,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."); } } @@ -253,7 +253,6 @@ pub(super) mod parachain { impl DipIdentityCommitmentProofVerifier where ParaInfo: ProviderParachainStateInfo, - ParaInfo::Hasher: 'static, OutputOf: Ord, ParaInfo::Commitment: Decode, ParaInfo::Key: AsRef<[u8]>, diff --git a/crates/kilt-dip-support/src/traits.rs b/crates/kilt-dip-support/src/traits.rs index 1fbe999c49..524a9d7dc6 100644 --- a/crates/kilt-dip-support/src/traits.rs +++ b/crates/kilt-dip-support/src/traits.rs @@ -117,7 +117,7 @@ pub trait HistoryProvider { type BlockNumber; type Hasher: sp_runtime::traits::Hash; - fn block_hash_for(block: &Self::BlockNumber) -> Option<::Output>; + fn block_hash_for(block: &Self::BlockNumber) -> Option>; } impl HistoryProvider for T @@ -127,7 +127,7 @@ where type BlockNumber = T::BlockNumber; type Hasher = T::Hashing; - fn block_hash_for(block: &Self::BlockNumber) -> Option<::Output> { + fn block_hash_for(block: &Self::BlockNumber) -> Option> { let retrieved_block = frame_system::Pallet::::block_hash(block); let default_block_hash_value = ::default(); From b5d7e1a6754c9a0017e7a2e522252e23e3537ea7 Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Wed, 9 Aug 2023 09:39:06 +0200 Subject: [PATCH 07/14] Rewording --- dip-template/runtimes/dip-consumer/src/dip.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dip-template/runtimes/dip-consumer/src/dip.rs b/dip-template/runtimes/dip-consumer/src/dip.rs index 78d25919df..dbdc0b586c 100644 --- a/dip-template/runtimes/dip-consumer/src/dip.rs +++ b/dip-template/runtimes/dip-consumer/src/dip.rs @@ -33,7 +33,7 @@ use crate::{AccountId, DidIdentifier, Runtime, RuntimeCall, RuntimeOrigin}; pub type ProofVerifier = DipSiblingProviderStateProofVerifier< RococoStateRootsViaRelayStorePallet, ConstU32<2_000>, - KiltDipCommitmentsForDipProviderPallet, + KiltDipCommitmentsForDipProviderPallet, AccountId, BlakeTwo256, KeyIdOf, From c050dadbd007c859d75357fa8899e735f34f4828 Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Mon, 21 Aug 2023 09:36:53 +0200 Subject: [PATCH 08/14] Update scale-info dependency --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 1b952718fd..f8a978910c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,7 +42,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} From 7067d6c5fe0e5c75e00e93bf2fdf9a55c023a23c Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Mon, 21 Aug 2023 10:57:04 +0200 Subject: [PATCH 09/14] Add derive impls --- crates/kilt-dip-support/src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crates/kilt-dip-support/src/lib.rs b/crates/kilt-dip-support/src/lib.rs index ae88370ee1..b3704418d3 100644 --- a/crates/kilt-dip-support/src/lib.rs +++ b/crates/kilt-dip-support/src/lib.rs @@ -77,6 +77,7 @@ pub struct DipMerkleProofAndDidSignature { signature: TimeBoundDidSignature, } +#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)] pub struct DipSiblingProviderStateProofVerifier< RelayChainStateInfo, SiblingProviderParachainId, @@ -249,6 +250,7 @@ impl< } } +#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)] pub struct ChildParachainDipStateProof< RelayBlockHeight: Copy + Into + TryFrom, RelayBlockHasher: Hash, From 9d7cc42213d4f334397c761e13ba830c03481a82 Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Wed, 7 Jun 2023 15:27:40 +0200 Subject: [PATCH 10/14] Add postit pallet (cherry picked from commit 6a1e90c86ffd62c7743cf9eb13e1af448e6943ba) --- Cargo.lock | 12 ++ Cargo.toml | 2 + dip-template/pallets/pallet-postit/Cargo.toml | 40 ++++ dip-template/pallets/pallet-postit/src/lib.rs | 174 ++++++++++++++++++ .../pallets/pallet-postit/src/post.rs | 55 ++++++ .../pallets/pallet-postit/src/traits.rs | 23 +++ 6 files changed, 306 insertions(+) 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 diff --git a/Cargo.lock b/Cargo.lock index 4994a89e3d..fbd325ba35 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6772,6 +6772,18 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-postit" +version = "1.11.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 f8a978910c..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/*", @@ -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/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..d6edf07f0e --- /dev/null +++ b/dip-template/pallets/pallet-postit/src/lib.rs @@ -0,0 +1,174 @@ +// 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; + +#[frame_support::pallet] +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 OriginCheck: EnsureOrigin<::RuntimeOrigin, Success = Self::OriginSuccess>; + type OriginSuccess: Usernamable; + type MaxTextLength: Get; + 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::generate_store(pub(super) trait Store)] + #[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 { + post_id: T::Hash, + comment_id: T::Hash, + author: 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); + Comments::::insert(comment_id, comment); + 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) + .expect("Failed to add like to comment."); + Ok(()) + } else { + Err(()) + } + }) + }) + .map_err(|_| DispatchError::Other("No post or comment with provided ID found."))?; + 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; +} From 72518a4ef82ee51690103559b6fe4ebf42efcb72 Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Tue, 22 Aug 2023 14:01:04 +0200 Subject: [PATCH 11/14] Update post-it pallet for Substrate 0.9.43 --- Cargo.lock | 2 +- dip-template/pallets/pallet-postit/src/lib.rs | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fbd325ba35..436f3da47a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6774,7 +6774,7 @@ dependencies = [ [[package]] name = "pallet-postit" -version = "1.11.0-dev" +version = "1.12.0-dev" dependencies = [ "frame-support", "frame-system", diff --git a/dip-template/pallets/pallet-postit/src/lib.rs b/dip-template/pallets/pallet-postit/src/lib.rs index d6edf07f0e..4a51e1b82b 100644 --- a/dip-template/pallets/pallet-postit/src/lib.rs +++ b/dip-template/pallets/pallet-postit/src/lib.rs @@ -21,7 +21,7 @@ pub mod post; pub mod traits; -#[frame_support::pallet] +#[frame_support::pallet(dev_mode)] pub mod pallet { use super::*; @@ -64,7 +64,6 @@ pub mod pallet { pub type Comments = StorageMap<_, Twox64Concat, ::Hash, CommentOf>; #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] #[pallet::storage_version(STORAGE_VERSION)] pub struct Pallet(_); From bde7beeec0d9cd4fbff9a0d00affd7e1c1ef7a3a Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Tue, 22 Aug 2023 14:05:16 +0200 Subject: [PATCH 12/14] Change provider SS58 prefix to match KILT --- dip-template/runtimes/dip-provider/src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 712c8a393134afafcbe479ccce7b37f0c7be0098 Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Tue, 22 Aug 2023 14:33:43 +0200 Subject: [PATCH 13/14] Compiling --- Cargo.lock | 1 + .../nodes/dip-consumer/src/chain_spec.rs | 1 - dip-template/pallets/pallet-postit/src/lib.rs | 20 +++++-- dip-template/runtimes/dip-consumer/Cargo.toml | 2 + dip-template/runtimes/dip-consumer/src/dip.rs | 47 ++-------------- dip-template/runtimes/dip-consumer/src/lib.rs | 36 ++++--------- .../dip-consumer/src/origin_adapter.rs | 53 +++++++++++++++++++ 7 files changed, 85 insertions(+), 75 deletions(-) create mode 100644 dip-template/runtimes/dip-consumer/src/origin_adapter.rs diff --git a/Cargo.lock b/Cargo.lock index 436f3da47a..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", 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/src/lib.rs b/dip-template/pallets/pallet-postit/src/lib.rs index 4a51e1b82b..170797f61e 100644 --- a/dip-template/pallets/pallet-postit/src/lib.rs +++ b/dip-template/pallets/pallet-postit/src/lib.rs @@ -21,6 +21,8 @@ pub mod post; pub mod traits; +pub use pallet::*; + #[frame_support::pallet(dev_mode)] pub mod pallet { @@ -48,9 +50,9 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { + type MaxTextLength: Get; type OriginCheck: EnsureOrigin<::RuntimeOrigin, Success = Self::OriginSuccess>; type OriginSuccess: Usernamable; - type MaxTextLength: Get; type RuntimeEvent: From> + IsType<::RuntimeEvent>; type Username: Encode + Decode + TypeInfo + MaxEncodedLen + Clone + PartialEq + Debug + Default; } @@ -75,10 +77,14 @@ pub mod pallet { author: T::Username, }, NewComment { - post_id: T::Hash, + resource_id: T::Hash, comment_id: T::Hash, author: T::Username, }, + NewLike { + resource_id: T::Hash, + liker: T::Username, + }, } #[pallet::call] @@ -134,8 +140,13 @@ pub mod pallet { }) }) .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); + 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(()) } @@ -158,7 +169,7 @@ pub mod pallet { comment .details .likes - .try_push(liker) + .try_push(liker.clone()) .expect("Failed to add like to comment."); Ok(()) } else { @@ -167,6 +178,7 @@ pub mod pallet { }) }) .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/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 dbdc0b586c..33e306e6da 100644 --- a/dip-template/runtimes/dip-consumer/src/dip.rs +++ b/dip-template/runtimes/dip-consumer/src/dip.rs @@ -30,6 +30,8 @@ use sp_runtime::traits::BlakeTwo256; use crate::{AccountId, DidIdentifier, Runtime, RuntimeCall, RuntimeOrigin}; +pub type MerkleProofVerifierOutputOf = + >::VerificationResult; pub type ProofVerifier = DipSiblingProviderStateProofVerifier< RococoStateRootsViaRelayStorePallet, ConstU32<2_000>, @@ -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.") + } +} From 83ef751d9621a36b74092aeb23bfee4fb40ffde1 Mon Sep 17 00:00:00 2001 From: Antonio Antonino Date: Wed, 23 Aug 2023 11:26:12 +0200 Subject: [PATCH 14/14] Minor changes --- crates/kilt-dip-support/src/lib.rs | 14 ++++----- crates/kilt-dip-support/src/state_proofs.rs | 29 ++----------------- crates/kilt-dip-support/src/traits.rs | 24 +++++++++++++-- dip-template/runtimes/dip-consumer/src/dip.rs | 6 ++-- 4 files changed, 33 insertions(+), 40 deletions(-) diff --git a/crates/kilt-dip-support/src/lib.rs b/crates/kilt-dip-support/src/lib.rs index b3704418d3..b19daada83 100644 --- a/crates/kilt-dip-support/src/lib.rs +++ b/crates/kilt-dip-support/src/lib.rs @@ -37,7 +37,7 @@ use crate::{ merkle::{DidMerkleProof, DidMerkleProofVerifier, RevealedDidMerkleProofLeaf, RevealedDidMerkleProofLeaves}, state_proofs::{parachain::DipIdentityCommitmentProofVerifier, relay_chain::ParachainHeadProofVerifier}, traits::{ - Bump, DidSignatureVerifierContext, DipCallOriginFilter, HistoryProvider, ProviderParachainStateInfo, + Bump, DidSignatureVerifierContext, DipCallOriginFilter, HistoricalBlockRegistry, ProviderParachainStateInfo, RelayChainStorageInfo, }, utils::OutputOf, @@ -49,9 +49,7 @@ pub mod state_proofs; pub mod traits; pub mod utils; -pub use state_proofs::{ - parachain::KiltDipCommitmentsForDipProviderPallet, relay_chain::RococoStateRootsViaRelayStorePallet, -}; +pub use state_proofs::relay_chain::RococoStateRootsViaRelayStorePallet; #[derive(Encode, Decode, PartialEq, Eq, RuntimeDebug, TypeInfo, Clone)] pub struct SiblingParachainDipStateProof< @@ -259,7 +257,7 @@ pub struct ChildParachainDipStateProof< DipProviderBlockNumber, > { para_state_root: ParachainRootStateProof, - header: Header, + relay_header: Header, dip_identity_commitment: Vec>, did: DipMerkleProofAndDidSignature, } @@ -331,7 +329,7 @@ impl< TxSubmitter: Encode, RelayChainInfo: RelayChainStorageInfo - + HistoryProvider< + + HistoricalBlockRegistry< BlockNumber = ::BlockNumber, Hasher = ::Hasher, >, @@ -405,11 +403,11 @@ impl< 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.header.hash() { + 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.header.state_root; + let state_root_at_height = proof.relay_header.state_root; // FIXME: Compilation error // 2. Verify relay chain proof diff --git a/crates/kilt-dip-support/src/state_proofs.rs b/crates/kilt-dip-support/src/state_proofs.rs index c46712a3a1..0e8bf02562 100644 --- a/crates/kilt-dip-support/src/state_proofs.rs +++ b/crates/kilt-dip-support/src/state_proofs.rs @@ -86,10 +86,10 @@ mod substrate_no_std_port { } pub(super) mod relay_chain { - use sp_runtime::traits::BlakeTwo256; - use super::*; + use sp_runtime::traits::BlakeTwo256; + use crate::traits::{RelayChainStateInfo, RelayChainStorageInfo}; pub struct ParachainHeadProofVerifier(PhantomData); @@ -281,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 524a9d7dc6..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; @@ -77,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; @@ -113,14 +133,14 @@ where fn signed_extra() -> Self::SignedExtra {} } -pub trait HistoryProvider { +pub trait HistoricalBlockRegistry { type BlockNumber; type Hasher: sp_runtime::traits::Hash; fn block_hash_for(block: &Self::BlockNumber) -> Option>; } -impl HistoryProvider for T +impl HistoricalBlockRegistry for T where T: frame_system::Config, { diff --git a/dip-template/runtimes/dip-consumer/src/dip.rs b/dip-template/runtimes/dip-consumer/src/dip.rs index 33e306e6da..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; @@ -35,7 +35,7 @@ pub type MerkleProofVerifierOutputOf = pub type ProofVerifier = DipSiblingProviderStateProofVerifier< RococoStateRootsViaRelayStorePallet, ConstU32<2_000>, - KiltDipCommitmentsForDipProviderPallet, + ProviderParachainStateInfoViaProviderPallet, AccountId, BlakeTwo256, KeyIdOf,