1use crate::{
2 builder::{
3 AccountSigner, BuilderError, ContractSigner, TransactionError, TransactionSigner,
4 WitnessCondition, WitnessRule, WitnessScope,
5 },
6 codec::{Decoder, Encoder, NeoSerializable},
7 config::NeoConstants,
8 crypto::Secp256r1PublicKey,
9 neo_protocol::AccountTrait,
10};
11use elliptic_curve::pkcs8::der::Encode;
12use primitive_types::H160;
13use serde::{Deserialize, Serialize, Serializer};
14use std::{
15 collections::HashSet,
16 hash::{Hash, Hasher},
17 ops::Deref,
18};
19
20use lazy_static::lazy_static;
21
22#[derive(Debug, Clone, PartialEq, Eq, Hash)]
24pub enum SignerType {
25 AccountSigner,
26 ContractSigner,
27 TransactionSigner,
28}
29
30pub trait SignerTrait {
32 fn get_type(&self) -> SignerType;
33
34 fn get_signer_hash(&self) -> &H160;
35
36 fn set_signer_hash(&mut self, signer_hash: H160);
37
38 fn get_scopes(&self) -> &Vec<WitnessScope>;
39 fn get_scopes_mut(&mut self) -> &mut Vec<WitnessScope>;
40
41 fn set_scopes(&mut self, scopes: Vec<WitnessScope>);
42
43 fn get_allowed_contracts(&self) -> &Vec<H160>;
44
45 fn get_allowed_contracts_mut(&mut self) -> &mut Vec<H160>;
46
47 fn get_allowed_groups(&self) -> &Vec<Secp256r1PublicKey>;
50 fn get_allowed_groups_mut(&mut self) -> &mut Vec<Secp256r1PublicKey>;
51
52 fn get_rules(&self) -> &Vec<WitnessRule>;
53 fn get_rules_mut(&mut self) -> &mut Vec<WitnessRule>;
54
55 fn set_allowed_contracts(&mut self, contracts: Vec<H160>) -> Result<(), BuilderError> {
57 if self.get_scopes().contains(&WitnessScope::Global) {
59 return Err(BuilderError::SignerConfiguration(
60 "Trying to set allowed contracts on a Signer with global scope.".to_string(),
61 ));
62 }
63
64 if self.get_allowed_contracts().len() + contracts.len()
65 > NeoConstants::MAX_SIGNER_SUBITEMS as usize
66 {
67 return Err(BuilderError::SignerConfiguration(format!(
68 "Trying to set more than {} allowed contracts on a signer.",
69 NeoConstants::MAX_SIGNER_SUBITEMS
70 )));
71 }
72
73 self.get_scopes_mut().retain(|scope| *scope != WitnessScope::None);
83
84 if !self.get_scopes().contains(&WitnessScope::CustomContracts) {
86 self.get_scopes_mut().push(WitnessScope::CustomContracts);
87 }
88
89 self.get_allowed_contracts_mut().extend(contracts);
90
91 Ok(())
92 }
93
94 fn set_allowed_groups(&mut self, groups: Vec<Secp256r1PublicKey>) -> Result<(), BuilderError> {
96 if self.get_scopes().contains(&WitnessScope::Global) {
97 return Err(BuilderError::SignerConfiguration(
98 "Trying to set allowed contract groups on a Signer with global scope.".to_string(),
99 ));
100 }
101
102 if self.get_allowed_groups().len() + groups.len()
103 > NeoConstants::MAX_SIGNER_SUBITEMS as usize
104 {
105 return Err(BuilderError::SignerConfiguration(format!(
106 "Trying to set more than {} allowed contract groups on a signer.",
107 NeoConstants::MAX_SIGNER_SUBITEMS
108 )));
109 }
110
111 self.get_scopes_mut().retain(|scope| *scope != WitnessScope::None);
112
113 if !self.get_scopes().contains(&WitnessScope::CustomGroups) {
114 self.get_scopes_mut().push(WitnessScope::CustomGroups);
115 }
116
117 self.get_allowed_groups_mut().extend(groups);
118
119 Ok(())
120 }
121
122 fn set_rules(&mut self, mut rules: Vec<WitnessRule>) -> Result<&mut Self, BuilderError> {
123 if !rules.is_empty() {
124 if self.get_scopes().contains(&WitnessScope::Global) {
125 return Err(BuilderError::SignerConfiguration(
126 "Trying to set witness rules on a Signer with global scope.".to_string(),
127 ));
128 }
129
130 if self.get_rules().len() + rules.len() > NeoConstants::MAX_SIGNER_SUBITEMS as usize {
131 return Err(BuilderError::SignerConfiguration(format!(
132 "Trying to set more than {} allowed witness rules on a signer.",
133 NeoConstants::MAX_SIGNER_SUBITEMS
134 )));
135 }
136
137 for rule in &rules {
138 self.check_depth(&rule.condition, WitnessCondition::MAX_NESTING_DEPTH as i8)?;
139 }
140
141 if !self.get_scopes().contains(&WitnessScope::WitnessRules) {
142 self.get_scopes_mut().push(WitnessScope::WitnessRules);
143 }
144
145 self.get_rules_mut().append(&mut rules);
146 }
147
148 Ok(self)
149 }
150
151 fn check_depth(&self, condition: &WitnessCondition, depth: i8) -> Result<(), BuilderError> {
152 if depth < 0 {
153 return Err(BuilderError::IllegalState(format!(
154 "A maximum nesting depth of {} is allowed for witness conditions",
155 WitnessCondition::MAX_NESTING_DEPTH
156 ))); }
158
159 match condition {
160 WitnessCondition::And(conditions) | WitnessCondition::Or(conditions) => {
161 for c in conditions {
162 self.check_depth(c, depth - 1)?
163 }
164 },
165 _ => (),
166 };
167
168 Ok(())
169 }
170
171 fn validate_subitems(&self, count: usize, _name: &str) -> Result<(), BuilderError> {
172 if count > NeoConstants::MAX_SIGNER_SUBITEMS as usize {
173 return Err(BuilderError::TooManySigners("".to_string()));
174 }
175 Ok(())
176 }
177}
178
179#[derive(Debug, Clone, Deserialize)]
183pub enum Signer {
184 AccountSigner(AccountSigner),
185 ContractSigner(ContractSigner),
186 TransactionSigner(TransactionSigner),
187}
188
189impl PartialEq for Signer {
190 fn eq(&self, other: &Self) -> bool {
191 match self {
192 Signer::AccountSigner(account_signer) => match other {
193 Signer::AccountSigner(other_account_signer) => {
194 account_signer.get_signer_hash() == other_account_signer.get_signer_hash()
195 },
196 _ => false,
197 },
198 Signer::ContractSigner(contract_signer) => match other {
199 Signer::ContractSigner(other_contract_signer) => {
200 contract_signer.get_signer_hash() == other_contract_signer.get_signer_hash()
201 },
202 _ => false,
203 },
204 Signer::TransactionSigner(transaction_signer) => match other {
205 Signer::TransactionSigner(other_transaction_signer) => {
206 transaction_signer.get_signer_hash()
207 == other_transaction_signer.get_signer_hash()
208 },
209 _ => false,
210 },
211 }
212 }
213}
214
215impl SignerTrait for Signer {
216 fn get_type(&self) -> SignerType {
217 match self {
218 Signer::AccountSigner(account_signer) => account_signer.get_type(),
219 Signer::ContractSigner(contract_signer) => contract_signer.get_type(),
220 Signer::TransactionSigner(transaction_signer) => transaction_signer.get_type(),
221 }
222 }
223
224 fn get_signer_hash(&self) -> &H160 {
225 match self {
226 Signer::AccountSigner(account_signer) => account_signer.get_signer_hash(),
227 Signer::ContractSigner(contract_signer) => contract_signer.get_signer_hash(),
228 Signer::TransactionSigner(transaction_signer) => transaction_signer.get_signer_hash(),
229 }
230 }
231
232 fn set_signer_hash(&mut self, signer_hash: H160) {
233 match self {
234 Signer::AccountSigner(account_signer) => account_signer.set_signer_hash(signer_hash),
235 Signer::ContractSigner(contract_signer) => contract_signer.set_signer_hash(signer_hash),
236 Signer::TransactionSigner(transaction_signer) => {
237 transaction_signer.set_signer_hash(signer_hash)
238 },
239 }
240 }
241
242 fn get_scopes(&self) -> &Vec<WitnessScope> {
243 match self {
244 Signer::AccountSigner(account_signer) => account_signer.get_scopes(),
245 Signer::ContractSigner(contract_signer) => contract_signer.get_scopes(),
246 Signer::TransactionSigner(transaction_signer) => transaction_signer.get_scopes(),
247 }
248 }
249
250 fn get_scopes_mut(&mut self) -> &mut Vec<WitnessScope> {
251 match self {
252 Signer::AccountSigner(account_signer) => account_signer.get_scopes_mut(),
253 Signer::ContractSigner(contract_signer) => contract_signer.get_scopes_mut(),
254 Signer::TransactionSigner(transaction_signer) => transaction_signer.get_scopes_mut(),
255 }
256 }
257
258 fn set_scopes(&mut self, scopes: Vec<WitnessScope>) {
259 match self {
260 Signer::AccountSigner(account_signer) => account_signer.set_scopes(scopes),
261 Signer::ContractSigner(contract_signer) => contract_signer.set_scopes(scopes),
262 Signer::TransactionSigner(transaction_signer) => transaction_signer.set_scopes(scopes),
263 }
264 }
265
266 fn get_allowed_contracts(&self) -> &Vec<H160> {
267 match self {
268 Signer::AccountSigner(account_signer) => account_signer.get_allowed_contracts(),
269 Signer::ContractSigner(contract_signer) => contract_signer.get_allowed_contracts(),
270 Signer::TransactionSigner(transaction_signer) => {
271 transaction_signer.get_allowed_contracts()
272 },
273 }
274 }
275
276 fn get_allowed_contracts_mut(&mut self) -> &mut Vec<H160> {
277 match self {
278 Signer::AccountSigner(account_signer) => account_signer.get_allowed_contracts_mut(),
279 Signer::ContractSigner(contract_signer) => contract_signer.get_allowed_contracts_mut(),
280 Signer::TransactionSigner(transaction_signer) => {
281 transaction_signer.get_allowed_contracts_mut()
282 },
283 }
284 }
285
286 fn get_allowed_groups(&self) -> &Vec<Secp256r1PublicKey> {
287 match self {
288 Signer::AccountSigner(account_signer) => account_signer.get_allowed_groups(),
289 Signer::ContractSigner(contract_signer) => contract_signer.get_allowed_groups(),
290 Signer::TransactionSigner(transaction_signer) => {
291 transaction_signer.get_allowed_groups()
292 },
293 }
294 }
295
296 fn get_allowed_groups_mut(&mut self) -> &mut Vec<Secp256r1PublicKey> {
297 match self {
298 Signer::AccountSigner(account_signer) => account_signer.get_allowed_groups_mut(),
299 Signer::ContractSigner(contract_signer) => contract_signer.get_allowed_groups_mut(),
300 Signer::TransactionSigner(transaction_signer) => {
301 transaction_signer.get_allowed_groups_mut()
302 },
303 }
304 }
305
306 fn get_rules(&self) -> &Vec<WitnessRule> {
307 match self {
308 Signer::AccountSigner(account_signer) => account_signer.get_rules(),
309 Signer::ContractSigner(contract_signer) => contract_signer.get_rules(),
310 Signer::TransactionSigner(transaction_signer) => transaction_signer.get_rules(),
311 }
312 }
313
314 fn get_rules_mut(&mut self) -> &mut Vec<WitnessRule> {
315 match self {
316 Signer::AccountSigner(account_signer) => account_signer.get_rules_mut(),
317 Signer::ContractSigner(contract_signer) => contract_signer.get_rules_mut(),
318 Signer::TransactionSigner(transaction_signer) => transaction_signer.get_rules_mut(),
319 }
320 }
321}
322
323impl Signer {
324 pub fn from_bytes(data: &[u8]) -> Result<Signer, TransactionError> {
334 let mut reader = Decoder::new(data);
335 Signer::decode(&mut reader)
336 }
337
338 pub fn get_type(&self) -> SignerType {
340 match self {
341 Signer::AccountSigner(account_signer) => account_signer.get_type(),
342 Signer::ContractSigner(contract_signer) => contract_signer.get_type(),
343 Signer::TransactionSigner(transaction_signer) => transaction_signer.get_type(),
344 }
345 }
346 pub fn get_signer_hash(&self) -> &H160 {
348 match self {
349 Signer::AccountSigner(account_signer) => account_signer.get_signer_hash(),
350 Signer::ContractSigner(contract_signer) => contract_signer.get_signer_hash(),
351 Signer::TransactionSigner(transaction_signer) => transaction_signer.get_signer_hash(),
352 }
353 }
354
355 pub fn as_account_signer(&self) -> Option<&AccountSigner> {
356 match self {
357 Signer::AccountSigner(account_signer) => Some(account_signer),
358 _ => None,
359 }
360 }
361
362 pub fn as_contract_signer(&self) -> Option<&ContractSigner> {
363 match self {
364 Signer::ContractSigner(contract_signer) => Some(contract_signer),
365 _ => None,
366 }
367 }
368
369 pub fn as_transaction_signer(&self) -> Option<&TransactionSigner> {
370 match self {
371 Signer::TransactionSigner(transaction_signer) => Some(transaction_signer),
372 _ => None,
373 }
374 }
375
376 pub fn to_account_signer(self) -> Result<AccountSigner, String> {
378 match self {
379 Signer::AccountSigner(account_signer) => Ok(account_signer),
380 _ => {
381 Err("Cannot convert ContractSigner or TransactionSigner into AccountSigner"
382 .to_string())
383 },
384 }
385 }
386
387 pub fn to_contract_signer(self) -> Result<ContractSigner, String> {
389 match self {
390 Signer::AccountSigner(_) => {
391 Err("Cannot convert AccountSigner into ContractSigner".to_string())
392 },
393 Signer::ContractSigner(contract_signer) => Ok(contract_signer),
394 Signer::TransactionSigner(_) => {
395 Err("Cannot convert TransactionSigner into ContractSigner".to_string())
396 },
397 }
398 }
399}
400
401impl Hash for Signer {
402 fn hash<H: Hasher>(&self, state: &mut H) {
403 match self {
404 Signer::AccountSigner(account_signer) => account_signer.hash(state),
405 Signer::ContractSigner(contract_signer) => contract_signer.hash(state),
406 Signer::TransactionSigner(transaction_signer) => transaction_signer.hash(state),
407 }
408 }
409}
410
411impl From<AccountSigner> for Signer {
412 fn from(account_signer: AccountSigner) -> Self {
413 Signer::AccountSigner(account_signer)
414 }
415}
416
417impl From<ContractSigner> for Signer {
418 fn from(contract_signer: ContractSigner) -> Self {
419 Signer::ContractSigner(contract_signer)
420 }
421}
422
423impl Into<AccountSigner> for Signer {
425 fn into(self) -> AccountSigner {
426 match self {
427 Signer::AccountSigner(account_signer) => account_signer,
428 _ => {
429 eprintln!("Warning: Cannot convert ContractSigner or TransactionSigner into AccountSigner, returning default");
430 AccountSigner::none_hash160(primitive_types::H160::zero()).unwrap_or_else(|_| {
432 let account = crate::neo_protocol::Account::from_wif(
434 "L1WMhxazScMhUrdv34JqQb1HFSQmWeN2Kpc1R9JGKwL7CDNP21uR",
435 )
436 .unwrap();
437 AccountSigner::new(&account, crate::builder::WitnessScope::None)
438 })
439 },
440 }
441 }
442}
443
444impl Into<TransactionSigner> for Signer {
445 fn into(self) -> TransactionSigner {
446 match self {
447 Signer::AccountSigner(account_signer) => TransactionSigner::new_full(
448 account_signer.account.get_script_hash(),
449 account_signer.get_scopes().to_vec(),
450 account_signer.get_allowed_contracts().to_vec(),
451 account_signer.get_allowed_groups().to_vec(),
452 account_signer.get_rules().to_vec(),
453 ),
454 Signer::ContractSigner(contract_signer) => TransactionSigner::new_full(
455 *contract_signer.get_signer_hash(),
456 contract_signer.get_scopes().to_vec(),
457 contract_signer.get_allowed_contracts().to_vec(),
458 contract_signer.get_allowed_groups().to_vec(),
459 contract_signer.get_rules().to_vec(),
460 ),
461 Signer::TransactionSigner(transaction_signer) => transaction_signer,
462 }
463 }
464}
465
466impl Into<TransactionSigner> for &Signer {
467 fn into(self) -> TransactionSigner {
468 match self {
469 Signer::AccountSigner(account_signer) => TransactionSigner::new_full(
470 account_signer.account.get_script_hash(),
471 account_signer.get_scopes().to_vec(),
472 account_signer.get_allowed_contracts().to_vec(),
473 account_signer.get_allowed_groups().to_vec(),
474 account_signer.get_rules().to_vec(),
475 ),
476 Signer::ContractSigner(contract_signer) => TransactionSigner::new_full(
477 *contract_signer.get_signer_hash(),
478 contract_signer.get_scopes().to_vec(),
479 contract_signer.get_allowed_contracts().to_vec(),
480 contract_signer.get_allowed_groups().to_vec(),
481 contract_signer.get_rules().to_vec(),
482 ),
483 Signer::TransactionSigner(transaction_signer) => transaction_signer.clone(),
488 }
489 }
490}
491
492impl Into<TransactionSigner> for &mut Signer {
493 fn into(self) -> TransactionSigner {
494 match self {
495 Signer::AccountSigner(account_signer) => TransactionSigner::new_full(
496 account_signer.account.get_script_hash(),
497 account_signer.get_scopes().to_vec(),
498 account_signer.get_allowed_contracts().to_vec(),
499 account_signer.get_allowed_groups().to_vec(),
500 account_signer.get_rules().to_vec(),
501 ),
502 Signer::ContractSigner(contract_signer) => TransactionSigner::new_full(
503 *contract_signer.get_signer_hash(),
504 contract_signer.get_scopes().to_vec(),
505 contract_signer.get_allowed_contracts().to_vec(),
506 contract_signer.get_allowed_groups().to_vec(),
507 contract_signer.get_rules().to_vec(),
508 ),
509 Signer::TransactionSigner(transaction_signer) => transaction_signer.clone(),
510 }
511 }
512}
513
514impl Into<ContractSigner> for &mut Signer {
515 fn into(self) -> ContractSigner {
516 match self {
517 Signer::ContractSigner(contract_signer) => contract_signer.clone(),
518 _ => {
519 eprintln!("Warning: Cannot convert signer type to ContractSigner, returning minimal fallback");
521 ContractSigner::called_by_entry(H160::zero(), &[])
522 },
523 }
524 }
525}
526
527impl Into<ContractSigner> for Signer {
528 fn into(self) -> ContractSigner {
529 match self {
530 Signer::ContractSigner(contract_signer) => contract_signer,
531 _ => {
532 eprintln!("Warning: Cannot convert signer type to ContractSigner, returning minimal fallback");
534 ContractSigner::called_by_entry(H160::zero(), &[])
535 },
536 }
537 }
538}
539
540impl Serialize for Signer {
541 fn serialize<S>(&self, serializer: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>
542 where
543 S: Serializer,
544 {
545 match self {
546 Signer::AccountSigner(account_signer) => account_signer.serialize(serializer),
547 Signer::ContractSigner(contract_signer) => contract_signer.serialize(serializer),
548 Signer::TransactionSigner(transaction_signer) => {
549 transaction_signer.serialize(serializer)
550 },
551 }
552 }
553}
554
555impl NeoSerializable for Signer {
556 type Error = TransactionError;
557
558 fn size(&self) -> usize {
559 match self {
560 Signer::AccountSigner(account_signer) => account_signer.size(),
561 Signer::ContractSigner(contract_signer) => contract_signer.size(),
562 Signer::TransactionSigner(transaction_signer) => transaction_signer.size(),
563 }
564 }
565
566 fn encode(&self, writer: &mut Encoder) {
567 match self {
568 Signer::AccountSigner(account_signer) => account_signer.encode(writer),
569 Signer::ContractSigner(contract_signer) => contract_signer.encode(writer),
570 Signer::TransactionSigner(transaction_signer) => transaction_signer.encode(writer),
571 }
572 }
573
574 fn decode(reader: &mut Decoder) -> Result<Self, Self::Error>
575 where
576 Self: Sized,
577 {
578 match reader.read_u8() {
579 0 => Ok(Signer::AccountSigner(AccountSigner::decode(reader)?)),
580 1 => Ok(Signer::ContractSigner(ContractSigner::decode(reader)?)),
581 _ => Err(TransactionError::InvalidTransaction),
583 }
584 }
585
586 fn to_array(&self) -> Vec<u8> {
587 match self {
588 Signer::AccountSigner(account_signer) => account_signer.to_array(),
589 Signer::ContractSigner(contract_signer) => contract_signer.to_array(),
590 Signer::TransactionSigner(transaction_signer) => transaction_signer.to_array(),
591 }
592 }
593}
594
595#[cfg(test)]
596mod tests {
597 use std::{collections::HashSet, ops::Deref};
598
599 use lazy_static::lazy_static;
600 use primitive_types::H160;
601
602 use crate::{
603 builder::{
604 AccountSigner, BuilderError, ContractSigner, SignerTrait, WitnessAction,
605 WitnessCondition, WitnessRule, WitnessScope,
606 },
607 codec::{Encoder, NeoSerializable},
608 config::NeoConstants,
609 crypto::Secp256r1PublicKey,
610 neo_protocol::{Account, AccountTrait},
611 ScriptHash, ScriptHashExtension,
612 };
613 use neo3::builder::Signer;
614
615 lazy_static! {
616 pub static ref SCRIPT_HASH: ScriptHash = {
617 Account::from_wif("Kzt94tAAiZSgH7Yt4i25DW6jJFprZFPSqTgLr5dWmWgKDKCjXMfZ")
618 .unwrap()
619 .get_script_hash()
620 };
621 pub static ref SCRIPT_HASH1: H160 = H160::from_script(&hex::decode("d802a401").unwrap());
622 pub static ref SCRIPT_HASH2: H160 = H160::from_script(&hex::decode("c503b112").unwrap());
623 pub static ref GROUP_PUB_KEY1: Secp256r1PublicKey = Secp256r1PublicKey::from_encoded(
624 "0306d3e7f18e6dd477d34ce3cfeca172a877f3c907cc6c2b66c295d1fcc76ff8f7",
625 )
626 .unwrap();
627 pub static ref GROUP_PUB_KEY2: Secp256r1PublicKey = Secp256r1PublicKey::from_encoded(
628 "02958ab88e4cea7ae1848047daeb8883daf5fdf5c1301dbbfe973f0a29fe75de60",
629 )
630 .unwrap();
631 }
632
633 #[test]
634 fn test_create_signer_with_call_by_entry_scope() {
635 let signer = AccountSigner::called_by_entry(&SCRIPT_HASH.deref().into()).unwrap();
636
637 assert_eq!(signer.signer_hash, *SCRIPT_HASH);
638 assert_eq!(signer.scopes, vec![WitnessScope::CalledByEntry]);
639 assert!(signer.get_allowed_contracts().is_empty());
640 assert!(signer.get_allowed_groups().is_empty());
641 }
642
643 #[test]
644 fn test_create_signer_with_global_scope() {
645 let signer = AccountSigner::global(&SCRIPT_HASH.deref().into()).unwrap();
646
647 assert_eq!(signer.signer_hash, *SCRIPT_HASH);
648 assert_eq!(signer.scopes, vec![WitnessScope::Global]);
649 assert!(signer.get_allowed_contracts().is_empty());
650 assert!(signer.get_allowed_groups().is_empty());
651 }
652
653 #[test]
654 fn test_build_valid_signer1() {
655 let mut signer = AccountSigner::called_by_entry(&SCRIPT_HASH.deref().into())
656 .expect("Should be able to create AccountSigner with called_by_entry scope in test");
657 signer
658 .set_allowed_contracts(vec![*SCRIPT_HASH1, *SCRIPT_HASH2])
659 .expect("Should be able to set allowed contracts in test");
660
661 assert_eq!(signer.signer_hash, *SCRIPT_HASH);
662 assert_eq!(
663 signer.get_scopes().iter().cloned().collect::<HashSet<_>>(),
664 vec![WitnessScope::CalledByEntry, WitnessScope::CustomContracts]
665 .into_iter()
666 .collect()
667 );
668 assert_eq!(
669 signer.get_allowed_contracts().iter().cloned().collect::<HashSet<_>>(),
670 vec![*SCRIPT_HASH1, *SCRIPT_HASH2].into_iter().collect()
671 );
672 assert!(signer.get_allowed_groups().is_empty());
673 }
674
675 #[test]
676 fn test_build_valid_signer2() {
677 let mut signer = AccountSigner::none(&SCRIPT_HASH.deref().into())
678 .expect("Should be able to create AccountSigner with none scope in test");
679 signer
680 .set_allowed_contracts(vec![*SCRIPT_HASH1, *SCRIPT_HASH2])
681 .expect("Should be able to set allowed contracts in test");
682
683 assert_eq!(signer.signer_hash, *SCRIPT_HASH);
684 assert_eq!(signer.get_scopes(), &vec![WitnessScope::CustomContracts]);
685 assert_eq!(
686 signer.get_allowed_contracts().iter().cloned().collect::<HashSet<_>>(),
687 vec![*SCRIPT_HASH1, *SCRIPT_HASH2].into_iter().collect()
688 );
689 assert!(signer.get_allowed_groups().is_empty());
690 }
691
692 #[test]
693 fn test_build_valid_signer3() {
694 let mut signer = AccountSigner::none(&SCRIPT_HASH.deref().into())
695 .expect("Should be able to create AccountSigner with none scope in test");
696 signer
697 .set_allowed_groups(vec![GROUP_PUB_KEY1.clone(), GROUP_PUB_KEY2.clone()])
698 .expect("Should be able to set allowed groups in test");
699
700 assert_eq!(signer.signer_hash, *SCRIPT_HASH);
701 assert_eq!(signer.get_scopes(), &vec![WitnessScope::CustomGroups]);
702 assert_eq!(
703 signer.get_allowed_groups().iter().cloned().collect::<HashSet<_>>(),
704 vec![GROUP_PUB_KEY1.clone(), GROUP_PUB_KEY2.clone()].into_iter().collect()
705 );
706 assert!(signer.get_allowed_contracts().is_empty());
707 }
708
709 #[test]
710 fn test_fail_building_signer_with_global_scope_and_custom_contracts() {
711 let mut signer = AccountSigner::global(&SCRIPT_HASH.deref().into()).unwrap();
712 let err = signer.set_allowed_contracts(vec![*SCRIPT_HASH1, *SCRIPT_HASH2]).unwrap_err();
713
714 assert_eq!(
715 err,
716 BuilderError::SignerConfiguration(
717 "Trying to set allowed contracts on a Signer with global scope.".to_string()
718 )
719 );
720 }
721
722 #[test]
723 fn test_fail_building_signer_with_global_scope_and_custom_groups() {
724 let mut signer = AccountSigner::global(&SCRIPT_HASH.deref().into()).unwrap();
725 let err = signer
726 .set_allowed_groups(vec![GROUP_PUB_KEY1.clone(), GROUP_PUB_KEY2.clone()])
727 .unwrap_err();
728
729 assert_eq!(
730 err,
731 BuilderError::SignerConfiguration(
732 "Trying to set allowed contract groups on a Signer with global scope.".to_string()
733 )
734 );
735 }
736
737 #[test]
738 fn test_fail_building_signer_too_many_contracts() {
739 let script = H160::from_hex("3ab0be8672e25cf475219d018ded961ec684ca88").unwrap();
740 let contracts = (0..=16).map(|_| script.clone()).collect::<Vec<_>>();
741
742 let err = AccountSigner::called_by_entry(&SCRIPT_HASH.deref().into())
743 .unwrap()
744 .set_allowed_contracts(contracts)
745 .unwrap_err();
746
747 assert_eq!(
748 err,
749 BuilderError::SignerConfiguration(format!(
750 "Trying to set more than {} allowed contracts on a signer.",
751 NeoConstants::MAX_SIGNER_SUBITEMS
752 ))
753 );
754 }
755
756 #[test]
757 fn test_fail_building_signer_too_many_contracts_added_separately() {
758 let script = H160::from_hex("3ab0be8672e25cf475219d018ded961ec684ca88").unwrap();
759 let contracts = (0..=15).map(|_| script.clone()).collect::<Vec<_>>();
760
761 let mut signer = AccountSigner::none(&SCRIPT_HASH.deref().into()).unwrap();
762 signer.set_allowed_contracts(vec![script]).expect("");
763
764 let err = signer.set_allowed_contracts(contracts).unwrap_err();
765
766 assert_eq!(
767 err,
768 BuilderError::SignerConfiguration(format!(
769 "Trying to set more than {} allowed contracts on a signer.",
770 NeoConstants::MAX_SIGNER_SUBITEMS
771 ))
772 );
773 }
774
775 #[test]
776 fn test_fail_building_signer_too_many_groups() {
777 let public_key = Secp256r1PublicKey::from_encoded(
778 "0306d3e7f18e6dd477d34ce3cfeca172a877f3c907cc6c2b66c295d1fcc76ff8f7",
779 )
780 .unwrap();
781 let groups = (0..=16).map(|_| public_key.clone()).collect::<Vec<_>>();
782
783 let err = AccountSigner::called_by_entry(&SCRIPT_HASH.deref().into())
784 .unwrap()
785 .set_allowed_groups(groups)
786 .unwrap_err();
787
788 assert_eq!(
789 err,
790 BuilderError::SignerConfiguration(format!(
791 "Trying to set more than {} allowed contract groups on a signer.",
792 NeoConstants::MAX_SIGNER_SUBITEMS
793 ))
794 );
795 }
796
797 #[test]
798 fn test_fail_building_signer_too_many_groups_added_separately() {
799 let public_key = Secp256r1PublicKey::from_encoded(
800 "0306d3e7f18e6dd477d34ce3cfeca172a877f3c907cc6c2b66c295d1fcc76ff8f7",
801 )
802 .unwrap();
803 let groups = (0..=15).map(|_| public_key.clone()).collect::<Vec<_>>();
804
805 let mut signer = AccountSigner::none(&SCRIPT_HASH.deref().into()).unwrap();
806 signer.set_allowed_groups(vec![public_key]).expect("");
807
808 let err = signer.set_allowed_groups(groups).unwrap_err();
809
810 assert_eq!(
811 err,
812 BuilderError::SignerConfiguration(format!(
813 "Trying to set more than {} allowed contract groups on a signer.",
814 NeoConstants::MAX_SIGNER_SUBITEMS
815 ))
816 );
817 }
818
819 #[test]
820 fn test_serialize_global_scope() {
821 let mut buffer = Encoder::new();
822
823 AccountSigner::global(&SCRIPT_HASH.deref().into()).unwrap().encode(&mut buffer);
824
825 let expected = format!(
826 "{}{:02x}",
827 hex::encode(SCRIPT_HASH.as_bytes()),
828 WitnessScope::Global.byte_repr()
829 );
830 assert_eq!(hex::encode(buffer.to_bytes()), expected);
831 }
832
833 #[test]
834 fn test_serialize_custom_contracts_scope_produces_correct_byte_array() {
835 let mut signer = AccountSigner::none(&SCRIPT_HASH.deref().into()).unwrap();
836 signer.set_allowed_contracts(vec![*SCRIPT_HASH1, *SCRIPT_HASH2]).unwrap();
837
838 let expected = format!(
839 "{}{:02x}02{}{}",
840 hex::encode(SCRIPT_HASH.as_bytes()),
841 WitnessScope::CustomContracts.byte_repr(),
842 hex::encode(SCRIPT_HASH1.as_bytes()),
843 hex::encode(SCRIPT_HASH2.as_bytes())
844 );
845
846 assert_eq!(signer.to_array(), hex::decode(&expected).unwrap());
847 }
848
849 #[test]
850 fn test_serialize_custom_group_scope() {
851 let mut signer = AccountSigner::none(&SCRIPT_HASH.deref().into()).unwrap();
852 signer
853 .set_allowed_groups(vec![GROUP_PUB_KEY1.clone(), GROUP_PUB_KEY2.clone()])
854 .expect("");
855
856 let expected = format!(
857 "{}{:02x}02{}{}",
858 hex::encode(SCRIPT_HASH.as_bytes()),
859 WitnessScope::CustomGroups.byte_repr(),
860 GROUP_PUB_KEY1.get_encoded_compressed_hex().trim_start_matches("0x").to_string(),
861 GROUP_PUB_KEY2.get_encoded_compressed_hex().trim_start_matches("0x").to_string(),
862 );
863
864 assert_eq!(signer.to_array(), hex::decode(&expected).unwrap());
865 }
866
867 #[test]
868 fn test_serialize_multiple_scopes_contracts_groups_and_rules() {
869 let rule = WitnessRule::new(
870 WitnessAction::Allow,
871 WitnessCondition::CalledByContract(*SCRIPT_HASH1),
872 );
873 let mut signer = AccountSigner::called_by_entry(&SCRIPT_HASH.deref().into()).unwrap();
874 signer
875 .set_allowed_groups(vec![GROUP_PUB_KEY1.clone(), GROUP_PUB_KEY2.clone()])
876 .expect("");
877 signer.set_allowed_contracts(vec![*SCRIPT_HASH1, *SCRIPT_HASH2]).expect("");
878 signer.set_rules(vec![rule]).expect("");
879
880 let expected = format!(
881 "{}{}{}{}{}{}{}{}{}{}{}{}",
882 hex::encode(SCRIPT_HASH.as_bytes()),
883 "71",
884 "02",
885 hex::encode(SCRIPT_HASH1.as_bytes()),
886 hex::encode(SCRIPT_HASH2.as_bytes()),
887 "02",
888 GROUP_PUB_KEY1.get_encoded_compressed_hex().trim_start_matches("0x").to_string(),
889 GROUP_PUB_KEY2.get_encoded_compressed_hex().trim_start_matches("0x").to_string(),
890 "01",
891 "01",
892 "28",
893 hex::encode(SCRIPT_HASH1.as_bytes())
894 );
895
896 assert_eq!(signer.to_array(), hex::decode(&expected).unwrap());
897 }
898
899 #[test]
900 fn test_fail_deserialize_too_many_contracts() {
901 let mut serialized = format!("{}1111", hex::encode(SCRIPT_HASH.as_bytes()));
902 for _ in 0..=17 {
903 serialized.push_str(&hex::encode(SCRIPT_HASH1.as_bytes()));
904 }
905 let mut data = hex::decode(&serialized).unwrap();
906 data.insert(0, 1);
907
908 let err = Signer::from_bytes(&data).unwrap_err();
909
910 assert!(err.to_string().contains(&format!(
911 "A signer's scope can only contain {} allowed contracts.",
912 NeoConstants::MAX_SIGNER_SUBITEMS
913 )));
914 }
915
916 #[test]
917 fn test_fail_deserialize_too_many_contract_groups() {
918 let mut serialized = format!("{}2111", hex::encode(SCRIPT_HASH.as_bytes()));
919 for _ in 0..=17 {
920 serialized.push_str(
921 &GROUP_PUB_KEY1.get_encoded_compressed_hex().trim_start_matches("0x").to_string(),
922 );
923 }
924 let mut data = hex::decode(&serialized).unwrap();
925 data.insert(0, 1);
926
927 let err = Signer::from_bytes(&data).unwrap_err();
928
929 assert!(err.to_string().contains(&format!(
930 "A signer's scope can only contain {} allowed contract groups.",
931 NeoConstants::MAX_SIGNER_SUBITEMS
932 )));
933 }
934
935 #[test]
936 fn test_fail_deserialize_too_many_rules() {
937 let mut serialized = format!("{}4111", hex::encode(SCRIPT_HASH.as_bytes()));
938 for _ in 0..=17 {
939 serialized.push_str("01");
940 serialized.push_str("28");
941 serialized.push_str(&hex::encode(SCRIPT_HASH1.as_bytes()));
942 }
943 let mut data = hex::decode(&serialized).unwrap();
944 data.insert(0, 1);
945
946 let err = Signer::from_bytes(&data).unwrap_err();
947
948 assert!(err.to_string().contains(&format!(
949 "A signer's scope can only contain {} rules.",
950 NeoConstants::MAX_SIGNER_SUBITEMS
951 )));
952 }
953
954 #[test]
955 fn test_get_size() {
956 let rule = WitnessRule::new(
957 WitnessAction::Allow,
958 WitnessCondition::And(vec![
959 WitnessCondition::Boolean(true),
960 WitnessCondition::Boolean(false),
961 ]),
962 );
963 let mut signer = AccountSigner::called_by_entry(&SCRIPT_HASH.deref().into()).unwrap();
964 signer
965 .set_allowed_groups(vec![GROUP_PUB_KEY1.clone(), GROUP_PUB_KEY2.clone()])
966 .expect("");
967 signer.set_allowed_contracts(vec![*SCRIPT_HASH1, *SCRIPT_HASH2]).expect("");
968 signer.set_rules(vec![rule.clone(), rule]).expect("");
969
970 let expected_size = 20 + 1 + 1 + 20 + 20 + 1 + 33 + 33 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1; assert_eq!(signer.size(), expected_size);
993 }
994
995 #[test]
996 fn test_serialize_deserialize_max_nested_rules() {
997 let rule = WitnessRule::new(
998 WitnessAction::Allow,
999 WitnessCondition::And(vec![WitnessCondition::And(vec![WitnessCondition::Boolean(
1000 true,
1001 )])]),
1002 );
1003
1004 let mut buffer = Encoder::new();
1005 let mut account_signer = AccountSigner::none(&ScriptHash::zero().into()).unwrap();
1006
1007 account_signer.set_rules(vec![rule]).unwrap();
1008 account_signer.encode(&mut buffer);
1009
1010 let expected =
1011 hex::decode("0000000000000000000000000000000000000000400101020102010001").unwrap();
1012 assert_eq!(buffer.to_bytes(), expected);
1013 }
1014
1015 #[test]
1016 fn test_fail_adding_rules_to_global_signer() {
1017 let rule =
1018 WitnessRule::new(WitnessAction::Allow, WitnessCondition::ScriptHash(*SCRIPT_HASH));
1019
1020 let mut signer = AccountSigner::global(&SCRIPT_HASH.deref().into()).unwrap();
1021
1022 let err = signer.set_rules(vec![rule]).unwrap_err();
1023
1024 assert_eq!(
1025 err,
1026 BuilderError::SignerConfiguration(
1027 "Trying to set witness rules on a Signer with global scope.".to_string()
1028 )
1029 );
1030 }
1031
1032 #[test]
1033 fn test_fail_adding_too_many_rules() {
1034 let rule =
1035 WitnessRule::new(WitnessAction::Allow, WitnessCondition::ScriptHash(*SCRIPT_HASH));
1036
1037 let mut signer = AccountSigner::none(&SCRIPT_HASH.deref().into()).unwrap();
1038
1039 for _ in 0..NeoConstants::MAX_SIGNER_SUBITEMS {
1040 signer.set_rules(vec![rule.clone()]).unwrap();
1041 }
1042
1043 let err = signer.set_rules(vec![rule]).unwrap_err();
1044
1045 assert_eq!(
1046 err,
1047 BuilderError::SignerConfiguration(format!(
1048 "Trying to set more than {} allowed witness rules on a signer.",
1049 NeoConstants::MAX_SIGNER_SUBITEMS
1050 ))
1051 );
1052 }
1053
1054 #[test]
1055 fn test_signer_equals() {
1056 let signer1 = AccountSigner::global(&SCRIPT_HASH.deref().into()).unwrap();
1057 let signer2 = AccountSigner::global(&SCRIPT_HASH.deref().into()).unwrap();
1058
1059 assert_eq!(signer1, signer2);
1060
1061 let signer3 = ContractSigner::called_by_entry(*SCRIPT_HASH, &[]);
1062 let signer4 = ContractSigner::called_by_entry(*SCRIPT_HASH, &[]);
1063
1064 assert_eq!(signer3, signer4);
1065
1066 let mut signer5 = AccountSigner::called_by_entry(&SCRIPT_HASH.deref().into()).unwrap();
1067 signer5
1068 .set_allowed_groups(vec![GROUP_PUB_KEY1.clone(), GROUP_PUB_KEY2.clone()])
1069 .expect("");
1070 signer5.set_allowed_contracts(vec![*SCRIPT_HASH1, *SCRIPT_HASH2]).expect("");
1071
1072 let mut signer6 = AccountSigner::called_by_entry(&SCRIPT_HASH.deref().into()).unwrap();
1073 signer6
1074 .set_allowed_groups(vec![GROUP_PUB_KEY1.clone(), GROUP_PUB_KEY2.clone()])
1075 .expect("");
1076 signer6.set_allowed_contracts(vec![*SCRIPT_HASH1, *SCRIPT_HASH2]).expect("");
1077
1078 assert_eq!(signer5, signer6);
1079 }
1080
1081 #[test]
1082 fn test_serialize_with_multiple_scopes_contracts_groups_and_rules() {
1083 let rule = WitnessRule::new(
1084 WitnessAction::Allow,
1085 WitnessCondition::CalledByContract(*SCRIPT_HASH1),
1086 );
1087 let mut signer = AccountSigner::called_by_entry(&SCRIPT_HASH.deref().into()).unwrap();
1088 signer
1089 .set_allowed_groups(vec![GROUP_PUB_KEY1.clone(), GROUP_PUB_KEY2.clone()])
1090 .expect("");
1091 signer.set_allowed_contracts(vec![*SCRIPT_HASH1, *SCRIPT_HASH2]).expect("");
1092 signer.set_rules(vec![rule]).expect("");
1093
1094 let expected = format!(
1095 "{}{}{}{}{}{}{}{}{}{}{}{}",
1096 hex::encode(SCRIPT_HASH.as_bytes()),
1097 "71",
1098 "02",
1099 hex::encode(SCRIPT_HASH1.as_bytes()),
1100 hex::encode(SCRIPT_HASH2.as_bytes()),
1101 "02",
1102 GROUP_PUB_KEY1.get_encoded_compressed_hex().trim_start_matches("0x").to_string(),
1103 GROUP_PUB_KEY2.get_encoded_compressed_hex().trim_start_matches("0x").to_string(),
1104 "01",
1105 "01",
1106 "28",
1107 hex::encode(SCRIPT_HASH1.as_bytes())
1108 );
1109
1110 assert_eq!(signer.to_array(), hex::decode(&expected).unwrap());
1111 }
1112
1113 #[test]
1114 fn test_deserialize() {
1115 let data_str = format!(
1116 "{}{}{}{}{}{}{}{}{}{}{}{}",
1117 hex::encode(SCRIPT_HASH.as_bytes()),
1118 "71",
1119 "02",
1120 hex::encode(SCRIPT_HASH1.as_bytes()),
1121 hex::encode(SCRIPT_HASH2.as_bytes()),
1122 "02",
1123 GROUP_PUB_KEY1.get_encoded_compressed_hex().trim_start_matches("0x").to_string(),
1124 GROUP_PUB_KEY2.get_encoded_compressed_hex().trim_start_matches("0x").to_string(),
1125 "01",
1126 "01",
1127 "28",
1128 hex::encode(SCRIPT_HASH1.as_bytes())
1129 );
1130 let mut serialized = hex::decode(&data_str).unwrap();
1131 serialized.insert(0, 1);
1132
1133 let signer = Signer::from_bytes(&serialized).unwrap();
1134
1135 assert_eq!(signer.get_signer_hash(), SCRIPT_HASH.deref());
1136
1137 let expected_scopes: HashSet<WitnessScope> = vec![
1138 WitnessScope::CalledByEntry,
1139 WitnessScope::CustomContracts,
1140 WitnessScope::CustomGroups,
1141 WitnessScope::WitnessRules,
1142 ]
1143 .into_iter()
1144 .collect();
1145 assert_eq!(signer.get_scopes().iter().cloned().collect::<HashSet<_>>(), expected_scopes);
1146
1147 assert_eq!(
1148 signer.get_allowed_contracts().iter().cloned().collect::<HashSet<_>>(),
1149 vec![*SCRIPT_HASH1, *SCRIPT_HASH2].into_iter().collect()
1150 );
1151
1152 assert_eq!(
1153 signer.get_allowed_groups().iter().cloned().collect::<HashSet<_>>(),
1154 vec![GROUP_PUB_KEY1.clone(), GROUP_PUB_KEY2.clone()].into_iter().collect()
1155 );
1156
1157 let rule = &signer.get_rules()[0];
1158 assert_eq!(rule.action, WitnessAction::Allow);
1159 assert_eq!(rule.condition, WitnessCondition::CalledByContract(*SCRIPT_HASH1));
1160 }
1161}