cap_common/
transaction.rs1use crate::did::EventHash;
2use certified_vars::HashTree::Pruned;
3use certified_vars::{AsHashTree, Hash, HashTree};
4use ic_kit::candid::{CandidType, Deserialize, Nat};
5use ic_kit::Principal;
6use serde::Serialize;
7use sha2::{Digest, Sha256};
8use std::collections::BTreeSet;
9use std::convert::TryInto;
10
11#[derive(CandidType, Serialize, Deserialize, Clone, Debug)]
12pub struct Event {
13 pub time: u64,
15 pub caller: Principal,
17 pub operation: String,
19 pub details: Vec<(String, DetailValue)>,
21}
22
23#[derive(CandidType, Serialize, Deserialize, Clone, Debug)]
24pub struct IndefiniteEvent {
25 pub caller: Principal,
27 pub operation: String,
29 pub details: Vec<(String, DetailValue)>,
31}
32
33#[derive(CandidType, Serialize, Deserialize, Clone, Debug)]
34pub enum DetailValue {
35 True,
36 False,
37 U64(u64),
38 I64(i64),
39 Float(f64),
40 Text(String),
41 Principal(Principal),
42 #[serde(with = "serde_bytes")]
43 Slice(Vec<u8>),
44 Vec(Vec<DetailValue>),
45 TokenIdU64(u64),
46}
47
48impl Event {
49 #[inline]
51 pub fn extract_principal_ids(&self) -> BTreeSet<&Principal> {
52 let mut principals = BTreeSet::new();
53
54 principals.insert(&self.caller);
55
56 fn visit<'a>(principals: &mut BTreeSet<&'a Principal>, value: &'a DetailValue) {
57 match value {
58 DetailValue::Principal(p) => {
59 principals.insert(p);
60 }
61 DetailValue::Vec(items) => {
62 for item in items {
63 visit(principals, item);
64 }
65 }
66 _ => {}
67 }
68 }
69
70 for (_, value) in &self.details {
71 visit(&mut principals, value);
72 }
73
74 principals
75 }
76
77 #[inline]
79 pub fn extract_token_ids(&self) -> BTreeSet<u64> {
80 let mut tokens = BTreeSet::new();
81
82 fn visit(tokens: &mut BTreeSet<u64>, value: &DetailValue) {
83 match value {
84 DetailValue::TokenIdU64(id) => {
85 tokens.insert(*id);
86 }
87 DetailValue::Vec(items) => {
88 for item in items {
89 visit(tokens, item);
90 }
91 }
92 _ => {}
93 }
94 }
95
96 for (_, value) in &self.details {
97 visit(&mut tokens, value);
98 }
99
100 tokens
101 }
102
103 pub fn hash(&self) -> EventHash {
105 let mut h = domain_sep(&self.operation);
106
107 h.update(&self.time.to_be_bytes() as &[u8]);
108 let caller = self.caller.as_slice();
109 h.update(&caller.len().to_be_bytes() as &[u8]);
110 h.update(caller);
111
112 fn hash_value(h: &mut Sha256, value: &DetailValue) {
113 match value {
114 DetailValue::True => {
115 h.update(&[0]);
116 }
117 DetailValue::False => {
118 h.update(&[1]);
119 }
120 DetailValue::U64(val) => {
121 let bytes = val.to_be_bytes();
122 h.update(&[2]);
123 h.update(&bytes.len().to_be_bytes() as &[u8]);
124 h.update(bytes);
125 }
126 DetailValue::I64(val) => {
127 let bytes = val.to_be_bytes();
128 h.update(&[3]);
129 h.update(&bytes.len().to_be_bytes() as &[u8]);
130 h.update(bytes);
131 }
132 DetailValue::Float(val) => {
133 let bytes = val.to_be_bytes();
134 h.update(&[4]);
135 h.update(&bytes.len().to_be_bytes() as &[u8]);
136 h.update(bytes);
137 }
138 DetailValue::Text(val) => {
139 let bytes = val.as_str().as_bytes();
140 h.update(&[5]);
141 h.update(&bytes.len().to_be_bytes() as &[u8]);
142 h.update(bytes);
143 }
144 DetailValue::Principal(val) => {
145 let bytes = val.as_slice();
146 h.update(&[6]);
147 h.update(&bytes.len().to_be_bytes() as &[u8]);
148 h.update(bytes);
149 }
150 DetailValue::Slice(val) => {
151 let bytes = val.as_slice();
152 h.update(&[7]);
153 h.update(&bytes.len().to_be_bytes() as &[u8]);
154 h.update(bytes);
155 }
156 DetailValue::Vec(val) => {
157 h.update(&[8]);
158 h.update(&val.len().to_be_bytes() as &[u8]);
159 for item in val.iter() {
160 hash_value(h, item);
161 }
162 }
163 DetailValue::TokenIdU64(val) => {
164 let bytes = val.to_be_bytes();
165 h.update(&[9]);
166 h.update(&bytes.len().to_be_bytes() as &[u8]);
167 h.update(bytes);
168 }
169 }
170 }
171
172 for (key, value) in &self.details {
173 h.update(&key.len().to_be_bytes() as &[u8]);
174 h.update(key.as_str().as_bytes());
175 hash_value(&mut h, value);
176 }
177
178 h.finalize().into()
179 }
180}
181
182impl Into<IndefiniteEvent> for Event {
183 fn into(self) -> IndefiniteEvent {
184 IndefiniteEvent {
185 caller: self.caller,
186 operation: self.operation,
187 details: self.details,
188 }
189 }
190}
191
192impl IndefiniteEvent {
193 #[inline]
195 pub fn to_event(self, time: u64) -> Event {
196 Event {
197 time,
198 caller: self.caller,
199 operation: self.operation,
200 details: self.details,
201 }
202 }
203}
204
205impl From<u64> for DetailValue {
206 fn from(num: u64) -> Self {
207 Self::U64(num)
208 }
209}
210
211impl TryInto<u64> for DetailValue {
212 type Error = ();
213
214 fn try_into(self) -> Result<u64, Self::Error> {
215 if let Self::U64(num) = self {
216 Ok(num)
217 } else {
218 Err(())
219 }
220 }
221}
222
223impl From<i64> for DetailValue {
224 fn from(num: i64) -> Self {
225 Self::I64(num)
226 }
227}
228
229impl TryInto<i64> for DetailValue {
230 type Error = ();
231
232 fn try_into(self) -> Result<i64, Self::Error> {
233 if let Self::I64(num) = self {
234 Ok(num)
235 } else {
236 Err(())
237 }
238 }
239}
240
241impl From<f64> for DetailValue {
242 fn from(float: f64) -> Self {
243 Self::Float(float)
244 }
245}
246
247impl TryInto<f64> for DetailValue {
248 type Error = ();
249
250 fn try_into(self) -> Result<f64, Self::Error> {
251 if let Self::Float(num) = self {
252 Ok(num)
253 } else {
254 Err(())
255 }
256 }
257}
258
259impl From<String> for DetailValue {
260 fn from(string: String) -> Self {
261 Self::Text(string)
262 }
263}
264
265impl TryInto<String> for DetailValue {
266 type Error = ();
267
268 fn try_into(self) -> Result<String, Self::Error> {
269 if let Self::Text(val) = self {
270 Ok(val)
271 } else {
272 Err(())
273 }
274 }
275}
276
277impl From<Principal> for DetailValue {
278 fn from(principal: Principal) -> Self {
279 Self::Principal(principal)
280 }
281}
282
283impl TryInto<Principal> for DetailValue {
284 type Error = ();
285
286 fn try_into(self) -> Result<Principal, Self::Error> {
287 if let Self::Principal(principal) = self {
288 Ok(principal)
289 } else {
290 Err(())
291 }
292 }
293}
294
295impl From<Nat> for DetailValue {
296 fn from(nat: Nat) -> Self {
297 let mut vec = vec![];
298
299 nat.encode(&mut vec).unwrap();
300
301 DetailValue::Slice(vec)
302 }
303}
304
305impl TryInto<Nat> for DetailValue {
306 type Error = ();
307
308 fn try_into(self) -> Result<Nat, Self::Error> {
309 if let Self::Slice(nat) = self {
310 if let Ok(nat) = Nat::parse(&nat) {
311 Ok(nat)
312 } else {
313 Err(())
314 }
315 } else {
316 Err(())
317 }
318 }
319}
320
321fn domain_sep(s: &str) -> sha2::Sha256 {
322 let buf: [u8; 1] = [s.len() as u8];
323 let mut h = sha2::Sha256::new();
324 h.update(&buf[..]);
325 h.update(s.as_bytes());
326 h
327}
328
329impl AsHashTree for Event {
330 fn root_hash(&self) -> Hash {
331 self.hash()
332 }
333
334 fn as_hash_tree(&self) -> HashTree<'_> {
335 Pruned(self.hash())
336 }
337}
338
339