-
Notifications
You must be signed in to change notification settings - Fork 40
/
delegation.rs
206 lines (185 loc) · 7.85 KB
/
delegation.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
use rstd::result;
use rstd::prelude::*;
use runtime_primitives::traits::{Hash, CheckEqual, SimpleBitOps, Member, Verify, MaybeDisplay};
use support::{dispatch::Result, StorageMap, Parameter, decl_module, decl_storage};
use parity_codec_derive::{Encode, Decode};
use core::default::Default;
use runtime_primitives::codec::Codec;
use {system::{self, ensure_signed}, super::ctype};
use runtime_primitives::verify_encoded_lazy;
bitflags! {
#[derive(Encode, Decode)]
pub struct Permissions: u32 {
const ATTEST = 0b00000001;
const DELEGATE = 0b00000010;
}
}
impl Permissions {
fn as_u8(&self) -> [u8;4] {
let x: u32 = (*self).bits;
let b1 : u8 = ((x >> 24) & 0xff) as u8;
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];
}
}
impl Default for Permissions {
fn default() -> Self {
return Permissions::ATTEST;
}
}
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]>;
}
decl_module! {
pub struct Module<T: Trait> for enum Call where origin: T::Origin {
pub fn create_root(origin, root_id: T::DelegationNodeId, ctype_hash: T::Hash) -> Result {
let sender = ensure_signed(origin)?;
if <Root<T>>::exists(root_id) {
return Err("root already exist")
}
if !<ctype::CTYPEs<T>>::exists(ctype_hash) {
return Err("CTYPE does not exist")
}
::runtime_io::print("insert Delegation Root");
<Root<T>>::insert(root_id.clone(), (ctype_hash.clone(), sender.clone(), false));
return Ok(());
}
pub fn add_delegation(origin, delegation_id: T::DelegationNodeId,
root_id: T::DelegationNodeId, parent_id: Option<T::DelegationNodeId>,
delegate: T::AccountId, permissions: Permissions, delegate_signature: T::Signature) -> Result {
let sender = ensure_signed(origin)?;
if <Delegations<T>>::exists(delegation_id) {
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) {
// TODO: abort on signature error
::runtime_io::print("WARNING: SIGNATURE DOES NOT MATCH!");
// return Err("bad delegate signature")
}
if <Root<T>>::exists(root_id) {
let root = <Root<T>>::get(root_id.clone());
match parent_id {
Some(p) => {
if <Delegations<T>>::exists(p) {
let parent = <Delegations<T>>::get(p.clone());
if !parent.2.eq(&sender) {
return Err("not owner of parent")
} else if (parent.3 & Permissions::DELEGATE) != Permissions::DELEGATE {
return Err("not authorized to delegate")
} else {
// TODO: check for cycles?
::runtime_io::print("insert Delegation with parent");
<Delegations<T>>::insert(delegation_id.clone(), (root_id.clone(), Some(p.clone()), delegate, permissions, false));
Self::add_child(delegation_id.clone(), p.clone());
}
} else {
return Err("parent not found")
}
},
None => {
if !root.1.eq(&sender) {
return Err("not owner of root")
}
::runtime_io::print("insert Delegation without parent");
<Delegations<T>>::insert(delegation_id.clone(), (root_id.clone(), None, delegate, permissions, false));
Self::add_child(delegation_id.clone(), root_id.clone());
}
}
} else {
return Err("root not found")
}
return Ok(());
}
pub fn revoke_root(origin, root_id: T::DelegationNodeId) -> Result {
let sender = ensure_signed(origin)?;
if !<Root<T>>::exists(root_id) {
return Err("root not found")
}
let mut r = <Root<T>>::get(root_id.clone());
if !r.1.eq(&sender) {
return Err("not permitted to revoke")
}
if !r.2 {
r.2 = false;
<Root<T>>::insert(root_id.clone(), r);
Self::revoke_children(&root_id);
}
return Ok(());
}
pub fn revoke_delegation(origin, delegation_id: T::DelegationNodeId) -> Result {
let sender = ensure_signed(origin)?;
if !Self::is_delegating(&sender, &delegation_id)? {
return Err("not permitted to revoke")
}
Self::revoke(&delegation_id);
return Ok(());
}
}
}
impl<T: Trait> Module<T> {
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")
}
let d = <Delegations<T>>::get(delegation);
if d.2.eq(account) {
Ok(true)
} else {
match d.1 {
None => {
let r = <Root<T>>::get(d.0.clone());
Ok(r.1.eq(account))
},
Some(p) => {
return Self::is_delegating(account, &p)
}
}
}
}
fn revoke(delegation: &T::DelegationNodeId) {
let mut d = <Delegations<T>>::get(delegation.clone());
if !d.4 {
d.4 = false;
<Delegations<T>>::insert(delegation.clone(), d);
Self::revoke_children(delegation);
}
}
fn revoke_children(delegation: &T::DelegationNodeId) {
if <Children<T>>::exists(delegation) {
let children = <Children<T>>::get(delegation);
for child in children {
Self::revoke(&child);
}
}
}
fn add_child(child: T::DelegationNodeId, parent: T::DelegationNodeId) {
let mut children = <Children<T>>::get(parent.clone());
children.push(child);
<Children<T>>::insert(parent, children);
}
}
decl_storage! {
trait Store for Module<T: Trait> as Delegation {
// Root: root-id => (ctype-hash, account, revoked)
pub Root get(root): map T::DelegationNodeId => (T::Hash,T::AccountId,bool);
// Delegations: delegation-id => (root-id, parent-id?, account, permissions, revoked)
pub Delegations get(delegation): map T::DelegationNodeId => (T::DelegationNodeId,Option<T::DelegationNodeId>,T::AccountId,Permissions,bool);
// Children: root-or-delegation-id => [delegation-id]
pub Children get(children): map T::DelegationNodeId => Vec<T::DelegationNodeId>;
}
}