diff --git a/runtime/src/attestation.rs b/runtime/src/attestation.rs index dc3183d6b..c344c3c2a 100644 --- a/runtime/src/attestation.rs +++ b/runtime/src/attestation.rs @@ -18,6 +18,9 @@ decl_module! { match delegation_id { Some(d) => { + if !>::exists(d.clone()) { + return Err("delegation not found") + } let delegation = >::get(d.clone()); if delegation.4 { return Err("delegation revoked") @@ -121,6 +124,7 @@ mod tests { use runtime_primitives::Ed25519Signature; use primitives::*; use support::{impl_outer_origin, assert_ok, assert_err}; + use parity_codec::Encode; use runtime_primitives::{ BuildStorage, traits::{BlakeTwo256, IdentityLookup}, testing::{Digest, DigestItem, Header} @@ -162,11 +166,17 @@ mod tests { type Attestation = Module; type Ctype = ctype::Module; + type Delegation = delegation::Module; fn new_test_ext() -> runtime_io::TestExternalities { system::GenesisConfig::::default().build_storage().unwrap().0.into() } + fn hash_to_u8 (hash : T) -> Vec{ + return hash.encode(); + } + + #[test] fn check_add_attestation() { with_externalities(&mut new_test_ext(), || { @@ -224,4 +234,57 @@ mod tests { assert_err!(Attestation::revoke(Origin::signed(account_hash.clone()), hash.clone()), "no valid attestation found"); }); } + + + #[test] + fn check_add_attestation_withdelegation() { + with_externalities(&mut new_test_ext(), || { + let pair_alice = ed25519::Pair::from_seed(b"Alice "); + let account_hash_alice = H256::from(pair_alice.public().0); + let pair_bob = ed25519::Pair::from_seed(b"Bob "); + let account_hash_bob = H256::from(pair_bob.public().0); + + let ctype_hash = H256::from_low_u64_be(1); + let other_ctype_hash = H256::from_low_u64_be(2); + let claim_hash = H256::from_low_u64_be(1); + + let delegation_root = H256::from_low_u64_be(0); + let delegation_1 = H256::from_low_u64_be(1); + let delegation_2 = H256::from_low_u64_be(2); + + assert_ok!(Ctype::add(Origin::signed(account_hash_alice.clone()), ctype_hash.clone())); + + assert_err!(Attestation::add(Origin::signed(account_hash_alice.clone()), claim_hash.clone(), ctype_hash.clone(), Some(delegation_1)), + "delegation not found"); + + assert_ok!(Delegation::create_root(Origin::signed(account_hash_alice.clone()), delegation_root.clone(), ctype_hash.clone())); + assert_ok!(Delegation::add_delegation(Origin::signed(account_hash_alice.clone()), delegation_1.clone(), delegation_root.clone(), + None, account_hash_bob.clone(), delegation::Permissions::DELEGATE, + Ed25519Signature::from(pair_bob.sign(&hash_to_u8( + Delegation::calculate_hash(delegation_1.clone(), delegation_root.clone(), None, delegation::Permissions::DELEGATE)))))); + assert_ok!(Delegation::add_delegation(Origin::signed(account_hash_alice.clone()), delegation_2.clone(), delegation_root.clone(), + None, account_hash_bob.clone(), delegation::Permissions::ATTEST, + Ed25519Signature::from(pair_bob.sign(&hash_to_u8( + Delegation::calculate_hash(delegation_2.clone(), delegation_root.clone(), None, delegation::Permissions::ATTEST)))))); + + assert_err!(Attestation::add(Origin::signed(account_hash_bob.clone()), claim_hash.clone(), other_ctype_hash.clone(), Some(delegation_2)), + "CTYPE not found"); + assert_ok!(Ctype::add(Origin::signed(account_hash_alice.clone()), other_ctype_hash.clone())); + assert_err!(Attestation::add(Origin::signed(account_hash_bob.clone()), claim_hash.clone(), other_ctype_hash.clone(), Some(delegation_2)), + "CTYPE of delegation does not match"); + assert_err!(Attestation::add(Origin::signed(account_hash_alice.clone()), claim_hash.clone(), ctype_hash.clone(), Some(delegation_2)), + "not delegated to attester"); + assert_err!(Attestation::add(Origin::signed(account_hash_bob.clone()), claim_hash.clone(), ctype_hash.clone(), Some(delegation_1)), + "delegation not authorized to attest"); + assert_ok!(Attestation::add(Origin::signed(account_hash_bob.clone()), claim_hash.clone(), ctype_hash.clone(), Some(delegation_2))); + + let existing_attestations_for_delegation = Attestation::delegated_attestations(delegation_2.clone()); + assert_eq!(existing_attestations_for_delegation.len(), 1); + assert_eq!(existing_attestations_for_delegation[0], claim_hash.clone()); + + assert_ok!(Delegation::revoke_root(Origin::signed(account_hash_alice.clone()), delegation_root.clone())); + assert_err!(Attestation::add(Origin::signed(account_hash_bob.clone()), claim_hash.clone(), ctype_hash.clone(), Some(delegation_2)), + "delegation revoked"); + }); + } } diff --git a/runtime/src/delegation.rs b/runtime/src/delegation.rs index f240e417f..a573ddcf0 100644 --- a/runtime/src/delegation.rs +++ b/runtime/src/delegation.rs @@ -132,6 +132,9 @@ decl_module! { pub fn revoke_delegation(origin, delegation_id: T::DelegationNodeId) -> Result { let sender = ensure_signed(origin)?; + if !>::exists(delegation_id) { + return Err("delegation not found") + } if !Self::is_delegating(&sender, &delegation_id)? { return Err("not permitted to revoke") } @@ -143,7 +146,7 @@ decl_module! { impl Module { - fn calculate_hash(delegation_id: T::DelegationNodeId, + pub fn calculate_hash(delegation_id: T::DelegationNodeId, root_id: T::DelegationNodeId, parent_id: Option, permissions: Permissions) -> T::Hash { let mut hashed_values : Vec = delegation_id.as_ref().to_vec(); @@ -288,6 +291,7 @@ mod tests { let id_level_1 = H256::from_low_u64_be(2); let id_level_2_1 = H256::from_low_u64_be(21); let id_level_2_2 = H256::from_low_u64_be(22); + let id_level_2_2_1 = H256::from_low_u64_be(221); assert_ok!(Ctype::add(Origin::signed(account_hash_alice.clone()), ctype_hash.clone())); @@ -346,6 +350,12 @@ mod tests { Ed25519Signature::from(pair_charlie.sign(&hash_to_u8( Delegation::calculate_hash(id_level_2_2.clone(), id_level_0.clone(), Some(id_level_1.clone()), Permissions::ATTEST | Permissions::DELEGATE)))))); + + assert_ok!(Delegation::add_delegation(Origin::signed(account_hash_charlie.clone()), id_level_2_2_1.clone(), id_level_0.clone(), + Some(id_level_2_2.clone()), account_hash_alice.clone(), Permissions::ATTEST, + Ed25519Signature::from(pair_alice.sign(&hash_to_u8( + Delegation::calculate_hash(id_level_2_2_1.clone(), id_level_0.clone(), Some(id_level_2_2.clone()), Permissions::ATTEST)))))); + let root = Delegation::root(id_level_0.clone()); assert_eq!(root.0, ctype_hash.clone()); @@ -379,8 +389,24 @@ mod tests { assert_eq!(Delegation::is_delegating(&account_hash_charlie, &id_level_1), Ok(false)); assert_eq!(Delegation::is_delegating(&account_hash_charlie, &id_level_0), Err("delegation not found")); - // TODO: test revocation with state and errors - // TODO: test attestation based on delegation + assert_err!(Delegation::revoke_delegation(Origin::signed(account_hash_charlie.clone()), H256::from_low_u64_be(999)), + "delegation not found"); + assert_err!(Delegation::revoke_delegation(Origin::signed(account_hash_charlie.clone()), id_level_1.clone()), + "not permitted to revoke"); + assert_ok!(Delegation::revoke_delegation(Origin::signed(account_hash_charlie.clone()), id_level_2_2.clone())); + + assert_eq!(Delegation::delegation(id_level_2_2.clone()).4, true); + assert_eq!(Delegation::delegation(id_level_2_2_1.clone()).4, true); + + assert_err!(Delegation::revoke_root(Origin::signed(account_hash_bob.clone()), H256::from_low_u64_be(999)), + "root not found"); + assert_err!(Delegation::revoke_root(Origin::signed(account_hash_bob.clone()), id_level_0.clone()), + "not permitted to revoke"); + assert_ok!(Delegation::revoke_root(Origin::signed(account_hash_alice.clone()), id_level_0.clone())); + + assert_eq!(Delegation::root(id_level_0.clone()).2, true); + assert_eq!(Delegation::delegation(id_level_1.clone()).4, true); + assert_eq!(Delegation::delegation(id_level_2_1.clone()).4, true); }); } } \ No newline at end of file