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
// KILT Blockchain – https://botlabs.org
// Copyright (C) 2019-2024 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 <https://www.gnu.org/licenses/>.

// If you feel like getting in touch with us, you can do so at info@botlabs.org

use bitflags::bitflags;
use frame_support::{storage::bounded_btree_set::BoundedBTreeSet, traits::Get};
use kilt_support::Deposit;
use parity_scale_codec::{Decode, Encode, MaxEncodedLen};
use scale_info::TypeInfo;

bitflags! {
	/// Bitflags for permissions.
	///
	/// Permission bits can be combined to express multiple permissions.
	#[derive(Encode, Decode, TypeInfo, MaxEncodedLen)]
	pub struct Permissions: u32 {
		/// Permission to write attestations on chain.
		const ATTEST = 0b0000_0001;
		/// Permission to write delegations on chain.
		const DELEGATE = 0b0000_0010;
	}
}

impl Permissions {
	/// Encode permission bitflags into u8 array.
	pub 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;
		[b4, b3, b2, b1]
	}
}

impl Default for Permissions {
	fn default() -> Self {
		Permissions::ATTEST
	}
}

/// 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, Eq, PartialEq, MaxEncodedLen, TypeInfo)]
pub struct DelegationNode<DelegationNodeId, MaxChildren: Get<u32>, DelegationDetails, AccountId, Balance> {
	/// The ID of the delegation hierarchy the node is part of.
	pub hierarchy_root_id: DelegationNodeId,
	/// The ID of the parent. For all but root nodes this is not None.
	pub parent: Option<DelegationNodeId>,
	/// The set of IDs of all the children nodes.
	pub children: BoundedBTreeSet<DelegationNodeId, MaxChildren>,
	/// The additional information attached to the delegation node.
	pub details: DelegationDetails,
	/// The deposit that was taken to incentivise fair use of the on chain
	/// storage.
	pub deposit: Deposit<AccountId, Balance>,
}

impl<DelegationNodeId: Ord, MaxChildren: Get<u32>, DelegationDetails, AccountId, Balance>
	DelegationNode<DelegationNodeId, MaxChildren, DelegationDetails, AccountId, Balance>
{
	/// Creates a new delegation root node with the given ID and delegation
	/// details.
	pub fn new_root_node(
		id: DelegationNodeId,
		details: DelegationDetails,
		deposit_owner: AccountId,
		deposit_amount: Balance,
	) -> Self {
		Self {
			hierarchy_root_id: id,
			parent: None,
			children: BoundedBTreeSet::<DelegationNodeId, MaxChildren>::new(),
			details,
			deposit: Deposit::<AccountId, Balance> {
				owner: deposit_owner,
				amount: deposit_amount,
			},
		}
	}

	/// Creates a new delegation node under the given hierarchy ID, with the
	/// given parent and delegation details.
	pub fn new_node(
		hierarchy_root_id: DelegationNodeId,
		parent: DelegationNodeId,
		details: DelegationDetails,
		deposit_owner: AccountId,
		deposit_amount: Balance,
	) -> Self {
		Self {
			hierarchy_root_id,
			parent: Some(parent),
			children: BoundedBTreeSet::<DelegationNodeId, MaxChildren>::new(),
			details,
			deposit: Deposit::<AccountId, Balance> {
				owner: deposit_owner,
				amount: deposit_amount,
			},
		}
	}

	/// Adds a node by its ID to the current node's children.
	pub fn try_add_child(&mut self, child_id: DelegationNodeId) -> Result<(), DelegationNodeId> {
		self.children.try_insert(child_id)?;
		Ok(())
	}
}

/// Delegation information attached to delegation nodes.
#[derive(Clone, Debug, Encode, Decode, Eq, PartialEq, TypeInfo, MaxEncodedLen)]
pub struct DelegationDetails<DelegatorId> {
	/// The owner of the delegation (and its node).
	pub owner: DelegatorId,
	/// 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<DelegatorId> DelegationDetails<DelegatorId> {
	/// Creates new delegation details including the given owner.
	///
	/// The default revocation status is false and all permissions are granted
	/// by default.
	pub fn default_with_owner(owner: DelegatorId) -> Self {
		Self {
			owner,
			permissions: Permissions::all(),
			revoked: false,
		}
	}
}

/// The details associated with a delegation hierarchy.
#[derive(Clone, Debug, Encode, Decode, Eq, PartialEq, Ord, PartialOrd, TypeInfo, MaxEncodedLen)]
pub struct DelegationHierarchyDetails<CtypeHash> {
	/// The authorised CTYPE hash that attesters can attest using this
	/// delegation hierarchy.
	pub ctype_hash: CtypeHash,
}