1mod account_hash;
4pub mod action_thresholds;
5pub mod action_type;
6pub mod associated_keys;
7mod error;
8mod weight;
9
10use serde::{Deserialize, Serialize};
11
12use alloc::{collections::BTreeSet, vec::Vec};
13
14#[cfg(feature = "datasize")]
15use datasize::DataSize;
16#[cfg(feature = "json-schema")]
17use once_cell::sync::Lazy;
18#[cfg(feature = "json-schema")]
19use schemars::JsonSchema;
20
21pub use self::{
22 account_hash::{AccountHash, ACCOUNT_HASH_FORMATTED_STRING_PREFIX, ACCOUNT_HASH_LENGTH},
23 action_thresholds::ActionThresholds,
24 action_type::ActionType,
25 associated_keys::{AddKeyFailure, AssociatedKeys, RemoveKeyFailure, UpdateKeyFailure},
26 error::{FromStrError, SetThresholdFailure, TryFromIntError},
27 weight::Weight,
28};
29
30use crate::{
31 bytesrepr::{self, FromBytes, ToBytes},
32 contracts::NamedKeys,
33 AccessRights, Key, URef,
34};
35#[cfg(feature = "json-schema")]
36use crate::{PublicKey, SecretKey};
37
38#[cfg(feature = "json-schema")]
39static ACCOUNT: Lazy<Account> = Lazy::new(|| {
40 let secret_key = SecretKey::ed25519_from_bytes([0; 32]).unwrap();
41 let account_hash = PublicKey::from(&secret_key).to_account_hash();
42 let main_purse = URef::from_formatted_str(
43 "uref-09480c3248ef76b603d386f3f4f8a5f87f597d4eaffd475433f861af187ab5db-007",
44 )
45 .unwrap();
46 let mut named_keys = NamedKeys::new();
47 named_keys.insert("main_purse".to_string(), Key::URef(main_purse));
48 let weight = Weight::new(1);
49 let associated_keys = AssociatedKeys::new(account_hash, weight);
50 let action_thresholds = ActionThresholds::new(weight, weight).unwrap();
51 Account {
52 account_hash,
53 named_keys,
54 main_purse,
55 associated_keys,
56 action_thresholds,
57 }
58});
59
60#[derive(PartialEq, Eq, Clone, Serialize, Deserialize, Debug)]
62#[cfg_attr(feature = "datasize", derive(DataSize))]
63#[cfg_attr(feature = "json-schema", derive(JsonSchema))]
64#[serde(deny_unknown_fields)]
65pub struct Account {
66 account_hash: AccountHash,
67 named_keys: NamedKeys,
68 main_purse: URef,
69 associated_keys: AssociatedKeys,
70 action_thresholds: ActionThresholds,
71}
72
73impl Account {
74 pub fn new(
76 account_hash: AccountHash,
77 named_keys: NamedKeys,
78 main_purse: URef,
79 associated_keys: AssociatedKeys,
80 action_thresholds: ActionThresholds,
81 ) -> Self {
82 Account {
83 account_hash,
84 named_keys,
85 main_purse,
86 associated_keys,
87 action_thresholds,
88 }
89 }
90
91 pub fn create(account: AccountHash, named_keys: NamedKeys, main_purse: URef) -> Self {
97 let associated_keys = AssociatedKeys::new(account, Weight::new(1));
98
99 let action_thresholds: ActionThresholds = Default::default();
100 Account::new(
101 account,
102 named_keys,
103 main_purse,
104 associated_keys,
105 action_thresholds,
106 )
107 }
108
109 pub fn named_keys_append(&mut self, keys: NamedKeys) {
111 self.named_keys.append(keys);
112 }
113
114 pub fn named_keys(&self) -> &NamedKeys {
116 &self.named_keys
117 }
118
119 pub fn named_keys_mut(&mut self) -> &mut NamedKeys {
121 &mut self.named_keys
122 }
123
124 pub fn remove_named_key(&mut self, name: &str) -> Option<Key> {
126 self.named_keys.remove(name)
127 }
128
129 pub fn account_hash(&self) -> AccountHash {
131 self.account_hash
132 }
133
134 pub fn main_purse(&self) -> URef {
136 self.main_purse
137 }
138
139 pub fn main_purse_add_only(&self) -> URef {
141 URef::new(self.main_purse.addr(), AccessRights::ADD)
142 }
143
144 pub fn associated_keys(&self) -> &AssociatedKeys {
146 &self.associated_keys
147 }
148
149 pub fn action_thresholds(&self) -> &ActionThresholds {
151 &self.action_thresholds
152 }
153
154 pub fn add_associated_key(
156 &mut self,
157 account_hash: AccountHash,
158 weight: Weight,
159 ) -> Result<(), AddKeyFailure> {
160 self.associated_keys.add_key(account_hash, weight)
161 }
162
163 fn can_remove_key(&self, account_hash: AccountHash) -> bool {
165 let total_weight_without = self
166 .associated_keys
167 .total_keys_weight_excluding(account_hash);
168
169 total_weight_without >= *self.action_thresholds().deployment()
172 && total_weight_without >= *self.action_thresholds().key_management()
173 }
174
175 fn can_update_key(&self, account_hash: AccountHash, weight: Weight) -> bool {
178 let total_weight = self
180 .associated_keys
181 .total_keys_weight_excluding(account_hash);
182
183 let new_weight = total_weight.value().saturating_add(weight.value());
185
186 new_weight >= self.action_thresholds().deployment().value()
189 && new_weight >= self.action_thresholds().key_management().value()
190 }
191
192 pub fn remove_associated_key(
197 &mut self,
198 account_hash: AccountHash,
199 ) -> Result<(), RemoveKeyFailure> {
200 if self.associated_keys.contains_key(&account_hash) {
201 if !self.can_remove_key(account_hash) {
203 return Err(RemoveKeyFailure::ThresholdViolation);
204 }
205 }
206 self.associated_keys.remove_key(&account_hash)
207 }
208
209 pub fn update_associated_key(
213 &mut self,
214 account_hash: AccountHash,
215 weight: Weight,
216 ) -> Result<(), UpdateKeyFailure> {
217 if let Some(current_weight) = self.associated_keys.get(&account_hash) {
218 if weight < *current_weight {
219 if !self.can_update_key(account_hash, weight) {
221 return Err(UpdateKeyFailure::ThresholdViolation);
222 }
223 }
224 }
225 self.associated_keys.update_key(account_hash, weight)
226 }
227
228 pub fn set_action_threshold_unchecked(
236 &mut self,
237 action_type: ActionType,
238 threshold: Weight,
239 ) -> Result<(), SetThresholdFailure> {
240 self.action_thresholds.set_threshold(action_type, threshold)
241 }
242
243 pub fn set_action_threshold(
248 &mut self,
249 action_type: ActionType,
250 weight: Weight,
251 ) -> Result<(), SetThresholdFailure> {
252 self.can_set_threshold(weight)?;
255 self.action_thresholds.set_threshold(action_type, weight)
257 }
258
259 pub fn can_set_threshold(&self, new_threshold: Weight) -> Result<(), SetThresholdFailure> {
261 let total_weight = self.associated_keys.total_keys_weight();
262 if new_threshold > total_weight {
263 return Err(SetThresholdFailure::InsufficientTotalWeight);
264 }
265 Ok(())
266 }
267
268 pub fn can_authorize(&self, authorization_keys: &BTreeSet<AccountHash>) -> bool {
270 !authorization_keys.is_empty()
271 && authorization_keys
272 .iter()
273 .all(|e| self.associated_keys.contains_key(e))
274 }
275
276 pub fn can_deploy_with(&self, authorization_keys: &BTreeSet<AccountHash>) -> bool {
279 let total_weight = self
280 .associated_keys
281 .calculate_keys_weight(authorization_keys);
282
283 total_weight >= *self.action_thresholds().deployment()
284 }
285
286 pub fn can_manage_keys_with(&self, authorization_keys: &BTreeSet<AccountHash>) -> bool {
289 let total_weight = self
290 .associated_keys
291 .calculate_keys_weight(authorization_keys);
292
293 total_weight >= *self.action_thresholds().key_management()
294 }
295
296 #[doc(hidden)]
298 #[cfg(feature = "json-schema")]
299 pub fn example() -> &'static Self {
300 &ACCOUNT
301 }
302}
303
304impl ToBytes for Account {
305 fn to_bytes(&self) -> Result<Vec<u8>, bytesrepr::Error> {
306 let mut result = bytesrepr::allocate_buffer(self)?;
307 self.account_hash().write_bytes(&mut result)?;
308 self.named_keys().write_bytes(&mut result)?;
309 self.main_purse.write_bytes(&mut result)?;
310 self.associated_keys().write_bytes(&mut result)?;
311 self.action_thresholds().write_bytes(&mut result)?;
312 Ok(result)
313 }
314
315 fn serialized_length(&self) -> usize {
316 self.account_hash.serialized_length()
317 + self.named_keys.serialized_length()
318 + self.main_purse.serialized_length()
319 + self.associated_keys.serialized_length()
320 + self.action_thresholds.serialized_length()
321 }
322
323 fn write_bytes(&self, writer: &mut Vec<u8>) -> Result<(), bytesrepr::Error> {
324 self.account_hash().write_bytes(writer)?;
325 self.named_keys().write_bytes(writer)?;
326 self.main_purse().write_bytes(writer)?;
327 self.associated_keys().write_bytes(writer)?;
328 self.action_thresholds().write_bytes(writer)?;
329 Ok(())
330 }
331}
332
333impl FromBytes for Account {
334 fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), bytesrepr::Error> {
335 let (account_hash, rem) = AccountHash::from_bytes(bytes)?;
336 let (named_keys, rem) = NamedKeys::from_bytes(rem)?;
337 let (main_purse, rem) = URef::from_bytes(rem)?;
338 let (associated_keys, rem) = AssociatedKeys::from_bytes(rem)?;
339 let (action_thresholds, rem) = ActionThresholds::from_bytes(rem)?;
340 Ok((
341 Account {
342 account_hash,
343 named_keys,
344 main_purse,
345 associated_keys,
346 action_thresholds,
347 },
348 rem,
349 ))
350 }
351}
352
353#[doc(hidden)]
354#[cfg(any(feature = "testing", feature = "gens", test))]
355pub mod gens {
356 use proptest::prelude::*;
357
358 use crate::{
359 account::{associated_keys::gens::account_associated_keys_arb, Account, Weight},
360 gens::{account_hash_arb, named_keys_arb, uref_arb},
361 };
362
363 use super::action_thresholds::gens::account_action_thresholds_arb;
364
365 prop_compose! {
366 pub fn account_arb()(
367 account_hash in account_hash_arb(),
368 urefs in named_keys_arb(3),
369 purse in uref_arb(),
370 thresholds in account_action_thresholds_arb(),
371 mut associated_keys in account_associated_keys_arb(),
372 ) -> Account {
373 associated_keys.add_key(account_hash, Weight::new(1)).unwrap();
374 Account::new(
375 account_hash,
376 urefs,
377 purse,
378 associated_keys,
379 thresholds,
380 )
381 }
382 }
383}
384
385#[cfg(test)]
386mod tests {
387 use crate::{
388 account::{
389 Account, AccountHash, ActionThresholds, ActionType, AssociatedKeys, RemoveKeyFailure,
390 TryFromIntError, UpdateKeyFailure, Weight,
391 },
392 contracts::NamedKeys,
393 AccessRights, URef,
394 };
395 use std::{collections::BTreeSet, convert::TryFrom, iter::FromIterator, vec::Vec};
396
397 use super::*;
398
399 #[test]
400 fn account_hash_from_slice() {
401 let bytes: Vec<u8> = (0..32).collect();
402 let account_hash = AccountHash::try_from(&bytes[..]).expect(
403 "should create account
404hash",
405 );
406 assert_eq!(&bytes, &account_hash.as_bytes());
407 }
408
409 #[test]
410 fn account_hash_from_slice_too_small() {
411 let _account_hash =
412 AccountHash::try_from(&[0u8; 31][..]).expect_err("should not create account hash");
413 }
414
415 #[test]
416 fn account_hash_from_slice_too_big() {
417 let _account_hash =
418 AccountHash::try_from(&[0u8; 33][..]).expect_err("should not create account hash");
419 }
420
421 #[test]
422 fn try_from_i32_for_set_threshold_failure() {
423 let max_valid_value_for_variant = SetThresholdFailure::InsufficientTotalWeight as i32;
424 assert_eq!(
425 Err(TryFromIntError(())),
426 SetThresholdFailure::try_from(max_valid_value_for_variant + 1),
427 "Did you forget to update `SetThresholdFailure::try_from` for a new variant of \
428 `SetThresholdFailure`, or `max_valid_value_for_variant` in this test?"
429 );
430 }
431
432 #[test]
433 fn try_from_i32_for_add_key_failure() {
434 let max_valid_value_for_variant = AddKeyFailure::PermissionDenied as i32;
435 assert_eq!(
436 Err(TryFromIntError(())),
437 AddKeyFailure::try_from(max_valid_value_for_variant + 1),
438 "Did you forget to update `AddKeyFailure::try_from` for a new variant of \
439 `AddKeyFailure`, or `max_valid_value_for_variant` in this test?"
440 );
441 }
442
443 #[test]
444 fn try_from_i32_for_remove_key_failure() {
445 let max_valid_value_for_variant = RemoveKeyFailure::ThresholdViolation as i32;
446 assert_eq!(
447 Err(TryFromIntError(())),
448 RemoveKeyFailure::try_from(max_valid_value_for_variant + 1),
449 "Did you forget to update `RemoveKeyFailure::try_from` for a new variant of \
450 `RemoveKeyFailure`, or `max_valid_value_for_variant` in this test?"
451 );
452 }
453
454 #[test]
455 fn try_from_i32_for_update_key_failure() {
456 let max_valid_value_for_variant = UpdateKeyFailure::ThresholdViolation as i32;
457 assert_eq!(
458 Err(TryFromIntError(())),
459 UpdateKeyFailure::try_from(max_valid_value_for_variant + 1),
460 "Did you forget to update `UpdateKeyFailure::try_from` for a new variant of \
461 `UpdateKeyFailure`, or `max_valid_value_for_variant` in this test?"
462 );
463 }
464
465 #[test]
466 fn account_hash_from_str() {
467 let account_hash = AccountHash([3; 32]);
468 let encoded = account_hash.to_formatted_string();
469 let decoded = AccountHash::from_formatted_str(&encoded).unwrap();
470 assert_eq!(account_hash, decoded);
471
472 let invalid_prefix =
473 "accounthash-0000000000000000000000000000000000000000000000000000000000000000";
474 assert!(AccountHash::from_formatted_str(invalid_prefix).is_err());
475
476 let invalid_prefix =
477 "account-hash0000000000000000000000000000000000000000000000000000000000000000";
478 assert!(AccountHash::from_formatted_str(invalid_prefix).is_err());
479
480 let short_addr =
481 "account-hash-00000000000000000000000000000000000000000000000000000000000000";
482 assert!(AccountHash::from_formatted_str(short_addr).is_err());
483
484 let long_addr =
485 "account-hash-000000000000000000000000000000000000000000000000000000000000000000";
486 assert!(AccountHash::from_formatted_str(long_addr).is_err());
487
488 let invalid_hex =
489 "account-hash-000000000000000000000000000000000000000000000000000000000000000g";
490 assert!(AccountHash::from_formatted_str(invalid_hex).is_err());
491 }
492
493 #[test]
494 fn account_hash_serde_roundtrip() {
495 let account_hash = AccountHash([255; 32]);
496 let serialized = bincode::serialize(&account_hash).unwrap();
497 let decoded = bincode::deserialize(&serialized).unwrap();
498 assert_eq!(account_hash, decoded);
499 }
500
501 #[test]
502 fn account_hash_json_roundtrip() {
503 let account_hash = AccountHash([255; 32]);
504 let json_string = serde_json::to_string_pretty(&account_hash).unwrap();
505 let decoded = serde_json::from_str(&json_string).unwrap();
506 assert_eq!(account_hash, decoded);
507 }
508
509 #[test]
510 fn associated_keys_can_authorize_keys() {
511 let key_1 = AccountHash::new([0; 32]);
512 let key_2 = AccountHash::new([1; 32]);
513 let key_3 = AccountHash::new([2; 32]);
514 let mut keys = AssociatedKeys::default();
515
516 keys.add_key(key_2, Weight::new(2))
517 .expect("should add key_1");
518 keys.add_key(key_1, Weight::new(1))
519 .expect("should add key_1");
520 keys.add_key(key_3, Weight::new(3))
521 .expect("should add key_1");
522
523 let account = Account::new(
524 AccountHash::new([0u8; 32]),
525 NamedKeys::new(),
526 URef::new([0u8; 32], AccessRights::READ_ADD_WRITE),
527 keys,
528 ActionThresholds::new(Weight::new(33), Weight::new(48))
530 .expect("should create thresholds"),
531 );
532
533 assert!(account.can_authorize(&BTreeSet::from_iter(vec![key_3, key_2, key_1])));
534 assert!(account.can_authorize(&BTreeSet::from_iter(vec![key_1, key_3, key_2])));
535
536 assert!(account.can_authorize(&BTreeSet::from_iter(vec![key_1, key_2])));
537 assert!(account.can_authorize(&BTreeSet::from_iter(vec![key_1])));
538
539 assert!(!account.can_authorize(&BTreeSet::from_iter(vec![
540 key_1,
541 key_2,
542 AccountHash::new([42; 32])
543 ])));
544 assert!(!account.can_authorize(&BTreeSet::from_iter(vec![
545 AccountHash::new([42; 32]),
546 key_1,
547 key_2
548 ])));
549 assert!(!account.can_authorize(&BTreeSet::from_iter(vec![
550 AccountHash::new([43; 32]),
551 AccountHash::new([44; 32]),
552 AccountHash::new([42; 32])
553 ])));
554 assert!(!account.can_authorize(&BTreeSet::new()));
555 }
556
557 #[test]
558 fn account_can_deploy_with() {
559 let associated_keys = {
560 let mut res = AssociatedKeys::new(AccountHash::new([1u8; 32]), Weight::new(1));
561 res.add_key(AccountHash::new([2u8; 32]), Weight::new(11))
562 .expect("should add key 1");
563 res.add_key(AccountHash::new([3u8; 32]), Weight::new(11))
564 .expect("should add key 2");
565 res.add_key(AccountHash::new([4u8; 32]), Weight::new(11))
566 .expect("should add key 3");
567 res
568 };
569 let account = Account::new(
570 AccountHash::new([0u8; 32]),
571 NamedKeys::new(),
572 URef::new([0u8; 32], AccessRights::READ_ADD_WRITE),
573 associated_keys,
574 ActionThresholds::new(Weight::new(33), Weight::new(48))
576 .expect("should create thresholds"),
577 );
578
579 assert!(!account.can_deploy_with(&BTreeSet::from_iter(vec![
581 AccountHash::new([3u8; 32]),
582 AccountHash::new([2u8; 32]),
583 ])));
584
585 assert!(account.can_deploy_with(&BTreeSet::from_iter(vec![
587 AccountHash::new([4u8; 32]),
588 AccountHash::new([3u8; 32]),
589 AccountHash::new([2u8; 32]),
590 ])));
591
592 assert!(account.can_deploy_with(&BTreeSet::from_iter(vec![
594 AccountHash::new([2u8; 32]),
595 AccountHash::new([1u8; 32]),
596 AccountHash::new([4u8; 32]),
597 AccountHash::new([3u8; 32]),
598 ])));
599 }
600
601 #[test]
602 fn account_can_manage_keys_with() {
603 let associated_keys = {
604 let mut res = AssociatedKeys::new(AccountHash::new([1u8; 32]), Weight::new(1));
605 res.add_key(AccountHash::new([2u8; 32]), Weight::new(11))
606 .expect("should add key 1");
607 res.add_key(AccountHash::new([3u8; 32]), Weight::new(11))
608 .expect("should add key 2");
609 res.add_key(AccountHash::new([4u8; 32]), Weight::new(11))
610 .expect("should add key 3");
611 res
612 };
613 let account = Account::new(
614 AccountHash::new([0u8; 32]),
615 NamedKeys::new(),
616 URef::new([0u8; 32], AccessRights::READ_ADD_WRITE),
617 associated_keys,
618 ActionThresholds::new(Weight::new(11), Weight::new(33))
620 .expect("should create thresholds"),
621 );
622
623 assert!(!account.can_manage_keys_with(&BTreeSet::from_iter(vec![
625 AccountHash::new([3u8; 32]),
626 AccountHash::new([2u8; 32]),
627 ])));
628
629 assert!(account.can_manage_keys_with(&BTreeSet::from_iter(vec![
631 AccountHash::new([4u8; 32]),
632 AccountHash::new([3u8; 32]),
633 AccountHash::new([2u8; 32]),
634 ])));
635
636 assert!(account.can_manage_keys_with(&BTreeSet::from_iter(vec![
638 AccountHash::new([2u8; 32]),
639 AccountHash::new([1u8; 32]),
640 AccountHash::new([4u8; 32]),
641 AccountHash::new([3u8; 32]),
642 ])));
643 }
644
645 #[test]
646 fn set_action_threshold_higher_than_total_weight() {
647 let identity_key = AccountHash::new([1u8; 32]);
648 let key_1 = AccountHash::new([2u8; 32]);
649 let key_2 = AccountHash::new([3u8; 32]);
650 let key_3 = AccountHash::new([4u8; 32]);
651 let associated_keys = {
652 let mut res = AssociatedKeys::new(identity_key, Weight::new(1));
653 res.add_key(key_1, Weight::new(2))
654 .expect("should add key 1");
655 res.add_key(key_2, Weight::new(3))
656 .expect("should add key 2");
657 res.add_key(key_3, Weight::new(4))
658 .expect("should add key 3");
659 res
660 };
661 let mut account = Account::new(
662 AccountHash::new([0u8; 32]),
663 NamedKeys::new(),
664 URef::new([0u8; 32], AccessRights::READ_ADD_WRITE),
665 associated_keys,
666 ActionThresholds::new(Weight::new(33), Weight::new(48))
668 .expect("should create thresholds"),
669 );
670
671 assert_eq!(
672 account
673 .set_action_threshold(ActionType::Deployment, Weight::new(1 + 2 + 3 + 4 + 1))
674 .unwrap_err(),
675 SetThresholdFailure::InsufficientTotalWeight,
676 );
677 assert_eq!(
678 account
679 .set_action_threshold(ActionType::Deployment, Weight::new(1 + 2 + 3 + 4 + 245))
680 .unwrap_err(),
681 SetThresholdFailure::InsufficientTotalWeight,
682 )
683 }
684
685 #[test]
686 fn remove_key_would_violate_action_thresholds() {
687 let identity_key = AccountHash::new([1u8; 32]);
688 let key_1 = AccountHash::new([2u8; 32]);
689 let key_2 = AccountHash::new([3u8; 32]);
690 let key_3 = AccountHash::new([4u8; 32]);
691 let associated_keys = {
692 let mut res = AssociatedKeys::new(identity_key, Weight::new(1));
693 res.add_key(key_1, Weight::new(2))
694 .expect("should add key 1");
695 res.add_key(key_2, Weight::new(3))
696 .expect("should add key 2");
697 res.add_key(key_3, Weight::new(4))
698 .expect("should add key 3");
699 res
700 };
701 let mut account = Account::new(
702 AccountHash::new([0u8; 32]),
703 NamedKeys::new(),
704 URef::new([0u8; 32], AccessRights::READ_ADD_WRITE),
705 associated_keys,
706 ActionThresholds::new(Weight::new(1 + 2 + 3 + 4), Weight::new(1 + 2 + 3 + 4 + 5))
708 .expect("should create thresholds"),
709 );
710
711 assert_eq!(
712 account.remove_associated_key(key_3).unwrap_err(),
713 RemoveKeyFailure::ThresholdViolation,
714 )
715 }
716
717 #[test]
718 fn updating_key_would_violate_action_thresholds() {
719 let identity_key = AccountHash::new([1u8; 32]);
720 let identity_key_weight = Weight::new(1);
721 let key_1 = AccountHash::new([2u8; 32]);
722 let key_1_weight = Weight::new(2);
723 let key_2 = AccountHash::new([3u8; 32]);
724 let key_2_weight = Weight::new(3);
725 let key_3 = AccountHash::new([4u8; 32]);
726 let key_3_weight = Weight::new(4);
727 let associated_keys = {
728 let mut res = AssociatedKeys::new(identity_key, identity_key_weight);
729 res.add_key(key_1, key_1_weight).expect("should add key 1");
730 res.add_key(key_2, key_2_weight).expect("should add key 2");
731 res.add_key(key_3, key_3_weight).expect("should add key 3");
732 res
734 };
735
736 let deployment_threshold = Weight::new(
737 identity_key_weight.value()
738 + key_1_weight.value()
739 + key_2_weight.value()
740 + key_3_weight.value(),
741 );
742 let key_management_threshold = Weight::new(deployment_threshold.value() + 1);
743 let mut account = Account::new(
744 identity_key,
745 NamedKeys::new(),
746 URef::new([0u8; 32], AccessRights::READ_ADD_WRITE),
747 associated_keys,
748 ActionThresholds::new(deployment_threshold, key_management_threshold)
750 .expect("should create thresholds"),
751 );
752
753 assert_eq!(
755 account
756 .clone()
757 .update_associated_key(key_3, Weight::new(1))
758 .unwrap_err(),
759 UpdateKeyFailure::ThresholdViolation,
760 );
761
762 account
764 .update_associated_key(identity_key, Weight::new(3))
765 .unwrap();
766
767 account
769 .clone()
770 .update_associated_key(key_3, Weight::new(3))
771 .unwrap();
772 assert_eq!(
774 account
775 .update_associated_key(key_3, Weight::new(1))
776 .unwrap_err(),
777 UpdateKeyFailure::ThresholdViolation
778 );
779 }
780
781 #[test]
782 fn overflowing_should_allow_removal() {
783 let identity_key = AccountHash::new([42; 32]);
784 let key_1 = AccountHash::new([2u8; 32]);
785 let key_2 = AccountHash::new([3u8; 32]);
786
787 let associated_keys = {
788 let mut res = AssociatedKeys::new(identity_key, Weight::new(1));
790
791 res.add_key(key_1, Weight::new(2))
793 .expect("should add key 1");
794 res.add_key(key_2, Weight::new(255))
796 .expect("should add key 2");
797
798 res
799 };
800
801 let mut account = Account::new(
802 identity_key,
803 NamedKeys::new(),
804 URef::new([0u8; 32], AccessRights::READ_ADD_WRITE),
805 associated_keys,
806 ActionThresholds::new(Weight::new(1), Weight::new(254))
807 .expect("should create thresholds"),
808 );
809
810 account.remove_associated_key(key_1).expect("should work")
811 }
812
813 #[test]
814 fn overflowing_should_allow_updating() {
815 let identity_key = AccountHash::new([1; 32]);
816 let identity_key_weight = Weight::new(1);
817 let key_1 = AccountHash::new([2u8; 32]);
818 let key_1_weight = Weight::new(3);
819 let key_2 = AccountHash::new([3u8; 32]);
820 let key_2_weight = Weight::new(255);
821 let deployment_threshold = Weight::new(1);
822 let key_management_threshold = Weight::new(254);
823
824 let associated_keys = {
825 let mut res = AssociatedKeys::new(identity_key, identity_key_weight);
827
828 res.add_key(key_1, key_1_weight).expect("should add key 1");
830 res.add_key(key_2, key_2_weight).expect("should add key 2");
832
833 res
834 };
835
836 let mut account = Account::new(
837 identity_key,
838 NamedKeys::new(),
839 URef::new([0u8; 32], AccessRights::READ_ADD_WRITE),
840 associated_keys,
841 ActionThresholds::new(deployment_threshold, key_management_threshold)
842 .expect("should create thresholds"),
843 );
844
845 account
847 .update_associated_key(key_1, Weight::new(1))
848 .expect("should work");
849 }
850}
851
852#[cfg(test)]
853mod proptests {
854 use proptest::prelude::*;
855
856 use crate::bytesrepr;
857
858 use super::*;
859
860 proptest! {
861 #[test]
862 fn test_value_account(acct in gens::account_arb()) {
863 bytesrepr::test_serialization_roundtrip(&acct);
864 }
865 }
866}