diff --git a/Cargo.lock b/Cargo.lock index 131445d772..03b943864a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1809,6 +1809,7 @@ version = "0.24.0" dependencies = [ "bitflags", "ctype", + "env_logger 0.8.4", "frame-benchmarking", "frame-support", "frame-system", diff --git a/pallets/attestation/src/default_weights.rs b/pallets/attestation/src/default_weights.rs index a8fd991570..271f0e2371 100644 --- a/pallets/attestation/src/default_weights.rs +++ b/pallets/attestation/src/default_weights.rs @@ -19,29 +19,24 @@ //! Autogenerated weights for attestation //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 3.0.0 -//! DATE: 2021-06-11, STEPS: {{cmd.steps}}\, REPEAT: {{cmd.repeat}}\, LOW RANGE: {{cmd.lowest_range_values}}\, HIGH RANGE: {{cmd.highest_range_values}}\ +//! DATE: 2021-07-21, STEPS: {{cmd.steps}}\, REPEAT: {{cmd.repeat}}\, LOW RANGE: {{cmd.lowest_range_values}}\, HIGH RANGE: {{cmd.highest_range_values}}\ //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 // Executed Command: -// ./kilt-parachain +// target/release/kilt-parachain // benchmark -// --chain -// dev -// --execution -// wasm -// --wasm-execution -// compiled -// --pallet -// attestation -// --extrinsic -// * -// --steps -// 1 -// --repeat -// 10 +// --chain=dev +// --execution=wasm +// --wasm-execution=Compiled // --heap-pages=4096 -// --output=../../pallets/attestation/src/default_weights.rs -// --template=../../.maintain/weight-template.hbs +// --extrinsic=* +// --pallet=attestation +// --steps=1 +// --repeat=20 +// --template +// .maintain/weight-template.hbs +// --output +// pallets/attestation/src/default_weights.rs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -61,14 +56,14 @@ pub trait WeightInfo { pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { fn add() -> Weight { - (37_981_000_u64) + (38_091_000_u64) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } fn revoke(d: u32, ) -> Weight { - (23_806_000_u64) - // Standard Error: 20_000 - .saturating_add((4_670_000_u64).saturating_mul(d as Weight)) + (25_042_000_u64) + // Standard Error: 28_000 + .saturating_add((4_866_000_u64).saturating_mul(d as Weight)) .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().writes(1_u64)) @@ -78,14 +73,14 @@ impl WeightInfo for SubstrateWeight { // For backwards compatibility and tests impl WeightInfo for () { fn add() -> Weight { - (37_981_000_u64) + (38_091_000_u64) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } fn revoke(d: u32, ) -> Weight { - (23_806_000_u64) - // Standard Error: 20_000 - .saturating_add((4_670_000_u64).saturating_mul(d as Weight)) + (25_042_000_u64) + // Standard Error: 28_000 + .saturating_add((4_866_000_u64).saturating_mul(d as Weight)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(d as Weight))) .saturating_add(RocksDbWeight::get().writes(1_u64)) diff --git a/pallets/attestation/src/lib.rs b/pallets/attestation/src/lib.rs index 78ca160f63..5df121d82e 100644 --- a/pallets/attestation/src/lib.rs +++ b/pallets/attestation/src/lib.rs @@ -224,21 +224,22 @@ pub mod pallet { // Check for validity of the delegation node if specified. if let Some(delegation_id) = delegation_id { - let delegation = >::get(delegation_id) + let delegation = >::get(delegation_id) .ok_or(delegation::Error::::DelegationNotFound)?; - ensure!(!delegation.revoked, Error::::DelegationRevoked); + ensure!(!delegation.details.revoked, Error::::DelegationRevoked); - ensure!(delegation.owner == attester, Error::::NotDelegatedToAttester); + ensure!(delegation.details.owner == attester, Error::::NotDelegatedToAttester); ensure!( - (delegation.permissions & delegation::Permissions::ATTEST) == delegation::Permissions::ATTEST, + (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.root_id).ok_or(delegation::Error::::RootNotFound)?; + 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 diff --git a/pallets/attestation/src/tests.rs b/pallets/attestation/src/tests.rs index 4afe8ef452..c333f203ed 100644 --- a/pallets/attestation/src/tests.rs +++ b/pallets/attestation/src/tests.rs @@ -61,15 +61,16 @@ fn attest_with_delegation_successful() { let attester_keypair = get_alice_ed25519(); let attester = get_ed25519_account(attester_keypair.public()); let claim_hash = get_claim_hash(true); - let (root_id, root_node) = ( - delegation_mock::get_delegation_root_id(true), - delegation_mock::generate_base_delegation_root(attester.clone()), + + let (hierarchy_root_id, hierarchy_details) = ( + delegation_mock::get_delegation_hierarchy_id(true), + delegation_mock::generate_base_delegation_hierarchy_details(), ); let (delegation_id, mut delegation_node) = ( delegation_mock::get_delegation_id(true), - delegation_mock::generate_base_delegation_node(root_id, attester.clone()), + delegation_mock::generate_base_delegation_node(hierarchy_root_id, attester.clone(), Some(hierarchy_root_id)), ); - delegation_node.permissions = delegation::Permissions::ATTEST; + delegation_node.details.permissions = delegation::Permissions::ATTEST; let mut attestation = generate_base_attestation(attester.clone()); attestation.delegation_id = Some(delegation_id); @@ -79,9 +80,8 @@ fn attest_with_delegation_successful() { .with_ctypes(vec![(operation.ctype_hash, attester.clone())]) .build(None); let mut ext = delegation_mock::ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, attester.clone())]) .with_delegations(vec![(delegation_id, delegation_node)]) - .with_children(vec![(root_id, vec![delegation_id])]) .build(Some(ext)); ext.execute_with(|| { @@ -196,16 +196,16 @@ fn delegation_revoked_attest_error() { let attester_keypair = get_alice_ed25519(); let attester = get_ed25519_account(attester_keypair.public()); let claim_hash = get_claim_hash(true); - let (root_id, root_node) = ( - delegation_mock::get_delegation_root_id(true), - delegation_mock::generate_base_delegation_root(attester.clone()), + let (hierarchy_root_id, hierarchy_details) = ( + delegation_mock::get_delegation_hierarchy_id(true), + delegation_mock::generate_base_delegation_hierarchy_details(), ); let (delegation_id, mut delegation_node) = ( delegation_mock::get_delegation_id(true), - delegation_mock::generate_base_delegation_node(root_id, attester.clone()), + delegation_mock::generate_base_delegation_node(hierarchy_root_id, attester.clone(), Some(hierarchy_root_id)), ); - delegation_node.permissions = delegation::Permissions::ATTEST; - delegation_node.revoked = true; + delegation_node.details.permissions = delegation::Permissions::ATTEST; + delegation_node.details.revoked = true; let mut attestation = generate_base_attestation(attester.clone()); attestation.delegation_id = Some(delegation_id); @@ -215,9 +215,8 @@ fn delegation_revoked_attest_error() { .with_ctypes(vec![(operation.ctype_hash, attester.clone())]) .build(None); let mut ext = delegation_mock::ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, attester.clone())]) .with_delegations(vec![(delegation_id, delegation_node)]) - .with_children(vec![(root_id, vec![delegation_id])]) .build(Some(ext)); ext.execute_with(|| { @@ -240,15 +239,15 @@ fn not_delegation_owner_attest_error() { let alternative_owner_keypair = get_bob_ed25519(); let alternative_owner = get_ed25519_account(alternative_owner_keypair.public()); let claim_hash = get_claim_hash(true); - let (root_id, root_node) = ( - delegation_mock::get_delegation_root_id(true), - delegation_mock::generate_base_delegation_root(alternative_owner.clone()), + let (hierarchy_root_id, hierarchy_details) = ( + delegation_mock::get_delegation_hierarchy_id(true), + delegation_mock::generate_base_delegation_hierarchy_details(), ); let (delegation_id, mut delegation_node) = ( delegation_mock::get_delegation_id(true), - delegation_mock::generate_base_delegation_node(root_id, alternative_owner), + delegation_mock::generate_base_delegation_node(hierarchy_root_id, alternative_owner, Some(hierarchy_root_id)), ); - delegation_node.permissions = delegation::Permissions::ATTEST; + delegation_node.details.permissions = delegation::Permissions::ATTEST; let mut attestation = generate_base_attestation(attester.clone()); attestation.delegation_id = Some(delegation_id); @@ -258,9 +257,8 @@ fn not_delegation_owner_attest_error() { .with_ctypes(vec![(operation.ctype_hash, attester.clone())]) .build(None); let mut ext = delegation_mock::ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, attester.clone())]) .with_delegations(vec![(delegation_id, delegation_node)]) - .with_children(vec![(root_id, vec![delegation_id])]) .build(Some(ext)); ext.execute_with(|| { @@ -281,13 +279,14 @@ fn unauthorised_permissions_attest_error() { let attester_keypair = get_alice_ed25519(); let attester = get_ed25519_account(attester_keypair.public()); let claim_hash = get_claim_hash(true); - let (root_id, root_node) = ( - delegation_mock::get_delegation_root_id(true), - delegation_mock::generate_base_delegation_root(attester.clone()), + let (hierarchy_root_id, hierarchy_details) = ( + delegation_mock::get_delegation_hierarchy_id(true), + delegation_mock::generate_base_delegation_hierarchy_details(), ); + // Delegation node does not have permissions to attest. let (delegation_id, delegation_node) = ( delegation_mock::get_delegation_id(true), - delegation_mock::generate_base_delegation_node(root_id, attester.clone()), + delegation_mock::generate_base_delegation_node(hierarchy_root_id, attester.clone(), Some(hierarchy_root_id)), ); let mut attestation = generate_base_attestation(attester.clone()); attestation.delegation_id = Some(delegation_id); @@ -298,9 +297,8 @@ fn unauthorised_permissions_attest_error() { .with_ctypes(vec![(operation.ctype_hash, attester.clone())]) .build(None); let mut ext = delegation_mock::ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, attester.clone())]) .with_delegations(vec![(delegation_id, delegation_node)]) - .with_children(vec![(root_id, vec![delegation_id])]) .build(Some(ext)); ext.execute_with(|| { @@ -321,16 +319,20 @@ fn root_not_present_attest_error() { let attester_keypair = get_alice_ed25519(); let attester = get_ed25519_account(attester_keypair.public()); let claim_hash = get_claim_hash(true); - let (root_id, root_node) = ( - delegation_mock::get_delegation_root_id(true), - delegation_mock::generate_base_delegation_root(attester.clone()), + let (hierarchy_root_id, hierarchy_details) = ( + delegation_mock::get_delegation_hierarchy_id(true), + delegation_mock::generate_base_delegation_hierarchy_details(), ); - let alternative_root_id = delegation_mock::get_delegation_root_id(false); + let alternative_hierarchy_root_id = delegation_mock::get_delegation_hierarchy_id(false); let (delegation_id, mut delegation_node) = ( delegation_mock::get_delegation_id(true), - delegation_mock::generate_base_delegation_node(root_id, attester.clone()), + delegation_mock::generate_base_delegation_node( + hierarchy_root_id, + attester.clone(), + Some(alternative_hierarchy_root_id), + ), ); - delegation_node.permissions = delegation::Permissions::ATTEST; + delegation_node.details.permissions = delegation::Permissions::ATTEST; let mut attestation = generate_base_attestation(attester.clone()); attestation.delegation_id = Some(delegation_id); @@ -340,9 +342,12 @@ fn root_not_present_attest_error() { .with_ctypes(vec![(operation.ctype_hash, attester.clone())]) .build(None); let mut ext = delegation_mock::ExtBuilder::default() - .with_root_delegations(vec![(alternative_root_id, root_node)]) + .with_delegation_hierarchies(vec![( + alternative_hierarchy_root_id, + hierarchy_details, + attester.clone(), + )]) .with_delegations(vec![(delegation_id, delegation_node)]) - .with_children(vec![(alternative_root_id, vec![delegation_id])]) .build(Some(ext)); ext.execute_with(|| { @@ -353,7 +358,7 @@ fn root_not_present_attest_error() { operation.ctype_hash, operation.delegation_id ), - delegation::Error::::RootNotFound + delegation::Error::::HierarchyNotFound ); }); } @@ -364,16 +369,16 @@ fn root_ctype_mismatch_attest_error() { let attester = get_ed25519_account(attester_keypair.public()); let claim_hash = get_claim_hash(true); let alternative_ctype_hash = ctype_mock::get_ctype_hash(false); - let (root_id, mut root_node) = ( - delegation_mock::get_delegation_root_id(true), - delegation_mock::generate_base_delegation_root(attester.clone()), + let (hierarchy_root_id, mut hierarchy_details) = ( + delegation_mock::get_delegation_hierarchy_id(true), + delegation_mock::generate_base_delegation_hierarchy_details(), ); - root_node.ctype_hash = alternative_ctype_hash; + hierarchy_details.ctype_hash = alternative_ctype_hash; let (delegation_id, mut delegation_node) = ( delegation_mock::get_delegation_id(true), - delegation_mock::generate_base_delegation_node(root_id, attester.clone()), + delegation_mock::generate_base_delegation_node(hierarchy_root_id, attester.clone(), Some(hierarchy_root_id)), ); - delegation_node.permissions = delegation::Permissions::ATTEST; + delegation_node.details.permissions = delegation::Permissions::ATTEST; let mut attestation = generate_base_attestation(attester.clone()); attestation.delegation_id = Some(delegation_id); @@ -383,9 +388,8 @@ fn root_ctype_mismatch_attest_error() { .with_ctypes(vec![(operation.ctype_hash, attester.clone())]) .build(None); let mut ext = delegation_mock::ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, attester.clone())]) .with_delegations(vec![(delegation_id, delegation_node)]) - .with_children(vec![(root_id, vec![delegation_id])]) .build(Some(ext)); ext.execute_with(|| { @@ -442,15 +446,15 @@ fn revoke_with_delegation_successful() { let attestation_owner = get_ed25519_account(attestation_owner_keypair.public()); let claim_hash = get_claim_hash(true); - let (root_id, root_node) = ( - delegation_mock::get_delegation_root_id(true), - delegation_mock::generate_base_delegation_root(revoker.clone()), + let (hierarchy_root_id, hierarchy_details) = ( + delegation_mock::get_delegation_hierarchy_id(true), + delegation_mock::generate_base_delegation_hierarchy_details(), ); let (delegation_id, mut delegation_node) = ( delegation_mock::get_delegation_id(true), - delegation_mock::generate_base_delegation_node(root_id, revoker.clone()), + delegation_mock::generate_base_delegation_node(hierarchy_root_id, revoker.clone(), Some(hierarchy_root_id)), ); - delegation_node.permissions = delegation::Permissions::ATTEST; + 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); @@ -464,9 +468,8 @@ fn revoke_with_delegation_successful() { .with_ctypes(vec![(attestation.ctype_hash, revoker.clone())]) .build(None); let ext = delegation_mock::ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, revoker.clone())]) .with_delegations(vec![(delegation_id, delegation_node)]) - .with_children(vec![(root_id, vec![delegation_id])]) .build(Some(ext)); let mut ext = ExtBuilder::default() .with_attestations(vec![(operation.claim_hash, attestation)]) @@ -495,18 +498,18 @@ fn revoke_with_parent_delegation_successful() { let attestation_owner = get_ed25519_account(attestation_owner_keypair.public()); let claim_hash = get_claim_hash(true); - let (root_id, root_node) = ( - delegation_mock::get_delegation_root_id(true), - delegation_mock::generate_base_delegation_root(revoker.clone()), + let (hierarchy_root_id, hierarchy_details) = ( + delegation_mock::get_delegation_hierarchy_id(true), + delegation_mock::generate_base_delegation_hierarchy_details(), ); let (parent_id, mut parent_node) = ( delegation_mock::get_delegation_id(true), - delegation_mock::generate_base_delegation_node(root_id, revoker.clone()), + delegation_mock::generate_base_delegation_node(hierarchy_root_id, revoker.clone(), Some(hierarchy_root_id)), ); - parent_node.permissions = delegation::Permissions::ATTEST; + parent_node.details.permissions = delegation::Permissions::ATTEST; let (delegation_id, delegation_node) = ( delegation_mock::get_delegation_id(false), - delegation_mock::generate_base_delegation_node(root_id, attestation_owner.clone()), + delegation_mock::generate_base_delegation_node(hierarchy_root_id, attestation_owner.clone(), Some(parent_id)), ); let mut attestation = generate_base_attestation(attestation_owner); attestation.delegation_id = Some(delegation_id); @@ -520,9 +523,8 @@ fn revoke_with_parent_delegation_successful() { .with_ctypes(vec![(attestation.ctype_hash, revoker.clone())]) .build(None); let ext = delegation_mock::ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, revoker.clone())]) .with_delegations(vec![(parent_id, parent_node), (delegation_id, delegation_node)]) - .with_children(vec![(root_id, vec![parent_id]), (parent_id, vec![delegation_id])]) .build(Some(ext)); let mut ext = ExtBuilder::default() .with_attestations(vec![(operation.claim_hash, attestation)]) @@ -550,18 +552,18 @@ fn revoke_parent_delegation_no_attestation_permissions_successful() { let attestation_owner = get_ed25519_account(attestation_owner_keypair.public()); let claim_hash = get_claim_hash(true); - let (root_id, root_node) = ( - delegation_mock::get_delegation_root_id(true), - delegation_mock::generate_base_delegation_root(revoker.clone()), + let (hierarchy_root_id, hierarchy_details) = ( + delegation_mock::get_delegation_hierarchy_id(true), + delegation_mock::generate_base_delegation_hierarchy_details(), ); let (parent_id, mut parent_node) = ( delegation_mock::get_delegation_id(true), - delegation_mock::generate_base_delegation_node(root_id, revoker.clone()), + delegation_mock::generate_base_delegation_node(hierarchy_root_id, revoker.clone(), Some(hierarchy_root_id)), ); - parent_node.permissions = delegation::Permissions::DELEGATE; + parent_node.details.permissions = delegation::Permissions::DELEGATE; let (delegation_id, delegation_node) = ( delegation_mock::get_delegation_id(false), - delegation_mock::generate_base_delegation_node(root_id, attestation_owner.clone()), + delegation_mock::generate_base_delegation_node(hierarchy_root_id, attestation_owner.clone(), Some(parent_id)), ); let mut attestation = generate_base_attestation(attestation_owner); attestation.delegation_id = Some(delegation_id); @@ -575,9 +577,8 @@ fn revoke_parent_delegation_no_attestation_permissions_successful() { .with_ctypes(vec![(attestation.ctype_hash, revoker.clone())]) .build(None); let ext = delegation_mock::ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, revoker.clone())]) .with_delegations(vec![(parent_id, parent_node), (delegation_id, delegation_node)]) - .with_children(vec![(root_id, vec![parent_id]), (parent_id, vec![delegation_id])]) .build(Some(ext)); let mut ext = ExtBuilder::default() .with_attestations(vec![(operation.claim_hash, attestation)]) @@ -605,20 +606,20 @@ fn revoke_parent_delegation_with_direct_delegation_revoked_successful() { let attestation_owner = get_ed25519_account(attestation_owner_keypair.public()); let claim_hash = get_claim_hash(true); - let (root_id, root_node) = ( - delegation_mock::get_delegation_root_id(true), - delegation_mock::generate_base_delegation_root(revoker.clone()), + let (hierarchy_root_id, hierarchy_details) = ( + delegation_mock::get_delegation_hierarchy_id(true), + delegation_mock::generate_base_delegation_hierarchy_details(), ); let (parent_id, mut parent_node) = ( delegation_mock::get_delegation_id(true), - delegation_mock::generate_base_delegation_node(root_id, revoker.clone()), + delegation_mock::generate_base_delegation_node(hierarchy_root_id, revoker.clone(), Some(hierarchy_root_id)), ); - parent_node.permissions = delegation::Permissions::ATTEST; + parent_node.details.permissions = delegation::Permissions::ATTEST; let (delegation_id, mut delegation_node) = ( delegation_mock::get_delegation_id(false), - delegation_mock::generate_base_delegation_node(root_id, attestation_owner.clone()), + delegation_mock::generate_base_delegation_node(hierarchy_root_id, attestation_owner.clone(), Some(parent_id)), ); - delegation_node.revoked = true; + delegation_node.details.revoked = true; let mut attestation = generate_base_attestation(attestation_owner); attestation.delegation_id = Some(delegation_id); @@ -631,9 +632,8 @@ fn revoke_parent_delegation_with_direct_delegation_revoked_successful() { .with_ctypes(vec![(attestation.ctype_hash, revoker.clone())]) .build(None); let ext = delegation_mock::ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, revoker.clone())]) .with_delegations(vec![(parent_id, parent_node), (delegation_id, delegation_node)]) - .with_children(vec![(root_id, vec![parent_id]), (parent_id, vec![delegation_id])]) .build(Some(ext)); let mut ext = ExtBuilder::default() .with_attestations(vec![(operation.claim_hash, attestation)]) @@ -752,20 +752,19 @@ fn max_parent_lookups_revoke_error() { let attestation_owner = get_ed25519_account(attestation_owner_keypair.public()); let claim_hash = get_claim_hash(true); - let (root_id, root_node) = ( - delegation_mock::get_delegation_root_id(true), - delegation_mock::generate_base_delegation_root(revoker.clone()), + let (hierarchy_root_id, hierarchy_details) = ( + delegation_mock::get_delegation_hierarchy_id(true), + delegation_mock::generate_base_delegation_hierarchy_details(), ); - let (parent_delegation_id, parent_delegation_node) = ( + let (parent_id, parent_node) = ( delegation_mock::get_delegation_id(true), - delegation_mock::generate_base_delegation_node(root_id, revoker.clone()), + delegation_mock::generate_base_delegation_node(hierarchy_root_id, revoker.clone(), Some(hierarchy_root_id)), ); let (delegation_id, mut delegation_node) = ( - delegation_mock::get_delegation_id(true), - delegation_mock::generate_base_delegation_node(root_id, attestation_owner.clone()), + delegation_mock::get_delegation_id(false), + delegation_mock::generate_base_delegation_node(hierarchy_root_id, attestation_owner.clone(), Some(parent_id)), ); - delegation_node.permissions = delegation::Permissions::ATTEST; - delegation_node.parent = Some(parent_delegation_id); + delegation_node.details.permissions = delegation::Permissions::ATTEST; let mut attestation = generate_base_attestation(attestation_owner); attestation.delegation_id = Some(delegation_id); @@ -776,15 +775,8 @@ fn max_parent_lookups_revoke_error() { .with_ctypes(vec![(attestation.ctype_hash, revoker.clone())]) .build(None); let ext = delegation_mock::ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) - .with_delegations(vec![ - (parent_delegation_id, parent_delegation_node), - (delegation_id, delegation_node), - ]) - .with_children(vec![ - (root_id, vec![parent_delegation_id]), - (parent_delegation_id, vec![delegation_id]), - ]) + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, revoker.clone())]) + .with_delegations(vec![(parent_id, parent_node), (delegation_id, delegation_node)]) .build(Some(ext)); let mut ext = ExtBuilder::default() .with_attestations(vec![(operation.claim_hash, attestation)]) @@ -810,16 +802,16 @@ fn revoked_delegation_revoke_error() { let attestation_owner = get_ed25519_account(attestation_owner_keypair.public()); let claim_hash = get_claim_hash(true); - let (root_id, root_node) = ( - delegation_mock::get_delegation_root_id(true), - delegation_mock::generate_base_delegation_root(revoker.clone()), + let (hierarchy_root_id, hierarchy_details) = ( + delegation_mock::get_delegation_hierarchy_id(true), + delegation_mock::generate_base_delegation_hierarchy_details(), ); let (delegation_id, mut delegation_node) = ( delegation_mock::get_delegation_id(true), - delegation_mock::generate_base_delegation_node(root_id, revoker.clone()), + delegation_mock::generate_base_delegation_node(hierarchy_root_id, revoker.clone(), Some(hierarchy_root_id)), ); - delegation_node.permissions = delegation::Permissions::ATTEST; - delegation_node.revoked = true; + delegation_node.details.permissions = delegation::Permissions::ATTEST; + delegation_node.details.revoked = true; let mut attestation = generate_base_attestation(attestation_owner); attestation.delegation_id = Some(delegation_id); @@ -829,9 +821,8 @@ fn revoked_delegation_revoke_error() { .with_ctypes(vec![(attestation.ctype_hash, revoker.clone())]) .build(None); let ext = delegation_mock::ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, revoker.clone())]) .with_delegations(vec![(delegation_id, delegation_node)]) - .with_children(vec![(root_id, vec![delegation_id])]) .build(Some(ext)); let mut ext = ExtBuilder::default() .with_attestations(vec![(operation.claim_hash, attestation)]) diff --git a/pallets/ctype/src/lib.rs b/pallets/ctype/src/lib.rs index a45c79991b..285579adb0 100644 --- a/pallets/ctype/src/lib.rs +++ b/pallets/ctype/src/lib.rs @@ -115,8 +115,8 @@ pub mod pallet { #[pallet::call] impl Pallet { - /// Create a new CType from the given unique CType hashand associates it - /// with its creator. + /// Create a new CType from the given unique CType hash and associates + /// it with its creator. /// /// A CType with the same hash must not be stored on chain. /// diff --git a/pallets/delegation/Cargo.toml b/pallets/delegation/Cargo.toml index 06a551e0e1..4b2e647ac7 100644 --- a/pallets/delegation/Cargo.toml +++ b/pallets/delegation/Cargo.toml @@ -14,6 +14,7 @@ substrate-wasm-builder-runner = {version = "3.0.0"} [dev-dependencies] ctype = {features = ["mock"], path = "../ctype", version = "0.24.0"} +env_logger = {version = "0.8.4"} kilt-primitives = {default-features = false, path = "../../primitives"} serde = {version = "1.0.101"} sp-core = {branch = "polkadot-v0.9.8", default-features = false, git = "https://github.com/paritytech/substrate", version = "3.0.0"} diff --git a/pallets/delegation/src/benchmarking.rs b/pallets/delegation/src/benchmarking.rs index 1836759089..62a00badd6 100644 --- a/pallets/delegation/src/benchmarking.rs +++ b/pallets/delegation/src/benchmarking.rs @@ -23,7 +23,7 @@ use frame_system::RawOrigin; use sp_core::{offchain::KeyTypeId, sr25519}; use sp_io::crypto::sr25519_generate; use sp_runtime::MultiSignature; -use sp_std::{num::NonZeroU32, vec::Vec}; +use sp_std::{collections::btree_set::BTreeSet, num::NonZeroU32, vec::Vec}; use crate::*; @@ -45,20 +45,10 @@ where hash.into() } -/// sets parent to `None` if it is the root -fn parent_id_check( - root_id: T::DelegationNodeId, - parent_id: T::DelegationNodeId, -) -> Option { - if parent_id == root_id { - None - } else { - Some(parent_id) - } -} - /// add ctype to storage and root delegation -fn add_root_delegation(number: u32) -> Result<(DelegationTriplet, T::Hash), DispatchErrorWithPostInfo> +fn add_delegation_hierarchy( + number: u32, +) -> Result<(DelegationTriplet, T::Hash), DispatchErrorWithPostInfo> where T::AccountId: From, T::DelegationNodeId: From, @@ -66,16 +56,20 @@ where let root_public = sr25519_generate(KeyTypeId(*b"aura"), None); let root_acc: T::AccountId = root_public.into(); let ctype_hash = ::default(); - let root_id = generate_delegation_id::(number); + let hierarchy_root_id = generate_delegation_id::(number); ctype::Pallet::::add(RawOrigin::Signed(root_acc.clone()).into(), ctype_hash)?; - Pallet::::create_root(RawOrigin::Signed(root_acc.clone()).into(), root_id, ctype_hash)?; + Pallet::::create_hierarchy( + RawOrigin::Signed(root_acc.clone()).into(), + hierarchy_root_id, + ctype_hash, + )?; Ok(( DelegationTriplet:: { public: root_public, acc: root_acc, - delegation_id: root_id, + delegation_id: hierarchy_root_id, }, ctype_hash, )) @@ -107,11 +101,10 @@ where let delegation_acc_id: T::AccountId = delegation_acc_public.into(); let delegation_id = generate_delegation_id::(level * children_per_level.get() + c); - // only set parent if not root - let parent = parent_id_check::(root_id, parent_id); - // delegate signs delegation to parent - let hash: Vec = Pallet::::calculate_hash(&delegation_id, &root_id, &parent, &permissions).encode(); + let hash: Vec = + Pallet::::calculate_delegation_creation_hash(&delegation_id, &root_id, &parent_id, &permissions) + .encode(); let sig = sp_io::crypto::sr25519_sign(KeyTypeId(*b"aura"), &delegation_acc_public, hash.as_ref()) .ok_or("Error while building signature of delegation.")?; @@ -119,8 +112,7 @@ where let _ = Pallet::::add_delegation( RawOrigin::Signed(parent_acc_id.clone()).into(), delegation_id, - root_id, - parent, + parent_id, delegation_acc_id.clone().into(), permissions, MultiSignature::from(sig).encode(), @@ -169,58 +161,40 @@ where DelegationTriplet:: { public: root_public, acc: root_acc, - delegation_id: root_id, + delegation_id: hierarchy_id, }, _, - ) = add_root_delegation::(0)?; + ) = add_delegation_hierarchy::(0)?; // iterate levels and start with parent == root let (leaf_acc_public, _, leaf_id) = add_children::( - root_id, - root_id, + hierarchy_id, + hierarchy_id, root_public, root_acc, permissions, levels, children_per_level, )?; - Ok((root_public, root_id, leaf_acc_public, leaf_id)) + Ok((root_public, hierarchy_id, leaf_acc_public, leaf_id)) } benchmarks! { where_clause { where T: core::fmt::Debug, T::AccountId: From + Into, T::DelegationNodeId: From, ::Origin: From::DelegationEntityId>> } - create_root { + create_hierarchy { let caller: T::AccountId = account("caller", 0, SEED); let ctype = ::default(); let delegation = generate_delegation_id::(0); ctype::Pallet::::add(RawOrigin::Signed(caller.clone()).into(), ctype)?; }: _(RawOrigin::Signed(caller), delegation, ctype) verify { - assert!(Roots::::contains_key(delegation)); - } - - revoke_root { - let r in 1 .. T::MaxRevocations::get(); - let (root_acc, root_id, leaf_acc, leaf_id) = setup_delegations::(r, ONE_CHILD_PER_LEVEL.expect(">0"), Permissions::DELEGATE)?; - let root_acc_id: T::AccountId = root_acc.into(); - }: _(RawOrigin::Signed(root_acc_id.clone()), root_id, r) - verify { - assert!(Roots::::contains_key(root_id)); - let root_delegation = Roots::::get(root_id).ok_or("Missing root delegation")?; - assert_eq!(root_delegation.owner, root_acc_id.into()); - assert!(root_delegation.revoked); - - assert!(Delegations::::contains_key(leaf_id)); - let leaf_delegation = Delegations::::get(leaf_id).ok_or("Missing leaf delegation")?; - assert_eq!(leaf_delegation.root_id, root_id); - assert_eq!(leaf_delegation.owner, T::AccountId::from(leaf_acc).into()); - assert!(leaf_delegation.revoked); + assert!(DelegationHierarchies::::contains_key(delegation)); } add_delegation { // do setup - let (_, root_id, leaf_acc, leaf_id) = setup_delegations::(1, ONE_CHILD_PER_LEVEL.expect(">0"), Permissions::DELEGATE)?; + let (_, hierarchy_id, leaf_acc, leaf_id) = setup_delegations::(1, ONE_CHILD_PER_LEVEL.expect(">0"), Permissions::DELEGATE)?; // add one more delegation let delegate_acc_public = sr25519_generate( @@ -228,17 +202,17 @@ benchmarks! { None ); let delegation_id = generate_delegation_id::(u32::MAX); - let parent_id = parent_id_check::(root_id, leaf_id); + let parent_id = leaf_id; let perm: Permissions = Permissions::ATTEST | Permissions::DELEGATE; - let hash_root = Pallet::::calculate_hash(&delegation_id, &root_id, &parent_id, &perm); + let hash_root = Pallet::::calculate_delegation_creation_hash(&delegation_id, &hierarchy_id, &parent_id, &perm); let sig = sp_io::crypto::sr25519_sign(KeyTypeId(*b"aura"), &delegate_acc_public, hash_root.as_ref()).ok_or("Error while building signature of delegation.")?; let delegate_acc_id: T::AccountId = delegate_acc_public.into(); let leaf_acc_id: T::AccountId = leaf_acc.into(); - }: _(RawOrigin::Signed(leaf_acc_id), delegation_id, root_id, parent_id, delegate_acc_id.into(), perm, MultiSignature::from(sig).encode()) + }: _(RawOrigin::Signed(leaf_acc_id), delegation_id, parent_id, delegate_acc_id.into(), perm, MultiSignature::from(sig).encode()) verify { - assert!(Delegations::::contains_key(delegation_id)); + assert!(DelegationNodes::::contains_key(delegation_id)); } // worst case #1: revoke a child of the root delegation @@ -247,21 +221,22 @@ benchmarks! { revoke_delegation_root_child { let r in 1 .. T::MaxRevocations::get(); let c in 1 .. T::MaxParentChecks::get(); - let (_, root_id, leaf_acc, leaf_id) = setup_delegations::(r, ONE_CHILD_PER_LEVEL.expect(">0"), Permissions::DELEGATE)?; - let children: Vec = Children::::get(root_id).unwrap_or_default(); - let child_id: T::DelegationNodeId = *children.get(0).ok_or("Root should have children")?; - let child_delegation = Delegations::::get(child_id).ok_or("Child of root should have delegation id")?; - }: revoke_delegation(RawOrigin::Signed(child_delegation.owner.clone()), child_id, c, r) + let (_, hierarchy_id, leaf_acc, leaf_id) = setup_delegations::(r, ONE_CHILD_PER_LEVEL.expect(">0"), Permissions::DELEGATE)?; + let root_node = DelegationNodes::::get(hierarchy_id).expect("Root hierarchy node should be present on chain."); + let children: BTreeSet = root_node.children; + let child_id: T::DelegationNodeId = *children.iter().next().ok_or("Root should have children")?; + let child_delegation = DelegationNodes::::get(child_id).ok_or("Child of root should have delegation id")?; + }: revoke_delegation(RawOrigin::Signed(child_delegation.details.owner.clone()), child_id, c, r) verify { - assert!(Delegations::::contains_key(child_id)); - let DelegationNode:: { revoked, .. } = Delegations::::get(leaf_id).ok_or("Child of root should have delegation id")?; - assert!(revoked); - - assert!(Delegations::::contains_key(leaf_id)); - let leaf_delegation = Delegations::::get(leaf_id).ok_or("Missing leaf delegation")?; - assert_eq!(leaf_delegation.root_id, root_id); - assert_eq!(leaf_delegation.owner, T::AccountId::from(leaf_acc).into()); - assert!(leaf_delegation.revoked); + assert!(DelegationNodes::::contains_key(child_id)); + let DelegationNode:: { details, .. } = DelegationNodes::::get(leaf_id).ok_or("Child of root should have delegation id")?; + assert!(details.revoked); + + assert!(DelegationNodes::::contains_key(leaf_id)); + let leaf_delegation = DelegationNodes::::get(leaf_id).ok_or("Missing leaf delegation")?; + assert_eq!(leaf_delegation.hierarchy_root_id, hierarchy_id); + assert_eq!(leaf_delegation.details.owner, T::AccountId::from(leaf_acc).into()); + assert!(leaf_delegation.details.revoked); } // TODO: Might want to add variant iterating over children instead of depth at some later point @@ -274,9 +249,9 @@ benchmarks! { let (root_acc, _, _, leaf_id) = setup_delegations::(c, ONE_CHILD_PER_LEVEL.expect(">0"), Permissions::DELEGATE)?; }: revoke_delegation(RawOrigin::Signed(T::AccountId::from(root_acc).into()), leaf_id, c, r) verify { - assert!(Delegations::::contains_key(leaf_id)); - let DelegationNode:: { revoked, .. } = Delegations::::get(leaf_id).ok_or("Child of root should have delegation id")?; - assert!(revoked); + assert!(DelegationNodes::::contains_key(leaf_id)); + let DelegationNode:: { details, .. } = DelegationNodes::::get(leaf_id).ok_or("Child of root should have delegation id")?; + assert!(details.revoked); } // TODO: Might want to add variant iterating over children instead of depth at some later point } diff --git a/pallets/delegation/src/default_weights.rs b/pallets/delegation/src/default_weights.rs index a5f96986d2..6bee212825 100644 --- a/pallets/delegation/src/default_weights.rs +++ b/pallets/delegation/src/default_weights.rs @@ -19,29 +19,24 @@ //! Autogenerated weights for delegation //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 3.0.0 -//! DATE: 2021-06-11, STEPS: {{cmd.steps}}\, REPEAT: {{cmd.repeat}}\, LOW RANGE: {{cmd.lowest_range_values}}\, HIGH RANGE: {{cmd.highest_range_values}}\ +//! DATE: 2021-07-21, STEPS: {{cmd.steps}}\, REPEAT: {{cmd.repeat}}\, LOW RANGE: {{cmd.lowest_range_values}}\, HIGH RANGE: {{cmd.highest_range_values}}\ //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 // Executed Command: -// ./kilt-parachain +// target/release/kilt-parachain // benchmark -// --chain -// dev -// --execution -// wasm -// --wasm-execution -// compiled -// --pallet -// delegation -// --extrinsic -// * -// --steps -// 1 -// --repeat -// 10 +// --chain=dev +// --execution=wasm +// --wasm-execution=Compiled // --heap-pages=4096 -// --output=../../pallets/delegation/src/default_weights.rs -// --template=../../.maintain/weight-template.hbs +// --extrinsic=* +// --pallet=delegation +// --steps=1 +// --repeat=20 +// --template +// .maintain/weight-template.hbs +// --output +// pallets/delegation/src/default_weights.rs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -53,8 +48,7 @@ use sp_std::marker::PhantomData; /// Weight functions needed for delegation. pub trait WeightInfo { - fn create_root() -> Weight; - fn revoke_root(r: u32, ) -> Weight; + fn create_hierarchy() -> Weight; fn add_delegation() -> Weight; fn revoke_delegation_root_child(r: u32, c: u32, ) -> Weight; fn revoke_delegation_leaf(r: u32, c: u32, ) -> Weight; @@ -63,38 +57,30 @@ pub trait WeightInfo { /// Weights for delegation using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - fn create_root() -> Weight { - (22_442_000_u64) + fn create_hierarchy() -> Weight { + (24_797_000_u64) .saturating_add(T::DbWeight::get().reads(2_u64)) - .saturating_add(T::DbWeight::get().writes(1_u64)) - } - fn revoke_root(r: u32, ) -> Weight { - (24_418_000_u64) - // Standard Error: 29_000 - .saturating_add((17_591_000_u64).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(2_u64)) - .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(r as Weight))) - .saturating_add(T::DbWeight::get().writes(1_u64)) - .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(r as Weight))) + .saturating_add(T::DbWeight::get().writes(2_u64)) } fn add_delegation() -> Weight { - (83_497_000_u64) - .saturating_add(T::DbWeight::get().reads(4_u64)) + (80_841_000_u64) + .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } fn revoke_delegation_root_child(r: u32, _c: u32, ) -> Weight { - (11_210_000_u64) - // Standard Error: 55_000 - .saturating_add((17_485_000_u64).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(r as Weight))) + (17_804_000_u64) + // Standard Error: 94_000 + .saturating_add((17_445_000_u64).saturating_mul(r as Weight)) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(r as Weight))) } fn revoke_delegation_leaf(r: u32, c: u32, ) -> Weight { - (27_413_000_u64) - // Standard Error: 30_000 - .saturating_add((111_000_u64).saturating_mul(r as Weight)) - // Standard Error: 30_000 - .saturating_add((4_692_000_u64).saturating_mul(c as Weight)) + (31_213_000_u64) + // Standard Error: 61_000 + .saturating_add((327_000_u64).saturating_mul(r as Weight)) + // Standard Error: 61_000 + .saturating_add((5_210_000_u64).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(c as Weight))) .saturating_add(T::DbWeight::get().writes(1_u64)) @@ -103,38 +89,30 @@ impl WeightInfo for SubstrateWeight { // For backwards compatibility and tests impl WeightInfo for () { - fn create_root() -> Weight { - (22_442_000_u64) + fn create_hierarchy() -> Weight { + (24_797_000_u64) .saturating_add(RocksDbWeight::get().reads(2_u64)) - .saturating_add(RocksDbWeight::get().writes(1_u64)) - } - fn revoke_root(r: u32, ) -> Weight { - (24_418_000_u64) - // Standard Error: 29_000 - .saturating_add((17_591_000_u64).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(2_u64)) - .saturating_add(RocksDbWeight::get().reads((2_u64).saturating_mul(r as Weight))) - .saturating_add(RocksDbWeight::get().writes(1_u64)) - .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(r as Weight))) + .saturating_add(RocksDbWeight::get().writes(2_u64)) } fn add_delegation() -> Weight { - (83_497_000_u64) - .saturating_add(RocksDbWeight::get().reads(4_u64)) + (80_841_000_u64) + .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } fn revoke_delegation_root_child(r: u32, _c: u32, ) -> Weight { - (11_210_000_u64) - // Standard Error: 55_000 - .saturating_add((17_485_000_u64).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads((2_u64).saturating_mul(r as Weight))) + (17_804_000_u64) + // Standard Error: 94_000 + .saturating_add((17_445_000_u64).saturating_mul(r as Weight)) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(r as Weight))) } fn revoke_delegation_leaf(r: u32, c: u32, ) -> Weight { - (27_413_000_u64) - // Standard Error: 30_000 - .saturating_add((111_000_u64).saturating_mul(r as Weight)) - // Standard Error: 30_000 - .saturating_add((4_692_000_u64).saturating_mul(c as Weight)) + (31_213_000_u64) + // Standard Error: 61_000 + .saturating_add((327_000_u64).saturating_mul(r as Weight)) + // Standard Error: 61_000 + .saturating_add((5_210_000_u64).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(c as Weight))) .saturating_add(RocksDbWeight::get().writes(1_u64)) diff --git a/pallets/delegation/src/delegation_hierarchy.rs b/pallets/delegation/src/delegation_hierarchy.rs index b0eee43d48..1f55ed5833 100644 --- a/pallets/delegation/src/delegation_hierarchy.rs +++ b/pallets/delegation/src/delegation_hierarchy.rs @@ -18,6 +18,8 @@ use bitflags::bitflags; use codec::{Decode, Encode}; +use ctype::CtypeHashOf; +use sp_std::collections::btree_set::BTreeSet; use crate::*; @@ -52,87 +54,88 @@ impl Default for Permissions { } } -/// A node representing a delegation hierarchy root. +/// A node in a delegation hierarchy. +/// +/// For quicker lookups of the hierarchy details, all nodes maintain a direct +/// link to the hierarchy root node. Furthermore, all nodes have a parent except +/// the root nodes, which point to themselves for the hierarchy root node link. #[derive(Clone, Debug, Encode, Decode, PartialEq)] -pub struct DelegationRoot { - /// The hash of the CType that delegated attesters within this trust - /// hierarchy can attest. - pub ctype_hash: CtypeHashOf, - /// The identifier of the root owner. - pub owner: DelegatorIdOf, - /// The flag indicating whether the root has been revoked or not. - pub revoked: bool, +pub struct DelegationNode { + /// The ID of the delegation hierarchy the node is part of. + pub hierarchy_root_id: DelegationNodeIdOf, + /// The ID of the parent. For all but root nodes this is not None. + pub parent: Option>, + /// The set of IDs of all the children nodes. + pub children: BTreeSet>, + /// The additional information attached to the delegation node. + pub details: DelegationDetails, } -impl DelegationRoot { - pub fn new(ctype_hash: CtypeHashOf, owner: DelegatorIdOf) -> Self { - DelegationRoot { - ctype_hash, - owner, - revoked: false, +impl DelegationNode { + /// Creates a new delegation root node with the given ID and delegation + /// details. + pub fn new_root_node(id: DelegationNodeIdOf, details: DelegationDetails) -> Self { + Self { + hierarchy_root_id: id, + parent: None, + children: BTreeSet::new(), + details, } } + + /// Creates a new delegation node under the given hierarchy ID, with the + /// given parent and delegation details. + pub fn new_node( + hierarchy_root_id: DelegationNodeIdOf, + parent: DelegationNodeIdOf, + details: DelegationDetails, + ) -> Self { + Self { + hierarchy_root_id, + parent: Some(parent), + children: BTreeSet::new(), + details, + } + } + + /// Adds a node by its ID to the current node's children. + pub fn add_child(&mut self, child_id: DelegationNodeIdOf) { + self.children.insert(child_id); + } } -/// A node representing a node in the delegation hierarchy. +/// Delegation information attached to delegation nodes. #[derive(Clone, Debug, Encode, Decode, PartialEq)] -pub struct DelegationNode { - /// The ID of the delegation hierarchy root. - pub root_id: DelegationNodeIdOf, - /// \[OPTIONAL\] The ID of the parent node. If None, the node is - /// considered a direct child of the root node. - pub parent: Option>, - /// The identifier of the owner of the delegation node, i.e., the delegate. +pub struct DelegationDetails { + /// The owner of the delegation (and its node). pub owner: DelegatorIdOf, - /// The permission flags for the operations the delegate is allowed to - /// perform. - pub permissions: Permissions, - /// The flag indicating whether the delegation has been revoked or not. + /// Status indicating whether the delegation has been revoked (true) or not + /// (false). pub revoked: bool, + /// The set of permissions associated with the delegation. + pub permissions: Permissions, } -impl DelegationNode { - /// Create a new delegation node that is a direct descendent of the - /// given root. +impl DelegationDetails { + /// Creates new delegation details including the given owner. /// - /// * root_id: the root node ID this node will be a child of - /// * owner: the identifier of the owner of the new delegation, i.e., the - /// new delegate - /// * permissions: the permission flags for the operations the delegate is - /// allowed to perform - pub fn new_root_child(root_id: DelegationNodeIdOf, owner: DelegatorIdOf, permissions: Permissions) -> Self { - DelegationNode { - root_id, + /// The default revocation status is false and all permissions are granted + /// by default. + pub fn default_with_owner(owner: DelegatorIdOf) -> Self { + Self { owner, - permissions, + permissions: Permissions::all(), revoked: false, - parent: None, } } +} - /// Creates a new delegation node that is a direct descendent of the - /// given node. - /// - /// * root_id: the root node ID this node will be a child of - /// * parent - the parent node ID this node will be a child of - /// * owner: the identifier of the owner of the new delegation, i.e., the - /// new delegate - /// * permissions: the permission flags for the operations the delegate is - /// allowed to perform - pub fn new_node_child( - root_id: DelegationNodeIdOf, - parent: DelegationNodeIdOf, - owner: DelegatorIdOf, - permissions: Permissions, - ) -> Self { - DelegationNode { - root_id, - parent: Some(parent), - owner, - permissions, - revoked: false, - } - } +/// The details associated with a delegation hierarchy. +#[derive(Clone, Debug, Encode, Decode, Eq, PartialEq, Ord, PartialOrd)] +pub struct DelegationHierarchyDetails { + /// The authorised CTYPE hash that attesters can attest using this + /// delegation hierarchy. + pub ctype_hash: CtypeHashOf, } /// The result that the delegation pallet expects from the implementer of the diff --git a/pallets/delegation/src/deprecated.rs b/pallets/delegation/src/deprecated.rs new file mode 100644 index 0000000000..0f6ea788b3 --- /dev/null +++ b/pallets/delegation/src/deprecated.rs @@ -0,0 +1,103 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2021 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 + +/// Deprecated types used in version 1. +pub(crate) mod v1 { + use codec::{Decode, Encode}; + + use crate::*; + + #[derive(Clone, Debug, Encode, Decode, PartialEq)] + pub struct DelegationRoot { + pub(crate) ctype_hash: CtypeHashOf, + pub(crate) owner: DelegatorIdOf, + pub(crate) revoked: bool, + } + + impl DelegationRoot { + #[cfg(test)] + pub(crate) fn new(ctype_hash: CtypeHashOf, owner: DelegatorIdOf) -> Self { + DelegationRoot { + ctype_hash, + owner, + revoked: false, + } + } + } + + #[derive(Clone, Debug, Encode, Decode, PartialEq)] + pub struct DelegationNode { + pub(crate) root_id: DelegationNodeIdOf, + pub(crate) parent: Option>, + pub(crate) owner: DelegatorIdOf, + pub(crate) permissions: Permissions, + pub(crate) revoked: bool, + } + + impl DelegationNode { + #[cfg(test)] + pub(crate) fn new_root_child( + root_id: DelegationNodeIdOf, + owner: DelegatorIdOf, + permissions: Permissions, + ) -> Self { + DelegationNode { + root_id, + owner, + permissions, + revoked: false, + parent: None, + } + } + + #[cfg(test)] + pub(crate) fn new_node_child( + root_id: DelegationNodeIdOf, + parent: DelegationNodeIdOf, + owner: DelegatorIdOf, + permissions: Permissions, + ) -> Self { + DelegationNode { + root_id, + parent: Some(parent), + owner, + permissions, + revoked: false, + } + } + } + + pub(crate) mod storage { + use frame_support::{decl_module, decl_storage}; + use sp_std::prelude::*; + + use super::*; + + decl_module! { + pub struct OldPallet for enum Call where origin: T::Origin {} + } + + decl_storage! { + trait Store for OldPallet as Delegation { + pub(crate) Roots get(fn roots): map hasher(blake2_128_concat) DelegationNodeIdOf => Option>; + pub(crate) Delegations get(fn delegations): map hasher(blake2_128_concat) DelegationNodeIdOf => Option>; + pub(crate) Children get(fn children): map hasher(blake2_128_concat) DelegationNodeIdOf => Option>>; + } + } + } +} diff --git a/pallets/delegation/src/lib.rs b/pallets/delegation/src/lib.rs index 54bef58ccc..ce3229ac82 100644 --- a/pallets/delegation/src/lib.rs +++ b/pallets/delegation/src/lib.rs @@ -75,6 +75,7 @@ pub mod default_weights; pub mod delegation_hierarchy; +pub mod migrations; #[cfg(any(feature = "mock", test))] pub mod mock; @@ -85,14 +86,19 @@ pub mod benchmarking; #[cfg(test)] mod tests; +mod deprecated; + pub use crate::{default_weights::WeightInfo, delegation_hierarchy::*, pallet::*}; use frame_support::{ensure, pallet_prelude::Weight, traits::Get}; use sp_runtime::{traits::Hash, DispatchError}; use sp_std::vec::Vec; +use migrations::*; + #[frame_support::pallet] pub mod pallet { + use super::*; use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; @@ -121,7 +127,7 @@ pub mod pallet { Signature = Vec, >; type DelegationEntityId: Parameter; - type DelegationNodeId: Parameter + Copy + AsRef<[u8]>; + type DelegationNodeId: Parameter + Copy + AsRef<[u8]> + Eq + PartialEq + Ord + PartialOrd; type EnsureOrigin: EnsureOrigin, ::Origin>; type Event: From> + IsType<::Event>; #[pallet::constant] @@ -138,39 +144,51 @@ pub mod pallet { pub struct Pallet(_); #[pallet::hooks] - impl Hooks> for Pallet {} + impl Hooks> for Pallet { + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result<(), &'static str> { + migrations::DelegationStorageMigrator::::pre_migrate() + } - /// Delegation root nodes stored on chain. - /// - /// It maps from a root node ID to the full root node. + fn on_runtime_upgrade() -> Weight { + migrations::DelegationStorageMigrator::::migrate() + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade() -> Result<(), &'static str> { + migrations::DelegationStorageMigrator::::post_migrate() + } + } + + /// Contains the latest storage version deployed. #[pallet::storage] - #[pallet::getter(fn roots)] - pub type Roots = StorageMap<_, Blake2_128Concat, DelegationNodeIdOf, DelegationRoot>; + #[pallet::getter(fn last_version_migration_used)] + pub(crate) type StorageVersion = StorageValue<_, DelegationStorageVersion, ValueQuery>; /// Delegation nodes stored on chain. /// - /// It maps from a node ID to the full delegation node. + /// It maps from a node ID to the node details. #[pallet::storage] - #[pallet::getter(fn delegations)] - pub type Delegations = StorageMap<_, Blake2_128Concat, DelegationNodeIdOf, DelegationNode>; + #[pallet::getter(fn delegation_nodes)] + pub type DelegationNodes = StorageMap<_, Blake2_128Concat, DelegationNodeIdOf, DelegationNode>; - /// Children delegation nodes. + /// Delegation hierarchies stored on chain. /// - /// It maps from a delegation node ID, including the root node, to the list - /// of children nodes, sorted by time of creation. + /// It maps for a (root) node ID to the hierarchy details. #[pallet::storage] - #[pallet::getter(fn children)] - pub type Children = StorageMap<_, Blake2_128Concat, DelegationNodeIdOf, Vec>>; + #[pallet::getter(fn delegation_hierarchies)] + pub type DelegationHierarchies = + StorageMap<_, Blake2_128Concat, DelegationNodeIdOf, DelegationHierarchyDetails>; #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { - /// A new root has been created. - /// \[creator ID, root node ID, CType hash\] - RootCreated(DelegatorIdOf, DelegationNodeIdOf, CtypeHashOf), - /// A root has been revoked. + /// A new hierarchy has been created. + /// \[creator ID, root node ID, CTYPE hash\] + HierarchyCreated(DelegatorIdOf, DelegationNodeIdOf, CtypeHashOf), + /// A hierarchy has been revoked. /// \[revoker ID, root node ID\] - RootRevoked(DelegatorIdOf, DelegationNodeIdOf), + HierarchyRevoked(DelegatorIdOf, DelegationNodeIdOf), /// A new delegation has been created. /// \[creator ID, root node ID, delegation node ID, parent node ID, /// delegate ID, permissions\] @@ -178,7 +196,7 @@ pub mod pallet { DelegatorIdOf, DelegationNodeIdOf, DelegationNodeIdOf, - Option>, + DelegationNodeIdOf, DelegatorIdOf, Permissions, ), @@ -198,19 +216,21 @@ pub mod pallet { DelegationNotFound, /// No delegate with the given ID stored on chain. DelegateNotFound, - /// There is already a root node with the same ID stored on chain. - RootAlreadyExists, - /// No root delegation with the given ID stored on chain. - RootNotFound, + /// There is already a hierarchy with the same ID stored on chain. + HierarchyAlreadyExists, + /// No hierarchy with the given ID stored on chain. + HierarchyNotFound, /// Max number of nodes checked without verifying the given condition. MaxSearchDepthReached, /// Max number of nodes checked without verifying the given condition. NotOwnerOfParentDelegation, /// The delegation creator is not allowed to write the delegation /// because he is not the owner of the delegation root node. - NotOwnerOfRootDelegation, + NotOwnerOfDelegationHierarchy, /// No parent delegation with the given ID stored on chain. ParentDelegationNotFound, + /// The parent delegation has previously been revoked. + ParentDelegationRevoked, /// The delegation revoker is not allowed to revoke the delegation. UnauthorizedRevocation, /// The delegation creator is not allowed to create the delegation. @@ -246,15 +266,18 @@ pub mod pallet { /// - Reads: [Origin Account], Roots, CTypes /// - Writes: Roots /// # - #[pallet::weight(::WeightInfo::create_root())] - pub fn create_root( + #[pallet::weight(::WeightInfo::create_hierarchy())] + pub fn create_hierarchy( origin: OriginFor, - root_id: DelegationNodeIdOf, + root_node_id: DelegationNodeIdOf, ctype_hash: CtypeHashOf, ) -> DispatchResult { let creator = ::EnsureOrigin::ensure_origin(origin)?; - ensure!(!>::contains_key(&root_id), Error::::RootAlreadyExists); + ensure!( + !>::contains_key(&root_node_id), + Error::::HierarchyAlreadyExists + ); ensure!( >::contains_key(&ctype_hash), @@ -262,9 +285,14 @@ pub mod pallet { ); log::debug!("insert Delegation Root"); - >::insert(&root_id, DelegationRoot::new(ctype_hash, creator.clone())); - Self::deposit_event(Event::RootCreated(creator, root_id, ctype_hash)); + Self::create_and_store_new_hierarchy( + root_node_id, + DelegationHierarchyDetails:: { ctype_hash }, + creator.clone(), + ); + + Self::deposit_event(Event::HierarchyCreated(creator, root_node_id, ctype_hash)); Ok(()) } @@ -298,16 +326,24 @@ pub mod pallet { pub fn add_delegation( origin: OriginFor, delegation_id: DelegationNodeIdOf, - root_id: DelegationNodeIdOf, - parent_id: Option>, + parent_id: DelegationNodeIdOf, delegate: DelegatorIdOf, permissions: Permissions, delegate_signature: DelegateSignatureTypeOf, ) -> DispatchResult { let delegator = ::EnsureOrigin::ensure_origin(origin)?; + ensure!( + !>::contains_key(&delegation_id), + Error::::DelegationAlreadyExists + ); + + let parent_node = >::get(&parent_id).ok_or(Error::::ParentDelegationNotFound)?; + let hierarchy_root_id = parent_node.hierarchy_root_id; + // Calculate the hash root - let hash_root = Self::calculate_hash(&delegation_id, &root_id, &parent_id, &permissions); + let hash_root = + Self::calculate_delegation_creation_hash(&delegation_id, &hierarchy_root_id, &parent_id, &permissions); // Verify that the hash root signature is correct. DelegationSignatureVerificationOf::::verify(&delegate, &hash_root.encode(), &delegate_signature) @@ -316,57 +352,38 @@ pub mod pallet { SignatureVerificationError::SignatureInvalid => Error::::InvalidDelegateSignature, })?; + // Check if the parent's delegate is the creator of this delegation node... ensure!( - !>::contains_key(&delegation_id), - Error::::DelegationAlreadyExists + parent_node.details.owner == delegator, + Error::::NotOwnerOfParentDelegation + ); + // ... and that the node has not been revoked... + ensure!(!parent_node.details.revoked, Error::::ParentDelegationRevoked); + // ... and that has permission to delegate + ensure!( + (parent_node.details.permissions & Permissions::DELEGATE) == Permissions::DELEGATE, + Error::::UnauthorizedDelegation ); - let root = >::get(&root_id).ok_or(Error::::RootNotFound)?; - - // Computes the delegation parent. Either the given parent (if allowed) or the - // root node. - let parent = if let Some(parent_id) = parent_id { - let parent_node = >::get(&parent_id).ok_or(Error::::ParentDelegationNotFound)?; - - // Check if the parent's delegate is the creator of this delegation node... - ensure!(parent_node.owner == delegator, Error::::NotOwnerOfParentDelegation); - // ... and has permission to delegate - ensure!( - (parent_node.permissions & Permissions::DELEGATE) == Permissions::DELEGATE, - Error::::UnauthorizedDelegation - ); - - log::debug!("insert Delegation with parent"); - >::insert( - &delegation_id, - DelegationNode::::new_node_child(root_id, parent_id, delegate.clone(), permissions), - ); - - // Return parent_id as the result of this if branch - parent_id - } else { - // Check if the creator of this delegation node is the creator of the root node - // (as no parent is given) - ensure!(root.owner == delegator, Error::::NotOwnerOfRootDelegation); - - log::debug!("insert Delegation without parent"); - >::insert( - &delegation_id, - DelegationNode::::new_root_child(root_id, delegate.clone(), permissions), - ); - - // Return node_id as the result of this if branch - root_id - }; - - // Regardless of the node returned as parent, add the new node as a child of - // that node - Self::add_child(delegation_id, parent); + Self::store_delegation_under_parent( + delegation_id, + DelegationNode::new_node( + hierarchy_root_id, + parent_id, + DelegationDetails { + owner: delegate.clone(), + permissions, + revoked: false, + }, + ), + parent_id, + parent_node, + ); Self::deposit_event(Event::DelegationCreated( delegator, + hierarchy_root_id, delegation_id, - root_id, parent_id, delegate, permissions, @@ -375,62 +392,8 @@ pub mod pallet { Ok(()) } - /// Revoke a delegation root and the whole delegation hierarchy below. - /// - /// Revoking a delegation root results in the whole trust hierarchy - /// being revoked. Nevertheless, revocation starts from the leave nodes - /// upwards, so if the operation ends prematurely because it runs out of - /// gas, the delegation state would be consistent as no child would - /// "survive" its parent. As a consequence, if the root node is revoked, - /// the whole trust hierarchy is to be considered revoked. - /// - /// The dispatch origin must be `DelegationEntityId`. - /// - /// Emits `RootRevoked` and C * `DelegationRevoked`. - /// - /// # - /// Weight: O(C) where C is the number of children of the root which is - /// bounded by `max_children`. - /// - Reads: [Origin Account], Roots, C * Delegations, C * Children. - /// - Writes: Roots, C * Delegations - /// # - #[pallet::weight(::WeightInfo::revoke_root(*max_children))] - pub fn revoke_root( - origin: OriginFor, - root_id: DelegationNodeIdOf, - max_children: u32, - ) -> DispatchResultWithPostInfo { - let invoker = ::EnsureOrigin::ensure_origin(origin)?; - - let mut root = >::get(&root_id).ok_or(Error::::RootNotFound)?; - - ensure!(root.owner == invoker, Error::::UnauthorizedRevocation); - - ensure!( - max_children <= T::MaxRevocations::get(), - Error::::MaxRevocationsTooLarge - ); - - let consumed_weight: Weight = if !root.revoked { - // Recursively revoke all children - let (_, post_weight) = Self::revoke_children(&root_id, &invoker, max_children)?; - - // If we didn't return an ExceededRevocationBounds error, we can revoke the root - // too. - root.revoked = true; - >::insert(&root_id, root); - - post_weight.saturating_add(T::DbWeight::get().writes(1)) - } else { - 0 - }; - - Self::deposit_event(Event::RootRevoked(invoker, root_id)); - - Ok(Some(consumed_weight.saturating_add(T::DbWeight::get().reads(1))).into()) - } - - /// Revoke a delegation node and all its children. + /// Revoke a delegation node (potentially a root node) and all its + /// children. /// /// Revoking a delegation node results in the trust hierarchy starting /// from the given node being revoked. Nevertheless, revocation starts @@ -462,7 +425,7 @@ pub mod pallet { let invoker = ::EnsureOrigin::ensure_origin(origin)?; ensure!( - >::contains_key(&delegation_id), + >::contains_key(&delegation_id), Error::::DelegationNotFound ); @@ -471,16 +434,22 @@ pub mod pallet { Error::::MaxParentChecksTooLarge ); - let (authorized, parent_checks) = Self::is_delegating(&invoker, &delegation_id, max_parent_checks)?; - ensure!(authorized, Error::::UnauthorizedRevocation); - ensure!( max_revocations <= T::MaxRevocations::get(), Error::::MaxRevocationsTooLarge ); - // Revoke the delegation and recursively all of its children - let (revocation_checks, _) = Self::revoke(&delegation_id, &invoker, max_revocations)?; + let (authorized, parent_checks) = Self::is_delegating(&invoker, &delegation_id, max_parent_checks)?; + ensure!(authorized, Error::::UnauthorizedRevocation); + + // Revoke the delegation and recursively all of its children (add 1 to + // max_revocations to account for the node itself) + let (revocation_checks, _) = Self::revoke(&delegation_id, &invoker, max_revocations.saturating_add(1))?; + + // If the revoked node is a root node, emit also a HierarchyRevoked event. + if DelegationHierarchies::::contains_key(&delegation_id) { + Self::deposit_event(Event::HierarchyRevoked(invoker, delegation_id)); + } // Add worst case reads from `is_delegating` Ok(Some( @@ -494,28 +463,55 @@ pub mod pallet { } impl Pallet { - /// Calculate the hash of all values of a delegation transaction. + /// Calculate the hash of all values of a delegation creation transaction. /// /// # /// Weight: O(1) /// # - fn calculate_hash( + fn calculate_delegation_creation_hash( delegation_id: &DelegationNodeIdOf, root_id: &DelegationNodeIdOf, - parent_id: &Option>, + parent_id: &DelegationNodeIdOf, permissions: &Permissions, ) -> T::Hash { - // Add all values to an u8 vector + // Add all values to an u8 vector. let mut hashed_values: Vec = delegation_id.as_ref().to_vec(); hashed_values.extend_from_slice(root_id.as_ref()); - if let Some(parent) = parent_id { - hashed_values.extend_from_slice(parent.as_ref()) - } + hashed_values.extend_from_slice(parent_id.as_ref()); hashed_values.extend_from_slice(permissions.as_u8().as_ref()); // Hash the resulting vector T::Hashing::hash(&hashed_values) } + // Creates a new root node with the given details and store the new hierarchy in + // the hierarchies storage and the new root node in the nodes storage. + fn create_and_store_new_hierarchy( + root_id: DelegationNodeIdOf, + hierarchy_details: DelegationHierarchyDetails, + hierarchy_owner: DelegatorIdOf, + ) { + let root_node = DelegationNode::new_root_node(root_id, DelegationDetails::default_with_owner(hierarchy_owner)); + >::insert(root_id, root_node); + >::insert(root_id, hierarchy_details); + } + + // Adds the given node to the storage and updates the parent node to include the + // given node as child. + // + // This function assumes that the parent node is already stored on the chain. If + // not, the behaviour of the system is undefined. + fn store_delegation_under_parent( + delegation_id: DelegationNodeIdOf, + delegation_node: DelegationNode, + parent_id: DelegationNodeIdOf, + mut parent_node: DelegationNode, + ) { + >::insert(delegation_id, delegation_node); + // Add the new node as a child of that node + parent_node.add_child(delegation_id); + >::insert(parent_id, parent_node); + } + /// Check if an identity is the owner of the given delegation node or any /// node up the hierarchy, and if the delegation has not been yet revoked. /// @@ -535,34 +531,60 @@ impl Pallet { delegation: &DelegationNodeIdOf, max_parent_checks: u32, ) -> Result<(bool, u32), DispatchError> { - let delegation_node = >::get(delegation).ok_or(Error::::DelegationNotFound)?; + let delegation_node = >::get(delegation).ok_or(Error::::DelegationNotFound)?; // Check if the given account is the owner of the delegation and that the // delegation has not been removed - if &delegation_node.owner == identity { - Ok((!delegation_node.revoked, 0u32)) - } else { - // Counter is decreased regardless of whether we are checking the parent node - // next of the root node, as the root node is as a matter of fact the top node's - // parent. + if &delegation_node.details.owner == identity { + Ok((!delegation_node.details.revoked, 0u32)) + } else if let Some(parent) = delegation_node.parent { + // Only decrease (and perhaps fail) remaining_lookups if there are more parents + // to visit let remaining_lookups = max_parent_checks .checked_sub(1) .ok_or(Error::::MaxSearchDepthReached)?; - if let Some(parent) = delegation_node.parent { - // Recursively check upwards in hierarchy - Self::is_delegating(identity, &parent, remaining_lookups) - } else { - // Return whether the given account is the owner of the root and the root has - // not been revoked - let root = >::get(delegation_node.root_id).ok_or(Error::::RootNotFound)?; - Ok(( - (&root.owner == identity) && !root.revoked, - // safe because remaining lookups is at most max_parent_checks - max_parent_checks - remaining_lookups, - )) + // Recursively check upwards in hierarchy + Self::is_delegating(identity, &parent, remaining_lookups) + } else { + // Return false and return max_parent_checks as no other check is performed + Ok((false, max_parent_checks)) + } + } + + /// Revokes all children of a delegation. + /// Returns the number of revoked delegations and the consumed weight. + /// + /// # + /// Weight: O(C) where C is the number of children of the delegation node + /// which is bounded by `max_children`. + /// - Reads: C * Children, C * Delegations + /// - Writes: C * Delegations + /// # + fn revoke_children( + delegation: &DelegationNodeIdOf, + sender: &DelegatorIdOf, + max_revocations: u32, + ) -> Result<(u32, Weight), DispatchError> { + let mut revocations: u32 = 0; + let mut consumed_weight: Weight = 0; + if let Some(delegation_node) = >::get(delegation) { + // Iterate children and revoke all nodes + for child in delegation_node.children.iter() { + let remaining_revocations = max_revocations + .checked_sub(revocations) + .ok_or(Error::::ExceededRevocationBounds)?; + + // Check whether we ran out of gas + ensure!(remaining_revocations > 0, Error::::ExceededRevocationBounds); + + Self::revoke(child, sender, remaining_revocations).map(|(r, w)| { + revocations = revocations.saturating_add(r); + consumed_weight = consumed_weight.saturating_add(w); + })?; } } + Ok((revocations, consumed_weight.saturating_add(T::DbWeight::get().reads(1)))) } /// Revoke a delegation and all of its children recursively. @@ -583,11 +605,11 @@ impl Pallet { let mut revocations: u32 = 0; let mut consumed_weight: Weight = 0; // Retrieve delegation node from storage - let mut delegation_node = >::get(*delegation).ok_or(Error::::DelegationNotFound)?; + let mut delegation_node = >::get(*delegation).ok_or(Error::::DelegationNotFound)?; consumed_weight = consumed_weight.saturating_add(T::DbWeight::get().reads(1)); // Check if already revoked - if !delegation_node.revoked { + if !delegation_node.details.revoked { // First revoke all children recursively let remaining_revocations = max_revocations .checked_sub(1) @@ -602,8 +624,8 @@ impl Pallet { ensure!(revocations < max_revocations, Error::::ExceededRevocationBounds); // Set revoked flag and store delegation node - delegation_node.revoked = true; - >::insert(*delegation, delegation_node); + delegation_node.details.revoked = true; + >::insert(*delegation, delegation_node); consumed_weight = consumed_weight.saturating_add(T::DbWeight::get().writes(1)); // Deposit event that the delegation has been revoked Self::deposit_event(Event::DelegationRevoked(sender.clone(), *delegation)); @@ -611,56 +633,4 @@ impl Pallet { } Ok((revocations, consumed_weight)) } - - /// Revokes all children of a delegation. - /// Returns the number of revoked delegations and the consumed weight. - /// - /// # - /// Weight: O(C) where C is the number of children of the delegation node - /// which is bounded by `max_children`. - /// - Reads: C * Children, C * Delegations - /// - Writes: C * Delegations - /// # - fn revoke_children( - delegation: &DelegationNodeIdOf, - sender: &DelegatorIdOf, - max_revocations: u32, - ) -> Result<(u32, Weight), DispatchError> { - let mut revocations: u32 = 0; - let mut consumed_weight: Weight = 0; - // Check if there's a child vector in the storage - if let Some(children) = >::get(delegation) { - consumed_weight = consumed_weight.saturating_add(T::DbWeight::get().reads(1)); - - // Iterate child vector and revoke all nodes - for child in children { - let remaining_revocations = max_revocations - .checked_sub(revocations) - .ok_or(Error::::ExceededRevocationBounds)?; - - // Check whether we ran out of gas - ensure!(remaining_revocations > 0, Error::::ExceededRevocationBounds); - - Self::revoke(&child, sender, remaining_revocations).map(|(r, w)| { - revocations = revocations.saturating_add(r); - consumed_weight = consumed_weight.saturating_add(w); - })?; - } - } - Ok((revocations, consumed_weight.saturating_add(T::DbWeight::get().reads(1)))) - } - - /// Add a child node into the delegation hierarchy. - /// - /// # - /// Weight: O(1) - /// - Reads: Children - /// - Writes: Children - /// # - fn add_child(child: DelegationNodeIdOf, parent: DelegationNodeIdOf) { - // Get the children vector or initialize an empty one if none - let mut children = >::get(parent).unwrap_or_default(); - children.push(child); - >::insert(parent, children); - } } diff --git a/pallets/delegation/src/migrations.rs b/pallets/delegation/src/migrations.rs new file mode 100644 index 0000000000..b4a6b447e9 --- /dev/null +++ b/pallets/delegation/src/migrations.rs @@ -0,0 +1,223 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2021 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 codec::{Decode, Encode}; +use sp_std::marker::PhantomData; + +use crate::*; + +mod v1; + +/// A trait that allows version migrators to access the underlying pallet's +/// context, e.g., its Config trait. +/// +/// In this way, the migrator can access the pallet's storage and the pallet's +/// types directly. +pub trait VersionMigratorTrait { + #[cfg(feature = "try-runtime")] + fn pre_migrate(&self) -> Result<(), &str>; + fn migrate(&self) -> Weight; + #[cfg(feature = "try-runtime")] + fn post_migrate(&self) -> Result<(), &str>; +} + +/// Storage version of the delegation pallet. +#[derive(Copy, Clone, Encode, Eq, Decode, Ord, PartialEq, PartialOrd)] +pub enum DelegationStorageVersion { + V1, + V2, +} + +#[cfg(feature = "try-runtime")] +impl DelegationStorageVersion { + /// The latest storage version. + fn latest() -> Self { + Self::V2 + } +} + +// All nodes will default to this, which is not bad, as in case the "real" +// version is a later one (i.e. the node has been started with already the +// latest version), the migration will simply do nothing as there's nothing in +// the old storage entries to migrate from. +// +// It might get updated in the future when we know that no node is running this +// old version anymore. +impl Default for DelegationStorageVersion { + fn default() -> Self { + Self::V1 + } +} + +impl VersionMigratorTrait for DelegationStorageVersion { + // It runs the right pre_migrate logic depending on the current storage version. + #[cfg(feature = "try-runtime")] + fn pre_migrate(&self) -> Result<(), &str> { + match *self { + Self::V1 => v1::pre_migrate::(), + Self::V2 => Err("Already latest v2 version."), + } + } + + // It runs the righ migration logic depending on the current storage version. + fn migrate(&self) -> Weight { + match *self { + Self::V1 => v1::migrate::(), + Self::V2 => 0u64, + } + } + + // It runs the right post_migrate logic depending on the current storage + // version. + #[cfg(feature = "try-runtime")] + fn post_migrate(&self) -> Result<(), &str> { + match *self { + Self::V1 => v1::post_migrate::(), + Self::V2 => Err("Migration from v2 should have never happened in the first place."), + } + } +} + +/// The delegation pallet's storage migrator, which handles all version +/// migrations in a sequential fashion. +/// +/// If a node has missed on more than one upgrade, the migrator will apply the +/// needed migrations one after the other. Otherwise, if no migration is needed, +/// the migrator will simply not do anything. +pub struct DelegationStorageMigrator(PhantomData); + +impl DelegationStorageMigrator { + // Contains the migration sequence logic. + fn get_next_storage_version(current: DelegationStorageVersion) -> Option { + // If the version current deployed is at least v1, there is no more migrations + // to run (other than the one from v1). + match current { + DelegationStorageVersion::V1 => None, + DelegationStorageVersion::V2 => None, + } + } + + /// Checks whether the latest storage version deployed is lower than the + /// latest possible. + #[cfg(feature = "try-runtime")] + pub(crate) fn pre_migrate() -> Result<(), &'static str> { + ensure!( + StorageVersion::::get() < DelegationStorageVersion::latest(), + "Already the latest storage version." + ); + + // Don't need to check for any other pre_migrate, as in try-runtime it is also + // called in the migrate() function. Same applies for post_migrate checks for + // each version migrator. + + Ok(()) + } + + /// Applies all the needed migrations from the currently deployed version to + /// the latest possible, one after the other. + /// + /// It returns the total weight consumed by ALL the migrations applied. + pub(crate) fn migrate() -> Weight { + let mut current_version: Option = Some(StorageVersion::::get()); + // Weight for StorageVersion::get(). + let mut total_weight = T::DbWeight::get().reads(1); + + while let Some(ver) = current_version { + // If any of the needed migrations pre-checks fail, the whole chain panics + // (during tests). + #[cfg(feature = "try-runtime")] + if let Err(err) = >::pre_migrate(&ver) { + panic!("{:?}", err); + } + let consumed_weight = >::migrate(&ver); + total_weight = total_weight.saturating_add(consumed_weight); + // If any of the needed migrations post-checks fail, the whole chain panics + // (during tests). + #[cfg(feature = "try-runtime")] + if let Err(err) = >::post_migrate(&ver) { + panic!("{:?}", err); + } + // If more migrations should be applied, current_version will not be None. + current_version = Self::get_next_storage_version(ver); + } + + total_weight + } + + /// Checks whether the storage version after all the needed migrations match + /// the latest one. + #[cfg(feature = "try-runtime")] + pub(crate) fn post_migrate() -> Result<(), &'static str> { + ensure!( + StorageVersion::::get() == DelegationStorageVersion::latest(), + "Not updated to the latest version." + ); + + Ok(()) + } +} + +// Tests for the entire storage migrator. +#[cfg(test)] +mod tests { + use super::*; + + use crate::mock::Test as TestRuntime; + + #[test] + fn ok_from_v1_migration() { + let mut ext = mock::ExtBuilder::default() + .with_storage_version(DelegationStorageVersion::V1) + .build(None); + ext.execute_with(|| { + #[cfg(feature = "try-runtime")] + assert!( + DelegationStorageMigrator::::pre_migrate().is_ok(), + "Storage pre-migrate from v1 should not fail." + ); + + DelegationStorageMigrator::::migrate(); + + #[cfg(feature = "try-runtime")] + assert!( + DelegationStorageMigrator::::post_migrate().is_ok(), + "Storage post-migrate from v1 should not fail." + ); + }); + } + + #[test] + fn ok_from_default_migration() { + let mut ext = mock::ExtBuilder::default().build(None); + ext.execute_with(|| { + #[cfg(feature = "try-runtime")] + assert!( + DelegationStorageMigrator::::pre_migrate().is_ok(), + "Storage pre-migrate from default version should not fail." + ); + + DelegationStorageMigrator::::migrate(); + + #[cfg(feature = "try-runtime")] + assert!( + DelegationStorageMigrator::::post_migrate().is_ok(), + "Storage post-migrate from default version should not fail." + ); + }); + } +} diff --git a/pallets/delegation/src/migrations/v1.rs b/pallets/delegation/src/migrations/v1.rs new file mode 100644 index 0000000000..f69a115ec7 --- /dev/null +++ b/pallets/delegation/src/migrations/v1.rs @@ -0,0 +1,522 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2021 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::*; + +use frame_support::{IterableStorageMap, StorageMap, StoragePrefixedMap}; +use sp_runtime::traits::Zero; +use sp_std::collections::btree_map::BTreeMap; + +/// Checks whether the deployed storage version is v1. If not, it won't try +/// migrate any data. +/// +/// Since we have the default storage version to this one, it can happen +/// that new nodes will still try to perform runtime migrations. This is not +/// a problem as at the end of the day there will not be anything in the old +/// storage entries to migrate from. Hence, the "pseudo-"migration will +/// simply result in the update of the storage deployed version. +#[cfg(feature = "try-runtime")] +pub(crate) fn pre_migrate() -> Result<(), &'static str> { + ensure!( + StorageVersion::::get() == DelegationStorageVersion::V1, + "Current deployed version is not v1." + ); + + log::info!("Version storage migrating from v1 to v2"); + Ok(()) +} + +/// It migrates the old storage entries to the new ones. +/// +/// Specifically, for each entry in Roots, a new entry in +/// DelegationHierarchies + a new node in DelegationNodes is created. +/// Furthermore, nodes in Delegations are migrated to the new structure and +/// stored under DelegationNodes, with any children from the Children +/// storage entry added to the nodes under the children set. +pub(crate) fn migrate() -> Weight { + log::info!("v1 -> v2 delegation storage migrator started!"); + let mut total_weight = Weight::zero(); + + // Before being stored, the nodes are saved in a map so that after we go over + // all the nodes and the parent-child relationship in the storage, we can update + // the `parent` link of each node accordingly. Otherwise, we would need to save + // the node in the storage, and then retrieve it again to update the parent + // link. + let mut new_nodes: BTreeMap, DelegationNode> = BTreeMap::new(); + + // First iterate over the delegation roots and translate them to hierarchies. + total_weight = total_weight.saturating_add(migrate_roots::(&mut new_nodes)); + + // Then iterate over the regular delegation nodes. + total_weight = total_weight.saturating_add(migrate_nodes::(&mut new_nodes, total_weight)); + + // By now, all the children should have been correctly added to the nodes. + // We now need to modify all the nodes that are children by adding a reference + // to their parents. + total_weight = total_weight.saturating_add(finalize_children_nodes::(&mut new_nodes, total_weight)); + + StorageVersion::::set(DelegationStorageVersion::V2); + // Adds a write from StorageVersion::set() weight. + total_weight = total_weight.saturating_add(T::DbWeight::get().writes(1)); + log::debug!("Total weight consumed: {}", total_weight); + log::info!("v1 -> v2 delegation storage migrator finished!"); + + total_weight +} + +fn migrate_roots(new_nodes: &mut BTreeMap, DelegationNode>) -> Weight { + let total_weight = deprecated::v1::storage::Roots::::iter().fold( + Weight::zero(), + |mut total_weight, (old_root_id, old_root_node)| { + let new_hierarchy_details = DelegationHierarchyDetails:: { + ctype_hash: old_root_node.ctype_hash, + }; + let new_root_details = DelegationDetails:: { + owner: old_root_node.owner, + // Old roots did not have any permissions. So now we give them all permissions. + permissions: Permissions::all(), + revoked: old_root_node.revoked, + }; + // In here, we already check for potential children of root nodes and ONLY + // update the children information. The parent information will be updated + // later, when we know we have seen all the children already. + let mut new_root_node = DelegationNode::new_root_node(old_root_id, new_root_details); + if let Some(root_children_ids) = deprecated::v1::storage::Children::::take(old_root_id) { + new_root_node.children = root_children_ids.iter().copied().collect(); + } + // Add Children::take() weight + total_weight = total_weight.saturating_add(T::DbWeight::get().reads(1)); + + DelegationHierarchies::insert(old_root_id, new_hierarchy_details); + // Adds a read from Roots::drain() and a write from + // DelegationHierarchies::insert() weights + total_weight = total_weight.saturating_add(T::DbWeight::get().reads_writes(1, 1)); + // Add the node to the temporary map of nodes to be added at the end. + new_nodes.insert(old_root_id, new_root_node); + + total_weight + }, + ); + + // If runtime testing, makes sure that the old number of roots is reflected in + // the new number of nodes and hierarchies migrated. + #[cfg(feature = "try-runtime")] + { + assert_eq!( + deprecated::v1::storage::Roots::::iter().count(), + DelegationHierarchies::::iter().count(), + "The # of old roots does not match the # of new delegation hierarchies." + ); + + assert_eq!( + deprecated::v1::storage::Roots::::iter().count(), + new_nodes.iter().count(), + "The # of old roots does not match the current # of new delegation nodes." + ); + + log::info!( + "{} root(s) migrated.", + deprecated::v1::storage::Roots::::iter().count() + ); + } + + // Removes the whole Roots storage. + frame_support::migration::remove_storage_prefix( + deprecated::v1::storage::Roots::::module_prefix(), + deprecated::v1::storage::Roots::::storage_prefix(), + b"", + ); + + total_weight +} + +fn migrate_nodes( + new_nodes: &mut BTreeMap, DelegationNode>, + initial_weight: Weight, +) -> Weight { + let total_weight = deprecated::v1::storage::Delegations::::iter().fold( + initial_weight, + |mut total_weight, (old_node_id, old_node)| { + let new_node_details = DelegationDetails:: { + owner: old_node.owner, + permissions: old_node.permissions, + revoked: old_node.revoked, + }; + // In the old version, a parent None indicated the node is a child of the root. + let new_node_parent_id = old_node.parent.unwrap_or(old_node.root_id); + let mut new_node = DelegationNode::new_node(old_node.root_id, new_node_parent_id, new_node_details); + if let Some(children_ids) = deprecated::v1::storage::Children::::take(old_node_id) { + new_node.children = children_ids.iter().copied().collect(); + } + // Add Children::take() weight + total_weight = total_weight.saturating_add(T::DbWeight::get().reads(1)); + // Adds a read from Roots::drain() weight + total_weight = total_weight.saturating_add(T::DbWeight::get().reads(1)); + new_nodes.insert(old_node_id, new_node); + + total_weight + }, + ); + + // If runtime testing, makes sure that the old number of delegations is + // reflected in the new number of nodes that will be added to the storage. + #[cfg(feature = "try-runtime")] + { + assert_eq!( + deprecated::v1::storage::Delegations::::iter().count(), + new_nodes.iter().count().saturating_sub(DelegationHierarchies::::iter().count()), + "The # of old delegation nodes does not match the # of new delegation nodes (calculate as the total # of nodes - the # of delegation hierarchies)." + ); + + log::info!( + "{} regular node(s) migrated.", + deprecated::v1::storage::Delegations::::iter().count() + ); + } + + // Removes the whole Delegations and Children storages. + frame_support::migration::remove_storage_prefix( + deprecated::v1::storage::Delegations::::module_prefix(), + deprecated::v1::storage::Delegations::::storage_prefix(), + b"", + ); + frame_support::migration::remove_storage_prefix( + deprecated::v1::storage::Children::::module_prefix(), + deprecated::v1::storage::Children::::storage_prefix(), + b"", + ); + + total_weight +} + +fn finalize_children_nodes( + new_nodes: &mut BTreeMap, DelegationNode>, + initial_weight: Weight, +) -> Weight { + new_nodes + .clone() + .into_iter() + .fold(initial_weight, |mut total_weight, (new_node_id, new_node)| { + // Iterate over the children of every node and update their parent link. + new_node.children.iter().for_each(|child_id| { + new_nodes + .entry(*child_id) + .and_modify(|node| node.parent = Some(new_node_id)); + }); + // We can then finally insert the new delegation node in the storage as it won't + // be updated anymore during the migration. + DelegationNodes::::insert(new_node_id, new_node); + // Adds a write from DelegationNodes::insert() weight + total_weight = total_weight.saturating_add(T::DbWeight::get().writes(1)); + + total_weight + }) +} + +/// Checks whether the deployed storage version is v2 and whether any +/// parent-child link has gone missing. +#[cfg(feature = "try-runtime")] +pub(crate) fn post_migrate() -> Result<(), &'static str> { + ensure!( + StorageVersion::::get() == DelegationStorageVersion::V2, + "The version after deployment is not 2 as expected." + ); + ensure!( + verify_parent_children_integrity::(), + "Some parent-child relationship has been broken in the migration." + ); + log::info!("Version storage migrated from v1 to v2"); + Ok(()) +} + +// Verifies that for any node that has a parent, the parent includes that node +// in its children. +#[cfg(feature = "try-runtime")] +fn verify_parent_children_integrity() -> bool { + // If all's good and false is returned, returns true. + !DelegationNodes::::iter().any(|(node_id, node)| { + if let Some(parent_id) = node.parent { + if let Some(parent_node) = DelegationNodes::::get(parent_id) { + // True if the children set does not contain the parent ID + return !parent_node.children.contains(&node_id); + } else { + // If the parent node cannot be found, it is definitely an error, so return + // true. + return true; + } + } + // If all's good we keep returning false. + false + }) +} + +// Tests for the v1 storage migrator. +#[cfg(test)] +mod tests { + use sp_core::Pair; + + use super::*; + use crate::mock::Test as TestRuntime; + + #[test] + fn fail_version_higher() { + let mut ext = mock::ExtBuilder::default() + .with_storage_version(DelegationStorageVersion::V2) + .build(None); + ext.execute_with(|| { + #[cfg(feature = "try-runtime")] + assert!( + pre_migrate::().is_err(), + "Pre-migration for v1 should fail." + ); + }); + } + + #[test] + fn ok_no_delegations() { + let mut ext = mock::ExtBuilder::default() + .with_storage_version(DelegationStorageVersion::V1) + .build(None); + ext.execute_with(|| { + #[cfg(feature = "try-runtime")] + assert!( + pre_migrate::().is_ok(), + "Pre-migration for v1 should not fail." + ); + + migrate::(); + + #[cfg(feature = "try-runtime")] + assert!( + post_migrate::().is_ok(), + "Post-migration for v1 should not fail." + ); + }); + } + + #[test] + fn ok_only_root() { + let mut ext = mock::ExtBuilder::default() + .with_storage_version(DelegationStorageVersion::V1) + .build(None); + ext.execute_with(|| { + let alice = mock::get_ed25519_account(mock::get_alice_ed25519().public()); + let old_root_id = mock::get_delegation_id(true); + let old_root_node = + crate::deprecated::v1::DelegationRoot::::new(ctype::mock::get_ctype_hash(true), alice); + deprecated::v1::storage::Roots::insert(old_root_id, old_root_node.clone()); + + #[cfg(feature = "try-runtime")] + assert!( + pre_migrate::().is_ok(), + "Pre-migration for v1 should not fail." + ); + + migrate::(); + + #[cfg(feature = "try-runtime")] + assert!( + post_migrate::().is_ok(), + "Post-migration for v1 should not fail." + ); + + assert_eq!(deprecated::v1::storage::Roots::::iter_values().count(), 0); + assert_eq!( + deprecated::v1::storage::Delegations::::iter_values().count(), + 0 + ); + assert_eq!( + deprecated::v1::storage::Children::::iter_values().count(), + 0 + ); + + let new_stored_hierarchy = DelegationHierarchies::::get(old_root_id) + .expect("New delegation hierarchy should exist in the storage."); + assert_eq!(new_stored_hierarchy.ctype_hash, old_root_node.ctype_hash); + let new_stored_root = DelegationNodes::::get(old_root_id) + .expect("New delegation root should exist in the storage."); + assert_eq!(new_stored_root.hierarchy_root_id, old_root_id); + assert!(new_stored_root.parent.is_none()); + assert!(new_stored_root.children.is_empty()); + assert_eq!(new_stored_root.details.owner, old_root_node.owner); + assert_eq!(new_stored_root.details.revoked, old_root_node.revoked); + }); + } + + #[test] + fn ok_root_two_children() { + let mut ext = mock::ExtBuilder::default() + .with_storage_version(DelegationStorageVersion::V1) + .build(None); + ext.execute_with(|| { + let alice = mock::get_ed25519_account(mock::get_alice_ed25519().public()); + let bob = mock::get_sr25519_account(mock::get_bob_sr25519().public()); + let old_root_id = mock::get_delegation_id(true); + let old_root_node = + deprecated::v1::DelegationRoot::::new(ctype::mock::get_ctype_hash(true), alice.clone()); + let old_node_id_1 = mock::get_delegation_id(false); + let old_node_1 = deprecated::v1::DelegationNode::::new_root_child( + old_root_id, + alice, + Permissions::DELEGATE, + ); + let old_node_id_2 = mock::get_delegation_id_2(true); + let old_node_2 = + deprecated::v1::DelegationNode::::new_root_child(old_root_id, bob, Permissions::ATTEST); + deprecated::v1::storage::Roots::insert(old_root_id, old_root_node.clone()); + deprecated::v1::storage::Delegations::insert(old_node_id_1, old_node_1.clone()); + deprecated::v1::storage::Delegations::insert(old_node_id_2, old_node_2.clone()); + deprecated::v1::storage::Children::::insert(old_root_id, vec![old_node_id_1, old_node_id_2]); + + #[cfg(feature = "try-runtime")] + assert!( + pre_migrate::().is_ok(), + "Pre-migration for v1 should not fail." + ); + + migrate::(); + + #[cfg(feature = "try-runtime")] + assert!( + post_migrate::().is_ok(), + "Post-migration for v1 should not fail." + ); + + assert_eq!(deprecated::v1::storage::Roots::::iter_values().count(), 0); + assert_eq!( + deprecated::v1::storage::Delegations::::iter_values().count(), + 0 + ); + assert_eq!( + deprecated::v1::storage::Children::::iter_values().count(), + 0 + ); + + let new_stored_hierarchy = DelegationHierarchies::::get(old_root_id) + .expect("New delegation hierarchy should exist in the storage."); + assert_eq!(new_stored_hierarchy.ctype_hash, old_root_node.ctype_hash); + let new_stored_root = DelegationNodes::::get(old_root_id) + .expect("New delegation root should exist in the storage."); + assert_eq!(new_stored_root.hierarchy_root_id, old_root_id); + assert!(new_stored_root.parent.is_none()); + assert_eq!(new_stored_root.children.len(), 2); + assert!(new_stored_root.children.contains(&old_node_id_1)); + assert!(new_stored_root.children.contains(&old_node_id_2)); + assert_eq!(new_stored_root.details.owner, old_root_node.owner); + assert_eq!(new_stored_root.details.revoked, old_root_node.revoked); + + let new_stored_node_1 = DelegationNodes::::get(old_node_id_1) + .expect("New delegation 1 should exist in the storage."); + assert_eq!(new_stored_node_1.hierarchy_root_id, old_root_id); + assert_eq!(new_stored_node_1.parent, Some(old_root_id)); + assert!(new_stored_node_1.children.is_empty()); + assert_eq!(new_stored_node_1.details.owner, old_node_1.owner); + assert_eq!(new_stored_node_1.details.revoked, old_node_1.revoked); + + let new_stored_node_2 = DelegationNodes::::get(old_node_id_2) + .expect("New delegation 2 should exist in the storage."); + assert_eq!(new_stored_node_2.hierarchy_root_id, old_root_id); + assert_eq!(new_stored_node_2.parent, Some(old_root_id)); + assert!(new_stored_node_2.children.is_empty()); + assert_eq!(new_stored_node_2.details.owner, old_node_2.owner); + assert_eq!(new_stored_node_2.details.revoked, old_node_2.revoked); + }); + } + + #[test] + fn ok_three_level_hierarchy() { + let mut ext = mock::ExtBuilder::default() + .with_storage_version(DelegationStorageVersion::V1) + .build(None); + ext.execute_with(|| { + let alice = mock::get_ed25519_account(mock::get_alice_ed25519().public()); + let bob = mock::get_sr25519_account(mock::get_bob_sr25519().public()); + let old_root_id = mock::get_delegation_id(true); + let old_root_node = + deprecated::v1::DelegationRoot::::new(ctype::mock::get_ctype_hash(true), alice.clone()); + let old_parent_id = mock::get_delegation_id(false); + let old_parent_node = + deprecated::v1::DelegationNode::::new_root_child(old_root_id, alice, Permissions::all()); + let old_node_id = mock::get_delegation_id_2(true); + let old_node = deprecated::v1::DelegationNode::::new_node_child( + old_root_id, + old_parent_id, + bob, + Permissions::ATTEST, + ); + deprecated::v1::storage::Roots::insert(old_root_id, old_root_node.clone()); + deprecated::v1::storage::Delegations::insert(old_parent_id, old_parent_node.clone()); + deprecated::v1::storage::Delegations::insert(old_node_id, old_node.clone()); + deprecated::v1::storage::Children::::insert(old_root_id, vec![old_parent_id]); + deprecated::v1::storage::Children::::insert(old_parent_id, vec![old_node_id]); + + #[cfg(feature = "try-runtime")] + assert!( + pre_migrate::().is_ok(), + "Pre-migration for v1 should not fail." + ); + + migrate::(); + + #[cfg(feature = "try-runtime")] + assert!( + post_migrate::().is_ok(), + "Post-migration for v1 should not fail." + ); + + assert_eq!(deprecated::v1::storage::Roots::::iter_values().count(), 0); + assert_eq!( + deprecated::v1::storage::Delegations::::iter_values().count(), + 0 + ); + assert_eq!( + deprecated::v1::storage::Children::::iter_values().count(), + 0 + ); + + let new_stored_hierarchy = DelegationHierarchies::::get(old_root_id) + .expect("New delegation hierarchy should exist in the storage."); + assert_eq!(new_stored_hierarchy.ctype_hash, old_root_node.ctype_hash); + let new_stored_root = DelegationNodes::::get(old_root_id) + .expect("New delegation root should exist in the storage."); + assert_eq!(new_stored_root.hierarchy_root_id, old_root_id); + assert!(new_stored_root.parent.is_none()); + assert_eq!(new_stored_root.children.len(), 1); + assert!(new_stored_root.children.contains(&old_parent_id)); + assert_eq!(new_stored_root.details.owner, old_root_node.owner); + assert_eq!(new_stored_root.details.revoked, old_root_node.revoked); + + let new_stored_parent = DelegationNodes::::get(old_parent_id) + .expect("New delegation parent should exist in the storage."); + assert_eq!(new_stored_parent.hierarchy_root_id, old_root_id); + assert_eq!(new_stored_parent.parent, Some(old_root_id)); + assert_eq!(new_stored_parent.children.len(), 1); + assert!(new_stored_parent.children.contains(&old_node_id)); + assert_eq!(new_stored_parent.details.owner, old_parent_node.owner); + assert_eq!(new_stored_parent.details.revoked, old_parent_node.revoked); + + let new_stored_node = DelegationNodes::::get(old_node_id) + .expect("New delegation node should exist in the storage."); + assert_eq!(new_stored_node.hierarchy_root_id, old_root_id); + assert_eq!(new_stored_node.parent, Some(old_parent_id)); + assert!(new_stored_node.children.is_empty()); + assert_eq!(new_stored_node.details.owner, old_node.owner); + assert_eq!(new_stored_node.details.revoked, old_node.revoked); + }); + } +} diff --git a/pallets/delegation/src/mock.rs b/pallets/delegation/src/mock.rs index 36410c3d56..4c8b77baf9 100644 --- a/pallets/delegation/src/mock.rs +++ b/pallets/delegation/src/mock.rs @@ -28,7 +28,7 @@ use sp_runtime::{ traits::{BlakeTwo256, IdentifyAccount, IdentityLookup, Verify}, MultiSignature, MultiSigner, }; -use sp_std::sync::Arc; +use sp_std::{collections::btree_set::BTreeSet, sync::Arc}; #[cfg(test)] use codec::Encode; @@ -143,12 +143,12 @@ const ALICE_SEED: [u8; 32] = [0u8; 32]; const BOB_SEED: [u8; 32] = [1u8; 32]; const CHARLIE_SEED: [u8; 32] = [2u8; 32]; -const DEFAULT_ROOT_ID_SEED: u64 = 1u64; -const ALTERNATIVE_ROOT_ID_SEED: u64 = 2u64; +const DEFAULT_HIERARCHY_ID_SEED: u64 = 1u64; +const ALTERNATIVE_HIERARCHY_ID_SEED: u64 = 2u64; const DEFAULT_DELEGATION_ID_SEED: u64 = 3u64; const ALTERNATIVE_DELEGATION_ID_SEED: u64 = 4u64; -const DEFAULT_DELEGATION_ID_2_SEED: u64 = 3u64; -const ALTERNATIVE_DELEGATION_ID_2_SEED: u64 = 4u64; +const DEFAULT_DELEGATION_ID_2_SEED: u64 = 5u64; +const ALTERNATIVE_DELEGATION_ID_2_SEED: u64 = 6u64; pub fn get_origin(account: TestDelegatorId) -> Origin { Origin::signed(account) @@ -186,27 +186,27 @@ pub fn get_charlie_sr25519() -> sr25519::Pair { sr25519::Pair::from_seed(&CHARLIE_SEED) } -pub fn get_delegation_root_id(default: bool) -> TestDelegationNodeId { +pub fn get_delegation_hierarchy_id(default: bool) -> TestDelegationNodeId { if default { - TestCtypeHash::from_low_u64_be(DEFAULT_ROOT_ID_SEED) + TestDelegationNodeId::from_low_u64_be(DEFAULT_HIERARCHY_ID_SEED) } else { - TestCtypeHash::from_low_u64_be(ALTERNATIVE_ROOT_ID_SEED) + TestDelegationNodeId::from_low_u64_be(ALTERNATIVE_HIERARCHY_ID_SEED) } } pub fn get_delegation_id(default: bool) -> TestDelegationNodeId { if default { - TestCtypeHash::from_low_u64_be(DEFAULT_DELEGATION_ID_SEED) + TestDelegationNodeId::from_low_u64_be(DEFAULT_DELEGATION_ID_SEED) } else { - TestCtypeHash::from_low_u64_be(ALTERNATIVE_DELEGATION_ID_SEED) + TestDelegationNodeId::from_low_u64_be(ALTERNATIVE_DELEGATION_ID_SEED) } } pub fn get_delegation_id_2(default: bool) -> TestDelegationNodeId { if default { - TestCtypeHash::from_low_u64_be(DEFAULT_DELEGATION_ID_2_SEED) + TestDelegationNodeId::from_low_u64_be(DEFAULT_DELEGATION_ID_2_SEED) } else { - TestCtypeHash::from_low_u64_be(ALTERNATIVE_DELEGATION_ID_2_SEED) + TestDelegationNodeId::from_low_u64_be(ALTERNATIVE_DELEGATION_ID_2_SEED) } } @@ -215,116 +215,133 @@ pub(crate) fn hash_to_u8(hash: T) -> Vec { hash.encode() } -pub struct DelegationRootCreationDetails { - pub root_id: TestDelegationNodeId, +pub fn generate_base_delegation_hierarchy_details() -> DelegationHierarchyDetails { + DelegationHierarchyDetails { + ctype_hash: ctype_mock::get_ctype_hash(true), + } +} + +pub fn generate_base_delegation_node( + hierarchy_id: TestDelegationNodeId, + owner: TestDelegatorId, + parent: Option, +) -> DelegationNode { + DelegationNode { + details: generate_base_delegation_details(owner), + children: BTreeSet::new(), + hierarchy_root_id: hierarchy_id, + parent, + } +} + +pub fn generate_base_delegation_details(owner: TestDelegatorId) -> DelegationDetails { + DelegationDetails { + owner, + permissions: Permissions::DELEGATE, + revoked: false, + } +} + +pub struct DelegationHierarchyCreationOperation { + pub id: TestDelegationNodeId, pub ctype_hash: TestCtypeHash, } -pub fn generate_base_delegation_root_creation_details( - root_id: TestDelegationNodeId, - root_node: DelegationRoot, -) -> DelegationRootCreationDetails { - DelegationRootCreationDetails { - ctype_hash: root_node.ctype_hash, - root_id, +pub fn generate_base_delegation_hierarchy_creation_operation( + id: TestDelegationNodeId, +) -> DelegationHierarchyCreationOperation { + DelegationHierarchyCreationOperation { + id, + ctype_hash: ctype::mock::get_ctype_hash(true), } } -pub struct DelegationCreationDetails { +pub struct DelegationCreationOperation { pub delegation_id: TestDelegationNodeId, - pub root_id: TestDelegationNodeId, - pub parent_id: Option, + pub hierarchy_id: TestDelegationNodeId, + pub parent_id: TestDelegationNodeId, pub delegate: TestDelegatorId, pub permissions: Permissions, pub delegate_signature: TestDelegateSignature, } -pub fn generate_base_delegation_creation_details( +pub fn generate_base_delegation_creation_operation( delegation_id: TestDelegationNodeId, delegate_signature: TestDelegateSignature, delegation_node: DelegationNode, -) -> DelegationCreationDetails { - DelegationCreationDetails { +) -> DelegationCreationOperation { + DelegationCreationOperation { delegation_id, - parent_id: delegation_node.parent, - root_id: delegation_node.root_id, - delegate: delegation_node.owner, + parent_id: delegation_node + .parent + .expect("Delegation node must specify a parent ID upon creation"), + hierarchy_id: delegation_node.hierarchy_root_id, + delegate: delegation_node.details.owner, delegate_signature, - permissions: delegation_node.permissions, + permissions: delegation_node.details.permissions, } } -pub struct DelegationRootRevocationDetails { - pub root_id: TestDelegationNodeId, +pub struct DelegationHierarchyRevocationOperation { + pub id: TestDelegationNodeId, pub max_children: u32, } -pub fn generate_base_delegation_root_revocation_details( - root_id: TestDelegationNodeId, -) -> DelegationRootRevocationDetails { - DelegationRootRevocationDetails { - root_id, - max_children: 0u32, - } +pub fn generate_base_delegation_hierarchy_revocation_operation( + id: TestDelegationNodeId, +) -> DelegationHierarchyRevocationOperation { + DelegationHierarchyRevocationOperation { id, max_children: 0u32 } } -pub struct DelegationRevocationDetails { +pub struct DelegationRevocationOperation { pub delegation_id: TestDelegationNodeId, pub max_parent_checks: u32, pub max_revocations: u32, } -pub fn generate_base_delegation_revocation_details(delegation_id: TestDelegationNodeId) -> DelegationRevocationDetails { - DelegationRevocationDetails { +pub fn generate_base_delegation_revocation_operation( + delegation_id: TestDelegationNodeId, +) -> DelegationRevocationOperation { + DelegationRevocationOperation { delegation_id, max_parent_checks: 0u32, max_revocations: 0u32, } } -pub fn generate_base_delegation_root(owner: TestDelegatorId) -> DelegationRoot { - DelegationRoot { - owner, - ctype_hash: ctype_mock::get_ctype_hash(true), - revoked: false, - } -} - -pub fn generate_base_delegation_node(root_id: TestDelegationNodeId, owner: TestDelegatorId) -> DelegationNode { - DelegationNode { - owner, - parent: None, - root_id, - permissions: Permissions::DELEGATE, - revoked: false, - } -} - #[derive(Clone)] pub struct ExtBuilder { ctype_builder: Option, - root_delegations_stored: Vec<(TestDelegationNodeId, DelegationRoot)>, + delegation_hierarchies_stored: Vec<( + TestDelegationNodeId, + DelegationHierarchyDetails, + DelegatorIdOf, + )>, delegations_stored: Vec<(TestDelegationNodeId, DelegationNode)>, - children_stored: Vec<(TestDelegationNodeId, Vec)>, + storage_version: DelegationStorageVersion, } impl Default for ExtBuilder { fn default() -> Self { Self { ctype_builder: None, - root_delegations_stored: vec![], + delegation_hierarchies_stored: vec![], delegations_stored: vec![], - children_stored: vec![], + storage_version: DelegationStorageVersion::default(), } } } impl ExtBuilder { - pub fn with_root_delegations( + pub fn with_delegation_hierarchies( mut self, - root_delegations: Vec<(TestDelegationNodeId, DelegationRoot)>, + delegation_hierarchies: Vec<( + TestDelegationNodeId, + DelegationHierarchyDetails, + DelegatorIdOf, + )>, ) -> Self { - self.root_delegations_stored = root_delegations; + self.delegation_hierarchies_stored = delegation_hierarchies; self } @@ -333,8 +350,8 @@ impl ExtBuilder { self } - pub fn with_children(mut self, children: Vec<(TestDelegationNodeId, Vec)>) -> Self { - self.children_stored = children; + pub fn with_storage_version(mut self, storage_version: DelegationStorageVersion) -> Self { + self.storage_version = storage_version; self } @@ -346,29 +363,41 @@ impl ExtBuilder { sp_io::TestExternalities::new(storage) }; - if !self.root_delegations_stored.is_empty() { + if !self.delegation_hierarchies_stored.is_empty() { ext.execute_with(|| { - self.root_delegations_stored.iter().for_each(|root_delegation| { - delegation::Roots::::insert(root_delegation.0, root_delegation.1.clone()); - }) + self.delegation_hierarchies_stored + .iter() + .for_each(|delegation_hierarchy| { + delegation::Pallet::create_and_store_new_hierarchy( + delegation_hierarchy.0, + delegation_hierarchy.1.clone(), + delegation_hierarchy.2.clone(), + ); + }) }); } if !self.delegations_stored.is_empty() { ext.execute_with(|| { self.delegations_stored.iter().for_each(|del| { - delegation::Delegations::::insert(del.0, del.1.clone()); + let parent_node_id = del + .1 + .parent + .expect("Delegation node that is not a root must have a parent ID specified."); + let parent_node = delegation::DelegationNodes::::get(&parent_node_id).unwrap(); + delegation::Pallet::store_delegation_under_parent( + del.0, + del.1.clone(), + parent_node_id, + parent_node, + ); }) }); } - if !self.children_stored.is_empty() { - ext.execute_with(|| { - self.children_stored.iter().for_each(|child| { - delegation::Children::::insert(child.0, child.1.clone()); - }) - }); - } + ext.execute_with(|| { + delegation::StorageVersion::::set(self.storage_version); + }); ext } diff --git a/pallets/delegation/src/tests.rs b/pallets/delegation/src/tests.rs index 9fd63a451e..3a618352e5 100644 --- a/pallets/delegation/src/tests.rs +++ b/pallets/delegation/src/tests.rs @@ -30,31 +30,37 @@ fn create_root_delegation_successful() { let creator_keypair = get_alice_ed25519(); let creator = get_ed25519_account(creator_keypair.public()); - let (root_id, root_node) = ( - get_delegation_root_id(true), - generate_base_delegation_root(creator.clone()), - ); + let hierarchy_root_id = get_delegation_hierarchy_id(true); - let operation = generate_base_delegation_root_creation_details(root_id, root_node.clone()); + let operation = generate_base_delegation_hierarchy_creation_operation(hierarchy_root_id); let mut ext = ctype_mock::ExtBuilder::default() - .with_ctypes(vec![(root_node.ctype_hash, creator.clone())]) + .with_ctypes(vec![(operation.ctype_hash, creator.clone())]) .build(None); ext.execute_with(|| { - assert_ok!(Delegation::create_root( + assert_ok!(Delegation::create_hierarchy( get_origin(creator.clone()), - operation.root_id, + operation.id, operation.ctype_hash )); }); - let stored_delegation_root = ext - .execute_with(|| Delegation::roots(&operation.root_id).expect("Delegation root should be present on chain.")); + let stored_hierarchy_details = ext.execute_with(|| { + Delegation::delegation_hierarchies(&hierarchy_root_id) + .expect("Delegation hierarchy should be present on chain.") + }); + assert_eq!(stored_hierarchy_details.ctype_hash, operation.ctype_hash); - assert_eq!(stored_delegation_root.owner, creator); - assert_eq!(stored_delegation_root.ctype_hash, operation.ctype_hash); - assert!(!stored_delegation_root.revoked); + let stored_delegation_root = ext.execute_with(|| { + Delegation::delegation_nodes(&hierarchy_root_id).expect("Delegation root should be present on chain.") + }); + + assert_eq!(stored_delegation_root.hierarchy_root_id, hierarchy_root_id); + assert_eq!(stored_delegation_root.parent, None); + assert_eq!(stored_delegation_root.children.len(), 0); + assert_eq!(stored_delegation_root.details.owner, creator); + assert!(!stored_delegation_root.details.revoked); } #[test] @@ -62,24 +68,24 @@ fn duplicate_create_root_delegation_error() { let creator_keypair = get_alice_ed25519(); let creator = get_ed25519_account(creator_keypair.public()); - let (root_id, root_node) = ( - get_delegation_root_id(true), - generate_base_delegation_root(creator.clone()), + let (hierarchy_root_id, hierarchy_details) = ( + get_delegation_hierarchy_id(true), + generate_base_delegation_hierarchy_details(), ); - let operation = generate_base_delegation_root_creation_details(root_id, root_node.clone()); + let operation = generate_base_delegation_hierarchy_creation_operation(hierarchy_root_id); let ext = ctype_mock::ExtBuilder::default() - .with_ctypes(vec![(root_node.ctype_hash, creator.clone())]) + .with_ctypes(vec![(operation.ctype_hash, creator.clone())]) .build(None); let mut ext = ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, creator.clone())]) .build(Some(ext)); ext.execute_with(|| { - assert_err!( - Delegation::create_root(get_origin(creator.clone()), operation.root_id, operation.ctype_hash), - delegation::Error::::RootAlreadyExists + assert_noop!( + Delegation::create_hierarchy(get_origin(creator.clone()), operation.id, operation.ctype_hash), + delegation::Error::::HierarchyAlreadyExists ); }); } @@ -89,19 +95,16 @@ fn ctype_not_found_create_root_delegation_error() { let creator_keypair = get_alice_ed25519(); let creator = get_ed25519_account(creator_keypair.public()); - let (root_id, root_node) = ( - get_delegation_root_id(true), - generate_base_delegation_root(creator.clone()), - ); + let hierarchy_root_id = get_delegation_hierarchy_id(true); - let operation = generate_base_delegation_root_creation_details(root_id, root_node); + let operation = generate_base_delegation_hierarchy_creation_operation(hierarchy_root_id); // No CType stored, let mut ext = ExtBuilder::default().build(None); ext.execute_with(|| { - assert_err!( - Delegation::create_root(get_origin(creator.clone()), operation.root_id, operation.ctype_hash), + assert_noop!( + Delegation::create_hierarchy(get_origin(creator.clone()), operation.id, operation.ctype_hash), ctype::Error::::CTypeNotFound ); }); @@ -110,45 +113,44 @@ fn ctype_not_found_create_root_delegation_error() { // submit_delegation_creation_operation() #[test] -fn create_delegation_no_parent_successful() { +fn create_delegation_direct_root_successful() { let creator_keypair = get_alice_ed25519(); let creator = get_ed25519_account(creator_keypair.public()); let delegate_keypair = get_bob_sr25519(); let delegate = get_sr25519_account(delegate_keypair.public()); - let (root_id, root_node) = ( - get_delegation_root_id(true), - generate_base_delegation_root(creator.clone()), + let (hierarchy_root_id, hierarchy_details) = ( + get_delegation_hierarchy_id(true), + generate_base_delegation_hierarchy_details(), ); let (delegation_id, delegation_node) = ( get_delegation_id(true), - generate_base_delegation_node(root_id, delegate), + generate_base_delegation_node(hierarchy_root_id, delegate, Some(hierarchy_root_id)), ); - let delegation_info = Delegation::calculate_hash( + let delegation_info = Delegation::calculate_delegation_creation_hash( &delegation_id, - &delegation_node.root_id, - &delegation_node.parent, - &delegation_node.permissions, + &hierarchy_root_id, + &hierarchy_root_id, + &delegation_node.details.permissions, ); let delegate_signature = delegate_keypair.sign(&hash_to_u8(delegation_info)); let operation = - generate_base_delegation_creation_details(delegation_id, delegate_signature.into(), delegation_node); + generate_base_delegation_creation_operation(delegation_id, delegate_signature.into(), delegation_node); let ext = ctype_mock::ExtBuilder::default() - .with_ctypes(vec![(root_node.ctype_hash, creator.clone())]) + .with_ctypes(vec![(hierarchy_details.ctype_hash, creator.clone())]) .build(None); let mut ext = ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, creator.clone())]) .build(Some(ext)); ext.execute_with(|| { assert_ok!(Delegation::add_delegation( get_origin(creator.clone()), operation.delegation_id, - operation.root_id, operation.parent_id, operation.delegate.clone(), operation.permissions, @@ -157,21 +159,22 @@ fn create_delegation_no_parent_successful() { }); let stored_delegation = ext.execute_with(|| { - Delegation::delegations(&operation.delegation_id).expect("Delegation should be present on chain.") + Delegation::delegation_nodes(&operation.delegation_id).expect("Delegation should be present on chain.") }); - assert_eq!(stored_delegation.root_id, operation.root_id); - assert_eq!(stored_delegation.parent, operation.parent_id); - assert_eq!(stored_delegation.owner, operation.delegate); - assert_eq!(stored_delegation.permissions, operation.permissions); - assert!(!stored_delegation.revoked); + assert_eq!(stored_delegation.hierarchy_root_id, operation.hierarchy_id); + assert_eq!(stored_delegation.parent, Some(operation.parent_id)); + assert!(stored_delegation.children.is_empty()); + assert_eq!(stored_delegation.details.owner, operation.delegate); + assert_eq!(stored_delegation.details.permissions, operation.permissions); + assert!(!stored_delegation.details.revoked); // Verify that the root has the new delegation among its children - let stored_root_children = ext.execute_with(|| { - Delegation::children(&operation.root_id).expect("Delegation root children should be present on chain.") + let stored_root = ext.execute_with(|| { + Delegation::delegation_nodes(&operation.hierarchy_id).expect("Delegation root should be present on chain.") }); - assert_eq!(stored_root_children, vec![operation.delegation_id]); + assert!(stored_root.children.contains(&operation.delegation_id)); } #[test] @@ -181,418 +184,423 @@ fn create_delegation_with_parent_successful() { let delegate_keypair = get_bob_sr25519(); let delegate = get_sr25519_account(delegate_keypair.public()); - let (root_id, root_node) = ( - get_delegation_root_id(true), - generate_base_delegation_root(creator.clone()), + let (hierarchy_root_id, hierarchy_details) = ( + get_delegation_hierarchy_id(true), + generate_base_delegation_hierarchy_details(), ); - let (parent_delegation_id, parent_delegation_node) = ( + let (parent_id, parent_node) = ( get_delegation_id(true), - generate_base_delegation_node(root_id, creator.clone()), + generate_base_delegation_node(hierarchy_root_id, creator.clone(), Some(hierarchy_root_id)), ); - let (delegation_id, mut delegation_node) = ( + let (delegation_id, delegation_node) = ( get_delegation_id(false), - generate_base_delegation_node(root_id, delegate.clone()), + generate_base_delegation_node(hierarchy_root_id, delegate, Some(parent_id)), ); - delegation_node.parent = Some(parent_delegation_id); - let delegate_signature = delegate_keypair.sign(&hash_to_u8(Delegation::calculate_hash( + let delegation_info = Delegation::calculate_delegation_creation_hash( &delegation_id, - &delegation_node.root_id, - &delegation_node.parent, - &delegation_node.permissions, - ))); + &hierarchy_root_id, + &parent_id, + &delegation_node.details.permissions, + ); + + let delegate_signature = delegate_keypair.sign(&hash_to_u8(delegation_info)); let operation = - generate_base_delegation_creation_details(delegation_id, delegate_signature.into(), delegation_node); + generate_base_delegation_creation_operation(delegation_id, delegate_signature.into(), delegation_node); let ext = ctype_mock::ExtBuilder::default() - .with_ctypes(vec![(root_node.ctype_hash, creator.clone())]) + .with_ctypes(vec![(hierarchy_details.ctype_hash, creator.clone())]) .build(None); let mut ext = ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) - .with_delegations(vec![(parent_delegation_id, parent_delegation_node)]) - .with_children(vec![(root_id, vec![(parent_delegation_id)])]) + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, creator.clone())]) + .with_delegations(vec![(parent_id, parent_node)]) .build(Some(ext)); ext.execute_with(|| { assert_ok!(Delegation::add_delegation( get_origin(creator.clone()), operation.delegation_id, - operation.root_id, operation.parent_id, - delegate.clone(), + operation.delegate.clone(), operation.permissions, operation.delegate_signature.clone().encode(), )); }); let stored_delegation = ext.execute_with(|| { - Delegation::delegations(&operation.delegation_id).expect("Delegation should be present on chain.") + Delegation::delegation_nodes(&operation.delegation_id).expect("Delegation should be present on chain.") }); - assert_eq!(stored_delegation.root_id, operation.root_id); - assert_eq!(stored_delegation.parent, operation.parent_id); - assert_eq!(stored_delegation.owner, operation.delegate); - assert_eq!(stored_delegation.permissions, operation.permissions); - assert!(!stored_delegation.revoked); + assert_eq!(stored_delegation.hierarchy_root_id, operation.hierarchy_id); + assert_eq!(stored_delegation.parent, Some(operation.parent_id)); + assert!(stored_delegation.children.is_empty()); + assert_eq!(stored_delegation.details.owner, operation.delegate); + assert_eq!(stored_delegation.details.permissions, operation.permissions); + assert!(!stored_delegation.details.revoked); // Verify that the parent has the new delegation among its children - let stored_parent_children = ext.execute_with(|| { - Delegation::children(&operation.parent_id.unwrap()) - .expect("Delegation parent children should be present on chain.") + let stored_parent = ext.execute_with(|| { + Delegation::delegation_nodes(&operation.parent_id).expect("Delegation parent should be present on chain.") }); - assert_eq!(stored_parent_children, vec![delegation_id]); + assert!(stored_parent.children.contains(&operation.delegation_id)); } #[test] -fn invalid_delegate_signature_create_delegation_error() { +fn create_delegation_direct_root_revoked_error() { let creator_keypair = get_alice_ed25519(); let creator = get_ed25519_account(creator_keypair.public()); - let alternative_keypair = get_alice_sr25519(); let delegate_keypair = get_bob_sr25519(); let delegate = get_sr25519_account(delegate_keypair.public()); - let (root_id, root_node) = ( - get_delegation_root_id(true), - generate_base_delegation_root(creator.clone()), + let (hierarchy_root_id, hierarchy_details) = ( + get_delegation_hierarchy_id(true), + generate_base_delegation_hierarchy_details(), ); let (delegation_id, delegation_node) = ( get_delegation_id(true), - generate_base_delegation_node(root_id, delegate.clone()), + generate_base_delegation_node(hierarchy_root_id, delegate.clone(), Some(hierarchy_root_id)), ); - let delegate_signature = alternative_keypair.sign(&hash_to_u8(Delegation::calculate_hash( + let delegation_info = Delegation::calculate_delegation_creation_hash( &delegation_id, - &delegation_node.root_id, - &delegation_node.parent, - &delegation_node.permissions, - ))); + &hierarchy_root_id, + &hierarchy_root_id, + &delegation_node.details.permissions, + ); + + let delegate_signature = delegate_keypair.sign(&hash_to_u8(delegation_info)); let operation = - generate_base_delegation_creation_details(delegation_id, delegate_signature.into(), delegation_node); + generate_base_delegation_creation_operation(delegation_id, delegate_signature.into(), delegation_node); let ext = ctype_mock::ExtBuilder::default() - .with_ctypes(vec![(root_node.ctype_hash, creator.clone())]) + .with_ctypes(vec![(hierarchy_details.ctype_hash, creator.clone())]) .build(None); let mut ext = ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, creator.clone())]) .build(Some(ext)); ext.execute_with(|| { - assert_err!( + let _ = Delegation::revoke_delegation( + get_origin(creator.clone()), + operation.hierarchy_id, + 0u32, + MaxRevocations::get(), + ); + assert_noop!( Delegation::add_delegation( get_origin(creator.clone()), operation.delegation_id, - operation.root_id, operation.parent_id, - delegate.clone(), + delegate, operation.permissions, operation.delegate_signature.clone().encode(), ), - delegation::Error::::InvalidDelegateSignature + delegation::Error::::ParentDelegationRevoked ); }); } #[test] -fn duplicate_delegation_create_delegation_error() { +fn create_delegation_with_parent_revoked_error() { let creator_keypair = get_alice_ed25519(); let creator = get_ed25519_account(creator_keypair.public()); let delegate_keypair = get_bob_sr25519(); let delegate = get_sr25519_account(delegate_keypair.public()); - let (root_id, root_node) = ( - get_delegation_root_id(true), - generate_base_delegation_root(creator.clone()), + let (hierarchy_root_id, hierarchy_details) = ( + get_delegation_hierarchy_id(true), + generate_base_delegation_hierarchy_details(), ); - let (delegation_id, delegation_node) = ( + let (parent_id, parent_node) = ( get_delegation_id(true), - generate_base_delegation_node(root_id, delegate.clone()), + generate_base_delegation_node(hierarchy_root_id, creator.clone(), Some(hierarchy_root_id)), + ); + let (delegation_id, delegation_node) = ( + get_delegation_id(false), + generate_base_delegation_node(hierarchy_root_id, delegate.clone(), Some(parent_id)), ); - let delegate_signature = delegate_keypair.sign(&hash_to_u8(Delegation::calculate_hash( + let delegation_info = Delegation::calculate_delegation_creation_hash( &delegation_id, - &delegation_node.root_id, - &delegation_node.parent, - &delegation_node.permissions, - ))); + &hierarchy_root_id, + &parent_id, + &delegation_node.details.permissions, + ); + + let delegate_signature = delegate_keypair.sign(&hash_to_u8(delegation_info)); let operation = - generate_base_delegation_creation_details(delegation_id, delegate_signature.into(), delegation_node.clone()); + generate_base_delegation_creation_operation(delegation_id, delegate_signature.into(), delegation_node); let ext = ctype_mock::ExtBuilder::default() - .with_ctypes(vec![(root_node.ctype_hash, creator.clone())]) + .with_ctypes(vec![(hierarchy_details.ctype_hash, creator.clone())]) .build(None); let mut ext = ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) - .with_delegations(vec![(delegation_id, delegation_node)]) - .with_children(vec![(root_id, vec![delegation_id])]) + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, creator.clone())]) + .with_delegations(vec![(parent_id, parent_node)]) .build(Some(ext)); ext.execute_with(|| { - assert_err!( + let _ = Delegation::revoke_delegation( + get_origin(creator.clone()), + operation.parent_id, + MaxRevocations::get(), + MaxParentChecks::get(), + ); + assert_noop!( Delegation::add_delegation( get_origin(creator.clone()), operation.delegation_id, - operation.root_id, operation.parent_id, - delegate.clone(), + delegate, operation.permissions, operation.delegate_signature.clone().encode(), ), - delegation::Error::::DelegationAlreadyExists + delegation::Error::::ParentDelegationRevoked ); }); } #[test] -fn root_not_existing_create_delegation_error() { +fn invalid_delegate_signature_create_delegation_error() { let creator_keypair = get_alice_ed25519(); let creator = get_ed25519_account(creator_keypair.public()); + let alternative_keypair = get_alice_sr25519(); let delegate_keypair = get_bob_sr25519(); let delegate = get_sr25519_account(delegate_keypair.public()); - let (root_id, root_node) = ( - get_delegation_root_id(true), - generate_base_delegation_root(creator.clone()), + let (hierarchy_root_id, hierarchy_details) = ( + get_delegation_hierarchy_id(true), + generate_base_delegation_hierarchy_details(), ); let (delegation_id, delegation_node) = ( get_delegation_id(true), - generate_base_delegation_node(root_id, delegate.clone()), + generate_base_delegation_node(hierarchy_root_id, delegate.clone(), Some(hierarchy_root_id)), ); - let delegate_signature = delegate_keypair.sign(&hash_to_u8(Delegation::calculate_hash( + let delegate_signature = alternative_keypair.sign(&hash_to_u8(Delegation::calculate_delegation_creation_hash( &delegation_id, - &delegation_node.root_id, - &delegation_node.parent, - &delegation_node.permissions, + &hierarchy_root_id, + &hierarchy_root_id, + &delegation_node.details.permissions, ))); let operation = - generate_base_delegation_creation_details(delegation_id, delegate_signature.into(), delegation_node); + generate_base_delegation_creation_operation(delegation_id, delegate_signature.into(), delegation_node); let ext = ctype_mock::ExtBuilder::default() - .with_ctypes(vec![(root_node.ctype_hash, creator.clone())]) + .with_ctypes(vec![(hierarchy_details.ctype_hash, creator.clone())]) .build(None); - // No delegations added to the pallet storage - let mut ext = ExtBuilder::default().build(Some(ext)); + let mut ext = ExtBuilder::default() + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, creator.clone())]) + .build(Some(ext)); ext.execute_with(|| { - assert_err!( + assert_noop!( Delegation::add_delegation( get_origin(creator.clone()), operation.delegation_id, - operation.root_id, operation.parent_id, delegate.clone(), operation.permissions, operation.delegate_signature.clone().encode(), ), - delegation::Error::::RootNotFound + delegation::Error::::InvalidDelegateSignature ); }); } #[test] -fn parent_not_existing_create_delegation_error() { +fn duplicate_delegation_create_delegation_error() { let creator_keypair = get_alice_ed25519(); let creator = get_ed25519_account(creator_keypair.public()); let delegate_keypair = get_bob_sr25519(); let delegate = get_sr25519_account(delegate_keypair.public()); - let (root_id, root_node) = ( - get_delegation_root_id(true), - generate_base_delegation_root(creator.clone()), + let (hierarchy_root_id, hierarchy_details) = ( + get_delegation_hierarchy_id(true), + generate_base_delegation_hierarchy_details(), ); - let alternative_parent_id = get_delegation_id(false); - let (delegation_id, mut delegation_node) = ( + let (delegation_id, delegation_node) = ( get_delegation_id(true), - generate_base_delegation_node(root_id, delegate.clone()), + generate_base_delegation_node(hierarchy_root_id, delegate.clone(), Some(hierarchy_root_id)), ); - delegation_node.parent = Some(alternative_parent_id); - let delegate_signature = delegate_keypair.sign(&hash_to_u8(Delegation::calculate_hash( + let delegate_signature = delegate_keypair.sign(&hash_to_u8(Delegation::calculate_delegation_creation_hash( &delegation_id, - &delegation_node.root_id, - &delegation_node.parent, - &delegation_node.permissions, + &hierarchy_root_id, + &hierarchy_root_id, + &delegation_node.details.permissions, ))); let operation = - generate_base_delegation_creation_details(delegation_id, delegate_signature.into(), delegation_node); + generate_base_delegation_creation_operation(delegation_id, delegate_signature.into(), delegation_node.clone()); let ext = ctype_mock::ExtBuilder::default() - .with_ctypes(vec![(root_node.ctype_hash, creator.clone())]) + .with_ctypes(vec![(hierarchy_details.ctype_hash, creator.clone())]) .build(None); let mut ext = ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, creator.clone())]) + .with_delegations(vec![(delegation_id, delegation_node)]) .build(Some(ext)); ext.execute_with(|| { - assert_err!( + assert_noop!( Delegation::add_delegation( get_origin(creator.clone()), operation.delegation_id, - operation.root_id, operation.parent_id, delegate.clone(), operation.permissions, operation.delegate_signature.clone().encode(), ), - delegation::Error::::ParentDelegationNotFound + delegation::Error::::DelegationAlreadyExists ); }); } #[test] -fn not_owner_of_parent_create_delegation_error() { +fn parent_not_existing_create_delegation_error() { let creator_keypair = get_alice_ed25519(); let creator = get_ed25519_account(creator_keypair.public()); - let alternative_owner_keypair = get_charlie_ed25519(); - let alternative_owner = get_ed25519_account(alternative_owner_keypair.public()); let delegate_keypair = get_bob_sr25519(); let delegate = get_sr25519_account(delegate_keypair.public()); - let (root_id, root_node) = ( - get_delegation_root_id(true), - generate_base_delegation_root(creator.clone()), + let (hierarchy_root_id, hierarchy_details) = ( + get_delegation_hierarchy_id(true), + generate_base_delegation_hierarchy_details(), ); - let (parent_delegation_id, parent_delegation_node) = ( + let (delegation_id, delegation_node) = ( get_delegation_id(true), - generate_base_delegation_node(root_id, alternative_owner), + generate_base_delegation_node(hierarchy_root_id, delegate.clone(), Some(hierarchy_root_id)), ); - let (delegation_id, mut delegation_node) = ( - get_delegation_id(false), - generate_base_delegation_node(root_id, delegate.clone()), - ); - delegation_node.parent = Some(parent_delegation_id); - let delegate_signature = delegate_keypair.sign(&hash_to_u8(Delegation::calculate_hash( + let delegate_signature = delegate_keypair.sign(&hash_to_u8(Delegation::calculate_delegation_creation_hash( &delegation_id, - &delegation_node.root_id, - &delegation_node.parent, - &delegation_node.permissions, + &hierarchy_root_id, + &hierarchy_root_id, + &delegation_node.details.permissions, ))); let operation = - generate_base_delegation_creation_details(delegation_id, delegate_signature.into(), delegation_node); + generate_base_delegation_creation_operation(delegation_id, delegate_signature.into(), delegation_node); let ext = ctype_mock::ExtBuilder::default() - .with_ctypes(vec![(root_node.ctype_hash, creator.clone())]) + .with_ctypes(vec![(hierarchy_details.ctype_hash, creator.clone())]) .build(None); - let mut ext = ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) - .with_delegations(vec![(parent_delegation_id, parent_delegation_node)]) - .with_children(vec![(root_id, vec![parent_delegation_id])]) - .build(Some(ext)); + // No delegations added to the pallet storage + let mut ext = ExtBuilder::default().build(Some(ext)); ext.execute_with(|| { - assert_err!( + assert_noop!( Delegation::add_delegation( get_origin(creator.clone()), operation.delegation_id, - operation.root_id, operation.parent_id, delegate.clone(), operation.permissions, operation.delegate_signature.clone().encode(), ), - delegation::Error::::NotOwnerOfParentDelegation + delegation::Error::::ParentDelegationNotFound ); }); } #[test] -fn unauthorised_delegation_create_delegation_error() { +fn not_owner_of_parent_create_delegation_error() { let creator_keypair = get_alice_ed25519(); let creator = get_ed25519_account(creator_keypair.public()); + let alternative_owner_keypair = get_charlie_ed25519(); + let alternative_owner = get_ed25519_account(alternative_owner_keypair.public()); let delegate_keypair = get_bob_sr25519(); let delegate = get_sr25519_account(delegate_keypair.public()); - let (root_id, root_node) = ( - get_delegation_root_id(true), - generate_base_delegation_root(creator.clone()), + let (hierarchy_root_id, hierarchy_details) = ( + get_delegation_hierarchy_id(true), + generate_base_delegation_hierarchy_details(), ); - let (parent_delegation_id, mut parent_delegation_node) = ( + let (parent_id, parent_node) = ( get_delegation_id(true), - generate_base_delegation_node(root_id, creator.clone()), + generate_base_delegation_node(hierarchy_root_id, alternative_owner, Some(hierarchy_root_id)), ); - parent_delegation_node.permissions = delegation::Permissions::ATTEST; - let (delegation_id, mut delegation_node) = ( + let (delegation_id, delegation_node) = ( get_delegation_id(false), - generate_base_delegation_node(root_id, delegate.clone()), + generate_base_delegation_node(hierarchy_root_id, delegate.clone(), Some(parent_id)), ); - delegation_node.parent = Some(parent_delegation_id); - let delegate_signature = delegate_keypair.sign(&hash_to_u8(Delegation::calculate_hash( + let delegate_signature = delegate_keypair.sign(&hash_to_u8(Delegation::calculate_delegation_creation_hash( &delegation_id, - &delegation_node.root_id, - &delegation_node.parent, - &delegation_node.permissions, + &hierarchy_root_id, + &parent_id, + &delegation_node.details.permissions, ))); let operation = - generate_base_delegation_creation_details(delegation_id, delegate_signature.into(), delegation_node); + generate_base_delegation_creation_operation(delegation_id, delegate_signature.into(), delegation_node); let ext = ctype_mock::ExtBuilder::default() - .with_ctypes(vec![(root_node.ctype_hash, creator.clone())]) + .with_ctypes(vec![(hierarchy_details.ctype_hash, creator.clone())]) .build(None); let mut ext = ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) - .with_delegations(vec![(parent_delegation_id, parent_delegation_node)]) - .with_children(vec![(root_id, vec![parent_delegation_id])]) + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, creator.clone())]) + .with_delegations(vec![(parent_id, parent_node)]) .build(Some(ext)); ext.execute_with(|| { - assert_err!( + assert_noop!( Delegation::add_delegation( get_origin(creator.clone()), operation.delegation_id, - operation.root_id, operation.parent_id, delegate.clone(), operation.permissions, operation.delegate_signature.clone().encode(), ), - delegation::Error::::UnauthorizedDelegation + delegation::Error::::NotOwnerOfParentDelegation ); }); } #[test] -fn not_owner_of_root_create_delegation_error() { +fn unauthorised_delegation_create_delegation_error() { let creator_keypair = get_alice_ed25519(); let creator = get_ed25519_account(creator_keypair.public()); - let alternative_owner_keypair = get_charlie_ed25519(); - let alternative_owner = get_ed25519_account(alternative_owner_keypair.public()); let delegate_keypair = get_bob_sr25519(); let delegate = get_sr25519_account(delegate_keypair.public()); - let (root_id, root_node) = ( - get_delegation_root_id(true), - generate_base_delegation_root(alternative_owner), + let (hierarchy_root_id, hierarchy_details) = ( + get_delegation_hierarchy_id(true), + generate_base_delegation_hierarchy_details(), ); - let (delegation_id, delegation_node) = ( + let (parent_id, mut parent_node) = ( get_delegation_id(true), - generate_base_delegation_node(root_id, delegate.clone()), + generate_base_delegation_node(hierarchy_root_id, creator.clone(), Some(hierarchy_root_id)), + ); + parent_node.details.permissions = delegation::Permissions::ATTEST; + let (delegation_id, delegation_node) = ( + get_delegation_id(false), + generate_base_delegation_node(hierarchy_root_id, delegate.clone(), Some(parent_id)), ); - let delegate_signature = delegate_keypair.sign(&hash_to_u8(Delegation::calculate_hash( + let delegate_signature = delegate_keypair.sign(&hash_to_u8(Delegation::calculate_delegation_creation_hash( &delegation_id, - &delegation_node.root_id, - &delegation_node.parent, - &delegation_node.permissions, + &hierarchy_root_id, + &parent_id, + &delegation_node.details.permissions, ))); let operation = - generate_base_delegation_creation_details(delegation_id, delegate_signature.into(), delegation_node); + generate_base_delegation_creation_operation(delegation_id, delegate_signature.into(), delegation_node); let ext = ctype_mock::ExtBuilder::default() - .with_ctypes(vec![(root_node.ctype_hash, creator.clone())]) + .with_ctypes(vec![(hierarchy_details.ctype_hash, creator.clone())]) .build(None); let mut ext = ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, creator.clone())]) + .with_delegations(vec![(parent_id, parent_node)]) .build(Some(ext)); ext.execute_with(|| { @@ -600,218 +608,220 @@ fn not_owner_of_root_create_delegation_error() { Delegation::add_delegation( get_origin(creator.clone()), operation.delegation_id, - operation.root_id, operation.parent_id, delegate.clone(), operation.permissions, operation.delegate_signature.clone().encode(), ), - delegation::Error::::NotOwnerOfRootDelegation + delegation::Error::::UnauthorizedDelegation ); }); } // submit_delegation_root_revocation_operation() + #[test] fn empty_revoke_root_successful() { let revoker_keypair = get_alice_ed25519(); let revoker = get_ed25519_account(revoker_keypair.public()); - let (root_id, root_node) = ( - get_delegation_root_id(true), - generate_base_delegation_root(revoker.clone()), + let (hierarchy_root_id, hierarchy_details) = ( + get_delegation_hierarchy_id(true), + generate_base_delegation_hierarchy_details(), ); - let mut operation = generate_base_delegation_root_revocation_details(root_id); - operation.max_children = 2u32; + let operation = generate_base_delegation_hierarchy_revocation_operation(hierarchy_root_id); let ext = ctype_mock::ExtBuilder::default() - .with_ctypes(vec![(root_node.ctype_hash, revoker.clone())]) + .with_ctypes(vec![(hierarchy_details.ctype_hash, revoker.clone())]) .build(None); let mut ext = ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, revoker.clone())]) .build(Some(ext)); ext.execute_with(|| { - assert_ok!(Delegation::revoke_root( + assert_ok!(Delegation::revoke_delegation( get_origin(revoker.clone()), - operation.root_id, + operation.id, + 0u32, operation.max_children )); }); - let stored_delegation_root = ext - .execute_with(|| Delegation::roots(&operation.root_id).expect("Delegation root should be present on chain.")); - assert!(stored_delegation_root.revoked); + let stored_delegation_hierarchy_root = ext.execute_with(|| { + Delegation::delegation_nodes(&operation.id).expect("Delegation root should be present on chain.") + }); + + assert!(stored_delegation_hierarchy_root.details.revoked); } #[test] fn list_hierarchy_revoke_root_successful() { let revoker_keypair = get_alice_ed25519(); let revoker = get_ed25519_account(revoker_keypair.public()); - let delegate_keypair = get_bob_ed25519(); - let delegate = get_ed25519_account(delegate_keypair.public()); + let delegate_keypair = get_bob_sr25519(); + let delegate = get_sr25519_account(delegate_keypair.public()); - let (root_id, root_node) = ( - get_delegation_root_id(true), - generate_base_delegation_root(revoker.clone()), + let (hierarchy_root_id, hierarchy_details) = ( + get_delegation_hierarchy_id(true), + generate_base_delegation_hierarchy_details(), ); - let (parent_delegation_id, parent_delegation_node) = ( + let (parent_id, parent_node) = ( get_delegation_id(true), - generate_base_delegation_node(root_id, revoker.clone()), + generate_base_delegation_node(hierarchy_root_id, revoker.clone(), Some(hierarchy_root_id)), ); - let (delegation_id, mut delegation_node) = ( + let (delegation_id, delegation_node) = ( get_delegation_id(false), - generate_base_delegation_node(root_id, delegate), + generate_base_delegation_node(hierarchy_root_id, delegate, Some(parent_id)), ); - delegation_node.parent = Some(parent_delegation_id); - let mut operation = generate_base_delegation_root_revocation_details(root_id); + let mut operation = generate_base_delegation_hierarchy_revocation_operation(hierarchy_root_id); operation.max_children = 2u32; let ext = ctype_mock::ExtBuilder::default() - .with_ctypes(vec![(root_node.ctype_hash, revoker.clone())]) + .with_ctypes(vec![(hierarchy_details.ctype_hash, revoker.clone())]) .build(None); let mut ext = ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) - .with_delegations(vec![ - (parent_delegation_id, parent_delegation_node), - (delegation_id, delegation_node), - ]) - .with_children(vec![ - // Root -> Parent -> Delegation - (root_id, vec![parent_delegation_id]), - (parent_delegation_id, vec![delegation_id]), - ]) + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, revoker.clone())]) + .with_delegations(vec![(parent_id, parent_node), (delegation_id, delegation_node)]) .build(Some(ext)); ext.execute_with(|| { - assert_ok!(Delegation::revoke_root( + assert_ok!(Delegation::revoke_delegation( get_origin(revoker.clone()), - operation.root_id, + operation.id, + 0u32, operation.max_children )); }); - let stored_delegation_root = ext - .execute_with(|| Delegation::roots(&operation.root_id).expect("Delegation root should be present on chain.")); - assert!(stored_delegation_root.revoked); + let stored_delegation_hierarchy_root = ext.execute_with(|| { + Delegation::delegation_nodes(&operation.id).expect("Delegation root should be present on chain.") + }); + assert!(stored_delegation_hierarchy_root.details.revoked); let stored_parent_delegation = ext.execute_with(|| { - Delegation::delegations(&parent_delegation_id).expect("Parent delegation should be present on chain.") + Delegation::delegation_nodes(&parent_id).expect("Parent delegation should be present on chain.") }); - assert!(stored_parent_delegation.revoked); + assert!(stored_parent_delegation.details.revoked); - let stored_delegation = - ext.execute_with(|| Delegation::delegations(&delegation_id).expect("Delegation should be present on chain.")); - assert!(stored_delegation.revoked); + let stored_delegation = ext + .execute_with(|| Delegation::delegation_nodes(&delegation_id).expect("Delegation should be present on chain.")); + assert!(stored_delegation.details.revoked); } #[test] fn tree_hierarchy_revoke_root_successful() { let revoker_keypair = get_alice_ed25519(); let revoker = get_ed25519_account(revoker_keypair.public()); - let delegate_keypair = get_bob_ed25519(); - let delegate = get_ed25519_account(delegate_keypair.public()); + let delegate_keypair = get_bob_sr25519(); + let delegate = get_sr25519_account(delegate_keypair.public()); - let (root_id, root_node) = ( - get_delegation_root_id(true), - generate_base_delegation_root(revoker.clone()), + let (hierarchy_root_id, hierarchy_details) = ( + get_delegation_hierarchy_id(true), + generate_base_delegation_hierarchy_details(), ); - let (delegation_id_1, delegation_node_1) = ( + let (delegation1_id, delegation1_node) = ( get_delegation_id(true), - generate_base_delegation_node(root_id, revoker.clone()), + generate_base_delegation_node(hierarchy_root_id, revoker.clone(), Some(hierarchy_root_id)), ); - let (delegation_id_2, delegation_node_2) = ( + let (delegation2_id, delegation2_node) = ( get_delegation_id(false), - generate_base_delegation_node(root_id, delegate), + generate_base_delegation_node(hierarchy_root_id, delegate, Some(hierarchy_root_id)), ); - let mut operation = generate_base_delegation_root_revocation_details(root_id); + let mut operation = generate_base_delegation_hierarchy_revocation_operation(hierarchy_root_id); operation.max_children = 2u32; let ext = ctype_mock::ExtBuilder::default() - .with_ctypes(vec![(root_node.ctype_hash, revoker.clone())]) + .with_ctypes(vec![(hierarchy_details.ctype_hash, revoker.clone())]) .build(None); let mut ext = ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, revoker.clone())]) .with_delegations(vec![ - (delegation_id_1, delegation_node_1), - (delegation_id_2, delegation_node_2), - ]) - .with_children(vec![ - // Root -> Delegation 1 && Delegation 2 - (root_id, vec![delegation_id_1, delegation_id_2]), + (delegation1_id, delegation1_node), + (delegation2_id, delegation2_node), ]) .build(Some(ext)); ext.execute_with(|| { - assert_ok!(Delegation::revoke_root( + assert_ok!(Delegation::revoke_delegation( get_origin(revoker.clone()), - operation.root_id, + operation.id, + 0u32, operation.max_children )); }); - let stored_delegation_root = ext - .execute_with(|| Delegation::roots(&operation.root_id).expect("Delegation root should be present on chain.")); - assert!(stored_delegation_root.revoked); + let stored_delegation_hierarchy_root = ext.execute_with(|| { + Delegation::delegation_nodes(&operation.id).expect("Delegation root should be present on chain.") + }); + assert!(stored_delegation_hierarchy_root.details.revoked); - let stored_delegation_1 = ext - .execute_with(|| Delegation::delegations(&delegation_id_1).expect("Delegation 1 should be present on chain.")); - assert!(stored_delegation_1.revoked); + let stored_delegation_1 = ext.execute_with(|| { + Delegation::delegation_nodes(&delegation1_id).expect("Delegation 1 should be present on chain.") + }); + assert!(stored_delegation_1.details.revoked); - let stored_delegation_2 = ext - .execute_with(|| Delegation::delegations(&delegation_id_2).expect("Delegation 2 should be present on chain.")); - assert!(stored_delegation_2.revoked); + let stored_delegation_2 = ext.execute_with(|| { + Delegation::delegation_nodes(&delegation2_id).expect("Delegation 2 should be present on chain.") + }); + assert!(stored_delegation_2.details.revoked); } #[test] -fn greater_max_revocations_revoke_root_successful() { +fn max_max_revocations_revoke_successful() { let revoker_keypair = get_alice_ed25519(); let revoker = get_ed25519_account(revoker_keypair.public()); - let delegate_keypair = get_alice_ed25519(); - let delegate = get_ed25519_account(delegate_keypair.public()); + let delegate_keypair = get_bob_sr25519(); + let delegate = get_sr25519_account(delegate_keypair.public()); - let (root_id, root_node) = ( - get_delegation_root_id(true), - generate_base_delegation_root(revoker.clone()), + let (hierarchy_root_id, hierarchy_details) = ( + get_delegation_hierarchy_id(true), + generate_base_delegation_hierarchy_details(), + ); + let (parent_id, parent_node) = ( + get_delegation_id(true), + generate_base_delegation_node(hierarchy_root_id, revoker.clone(), Some(hierarchy_root_id)), ); let (delegation_id, delegation_node) = ( get_delegation_id(false), - generate_base_delegation_node(root_id, delegate), + generate_base_delegation_node(hierarchy_root_id, delegate, Some(parent_id)), ); - let mut operation = generate_base_delegation_root_revocation_details(root_id); + let mut operation = generate_base_delegation_hierarchy_revocation_operation(hierarchy_root_id); operation.max_children = MaxRevocations::get(); let ext = ctype_mock::ExtBuilder::default() - .with_ctypes(vec![(root_node.ctype_hash, revoker.clone())]) + .with_ctypes(vec![(hierarchy_details.ctype_hash, revoker.clone())]) .build(None); let mut ext = ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) - .with_delegations(vec![(delegation_id, delegation_node)]) - .with_children(vec![ - // Root -> Delegation - (root_id, vec![delegation_id]), - ]) + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, revoker.clone())]) + .with_delegations(vec![(parent_id, parent_node), (delegation_id, delegation_node)]) .build(Some(ext)); ext.execute_with(|| { - assert_ok!(Delegation::revoke_root( + assert_ok!(Delegation::revoke_delegation( get_origin(revoker.clone()), - operation.root_id, + operation.id, + 0u32, operation.max_children )); }); - let stored_delegation_root = ext - .execute_with(|| Delegation::roots(&operation.root_id).expect("Delegation root should be present on chain.")); - assert!(stored_delegation_root.revoked); + let stored_delegation_hierarchy_root = ext.execute_with(|| { + Delegation::delegation_nodes(&operation.id).expect("Delegation root should be present on chain.") + }); + assert!(stored_delegation_hierarchy_root.details.revoked); + + let stored_parent_delegation = ext.execute_with(|| { + Delegation::delegation_nodes(&parent_id).expect("Parent delegation should be present on chain.") + }); + assert!(stored_parent_delegation.details.revoked); - let stored_delegation = - ext.execute_with(|| Delegation::delegations(&delegation_id).expect("Delegation should be present on chain.")); - assert!(stored_delegation.revoked); + let stored_delegation = ext + .execute_with(|| Delegation::delegation_nodes(&delegation_id).expect("Delegation should be present on chain.")); + assert!(stored_delegation.details.revoked); } #[test] @@ -819,16 +829,16 @@ fn root_not_found_revoke_root_error() { let revoker_keypair = get_alice_ed25519(); let revoker = get_ed25519_account(revoker_keypair.public()); - let root_id = get_delegation_root_id(true); + let hierarchy_root_id = get_delegation_hierarchy_id(true); - let operation = generate_base_delegation_root_revocation_details(root_id); + let operation = generate_base_delegation_hierarchy_revocation_operation(hierarchy_root_id); let mut ext = ExtBuilder::default().build(None); ext.execute_with(|| { assert_noop!( - Delegation::revoke_root(get_origin(revoker.clone()), operation.root_id, operation.max_children), - delegation::Error::::RootNotFound + Delegation::revoke_delegation(get_origin(revoker.clone()), operation.id, 0u32, operation.max_children), + delegation::Error::::DelegationNotFound ); }); } @@ -840,23 +850,23 @@ fn different_root_creator_revoke_root_error() { let alternative_revoker_keypair = get_charlie_ed25519(); let alternative_revoker = get_ed25519_account(alternative_revoker_keypair.public()); - let (root_id, root_node) = ( - get_delegation_root_id(true), - generate_base_delegation_root(alternative_revoker), + let (hierarchy_root_id, hierarchy_details) = ( + get_delegation_hierarchy_id(true), + generate_base_delegation_hierarchy_details(), ); - let operation = generate_base_delegation_root_revocation_details(root_id); + let operation = generate_base_delegation_hierarchy_revocation_operation(hierarchy_root_id); let ext = ctype_mock::ExtBuilder::default() - .with_ctypes(vec![(root_node.ctype_hash, revoker.clone())]) + .with_ctypes(vec![(hierarchy_details.ctype_hash, revoker.clone())]) .build(None); let mut ext = ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, alternative_revoker)]) .build(Some(ext)); ext.execute_with(|| { assert_noop!( - Delegation::revoke_root(get_origin(revoker.clone()), operation.root_id, operation.max_children), + Delegation::revoke_delegation(get_origin(revoker.clone()), operation.id, 0u32, operation.max_children), delegation::Error::::UnauthorizedRevocation ); }); @@ -869,33 +879,29 @@ fn too_small_max_revocations_revoke_root_error() { let delegate_keypair = get_alice_ed25519(); let delegate = get_ed25519_account(delegate_keypair.public()); - let (root_id, root_node) = ( - get_delegation_root_id(true), - generate_base_delegation_root(revoker.clone()), + let (hierarchy_root_id, hierarchy_details) = ( + get_delegation_hierarchy_id(true), + generate_base_delegation_hierarchy_details(), ); let (delegation_id, delegation_node) = ( get_delegation_id(false), - generate_base_delegation_node(root_id, delegate), + generate_base_delegation_node(hierarchy_root_id, delegate, Some(hierarchy_root_id)), ); - let mut operation = generate_base_delegation_root_revocation_details(root_id); + let mut operation = generate_base_delegation_hierarchy_revocation_operation(hierarchy_root_id); operation.max_children = 0u32; let ext = ctype_mock::ExtBuilder::default() - .with_ctypes(vec![(root_node.ctype_hash, revoker.clone())]) + .with_ctypes(vec![(hierarchy_details.ctype_hash, revoker.clone())]) .build(None); let mut ext = ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, revoker.clone())]) .with_delegations(vec![(delegation_id, delegation_node)]) - .with_children(vec![ - // Root -> Delegation - (root_id, vec![delegation_id]), - ]) .build(Some(ext)); ext.execute_with(|| { assert_noop!( - Delegation::revoke_root(get_origin(revoker.clone()), operation.root_id, operation.max_children), + Delegation::revoke_delegation(get_origin(revoker.clone()), operation.id, 0u32, operation.max_children), delegation::Error::::ExceededRevocationBounds ); }); @@ -908,42 +914,35 @@ fn exact_children_max_revocations_revoke_root_error() { let delegate_keypair = get_alice_ed25519(); let delegate = get_ed25519_account(delegate_keypair.public()); - let (root_id, root_node) = ( - get_delegation_root_id(true), - generate_base_delegation_root(revoker.clone()), + let (hierarchy_root_id, hierarchy_details) = ( + get_delegation_hierarchy_id(true), + generate_base_delegation_hierarchy_details(), ); - let (delegation_id_1, delegation_node_1) = ( + let (delegation1_id, delegation1_node) = ( get_delegation_id(true), - generate_base_delegation_node(root_id, delegate.clone()), + generate_base_delegation_node(hierarchy_root_id, delegate.clone(), Some(hierarchy_root_id)), ); - let (delegation_id_2, mut delegation_node_2) = ( + let (delegation2_id, delegation2_node) = ( get_delegation_id(false), - generate_base_delegation_node(root_id, delegate.clone()), + generate_base_delegation_node(hierarchy_root_id, delegate.clone(), Some(delegation1_id)), ); - delegation_node_2.parent = Some(delegation_id_1); - let (delegation_id_3, mut delegation_node_3) = ( - get_delegation_root_id(false), - generate_base_delegation_node(root_id, delegate), + let (delegation3_id, delegation3_node) = ( + get_delegation_id_2(true), + generate_base_delegation_node(hierarchy_root_id, delegate, Some(delegation1_id)), ); - delegation_node_3.parent = Some(delegation_id_1); - let mut operation = generate_base_delegation_root_revocation_details(root_id); + let mut operation = generate_base_delegation_hierarchy_revocation_operation(hierarchy_root_id); operation.max_children = 2u32; let ext = ctype_mock::ExtBuilder::default() - .with_ctypes(vec![(root_node.ctype_hash, revoker.clone())]) + .with_ctypes(vec![(hierarchy_details.ctype_hash, revoker.clone())]) .build(None); let mut ext = ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, revoker.clone())]) .with_delegations(vec![ - (delegation_id_1, delegation_node_1), - (delegation_id_2, delegation_node_2), - (delegation_id_3, delegation_node_3), - ]) - .with_children(vec![ - // Root -> Delegation 1 -> Delegation 2 && Delegation 3 - (root_id, vec![delegation_id_1]), - (delegation_id_1, vec![delegation_id_2, delegation_id_3]), + (delegation1_id, delegation1_node), + (delegation2_id, delegation2_node), + (delegation3_id, delegation3_node), ]) .build(Some(ext)); @@ -951,28 +950,32 @@ fn exact_children_max_revocations_revoke_root_error() { // assert_err and not asser_noop becase the storage is indeed changed, even tho // partially assert_err!( - Delegation::revoke_root(get_origin(revoker.clone()), operation.root_id, operation.max_children), + Delegation::revoke_delegation(get_origin(revoker.clone()), operation.id, 0u32, operation.max_children), delegation::Error::::ExceededRevocationBounds ); }); - let stored_delegation_root = ext - .execute_with(|| Delegation::roots(&operation.root_id).expect("Delegation root should be present on chain.")); - assert!(!stored_delegation_root.revoked); + let stored_delegation_root = ext.execute_with(|| { + Delegation::delegation_nodes(&operation.id).expect("Delegation root should be present on chain.") + }); + assert!(!stored_delegation_root.details.revoked); - let stored_delegation_1 = ext - .execute_with(|| Delegation::delegations(&delegation_id_1).expect("Delegation 1 should be present on chain.")); - assert!(!stored_delegation_1.revoked); + let stored_delegation_1 = ext.execute_with(|| { + Delegation::delegation_nodes(&delegation1_id).expect("Delegation 1 should be present on chain.") + }); + assert!(!stored_delegation_1.details.revoked); // Only this leaf should have been revoked as it is the first child of // delegation_1 - let stored_delegation_2 = ext - .execute_with(|| Delegation::delegations(&delegation_id_2).expect("Delegation 2 should be present on chain.")); - assert!(stored_delegation_2.revoked); + let stored_delegation_2 = ext.execute_with(|| { + Delegation::delegation_nodes(&delegation2_id).expect("Delegation 2 should be present on chain.") + }); + assert!(stored_delegation_2.details.revoked); - let stored_delegation_3 = ext - .execute_with(|| Delegation::delegations(&delegation_id_3).expect("Delegation 3 should be present on chain.")); - assert!(!stored_delegation_3.revoked); + let stored_delegation_3 = ext.execute_with(|| { + Delegation::delegation_nodes(&delegation3_id).expect("Delegation 3 should be present on chain.") + }); + assert!(!stored_delegation_3.details.revoked); } // submit_delegation_revocation_operation() @@ -984,37 +987,28 @@ fn direct_owner_revoke_delegation_successful() { let delegate_keypair = get_alice_ed25519(); let delegate = get_ed25519_account(delegate_keypair.public()); - let (root_id, root_node) = ( - get_delegation_root_id(true), - generate_base_delegation_root(revoker.clone()), + let (hierarchy_root_id, hierarchy_details) = ( + get_delegation_hierarchy_id(true), + generate_base_delegation_hierarchy_details(), ); - let (parent_delegation_id, parent_delegation_node) = ( + let (parent_id, parent_node) = ( get_delegation_id(true), - generate_base_delegation_node(root_id, revoker.clone()), + generate_base_delegation_node(hierarchy_root_id, revoker.clone(), Some(hierarchy_root_id)), ); - let (delegation_id, mut delegation_node) = ( + let (delegation_id, delegation_node) = ( get_delegation_id(false), - generate_base_delegation_node(root_id, delegate), + generate_base_delegation_node(hierarchy_root_id, delegate, Some(parent_id)), ); - delegation_node.parent = Some(parent_delegation_id); - let mut operation = generate_base_delegation_revocation_details(parent_delegation_id); + let mut operation = generate_base_delegation_revocation_operation(parent_id); operation.max_revocations = 2u32; let ext = ctype_mock::ExtBuilder::default() - .with_ctypes(vec![(root_node.ctype_hash, revoker.clone())]) + .with_ctypes(vec![(hierarchy_details.ctype_hash, revoker.clone())]) .build(None); - // Root -> Parent -> Child let mut ext = ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) - .with_delegations(vec![ - (parent_delegation_id, parent_delegation_node), - (delegation_id, delegation_node), - ]) - .with_children(vec![ - (root_id, vec![parent_delegation_id]), - (parent_delegation_id, vec![delegation_id]), - ]) + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, revoker.clone())]) + .with_delegations(vec![(parent_id, parent_node), (delegation_id, delegation_node)]) .build(Some(ext)); ext.execute_with(|| { @@ -1027,14 +1021,14 @@ fn direct_owner_revoke_delegation_successful() { }); let stored_parent_delegation = ext.execute_with(|| { - Delegation::delegations(&parent_delegation_id).expect("Parent delegation should be present on chain.") + Delegation::delegation_nodes(&parent_id).expect("Parent delegation should be present on chain.") }); - assert!(stored_parent_delegation.revoked); + assert!(stored_parent_delegation.details.revoked); let stored_child_delegation = ext.execute_with(|| { - Delegation::delegations(&delegation_id).expect("Child delegation should be present on chain.") + Delegation::delegation_nodes(&delegation_id).expect("Child delegation should be present on chain.") }); - assert!(stored_child_delegation.revoked); + assert!(stored_child_delegation.details.revoked); } #[test] @@ -1044,37 +1038,29 @@ fn parent_owner_revoke_delegation_successful() { let delegate_keypair = get_alice_ed25519(); let delegate = get_ed25519_account(delegate_keypair.public()); - let (root_id, root_node) = ( - get_delegation_root_id(true), - generate_base_delegation_root(revoker.clone()), + let (hierarchy_root_id, hierarchy_details) = ( + get_delegation_hierarchy_id(true), + generate_base_delegation_hierarchy_details(), ); - let (parent_delegation_id, parent_delegation_node) = ( + let (parent_id, parent_node) = ( get_delegation_id(true), - generate_base_delegation_node(root_id, revoker.clone()), + generate_base_delegation_node(hierarchy_root_id, revoker.clone(), Some(hierarchy_root_id)), ); - let (delegation_id, mut delegation_node) = ( + let (delegation_id, delegation_node) = ( get_delegation_id(false), - generate_base_delegation_node(root_id, delegate), + generate_base_delegation_node(hierarchy_root_id, delegate, Some(parent_id)), ); - delegation_node.parent = Some(parent_delegation_id); - let mut operation = generate_base_delegation_revocation_details(delegation_id); + let mut operation = generate_base_delegation_revocation_operation(delegation_id); operation.max_parent_checks = 1u32; operation.max_revocations = 1u32; let ext = ctype_mock::ExtBuilder::default() - .with_ctypes(vec![(root_node.ctype_hash, revoker.clone())]) + .with_ctypes(vec![(hierarchy_details.ctype_hash, revoker.clone())]) .build(None); let mut ext = ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) - .with_delegations(vec![ - (parent_delegation_id, parent_delegation_node), - (delegation_id, delegation_node), - ]) - .with_children(vec![ - (root_id, vec![parent_delegation_id]), - (parent_delegation_id, vec![delegation_id]), - ]) + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, revoker.clone())]) + .with_delegations(vec![(parent_id, parent_node), (delegation_id, delegation_node)]) .build(Some(ext)); ext.execute_with(|| { @@ -1087,14 +1073,14 @@ fn parent_owner_revoke_delegation_successful() { }); let stored_parent_delegation = ext.execute_with(|| { - Delegation::delegations(&parent_delegation_id).expect("Parent delegation should be present on chain.") + Delegation::delegation_nodes(&parent_id).expect("Parent delegation should be present on chain.") }); - assert!(!stored_parent_delegation.revoked); + assert!(!stored_parent_delegation.details.revoked); let stored_child_delegation = ext.execute_with(|| { - Delegation::delegations(&delegation_id).expect("Child delegation should be present on chain.") + Delegation::delegation_nodes(&delegation_id).expect("Child delegation should be present on chain.") }); - assert!(stored_child_delegation.revoked); + assert!(stored_child_delegation.details.revoked); } #[test] @@ -1102,19 +1088,19 @@ fn delegation_not_found_revoke_delegation_error() { let revoker_keypair = get_alice_ed25519(); let revoker = get_ed25519_account(revoker_keypair.public()); - let (root_id, root_node) = ( - get_delegation_root_id(true), - generate_base_delegation_root(revoker.clone()), + let (hierarchy_root_id, hierarchy_details) = ( + get_delegation_hierarchy_id(true), + generate_base_delegation_hierarchy_details(), ); - let delegation_id = get_delegation_id(true); + let delegation_id = get_delegation_id(false); - let operation = generate_base_delegation_revocation_details(delegation_id); + let operation = generate_base_delegation_revocation_operation(delegation_id); let ext = ctype_mock::ExtBuilder::default() - .with_ctypes(vec![(root_node.ctype_hash, revoker.clone())]) + .with_ctypes(vec![(hierarchy_details.ctype_hash, revoker.clone())]) .build(None); let mut ext = ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, revoker.clone())]) .build(Some(ext)); ext.execute_with(|| { @@ -1137,22 +1123,24 @@ fn not_delegating_revoke_delegation_error() { let revoker_keypair = get_bob_ed25519(); let revoker = get_ed25519_account(revoker_keypair.public()); - let (root_id, root_node) = ( - get_delegation_root_id(true), - generate_base_delegation_root(owner.clone()), + let (hierarchy_root_id, hierarchy_details) = ( + get_delegation_hierarchy_id(true), + generate_base_delegation_hierarchy_details(), + ); + let (delegation_id, delegation_node) = ( + get_delegation_id(true), + generate_base_delegation_node(hierarchy_root_id, owner.clone(), Some(hierarchy_root_id)), ); - let (delegation_id, delegation_node) = (get_delegation_id(false), generate_base_delegation_node(root_id, owner)); - let mut operation = generate_base_delegation_revocation_details(delegation_id); + let mut operation = generate_base_delegation_revocation_operation(delegation_id); operation.max_parent_checks = MaxParentChecks::get(); let ext = ctype_mock::ExtBuilder::default() - .with_ctypes(vec![(root_node.ctype_hash, revoker.clone())]) + .with_ctypes(vec![(hierarchy_details.ctype_hash, revoker.clone())]) .build(None); let mut ext = ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, owner)]) .with_delegations(vec![(delegation_id, delegation_node)]) - .with_children(vec![(root_id, vec![delegation_id])]) .build(Some(ext)); ext.execute_with(|| { @@ -1177,36 +1165,28 @@ fn parent_too_far_revoke_delegation_error() { let delegate_keypair = get_bob_ed25519(); let delegate = get_ed25519_account(delegate_keypair.public()); - let (root_id, root_node) = ( - get_delegation_root_id(true), - generate_base_delegation_root(owner.clone()), + let (hierarchy_root_id, hierarchy_details) = ( + get_delegation_hierarchy_id(true), + generate_base_delegation_hierarchy_details(), ); - let (parent_delegation_id, parent_delegation_node) = ( + let (parent_id, parent_node) = ( get_delegation_id(true), - generate_base_delegation_node(root_id, intermediate.clone()), + generate_base_delegation_node(hierarchy_root_id, intermediate.clone(), Some(hierarchy_root_id)), ); - let (delegation_id, mut delegation_node) = ( + let (delegation_id, delegation_node) = ( get_delegation_id(false), - generate_base_delegation_node(root_id, delegate), + generate_base_delegation_node(hierarchy_root_id, delegate, Some(parent_id)), ); - delegation_node.parent = Some(parent_delegation_id); - let mut operation = generate_base_delegation_revocation_details(delegation_id); + let mut operation = generate_base_delegation_revocation_operation(delegation_id); operation.max_parent_checks = 0u32; let ext = ctype_mock::ExtBuilder::default() - .with_ctypes(vec![(root_node.ctype_hash, owner)]) + .with_ctypes(vec![(hierarchy_details.ctype_hash, owner.clone())]) .build(None); let mut ext = ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) - .with_delegations(vec![ - (parent_delegation_id, parent_delegation_node), - (delegation_id, delegation_node), - ]) - .with_children(vec![ - (root_id, vec![parent_delegation_id]), - (parent_delegation_id, vec![delegation_id]), - ]) + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, owner)]) + .with_delegations(vec![(parent_id, parent_node), (delegation_id, delegation_node)]) .build(Some(ext)); ext.execute_with(|| { @@ -1229,36 +1209,27 @@ fn too_many_revocations_revoke_delegation_error() { let delegate_keypair = get_bob_ed25519(); let delegate = get_ed25519_account(delegate_keypair.public()); - let (root_id, root_node) = ( - get_delegation_root_id(true), - generate_base_delegation_root(revoker.clone()), + let (hierarchy_root_id, hierarchy_details) = ( + get_delegation_hierarchy_id(true), + generate_base_delegation_hierarchy_details(), ); - let (parent_delegation_id, parent_delegation_node) = ( + let (parent_id, parent_node) = ( get_delegation_id(true), - generate_base_delegation_node(root_id, revoker.clone()), + generate_base_delegation_node(hierarchy_root_id, revoker.clone(), Some(hierarchy_root_id)), ); - let (delegation_id, mut delegation_node) = ( + let (delegation_id, delegation_node) = ( get_delegation_id(false), - generate_base_delegation_node(root_id, delegate), + generate_base_delegation_node(hierarchy_root_id, delegate, Some(parent_id)), ); - delegation_node.parent = Some(parent_delegation_id); - let mut operation = generate_base_delegation_revocation_details(delegation_id); - operation.max_parent_checks = 1u32; + let operation = generate_base_delegation_revocation_operation(parent_id); let ext = ctype_mock::ExtBuilder::default() - .with_ctypes(vec![(root_node.ctype_hash, revoker.clone())]) + .with_ctypes(vec![(hierarchy_details.ctype_hash, revoker.clone())]) .build(None); let mut ext = ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) - .with_delegations(vec![ - (parent_delegation_id, parent_delegation_node), - (delegation_id, delegation_node), - ]) - .with_children(vec![ - (root_id, vec![parent_delegation_id]), - (parent_delegation_id, vec![delegation_id]), - ]) + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, revoker.clone())]) + .with_delegations(vec![(parent_id, parent_node), (delegation_id, delegation_node)]) .build(Some(ext)); ext.execute_with(|| { @@ -1285,33 +1256,33 @@ fn is_delegating_direct_not_revoked() { let user_3_keypair = get_charlie_ed25519(); let user_3 = get_ed25519_account(user_3_keypair.public()); - let (root_id, root_node) = (get_delegation_root_id(true), generate_base_delegation_root(user_1)); - let (delegation_id_1, delegation_node_1) = - (get_delegation_id(true), generate_base_delegation_node(root_id, user_2)); - let (delegation_id_2, mut delegation_node_2) = ( + let (hierarchy_root_id, hierarchy_details) = ( + get_delegation_hierarchy_id(true), + generate_base_delegation_hierarchy_details(), + ); + let (parent_id, parent_node) = ( + get_delegation_id(true), + generate_base_delegation_node(hierarchy_root_id, user_2, Some(hierarchy_root_id)), + ); + let (delegation_id, delegation_node) = ( get_delegation_id(false), - generate_base_delegation_node(root_id, user_3.clone()), + generate_base_delegation_node(hierarchy_root_id, user_3.clone(), Some(parent_id)), ); - delegation_node_2.parent = Some(delegation_id_1); let max_parent_checks = 0u32; - // Root -> Delegation 1 -> Delegation 2 - let mut ext = ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) - .with_delegations(vec![ - (delegation_id_1, delegation_node_1), - (delegation_id_2, delegation_node_2), - ]) - .with_children(vec![ - (root_id, vec![delegation_id_1]), - (delegation_id_1, vec![delegation_id_2]), - ]) + // Root -> Parent -> Delegation + let ext = ctype_mock::ExtBuilder::default() + .with_ctypes(vec![(hierarchy_details.ctype_hash, user_1.clone())]) .build(None); + let mut ext = ExtBuilder::default() + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, user_1)]) + .with_delegations(vec![(parent_id, parent_node), (delegation_id, delegation_node)]) + .build(Some(ext)); ext.execute_with(|| { assert_eq!( - Delegation::is_delegating(&user_3, &delegation_id_2, max_parent_checks), + Delegation::is_delegating(&user_3, &delegation_id, max_parent_checks), Ok((true, max_parent_checks)) ); }); @@ -1326,33 +1297,33 @@ fn is_delegating_direct_not_revoked_max_parent_checks_value() { let user_3_keypair = get_charlie_ed25519(); let user_3 = get_ed25519_account(user_3_keypair.public()); - let (root_id, root_node) = (get_delegation_root_id(true), generate_base_delegation_root(user_1)); - let (delegation_id_1, delegation_node_1) = - (get_delegation_id(true), generate_base_delegation_node(root_id, user_2)); - let (delegation_id_2, mut delegation_node_2) = ( + let (hierarchy_root_id, hierarchy_details) = ( + get_delegation_hierarchy_id(true), + generate_base_delegation_hierarchy_details(), + ); + let (parent_id, parent_node) = ( + get_delegation_id(true), + generate_base_delegation_node(hierarchy_root_id, user_2, Some(hierarchy_root_id)), + ); + let (delegation_id, delegation_node) = ( get_delegation_id(false), - generate_base_delegation_node(root_id, user_3.clone()), + generate_base_delegation_node(hierarchy_root_id, user_3.clone(), Some(parent_id)), ); - delegation_node_2.parent = Some(delegation_id_1); let max_parent_checks = u32::MAX; - // Root -> Delegation 1 -> Delegation 2 - let mut ext = ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) - .with_delegations(vec![ - (delegation_id_1, delegation_node_1), - (delegation_id_2, delegation_node_2), - ]) - .with_children(vec![ - (root_id, vec![delegation_id_1]), - (delegation_id_1, vec![delegation_id_2]), - ]) + // Root -> Parent -> Delegation + let ext = ctype_mock::ExtBuilder::default() + .with_ctypes(vec![(hierarchy_details.ctype_hash, user_1.clone())]) .build(None); + let mut ext = ExtBuilder::default() + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, user_1)]) + .with_delegations(vec![(parent_id, parent_node), (delegation_id, delegation_node)]) + .build(Some(ext)); ext.execute_with(|| { assert_eq!( - Delegation::is_delegating(&user_3, &delegation_id_2, max_parent_checks), + Delegation::is_delegating(&user_3, &delegation_id, max_parent_checks), Ok((true, 0u32)) ); }); @@ -1367,35 +1338,35 @@ fn is_delegating_direct_revoked() { let user_3_keypair = get_charlie_ed25519(); let user_3 = get_ed25519_account(user_3_keypair.public()); - let (root_id, root_node) = (get_delegation_root_id(true), generate_base_delegation_root(user_1)); - let (delegation_id_1, delegation_node_1) = - (get_delegation_id(true), generate_base_delegation_node(root_id, user_2)); - let (delegation_id_2, mut delegation_node_2) = ( + let (hierarchy_root_id, hierarchy_details) = ( + get_delegation_hierarchy_id(true), + generate_base_delegation_hierarchy_details(), + ); + let (parent_id, parent_node) = ( + get_delegation_id(true), + generate_base_delegation_node(hierarchy_root_id, user_2, Some(hierarchy_root_id)), + ); + let (delegation_id, mut delegation_node) = ( get_delegation_id(false), - generate_base_delegation_node(root_id, user_3.clone()), + generate_base_delegation_node(hierarchy_root_id, user_3.clone(), Some(parent_id)), ); - delegation_node_2.parent = Some(delegation_id_1); - delegation_node_2.revoked = true; + delegation_node.details.revoked = true; let max_parent_checks = 0u32; - // Root -> Delegation 1 -> Delegation 2 - let mut ext = ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) - .with_delegations(vec![ - (delegation_id_1, delegation_node_1), - (delegation_id_2, delegation_node_2), - ]) - .with_children(vec![ - (root_id, vec![delegation_id_1]), - (delegation_id_1, vec![delegation_id_2]), - ]) + // Root -> Parent -> Delegation + let ext = ctype_mock::ExtBuilder::default() + .with_ctypes(vec![(hierarchy_details.ctype_hash, user_1.clone())]) .build(None); + let mut ext = ExtBuilder::default() + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, user_1)]) + .with_delegations(vec![(parent_id, parent_node), (delegation_id, delegation_node)]) + .build(Some(ext)); ext.execute_with(|| { assert_eq!( - Delegation::is_delegating(&user_3, &delegation_id_2, max_parent_checks), - Ok((false, max_parent_checks)) + Delegation::is_delegating(&user_3, &delegation_id, max_parent_checks), + Ok((false, 0)) ); }); } @@ -1409,35 +1380,35 @@ fn is_delegating_direct_revoked_max_parent_checks_value() { let user_3_keypair = get_charlie_ed25519(); let user_3 = get_ed25519_account(user_3_keypair.public()); - let (root_id, root_node) = (get_delegation_root_id(true), generate_base_delegation_root(user_1)); - let (delegation_id_1, delegation_node_1) = - (get_delegation_id(true), generate_base_delegation_node(root_id, user_2)); - let (delegation_id_2, mut delegation_node_2) = ( + let (hierarchy_root_id, hierarchy_details) = ( + get_delegation_hierarchy_id(true), + generate_base_delegation_hierarchy_details(), + ); + let (parent_id, parent_node) = ( + get_delegation_id(true), + generate_base_delegation_node(hierarchy_root_id, user_2, Some(hierarchy_root_id)), + ); + let (delegation_id, mut delegation_node) = ( get_delegation_id(false), - generate_base_delegation_node(root_id, user_3.clone()), + generate_base_delegation_node(hierarchy_root_id, user_3.clone(), Some(parent_id)), ); - delegation_node_2.parent = Some(delegation_id_1); - delegation_node_2.revoked = true; + delegation_node.details.revoked = true; let max_parent_checks = u32::MAX; - // Root -> Delegation 1 -> Delegation 2 - let mut ext = ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) - .with_delegations(vec![ - (delegation_id_1, delegation_node_1), - (delegation_id_2, delegation_node_2), - ]) - .with_children(vec![ - (root_id, vec![delegation_id_1]), - (delegation_id_1, vec![delegation_id_2]), - ]) + // Root -> Parent -> Delegation + let ext = ctype_mock::ExtBuilder::default() + .with_ctypes(vec![(hierarchy_details.ctype_hash, user_1.clone())]) .build(None); + let mut ext = ExtBuilder::default() + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, user_1)]) + .with_delegations(vec![(parent_id, parent_node), (delegation_id, delegation_node)]) + .build(Some(ext)); ext.execute_with(|| { assert_eq!( - Delegation::is_delegating(&user_3, &delegation_id_2, max_parent_checks), - Ok((false, 0u32)) + Delegation::is_delegating(&user_3, &delegation_id, max_parent_checks), + Ok((false, 0)) ); }); } @@ -1451,33 +1422,33 @@ fn is_delegating_max_parent_not_revoked() { let user_3_keypair = get_charlie_ed25519(); let user_3 = get_ed25519_account(user_3_keypair.public()); - let (root_id, root_node) = (get_delegation_root_id(true), generate_base_delegation_root(user_1)); - let (delegation_id_1, delegation_node_1) = ( + let (hierarchy_root_id, hierarchy_details) = ( + get_delegation_hierarchy_id(true), + generate_base_delegation_hierarchy_details(), + ); + let (parent_id, parent_node) = ( get_delegation_id(true), - generate_base_delegation_node(root_id, user_2.clone()), + generate_base_delegation_node(hierarchy_root_id, user_2.clone(), Some(hierarchy_root_id)), + ); + let (delegation_id, delegation_node) = ( + get_delegation_id(false), + generate_base_delegation_node(hierarchy_root_id, user_3, Some(parent_id)), ); - let (delegation_id_2, mut delegation_node_2) = - (get_delegation_id(false), generate_base_delegation_node(root_id, user_3)); - delegation_node_2.parent = Some(delegation_id_1); let max_parent_checks = 1u32; - // Root -> Delegation 1 -> Delegation 2 - let mut ext = ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) - .with_delegations(vec![ - (delegation_id_1, delegation_node_1), - (delegation_id_2, delegation_node_2), - ]) - .with_children(vec![ - (root_id, vec![delegation_id_1]), - (delegation_id_1, vec![delegation_id_2]), - ]) + // Root -> Parent -> Delegation + let ext = ctype_mock::ExtBuilder::default() + .with_ctypes(vec![(hierarchy_details.ctype_hash, user_1.clone())]) .build(None); + let mut ext = ExtBuilder::default() + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, user_1)]) + .with_delegations(vec![(parent_id, parent_node), (delegation_id, delegation_node)]) + .build(Some(ext)); ext.execute_with(|| { assert_eq!( - Delegation::is_delegating(&user_2, &delegation_id_2, max_parent_checks), + Delegation::is_delegating(&user_2, &delegation_id, max_parent_checks), Ok((true, max_parent_checks - 1)) ); }); @@ -1492,34 +1463,34 @@ fn is_delegating_max_parent_revoked() { let user_3_keypair = get_charlie_ed25519(); let user_3 = get_ed25519_account(user_3_keypair.public()); - let (root_id, root_node) = (get_delegation_root_id(true), generate_base_delegation_root(user_1)); - let (delegation_id_1, mut delegation_node_1) = ( + let (hierarchy_root_id, hierarchy_details) = ( + get_delegation_hierarchy_id(true), + generate_base_delegation_hierarchy_details(), + ); + let (parent_id, mut parent_node) = ( get_delegation_id(true), - generate_base_delegation_node(root_id, user_2.clone()), + generate_base_delegation_node(hierarchy_root_id, user_2.clone(), Some(hierarchy_root_id)), + ); + parent_node.details.revoked = true; + let (delegation_id, delegation_node) = ( + get_delegation_id(false), + generate_base_delegation_node(hierarchy_root_id, user_3, Some(parent_id)), ); - delegation_node_1.revoked = true; - let (delegation_id_2, mut delegation_node_2) = - (get_delegation_id(false), generate_base_delegation_node(root_id, user_3)); - delegation_node_2.parent = Some(delegation_id_1); let max_parent_checks = 2u32; - // Root -> Delegation 1 -> Delegation 2 - let mut ext = ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) - .with_delegations(vec![ - (delegation_id_1, delegation_node_1), - (delegation_id_2, delegation_node_2), - ]) - .with_children(vec![ - (root_id, vec![delegation_id_1]), - (delegation_id_1, vec![delegation_id_2]), - ]) + // Root -> Parent -> Delegation + let ext = ctype_mock::ExtBuilder::default() + .with_ctypes(vec![(hierarchy_details.ctype_hash, user_1.clone())]) .build(None); + let mut ext = ExtBuilder::default() + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, user_1)]) + .with_delegations(vec![(parent_id, parent_node), (delegation_id, delegation_node)]) + .build(Some(ext)); ext.execute_with(|| { assert_eq!( - Delegation::is_delegating(&user_2, &delegation_id_2, max_parent_checks), + Delegation::is_delegating(&user_2, &delegation_id, max_parent_checks), Ok((false, max_parent_checks - 2)) ); }); @@ -1534,35 +1505,34 @@ fn is_delegating_root_owner_not_revoked() { let user_3_keypair = get_charlie_ed25519(); let user_3 = get_ed25519_account(user_3_keypair.public()); - let (root_id, root_node) = ( - get_delegation_root_id(true), - generate_base_delegation_root(user_1.clone()), + let (hierarchy_root_id, hierarchy_details) = ( + get_delegation_hierarchy_id(true), + generate_base_delegation_hierarchy_details(), + ); + let (parent_id, parent_node) = ( + get_delegation_id(true), + generate_base_delegation_node(hierarchy_root_id, user_2, Some(hierarchy_root_id)), + ); + let (delegation_id, delegation_node) = ( + get_delegation_id(false), + generate_base_delegation_node(hierarchy_root_id, user_3, Some(parent_id)), ); - let (delegation_id_1, delegation_node_1) = - (get_delegation_id(true), generate_base_delegation_node(root_id, user_2)); - let (delegation_id_2, mut delegation_node_2) = - (get_delegation_id(false), generate_base_delegation_node(root_id, user_3)); - delegation_node_2.parent = Some(delegation_id_1); let max_parent_checks = 2u32; - // Root -> Delegation 1 -> Delegation 2 - let mut ext = ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) - .with_delegations(vec![ - (delegation_id_1, delegation_node_1), - (delegation_id_2, delegation_node_2), - ]) - .with_children(vec![ - (root_id, vec![delegation_id_1]), - (delegation_id_1, vec![delegation_id_2]), - ]) + // Root -> Parent -> Delegation + let ext = ctype_mock::ExtBuilder::default() + .with_ctypes(vec![(hierarchy_details.ctype_hash, user_1.clone())]) .build(None); + let mut ext = ExtBuilder::default() + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, user_1.clone())]) + .with_delegations(vec![(parent_id, parent_node), (delegation_id, delegation_node)]) + .build(Some(ext)); ext.execute_with(|| { assert_eq!( - Delegation::is_delegating(&user_1, &delegation_id_2, max_parent_checks), - Ok((true, max_parent_checks - 1)) + Delegation::is_delegating(&user_1, &delegation_id, max_parent_checks), + Ok((true, max_parent_checks - 2)) ); }); } @@ -1576,37 +1546,36 @@ fn is_delegating_root_owner_revoked() { let user_3_keypair = get_charlie_ed25519(); let user_3 = get_ed25519_account(user_3_keypair.public()); - let (root_id, mut root_node) = ( - get_delegation_root_id(true), - generate_base_delegation_root(user_1.clone()), + let (hierarchy_root_id, hierarchy_details) = ( + get_delegation_hierarchy_id(true), + generate_base_delegation_hierarchy_details(), + ); + let (parent_id, parent_node) = ( + get_delegation_id(true), + generate_base_delegation_node(hierarchy_root_id, user_2, Some(hierarchy_root_id)), + ); + let (delegation_id, delegation_node) = ( + get_delegation_id(false), + generate_base_delegation_node(hierarchy_root_id, user_3, Some(parent_id)), ); - root_node.revoked = true; - let (delegation_id_1, mut delegation_node_1) = - (get_delegation_id(true), generate_base_delegation_node(root_id, user_2)); - delegation_node_1.revoked = true; - let (delegation_id_2, mut delegation_node_2) = - (get_delegation_id(false), generate_base_delegation_node(root_id, user_3)); - delegation_node_2.parent = Some(delegation_id_1); - let max_parent_checks = u32::MAX; + let max_parent_checks = 2u32; - // Root -> Delegation 1 -> Delegation 2 - let mut ext = ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) - .with_delegations(vec![ - (delegation_id_1, delegation_node_1), - (delegation_id_2, delegation_node_2), - ]) - .with_children(vec![ - (root_id, vec![delegation_id_1]), - (delegation_id_1, vec![delegation_id_2]), - ]) + // Root -> Parent -> Delegation + let ext = ctype_mock::ExtBuilder::default() + .with_ctypes(vec![(hierarchy_details.ctype_hash, user_1.clone())]) .build(None); + let mut ext = ExtBuilder::default() + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, user_1.clone())]) + .with_delegations(vec![(parent_id, parent_node), (delegation_id, delegation_node)]) + .build(Some(ext)); ext.execute_with(|| { + // First revoke the hierarchy, then test is_delegating. + let _ = Delegation::revoke_delegation(get_origin(user_1.clone()), hierarchy_root_id, 0u32, 2); assert_eq!( - Delegation::is_delegating(&user_1, &delegation_id_2, max_parent_checks), - Ok((false, 1u32)) + Delegation::is_delegating(&user_1, &delegation_id, max_parent_checks), + Ok((false, 0u32)) ); }); } @@ -1616,9 +1585,9 @@ fn is_delegating_delegation_not_found() { let user_1_keypair = get_alice_ed25519(); let user_1 = get_ed25519_account(user_1_keypair.public()); - let (root_id, root_node) = ( - get_delegation_root_id(true), - generate_base_delegation_root(user_1.clone()), + let (hierarchy_root_id, hierarchy_details) = ( + get_delegation_hierarchy_id(true), + generate_base_delegation_hierarchy_details(), ); let delegation_id = get_delegation_id(true); @@ -1626,7 +1595,7 @@ fn is_delegating_delegation_not_found() { // Root -> Delegation 1 let mut ext = ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, user_1.clone())]) .build(None); ext.execute_with(|| { @@ -1646,37 +1615,34 @@ fn is_delegating_root_after_max_limit() { let user_3_keypair = get_charlie_ed25519(); let user_3 = get_ed25519_account(user_3_keypair.public()); - let (root_id, mut root_node) = ( - get_delegation_root_id(true), - generate_base_delegation_root(user_1.clone()), + let (hierarchy_root_id, hierarchy_details) = ( + get_delegation_hierarchy_id(true), + generate_base_delegation_hierarchy_details(), + ); + let (parent_id, parent_node) = ( + get_delegation_id(true), + generate_base_delegation_node(hierarchy_root_id, user_2, Some(hierarchy_root_id)), + ); + let (delegation_id, delegation_node) = ( + get_delegation_id(false), + generate_base_delegation_node(hierarchy_root_id, user_3, Some(parent_id)), ); - root_node.revoked = true; - let (delegation_id_1, mut delegation_node_1) = - (get_delegation_id(true), generate_base_delegation_node(root_id, user_2)); - delegation_node_1.revoked = true; - let (delegation_id_2, mut delegation_node_2) = - (get_delegation_id(false), generate_base_delegation_node(root_id, user_3)); - delegation_node_2.parent = Some(delegation_id_1); // 1 less than needed let max_parent_checks = 1u32; - // Root -> Delegation 1 -> Delegation 2 - let mut ext = ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) - .with_delegations(vec![ - (delegation_id_1, delegation_node_1), - (delegation_id_2, delegation_node_2), - ]) - .with_children(vec![ - (root_id, vec![delegation_id_1]), - (delegation_id_1, vec![delegation_id_2]), - ]) + // Root -> Parent -> Delegation + let ext = ctype_mock::ExtBuilder::default() + .with_ctypes(vec![(hierarchy_details.ctype_hash, user_1.clone())]) .build(None); + let mut ext = ExtBuilder::default() + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, user_1.clone())]) + .with_delegations(vec![(parent_id, parent_node), (delegation_id, delegation_node)]) + .build(Some(ext)); ext.execute_with(|| { assert_noop!( - Delegation::is_delegating(&user_1, &delegation_id_2, max_parent_checks), + Delegation::is_delegating(&user_1, &delegation_id, max_parent_checks), delegation::Error::::MaxSearchDepthReached ); }); diff --git a/runtimes/peregrine/src/lib.rs b/runtimes/peregrine/src/lib.rs index 4673a03ee7..14a93e613a 100644 --- a/runtimes/peregrine/src/lib.rs +++ b/runtimes/peregrine/src/lib.rs @@ -121,7 +121,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("mashnet-node"), impl_name: create_runtime_str!("mashnet-node"), authoring_version: 4, - spec_version: 16, + spec_version: 17, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 2, diff --git a/runtimes/peregrine/src/weights/attestation.rs b/runtimes/peregrine/src/weights/attestation.rs index 1d409b375d..ca84370d96 100644 --- a/runtimes/peregrine/src/weights/attestation.rs +++ b/runtimes/peregrine/src/weights/attestation.rs @@ -19,30 +19,22 @@ //! Autogenerated weights for attestation //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 3.0.0 -//! DATE: 2021-06-17, STEPS: `[1, ]`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2021-07-21, STEPS: `[1, ]`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 // Executed Command: -// ./target/release/kilt-parachain +// target/release/kilt-parachain // benchmark -// --chain -// dev -// --heap-pages -// 4096 -// --extrinsic -// * -// --pallet -// attestation -// --steps -// 1 -// --repeat -// 20 -// --execution -// wasm -// --wasm-execution -// Compiled +// --chain=dev +// --execution=wasm +// --wasm-execution=Compiled +// --heap-pages=4096 +// --extrinsic=* +// --pallet=attestation +// --steps=1 +// --repeat=20 // --output -// runtimes/parachain/src/weights/attestation.rs +// runtimes/peregrine/src/weights/attestation.rs // --template // .maintain/runtime-weight-template.hbs @@ -58,16 +50,16 @@ use sp_std::marker::PhantomData; pub struct WeightInfo(PhantomData); impl attestation::WeightInfo for WeightInfo { fn add() -> Weight { - 67_947_000_u64 + (68_138_000_u64) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } fn revoke(d: u32, ) -> Weight { - 44_056_000_u64 - // Standard Error: 30_000 - .saturating_add(8_178_000_u64.saturating_mul(d as Weight)) + (46_806_000_u64) + // Standard Error: 134_000 + .saturating_add((8_122_000_u64).saturating_mul(d as Weight)) .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_mul(d as Weight))) .saturating_add(T::DbWeight::get().writes(1_u64)) } } \ No newline at end of file diff --git a/runtimes/peregrine/src/weights/delegation.rs b/runtimes/peregrine/src/weights/delegation.rs index 358cf251e3..f77437b42c 100644 --- a/runtimes/peregrine/src/weights/delegation.rs +++ b/runtimes/peregrine/src/weights/delegation.rs @@ -19,30 +19,22 @@ //! Autogenerated weights for delegation //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 3.0.0 -//! DATE: 2021-06-17, STEPS: `[1, ]`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2021-07-21, STEPS: `[1, ]`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 // Executed Command: -// ./target/release/kilt-parachain +// target/release/kilt-parachain // benchmark -// --chain -// dev -// --heap-pages -// 4096 -// --extrinsic -// * -// --pallet -// delegation -// --steps -// 1 -// --repeat -// 20 -// --execution -// wasm -// --wasm-execution -// Compiled +// --chain=dev +// --execution=wasm +// --wasm-execution=Compiled +// --heap-pages=4096 +// --extrinsic=* +// --pallet=delegation +// --steps=1 +// --repeat=20 // --output -// runtimes/parachain/src/weights/delegation.rs +// runtimes/peregrine/src/weights/delegation.rs // --template // .maintain/runtime-weight-template.hbs @@ -57,40 +49,34 @@ use sp_std::marker::PhantomData; /// Weights for delegation using the recommended hardware. pub struct WeightInfo(PhantomData); impl delegation::WeightInfo for WeightInfo { - fn create_root() -> Weight { - 45_635_000_u64 + fn create_hierarchy() -> Weight { + (48_641_000_u64) .saturating_add(T::DbWeight::get().reads(2_u64)) - .saturating_add(T::DbWeight::get().writes(1_u64)) - } - fn revoke_root(r: u32, ) -> Weight { - 48_761_000_u64 - // Standard Error: 311_000 - .saturating_add(31_784_000_u64.saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(2_u64)) - .saturating_add(T::DbWeight::get().reads(2_u64.saturating_mul(r as Weight))) - .saturating_add(T::DbWeight::get().writes(1_u64)) - .saturating_add(T::DbWeight::get().writes(1_u64.saturating_mul(r as Weight))) + .saturating_add(T::DbWeight::get().writes(2_u64)) } fn add_delegation() -> Weight { - 142_316_000_u64 - .saturating_add(T::DbWeight::get().reads(4_u64)) + (130_555_000_u64) + .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - fn revoke_delegation_root_child(r: u32, _c: u32, ) -> Weight { - 21_746_000_u64 - // Standard Error: 60_000 - .saturating_add(32_601_000_u64.saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(2_u64.saturating_mul(r as Weight))) - .saturating_add(T::DbWeight::get().writes(1_u64.saturating_mul(r as Weight))) + fn revoke_delegation_root_child(r: u32, c: u32, ) -> Weight { + (24_607_000_u64) + // Standard Error: 425_000 + .saturating_add((30_915_000_u64).saturating_mul(r as Weight)) + // Standard Error: 425_000 + .saturating_add((860_000_u64).saturating_mul(c as Weight)) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r as Weight))) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(r as Weight))) } fn revoke_delegation_leaf(r: u32, c: u32, ) -> Weight { - 52_521_000_u64 - // Standard Error: 45_000 - .saturating_add(93_000_u64.saturating_mul(r as Weight)) - // Standard Error: 45_000 - .saturating_add(8_110_000_u64.saturating_mul(c as Weight)) + (58_402_000_u64) + // Standard Error: 307_000 + .saturating_add((57_000_u64).saturating_mul(r as Weight)) + // Standard Error: 307_000 + .saturating_add((8_464_000_u64).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(2_u64)) - .saturating_add(T::DbWeight::get().reads(1_u64.saturating_mul(c as Weight))) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(c as Weight))) .saturating_add(T::DbWeight::get().writes(1_u64)) } } \ No newline at end of file diff --git a/runtimes/spiritnet/src/lib.rs b/runtimes/spiritnet/src/lib.rs index a36be7b449..871bc46ad4 100644 --- a/runtimes/spiritnet/src/lib.rs +++ b/runtimes/spiritnet/src/lib.rs @@ -102,7 +102,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("kilt-spiritnet"), impl_name: create_runtime_str!("kilt-spiritnet"), authoring_version: 1, - spec_version: 16, + spec_version: 17, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 1, diff --git a/runtimes/standalone/src/lib.rs b/runtimes/standalone/src/lib.rs index ff16c6bd31..9ab472eee6 100644 --- a/runtimes/standalone/src/lib.rs +++ b/runtimes/standalone/src/lib.rs @@ -109,7 +109,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("mashnet-node"), impl_name: create_runtime_str!("mashnet-node"), authoring_version: 4, - spec_version: 16, + spec_version: 17, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 2,