1mod account_hash;
4pub mod action_thresholds;
5mod action_type;
6pub mod associated_keys;
7mod error;
8mod weight;
9
10use serde::Serialize;
11
12use alloc::{collections::BTreeSet, vec::Vec};
13use core::{
14 convert::TryFrom,
15 fmt::{self, Debug, Display, Formatter},
16 iter,
17};
18
19#[cfg(feature = "datasize")]
20use datasize::DataSize;
21
22pub use self::{
23 account_hash::{AccountHash, ACCOUNT_HASH_FORMATTED_STRING_PREFIX, ACCOUNT_HASH_LENGTH},
24 action_thresholds::ActionThresholds,
25 action_type::ActionType,
26 associated_keys::AssociatedKeys,
27 error::{FromStrError, SetThresholdFailure, TryFromIntError, TryFromSliceForAccountHashError},
28 weight::{Weight, WEIGHT_SERIALIZED_LENGTH},
29};
30use crate::{
31 bytesrepr::{self, FromBytes, ToBytes},
32 contracts::NamedKeys,
33 crypto, AccessRights, ContextAccessRights, Key, URef, BLAKE2B_DIGEST_LENGTH,
34};
35
36#[derive(PartialEq, Eq, Clone, Debug, Serialize)]
38#[cfg_attr(feature = "datasize", derive(DataSize))]
39pub struct Account {
40 account_hash: AccountHash,
41 named_keys: NamedKeys,
42 main_purse: URef,
43 associated_keys: AssociatedKeys,
44 action_thresholds: ActionThresholds,
45}
46
47impl Account {
48 pub fn new(
50 account_hash: AccountHash,
51 named_keys: NamedKeys,
52 main_purse: URef,
53 associated_keys: AssociatedKeys,
54 action_thresholds: ActionThresholds,
55 ) -> Self {
56 Account {
57 account_hash,
58 named_keys,
59 main_purse,
60 associated_keys,
61 action_thresholds,
62 }
63 }
64
65 pub fn create(account: AccountHash, named_keys: NamedKeys, main_purse: URef) -> Self {
71 let associated_keys = AssociatedKeys::new(account, Weight::new(1));
72
73 let action_thresholds: ActionThresholds = Default::default();
74 Account::new(
75 account,
76 named_keys,
77 main_purse,
78 associated_keys,
79 action_thresholds,
80 )
81 }
82
83 pub fn extract_access_rights(&self) -> ContextAccessRights {
85 let urefs_iter = self
86 .named_keys
87 .values()
88 .filter_map(|key| key.as_uref().copied())
89 .chain(iter::once(self.main_purse));
90 ContextAccessRights::new(Key::from(self.account_hash), urefs_iter)
91 }
92
93 pub fn named_keys_append(&mut self, keys: &mut NamedKeys) {
95 self.named_keys.append(keys);
96 }
97
98 pub fn named_keys(&self) -> &NamedKeys {
100 &self.named_keys
101 }
102
103 pub fn named_keys_mut(&mut self) -> &mut NamedKeys {
105 &mut self.named_keys
106 }
107
108 pub fn account_hash(&self) -> AccountHash {
110 self.account_hash
111 }
112
113 pub fn main_purse(&self) -> URef {
115 self.main_purse
116 }
117
118 pub fn main_purse_add_only(&self) -> URef {
120 URef::new(self.main_purse.addr(), AccessRights::ADD)
121 }
122
123 pub fn associated_keys(&self) -> &AssociatedKeys {
125 &self.associated_keys
126 }
127
128 pub fn action_thresholds(&self) -> &ActionThresholds {
130 &self.action_thresholds
131 }
132
133 pub fn add_associated_key(
135 &mut self,
136 account_hash: AccountHash,
137 weight: Weight,
138 ) -> Result<(), AddKeyFailure> {
139 self.associated_keys.add_key(account_hash, weight)
140 }
141
142 fn can_remove_key(&self, account_hash: AccountHash) -> bool {
144 let total_weight_without = self
145 .associated_keys
146 .total_keys_weight_excluding(account_hash);
147
148 total_weight_without >= *self.action_thresholds().deployment()
151 && total_weight_without >= *self.action_thresholds().key_management()
152 }
153
154 fn can_update_key(&self, account_hash: AccountHash, weight: Weight) -> bool {
157 let total_weight = self
159 .associated_keys
160 .total_keys_weight_excluding(account_hash);
161
162 let new_weight = total_weight.value().saturating_add(weight.value());
164
165 new_weight >= self.action_thresholds().deployment().value()
168 && new_weight >= self.action_thresholds().key_management().value()
169 }
170
171 pub fn remove_associated_key(
176 &mut self,
177 account_hash: AccountHash,
178 ) -> Result<(), RemoveKeyFailure> {
179 if self.associated_keys.contains_key(&account_hash) {
180 if !self.can_remove_key(account_hash) {
182 return Err(RemoveKeyFailure::ThresholdViolation);
183 }
184 }
185 self.associated_keys.remove_key(&account_hash)
186 }
187
188 pub fn update_associated_key(
192 &mut self,
193 account_hash: AccountHash,
194 weight: Weight,
195 ) -> Result<(), UpdateKeyFailure> {
196 if let Some(current_weight) = self.associated_keys.get(&account_hash) {
197 if weight < *current_weight {
198 if !self.can_update_key(account_hash, weight) {
200 return Err(UpdateKeyFailure::ThresholdViolation);
201 }
202 }
203 }
204 self.associated_keys.update_key(account_hash, weight)
205 }
206
207 pub fn set_action_threshold(
212 &mut self,
213 action_type: ActionType,
214 weight: Weight,
215 ) -> Result<(), SetThresholdFailure> {
216 self.can_set_threshold(weight)?;
219 self.action_thresholds.set_threshold(action_type, weight)
221 }
222
223 pub fn can_set_threshold(&self, new_threshold: Weight) -> Result<(), SetThresholdFailure> {
225 let total_weight = self.associated_keys.total_keys_weight();
226 if new_threshold > total_weight {
227 return Err(SetThresholdFailure::InsufficientTotalWeight);
228 }
229 Ok(())
230 }
231
232 pub fn set_action_threshold_unchecked(
240 &mut self,
241 action_type: ActionType,
242 threshold: Weight,
243 ) -> Result<(), SetThresholdFailure> {
244 self.action_thresholds.set_threshold(action_type, threshold)
245 }
246
247 pub fn can_authorize(&self, authorization_keys: &BTreeSet<AccountHash>) -> bool {
249 !authorization_keys.is_empty()
250 && authorization_keys
251 .iter()
252 .all(|e| self.associated_keys.contains_key(e))
253 }
254
255 pub fn can_deploy_with(&self, authorization_keys: &BTreeSet<AccountHash>) -> bool {
258 let total_weight = self
259 .associated_keys
260 .calculate_keys_weight(authorization_keys);
261
262 total_weight >= *self.action_thresholds().deployment()
263 }
264
265 pub fn can_manage_keys_with(&self, authorization_keys: &BTreeSet<AccountHash>) -> bool {
268 let total_weight = self
269 .associated_keys
270 .calculate_keys_weight(authorization_keys);
271
272 total_weight >= *self.action_thresholds().key_management()
273 }
274}
275
276impl ToBytes for Account {
277 fn to_bytes(&self) -> Result<Vec<u8>, bytesrepr::Error> {
278 let mut result = bytesrepr::allocate_buffer(self)?;
279 self.account_hash().write_bytes(&mut result)?;
280 self.named_keys().write_bytes(&mut result)?;
281 self.main_purse.write_bytes(&mut result)?;
282 self.associated_keys().write_bytes(&mut result)?;
283 self.action_thresholds().write_bytes(&mut result)?;
284 Ok(result)
285 }
286
287 fn serialized_length(&self) -> usize {
288 self.account_hash.serialized_length()
289 + self.named_keys.serialized_length()
290 + self.main_purse.serialized_length()
291 + self.associated_keys.serialized_length()
292 + self.action_thresholds.serialized_length()
293 }
294
295 fn write_bytes(&self, writer: &mut Vec<u8>) -> Result<(), bytesrepr::Error> {
296 self.account_hash().write_bytes(writer)?;
297 self.named_keys().write_bytes(writer)?;
298 self.main_purse().write_bytes(writer)?;
299 self.associated_keys().write_bytes(writer)?;
300 self.action_thresholds().write_bytes(writer)?;
301 Ok(())
302 }
303}
304
305impl FromBytes for Account {
306 fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), bytesrepr::Error> {
307 let (account_hash, rem) = AccountHash::from_bytes(bytes)?;
308 let (named_keys, rem) = NamedKeys::from_bytes(rem)?;
309 let (main_purse, rem) = URef::from_bytes(rem)?;
310 let (associated_keys, rem) = AssociatedKeys::from_bytes(rem)?;
311 let (action_thresholds, rem) = ActionThresholds::from_bytes(rem)?;
312 Ok((
313 Account {
314 account_hash,
315 named_keys,
316 main_purse,
317 associated_keys,
318 action_thresholds,
319 },
320 rem,
321 ))
322 }
323}
324
325#[doc(hidden)]
326#[deprecated(
327 since = "1.4.4",
328 note = "function moved to casper_types::crypto::blake2b"
329)]
330pub fn blake2b<T: AsRef<[u8]>>(data: T) -> [u8; BLAKE2B_DIGEST_LENGTH] {
331 crypto::blake2b(data)
332}
333
334#[derive(PartialEq, Eq, Debug, Copy, Clone)]
336#[repr(i32)]
337#[non_exhaustive]
338pub enum AddKeyFailure {
339 MaxKeysLimit = 1,
341 DuplicateKey = 2,
343 PermissionDenied = 3,
346}
347
348impl Display for AddKeyFailure {
349 fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
350 match self {
351 AddKeyFailure::MaxKeysLimit => formatter.write_str(
352 "Unable to add new associated key because maximum amount of keys is reached",
353 ),
354 AddKeyFailure::DuplicateKey => formatter
355 .write_str("Unable to add new associated key because given key already exists"),
356 AddKeyFailure::PermissionDenied => formatter
357 .write_str("Unable to add new associated key due to insufficient permissions"),
358 }
359 }
360}
361
362#[doc(hidden)]
364impl TryFrom<i32> for AddKeyFailure {
365 type Error = TryFromIntError;
366
367 fn try_from(value: i32) -> Result<Self, Self::Error> {
368 match value {
369 d if d == AddKeyFailure::MaxKeysLimit as i32 => Ok(AddKeyFailure::MaxKeysLimit),
370 d if d == AddKeyFailure::DuplicateKey as i32 => Ok(AddKeyFailure::DuplicateKey),
371 d if d == AddKeyFailure::PermissionDenied as i32 => Ok(AddKeyFailure::PermissionDenied),
372 _ => Err(TryFromIntError(())),
373 }
374 }
375}
376
377#[derive(Debug, Eq, PartialEq, Copy, Clone)]
379#[repr(i32)]
380#[non_exhaustive]
381pub enum RemoveKeyFailure {
382 MissingKey = 1,
384 PermissionDenied = 2,
387 ThresholdViolation = 3,
390}
391
392impl Display for RemoveKeyFailure {
393 fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
394 match self {
395 RemoveKeyFailure::MissingKey => {
396 formatter.write_str("Unable to remove a key that does not exist")
397 }
398 RemoveKeyFailure::PermissionDenied => formatter
399 .write_str("Unable to remove associated key due to insufficient permissions"),
400 RemoveKeyFailure::ThresholdViolation => formatter.write_str(
401 "Unable to remove a key which would violate action threshold constraints",
402 ),
403 }
404 }
405}
406
407#[doc(hidden)]
409impl TryFrom<i32> for RemoveKeyFailure {
410 type Error = TryFromIntError;
411
412 fn try_from(value: i32) -> Result<Self, Self::Error> {
413 match value {
414 d if d == RemoveKeyFailure::MissingKey as i32 => Ok(RemoveKeyFailure::MissingKey),
415 d if d == RemoveKeyFailure::PermissionDenied as i32 => {
416 Ok(RemoveKeyFailure::PermissionDenied)
417 }
418 d if d == RemoveKeyFailure::ThresholdViolation as i32 => {
419 Ok(RemoveKeyFailure::ThresholdViolation)
420 }
421 _ => Err(TryFromIntError(())),
422 }
423 }
424}
425
426#[derive(PartialEq, Eq, Debug, Copy, Clone)]
429#[repr(i32)]
430#[non_exhaustive]
431pub enum UpdateKeyFailure {
432 MissingKey = 1,
434 PermissionDenied = 2,
437 ThresholdViolation = 3,
441}
442
443impl Display for UpdateKeyFailure {
444 fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
445 match self {
446 UpdateKeyFailure::MissingKey => formatter.write_str(
447 "Unable to update the value under an associated key that does not exist",
448 ),
449 UpdateKeyFailure::PermissionDenied => formatter
450 .write_str("Unable to update associated key due to insufficient permissions"),
451 UpdateKeyFailure::ThresholdViolation => formatter.write_str(
452 "Unable to update weight that would fall below any of action thresholds",
453 ),
454 }
455 }
456}
457
458#[doc(hidden)]
460impl TryFrom<i32> for UpdateKeyFailure {
461 type Error = TryFromIntError;
462
463 fn try_from(value: i32) -> Result<Self, Self::Error> {
464 match value {
465 d if d == UpdateKeyFailure::MissingKey as i32 => Ok(UpdateKeyFailure::MissingKey),
466 d if d == UpdateKeyFailure::PermissionDenied as i32 => {
467 Ok(UpdateKeyFailure::PermissionDenied)
468 }
469 d if d == UpdateKeyFailure::ThresholdViolation as i32 => {
470 Ok(UpdateKeyFailure::ThresholdViolation)
471 }
472 _ => Err(TryFromIntError(())),
473 }
474 }
475}
476
477#[doc(hidden)]
478#[cfg(any(feature = "testing", feature = "gens", test))]
479pub mod gens {
480 use proptest::prelude::*;
481
482 use crate::{
483 account::{
484 action_thresholds::gens::action_thresholds_arb,
485 associated_keys::gens::associated_keys_arb, Account, Weight,
486 },
487 gens::{account_hash_arb, named_keys_arb, uref_arb},
488 };
489
490 prop_compose! {
491 pub fn account_arb()(
492 account_hash in account_hash_arb(),
493 urefs in named_keys_arb(3),
494 purse in uref_arb(),
495 thresholds in action_thresholds_arb(),
496 mut associated_keys in associated_keys_arb(),
497 ) -> Account {
498 associated_keys.add_key(account_hash, Weight::new(1)).unwrap();
499 Account::new(
500 account_hash,
501 urefs,
502 purse,
503 associated_keys,
504 thresholds,
505 )
506 }
507 }
508}
509
510#[cfg(test)]
511mod tests {
512 use crate::{
513 account::{
514 Account, AccountHash, ActionThresholds, ActionType, AssociatedKeys, RemoveKeyFailure,
515 SetThresholdFailure, UpdateKeyFailure, Weight,
516 },
517 contracts::NamedKeys,
518 AccessRights, URef,
519 };
520 use std::{collections::BTreeSet, convert::TryFrom, iter::FromIterator, vec::Vec};
521
522 use super::*;
523
524 #[test]
525 fn account_hash_from_slice() {
526 let bytes: Vec<u8> = (0..32).collect();
527 let account_hash = AccountHash::try_from(&bytes[..]).expect("should create account hash");
528 assert_eq!(&bytes, &account_hash.as_bytes());
529 }
530
531 #[test]
532 fn account_hash_from_slice_too_small() {
533 let _account_hash =
534 AccountHash::try_from(&[0u8; 31][..]).expect_err("should not create account hash");
535 }
536
537 #[test]
538 fn account_hash_from_slice_too_big() {
539 let _account_hash =
540 AccountHash::try_from(&[0u8; 33][..]).expect_err("should not create account hash");
541 }
542
543 #[test]
544 fn try_from_i32_for_set_threshold_failure() {
545 let max_valid_value_for_variant = SetThresholdFailure::InsufficientTotalWeight as i32;
546 assert_eq!(
547 Err(TryFromIntError(())),
548 SetThresholdFailure::try_from(max_valid_value_for_variant + 1),
549 "Did you forget to update `SetThresholdFailure::try_from` for a new variant of \
550 `SetThresholdFailure`, or `max_valid_value_for_variant` in this test?"
551 );
552 }
553
554 #[test]
555 fn try_from_i32_for_add_key_failure() {
556 let max_valid_value_for_variant = AddKeyFailure::PermissionDenied as i32;
557 assert_eq!(
558 Err(TryFromIntError(())),
559 AddKeyFailure::try_from(max_valid_value_for_variant + 1),
560 "Did you forget to update `AddKeyFailure::try_from` for a new variant of \
561 `AddKeyFailure`, or `max_valid_value_for_variant` in this test?"
562 );
563 }
564
565 #[test]
566 fn try_from_i32_for_remove_key_failure() {
567 let max_valid_value_for_variant = RemoveKeyFailure::ThresholdViolation as i32;
568 assert_eq!(
569 Err(TryFromIntError(())),
570 RemoveKeyFailure::try_from(max_valid_value_for_variant + 1),
571 "Did you forget to update `RemoveKeyFailure::try_from` for a new variant of \
572 `RemoveKeyFailure`, or `max_valid_value_for_variant` in this test?"
573 );
574 }
575
576 #[test]
577 fn try_from_i32_for_update_key_failure() {
578 let max_valid_value_for_variant = UpdateKeyFailure::ThresholdViolation as i32;
579 assert_eq!(
580 Err(TryFromIntError(())),
581 UpdateKeyFailure::try_from(max_valid_value_for_variant + 1),
582 "Did you forget to update `UpdateKeyFailure::try_from` for a new variant of \
583 `UpdateKeyFailure`, or `max_valid_value_for_variant` in this test?"
584 );
585 }
586
587 #[test]
588 fn account_hash_from_str() {
589 let account_hash = AccountHash([3; 32]);
590 let encoded = account_hash.to_formatted_string();
591 let decoded = AccountHash::from_formatted_str(&encoded).unwrap();
592 assert_eq!(account_hash, decoded);
593
594 let invalid_prefix =
595 "accounthash-0000000000000000000000000000000000000000000000000000000000000000";
596 assert!(AccountHash::from_formatted_str(invalid_prefix).is_err());
597
598 let invalid_prefix =
599 "account-hash0000000000000000000000000000000000000000000000000000000000000000";
600 assert!(AccountHash::from_formatted_str(invalid_prefix).is_err());
601
602 let short_addr =
603 "account-hash-00000000000000000000000000000000000000000000000000000000000000";
604 assert!(AccountHash::from_formatted_str(short_addr).is_err());
605
606 let long_addr =
607 "account-hash-000000000000000000000000000000000000000000000000000000000000000000";
608 assert!(AccountHash::from_formatted_str(long_addr).is_err());
609
610 let invalid_hex =
611 "account-hash-000000000000000000000000000000000000000000000000000000000000000g";
612 assert!(AccountHash::from_formatted_str(invalid_hex).is_err());
613 }
614
615 #[test]
616 fn account_hash_serde_roundtrip() {
617 let account_hash = AccountHash([255; 32]);
618 let serialized = bincode::serialize(&account_hash).unwrap();
619 let decoded = bincode::deserialize(&serialized).unwrap();
620 assert_eq!(account_hash, decoded);
621 }
622
623 #[test]
624 fn account_hash_json_roundtrip() {
625 let account_hash = AccountHash([255; 32]);
626 let json_string = serde_json::to_string_pretty(&account_hash).unwrap();
627 let decoded = serde_json::from_str(&json_string).unwrap();
628 assert_eq!(account_hash, decoded);
629 }
630
631 #[test]
632 fn associated_keys_can_authorize_keys() {
633 let key_1 = AccountHash::new([0; 32]);
634 let key_2 = AccountHash::new([1; 32]);
635 let key_3 = AccountHash::new([2; 32]);
636 let mut keys = AssociatedKeys::default();
637
638 keys.add_key(key_2, Weight::new(2))
639 .expect("should add key_1");
640 keys.add_key(key_1, Weight::new(1))
641 .expect("should add key_1");
642 keys.add_key(key_3, Weight::new(3))
643 .expect("should add key_1");
644
645 let account = Account::new(
646 AccountHash::new([0u8; 32]),
647 NamedKeys::new(),
648 URef::new([0u8; 32], AccessRights::READ_ADD_WRITE),
649 keys,
650 ActionThresholds::new(Weight::new(33), Weight::new(48))
652 .expect("should create thresholds"),
653 );
654
655 assert!(account.can_authorize(&BTreeSet::from_iter(vec![key_3, key_2, key_1])));
656 assert!(account.can_authorize(&BTreeSet::from_iter(vec![key_1, key_3, key_2])));
657
658 assert!(account.can_authorize(&BTreeSet::from_iter(vec![key_1, key_2])));
659 assert!(account.can_authorize(&BTreeSet::from_iter(vec![key_1])));
660
661 assert!(!account.can_authorize(&BTreeSet::from_iter(vec![
662 key_1,
663 key_2,
664 AccountHash::new([42; 32])
665 ])));
666 assert!(!account.can_authorize(&BTreeSet::from_iter(vec![
667 AccountHash::new([42; 32]),
668 key_1,
669 key_2
670 ])));
671 assert!(!account.can_authorize(&BTreeSet::from_iter(vec![
672 AccountHash::new([43; 32]),
673 AccountHash::new([44; 32]),
674 AccountHash::new([42; 32])
675 ])));
676 assert!(!account.can_authorize(&BTreeSet::new()));
677 }
678
679 #[test]
680 fn account_can_deploy_with() {
681 let associated_keys = {
682 let mut res = AssociatedKeys::new(AccountHash::new([1u8; 32]), Weight::new(1));
683 res.add_key(AccountHash::new([2u8; 32]), Weight::new(11))
684 .expect("should add key 1");
685 res.add_key(AccountHash::new([3u8; 32]), Weight::new(11))
686 .expect("should add key 2");
687 res.add_key(AccountHash::new([4u8; 32]), Weight::new(11))
688 .expect("should add key 3");
689 res
690 };
691 let account = Account::new(
692 AccountHash::new([0u8; 32]),
693 NamedKeys::new(),
694 URef::new([0u8; 32], AccessRights::READ_ADD_WRITE),
695 associated_keys,
696 ActionThresholds::new(Weight::new(33), Weight::new(48))
698 .expect("should create thresholds"),
699 );
700
701 assert!(!account.can_deploy_with(&BTreeSet::from_iter(vec![
703 AccountHash::new([3u8; 32]),
704 AccountHash::new([2u8; 32]),
705 ])));
706
707 assert!(account.can_deploy_with(&BTreeSet::from_iter(vec![
709 AccountHash::new([4u8; 32]),
710 AccountHash::new([3u8; 32]),
711 AccountHash::new([2u8; 32]),
712 ])));
713
714 assert!(account.can_deploy_with(&BTreeSet::from_iter(vec![
716 AccountHash::new([2u8; 32]),
717 AccountHash::new([1u8; 32]),
718 AccountHash::new([4u8; 32]),
719 AccountHash::new([3u8; 32]),
720 ])));
721 }
722
723 #[test]
724 fn account_can_manage_keys_with() {
725 let associated_keys = {
726 let mut res = AssociatedKeys::new(AccountHash::new([1u8; 32]), Weight::new(1));
727 res.add_key(AccountHash::new([2u8; 32]), Weight::new(11))
728 .expect("should add key 1");
729 res.add_key(AccountHash::new([3u8; 32]), Weight::new(11))
730 .expect("should add key 2");
731 res.add_key(AccountHash::new([4u8; 32]), Weight::new(11))
732 .expect("should add key 3");
733 res
734 };
735 let account = Account::new(
736 AccountHash::new([0u8; 32]),
737 NamedKeys::new(),
738 URef::new([0u8; 32], AccessRights::READ_ADD_WRITE),
739 associated_keys,
740 ActionThresholds::new(Weight::new(11), Weight::new(33))
742 .expect("should create thresholds"),
743 );
744
745 assert!(!account.can_manage_keys_with(&BTreeSet::from_iter(vec![
747 AccountHash::new([3u8; 32]),
748 AccountHash::new([2u8; 32]),
749 ])));
750
751 assert!(account.can_manage_keys_with(&BTreeSet::from_iter(vec![
753 AccountHash::new([4u8; 32]),
754 AccountHash::new([3u8; 32]),
755 AccountHash::new([2u8; 32]),
756 ])));
757
758 assert!(account.can_manage_keys_with(&BTreeSet::from_iter(vec![
760 AccountHash::new([2u8; 32]),
761 AccountHash::new([1u8; 32]),
762 AccountHash::new([4u8; 32]),
763 AccountHash::new([3u8; 32]),
764 ])));
765 }
766
767 #[test]
768 fn set_action_threshold_higher_than_total_weight() {
769 let identity_key = AccountHash::new([1u8; 32]);
770 let key_1 = AccountHash::new([2u8; 32]);
771 let key_2 = AccountHash::new([3u8; 32]);
772 let key_3 = AccountHash::new([4u8; 32]);
773 let associated_keys = {
774 let mut res = AssociatedKeys::new(identity_key, Weight::new(1));
775 res.add_key(key_1, Weight::new(2))
776 .expect("should add key 1");
777 res.add_key(key_2, Weight::new(3))
778 .expect("should add key 2");
779 res.add_key(key_3, Weight::new(4))
780 .expect("should add key 3");
781 res
782 };
783 let mut account = Account::new(
784 AccountHash::new([0u8; 32]),
785 NamedKeys::new(),
786 URef::new([0u8; 32], AccessRights::READ_ADD_WRITE),
787 associated_keys,
788 ActionThresholds::new(Weight::new(33), Weight::new(48))
790 .expect("should create thresholds"),
791 );
792
793 assert_eq!(
794 account
795 .set_action_threshold(ActionType::Deployment, Weight::new(1 + 2 + 3 + 4 + 1))
796 .unwrap_err(),
797 SetThresholdFailure::InsufficientTotalWeight,
798 );
799 assert_eq!(
800 account
801 .set_action_threshold(ActionType::Deployment, Weight::new(1 + 2 + 3 + 4 + 245))
802 .unwrap_err(),
803 SetThresholdFailure::InsufficientTotalWeight,
804 )
805 }
806
807 #[test]
808 fn remove_key_would_violate_action_thresholds() {
809 let identity_key = AccountHash::new([1u8; 32]);
810 let key_1 = AccountHash::new([2u8; 32]);
811 let key_2 = AccountHash::new([3u8; 32]);
812 let key_3 = AccountHash::new([4u8; 32]);
813 let associated_keys = {
814 let mut res = AssociatedKeys::new(identity_key, Weight::new(1));
815 res.add_key(key_1, Weight::new(2))
816 .expect("should add key 1");
817 res.add_key(key_2, Weight::new(3))
818 .expect("should add key 2");
819 res.add_key(key_3, Weight::new(4))
820 .expect("should add key 3");
821 res
822 };
823 let mut account = Account::new(
824 AccountHash::new([0u8; 32]),
825 NamedKeys::new(),
826 URef::new([0u8; 32], AccessRights::READ_ADD_WRITE),
827 associated_keys,
828 ActionThresholds::new(Weight::new(1 + 2 + 3 + 4), Weight::new(1 + 2 + 3 + 4 + 5))
830 .expect("should create thresholds"),
831 );
832
833 assert_eq!(
834 account.remove_associated_key(key_3).unwrap_err(),
835 RemoveKeyFailure::ThresholdViolation,
836 )
837 }
838
839 #[test]
840 fn updating_key_would_violate_action_thresholds() {
841 let identity_key = AccountHash::new([1u8; 32]);
842 let identity_key_weight = Weight::new(1);
843 let key_1 = AccountHash::new([2u8; 32]);
844 let key_1_weight = Weight::new(2);
845 let key_2 = AccountHash::new([3u8; 32]);
846 let key_2_weight = Weight::new(3);
847 let key_3 = AccountHash::new([4u8; 32]);
848 let key_3_weight = Weight::new(4);
849 let associated_keys = {
850 let mut res = AssociatedKeys::new(identity_key, identity_key_weight);
851 res.add_key(key_1, key_1_weight).expect("should add key 1");
852 res.add_key(key_2, key_2_weight).expect("should add key 2");
853 res.add_key(key_3, key_3_weight).expect("should add key 3");
854 res
856 };
857
858 let deployment_threshold = Weight::new(
859 identity_key_weight.value()
860 + key_1_weight.value()
861 + key_2_weight.value()
862 + key_3_weight.value(),
863 );
864 let key_management_threshold = Weight::new(deployment_threshold.value() + 1);
865 let mut account = Account::new(
866 identity_key,
867 NamedKeys::new(),
868 URef::new([0u8; 32], AccessRights::READ_ADD_WRITE),
869 associated_keys,
870 ActionThresholds::new(deployment_threshold, key_management_threshold)
872 .expect("should create thresholds"),
873 );
874
875 assert_eq!(
877 account
878 .clone()
879 .update_associated_key(key_3, Weight::new(1))
880 .unwrap_err(),
881 UpdateKeyFailure::ThresholdViolation,
882 );
883
884 account
886 .update_associated_key(identity_key, Weight::new(3))
887 .unwrap();
888
889 account
891 .clone()
892 .update_associated_key(key_3, Weight::new(3))
893 .unwrap();
894 assert_eq!(
896 account
897 .update_associated_key(key_3, Weight::new(1))
898 .unwrap_err(),
899 UpdateKeyFailure::ThresholdViolation
900 );
901 }
902
903 #[test]
904 fn overflowing_should_allow_removal() {
905 let identity_key = AccountHash::new([42; 32]);
906 let key_1 = AccountHash::new([2u8; 32]);
907 let key_2 = AccountHash::new([3u8; 32]);
908
909 let associated_keys = {
910 let mut res = AssociatedKeys::new(identity_key, Weight::new(1));
912
913 res.add_key(key_1, Weight::new(2))
915 .expect("should add key 1");
916 res.add_key(key_2, Weight::new(255))
918 .expect("should add key 2");
919
920 res
921 };
922
923 let mut account = Account::new(
924 identity_key,
925 NamedKeys::new(),
926 URef::new([0u8; 32], AccessRights::READ_ADD_WRITE),
927 associated_keys,
928 ActionThresholds::new(Weight::new(1), Weight::new(254))
929 .expect("should create thresholds"),
930 );
931
932 account.remove_associated_key(key_1).expect("should work")
933 }
934
935 #[test]
936 fn overflowing_should_allow_updating() {
937 let identity_key = AccountHash::new([1; 32]);
938 let identity_key_weight = Weight::new(1);
939 let key_1 = AccountHash::new([2u8; 32]);
940 let key_1_weight = Weight::new(3);
941 let key_2 = AccountHash::new([3u8; 32]);
942 let key_2_weight = Weight::new(255);
943 let deployment_threshold = Weight::new(1);
944 let key_management_threshold = Weight::new(254);
945
946 let associated_keys = {
947 let mut res = AssociatedKeys::new(identity_key, identity_key_weight);
949
950 res.add_key(key_1, key_1_weight).expect("should add key 1");
952 res.add_key(key_2, key_2_weight).expect("should add key 2");
954
955 res
956 };
957
958 let mut account = Account::new(
959 identity_key,
960 NamedKeys::new(),
961 URef::new([0u8; 32], AccessRights::READ_ADD_WRITE),
962 associated_keys,
963 ActionThresholds::new(deployment_threshold, key_management_threshold)
964 .expect("should create thresholds"),
965 );
966
967 account
969 .update_associated_key(key_1, Weight::new(1))
970 .expect("should work");
971 }
972
973 #[test]
974 fn should_extract_access_rights() {
975 const MAIN_PURSE: URef = URef::new([2; 32], AccessRights::READ_ADD_WRITE);
976 const OTHER_UREF: URef = URef::new([3; 32], AccessRights::READ);
977
978 let account_hash = AccountHash::new([1u8; 32]);
979 let mut named_keys = NamedKeys::new();
980 named_keys.insert("a".to_string(), Key::URef(OTHER_UREF));
981 let associated_keys = AssociatedKeys::new(account_hash, Weight::new(1));
982 let account = Account::new(
983 account_hash,
984 named_keys,
985 MAIN_PURSE,
986 associated_keys,
987 ActionThresholds::new(Weight::new(1), Weight::new(1))
988 .expect("should create thresholds"),
989 );
990
991 let actual_access_rights = account.extract_access_rights();
992
993 let expected_access_rights =
994 ContextAccessRights::new(Key::from(account_hash), vec![MAIN_PURSE, OTHER_UREF]);
995 assert_eq!(actual_access_rights, expected_access_rights)
996 }
997}
998
999#[cfg(test)]
1000mod proptests {
1001 use proptest::prelude::*;
1002
1003 use crate::bytesrepr;
1004
1005 use super::*;
1006
1007 proptest! {
1008 #[test]
1009 fn test_value_account(acct in gens::account_arb()) {
1010 bytesrepr::test_serialization_roundtrip(&acct);
1011 }
1012 }
1013}