1use ethereum_types::H256;
2use futures_util::TryFutureExt;
47use std::{
48 cell::RefCell,
49 collections::HashSet,
50 default,
51 fmt::Debug,
52 hash::{Hash, Hasher},
53 iter::Iterator,
54 str::FromStr,
55};
56
57use crate::builder::SignerTrait;
58use getset::{CopyGetters, Getters, MutGetters, Setters};
59use once_cell::sync::Lazy;
60use primitive_types::H160;
61use serde::{Deserialize, Serialize};
62use serde_json::Value;
63use crate::neo_types::{
65 Bytes, ContractParameter, InvocationResult, NameOrAddress, ScriptHash, ScriptHashExtension,
66};
67
68use crate::neo_builder::{
70 transaction::{
71 Signer, SignerType, Transaction, TransactionAttribute, TransactionError,
72 VerificationScript, Witness, WitnessScope,
73 },
74 BuilderError,
75};
76
77use crate::{
79 neo_clients::{APITrait, JsonRpcProvider, RpcClient},
80 neo_codec::{Decoder, Encoder, NeoSerializable, VarSizeTrait},
81 neo_config::{NeoConstants, NEOCONFIG},
82 neo_crypto::{utils::ToHexString, HashableForVec, Secp256r1PublicKey},
83 neo_protocol::{AccountTrait, NeoNetworkFee},
84};
85
86use crate::neo_clients::public_key_to_script_hash;
88
89use crate::neo_protocol::Account;
91
92#[cfg(feature = "init")]
94use crate::prelude::init_logger;
95#[cfg(not(feature = "init"))]
97fn init_logger() {
98 }
100
101#[derive(Getters, Setters, MutGetters, CopyGetters, Default)]
102pub struct TransactionBuilder<'a, P: JsonRpcProvider + 'static> {
103 pub(crate) client: Option<&'a RpcClient<P>>,
104 version: u8,
105 nonce: u32,
106 valid_until_block: Option<u32>,
107 #[getset(get = "pub")]
109 pub(crate) signers: Vec<Signer>,
110 #[getset(get = "pub", set = "pub")]
111 additional_network_fee: u64,
112 #[getset(get = "pub", set = "pub")]
113 additional_system_fee: u64,
114 #[getset(get = "pub")]
115 attributes: Vec<TransactionAttribute>,
116 #[getset(get = "pub", set = "pub")]
117 script: Option<Bytes>,
118 fee_consumer: Option<Box<dyn Fn(i64, i64)>>,
119 fee_error: Option<TransactionError>,
120}
121
122impl<'a, P: JsonRpcProvider + 'static> Debug for TransactionBuilder<'a, P> {
123 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
124 f.debug_struct("TransactionBuilder")
125 .field("version", &self.version)
126 .field("nonce", &self.nonce)
127 .field("valid_until_block", &self.valid_until_block)
128 .field("signers", &self.signers)
129 .field("additional_network_fee", &self.additional_network_fee)
130 .field("additional_system_fee", &self.additional_system_fee)
131 .field("attributes", &self.attributes)
132 .field("script", &self.script)
133 .field("fee_error", &self.fee_error)
135 .finish()
136 }
137}
138
139impl<'a, P: JsonRpcProvider + 'static> Clone for TransactionBuilder<'a, P> {
140 fn clone(&self) -> Self {
141 Self {
142 client: self.client,
143 version: self.version,
144 nonce: self.nonce,
145 valid_until_block: self.valid_until_block,
146 signers: self.signers.clone(),
147 additional_network_fee: self.additional_network_fee,
148 additional_system_fee: self.additional_system_fee,
149 attributes: self.attributes.clone(),
150 script: self.script.clone(),
151 fee_consumer: None,
153 fee_error: None,
154 }
155 }
156}
157
158impl<'a, P: JsonRpcProvider + 'static> Eq for TransactionBuilder<'a, P> {}
159
160impl<'a, P: JsonRpcProvider + 'static> PartialEq for TransactionBuilder<'a, P> {
161 fn eq(&self, other: &Self) -> bool {
162 self.version == other.version
163 && self.nonce == other.nonce
164 && self.valid_until_block == other.valid_until_block
165 && self.signers == other.signers
166 && self.additional_network_fee == other.additional_network_fee
167 && self.additional_system_fee == other.additional_system_fee
168 && self.attributes == other.attributes
169 && self.script == other.script
170 }
171}
172
173impl<'a, P: JsonRpcProvider + 'static> Hash for TransactionBuilder<'a, P> {
174 fn hash<H: Hasher>(&self, state: &mut H) {
175 self.version.hash(state);
176 self.nonce.hash(state);
177 self.valid_until_block.hash(state);
178 self.signers.hash(state);
179 self.additional_network_fee.hash(state);
180 self.additional_system_fee.hash(state);
181 self.attributes.hash(state);
182 self.script.hash(state);
183 }
184}
185
186pub static GAS_TOKEN_HASH: Lazy<ScriptHash> = Lazy::new(|| {
187 ScriptHash::from_str("d2a4cff31913016155e38e474a2c06d08be276cf")
188 .expect("GAS token hash is a valid script hash")
189});
190
191impl<'a, P: JsonRpcProvider + 'static> TransactionBuilder<'a, P> {
192 pub const BALANCE_OF_FUNCTION: &'static str = "balanceOf";
194 pub const DUMMY_PUB_KEY: &'static str =
195 "02ec143f00b88524caf36a0121c2de09eef0519ddbe1c710a00f0e2663201ee4c0";
196
197 pub fn new() -> Self {
212 Self {
213 client: None,
214 version: 0,
215 nonce: 0,
216 valid_until_block: None,
217 signers: Vec::new(),
218 additional_network_fee: 0,
219 additional_system_fee: 0,
220 attributes: Vec::new(),
221 script: None,
222 fee_consumer: None,
223 fee_error: None,
224 }
225 }
226
227 pub fn with_client(client: &'a RpcClient<P>) -> Self {
248 Self {
249 client: Some(client),
250 version: 0,
251 nonce: 0,
252 valid_until_block: None,
253 signers: Vec::new(),
254 additional_network_fee: 0,
255 additional_system_fee: 0,
256 attributes: Vec::new(),
257 script: None,
258 fee_consumer: None,
259 fee_error: None,
260 }
261 }
262
263 pub fn version(&mut self, version: u8) -> &mut Self {
285 self.version = version;
286 self
287 }
288
289 pub fn nonce(&mut self, nonce: u32) -> Result<&mut Self, TransactionError> {
314 self.nonce = nonce;
317 Ok(self)
318 }
319
320 pub fn valid_until_block(&mut self, block: u32) -> Result<&mut Self, TransactionError> {
355 if block == 0 {
356 return Err(TransactionError::InvalidBlock);
357 }
358
359 self.valid_until_block = Some(block);
360 Ok(self)
361 }
362
363 pub fn first_signer(&mut self, sender: &Account) -> Result<&mut Self, TransactionError> {
370 self.first_signer_by_hash(&sender.get_script_hash())
371 }
372
373 pub fn first_signer_by_hash(&mut self, sender: &H160) -> Result<&mut Self, TransactionError> {
374 if self.signers.iter().any(|s| s.get_scopes().contains(&WitnessScope::None)) {
375 return Err(TransactionError::ScriptFormat("This transaction contains a signer with fee-only witness scope that will cover the fees. Hence, the order of the signers does not affect the payment of the fees.".to_string()));
376 }
377 if let Some(pos) = self.signers.iter().position(|s| s.get_signer_hash() == sender) {
378 let s = self.signers.remove(pos);
379 self.signers.insert(0, s);
380 Ok(self)
381 } else {
382 Err(TransactionError::ScriptFormat(format!("Could not find a signer with script hash {}. Make sure to add the signer before calling this method.", sender.to_string()).into()))
383 }
384 }
385
386 pub fn extend_script(&mut self, script: Vec<u8>) -> &mut Self {
387 if let Some(ref mut existing_script) = self.script {
388 existing_script.extend(script);
389 } else {
390 self.script = Some(script);
391 }
392 self
393 }
394
395 pub async fn call_invoke_script(&self) -> Result<InvocationResult, TransactionError> {
396 if self.script.is_none() || self.script.as_ref().unwrap().is_empty() {
397 return Err((TransactionError::NoScript));
398 }
399 let result = self
400 .client
401 .unwrap()
402 .rpc_client()
403 .invoke_script(self.script.clone().unwrap().to_hex_string(), self.signers.clone())
404 .await
405 .map_err(|e| TransactionError::ProviderError(e))?;
406 Ok((result))
407 }
408
409 pub async fn build(&mut self) -> Result<Transaction<P>, TransactionError> {
437 self.get_unsigned_tx().await
438 }
439
440 pub async fn get_unsigned_tx(&mut self) -> Result<Transaction<P>, TransactionError> {
442 if self.signers.is_empty() {
444 return Err(TransactionError::NoSigners);
445 }
446
447 if self.script.is_none() {
448 return Err(TransactionError::NoScript);
449 }
450 let len = self.signers.len();
451 self.signers.dedup();
452
453 if len != self.signers.len() {
455 return Err(TransactionError::DuplicateSigner);
456 }
457
458 if self.signers.len() > NeoConstants::MAX_SIGNER_SUBITEMS as usize {
460 return Err(TransactionError::TooManySigners);
461 }
462
463 if let Some(script) = &self.script {
465 if script.is_empty() {
466 return Err(TransactionError::EmptyScript);
467 }
468 } else {
469 return Err(TransactionError::NoScript);
470 }
471
472 if self.valid_until_block.is_none() {
473 self.valid_until_block = Some(
474 self.fetch_current_block_count().await?
475 + self.client.unwrap().max_valid_until_block_increment()
476 - 1,
477 )
478 }
479
480 if self.is_high_priority() && !self.is_allowed_for_high_priority().await {
482 return Err(TransactionError::IllegalState("This transaction does not have a committee member as signer. Only committee members can send transactions with high priority.".to_string()));
483 }
484
485 let system_fee = self.get_system_fee().await? + self.additional_system_fee as i64;
499
500 let network_fee = self.get_network_fee().await? + self.additional_network_fee as i64;
501
502 let mut tx = Transaction {
504 network: Some(self.client.unwrap()),
505 version: self.version,
506 nonce: self.nonce,
507 valid_until_block: self.valid_until_block.unwrap_or(100),
508 size: 0,
509 sys_fee: system_fee,
510 net_fee: network_fee,
511 signers: self.signers.clone(),
512 attributes: self.attributes.clone(),
513 script: self.script.clone().unwrap(), witnesses: vec![],
515 block_count_when_sent: None,
517 };
518
519 if self.fee_error.is_some()
522 && !self.can_send_cover_fees(system_fee as u64 + network_fee as u64).await?
523 {
524 if let Some(supplier) = &self.fee_error {
525 return Err(supplier.clone());
526 }
527 } else if let Some(fee_consumer) = &self.fee_consumer {
528 let sender_balance = self.get_sender_balance().await?.try_into().unwrap(); if network_fee + system_fee > sender_balance {
530 fee_consumer(network_fee + system_fee, sender_balance);
531 }
532 }
533 Ok(tx)
536 }
537
538 async fn get_system_fee(&self) -> Result<i64, TransactionError> {
539 let script = self.script.as_ref().ok_or_else(|| TransactionError::NoScript)?;
540
541 let client = self
542 .client
543 .ok_or_else(|| TransactionError::IllegalState("Client is not set".to_string()))?;
544
545 let response = client
546 .invoke_script(script.to_hex_string(), vec![self.signers[0].clone()])
547 .await
548 .map_err(|e| TransactionError::ProviderError(e))?;
549
550 if response.has_state_fault() {
552 let allows_fault = NEOCONFIG
554 .lock()
555 .map_err(|_| {
556 TransactionError::IllegalState("Failed to lock NEOCONFIG".to_string())
557 })?
558 .allows_transmission_on_fault;
559
560 if !allows_fault {
562 return Err(TransactionError::TransactionConfiguration(format!(
563 "The vm exited due to the following exception: {}",
564 response.exception.unwrap_or_else(|| "Unknown exception".to_string())
565 )));
566 }
567 }
569
570 Ok(i64::from_str(&response.gas_consumed).map_err(|_| {
571 TransactionError::IllegalState("Failed to parse gas consumed".to_string())
572 })?)
573 }
574
575 async fn get_network_fee(&mut self) -> Result<i64, TransactionError> {
576 let client = self
578 .client
579 .ok_or_else(|| TransactionError::IllegalState("Client is not set".to_string()))?;
580
581 let script = self.script.clone().unwrap_or_default(); let valid_until_block = self.valid_until_block.unwrap_or(100);
584
585 let mut tx = Transaction {
586 network: Some(client),
587 version: self.version,
588 nonce: self.nonce,
589 valid_until_block,
590 size: 0,
591 sys_fee: 0,
592 net_fee: 0,
593 signers: self.signers.clone(),
594 attributes: self.attributes.clone(),
595 script,
596 witnesses: vec![],
597 block_count_when_sent: None,
598 };
599 let mut has_atleast_one_signing_account = false;
600
601 for signer in self.signers.iter() {
602 match signer {
603 Signer::ContractSigner(contract_signer) => {
604 let witness =
606 Witness::create_contract_witness(contract_signer.verify_params().to_vec())
607 .map_err(|e| {
608 TransactionError::IllegalState(format!(
609 "Failed to create contract witness: {}",
610 e
611 ))
612 })?;
613 tx.add_witness(witness);
614 },
615 Signer::AccountSigner(account_signer) => {
616 let account = account_signer.account();
618 let verification_script;
619
620 if account.is_multi_sig() {
622 verification_script = self
624 .create_fake_multi_sig_verification_script(account)
625 .map_err(|e| {
626 TransactionError::IllegalState(format!(
627 "Failed to create multi-sig verification script: {}",
628 e
629 ))
630 })?;
631 } else {
632 verification_script =
634 self.create_fake_single_sig_verification_script().map_err(|e| {
635 TransactionError::IllegalState(format!(
636 "Failed to create single-sig verification script: {}",
637 e
638 ))
639 })?;
640 }
641
642 tx.add_witness(Witness::from_scripts(
644 vec![],
645 verification_script.script().to_vec(),
646 ));
647 has_atleast_one_signing_account = true;
648 },
649 _ => {
651 },
653 }
654 }
655 if (!has_atleast_one_signing_account) {
656 return Err(TransactionError::TransactionConfiguration("A transaction requires at least one signing account (i.e. an AccountSigner). None was provided.".to_string()))
657 }
658
659 let fee = client.calculate_network_fee(tx.to_array().to_hex_string()).await?;
660 Ok(fee.network_fee)
661 }
662
663 async fn fetch_current_block_count(&mut self) -> Result<u32, TransactionError> {
664 let client = self
665 .client
666 .ok_or_else(|| TransactionError::IllegalState("Client is not set".to_string()))?;
667 let count = client.get_block_count().await?;
668 Ok(count)
669 }
670
671 async fn get_sender_balance(&self) -> Result<u64, TransactionError> {
672 let sender = &self.signers[0];
674
675 if Self::is_account_signer(sender) {
676 let client = self
677 .client
678 .ok_or_else(|| TransactionError::IllegalState("Client is not set".to_string()))?;
679
680 let balance = client
681 .invoke_function(
682 &GAS_TOKEN_HASH,
683 Self::BALANCE_OF_FUNCTION.to_string(),
684 vec![ContractParameter::from(sender.get_signer_hash())],
685 None,
686 )
687 .await
688 .map_err(|e| TransactionError::ProviderError(e))?
689 .stack[0]
690 .clone();
691
692 return Ok(balance.as_int().ok_or_else(|| {
693 TransactionError::IllegalState("Failed to parse balance as integer".to_string())
694 })? as u64);
695 }
696 Err(TransactionError::InvalidSender)
697 }
698
699 fn create_fake_single_sig_verification_script(
700 &self,
701 ) -> Result<VerificationScript, TransactionError> {
702 let dummy_public_key =
704 Secp256r1PublicKey::from_encoded(Self::DUMMY_PUB_KEY).ok_or_else(|| {
705 TransactionError::IllegalState("Failed to create dummy public key".to_string())
706 })?;
707 Ok(VerificationScript::from_public_key(&dummy_public_key))
709 }
710
711 fn create_fake_multi_sig_verification_script(
712 &self,
713 account: &Account,
714 ) -> Result<VerificationScript, TransactionError> {
715 let mut pub_keys: Vec<Secp256r1PublicKey> = Vec::new();
717
718 let nr_of_participants = account.get_nr_of_participants().map_err(|e| {
720 TransactionError::IllegalState(format!("Failed to get number of participants: {}", e))
721 })?;
722
723 for _ in 0..nr_of_participants {
725 let dummy_public_key = Secp256r1PublicKey::from_encoded(Self::DUMMY_PUB_KEY)
727 .ok_or_else(|| {
728 TransactionError::IllegalState("Failed to create dummy public key".to_string())
729 })?;
730 pub_keys.push(dummy_public_key);
731 }
732
733 let threshold_value = account.get_signing_threshold().map_err(|e| {
735 TransactionError::IllegalState(format!("Failed to get signing threshold: {}", e))
736 })?;
737 let signing_threshold = u8::try_from(threshold_value).map_err(|_| {
738 TransactionError::IllegalState(
739 "Signing threshold value out of range for u8".to_string(),
740 )
741 })?;
742
743 let script = VerificationScript::from_multi_sig(&mut pub_keys[..], signing_threshold);
746
747 Ok(script)
748 }
749
750 fn is_account_signer(signer: &Signer) -> bool {
751 if signer.get_type() == SignerType::AccountSigner {
752 return true;
753 }
754 return false;
755 }
756
757 pub async fn sign(&mut self) -> Result<Transaction<P>, BuilderError> {
831 init_logger();
832 let mut unsigned_tx = self.get_unsigned_tx().await?;
833 let tx_bytes = unsigned_tx.get_hash_data().await?;
834
835 let mut witnesses_to_add = Vec::new();
836 for signer in &mut unsigned_tx.signers {
837 if Self::is_account_signer(signer) {
838 let account_signer = signer.as_account_signer().ok_or_else(|| {
839 BuilderError::IllegalState("Failed to get account signer".to_string())
840 })?;
841 let acc = &account_signer.account;
842 if acc.is_multi_sig() {
843 return Err(BuilderError::IllegalState(
844 "Transactions with multi-sig signers cannot be signed automatically."
845 .to_string(),
846 ));
847 }
848 let key_pair = acc.key_pair().as_ref().ok_or_else(|| {
849 BuilderError::InvalidConfiguration(
850 format!("Cannot create transaction signature because account {} does not hold a private key.", acc.get_address()),
851 )
852 })?;
853 witnesses_to_add.push(Witness::create(tx_bytes.clone(), key_pair)?);
854 } else {
855 let contract_signer = signer.as_contract_signer().ok_or_else(|| {
856 BuilderError::IllegalState(
857 "Expected contract signer but found another type".to_string(),
858 )
859 })?;
860 witnesses_to_add.push(Witness::create_contract_witness(
861 contract_signer.verify_params().clone(),
862 )?);
863 }
864 }
865 for witness in witnesses_to_add {
866 unsigned_tx.add_witness(witness);
867 }
868
869 Ok(unsigned_tx)
870 }
871
872 fn signers_contain_multi_sig_with_committee_member(&self, committee: &HashSet<H160>) -> bool {
873 for signer in &self.signers {
874 if let Some(account_signer) = signer.as_account_signer() {
875 if account_signer.is_multi_sig() {
876 if let Some(script) = &account_signer.account().verification_script() {
877 if let Ok(public_keys) = script.get_public_keys() {
879 for pubkey in public_keys {
880 let hash = public_key_to_script_hash(&pubkey);
881 if committee.contains(&hash) {
882 return true;
883 }
884 }
885 }
886 }
887 }
888 }
889 }
890
891 false
892 }
893
894 pub fn set_signers(&mut self, signers: Vec<Signer>) -> Result<&mut Self, TransactionError> {
924 if self.contains_duplicate_signers(&signers) {
925 return Err(TransactionError::TransactionConfiguration(
926 "Cannot add multiple signers concerning the same account.".to_string(),
927 ));
928 }
929
930 self.check_and_throw_if_max_attributes_exceeded(signers.len(), self.attributes.len())?;
931
932 self.signers = signers;
933 Ok(self)
934 }
935
936 pub fn add_attributes(
971 &mut self,
972 attributes: Vec<TransactionAttribute>,
973 ) -> Result<&mut Self, TransactionError> {
974 self.check_and_throw_if_max_attributes_exceeded(
975 self.signers.len(),
976 self.attributes.len() + attributes.len(),
977 )?;
978 for attr in attributes {
979 match attr {
980 TransactionAttribute::HighPriority => {
981 self.add_high_priority_attribute(attr)?;
982 },
983 TransactionAttribute::NotValidBefore { height } => {
984 self.add_not_valid_before_attribute(attr)?;
985 },
986 TransactionAttribute::Conflicts { hash } => {
987 self.add_conflicts_attribute(attr)?;
988 },
989 _ => {
993 self.attributes.push(attr);
995 },
996 }
997 }
998 Ok(self)
999 }
1000
1001 fn add_high_priority_attribute(
1002 &mut self,
1003 attr: TransactionAttribute,
1004 ) -> Result<(), TransactionError> {
1005 if self.is_high_priority() {
1006 return Err(TransactionError::TransactionConfiguration(
1007 "A transaction can only have one HighPriority attribute.".to_string(),
1008 ));
1009 }
1010 self.attributes.push(attr);
1012 Ok(())
1013 }
1014
1015 fn add_not_valid_before_attribute(
1016 &mut self,
1017 attr: TransactionAttribute,
1018 ) -> Result<(), TransactionError> {
1019 if self.has_attribute_of_type(TransactionAttribute::NotValidBefore { height: 0 }) {
1020 return Err(TransactionError::TransactionConfiguration(
1021 "A transaction can only have one NotValidBefore attribute.".to_string(),
1022 ));
1023 }
1024 self.attributes.push(attr);
1026 Ok(())
1027 }
1028
1029 fn add_conflicts_attribute(
1030 &mut self,
1031 attr: TransactionAttribute,
1032 ) -> Result<(), TransactionError> {
1033 if self.has_attribute(&attr) {
1034 let hash = attr.get_hash().ok_or_else(|| {
1035 TransactionError::IllegalState(
1036 "Expected Conflicts attribute to have a hash".to_string(),
1037 )
1038 })?;
1039
1040 return Err(TransactionError::TransactionConfiguration(format!(
1041 "There already exists a conflicts attribute for the hash {} in this transaction.",
1042 hash
1043 )));
1044 }
1045 self.attributes.push(attr);
1047 Ok(())
1048 }
1049
1050 fn has_attribute_of_type(&self, attr_type: TransactionAttribute) -> bool {
1052 self.attributes.iter().any(|attr| match (attr, &attr_type) {
1053 (
1054 TransactionAttribute::NotValidBefore { .. },
1055 TransactionAttribute::NotValidBefore { .. },
1056 ) => true,
1057 (TransactionAttribute::HighPriority, TransactionAttribute::HighPriority) => true,
1058 _ => false,
1059 })
1060 }
1061
1062 fn has_attribute(&self, attr: &TransactionAttribute) -> bool {
1063 self.attributes.iter().any(|a| a == attr)
1064 }
1065
1066 fn is_high_priority(&self) -> bool {
1068 self.has_attribute_of_type(TransactionAttribute::HighPriority)
1069 }
1070
1071 fn contains_duplicate_signers(&self, signers: &Vec<Signer>) -> bool {
1072 let signer_list: Vec<H160> = signers.iter().map(|s| s.get_signer_hash().clone()).collect();
1073 let signer_set: HashSet<_> = signer_list.iter().collect();
1074 signer_list.len() != signer_set.len()
1075 }
1076
1077 fn check_and_throw_if_max_attributes_exceeded(
1078 &self,
1079 total_signers: usize,
1080 total_attributes: usize,
1081 ) -> Result<(), TransactionError> {
1082 let max_attributes = NeoConstants::MAX_TRANSACTION_ATTRIBUTES.try_into().map_err(|e| {
1083 TransactionError::IllegalState(format!(
1084 "Failed to convert MAX_TRANSACTION_ATTRIBUTES to usize: {}",
1085 e
1086 ))
1087 })?;
1088
1089 if total_signers + total_attributes > max_attributes {
1090 return Err(TransactionError::TransactionConfiguration(format!(
1091 "A transaction cannot have more than {} attributes (including signers).",
1092 NeoConstants::MAX_TRANSACTION_ATTRIBUTES
1093 )));
1094 }
1095 Ok(())
1096 }
1097
1098 async fn is_allowed_for_high_priority(&self) -> bool {
1105 let client = match self.client {
1106 Some(client) => client,
1107 None => return false, };
1109
1110 let response =
1111 match client.get_committee().await.map_err(|e| TransactionError::ProviderError(e)) {
1112 Ok(response) => response,
1113 Err(_) => return false, };
1115
1116 let committee: HashSet<H160> = response
1118 .iter()
1119 .filter_map(|key_str| {
1120 let public_key = Secp256r1PublicKey::from_encoded(key_str)?;
1122 Some(public_key_to_script_hash(&public_key)) })
1124 .collect();
1125
1126 let signers_contain_committee_member = self
1127 .signers
1128 .iter()
1129 .map(|signer| signer.get_signer_hash())
1130 .any(|script_hash| committee.contains(&script_hash));
1131
1132 if signers_contain_committee_member {
1133 return true;
1134 }
1135
1136 return self.signers_contain_multi_sig_with_committee_member(&committee);
1137 }
1138
1139 pub fn do_if_sender_cannot_cover_fees<F>(
1185 &mut self,
1186 mut consumer: F,
1187 ) -> Result<&mut Self, TransactionError>
1188 where
1189 F: FnMut(i64, i64) + Send + Sync + 'static,
1190 {
1191 if self.fee_error.is_some() {
1192 return Err(TransactionError::IllegalState(
1193 "Cannot handle a consumer for this case, since an exception will be thrown if the sender cannot cover the fees.".to_string(),
1194 ));
1195 }
1196 let consumer = RefCell::new(consumer);
1197 self.fee_consumer = Some(Box::new(move |fee, balance| {
1198 let mut consumer = consumer.borrow_mut();
1199 consumer(fee, balance);
1200 }));
1201 Ok(self)
1202 }
1203
1204 pub fn throw_if_sender_cannot_cover_fees(
1211 &mut self,
1212 error: TransactionError,
1213 ) -> Result<&mut Self, TransactionError> {
1214 if self.fee_consumer.is_some() {
1215 return Err(TransactionError::IllegalState(
1216 "Cannot handle a supplier for this case, since a consumer will be executed if the sender cannot cover the fees.".to_string(),
1217 ));
1218 }
1219 self.fee_error = Some(error);
1220 Ok(self)
1221 }
1222
1223 async fn can_send_cover_fees(&self, fees: u64) -> Result<bool, BuilderError> {
1224 let balance = self.get_sender_balance().await?;
1225 Ok(balance >= fees)
1226 }
1227
1228 }