1#![warn(missing_docs)]
18
19mod account_data;
22mod error;
23mod stores;
24
25use self::{
26 account_data::{AccountData, Unlock},
27 stores::AddressBook,
28};
29
30use std::{
31 collections::HashMap,
32 time::{Duration, Instant},
33};
34
35use cfxkey::{Address, Generator, Message, Password, Public, Random, Secret};
36use cfxstore::{
37 accounts_dir::MemoryDirectory, random_string, CfxMultiStore, CfxStore,
38 OpaqueSecret, SecretStore, SecretVaultRef, SimpleSecretStore,
39 StoreAccountRef,
40};
41use log::warn;
42use parking_lot::RwLock;
43
44pub use cfxkey::Signature;
45pub use cfxstore::{Derivation, Error, IndexDerivation, KeyFile};
46
47pub use self::{account_data::AccountMeta, error::SignError};
48
49type AccountToken = Password;
50
51#[derive(Debug, Default)]
53pub struct AccountProviderSettings {
54 pub unlock_keep_secret: bool,
56 pub blacklisted_accounts: Vec<Address>,
58}
59
60pub struct AccountProvider {
63 unlocked_secrets: RwLock<HashMap<StoreAccountRef, OpaqueSecret>>,
65 unlocked: RwLock<HashMap<StoreAccountRef, AccountData>>,
67 address_book: RwLock<AddressBook>,
69 sstore: Box<dyn SecretStore>,
71 transient_sstore: CfxMultiStore,
73 unlock_keep_secret: bool,
76 blacklisted_accounts: Vec<Address>,
78}
79
80fn transient_sstore() -> CfxMultiStore {
81 CfxMultiStore::open(Box::new(MemoryDirectory::default()))
82 .expect("MemoryDirectory load always succeeds; qed")
83}
84
85impl AccountProvider {
86 pub fn new(
88 sstore: Box<dyn SecretStore>, settings: AccountProviderSettings,
89 ) -> Self {
90 if let Ok(accounts) = sstore.accounts() {
91 for account in accounts
92 .into_iter()
93 .filter(|a| settings.blacklisted_accounts.contains(&a.address))
94 {
95 warn!("Local Account {} has a blacklisted (known to be weak) address and will be ignored",
96 account.address);
97 }
98 }
99
100 let mut address_book = AddressBook::new(&sstore.local_path());
102 for addr in &settings.blacklisted_accounts {
103 address_book.remove(*addr);
104 }
105
106 AccountProvider {
107 unlocked_secrets: RwLock::new(HashMap::new()),
108 unlocked: RwLock::new(HashMap::new()),
109 address_book: RwLock::new(address_book),
110 sstore,
111 transient_sstore: transient_sstore(),
112 unlock_keep_secret: settings.unlock_keep_secret,
113 blacklisted_accounts: settings.blacklisted_accounts,
114 }
115 }
116
117 pub fn transient_provider() -> Self {
119 AccountProvider {
120 unlocked_secrets: RwLock::new(HashMap::new()),
121 unlocked: RwLock::new(HashMap::new()),
122 address_book: RwLock::new(AddressBook::transient()),
123 sstore: Box::new(
124 CfxStore::open(Box::new(MemoryDirectory::default()))
125 .expect("MemoryDirectory load always succeeds; qed"),
126 ),
127 transient_sstore: transient_sstore(),
128 unlock_keep_secret: false,
129 blacklisted_accounts: vec![],
130 }
131 }
132
133 pub fn new_account(&self, password: &Password) -> Result<Address, Error> {
135 self.new_account_and_public(password).map(|d| d.0)
136 }
137
138 pub fn new_account_and_public(
140 &self, password: &Password,
141 ) -> Result<(Address, Public), Error> {
142 let acc = Random
143 .generate()
144 .expect("secp context has generation capabilities; qed");
145 let public = acc.public().clone();
146 let secret = acc.secret().clone();
147 let account = self.sstore.insert_account(
148 SecretVaultRef::Root,
149 secret,
150 password,
151 )?;
152 Ok((account.address, public))
153 }
154
155 pub fn insert_account(
158 &self, secret: Secret, password: &Password,
159 ) -> Result<Address, Error> {
160 let account = self.sstore.insert_account(
161 SecretVaultRef::Root,
162 secret,
163 password,
164 )?;
165 if self.blacklisted_accounts.contains(&account.address) {
166 self.sstore.remove_account(&account, password)?;
167 return Err(Error::InvalidAccount);
168 }
169 Ok(account.address)
170 }
171
172 pub fn derive_account(
176 &self, address: &Address, password: Option<Password>,
177 derivation: Derivation, save: bool,
178 ) -> Result<Address, SignError> {
179 let account = self.sstore.account_ref(&address)?;
180 let password = password
181 .map(Ok)
182 .unwrap_or_else(|| self.password(&account))?;
183 Ok(if save {
184 self.sstore
185 .insert_derived(
186 SecretVaultRef::Root,
187 &account,
188 &password,
189 derivation,
190 )?
191 .address
192 } else {
193 self.sstore
194 .generate_derived(&account, &password, derivation)?
195 })
196 }
197
198 pub fn import_wallet(
200 &self, json: &[u8], password: &Password, gen_id: bool,
201 ) -> Result<Address, Error> {
202 let account = self.sstore.import_wallet(
203 SecretVaultRef::Root,
204 json,
205 password,
206 gen_id,
207 )?;
208 if self.blacklisted_accounts.contains(&account.address) {
209 self.sstore.remove_account(&account, password)?;
210 return Err(Error::InvalidAccount);
211 }
212 Ok(account.address)
213 }
214
215 pub fn has_account(&self, address: Address) -> bool {
217 self.sstore.account_ref(&address).is_ok()
218 && !self.blacklisted_accounts.contains(&address)
219 }
220
221 pub fn accounts(&self) -> Result<Vec<Address>, Error> {
223 let accounts = self.sstore.accounts()?;
224 Ok(accounts
225 .into_iter()
226 .map(|a| a.address)
227 .filter(|address| !self.blacklisted_accounts.contains(address))
228 .collect())
229 }
230
231 pub fn default_account(&self) -> Result<Address, Error> {
233 Ok(self.accounts()?.first().cloned().unwrap_or_default())
234 }
235
236 pub fn addresses_info(&self) -> HashMap<Address, AccountMeta> {
238 self.address_book.read().get()
239 }
240
241 pub fn set_address_name(&self, account: Address, name: String) {
243 self.address_book.write().set_name(account, name)
244 }
245
246 pub fn set_address_meta(&self, account: Address, meta: String) {
248 self.address_book.write().set_meta(account, meta)
249 }
250
251 pub fn remove_address(&self, addr: Address) {
253 self.address_book.write().remove(addr)
254 }
255
256 pub fn accounts_info(
258 &self,
259 ) -> Result<HashMap<Address, AccountMeta>, Error> {
260 let r = self
261 .sstore
262 .accounts()?
263 .into_iter()
264 .filter(|a| !self.blacklisted_accounts.contains(&a.address))
265 .map(|a| {
266 (
267 a.address.clone(),
268 self.account_meta(a.address).ok().unwrap_or_default(),
269 )
270 })
271 .collect();
272 Ok(r)
273 }
274
275 pub fn account_meta(&self, address: Address) -> Result<AccountMeta, Error> {
277 let account = self.sstore.account_ref(&address)?;
278 Ok(AccountMeta {
279 name: self.sstore.name(&account)?,
280 meta: self.sstore.meta(&account)?,
281 uuid: self.sstore.uuid(&account).ok().map(Into::into), })
283 }
284
285 pub fn account_public(
287 &self, address: Address, password: &Password,
288 ) -> Result<Public, Error> {
289 self.sstore
290 .public(&self.sstore.account_ref(&address)?, password)
291 }
292
293 pub fn set_account_name(
295 &self, address: Address, name: String,
296 ) -> Result<(), Error> {
297 self.sstore
298 .set_name(&self.sstore.account_ref(&address)?, name)?;
299 Ok(())
300 }
301
302 pub fn set_account_meta(
304 &self, address: Address, meta: String,
305 ) -> Result<(), Error> {
306 self.sstore
307 .set_meta(&self.sstore.account_ref(&address)?, meta)?;
308 Ok(())
309 }
310
311 pub fn test_password(
314 &self, address: &Address, password: &Password,
315 ) -> Result<bool, Error> {
316 self.sstore
317 .test_password(&self.sstore.account_ref(&address)?, password)
318 .map_err(Into::into)
319 }
320
321 pub fn kill_account(
323 &self, address: &Address, password: &Password,
324 ) -> Result<(), Error> {
325 self.sstore
326 .remove_account(&self.sstore.account_ref(&address)?, &password)?;
327 Ok(())
328 }
329
330 pub fn change_password(
333 &self, address: &Address, password: Password, new_password: Password,
334 ) -> Result<(), Error> {
335 self.sstore.change_password(
336 &self.sstore.account_ref(address)?,
337 &password,
338 &new_password,
339 )
340 }
341
342 pub fn export_account(
344 &self, address: &Address, password: Password,
345 ) -> Result<KeyFile, Error> {
346 self.sstore
347 .export_account(&self.sstore.account_ref(address)?, &password)
348 }
349
350 fn unlock_account(
352 &self, address: Address, password: Password, unlock: Unlock,
353 ) -> Result<(), Error> {
354 let account = self.sstore.account_ref(&address)?;
355
356 let mut unlocked = self.unlocked.write();
359 if let Some(data) = unlocked.get(&account) {
360 if let Unlock::Perm = data.unlock {
361 return Ok(());
362 }
363 }
364
365 if self.unlock_keep_secret && unlock == Unlock::Perm {
366 let secret = self.sstore.raw_secret(&account, &password)?;
368 self.unlocked_secrets
369 .write()
370 .insert(account.clone(), secret);
371 } else {
372 let _ =
375 self.sstore.sign(&account, &password, &Default::default())?;
376 }
377
378 let data = AccountData { unlock, password };
379
380 unlocked.insert(account, data);
381 Ok(())
382 }
383
384 pub fn lock_account(&self, address: Address) -> Result<(), Error> {
386 let account = self.sstore.account_ref(&address)?;
387
388 let mut unlocked = self.unlocked.write();
389 if let Some(data) = unlocked.get(&account) {
390 if let Unlock::Perm = data.unlock {
391 self.unlocked_secrets.write().remove(&account);
392 }
393 unlocked.remove(&account);
394 }
395 Ok(())
396 }
397
398 fn password(
399 &self, account: &StoreAccountRef,
400 ) -> Result<Password, SignError> {
401 let mut unlocked = self.unlocked.write();
402 Self::password_with_unlocked(&mut unlocked, account)
403 }
404
405 fn password_with_unlocked(
406 unlocked: &mut HashMap<StoreAccountRef, AccountData>,
407 account: &StoreAccountRef,
408 ) -> Result<Password, SignError> {
409 let data = unlocked.get(account).ok_or(SignError::NotUnlocked)?.clone();
410 if let Unlock::OneTime = data.unlock {
411 unlocked
412 .remove(account)
413 .expect("data exists: so key must exist: qed");
414 }
415 if let Unlock::Timed(ref end) = data.unlock {
416 if Instant::now() > *end {
417 unlocked
418 .remove(account)
419 .expect("data exists: so key must exist: qed");
420 return Err(SignError::NotUnlocked);
421 }
422 }
423 Ok(data.password)
424 }
425
426 pub fn unlock_account_permanently(
428 &self, account: Address, password: Password,
429 ) -> Result<(), Error> {
430 self.unlock_account(account, password, Unlock::Perm)
431 }
432
433 pub fn unlock_account_temporarily(
435 &self, account: Address, password: Password,
436 ) -> Result<(), Error> {
437 self.unlock_account(account, password, Unlock::OneTime)
438 }
439
440 pub fn unlock_account_timed(
442 &self, account: Address, password: Password, duration: Duration,
443 ) -> Result<(), Error> {
444 self.unlock_account(
445 account,
446 password,
447 Unlock::Timed(Instant::now() + duration),
448 )
449 }
450
451 pub fn is_unlocked(&self, address: &Address) -> bool {
453 let unlocked = self.unlocked.read();
454 let unlocked_secrets = self.unlocked_secrets.read();
455 self.sstore
456 .account_ref(address)
457 .map(|r| {
458 unlocked.get(&r).is_some() || unlocked_secrets.get(&r).is_some()
459 })
460 .unwrap_or(false)
461 }
462
463 pub fn is_unlocked_permanently(&self, address: &Address) -> bool {
465 let unlocked = self.unlocked.read();
466 self.sstore
467 .account_ref(address)
468 .map(|r| {
469 unlocked
470 .get(&r)
471 .map_or(false, |account| account.unlock == Unlock::Perm)
472 })
473 .unwrap_or(false)
474 }
475
476 pub fn sign(
479 &self, address: Address, password: Option<Password>, message: Message,
480 ) -> Result<Signature, SignError> {
481 let account = self.sstore.account_ref(&address)?;
482 let mut unlocked = self.unlocked.write();
484 match self.unlocked_secrets.read().get(&account) {
485 Some(secret) => {
486 Ok(self.sstore.sign_with_secret(&secret, &message)?)
487 }
488 None => {
489 let password = password.map(Ok).unwrap_or_else(|| {
490 Self::password_with_unlocked(&mut unlocked, &account)
491 })?;
492 Ok(self.sstore.sign(&account, &password, &message)?)
493 }
494 }
495 }
496
497 pub fn sign_derived(
500 &self, address: &Address, password: Option<Password>,
501 derivation: Derivation, message: Message,
502 ) -> Result<Signature, SignError> {
503 let account = self.sstore.account_ref(address)?;
504 let password = password
505 .map(Ok)
506 .unwrap_or_else(|| self.password(&account))?;
507 Ok(self
508 .sstore
509 .sign_derived(&account, &password, derivation, &message)?)
510 }
511
512 pub fn sign_with_token(
515 &self, address: Address, token: AccountToken, message: Message,
516 ) -> Result<(Signature, AccountToken), SignError> {
517 let account = self.sstore.account_ref(&address)?;
518 let is_std_password = self.sstore.test_password(&account, &token)?;
519
520 let new_token = Password::from(random_string(16));
521 let signature = if is_std_password {
522 self.sstore.copy_account(
524 &self.transient_sstore,
525 SecretVaultRef::Root,
526 &account,
527 &token,
528 &new_token,
529 )?;
530 self.sstore.sign(&account, &token, &message)?
532 } else {
533 self.transient_sstore
535 .change_password(&account, &token, &new_token)?;
536 self.transient_sstore.sign(&account, &new_token, &message)?
538 };
539
540 Ok((signature, new_token))
541 }
542
543 pub fn decrypt_with_token(
546 &self, address: Address, token: AccountToken, shared_mac: &[u8],
547 message: &[u8],
548 ) -> Result<(Vec<u8>, AccountToken), SignError> {
549 let account = self.sstore.account_ref(&address)?;
550 let is_std_password = self.sstore.test_password(&account, &token)?;
551
552 let new_token = Password::from(random_string(16));
553 let message = if is_std_password {
554 self.sstore.copy_account(
556 &self.transient_sstore,
557 SecretVaultRef::Root,
558 &account,
559 &token,
560 &new_token,
561 )?;
562 self.sstore.decrypt(&account, &token, shared_mac, message)?
564 } else {
565 self.transient_sstore
567 .change_password(&account, &token, &new_token)?;
568 self.transient_sstore
570 .decrypt(&account, &token, shared_mac, message)?
571 };
572
573 Ok((message, new_token))
574 }
575
576 pub fn decrypt(
579 &self, address: Address, password: Option<Password>, shared_mac: &[u8],
580 message: &[u8],
581 ) -> Result<Vec<u8>, SignError> {
582 let account = self.sstore.account_ref(&address)?;
583 let password = password
584 .map(Ok)
585 .unwrap_or_else(|| self.password(&account))?;
586 Ok(self
587 .sstore
588 .decrypt(&account, &password, shared_mac, message)?)
589 }
590
591 pub fn agree(
593 &self, address: Address, password: Option<Password>,
594 other_public: &Public,
595 ) -> Result<Secret, SignError> {
596 let account = self.sstore.account_ref(&address)?;
597 let password = password
598 .map(Ok)
599 .unwrap_or_else(|| self.password(&account))?;
600 Ok(self.sstore.agree(&account, &password, other_public)?)
601 }
602
603 pub fn list_geth_accounts(&self, testnet: bool) -> Vec<Address> {
605 self.sstore
606 .list_geth_accounts(testnet)
607 .into_iter()
608 .map(|a| a)
609 .collect()
610 }
611
612 pub fn import_geth_accounts(
614 &self, desired: Vec<Address>, testnet: bool,
615 ) -> Result<Vec<Address>, Error> {
616 self.sstore
617 .import_geth_accounts(SecretVaultRef::Root, desired, testnet)
618 .map(|a| a.into_iter().map(|a| a.address).collect())
619 .map_err(Into::into)
620 }
621
622 pub fn create_vault(
624 &self, name: &str, password: &Password,
625 ) -> Result<(), Error> {
626 self.sstore.create_vault(name, password).map_err(Into::into)
627 }
628
629 pub fn open_vault(
631 &self, name: &str, password: &Password,
632 ) -> Result<(), Error> {
633 self.sstore.open_vault(name, password).map_err(Into::into)
634 }
635
636 pub fn close_vault(&self, name: &str) -> Result<(), Error> {
638 self.sstore.close_vault(name).map_err(Into::into)
639 }
640
641 pub fn list_vaults(&self) -> Result<Vec<String>, Error> {
643 self.sstore.list_vaults().map_err(Into::into)
644 }
645
646 pub fn list_opened_vaults(&self) -> Result<Vec<String>, Error> {
648 self.sstore.list_opened_vaults().map_err(Into::into)
649 }
650
651 pub fn change_vault_password(
653 &self, name: &str, new_password: &Password,
654 ) -> Result<(), Error> {
655 self.sstore
656 .change_vault_password(name, new_password)
657 .map_err(Into::into)
658 }
659
660 pub fn change_vault(
662 &self, address: Address, new_vault: &str,
663 ) -> Result<(), Error> {
664 let new_vault_ref = if new_vault.is_empty() {
665 SecretVaultRef::Root
666 } else {
667 SecretVaultRef::Vault(new_vault.to_owned())
668 };
669 let old_account_ref = self.sstore.account_ref(&address)?;
670 self.sstore
671 .change_account_vault(new_vault_ref, old_account_ref)
672 .map_err(Into::into)
673 .map(|_| ())
674 }
675
676 pub fn get_vault_meta(&self, name: &str) -> Result<String, Error> {
678 self.sstore.get_vault_meta(name).map_err(Into::into)
679 }
680
681 pub fn set_vault_meta(&self, name: &str, meta: &str) -> Result<(), Error> {
683 self.sstore.set_vault_meta(name, meta).map_err(Into::into)
684 }
685}
686
687#[cfg(test)]
688mod tests {
689 use super::{AccountProvider, Unlock};
690 use cfx_types::H256;
691 use cfxkey::{Address, Generator, Random};
692 use cfxstore::{Derivation, StoreAccountRef};
693 use std::time::{Duration, Instant};
694
695 #[test]
696 fn unlock_account_temp() {
697 let kp = Random.generate().unwrap();
698 let ap = AccountProvider::transient_provider();
699 assert!(ap
700 .insert_account(kp.secret().clone(), &"test".into())
701 .is_ok());
702 assert!(ap
703 .unlock_account_temporarily(kp.address(), "test1".into())
704 .is_err());
705 assert!(ap
706 .unlock_account_temporarily(kp.address(), "test".into())
707 .is_ok());
708 assert!(ap.sign(kp.address(), None, Default::default()).is_ok());
709 assert!(ap.sign(kp.address(), None, Default::default()).is_err());
710 }
711
712 #[test]
713 fn derived_account_nosave() {
714 let kp = Random.generate().unwrap();
715 let ap = AccountProvider::transient_provider();
716 assert!(ap
717 .insert_account(kp.secret().clone(), &"base".into())
718 .is_ok());
719 assert!(ap
720 .unlock_account_permanently(kp.address(), "base".into())
721 .is_ok());
722
723 let derived_addr = ap
724 .derive_account(
725 &kp.address(),
726 None,
727 Derivation::SoftHash(H256::from_low_u64_be(999)),
728 false,
729 )
730 .expect("Derivation should not fail");
731
732 assert!(ap.unlock_account_permanently(derived_addr, "base".into()).is_err(),
733 "There should be an error because account is not supposed to be saved");
734 }
735
736 #[test]
737 fn derived_account_save() {
738 let kp = Random.generate().unwrap();
739 let ap = AccountProvider::transient_provider();
740 assert!(ap
741 .insert_account(kp.secret().clone(), &"base".into())
742 .is_ok());
743 assert!(ap
744 .unlock_account_permanently(kp.address(), "base".into())
745 .is_ok());
746
747 let derived_addr = ap
748 .derive_account(
749 &kp.address(),
750 None,
751 Derivation::SoftHash(H256::from_low_u64_be(999)),
752 true,
753 )
754 .expect("Derivation should not fail");
755
756 assert!(
757 ap.unlock_account_permanently(derived_addr, "base_wrong".into())
758 .is_err(),
759 "There should be an error because password is invalid"
760 );
761
762 assert!(
763 ap.unlock_account_permanently(derived_addr, "base".into())
764 .is_ok(),
765 "Should be ok because account is saved and password is valid"
766 );
767 }
768
769 #[test]
770 fn derived_account_sign() {
771 let kp = Random.generate().unwrap();
772 let ap = AccountProvider::transient_provider();
773 assert!(ap
774 .insert_account(kp.secret().clone(), &"base".into())
775 .is_ok());
776 assert!(ap
777 .unlock_account_permanently(kp.address(), "base".into())
778 .is_ok());
779
780 let derived_addr = ap
781 .derive_account(
782 &kp.address(),
783 None,
784 Derivation::SoftHash(H256::from_low_u64_be(1999)),
785 true,
786 )
787 .expect("Derivation should not fail");
788 ap.unlock_account_permanently(derived_addr, "base".into())
789 .expect(
790 "Should be ok because account is saved and password is valid",
791 );
792
793 let msg = Default::default();
794 let signed_msg1 = ap
795 .sign(derived_addr, None, msg)
796 .expect("Signing with existing unlocked account should not fail");
797 let signed_msg2 = ap.sign_derived(
798 &kp.address(),
799 None,
800 Derivation::SoftHash(H256::from_low_u64_be(1999)),
801 msg,
802 ).expect("Derived signing with existing unlocked account should not fail");
803
804 assert_eq!(signed_msg1, signed_msg2, "Signed messages should match");
805 }
806
807 #[test]
808 fn unlock_account_perm() {
809 let kp = Random.generate().unwrap();
810 let ap = AccountProvider::transient_provider();
811 assert!(ap
812 .insert_account(kp.secret().clone(), &"test".into())
813 .is_ok());
814 assert!(ap
815 .unlock_account_permanently(kp.address(), "test1".into())
816 .is_err());
817 assert!(ap
818 .unlock_account_permanently(kp.address(), "test".into())
819 .is_ok());
820 assert!(ap.sign(kp.address(), None, Default::default()).is_ok());
821 assert!(ap.sign(kp.address(), None, Default::default()).is_ok());
822 assert!(ap
823 .unlock_account_temporarily(kp.address(), "test".into())
824 .is_ok());
825 assert!(ap.sign(kp.address(), None, Default::default()).is_ok());
826 assert!(ap.sign(kp.address(), None, Default::default()).is_ok());
827 }
828
829 #[test]
830 fn unlock_account_timer() {
831 let kp = Random.generate().unwrap();
832 let ap = AccountProvider::transient_provider();
833 assert!(ap
834 .insert_account(kp.secret().clone(), &"test".into())
835 .is_ok());
836 assert!(ap
837 .unlock_account_timed(
838 kp.address(),
839 "test1".into(),
840 Duration::from_secs(60)
841 )
842 .is_err());
843 assert!(ap
844 .unlock_account_timed(
845 kp.address(),
846 "test".into(),
847 Duration::from_secs(60)
848 )
849 .is_ok());
850 assert!(ap.sign(kp.address(), None, Default::default()).is_ok());
851 ap.unlocked
852 .write()
853 .get_mut(&StoreAccountRef::root(kp.address()))
854 .unwrap()
855 .unlock = Unlock::Timed(Instant::now());
856 assert!(ap.sign(kp.address(), None, Default::default()).is_err());
857 }
858
859 #[test]
860 fn should_sign_and_return_token() {
861 let kp = Random.generate().unwrap();
863 let ap = AccountProvider::transient_provider();
864 assert!(ap
865 .insert_account(kp.secret().clone(), &"test".into())
866 .is_ok());
867
868 let (_signature, token) = ap
870 .sign_with_token(kp.address(), "test".into(), Default::default())
871 .unwrap();
872
873 ap.sign_with_token(kp.address(), token.clone(), Default::default())
875 .expect("First usage of token should be correct.");
876 assert!(
877 ap.sign_with_token(kp.address(), token, Default::default())
878 .is_err(),
879 "Second usage of the same token should fail."
880 );
881 }
882
883 #[test]
884 fn should_not_return_blacklisted_account() {
885 let mut ap = AccountProvider::transient_provider();
887 let acc = ap.new_account(&"test".into()).unwrap();
888 ap.blacklisted_accounts = vec![acc];
889
890 assert_eq!(
892 ap.accounts_info()
893 .unwrap()
894 .keys()
895 .cloned()
896 .collect::<Vec<Address>>(),
897 vec![]
898 );
899 assert_eq!(ap.accounts().unwrap(), vec![]);
900 }
901}