neo3/neo_builder/transaction/signers/
account_signer.rs

1use std::hash::{Hash, Hasher};
2
3use crate::{
4	builder::{BuilderError, SignerTrait, SignerType, TransactionError, WitnessRule, WitnessScope},
5	codec::{Decoder, Encoder, NeoSerializable, VarSizeTrait},
6	config::NeoConstants,
7	crypto::{PublicKeyExtension, Secp256r1PublicKey},
8	deserialize_script_hash, deserialize_vec_script_hash,
9	neo_protocol::{Account, AccountTrait},
10	neo_types::{deserialize_vec_public_key, serialize_vec_public_key},
11	serialize_script_hash, serialize_vec_script_hash, ScriptHashExtension,
12};
13use getset::{Getters, Setters};
14use primitive_types::H160;
15use serde::{Deserialize, Serialize};
16
17/// Represents an account signer in the NEO blockchain.
18///
19/// This struct contains information about the account signer, including
20/// the signer hash, scopes, allowed contracts, allowed groups, and witness rules.
21#[derive(Debug, Clone, Serialize, Deserialize, Getters, Setters)]
22pub struct AccountSigner {
23	#[serde(
24		serialize_with = "serialize_script_hash",
25		deserialize_with = "deserialize_script_hash"
26	)]
27	pub(crate) signer_hash: H160,
28	pub(crate) scopes: Vec<WitnessScope>,
29	#[serde(
30		serialize_with = "serialize_vec_script_hash",
31		deserialize_with = "deserialize_vec_script_hash"
32	)]
33	pub(crate) allowed_contracts: Vec<H160>,
34	#[serde(
35		serialize_with = "serialize_vec_public_key",
36		deserialize_with = "deserialize_vec_public_key"
37	)]
38	pub(crate) allowed_groups: Vec<Secp256r1PublicKey>,
39	rules: Vec<WitnessRule>,
40	#[getset(get = "pub")]
41	pub account: Account,
42}
43
44impl AccountSigner {
45	/// Creates a new `AccountSigner` with no scope.
46	///
47	/// # Arguments
48	///
49	/// * `account` - The account to create the signer for.
50	pub fn none(account: &Account) -> Result<Self, TransactionError> {
51		Ok(Self::new(account, WitnessScope::None))
52	}
53
54	/// Creates a new `AccountSigner` with the "Called By Entry" scope.
55	///
56	/// # Arguments
57	///
58	/// * `account` - The account to create the signer for.
59	pub fn called_by_entry(account: &Account) -> Result<Self, TransactionError> {
60		Ok(Self::new(account, WitnessScope::CalledByEntry))
61	}
62
63	/// Creates a new `AccountSigner` with the "Global" scope.
64	///
65	/// # Arguments
66	///
67	/// * `account` - The account to create the signer for.
68	pub fn global(account: &Account) -> Result<Self, TransactionError> {
69		Ok(Self::new(account, WitnessScope::Global))
70	}
71
72	/// Checks if the account is a multi-signature account.
73	pub fn is_multi_sig(&self) -> bool {
74		matches!(&self.account.verification_script(), Some(script) if script.is_multi_sig())
75	}
76
77	/// Returns the script hash of the account.
78	pub fn get_script_hash(&self) -> H160 {
79		self.account.get_script_hash().clone()
80	}
81}
82
83impl NeoSerializable for AccountSigner {
84	type Error = TransactionError;
85
86	fn size(&self) -> usize {
87		let mut size: usize = NeoConstants::HASH160_SIZE as usize + 1;
88		if self.scopes.contains(&WitnessScope::CustomContracts) {
89			size += self.allowed_contracts.var_size();
90		}
91		if self.scopes.contains(&WitnessScope::CustomGroups) {
92			size += self.allowed_groups.var_size();
93		}
94		if self.scopes.contains(&WitnessScope::WitnessRules) {
95			size += self.rules.var_size();
96		}
97		size
98	}
99
100	fn encode(&self, writer: &mut Encoder) {
101		writer.write_serializable_fixed(&self.signer_hash);
102		writer.write_u8(WitnessScope::combine(&self.scopes));
103		if self.scopes.contains(&WitnessScope::CustomContracts) {
104			writer.write_serializable_variable_list(&self.allowed_contracts);
105		}
106		if self.scopes.contains(&WitnessScope::CustomGroups) {
107			writer.write_serializable_variable_list(&self.allowed_groups);
108		}
109		if self.scopes.contains(&WitnessScope::WitnessRules) {
110			writer.write_serializable_variable_list(&self.rules);
111		}
112	}
113
114	fn decode(reader: &mut Decoder) -> Result<Self, Self::Error>
115	where
116		Self: Sized,
117	{
118		let signer_hash = reader.read_serializable::<H160>().unwrap();
119		let scopes = WitnessScope::split(reader.read_u8());
120		let mut allowed_contracts = vec![];
121		let mut allowed_groups = vec![];
122		let mut rules = vec![];
123		if scopes.contains(&WitnessScope::CustomContracts) {
124			allowed_contracts = reader.read_serializable_list::<H160>().unwrap();
125			if allowed_contracts.len() > NeoConstants::MAX_SIGNER_SUBITEMS as usize {
126				return Err(BuilderError::SignerConfiguration(format!(
127                    "A signer's scope can only contain {} allowed contracts. The input data contained {} contracts.",
128                    NeoConstants::MAX_SIGNER_SUBITEMS,
129                    allowed_contracts.len()
130                ))
131                    .into());
132			}
133		}
134		if scopes.contains(&WitnessScope::CustomGroups) {
135			allowed_groups = reader.read_serializable_list::<Secp256r1PublicKey>().unwrap();
136			if allowed_groups.len() > NeoConstants::MAX_SIGNER_SUBITEMS as usize {
137				return Err(BuilderError::SignerConfiguration(format!(
138                    "A signer's scope can only contain {} allowed contract groups. The input data contained {} groups.",
139                    NeoConstants::MAX_SIGNER_SUBITEMS,
140                    allowed_groups.len()
141                ))
142                    .into());
143			}
144		}
145		if scopes.contains(&WitnessScope::WitnessRules) {
146			rules = reader.read_serializable_list::<WitnessRule>().unwrap();
147			if rules.len() > NeoConstants::MAX_SIGNER_SUBITEMS as usize {
148				return Err(BuilderError::SignerConfiguration(format!(
149                    "A signer's scope can only contain {} rules. The input data contained {} rules.",
150                    NeoConstants::MAX_SIGNER_SUBITEMS,
151                    rules.len()
152                ))
153                    .into());
154			}
155		}
156		Ok(Self {
157			signer_hash,
158			scopes,
159			allowed_contracts,
160			allowed_groups,
161			rules,
162			account: Account::from_address(signer_hash.to_address().as_str()).unwrap(),
163		})
164	}
165
166	fn to_array(&self) -> Vec<u8> {
167		let mut writer = Encoder::new();
168		self.encode(&mut writer);
169		writer.to_bytes()
170	}
171}
172
173impl PartialEq for AccountSigner {
174	fn eq(&self, other: &Self) -> bool {
175		self.signer_hash == other.signer_hash
176			&& self.scopes == other.scopes
177			&& self.allowed_contracts == other.allowed_contracts
178			&& self.allowed_groups == other.allowed_groups
179			&& self.rules == other.rules
180		// && self.account == other.account
181	}
182}
183
184impl Hash for AccountSigner {
185	fn hash<H: Hasher>(&self, state: &mut H) {
186		self.signer_hash.hash(state);
187		self.scopes.hash(state);
188		self.allowed_contracts.hash(state);
189		for group in self.allowed_groups.iter() {
190			group.to_vec().hash(state);
191		}
192		// self.allowed_groups.to_vec().hash(state);
193		self.rules.hash(state);
194		// self.account.hash(state);
195		// self.scope.hash(state);
196	}
197}
198
199impl SignerTrait for AccountSigner {
200	fn get_type(&self) -> SignerType {
201		SignerType::AccountSigner
202	}
203
204	fn get_signer_hash(&self) -> &H160 {
205		&self.signer_hash
206	}
207
208	fn set_signer_hash(&mut self, signer_hash: H160) {
209		self.signer_hash = signer_hash;
210	}
211
212	fn get_scopes(&self) -> &Vec<WitnessScope> {
213		&self.scopes
214	}
215
216	fn get_scopes_mut(&mut self) -> &mut Vec<WitnessScope> {
217		&mut self.scopes
218	}
219
220	fn set_scopes(&mut self, scopes: Vec<WitnessScope>) {
221		self.scopes = scopes;
222	}
223
224	fn get_allowed_contracts(&self) -> &Vec<H160> {
225		&self.allowed_contracts
226	}
227
228	fn get_allowed_contracts_mut(&mut self) -> &mut Vec<H160> {
229		&mut self.allowed_contracts
230	}
231
232	fn get_allowed_groups(&self) -> &Vec<Secp256r1PublicKey> {
233		&self.allowed_groups
234	}
235
236	fn get_allowed_groups_mut(&mut self) -> &mut Vec<Secp256r1PublicKey> {
237		&mut self.allowed_groups
238	}
239
240	fn get_rules(&self) -> &Vec<WitnessRule> {
241		&self.rules
242	}
243
244	fn get_rules_mut(&mut self) -> &mut Vec<WitnessRule> {
245		&mut self.rules
246	}
247}
248
249impl AccountSigner {
250	pub fn new(account: &Account, scope: WitnessScope) -> Self {
251		Self {
252			signer_hash: account.get_script_hash().clone(),
253			scopes: vec![scope],
254			allowed_contracts: vec![],
255			allowed_groups: vec![],
256			rules: vec![],
257			account: account.clone(),
258		}
259	}
260
261	pub fn none_hash160(account_hash: H160) -> Result<Self, TransactionError> {
262		let account = Account::from_address(account_hash.to_address().as_str()).unwrap();
263		Ok(Self::new(&account, WitnessScope::None))
264	}
265
266	pub fn called_by_entry_hash160(account_hash: H160) -> Result<Self, TransactionError> {
267		let account = Account::from_address(account_hash.to_address().as_str()).unwrap();
268		Ok(Self::new(&account, WitnessScope::CalledByEntry))
269	}
270
271	pub fn global_hash160(account_hash: H160) -> Result<Self, TransactionError> {
272		let account = Account::from_address(account_hash.to_address().as_str()).unwrap();
273		Ok(Self::new(&account, WitnessScope::Global))
274	}
275}