diff --git a/Cargo.lock b/Cargo.lock
index 5609faeca2..f49eee1cb2 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -362,7 +362,6 @@ name = "attestation"
version = "1.5.0"
dependencies = [
"ctype",
- "delegation",
"frame-benchmarking",
"frame-support",
"frame-system",
@@ -370,7 +369,6 @@ dependencies = [
"log",
"pallet-balances",
"parity-scale-codec",
- "runtime-common",
"scale-info",
"serde",
"sp-core",
@@ -1375,7 +1373,6 @@ dependencies = [
"log",
"pallet-balances",
"parity-scale-codec",
- "runtime-common",
"scale-info",
"serde",
"sp-core",
@@ -1842,6 +1839,7 @@ dependencies = [
name = "delegation"
version = "1.5.0"
dependencies = [
+ "attestation",
"bitflags",
"ctype",
"env_logger 0.8.4",
@@ -1852,7 +1850,6 @@ dependencies = [
"log",
"pallet-balances",
"parity-scale-codec",
- "runtime-common",
"scale-info",
"serde",
"sp-core",
@@ -8556,6 +8553,7 @@ dependencies = [
name = "runtime-common"
version = "1.5.0"
dependencies = [
+ "attestation",
"frame-support",
"frame-system",
"pallet-authorship",
diff --git a/pallets/attestation/Cargo.toml b/pallets/attestation/Cargo.toml
index f282aeb1b2..34d3cf5b40 100644
--- a/pallets/attestation/Cargo.toml
+++ b/pallets/attestation/Cargo.toml
@@ -14,8 +14,7 @@ substrate-wasm-builder-runner = {version = "3.0.0"}
[dev-dependencies]
ctype = {features = ["mock"], path = "../ctype"}
-delegation = {features = ["mock"], path = "../delegation"}
-runtime-common = {default-features = false, path = "../../runtimes/common"}
+kilt-support = {features = ["mock"], path = "../../support"}
pallet-balances = {branch = "polkadot-v0.9.17", default-features = false, git = "https://github.com/paritytech/substrate"}
serde = {version = "1.0.132"}
@@ -31,9 +30,7 @@ serde = {optional = true, version = "1.0.132"}
# Internal dependencies
ctype = {default-features = false, path = "../ctype"}
-delegation = {default-features = false, path = "../delegation"}
kilt-support = {default-features = false, path = "../../support"}
-runtime-common = {default-features = false, optional = true, path = "../../runtimes/common"}
#External dependencies
frame-benchmarking = {branch = "polkadot-v0.9.17", default-features = false, git = "https://github.com/paritytech/substrate", optional = true}
@@ -49,7 +46,6 @@ sp-std = {branch = "polkadot-v0.9.17", default-features = false, git = "https://
[features]
default = ["std"]
mock = [
- "runtime-common",
"pallet-balances",
"serde",
"sp-core",
@@ -57,19 +53,17 @@ mock = [
"sp-keystore",
]
runtime-benchmarks = [
- "delegation/runtime-benchmarks",
"frame-benchmarking",
"frame-support/runtime-benchmarks",
"frame-system/runtime-benchmarks",
+ "kilt-support/runtime-benchmarks",
"sp-core",
]
std = [
"codec/std",
"ctype/std",
- "delegation/std",
"frame-support/std",
"frame-system/std",
- "runtime-common/std",
"kilt-support/std",
"log/std",
"pallet-balances/std",
diff --git a/pallets/attestation/src/access_control.rs b/pallets/attestation/src/access_control.rs
new file mode 100644
index 0000000000..a94d79502e
--- /dev/null
+++ b/pallets/attestation/src/access_control.rs
@@ -0,0 +1,105 @@
+// KILT Blockchain – https://botlabs.org
+// Copyright (C) 2019-2022 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::dispatch::Weight;
+use sp_runtime::DispatchError;
+
+/// Allow for more complex schemes on who can attest, revoke and remove.
+pub trait AttestationAccessControl {
+ /// Decides whether the account is allowed to attest with the given
+ /// information provided by the sender (&self).
+ fn can_attest(&self, who: &AttesterId, ctype: &Ctype, claim: &ClaimHash) -> Result;
+
+ /// Decides whether the account is allowed to revoke the attestation with
+ /// the `authorization_id` and the access information provided by the sender
+ /// (&self).
+ fn can_revoke(
+ &self,
+ who: &AttesterId,
+ ctype: &Ctype,
+ claim: &ClaimHash,
+ authorization_id: &AuthorizationId,
+ ) -> Result;
+
+ /// Decides whether the account is allowed to remove the attestation with
+ /// the `authorization_id` and the access information provided by the sender
+ /// (&self).
+ fn can_remove(
+ &self,
+ who: &AttesterId,
+ ctype: &Ctype,
+ claim: &ClaimHash,
+ authorization_id: &AuthorizationId,
+ ) -> Result;
+
+ /// The authorization ID that the sender provided. This will be used for new
+ /// attestations.
+ ///
+ /// NOTE: This method must not read storage or do any heavy computation
+ /// since it's not covered by the weight returned by `self.weight()`.
+ fn authorization_id(&self) -> AuthorizationId;
+
+ /// The worst-case weight of `can_attest`.
+ fn can_attest_weight(&self) -> Weight;
+
+ /// The worst-case weight of `can_revoke`.
+ fn can_revoke_weight(&self) -> Weight;
+
+ /// The worst-case weight of `can_remove`.
+ fn can_remove_weight(&self) -> Weight;
+}
+
+impl
+ AttestationAccessControl for ()
+where
+ AuthorizationId: Default,
+{
+ fn can_attest(&self, _who: &AttesterId, _ctype: &Ctype, _claim: &ClaimHash) -> Result {
+ Err(DispatchError::Other("Unimplemented"))
+ }
+ fn can_revoke(
+ &self,
+ _who: &AttesterId,
+ _ctype: &Ctype,
+ _claim: &ClaimHash,
+ _authorization_id: &AuthorizationId,
+ ) -> Result {
+ Err(DispatchError::Other("Unimplemented"))
+ }
+ fn can_remove(
+ &self,
+ _who: &AttesterId,
+ _ctype: &Ctype,
+ _claim: &ClaimHash,
+ _authorization_id: &AuthorizationId,
+ ) -> Result {
+ Err(DispatchError::Other("Unimplemented"))
+ }
+ fn authorization_id(&self) -> AuthorizationId {
+ Default::default()
+ }
+ fn can_attest_weight(&self) -> Weight {
+ 0
+ }
+ fn can_revoke_weight(&self) -> Weight {
+ 0
+ }
+ fn can_remove_weight(&self) -> Weight {
+ 0
+ }
+}
diff --git a/pallets/attestation/src/attestations.rs b/pallets/attestation/src/attestations.rs
index 5cb2dc7cd2..677d10377f 100644
--- a/pallets/attestation/src/attestations.rs
+++ b/pallets/attestation/src/attestations.rs
@@ -18,11 +18,10 @@
use codec::{Decode, Encode, MaxEncodedLen};
use ctype::CtypeHashOf;
-use delegation::DelegationNodeIdOf;
use kilt_support::deposit::Deposit;
use scale_info::TypeInfo;
-use crate::{AccountIdOf, AttesterOf, BalanceOf, Config};
+use crate::{AccountIdOf, AttesterOf, AuthorizationIdOf, BalanceOf, Config};
/// An on-chain attestation written by an attester.
#[derive(Clone, Debug, Encode, Decode, PartialEq, TypeInfo, MaxEncodedLen)]
@@ -35,10 +34,65 @@ pub struct AttestationDetails {
pub attester: AttesterOf,
/// \[OPTIONAL\] The ID of the delegation node used to authorize the
/// attester.
- pub delegation_id: Option>,
+ pub authorization_id: Option>,
/// The flag indicating whether the attestation has been revoked or not.
pub revoked: bool,
/// The deposit that was taken to incentivise fair use of the on chain
/// storage.
pub deposit: Deposit, BalanceOf>,
}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use crate::mock::*;
+
+ /// Old Attestation
+ #[derive(Clone, Debug, Encode, Decode, PartialEq, TypeInfo, MaxEncodedLen)]
+ #[scale_info(skip_type_params(T))]
+ #[codec(mel_bound())]
+ pub struct OldAttestationDetails {
+ /// The hash of the CType used for this attestation.
+ pub ctype_hash: CtypeHashOf,
+ /// The ID of the attester.
+ pub attester: AttesterOf,
+ /// \[OPTIONAL\] The ID of the delegation node used to authorize the
+ /// attester.
+ pub delegation_id: Option<[u8; 32]>,
+ /// The flag indicating whether the attestation has been revoked or not.
+ pub revoked: bool,
+ /// The deposit that was taken to incentivise fair use of the on chain
+ /// storage.
+ pub deposit: Deposit, BalanceOf>,
+ }
+
+ #[test]
+ fn test_no_need_to_migrate_if_none() {
+ let old = OldAttestationDetails:: {
+ ctype_hash: claim_hash_from_seed(CLAIM_HASH_SEED_01),
+ attester: sr25519_did_from_seed(&ALICE_SEED),
+ delegation_id: None,
+ revoked: true,
+ deposit: Deposit {
+ owner: ACCOUNT_00,
+ amount: ATTESTATION_DEPOSIT,
+ },
+ };
+ let encoded = old.encode();
+
+ let new = AttestationDetails::::decode(&mut &encoded[..]);
+ assert_eq!(
+ new,
+ Ok(AttestationDetails:: {
+ ctype_hash: claim_hash_from_seed(CLAIM_HASH_SEED_01),
+ attester: sr25519_did_from_seed(&ALICE_SEED),
+ authorization_id: None,
+ revoked: true,
+ deposit: Deposit {
+ owner: ACCOUNT_00,
+ amount: ATTESTATION_DEPOSIT,
+ },
+ })
+ );
+ }
+}
diff --git a/pallets/attestation/src/benchmarking.rs b/pallets/attestation/src/benchmarking.rs
index 2bfe53331c..8b4c123c74 100644
--- a/pallets/attestation/src/benchmarking.rs
+++ b/pallets/attestation/src/benchmarking.rs
@@ -19,49 +19,39 @@
use frame_benchmarking::{account, benchmarks, impl_benchmark_test_suite};
use frame_support::traits::{Currency, Get};
use frame_system::RawOrigin;
-use sp_core::sr25519;
use sp_runtime::traits::Hash;
-use sp_std::num::NonZeroU32;
-use delegation::{benchmarking::setup_delegations, Config as DelegationConfig, Permissions};
-use kilt_support::{signature::VerifySignature, traits::GenerateBenchmarkOrigin};
+use kilt_support::traits::GenerateBenchmarkOrigin;
use crate::*;
-const ONE_CHILD_PER_LEVEL: Option = NonZeroU32::new(1);
const SEED: u32 = 0;
benchmarks! {
where_clause {
where
T: core::fmt::Debug,
- T::DelegationNodeId: From,
- T::CtypeCreatorId: From,
- T::DelegationEntityId: From,
- <::DelegationSignatureVerification as VerifySignature>::Signature: From<(
- T::DelegationEntityId,
- <::DelegationSignatureVerification as VerifySignature>::Payload,
- )>,
- ::EnsureOrigin: GenerateBenchmarkOrigin,
- ::EnsureOrigin: GenerateBenchmarkOrigin,
+ ::EnsureOrigin: GenerateBenchmarkOrigin,
+ T: ctype::Config,
}
add {
let sender: T::AccountId = account("sender", 0, SEED);
+ let attester: T::AttesterId = account("attester", 0, SEED);
let claim_hash: T::Hash = T::Hashing::hash(b"claim");
let ctype_hash: T::Hash = T::Hash::default();
- let (_, _, delegate_public, delegation_id) = setup_delegations::(1, ONE_CHILD_PER_LEVEL.expect(">0"), Permissions::ATTEST)?;
- let delegate_acc: T::DelegationEntityId = delegate_public.into();
+
+ ctype::Ctypes::::insert(&ctype_hash, attester.clone());
::Currency::make_free_balance_be(&sender, ::Deposit::get() + ::Deposit::get());
- let origin = ::EnsureOrigin::generate_origin(sender.clone(), delegate_acc.clone());
- }: _(origin, claim_hash, ctype_hash, Some(delegation_id))
+ let origin = ::EnsureOrigin::generate_origin(sender.clone(), attester.clone());
+ }: _(origin, claim_hash, ctype_hash, None)
verify {
assert!(Attestations::::contains_key(claim_hash));
assert_eq!(Pallet::::attestations(claim_hash), Some(AttestationDetails {
ctype_hash,
- attester: delegate_acc,
- delegation_id: Some(delegation_id),
+ attester,
+ authorization_id: None,
revoked: false,
deposit: kilt_support::deposit::Deposit {
owner: sender,
@@ -71,29 +61,23 @@ benchmarks! {
}
revoke {
- let d in 1 .. T::MaxParentChecks::get();
-
let sender: T::AccountId = account("sender", 0, SEED);
+ let attester: T::AttesterId = account("attester", 0, SEED);
let claim_hash: T::Hash = T::Hashing::hash(b"claim");
let ctype_hash: T::Hash = T::Hash::default();
- let (root_public, _, delegate_public, delegation_id) = setup_delegations::(d, ONE_CHILD_PER_LEVEL.expect(">0"), Permissions::ATTEST | Permissions::DELEGATE)?;
- let root_acc: T::DelegationEntityId = root_public.into();
- let delegate_acc: T::DelegationEntityId = delegate_public.into();
+ ctype::Ctypes::::insert(&ctype_hash, attester.clone());
::Currency::make_free_balance_be(&sender, ::Deposit::get() + ::Deposit::get());
- // attest with leaf account
- let origin = ::EnsureOrigin::generate_origin(sender.clone(), delegate_acc.clone());
- Pallet::::add(origin, claim_hash, ctype_hash, Some(delegation_id))?;
- // revoke with root account, s.t. delegation tree needs to be traversed
- let origin = ::EnsureOrigin::generate_origin(sender.clone(), root_acc);
- }: _(origin, claim_hash, d)
+ let origin = ::EnsureOrigin::generate_origin(sender.clone(), attester.clone());
+ Pallet::::add(origin.clone(), claim_hash, ctype_hash, None)?;
+ }: _(origin, claim_hash, None)
verify {
assert!(Attestations::::contains_key(claim_hash));
assert_eq!(Attestations::::get(claim_hash), Some(AttestationDetails {
ctype_hash,
- attester: delegate_acc,
- delegation_id: Some(delegation_id),
+ attester,
+ authorization_id: None,
revoked: true,
deposit: kilt_support::deposit::Deposit {
owner: sender,
@@ -103,41 +87,34 @@ benchmarks! {
}
remove {
- let d in 1 .. T::MaxParentChecks::get();
-
+ let attester: T::AttesterId = account("attester", 0, SEED);
+ let sender: T::AccountId = account("sender", 0, SEED);
let claim_hash: T::Hash = T::Hashing::hash(b"claim");
let ctype_hash: T::Hash = T::Hash::default();
- let sender: T::AccountId = account("sender", 0, SEED);
- let (root_public, _, delegate_public, delegation_id) = setup_delegations::(d, ONE_CHILD_PER_LEVEL.expect(">0"), Permissions::ATTEST | Permissions::DELEGATE)?;
- let root_acc: T::DelegationEntityId = root_public.into();
- let delegate_acc: T::DelegationEntityId = delegate_public.into();
+ ctype::Ctypes::::insert(&ctype_hash, attester.clone());
::Currency::make_free_balance_be(&sender, ::Deposit::get() + ::Deposit::get());
- // attest with leaf account
- let origin = ::EnsureOrigin::generate_origin(sender.clone(), delegate_acc);
- Pallet::::add(origin, claim_hash, ctype_hash, Some(delegation_id))?;
- // revoke with root account, s.t. delegation tree needs to be traversed
- let origin = ::EnsureOrigin::generate_origin(sender, root_acc);
- }: _(origin, claim_hash, d)
+ let origin = ::EnsureOrigin::generate_origin(sender.clone(), attester.clone());
+ Pallet::::add(origin, claim_hash, ctype_hash, None)?;
+ let origin = ::EnsureOrigin::generate_origin(sender, attester);
+ }: _(origin, claim_hash, None)
verify {
assert!(!Attestations::::contains_key(claim_hash));
}
reclaim_deposit {
+ let attester: T::AttesterId = account("attester", 0, SEED);
+ let sender: T::AccountId = account("sender", 0, SEED);
let claim_hash: T::Hash = T::Hashing::hash(b"claim");
let ctype_hash: T::Hash = T::Hash::default();
- let sender: T::AccountId = account("sender", 0, SEED);
- let (root_public, _, delegate_public, delegation_id) = setup_delegations::(1, ONE_CHILD_PER_LEVEL.expect(">0"), Permissions::ATTEST | Permissions::DELEGATE)?;
- let root_acc: T::DelegationEntityId = root_public.into();
- let delegate_acc: T::DelegationEntityId = delegate_public.into();
+ ctype::Ctypes::::insert(&ctype_hash, attester.clone());
::Currency::make_free_balance_be(&sender, ::Deposit::get() + ::Deposit::get());
- // attest with leaf account
- let origin = ::EnsureOrigin::generate_origin(sender.clone(), delegate_acc);
- Pallet::::add(origin, claim_hash, ctype_hash, Some(delegation_id))?;
- // revoke with root account, s.t. delegation tree needs to be traversed
+ let origin = ::EnsureOrigin::generate_origin(sender.clone(), attester);
+ Pallet::::add(origin, claim_hash, ctype_hash, None)?;
+ // revoke with root account
let origin = RawOrigin::Signed(sender);
}: _(origin, claim_hash)
verify {
diff --git a/pallets/attestation/src/default_weights.rs b/pallets/attestation/src/default_weights.rs
index a38c1ea153..10634e2a98 100644
--- a/pallets/attestation/src/default_weights.rs
+++ b/pallets/attestation/src/default_weights.rs
@@ -47,8 +47,8 @@ use sp_std::marker::PhantomData;
/// Weight functions needed for attestation.
pub trait WeightInfo {
fn add() -> Weight;
- fn revoke(d: u32, ) -> Weight;
- fn remove(d: u32, ) -> Weight;
+ fn revoke() -> Weight;
+ fn remove() -> Weight;
fn reclaim_deposit() -> Weight;
}
@@ -60,20 +60,20 @@ impl WeightInfo for SubstrateWeight {
.saturating_add(T::DbWeight::get().reads(6_u64))
.saturating_add(T::DbWeight::get().writes(3_u64))
}
- fn revoke(d: u32, ) -> Weight {
+ fn revoke() -> Weight {
(37_029_000_u64)
// Standard Error: 44_000
- .saturating_add((6_325_000_u64).saturating_mul(d as Weight))
+ .saturating_add(6_325_000_u64)
.saturating_add(T::DbWeight::get().reads(2_u64))
- .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(d as Weight)))
+ .saturating_add(T::DbWeight::get().reads(1_u64))
.saturating_add(T::DbWeight::get().writes(1_u64))
}
- fn remove(d: u32, ) -> Weight {
+ fn remove() -> Weight {
(64_058_000_u64)
// Standard Error: 44_000
- .saturating_add((6_317_000_u64).saturating_mul(d as Weight))
+ .saturating_add(6_317_000_u64)
.saturating_add(T::DbWeight::get().reads(4_u64))
- .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(d as Weight)))
+ .saturating_add(T::DbWeight::get().reads(1_u64))
.saturating_add(T::DbWeight::get().writes(3_u64))
}
fn reclaim_deposit() -> Weight {
@@ -90,20 +90,20 @@ impl WeightInfo for () {
.saturating_add(RocksDbWeight::get().reads(6_u64))
.saturating_add(RocksDbWeight::get().writes(3_u64))
}
- fn revoke(d: u32, ) -> Weight {
+ fn revoke() -> Weight {
(37_029_000_u64)
// Standard Error: 44_000
- .saturating_add((6_325_000_u64).saturating_mul(d as Weight))
+ .saturating_add(6_325_000_u64)
.saturating_add(RocksDbWeight::get().reads(2_u64))
- .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(d as Weight)))
+ .saturating_add(RocksDbWeight::get().reads(1_u64))
.saturating_add(RocksDbWeight::get().writes(1_u64))
}
- fn remove(d: u32, ) -> Weight {
+ fn remove() -> Weight {
(64_058_000_u64)
// Standard Error: 44_000
- .saturating_add((6_317_000_u64).saturating_mul(d as Weight))
+ .saturating_add(6_317_000_u64)
.saturating_add(RocksDbWeight::get().reads(4_u64))
- .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(d as Weight)))
+ .saturating_add(RocksDbWeight::get().reads(1_u64))
.saturating_add(RocksDbWeight::get().writes(3_u64))
}
fn reclaim_deposit() -> Weight {
diff --git a/pallets/attestation/src/lib.rs b/pallets/attestation/src/lib.rs
index a1e8aba421..707a508b0c 100644
--- a/pallets/attestation/src/lib.rs
+++ b/pallets/attestation/src/lib.rs
@@ -82,32 +82,39 @@ pub mod mock;
#[cfg(feature = "runtime-benchmarks")]
pub mod benchmarking;
+mod access_control;
#[cfg(test)]
mod tests;
-pub use crate::{attestations::AttestationDetails, default_weights::WeightInfo, pallet::*};
+pub use crate::{
+ access_control::AttestationAccessControl, attestations::AttestationDetails, default_weights::WeightInfo, pallet::*,
+};
#[frame_support::pallet]
pub mod pallet {
use super::*;
- use ctype::CtypeHashOf;
- use delegation::DelegationNodeIdOf;
use frame_support::{
+ dispatch::{DispatchResult, DispatchResultWithPostInfo},
pallet_prelude::*,
traits::{Currency, Get, ReservableCurrency, StorageVersion},
- BoundedVec,
};
use frame_system::pallet_prelude::*;
+ use sp_runtime::DispatchError;
+
+ use ctype::CtypeHashOf;
use kilt_support::{deposit::Deposit, traits::CallSources};
/// The current storage version.
const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
/// Type of a claim hash.
- pub(crate) type ClaimHashOf = ::Hash;
+ pub type ClaimHashOf = ::Hash;
/// Type of an attester identifier.
- pub(crate) type AttesterOf = delegation::DelegatorIdOf;
+ pub(crate) type AttesterOf = ::AttesterId;
+
+ /// Authorization id type
+ pub(crate) type AuthorizationIdOf = ::AuthorizationId;
pub(crate) type AccountIdOf = ::AccountId;
@@ -116,7 +123,7 @@ pub mod pallet {
pub(crate) type CurrencyOf = ::Currency;
#[pallet::config]
- pub trait Config: frame_system::Config + ctype::Config + delegation::Config {
+ pub trait Config: frame_system::Config + ctype::Config {
type EnsureOrigin: EnsureOrigin<
Success = ::OriginSuccess,
::Origin,
@@ -136,6 +143,13 @@ pub mod pallet {
/// the same delegation.
#[pallet::constant]
type MaxDelegatedAttestations: Get;
+
+ type AttesterId: Parameter + MaxEncodedLen;
+
+ type AuthorizationId: Parameter + MaxEncodedLen;
+
+ type AccessControl: Parameter
+ + AttestationAccessControl, ClaimHashOf>;
}
#[pallet::pallet]
@@ -157,13 +171,9 @@ pub mod pallet {
///
/// It maps from a delegation ID to a vector of claim hashes.
#[pallet::storage]
- #[pallet::getter(fn delegated_attestations)]
- pub type DelegatedAttestations = StorageMap<
- _,
- Blake2_128Concat,
- DelegationNodeIdOf,
- BoundedVec, ::MaxDelegatedAttestations>,
- >;
+ #[pallet::getter(fn external_attestations)]
+ pub type ExternalAttestations =
+ StorageDoubleMap<_, Twox64Concat, AuthorizationIdOf, Blake2_128Concat, ClaimHashOf, bool, ValueQuery>;
#[pallet::event]
#[pallet::generate_deposit(pub(super) fn deposit_event)]
@@ -174,7 +184,7 @@ pub mod pallet {
AttesterOf,
ClaimHashOf,
CtypeHashOf,
- Option>,
+ Option>,
),
/// An attestation has been revoked.
/// \[account id, claim hash\]
@@ -199,15 +209,6 @@ pub mod pallet {
/// The attestation CType does not match the CType specified in the
/// delegation hierarchy root.
CTypeMismatch,
- /// The delegation node does not include the permission to create new
- /// attestations. Only when the revoker is not the original attester.
- DelegationUnauthorizedToAttest,
- /// The delegation node has already been revoked.
- /// Only when the revoker is not the original attester.
- DelegationRevoked,
- /// The delegation node owner is different than the attester.
- /// Only when the revoker is not the original attester.
- NotDelegatedToAttester,
/// The call origin is not authorized to change the attestation.
Unauthorized,
/// The maximum number of delegated attestations has already been
@@ -239,12 +240,15 @@ pub mod pallet {
/// DelegatedAttestations
/// - Writes: Attestations, (DelegatedAttestations)
/// #
- #[pallet::weight(::WeightInfo::add())]
+ #[pallet::weight(
+ ::WeightInfo::add()
+ .saturating_add(authorization.as_ref().map(|ac| ac.can_attest_weight()).unwrap_or(0))
+ )]
pub fn add(
origin: OriginFor,
claim_hash: ClaimHashOf,
ctype_hash: CtypeHashOf,
- delegation_id: Option>,
+ authorization: Option,
) -> DispatchResult {
let source = ::EnsureOrigin::ensure_origin(origin)?;
let payer = source.sender();
@@ -261,34 +265,11 @@ pub mod pallet {
);
// Check for validity of the delegation node if specified.
- let delegation_record = if let Some(delegation_id) = delegation_id {
- let delegation = >::get(delegation_id)
- .ok_or(delegation::Error::::DelegationNotFound)?;
-
- ensure!(!delegation.details.revoked, Error::::DelegationRevoked);
-
- ensure!(delegation.details.owner == who, Error::::NotDelegatedToAttester);
-
- ensure!(
- (delegation.details.permissions & delegation::Permissions::ATTEST)
- == delegation::Permissions::ATTEST,
- Error::::DelegationUnauthorizedToAttest
- );
-
- // Check if the CType of the delegation is matching the CType of the attestation
- let root = >::get(delegation.hierarchy_root_id)
- .ok_or(delegation::Error::::HierarchyNotFound)?;
- ensure!(root.ctype_hash == ctype_hash, Error::::CTypeMismatch);
-
- // If the attestation is based on a delegation, store separately
- let mut delegated_attestations = >::get(delegation_id).unwrap_or_default();
- delegated_attestations
- .try_push(claim_hash)
- .map_err(|_| Error::::MaxDelegatedAttestationsExceeded)?;
- Some((delegation_id, delegated_attestations))
- } else {
- None
- };
+ authorization
+ .as_ref()
+ .map(|ac| ac.can_attest(&who, &ctype_hash, &claim_hash))
+ .transpose()?;
+ let authorization_id = authorization.as_ref().map(|ac| ac.authorization_id());
let deposit = Pallet::::reserve_deposit(payer, deposit_amount)?;
@@ -296,23 +277,22 @@ pub mod pallet {
log::debug!("insert Attestation");
- // write delegation record, if any
- if let Some((id, delegated_attestation)) = delegation_record {
- >::insert(id, delegated_attestation);
- }
-
- >::insert(
+ Attestations::::insert(
&claim_hash,
AttestationDetails {
ctype_hash,
attester: who.clone(),
- delegation_id,
+ authorization_id: authorization_id.clone(),
revoked: false,
deposit,
},
);
+ if let Some(authorization_id) = &authorization_id {
+ ExternalAttestations::::insert(authorization_id, claim_hash, true);
+ }
+
+ Self::deposit_event(Event::AttestationCreated(who, claim_hash, ctype_hash, authorization_id));
- Self::deposit_event(Event::AttestationCreated(who, claim_hash, ctype_hash, delegation_id));
Ok(())
}
@@ -333,11 +313,14 @@ pub mod pallet {
/// - Reads per delegation step P: delegation::Delegations
/// - Writes: Attestations, DelegatedAttestations
/// #
- #[pallet::weight(::WeightInfo::revoke(*max_parent_checks))]
+ #[pallet::weight(
+ ::WeightInfo::revoke()
+ .saturating_add(authorization.as_ref().map(|ac| ac.can_revoke_weight()).unwrap_or(0))
+ )]
pub fn revoke(
origin: OriginFor,
claim_hash: ClaimHashOf,
- max_parent_checks: u32,
+ authorization: Option,
) -> DispatchResultWithPostInfo {
let source = ::EnsureOrigin::ensure_origin(origin)?;
let who = source.subject();
@@ -346,16 +329,20 @@ pub mod pallet {
ensure!(!attestation.revoked, Error::::AlreadyRevoked);
- let delegation_depth = if attestation.attester != who {
- Self::verify_delegated_access(&who, &attestation, max_parent_checks)?
- } else {
- 0
- };
+ if attestation.attester != who {
+ let attestation_auth_id = attestation.authorization_id.as_ref().ok_or(Error::::Unauthorized)?;
+ authorization.ok_or(Error::::Unauthorized)?.can_revoke(
+ &who,
+ &attestation.ctype_hash,
+ &claim_hash,
+ attestation_auth_id,
+ )?;
+ }
// *** No Fail beyond this point ***
log::debug!("revoking Attestation");
- >::insert(
+ Attestations::::insert(
&claim_hash,
AttestationDetails {
revoked: true,
@@ -365,7 +352,7 @@ pub mod pallet {
Self::deposit_event(Event::AttestationRevoked(who, claim_hash));
- Ok(Some(::WeightInfo::revoke(delegation_depth)).into())
+ Ok(Some(::WeightInfo::revoke()).into())
}
/// Remove an attestation.
@@ -385,22 +372,29 @@ pub mod pallet {
/// - Reads per delegation step P: delegation::Delegations
/// - Writes: Attestations, DelegatedAttestations
/// #
- #[pallet::weight(::WeightInfo::remove(*max_parent_checks))]
+ #[pallet::weight(
+ ::WeightInfo::remove()
+ .saturating_add(authorization.as_ref().map(|ac| ac.can_remove_weight()).unwrap_or(0))
+ )]
pub fn remove(
origin: OriginFor,
claim_hash: ClaimHashOf,
- max_parent_checks: u32,
+ authorization: Option,
) -> DispatchResultWithPostInfo {
let source = ::EnsureOrigin::ensure_origin(origin)?;
let who = source.subject();
let attestation = Attestations::::get(&claim_hash).ok_or(Error::::AttestationNotFound)?;
- let delegation_depth = if attestation.attester != who {
- Self::verify_delegated_access(&who, &attestation, max_parent_checks)?
- } else {
- 0
- };
+ if attestation.attester != who {
+ let attestation_auth_id = attestation.authorization_id.as_ref().ok_or(Error::::Unauthorized)?;
+ authorization.ok_or(Error::::Unauthorized)?.can_remove(
+ &who,
+ &attestation.ctype_hash,
+ &claim_hash,
+ attestation_auth_id,
+ )?;
+ }
// *** No Fail beyond this point ***
@@ -409,7 +403,7 @@ pub mod pallet {
Self::remove_attestation(attestation, claim_hash);
Self::deposit_event(Event::AttestationRemoved(who, claim_hash));
- Ok(Some(::WeightInfo::remove(delegation_depth)).into())
+ Ok(Some(::WeightInfo::remove()).into())
}
/// Reclaim a storage deposit by removing an attestation
@@ -440,28 +434,6 @@ pub mod pallet {
}
impl Pallet {
- /// Check the delegation tree if the attester is authorized to access
- /// the attestation.
- fn verify_delegated_access(
- attester: &AttesterOf,
- attestation: &AttestationDetails,
- max_parent_checks: u32,
- ) -> Result {
- // if there is no delegation id, access to this attestation wasn't delegated to
- // anyone.
- let delegation_id = attestation.delegation_id.ok_or(Error::::Unauthorized)?;
- ensure!(
- max_parent_checks <= T::MaxParentChecks::get(),
- delegation::Error::::MaxParentChecksTooLarge
- );
- // Check whether the sender of the revocation controls the delegation node and
- // that the delegation has not been revoked
- let (is_delegating, delegation_depth) =
- >::is_delegating(attester, &delegation_id, max_parent_checks)?;
- ensure!(is_delegating, Error::::Unauthorized);
- Ok(delegation_depth)
- }
-
/// Reserve the deposit and record the deposit on chain.
///
/// Fails if the `payer` has a balance less than deposit.
@@ -480,12 +452,8 @@ pub mod pallet {
fn remove_attestation(attestation: AttestationDetails, claim_hash: ClaimHashOf) {
kilt_support::free_deposit::, CurrencyOf>(&attestation.deposit);
Attestations::::remove(&claim_hash);
- if let Some(delegation_id) = attestation.delegation_id {
- DelegatedAttestations::::mutate(&delegation_id, |maybe_attestations| {
- if let Some(attestations) = maybe_attestations.as_mut() {
- attestations.retain(|&elem| elem != claim_hash);
- }
- });
+ if let Some(authorization_id) = &attestation.authorization_id {
+ ExternalAttestations::::remove(authorization_id, claim_hash);
}
}
}
diff --git a/pallets/attestation/src/mock.rs b/pallets/attestation/src/mock.rs
index 3eb90fdbb3..51665c2b28 100644
--- a/pallets/attestation/src/mock.rs
+++ b/pallets/attestation/src/mock.rs
@@ -23,13 +23,19 @@
//! other tests. Internal functions/structs can only be used in attestation
//! tests.
+use codec::{Decode, Encode};
+use frame_support::{dispatch::Weight, traits::Get};
+use scale_info::TypeInfo;
+use sp_core::H256;
+use sp_runtime::DispatchError;
+
use ctype::CtypeHashOf;
-use delegation::DelegationNodeIdOf;
-use frame_support::traits::Get;
use kilt_support::deposit::Deposit;
-use sp_core::H256;
-use crate::{AccountIdOf, AttestationDetails, AttesterOf, BalanceOf, ClaimHashOf, Config};
+use crate::{
+ pallet::AuthorizationIdOf, AccountIdOf, AttestationAccessControl, AttestationDetails, AttesterOf, BalanceOf,
+ ClaimHashOf, Config,
+};
#[cfg(test)]
pub use crate::mock::runtime::*;
@@ -37,7 +43,7 @@ pub use crate::mock::runtime::*;
pub struct AttestationCreationDetails {
pub claim_hash: ClaimHashOf,
pub ctype_hash: CtypeHashOf,
- pub delegation_id: Option>,
+ pub authorization_id: Option>,
}
pub fn generate_base_attestation_creation_details(
@@ -47,21 +53,7 @@ pub fn generate_base_attestation_creation_details(
AttestationCreationDetails {
claim_hash,
ctype_hash: attestation.ctype_hash,
- delegation_id: attestation.delegation_id,
- }
-}
-
-pub struct AttestationRevocationDetails {
- pub claim_hash: ClaimHashOf,
- pub max_parent_checks: u32,
-}
-
-pub fn generate_base_attestation_revocation_details(
- claim_hash: ClaimHashOf,
-) -> AttestationRevocationDetails {
- AttestationRevocationDetails {
- claim_hash,
- max_parent_checks: 0u32,
+ authorization_id: attestation.authorization_id,
}
}
@@ -72,7 +64,7 @@ where
{
AttestationDetails {
attester,
- delegation_id: None,
+ authorization_id: None,
ctype_hash: ctype::mock::get_ctype_hash::(true),
revoked: false,
deposit: Deposit::, BalanceOf> {
@@ -82,6 +74,82 @@ where
}
}
+/// Authorize iff the subject of the origin and the provided attester id match.
+#[derive(Clone, Debug, Encode, Decode, TypeInfo, PartialEq, Eq)]
+#[scale_info(skip_type_params(T))]
+pub struct MockAccessControl(pub T::AttesterId);
+
+impl AttestationAccessControl, ClaimHashOf>
+ for MockAccessControl
+where
+ T: Config::AttesterId>,
+{
+ fn can_attest(
+ &self,
+ who: &T::AttesterId,
+ _ctype: &CtypeHashOf,
+ _claim: &ClaimHashOf,
+ ) -> Result {
+ if who == &self.0 {
+ Ok(0)
+ } else {
+ Err(DispatchError::Other("Unauthorized"))
+ }
+ }
+
+ fn can_revoke(
+ &self,
+ who: &T::AttesterId,
+ _ctype: &CtypeHashOf,
+ _claim: &ClaimHashOf,
+ authorization_id: &T::AuthorizationId,
+ ) -> Result {
+ if authorization_id == who {
+ Ok(0)
+ } else {
+ Err(DispatchError::Other("Unauthorized"))
+ }
+ }
+
+ fn can_remove(
+ &self,
+ who: &T::AttesterId,
+ _ctype: &CtypeHashOf,
+ _claim: &ClaimHashOf,
+ authorization_id: &T::AuthorizationId,
+ ) -> Result {
+ if authorization_id == who {
+ Ok(0)
+ } else {
+ Err(DispatchError::Other("Unauthorized"))
+ }
+ }
+
+ fn authorization_id(&self) -> T::AuthorizationId {
+ self.0.clone()
+ }
+
+ fn can_attest_weight(&self) -> Weight {
+ 0
+ }
+ fn can_revoke_weight(&self) -> Weight {
+ 0
+ }
+ fn can_remove_weight(&self) -> Weight {
+ 0
+ }
+}
+
+pub fn insert_attestation(claim_hash: ClaimHashOf, details: AttestationDetails) {
+ crate::Pallet::::reserve_deposit(details.deposit.owner.clone(), details.deposit.amount)
+ .expect("Should have balance");
+
+ crate::Attestations::::insert(&claim_hash, details.clone());
+ if let Some(delegation_id) = details.authorization_id.as_ref() {
+ crate::ExternalAttestations::::insert(delegation_id, claim_hash, true)
+ }
+}
+
/// Mocks that are only used internally
#[cfg(test)]
pub(crate) mod runtime {
@@ -92,29 +160,26 @@ pub(crate) mod runtime {
use sp_runtime::{
testing::Header,
traits::{BlakeTwo256, IdentifyAccount, IdentityLookup, Verify},
- MultiSigner,
+ MultiSignature, MultiSigner,
};
use std::sync::Arc;
- use delegation::{mock::DelegationHierarchyInitialization, DelegationNode};
- use kilt_support::{
- mock::{mock_origin, SubjectId},
- signature::EqualVerify,
- };
- use runtime_common::constants::{attestation::ATTESTATION_DEPOSIT, delegation::DELEGATION_DEPOSIT, MILLI_KILT};
+ use kilt_support::mock::{mock_origin, SubjectId};
use super::*;
- use crate::Pallet;
type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic;
type Block = frame_system::mocking::MockBlock;
- type TestCtypeOwner = SubjectId;
- type TestCtypeHash = runtime_common::Hash;
- type TestDelegationNodeId = runtime_common::Hash;
- type TestDelegatorId = SubjectId;
- type TestClaimHash = runtime_common::Hash;
- type TestBalance = runtime_common::Balance;
+ pub type Hash = sp_core::H256;
+ pub type Balance = u128;
+ pub type Signature = MultiSignature;
+ pub type AccountPublic = ::Signer;
+ pub type AccountId = ::AccountId;
+
+ pub const UNIT: Balance = 10u128.pow(15);
+ pub const MILLI_UNIT: Balance = 10u128.pow(12);
+ pub const ATTESTATION_DEPOSIT: Balance = 10 * MILLI_UNIT;
frame_support::construct_runtime!(
pub enum Test where
@@ -125,7 +190,6 @@ pub(crate) mod runtime {
System: frame_system::{Pallet, Call, Config, Storage, Event},
Attestation: crate::{Pallet, Call, Storage, Event},
Ctype: ctype::{Pallet, Call, Storage, Event},
- Delegation: delegation::{Pallet, Call, Storage, Event},
Balances: pallet_balances::{Pallet, Call, Storage, Event},
MockOrigin: mock_origin::{Pallet, Origin},
}
@@ -141,9 +205,9 @@ pub(crate) mod runtime {
type Call = Call;
type Index = u64;
type BlockNumber = u64;
- type Hash = runtime_common::Hash;
+ type Hash = Hash;
type Hashing = BlakeTwo256;
- type AccountId = <::Signer as IdentifyAccount>::AccountId;
+ type AccountId = AccountId;
type Lookup = IdentityLookup;
type Header = Header;
type Event = ();
@@ -152,7 +216,7 @@ pub(crate) mod runtime {
type Version = ();
type PalletInfo = PalletInfo;
- type AccountData = pallet_balances::AccountData;
+ type AccountData = pallet_balances::AccountData;
type OnNewAccount = ();
type OnKilledAccount = ();
type BaseCallFilter = frame_support::traits::Everything;
@@ -165,13 +229,13 @@ pub(crate) mod runtime {
}
parameter_types! {
- pub const ExistentialDeposit: TestBalance = MILLI_KILT;
+ pub const ExistentialDeposit: Balance = MILLI_UNIT;
pub const MaxLocks: u32 = 50;
pub const MaxReserves: u32 = 50;
}
impl pallet_balances::Config for Test {
- type Balance = TestBalance;
+ type Balance = Balance;
type DustRemoval = ();
type Event = ();
type ExistentialDeposit = ExistentialDeposit;
@@ -183,13 +247,13 @@ pub(crate) mod runtime {
}
parameter_types! {
- pub const Fee: TestBalance = 500;
+ pub const Fee: Balance = 500;
}
impl ctype::Config for Test {
- type CtypeCreatorId = TestCtypeOwner;
- type EnsureOrigin = mock_origin::EnsureDoubleOrigin;
- type OriginSuccess = mock_origin::DoubleOrigin;
+ type CtypeCreatorId = SubjectId;
+ type EnsureOrigin = mock_origin::EnsureDoubleOrigin;
+ type OriginSuccess = mock_origin::DoubleOrigin;
type Event = ();
type WeightInfo = ();
@@ -198,65 +262,44 @@ pub(crate) mod runtime {
type FeeCollector = ();
}
- parameter_types! {
- pub const MaxSignatureByteLength: u16 = 64;
- pub const MaxParentChecks: u32 = 5;
- pub const MaxRevocations: u32 = 5;
- pub const MaxRemovals: u32 = 5;
- #[derive(Clone)]
- pub const MaxChildren: u32 = 1000;
- pub const DelegationDeposit: TestBalance = DELEGATION_DEPOSIT;
- }
-
- impl delegation::Config for Test {
- type Signature = (Self::DelegationEntityId, Vec);
- type DelegationSignatureVerification = EqualVerify>;
- type DelegationEntityId = TestDelegatorId;
- type DelegationNodeId = TestDelegationNodeId;
- type EnsureOrigin = mock_origin::EnsureDoubleOrigin;
- type OriginSuccess = mock_origin::DoubleOrigin;
- type Event = ();
- type MaxSignatureByteLength = MaxSignatureByteLength;
- type MaxParentChecks = MaxParentChecks;
- type MaxRevocations = MaxRevocations;
- type MaxRemovals = MaxRemovals;
- type MaxChildren = MaxChildren;
- type WeightInfo = ();
-
- type Currency = Balances;
- type Deposit = DelegationDeposit;
- }
-
impl mock_origin::Config for Test {
type Origin = Origin;
- type AccountId = runtime_common::AccountId;
+ type AccountId = AccountId;
type SubjectId = SubjectId;
}
parameter_types! {
pub const MaxDelegatedAttestations: u32 = 1000;
- pub const Deposit: TestBalance = ATTESTATION_DEPOSIT;
+ pub const Deposit: Balance = ATTESTATION_DEPOSIT;
}
impl Config for Test {
- type EnsureOrigin = mock_origin::EnsureDoubleOrigin>;
- type OriginSuccess = mock_origin::DoubleOrigin>;
+ type EnsureOrigin = mock_origin::EnsureDoubleOrigin>;
+ type OriginSuccess = mock_origin::DoubleOrigin>;
type Event = ();
type WeightInfo = ();
type Currency = Balances;
type Deposit = Deposit;
type MaxDelegatedAttestations = MaxDelegatedAttestations;
+ type AttesterId = SubjectId;
+ type AuthorizationId = SubjectId;
+ type AccessControl = MockAccessControl;
}
- pub(crate) const ACCOUNT_00: runtime_common::AccountId = runtime_common::AccountId::new([1u8; 32]);
- pub(crate) const ACCOUNT_01: runtime_common::AccountId = runtime_common::AccountId::new([2u8; 32]);
+ pub(crate) const ACCOUNT_00: AccountId = AccountId::new([1u8; 32]);
+ pub(crate) const ACCOUNT_01: AccountId = AccountId::new([2u8; 32]);
pub(crate) const ALICE_SEED: [u8; 32] = [1u8; 32];
pub(crate) const BOB_SEED: [u8; 32] = [2u8; 32];
+ pub(crate) const CHARLIE_SEED: [u8; 32] = [3u8; 32];
- const DEFAULT_CLAIM_HASH_SEED: u64 = 1u64;
- const ALTERNATIVE_CLAIM_HASH_SEED: u64 = 2u64;
+ pub const CLAIM_HASH_SEED_01: u64 = 1u64;
+ pub const CLAIM_HASH_SEED_02: u64 = 2u64;
+
+ pub fn claim_hash_from_seed(seed: u64) -> Hash {
+ Hash::from_low_u64_be(seed)
+ }
pub fn ed25519_did_from_seed(seed: &[u8; 32]) -> SubjectId {
MultiSigner::from(ed25519::Pair::from_seed(seed).public())
@@ -270,44 +313,18 @@ pub(crate) mod runtime {
.into()
}
- pub fn get_claim_hash(default: bool) -> TestClaimHash {
- if default {
- TestClaimHash::from_low_u64_be(DEFAULT_CLAIM_HASH_SEED)
- } else {
- TestClaimHash::from_low_u64_be(ALTERNATIVE_CLAIM_HASH_SEED)
- }
- }
-
#[derive(Clone, Default)]
pub struct ExtBuilder {
- delegation_hierarchies: DelegationHierarchyInitialization,
- delegations: Vec<(TestDelegationNodeId, DelegationNode)>,
-
/// initial ctypes & owners
- ctypes: Vec<(TestCtypeHash, CtypeCreatorOf)>,
+ ctypes: Vec<(CtypeHashOf, CtypeCreatorOf)>,
/// endowed accounts with balances
balances: Vec<(AccountIdOf, BalanceOf)>,
- attestations: Vec<(TestClaimHash, AttestationDetails)>,
+ attestations: Vec<(ClaimHashOf, AttestationDetails)>,
}
impl ExtBuilder {
#[must_use]
- pub fn with_delegation_hierarchies(
- mut self,
- delegation_hierarchies: DelegationHierarchyInitialization,
- ) -> Self {
- self.delegation_hierarchies = delegation_hierarchies;
- self
- }
-
- #[must_use]
- pub fn with_delegations(mut self, delegations: Vec<(TestDelegationNodeId, DelegationNode)>) -> Self {
- self.delegations = delegations;
- self
- }
-
- #[must_use]
- pub fn with_ctypes(mut self, ctypes: Vec<(TestCtypeHash, CtypeCreatorOf)>) -> Self {
+ pub fn with_ctypes(mut self, ctypes: Vec<(CtypeHashOf, CtypeCreatorOf)>) -> Self {
self.ctypes = ctypes;
self
}
@@ -319,7 +336,7 @@ pub(crate) mod runtime {
}
#[must_use]
- pub fn with_attestations(mut self, attestations: Vec<(TestClaimHash, AttestationDetails)>) -> Self {
+ pub fn with_attestations(mut self, attestations: Vec<(ClaimHashOf, AttestationDetails)>) -> Self {
self.attestations = attestations;
self
}
@@ -339,20 +356,8 @@ pub(crate) mod runtime {
ctype::Ctypes::::insert(ctype.0, ctype.1.clone());
}
- delegation::mock::initialize_pallet(self.delegations, self.delegation_hierarchies);
-
for (claim_hash, details) in self.attestations {
- Pallet::::reserve_deposit(details.deposit.owner.clone(), details.deposit.amount)
- .expect("Should have balance");
-
- crate::Attestations::::insert(&claim_hash, details.clone());
- if let Some(delegation_id) = details.delegation_id.as_ref() {
- crate::DelegatedAttestations::::try_mutate(delegation_id, |attestations| {
- let attestations = attestations.get_or_insert_with(Default::default);
- attestations.try_push(claim_hash)
- })
- .expect("Couldn't initialise delegated attestation");
- }
+ insert_attestation(claim_hash, details);
}
});
diff --git a/pallets/attestation/src/tests.rs b/pallets/attestation/src/tests.rs
index e0179fb852..0e7794b9ea 100644
--- a/pallets/attestation/src/tests.rs
+++ b/pallets/attestation/src/tests.rs
@@ -16,425 +16,174 @@
// If you feel like getting in touch with us, you can do so at info@botlabs.org
+use ctype::mock::get_ctype_hash;
use frame_support::{assert_noop, assert_ok};
-use sp_runtime::traits::Zero;
+use sp_runtime::{traits::Zero, DispatchError};
-use ctype::mock as ctype_mock;
-use delegation::mock::{self as delegation_mock, DELEGATION_ID_SEED_1, DELEGATION_ID_SEED_2};
use kilt_support::mock::mock_origin::DoubleOrigin;
use crate::{
self as attestation,
mock::{runtime::Balances, *},
- AttesterOf, Config, DelegatedAttestations,
+ AttestationAccessControl, AttesterOf, Config,
};
// #############################################################################
-// submit_attestation_creation_operation
+// add
#[test]
-fn attest_no_delegation_successful() {
+fn test_attest_without_authorization() {
let attester: AttesterOf = sr25519_did_from_seed(&ALICE_SEED);
- let claim_hash = get_claim_hash(true);
- let attestation = generate_base_attestation::(attester.clone(), ACCOUNT_00);
-
- let operation = generate_base_attestation_creation_details(claim_hash, attestation);
+ let claim_hash = claim_hash_from_seed(CLAIM_HASH_SEED_01);
+ let ctype_hash = get_ctype_hash::(true);
+ let authorization_info = None;
ExtBuilder::default()
- .with_ctypes(vec![(operation.ctype_hash, attester.clone())])
+ .with_ctypes(vec![(ctype_hash, attester.clone())])
.with_balances(vec![(ACCOUNT_00, ::Deposit::get() * 100)])
.build()
.execute_with(|| {
assert_ok!(Attestation::add(
DoubleOrigin(ACCOUNT_00, attester.clone()).into(),
- operation.claim_hash,
- operation.ctype_hash,
- operation.delegation_id
+ claim_hash,
+ ctype_hash,
+ authorization_info.clone()
));
let stored_attestation =
Attestation::attestations(&claim_hash).expect("Attestation should be present on chain.");
- assert_eq!(stored_attestation.ctype_hash, operation.ctype_hash);
+ assert_eq!(stored_attestation.ctype_hash, ctype_hash);
assert_eq!(stored_attestation.attester, attester);
- assert_eq!(stored_attestation.delegation_id, operation.delegation_id);
+ assert_eq!(
+ stored_attestation.authorization_id,
+ authorization_info.map(|ac| ac.authorization_id())
+ );
assert!(!stored_attestation.revoked);
});
}
#[test]
-fn attest_with_delegation_successful() {
+fn test_attest_authorized() {
let attester: AttesterOf = sr25519_did_from_seed(&ALICE_SEED);
- let claim_hash = get_claim_hash(true);
-
- let hierarchy_root_id = delegation_mock::get_delegation_hierarchy_id::(true);
- let hierarchy_details = delegation_mock::generate_base_delegation_hierarchy_details();
- let delegation_id = delegation_mock::delegation_id_from_seed::(DELEGATION_ID_SEED_1);
- let mut delegation_node = delegation_mock::generate_base_delegation_node(
- hierarchy_root_id,
- attester.clone(),
- Some(hierarchy_root_id),
- ACCOUNT_00,
- );
- delegation_node.details.permissions = delegation::Permissions::ATTEST;
- let mut attestation = generate_base_attestation::(attester.clone(), ACCOUNT_00);
- attestation.delegation_id = Some(delegation_id);
-
- let operation = generate_base_attestation_creation_details(claim_hash, attestation);
+ let claim_hash = claim_hash_from_seed(CLAIM_HASH_SEED_01);
+ let ctype = get_ctype_hash::(true);
+ let authorization_info = Some(MockAccessControl(attester.clone()));
ExtBuilder::default()
- .with_ctypes(vec![(operation.ctype_hash, attester.clone())])
- .with_delegation_hierarchies(vec![(
- hierarchy_root_id,
- hierarchy_details,
- attester.clone(),
- ACCOUNT_00,
- )])
- .with_delegations(vec![(delegation_id, delegation_node)])
+ .with_ctypes(vec![(ctype, attester.clone())])
.with_balances(vec![(ACCOUNT_00, ::Deposit::get() * 100)])
.build()
.execute_with(|| {
assert_ok!(Attestation::add(
DoubleOrigin(ACCOUNT_00, attester.clone()).into(),
- operation.claim_hash,
- operation.ctype_hash,
- operation.delegation_id
+ claim_hash,
+ ctype,
+ authorization_info.clone()
));
let stored_attestation =
Attestation::attestations(&claim_hash).expect("Attestation should be present on chain.");
+ assert!(Attestation::external_attestations(attester.clone(), claim_hash));
- assert_eq!(stored_attestation.ctype_hash, operation.ctype_hash);
+ assert_eq!(stored_attestation.ctype_hash, ctype);
assert_eq!(stored_attestation.attester, attester);
- assert_eq!(stored_attestation.delegation_id, operation.delegation_id);
- assert!(!stored_attestation.revoked);
-
- let delegated_attestations = Attestation::delegated_attestations(&delegation_id)
- .expect("Attested delegation should be present on chain.");
-
- assert_eq!(delegated_attestations, vec![claim_hash]);
- });
-}
-
-#[test]
-fn ctype_not_present_attest_error() {
- let attester: AttesterOf = sr25519_did_from_seed(&ALICE_SEED);
- let claim_hash = get_claim_hash(true);
- let attestation = generate_base_attestation::(attester.clone(), ACCOUNT_00);
-
- let operation = generate_base_attestation_creation_details(claim_hash, attestation);
-
- ExtBuilder::default()
- .with_balances(vec![(ACCOUNT_00, ::Deposit::get() * 100)])
- .build()
- .execute_with(|| {
- assert_noop!(
- Attestation::add(
- DoubleOrigin(ACCOUNT_00, attester.clone()).into(),
- operation.claim_hash,
- operation.ctype_hash,
- operation.delegation_id
- ),
- ctype::Error::::CTypeNotFound
- );
- });
-}
-
-#[test]
-fn duplicate_attest_error() {
- let attester: AttesterOf = sr25519_did_from_seed(&ALICE_SEED);
- let claim_hash = get_claim_hash(true);
-
- let attestation = generate_base_attestation::(attester.clone(), ACCOUNT_00);
- let operation = generate_base_attestation_creation_details(claim_hash, attestation.clone());
-
- ExtBuilder::default()
- .with_balances(vec![(ACCOUNT_00, ::Deposit::get() * 100)])
- .with_ctypes(vec![(operation.ctype_hash, attester.clone())])
- .with_attestations(vec![(claim_hash, attestation)])
- .build()
- .execute_with(|| {
- assert_noop!(
- Attestation::add(
- DoubleOrigin(ACCOUNT_00, attester.clone()).into(),
- operation.claim_hash,
- operation.ctype_hash,
- operation.delegation_id
- ),
- attestation::Error::::AlreadyAttested
- );
- });
-}
-
-#[test]
-fn delegation_not_found_attest_error() {
- let attester: AttesterOf = sr25519_did_from_seed(&ALICE_SEED);
- let claim_hash = get_claim_hash(true);
- let delegation_id = delegation_mock::delegation_id_from_seed::(DELEGATION_ID_SEED_1);
- let mut attestation = generate_base_attestation::(attester.clone(), ACCOUNT_00);
- attestation.delegation_id = Some(delegation_id);
-
- let operation = generate_base_attestation_creation_details(claim_hash, attestation);
-
- ExtBuilder::default()
- .with_balances(vec![(ACCOUNT_00, ::Deposit::get() * 100)])
- .with_ctypes(vec![(operation.ctype_hash, attester.clone())])
- .build()
- .execute_with(|| {
- assert_noop!(
- Attestation::add(
- DoubleOrigin(ACCOUNT_00, attester.clone()).into(),
- operation.claim_hash,
- operation.ctype_hash,
- operation.delegation_id
- ),
- delegation::Error::::DelegationNotFound
- );
- });
-}
-
-#[test]
-fn delegation_revoked_attest_error() {
- let attester: AttesterOf = sr25519_did_from_seed(&ALICE_SEED);
- let claim_hash = get_claim_hash(true);
- let hierarchy_root_id = delegation_mock::get_delegation_hierarchy_id::(true);
- let hierarchy_details = delegation_mock::generate_base_delegation_hierarchy_details::();
- // Delegation node does not have permissions to attest.
- let delegation_id = delegation_mock::delegation_id_from_seed::(DELEGATION_ID_SEED_1);
- let mut delegation_node = delegation_mock::generate_base_delegation_node(
- hierarchy_root_id,
- attester.clone(),
- Some(hierarchy_root_id),
- ACCOUNT_00,
- );
- delegation_node.details.permissions = delegation::Permissions::ATTEST;
- delegation_node.details.revoked = true;
- let mut attestation = generate_base_attestation::(attester.clone(), ACCOUNT_00);
- attestation.delegation_id = Some(delegation_id);
-
- let operation = generate_base_attestation_creation_details(claim_hash, attestation);
-
- ExtBuilder::default()
- .with_balances(vec![(ACCOUNT_00, ::Deposit::get() * 100)])
- .with_ctypes(vec![(operation.ctype_hash, attester.clone())])
- .with_delegation_hierarchies(vec![(
- hierarchy_root_id,
- hierarchy_details,
- attester.clone(),
- ACCOUNT_00,
- )])
- .with_delegations(vec![(delegation_id, delegation_node)])
- .build()
- .execute_with(|| {
- assert_noop!(
- Attestation::add(
- DoubleOrigin(ACCOUNT_00, attester.clone()).into(),
- operation.claim_hash,
- operation.ctype_hash,
- operation.delegation_id
- ),
- attestation::Error::::DelegationRevoked
- );
- });
-}
-
-#[test]
-fn not_delegation_owner_attest_error() {
- let attester: AttesterOf = sr25519_did_from_seed(&ALICE_SEED);
- let alternative_owner = sr25519_did_from_seed(&BOB_SEED);
-
- let claim_hash = get_claim_hash(true);
- let hierarchy_root_id = delegation_mock::get_delegation_hierarchy_id::(true);
- let hierarchy_details = delegation_mock::generate_base_delegation_hierarchy_details::();
- let delegation_id = delegation_mock::delegation_id_from_seed::(DELEGATION_ID_SEED_1);
- let mut delegation_node = delegation_mock::generate_base_delegation_node::(
- hierarchy_root_id,
- alternative_owner,
- Some(hierarchy_root_id),
- ACCOUNT_00,
- );
- delegation_node.details.permissions = delegation::Permissions::ATTEST;
- let mut attestation = generate_base_attestation::(attester.clone(), ACCOUNT_00);
- attestation.delegation_id = Some(delegation_id);
-
- let operation = generate_base_attestation_creation_details(claim_hash, attestation);
-
- ExtBuilder::default()
- .with_balances(vec![(ACCOUNT_00, ::Deposit::get() * 100)])
- .with_ctypes(vec![(operation.ctype_hash, attester.clone())])
- .with_delegation_hierarchies(vec![(
- hierarchy_root_id,
- hierarchy_details,
- attester.clone(),
- ACCOUNT_00,
- )])
- .with_delegations(vec![(delegation_id, delegation_node)])
- .with_balances(vec![(ACCOUNT_00, ::Deposit::get() * 100)])
- .build()
- .execute_with(|| {
- assert_noop!(
- Attestation::add(
- DoubleOrigin(ACCOUNT_00, attester.clone()).into(),
- operation.claim_hash,
- operation.ctype_hash,
- operation.delegation_id
- ),
- attestation::Error::::NotDelegatedToAttester
+ assert_eq!(
+ stored_attestation.authorization_id,
+ authorization_info.map(|ac| ac.authorization_id())
);
+ assert!(!stored_attestation.revoked);
});
}
#[test]
-fn unauthorised_permissions_attest_error() {
+fn test_attest_unauthorized() {
let attester: AttesterOf = sr25519_did_from_seed(&ALICE_SEED);
- let claim_hash = get_claim_hash(true);
- let hierarchy_root_id = delegation_mock::get_delegation_hierarchy_id::(true);
- let hierarchy_details = delegation_mock::generate_base_delegation_hierarchy_details::();
- // Delegation node does not have permissions to attest.
- let delegation_id = delegation_mock::delegation_id_from_seed::(DELEGATION_ID_SEED_1);
- let delegation_node = delegation_mock::generate_base_delegation_node(
- hierarchy_root_id,
- attester.clone(),
- Some(hierarchy_root_id),
- ACCOUNT_00,
- );
- let mut attestation = generate_base_attestation::(attester.clone(), ACCOUNT_00);
- attestation.delegation_id = Some(delegation_id);
-
- let operation = generate_base_attestation_creation_details(claim_hash, attestation);
+ let bob: AttesterOf = sr25519_did_from_seed(&BOB_SEED);
+ let claim_hash = claim_hash_from_seed(CLAIM_HASH_SEED_01);
+ let ctype = get_ctype_hash::(true);
+ let authorization_info = Some(MockAccessControl(bob));
ExtBuilder::default()
+ .with_ctypes(vec![(ctype, attester.clone())])
.with_balances(vec![(ACCOUNT_00, ::Deposit::get() * 100)])
- .with_ctypes(vec![(operation.ctype_hash, attester.clone())])
- .with_delegation_hierarchies(vec![(
- hierarchy_root_id,
- hierarchy_details,
- attester.clone(),
- ACCOUNT_00,
- )])
- .with_delegations(vec![(delegation_id, delegation_node)])
.build()
.execute_with(|| {
- assert_noop!(
+ assert_eq!(
Attestation::add(
DoubleOrigin(ACCOUNT_00, attester.clone()).into(),
- operation.claim_hash,
- operation.ctype_hash,
- operation.delegation_id
+ claim_hash,
+ ctype,
+ authorization_info
),
- attestation::Error::::DelegationUnauthorizedToAttest
+ Err(DispatchError::Other("Unauthorized"))
);
});
}
#[test]
-fn root_not_present_attest_error() {
+fn test_attest_ctype_not_found() {
let attester: AttesterOf = sr25519_did_from_seed(&ALICE_SEED);
- let claim_hash = get_claim_hash(true);
- let hierarchy_root_id = delegation_mock::get_delegation_hierarchy_id::(true);
- let hierarchy_details = delegation_mock::generate_base_delegation_hierarchy_details::();
- let alternative_hierarchy_root_id = delegation_mock::get_delegation_hierarchy_id::(false);
- let delegation_id = delegation_mock::delegation_id_from_seed::(DELEGATION_ID_SEED_1);
- let mut delegation_node = delegation_mock::generate_base_delegation_node(
- hierarchy_root_id,
- attester.clone(),
- Some(alternative_hierarchy_root_id),
- ACCOUNT_00,
- );
- delegation_node.details.permissions = delegation::Permissions::ATTEST;
- let mut attestation = generate_base_attestation::(attester.clone(), ACCOUNT_00);
- attestation.delegation_id = Some(delegation_id);
-
- let operation = generate_base_attestation_creation_details(claim_hash, attestation);
+ let claim_hash = claim_hash_from_seed(CLAIM_HASH_SEED_01);
+ let ctype_hash = get_ctype_hash::(true);
ExtBuilder::default()
.with_balances(vec![(ACCOUNT_00, ::Deposit::get() * 100)])
- .with_ctypes(vec![(operation.ctype_hash, attester.clone())])
- .with_delegation_hierarchies(vec![(
- alternative_hierarchy_root_id,
- hierarchy_details,
- attester.clone(),
- ACCOUNT_00,
- )])
- .with_delegations(vec![(delegation_id, delegation_node)])
.build()
.execute_with(|| {
assert_noop!(
Attestation::add(
DoubleOrigin(ACCOUNT_00, attester.clone()).into(),
- operation.claim_hash,
- operation.ctype_hash,
- operation.delegation_id
+ claim_hash,
+ ctype_hash,
+ None
),
- delegation::Error::::HierarchyNotFound
+ ctype::Error::::CTypeNotFound
);
});
}
#[test]
-fn root_ctype_mismatch_attest_error() {
+fn test_attest_already_exists() {
let attester: AttesterOf = sr25519_did_from_seed(&ALICE_SEED);
- let claim_hash = get_claim_hash(true);
- let alternative_ctype_hash = ctype_mock::get_ctype_hash::(false);
- let hierarchy_root_id = delegation_mock::get_delegation_hierarchy_id::(true);
- let mut hierarchy_details = delegation_mock::generate_base_delegation_hierarchy_details::();
- hierarchy_details.ctype_hash = alternative_ctype_hash;
- let delegation_id = delegation_mock::delegation_id_from_seed::(DELEGATION_ID_SEED_1);
- let mut delegation_node = delegation_mock::generate_base_delegation_node(
- hierarchy_root_id,
- attester.clone(),
- Some(hierarchy_root_id),
- ACCOUNT_00,
- );
- delegation_node.details.permissions = delegation::Permissions::ATTEST;
- let mut attestation = generate_base_attestation::(attester.clone(), ACCOUNT_00);
- attestation.delegation_id = Some(delegation_id);
-
- let operation = generate_base_attestation_creation_details(claim_hash, attestation);
+ let claim_hash = claim_hash_from_seed(CLAIM_HASH_SEED_01);
+ let attestation = generate_base_attestation::(attester.clone(), ACCOUNT_00);
ExtBuilder::default()
.with_balances(vec![(ACCOUNT_00, ::Deposit::get() * 100)])
- .with_ctypes(vec![(operation.ctype_hash, attester.clone())])
- .with_delegation_hierarchies(vec![(
- hierarchy_root_id,
- hierarchy_details,
- attester.clone(),
- ACCOUNT_00,
- )])
- .with_delegations(vec![(delegation_id, delegation_node)])
+ .with_ctypes(vec![(attestation.ctype_hash, attester.clone())])
+ .with_attestations(vec![(claim_hash, attestation.clone())])
.build()
.execute_with(|| {
assert_noop!(
Attestation::add(
DoubleOrigin(ACCOUNT_00, attester.clone()).into(),
- operation.claim_hash,
- operation.ctype_hash,
- operation.delegation_id
+ claim_hash,
+ attestation.ctype_hash,
+ None
),
- attestation::Error::::CTypeMismatch
+ attestation::Error::::AlreadyAttested
);
});
}
// #############################################################################
-// submit_attestation_revocation_operation
+// revoke
#[test]
-fn revoke_and_remove_direct_successful() {
+fn test_revoke_remove() {
let revoker: AttesterOf = sr25519_did_from_seed(&ALICE_SEED);
- let claim_hash = get_claim_hash(true);
+ let claim_hash = claim_hash_from_seed(CLAIM_HASH_SEED_01);
let attestation = generate_base_attestation::(revoker.clone(), ACCOUNT_00);
- let operation = generate_base_attestation_revocation_details::(claim_hash);
-
ExtBuilder::default()
.with_balances(vec![(ACCOUNT_00, ::Deposit::get() * 100)])
.with_ctypes(vec![(attestation.ctype_hash, revoker.clone())])
- .with_attestations(vec![(operation.claim_hash, attestation)])
+ .with_attestations(vec![(claim_hash, attestation)])
.build()
.execute_with(|| {
assert_ok!(Attestation::revoke(
DoubleOrigin(ACCOUNT_00, revoker.clone()).into(),
- operation.claim_hash,
- operation.max_parent_checks
+ claim_hash,
+ None
));
let stored_attestation =
Attestation::attestations(claim_hash).expect("Attestation should be present on chain.");
@@ -444,8 +193,8 @@ fn revoke_and_remove_direct_successful() {
assert_ok!(Attestation::remove(
DoubleOrigin(ACCOUNT_00, revoker.clone()).into(),
- operation.claim_hash,
- operation.max_parent_checks
+ claim_hash,
+ None
));
assert!(Attestation::attestations(claim_hash).is_none());
assert!(Balances::reserved_balance(ACCOUNT_00).is_zero());
@@ -453,249 +202,65 @@ fn revoke_and_remove_direct_successful() {
}
#[test]
-fn revoke_with_delegation_successful() {
- let revoker: AttesterOf = sr25519_did_from_seed(&ALICE_SEED);
- let attestation_owner: AttesterOf = sr25519_did_from_seed(&BOB_SEED);
- let claim_hash = get_claim_hash(true);
-
- let hierarchy_root_id = delegation_mock::get_delegation_hierarchy_id::(true);
- let hierarchy_details = delegation_mock::generate_base_delegation_hierarchy_details::();
- let delegation_id = delegation_mock::delegation_id_from_seed::(DELEGATION_ID_SEED_1);
- let mut delegation_node = delegation_mock::generate_base_delegation_node(
- hierarchy_root_id,
- revoker.clone(),
- Some(hierarchy_root_id),
- ACCOUNT_00,
- );
- delegation_node.details.permissions = delegation::Permissions::ATTEST;
- // Attestation owned by a different user, but delegation owned by the user
- // submitting the operation.
- let mut attestation = generate_base_attestation::(attestation_owner, ACCOUNT_00);
- attestation.delegation_id = Some(delegation_id);
-
- let mut operation = generate_base_attestation_revocation_details::(claim_hash);
- // Set to 0 as we only need to check the delegation node itself and no parent.
- operation.max_parent_checks = 0u32;
-
- ExtBuilder::default()
- .with_balances(vec![
- (ACCOUNT_00, ::Deposit::get() * 100),
- (ACCOUNT_01, ::Deposit::get() * 100),
- ])
- .with_ctypes(vec![(attestation.ctype_hash, revoker.clone())])
- .with_delegation_hierarchies(vec![(
- hierarchy_root_id,
- hierarchy_details,
- revoker.clone(),
- ACCOUNT_01,
- )])
- .with_delegations(vec![(delegation_id, delegation_node)])
- .with_attestations(vec![(operation.claim_hash, attestation)])
- .build()
- .execute_with(|| {
- assert_ok!(Attestation::revoke(
- DoubleOrigin(ACCOUNT_00, revoker.clone()).into(),
- operation.claim_hash,
- operation.max_parent_checks
- ));
- let stored_attestation =
- Attestation::attestations(operation.claim_hash).expect("Attestation should be present on chain.");
-
- assert!(stored_attestation.revoked);
- });
-}
-
-#[test]
-fn revoke_with_parent_delegation_successful() {
- let revoker: AttesterOf = sr25519_did_from_seed(&ALICE_SEED);
- let attestation_owner: AttesterOf = sr25519_did_from_seed(&BOB_SEED);
- let claim_hash = get_claim_hash(true);
-
- let hierarchy_root_id = delegation_mock::get_delegation_hierarchy_id::(true);
- let hierarchy_details = delegation_mock::generate_base_delegation_hierarchy_details::();
- let parent_id = delegation_mock::delegation_id_from_seed::(DELEGATION_ID_SEED_1);
- let mut parent_node = delegation_mock::generate_base_delegation_node(
- hierarchy_root_id,
- revoker.clone(),
- Some(hierarchy_root_id),
- ACCOUNT_00,
- );
- parent_node.details.permissions = delegation::Permissions::ATTEST;
- let delegation_id = delegation_mock::delegation_id_from_seed::(DELEGATION_ID_SEED_2);
- let delegation_node = delegation_mock::generate_base_delegation_node(
- hierarchy_root_id,
- attestation_owner.clone(),
- Some(parent_id),
- ACCOUNT_00,
- );
- let mut attestation = generate_base_attestation::(attestation_owner, ACCOUNT_00);
- attestation.delegation_id = Some(delegation_id);
-
- let mut operation = generate_base_attestation_revocation_details::(claim_hash);
- // Set to 1 as the delegation referenced in the attestation is the child of the
- // node we want to use
- operation.max_parent_checks = 1u32;
-
- ExtBuilder::default()
- .with_balances(vec![
- (ACCOUNT_00, ::Deposit::get() * 100),
- (ACCOUNT_01, ::Deposit::get() * 100),
- ])
- .with_ctypes(vec![(attestation.ctype_hash, revoker.clone())])
- .with_delegation_hierarchies(vec![(
- hierarchy_root_id,
- hierarchy_details,
- revoker.clone(),
- ACCOUNT_00,
- )])
- .with_delegations(vec![(parent_id, parent_node), (delegation_id, delegation_node)])
- .with_attestations(vec![(operation.claim_hash, attestation)])
- .build()
- .execute_with(|| {
- assert_ok!(Attestation::revoke(
- DoubleOrigin(ACCOUNT_00, revoker.clone()).into(),
- operation.claim_hash,
- operation.max_parent_checks
- ));
- let stored_attestation =
- Attestation::attestations(claim_hash).expect("Attestation should be present on chain.");
-
- assert!(stored_attestation.revoked);
- });
-}
-
-#[test]
-fn revoke_parent_delegation_no_attestation_permissions_successful() {
- let revoker: AttesterOf = sr25519_did_from_seed(&ALICE_SEED);
- let attestation_owner: AttesterOf = sr25519_did_from_seed(&BOB_SEED);
- let claim_hash = get_claim_hash(true);
-
- let hierarchy_root_id = delegation_mock::get_delegation_hierarchy_id::(true);
- let hierarchy_details = delegation_mock::generate_base_delegation_hierarchy_details::();
- let parent_id = delegation_mock::delegation_id_from_seed::(DELEGATION_ID_SEED_1);
- let mut parent_node = delegation_mock::generate_base_delegation_node(
- hierarchy_root_id,
- revoker.clone(),
- Some(hierarchy_root_id),
- ACCOUNT_00,
- );
- parent_node.details.permissions = delegation::Permissions::DELEGATE;
-
- let delegation_id = delegation_mock::delegation_id_from_seed::(DELEGATION_ID_SEED_2);
- let delegation_node = delegation_mock::generate_base_delegation_node(
- hierarchy_root_id,
- attestation_owner.clone(),
- Some(parent_id),
- ACCOUNT_00,
- );
-
- let mut attestation = generate_base_attestation::(attestation_owner, ACCOUNT_00);
- attestation.delegation_id = Some(delegation_id);
-
- let mut operation = generate_base_attestation_revocation_details::(claim_hash);
- // Set to 1 as the delegation referenced in the attestation is the child of the
- // node we want to use
- operation.max_parent_checks = 1u32;
+fn test_authorized_revoke() {
+ let attester: AttesterOf = sr25519_did_from_seed(&ALICE_SEED);
+ let revoker: AttesterOf = sr25519_did_from_seed(&BOB_SEED);
+ let claim_hash = claim_hash_from_seed(CLAIM_HASH_SEED_01);
+ let authorization_info = Some(MockAccessControl(revoker.clone()));
+ let mut attestation = generate_base_attestation::(attester.clone(), ACCOUNT_00);
+ attestation.authorization_id = Some(revoker.clone());
ExtBuilder::default()
- .with_balances(vec![
- (ACCOUNT_00, ::Deposit::get() * 100),
- (ACCOUNT_01, ::Deposit::get() * 100),
- ])
- .with_ctypes(vec![(attestation.ctype_hash, revoker.clone())])
- .with_delegation_hierarchies(vec![(
- hierarchy_root_id,
- hierarchy_details,
- revoker.clone(),
- ACCOUNT_00,
- )])
- .with_delegations(vec![(parent_id, parent_node), (delegation_id, delegation_node)])
- .with_attestations(vec![(operation.claim_hash, attestation)])
+ .with_balances(vec![(ACCOUNT_00, ::Deposit::get() * 100)])
+ .with_ctypes(vec![(attestation.ctype_hash, attester)])
+ .with_attestations(vec![(claim_hash, attestation)])
.build()
.execute_with(|| {
assert_ok!(Attestation::revoke(
DoubleOrigin(ACCOUNT_00, revoker.clone()).into(),
- operation.claim_hash,
- operation.max_parent_checks
+ claim_hash,
+ authorization_info
));
let stored_attestation =
Attestation::attestations(claim_hash).expect("Attestation should be present on chain.");
+ assert!(Attestation::external_attestations(revoker.clone(), claim_hash));
assert!(stored_attestation.revoked);
+ assert_eq!(Balances::reserved_balance(ACCOUNT_00), ::Deposit::get());
});
}
#[test]
-fn revoke_parent_delegation_with_direct_delegation_revoked_successful() {
- let revoker: AttesterOf = sr25519_did_from_seed(&ALICE_SEED);
- let attestation_owner: AttesterOf = sr25519_did_from_seed(&BOB_SEED);
- let claim_hash = get_claim_hash(true);
-
- let hierarchy_root_id = delegation_mock::get_delegation_hierarchy_id::(true);
- let hierarchy_details = delegation_mock::generate_base_delegation_hierarchy_details::();
- let parent_id = delegation_mock::delegation_id_from_seed::(DELEGATION_ID_SEED_1);
- let mut parent_node = delegation_mock::generate_base_delegation_node(
- hierarchy_root_id,
- revoker.clone(),
- Some(hierarchy_root_id),
- ACCOUNT_00,
- );
- parent_node.details.permissions = delegation::Permissions::ATTEST;
-
- let delegation_id = delegation_mock::delegation_id_from_seed::(DELEGATION_ID_SEED_2);
- let mut delegation_node = delegation_mock::generate_base_delegation_node(
- hierarchy_root_id,
- attestation_owner.clone(),
- Some(parent_id),
- ACCOUNT_00,
- );
-
- delegation_node.details.revoked = true;
- let mut attestation = generate_base_attestation::(attestation_owner, ACCOUNT_00);
- attestation.delegation_id = Some(delegation_id);
+fn test_unauthorized_revoke() {
+ let attester: AttesterOf = sr25519_did_from_seed(&ALICE_SEED);
+ let revoker: AttesterOf = sr25519_did_from_seed(&BOB_SEED);
+ let evil: AttesterOf = sr25519_did_from_seed(&CHARLIE_SEED);
- let mut operation = generate_base_attestation_revocation_details::(claim_hash);
- // Set to 1 as the delegation referenced in the attestation is the child of the
- // node we want to use
- operation.max_parent_checks = 1u32;
+ let claim_hash = claim_hash_from_seed(CLAIM_HASH_SEED_01);
+ let authorization_info = Some(MockAccessControl(revoker.clone()));
+ let mut attestation = generate_base_attestation::(attester.clone(), ACCOUNT_00);
+ attestation.authorization_id = Some(revoker);
ExtBuilder::default()
- .with_balances(vec![
- (ACCOUNT_00, ::Deposit::get() * 100),
- (ACCOUNT_01, ::Deposit::get() * 100),
- ])
- .with_ctypes(vec![(attestation.ctype_hash, revoker.clone())])
- .with_delegation_hierarchies(vec![(
- hierarchy_root_id,
- hierarchy_details,
- revoker.clone(),
- ACCOUNT_01,
- )])
- .with_delegations(vec![(parent_id, parent_node), (delegation_id, delegation_node)])
- .with_attestations(vec![(operation.claim_hash, attestation)])
+ .with_balances(vec![(ACCOUNT_00, ::Deposit::get() * 100)])
+ .with_ctypes(vec![(attestation.ctype_hash, attester)])
+ .with_attestations(vec![(claim_hash, attestation)])
.build()
.execute_with(|| {
- assert_ok!(Attestation::revoke(
- DoubleOrigin(ACCOUNT_00, revoker.clone()).into(),
- operation.claim_hash,
- operation.max_parent_checks
- ));
- let stored_attestation =
- Attestation::attestations(claim_hash).expect("Attestation should be present on chain.");
-
- assert!(stored_attestation.revoked);
+ assert_noop!(
+ Attestation::revoke(DoubleOrigin(ACCOUNT_00, evil).into(), claim_hash, authorization_info),
+ DispatchError::Other("Unauthorized")
+ );
});
}
#[test]
-fn attestation_not_present_revoke_error() {
+fn test_revoke_not_found() {
let revoker: AttesterOf = sr25519_did_from_seed(&ALICE_SEED);
- let claim_hash = get_claim_hash(true);
-
+ let claim_hash = claim_hash_from_seed(CLAIM_HASH_SEED_01);
+ let authorization_info = Some(MockAccessControl(revoker.clone()));
let attestation = generate_base_attestation::(revoker.clone(), ACCOUNT_00);
- let operation = generate_base_attestation_revocation_details::(claim_hash);
-
ExtBuilder::default()
.with_balances(vec![(ACCOUNT_00, ::Deposit::get() * 100)])
.with_ctypes(vec![(attestation.ctype_hash, revoker.clone())])
@@ -704,8 +269,8 @@ fn attestation_not_present_revoke_error() {
assert_noop!(
Attestation::revoke(
DoubleOrigin(ACCOUNT_00, revoker.clone()).into(),
- operation.claim_hash,
- operation.max_parent_checks
+ claim_hash,
+ authorization_info
),
attestation::Error::::AttestationNotFound
);
@@ -713,449 +278,206 @@ fn attestation_not_present_revoke_error() {
}
#[test]
-fn already_revoked_revoke_error() {
+fn test_already_revoked() {
let revoker: AttesterOf = sr25519_did_from_seed(&ALICE_SEED);
- let claim_hash = get_claim_hash(true);
+ let claim_hash = claim_hash_from_seed(CLAIM_HASH_SEED_01);
+ let authorization_info = Some(MockAccessControl(revoker.clone()));
// Attestation already revoked
let mut attestation = generate_base_attestation::(revoker.clone(), ACCOUNT_00);
attestation.revoked = true;
- let operation = generate_base_attestation_revocation_details::(claim_hash);
-
ExtBuilder::default()
.with_balances(vec![(ACCOUNT_00, ::Deposit::get() * 100)])
.with_ctypes(vec![(attestation.ctype_hash, revoker.clone())])
- .with_attestations(vec![(operation.claim_hash, attestation)])
+ .with_attestations(vec![(claim_hash, attestation)])
.build()
.execute_with(|| {
assert_noop!(
Attestation::revoke(
DoubleOrigin(ACCOUNT_00, revoker.clone()).into(),
- operation.claim_hash,
- operation.max_parent_checks
+ claim_hash,
+ authorization_info
),
attestation::Error::::AlreadyRevoked
);
});
}
-#[test]
-fn unauthorised_attestation_revoke_error() {
- let revoker: AttesterOf = sr25519_did_from_seed(&ALICE_SEED);
- let attestation_owner: AttesterOf = sr25519_did_from_seed(&BOB_SEED);
- let claim_hash = get_claim_hash(true);
-
- // Attestation owned by a different user
- let attestation = generate_base_attestation::(attestation_owner, ACCOUNT_00);
-
- let operation = generate_base_attestation_revocation_details::(claim_hash);
-
- ExtBuilder::default()
- .with_balances(vec![
- (ACCOUNT_00,