Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/bk test delegation #17

Merged
merged 4 commits into from
Mar 22, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion runtime/src/attestation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,10 @@ mod tests {
impl delegation::Trait for Test {
type Signature = Ed25519Signature;
type DelegationNodeId = H256;
}
fn print_hash(hash: Self::Hash) {
::runtime_io::print(&hash.as_bytes()[..]);
}
}

impl Trait for Test {
}
Expand Down
210 changes: 195 additions & 15 deletions runtime/src/delegation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ impl Permissions {
let b2 : u8 = ((x >> 16) & 0xff) as u8;
let b3 : u8 = ((x >> 8) & 0xff) as u8;
let b4 : u8 = (x & 0xff) as u8;
return [b1, b2, b3, b4];
return [b4, b3, b2, b1];
}
}

Expand All @@ -41,6 +41,8 @@ pub trait Trait: ctype::Trait + system::Trait {
type Signature: Verify<Signer = Self::AccountId> + Member + Codec + Default;
type DelegationNodeId: Parameter + Member + Codec + MaybeDisplay + SimpleBitOps
+ Default + Copy + CheckEqual + rstd::hash::Hash + AsRef<[u8]> + AsMut<[u8]>;

fn print_hash(hash: Self::Hash);
}

decl_module! {
Expand All @@ -67,21 +69,12 @@ decl_module! {
return Err("delegation already exist")
}

let mut hashed_values : Vec<Vec<u8>> = Vec::new();
hashed_values.push(delegation_id.as_ref().to_vec());
hashed_values.push(root_id.as_ref().to_vec());
match parent_id {
Some(p) => hashed_values.push(p.as_ref().to_vec()),
None => {}
}
let p = permissions.as_u8();
hashed_values.push((&p).to_vec());
let hashed_value_array = hashed_values.iter().map(Vec::as_slice).collect::<Vec<_>>();
let hash_root = T::Hashing::enumerated_trie_root(&hashed_value_array);
if !verify_encoded_lazy(&delegate_signature, &hash_root, &delegate) {
let hash_root = Self::calculate_hash(delegation_id, root_id, parent_id, permissions);
if !verify_encoded_lazy(&delegate_signature, &&hash_root, &delegate) {
// TODO: abort on signature error
::runtime_io::print("WARNING: SIGNATURE DOES NOT MATCH!");
// return Err("bad delegate signature")
::runtime_io::print("Error: signature does not match, hash:");
T::print_hash(hash_root);
return Err("bad delegate signature")
}

if <Root<T>>::exists(root_id) {
Expand Down Expand Up @@ -149,6 +142,21 @@ decl_module! {
}

impl<T: Trait> Module<T> {

fn calculate_hash(delegation_id: T::DelegationNodeId,
root_id: T::DelegationNodeId, parent_id: Option<T::DelegationNodeId>,
permissions: Permissions) -> T::Hash {
let mut hashed_values : Vec<u8> = delegation_id.as_ref().to_vec();
hashed_values.extend_from_slice(root_id.as_ref());
match parent_id {
Some(p) => hashed_values.extend_from_slice(p.as_ref()),
None => {}
}
hashed_values.extend_from_slice(permissions.as_u8().as_ref());
let hash_root = T::Hashing::hash(&hashed_values);
return hash_root;
}

pub fn is_delegating(account: &T::AccountId, delegation: &T::DelegationNodeId) -> result::Result<bool, &'static str> {
if !<Delegations<T>>::exists(delegation) {
return Err("delegation not found")
Expand Down Expand Up @@ -204,3 +212,175 @@ decl_storage! {
pub Children get(children): map T::DelegationNodeId => Vec<T::DelegationNodeId>;
}
}



#[cfg(test)]
mod tests {
use super::*;
use system;
use runtime_io::with_externalities;
use primitives::{H256, H512, Blake2Hasher};
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}
};

impl_outer_origin! {
pub enum Origin for Test {}
}

#[derive(Clone, Eq, PartialEq)]
pub struct Test;
impl system::Trait for Test {
type Origin = Origin;
type Index = u64;
type BlockNumber = u64;
type Hash = H256;
type Hashing = BlakeTwo256;
type Digest = Digest;
type AccountId = H256;
type Header = Header;
type Event = ();
type Log = DigestItem;
type Lookup = IdentityLookup<H256>;
}

impl ctype::Trait for Test {
}

impl Trait for Test {
type Signature = Ed25519Signature;
type DelegationNodeId = H256;

fn print_hash(hash: Self::Hash) {
::runtime_io::print(&hash.as_bytes()[..]);
}
}

type Ctype = ctype::Module<Test>;
type Delegation = Module<Test>;

fn hash_to_u8<T : Encode> (hash : T) -> Vec<u8>{
return hash.encode();
}

fn new_test_ext() -> runtime_io::TestExternalities<Blake2Hasher> {
system::GenesisConfig::<Test>::default().build_storage().unwrap().0.into()
}

#[test]
fn check_add_and_revoke_delegations() {
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 pair_charlie = ed25519::Pair::from_seed(b"Charlie ");
let account_hash_charlie = H256::from(pair_charlie.public().0);

let ctype_hash = H256::from_low_u64_be(1);
let id_level_0 = H256::from_low_u64_be(1);
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);

assert_ok!(Ctype::add(Origin::signed(account_hash_alice.clone()), ctype_hash.clone()));

assert_ok!(Delegation::create_root(Origin::signed(account_hash_alice.clone()), id_level_0.clone(), ctype_hash.clone()));
assert_err!(Delegation::create_root(Origin::signed(account_hash_alice.clone()), id_level_0.clone(), ctype_hash.clone()),
"root already exist");
assert_err!(Delegation::create_root(Origin::signed(account_hash_alice.clone()), id_level_1.clone(), H256::from_low_u64_be(2)),
"CTYPE does not exist");

assert_ok!(Delegation::add_delegation(Origin::signed(account_hash_alice.clone()), id_level_1.clone(), id_level_0.clone(),
None, account_hash_bob.clone(), Permissions::DELEGATE,
Ed25519Signature::from(pair_bob.sign(&hash_to_u8(
Delegation::calculate_hash(id_level_1.clone(), id_level_0.clone(), None, Permissions::DELEGATE))))));
assert_err!(Delegation::add_delegation(Origin::signed(account_hash_alice.clone()), id_level_1.clone(), id_level_0.clone(),
None, account_hash_bob.clone(), Permissions::DELEGATE,
Ed25519Signature::from(pair_bob.sign(&hash_to_u8(
Delegation::calculate_hash(id_level_1.clone(), id_level_0.clone(), None, Permissions::DELEGATE))))),
"delegation already exist");
assert_err!(Delegation::add_delegation(Origin::signed(account_hash_bob.clone()), id_level_2_1.clone(), id_level_0.clone(),
Some(id_level_1.clone()), account_hash_charlie.clone(), Permissions::ATTEST, Ed25519Signature::from(H512::from_low_u64_be(0))),
"bad delegate signature");
assert_err!(Delegation::add_delegation(Origin::signed(account_hash_charlie.clone()), id_level_2_1.clone(), id_level_0.clone(),
None, account_hash_bob.clone(), Permissions::DELEGATE,
Ed25519Signature::from(pair_bob.sign(&hash_to_u8(
Delegation::calculate_hash(id_level_2_1.clone(), id_level_0.clone(), None, Permissions::DELEGATE))))),
"not owner of root");
assert_err!(Delegation::add_delegation(Origin::signed(account_hash_alice.clone()), id_level_2_1.clone(), id_level_1.clone(),
None, account_hash_bob.clone(), Permissions::DELEGATE,
Ed25519Signature::from(pair_bob.sign(&hash_to_u8(
Delegation::calculate_hash(id_level_2_1.clone(), id_level_1.clone(), None, Permissions::DELEGATE))))),
"root not found");


assert_ok!(Delegation::add_delegation(Origin::signed(account_hash_bob.clone()), id_level_2_1.clone(), id_level_0.clone(),
Some(id_level_1.clone()), account_hash_charlie.clone(), Permissions::ATTEST,
Ed25519Signature::from(pair_charlie.sign(&hash_to_u8(
Delegation::calculate_hash(id_level_2_1.clone(), id_level_0.clone(), Some(id_level_1.clone()), Permissions::ATTEST))))));
assert_err!(Delegation::add_delegation(Origin::signed(account_hash_alice.clone()), id_level_2_2.clone(), id_level_0.clone(),
Some(id_level_1.clone()), account_hash_charlie.clone(), Permissions::ATTEST,
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))))),
"not owner of parent");
assert_err!(Delegation::add_delegation(Origin::signed(account_hash_charlie.clone()), id_level_2_2.clone(), id_level_0.clone(),
Some(id_level_2_1.clone()), account_hash_alice.clone(), Permissions::ATTEST,
Ed25519Signature::from(pair_alice.sign(&hash_to_u8(
Delegation::calculate_hash(id_level_2_2.clone(), id_level_0.clone(), Some(id_level_2_1.clone()), Permissions::ATTEST))))),
"not authorized to delegate");
assert_err!(Delegation::add_delegation(Origin::signed(account_hash_bob.clone()), id_level_2_2.clone(), id_level_0.clone(),
Some(id_level_0.clone()), account_hash_charlie.clone(), Permissions::ATTEST,
Ed25519Signature::from(pair_charlie.sign(&hash_to_u8(
Delegation::calculate_hash(id_level_2_2.clone(), id_level_0.clone(), Some(id_level_0.clone()), Permissions::ATTEST))))),
"parent not found");

assert_ok!(Delegation::add_delegation(Origin::signed(account_hash_bob.clone()), id_level_2_2.clone(), id_level_0.clone(),
Some(id_level_1.clone()), account_hash_charlie.clone(), Permissions::ATTEST | Permissions::DELEGATE,
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))))));

let root = Delegation::root(id_level_0.clone());
assert_eq!(root.0, ctype_hash.clone());
assert_eq!(root.1, account_hash_alice.clone());
assert_eq!(root.2, false);

let delegation_1 = Delegation::delegation(id_level_1.clone());
assert_eq!(delegation_1.0, id_level_0.clone());
assert_eq!(delegation_1.1, None);
assert_eq!(delegation_1.2, account_hash_bob.clone());
assert_eq!(delegation_1.3, Permissions::DELEGATE);
assert_eq!(delegation_1.4, false);

let delegation_2 = Delegation::delegation(id_level_2_2.clone());
assert_eq!(delegation_2.0, id_level_0.clone());
assert_eq!(delegation_2.1, Some(id_level_1.clone()));
assert_eq!(delegation_2.2, account_hash_charlie.clone());
assert_eq!(delegation_2.3, Permissions::ATTEST | Permissions::DELEGATE);
assert_eq!(delegation_2.4, false);

let children = Delegation::children(id_level_1.clone());
assert_eq!(children.len(), 2);
assert_eq!(children[0], id_level_2_1.clone());
assert_eq!(children[1], id_level_2_2.clone());

// check is_delgating
assert_eq!(Delegation::is_delegating(&account_hash_alice, &id_level_1), Ok(true));
assert_eq!(Delegation::is_delegating(&account_hash_alice, &id_level_2_1), Ok(true));
assert_eq!(Delegation::is_delegating(&account_hash_bob, &id_level_2_1), Ok(true));
assert_eq!(Delegation::is_delegating(&account_hash_charlie, &id_level_2_1), Ok(true));
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
});
}
}
22 changes: 16 additions & 6 deletions runtime/src/did.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,22 +16,22 @@ decl_module! {

pub fn add(origin, sign_key: T::PublicSigningKey, box_key: T::PublicBoxKey, doc_ref: Option<Vec<u8>>) -> Result {
let sender = ensure_signed(origin)?;
<DID<T>>::insert(sender.clone(), (sign_key, box_key, doc_ref));
<DIDs<T>>::insert(sender.clone(), (sign_key, box_key, doc_ref));
Ok(())
}

pub fn remove(origin) -> Result {
let sender = ensure_signed(origin)?;
<DID<T>>::remove(sender.clone());
<DIDs<T>>::remove(sender.clone());
Ok(())
}
}
}

decl_storage! {
trait Store for Module<T: Trait> as DID {
// DID: account-id -> (did-reference?)
DID get(dids): map T::AccountId => (T::PublicSigningKey, T::PublicBoxKey, Option<Vec<u8>>);
// DID: account-id -> (public-signing-key, public-encryption-key, did-reference?)
DIDs get(dids): map T::AccountId => (T::PublicSigningKey, T::PublicBoxKey, Option<Vec<u8>>);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is the DID reference actually type Vec and not type Hash?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's an actual URL, so it's a string put into a u8 vector.

}
}

Expand Down Expand Up @@ -84,10 +84,20 @@ mod tests {
fn check_add_did() {
with_externalities(&mut new_test_ext(), || {
let pair = ed25519::Pair::from_seed(b"Alice ");
let hash = H256::from_low_u64_be(1);
let signing_key = H256::from_low_u64_be(1);
let box_key = H256::from_low_u64_be(2);
let account_hash = H256::from(pair.public().0);
assert_ok!(DID::add(Origin::signed(account_hash.clone()),
hash.clone(), hash.clone(), Some(b"http://kilt.org/submit".to_vec())));
signing_key.clone(), box_key.clone(), Some(b"http://kilt.org/submit".to_vec())));

assert_eq!(<DIDs<Test>>::exists(account_hash), true);
let did = DID::dids(account_hash.clone());
assert_eq!(did.0, signing_key.clone());
assert_eq!(did.1, box_key.clone());
assert_eq!(did.2, Some(b"http://kilt.org/submit".to_vec()));

assert_ok!(DID::remove(Origin::signed(account_hash.clone())));
assert_eq!(<DIDs<Test>>::exists(account_hash), false);
});
}
}
5 changes: 5 additions & 0 deletions runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,11 @@ impl ctype::Trait for Runtime {
impl delegation::Trait for Runtime {
type Signature = Ed25519Signature;
type DelegationNodeId = Hash;

fn print_hash(hash: Hash) {
::runtime_io::print(&hash.as_bytes()[..]);
}

}

impl did::Trait for Runtime {
Expand Down