neo3/neo_builder/transaction/witness_rule/
witness_condition.rs

1use std::hash::{Hash, Hasher};
2
3use crate::{
4	builder::TransactionError,
5	codec::{Decoder, Encoder, NeoSerializable},
6	crypto::Secp256r1PublicKey,
7	neo_codec::VarSizeTrait,
8	neo_crypto::utils::{FromHexString, ToHexString},
9	neo_types::ScriptHashExtension,
10};
11use primitive_types::H160;
12use serde::{ser::SerializeStruct, Deserialize, Deserializer, Serialize, Serializer};
13use serde_json::Value;
14
15/// Enum representing the different types of witness conditions that can be used in a smart contract.
16#[derive(Clone, Debug, PartialEq)]
17pub enum WitnessCondition {
18	/// Boolean value.
19	Boolean(bool),
20	/// Not operator.
21	Not(Box<WitnessCondition>),
22	/// And operator.
23	And(Vec<WitnessCondition>),
24	/// Or operator.
25	Or(Vec<WitnessCondition>),
26	/// Script hash.
27	ScriptHash(H160),
28	/// Public key group.
29	Group(Secp256r1PublicKey),
30	/// Called by entry.
31	CalledByEntry,
32	/// Called by contract.
33	CalledByContract(H160),
34	/// Called by public key group.
35	CalledByGroup(Secp256r1PublicKey),
36}
37
38impl Serialize for WitnessCondition {
39	fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
40	where
41		S: Serializer,
42	{
43		let mut state = serializer.serialize_struct("WitnessCondition", 2)?;
44		match *self {
45			WitnessCondition::Boolean(b) => {
46				state.serialize_field("type", "Boolean")?;
47				state.serialize_field("expression", &b)?;
48			},
49			WitnessCondition::Not(ref condition) => {
50				state.serialize_field("type", "Not")?;
51				state.serialize_field("expression", condition)?;
52			},
53			WitnessCondition::And(ref conditions) | WitnessCondition::Or(ref conditions) => {
54				state.serialize_field(
55					"type",
56					if matches!(self, WitnessCondition::And(_)) { "And" } else { "Or" },
57				)?;
58				state.serialize_field("expressions", conditions)?;
59			},
60			WitnessCondition::ScriptHash(ref hash) => {
61				state.serialize_field("type", "ScriptHash")?;
62				state.serialize_field("hash", &hash.to_hex())?;
63			},
64			WitnessCondition::Group(ref key) | WitnessCondition::CalledByGroup(ref key) => {
65				state.serialize_field(
66					"type",
67					if matches!(self, WitnessCondition::Group(_)) {
68						"Group"
69					} else {
70						"CalledByGroup"
71					},
72				)?;
73				state.serialize_field("group", &key.get_encoded(true).to_hex_string())?;
74			},
75			WitnessCondition::CalledByEntry => {
76				state.serialize_field("type", "CalledByEntry")?;
77			},
78			WitnessCondition::CalledByContract(ref hash) => {
79				state.serialize_field("type", "CalledByContract")?;
80				state.serialize_field("hash", &hash.to_hex())?;
81			},
82			WitnessCondition::CalledByGroup(ref key) => {
83				state.serialize_field("type", "CalledByGroup")?;
84				state.serialize_field("group", &key.get_encoded_compressed_hex())?;
85			},
86		}
87		state.end()
88	}
89}
90
91fn deserialize_witness_condition<'de, D>(deserializer: D) -> Result<WitnessCondition, D::Error>
92where
93	D: Deserializer<'de>,
94{
95	let v = Value::deserialize(deserializer)?;
96	match v["type"].as_str() {
97		Some("Boolean") => {
98			let expression = v["expression"]
99				.as_str()
100				.ok_or(serde::de::Error::custom("Expected a boolean for Boolean type"))?;
101			Ok(WitnessCondition::Boolean(if expression == "true" { true } else { false }))
102		},
103		Some("Not") => {
104			let expression = serde_json::from_value(v["expression"].clone())
105				.map_err(|e| serde::de::Error::custom(format!("Not parsing failed: {}", e)))?;
106			Ok(WitnessCondition::Not(Box::new(expression)))
107		},
108		Some("And") | Some("Or") => {
109			let expressions = serde_json::from_value(v["expressions"].clone())
110				.map_err(|e| serde::de::Error::custom(format!("And/Or parsing failed: {}", e)))?;
111			if v["type"] == "And" {
112				Ok(WitnessCondition::And(expressions))
113			} else {
114				Ok(WitnessCondition::Or(expressions))
115			}
116		},
117		Some("ScriptHash") => {
118			let hash = v["hash"]
119				.as_str()
120				.ok_or(serde::de::Error::custom("Expected a string for ScriptHash"))?;
121			// Ok(WitnessCondition::ScriptHash(H160::from_slice(&hash.from_hex().unwrap())))
122			Ok(WitnessCondition::ScriptHash(
123				H160::from_hex(hash.trim_start_matches("0x")).map_err(|e| {
124					serde::de::Error::custom(format!("Failed to parse ScriptHash: {}", e))
125				})?,
126			))
127		},
128		Some("Group") | Some("CalledByGroup") => {
129			let group = v["group"]
130				.as_str()
131				.ok_or(serde::de::Error::custom("Expected a string for Group/CalledByGroup"))?;
132			let group_bytes = group
133				.from_hex_string()
134				.map_err(|e| serde::de::Error::custom(format!("Failed to decode hex: {}", e)))?;
135			let condition = if v["type"] == "Group" {
136				WitnessCondition::Group(Secp256r1PublicKey::from_bytes(&group_bytes).unwrap())
137			} else {
138				WitnessCondition::CalledByGroup(
139					Secp256r1PublicKey::from_bytes(&group_bytes).unwrap(),
140				)
141			};
142			Ok(condition)
143		},
144		Some("CalledByEntry") => Ok(WitnessCondition::CalledByEntry),
145		Some("CalledByContract") => {
146			let hash = v["hash"]
147				.as_str()
148				.ok_or(serde::de::Error::custom("Expected a string for CalledByContract"))?;
149			let hash_bytes = hash
150				.from_hex_string()
151				.map_err(|e| serde::de::Error::custom(format!("Failed to decode hex: {}", e)))?;
152			if hash_bytes.len() != 20 {
153				return Err(serde::de::Error::custom("Invalid H160 length"));
154			}
155			let mut arr = [0u8; 20];
156			arr.copy_from_slice(&hash_bytes);
157			Ok(WitnessCondition::CalledByContract(H160(arr)))
158		},
159		_ => Err(serde::de::Error::custom("Unknown WitnessCondition type")),
160	}
161}
162
163impl<'de> Deserialize<'de> for WitnessCondition {
164	fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
165	where
166		D: Deserializer<'de>,
167	{
168		deserialize_witness_condition(deserializer)
169	}
170}
171
172impl Hash for WitnessCondition {
173	/// Hashes the witness condition.
174	fn hash<H: Hasher>(&self, state: &mut H) {
175		match self {
176			WitnessCondition::Boolean(b) => b.hash(state),
177			WitnessCondition::Not(exp) => exp.hash(state),
178			WitnessCondition::And(exp) => exp.hash(state),
179			WitnessCondition::Or(exp) => exp.hash(state),
180			WitnessCondition::ScriptHash(hash) => hash.hash(state),
181			WitnessCondition::Group(group) => group.get_encoded(true).hash(state),
182			WitnessCondition::CalledByEntry => WitnessCondition::CalledByEntry.hash(state),
183			WitnessCondition::CalledByContract(hash) => hash.hash(state),
184			WitnessCondition::CalledByGroup(group) => group.get_encoded(true).hash(state),
185		}
186	}
187}
188
189impl WitnessCondition {
190	/// Maximum number of subitems.
191	const MAX_SUBITEMS: usize = 16;
192	/// Maximum nesting depth.
193	pub(crate) const MAX_NESTING_DEPTH: usize = 2;
194
195	/// Boolean value string.
196	const BOOLEAN_VALUE: &'static str = "Boolean";
197	/// Not operator string.
198	const NOT_VALUE: &'static str = "Not";
199	/// And operator string.
200	const AND_VALUE: &'static str = "And";
201	/// Or operator string.
202	const OR_VALUE: &'static str = "Or";
203	/// Script hash string.
204	const SCRIPT_HASH_VALUE: &'static str = "ScriptHash";
205	/// Public key group string.
206	const GROUP_VALUE: &'static str = "Group";
207	/// Called by entry string.
208	const CALLED_BY_ENTRY_VALUE: &'static str = "CalledByEntry";
209	/// Called by contract string.
210	const CALLED_BY_CONTRACT_VALUE: &'static str = "CalledByContract";
211	/// Called by public key group string.
212	const CALLED_BY_GROUP_VALUE: &'static str = "CalledByGroup";
213
214	/// Boolean byte value.
215	const BOOLEAN_BYTE: u8 = 0x00;
216	/// Not operator byte value.
217	const NOT_BYTE: u8 = 0x01;
218	/// And operator byte value.
219	const AND_BYTE: u8 = 0x02;
220	/// Or operator byte value.
221	const OR_BYTE: u8 = 0x03;
222	/// Script hash byte value.
223	const SCRIPT_HASH_BYTE: u8 = 0x18;
224	/// Public key group byte value.
225	const GROUP_BYTE: u8 = 0x19;
226	/// Called by entry byte value.
227	const CALLED_BY_ENTRY_BYTE: u8 = 0x20;
228	/// Called by contract byte value.
229	const CALLED_BY_CONTRACT_BYTE: u8 = 0x28;
230	/// Called by public key group byte value.
231	const CALLED_BY_GROUP_BYTE: u8 = 0x29;
232
233	/// Returns the JSON value of the witness condition.
234	pub fn json_value(&self) -> &'static str {
235		match self {
236			WitnessCondition::Boolean(_) => WitnessCondition::BOOLEAN_VALUE,
237			WitnessCondition::Not(_) => WitnessCondition::NOT_VALUE,
238			WitnessCondition::And(_) => WitnessCondition::AND_VALUE,
239			WitnessCondition::Or(_) => WitnessCondition::OR_VALUE,
240			WitnessCondition::ScriptHash(_) => WitnessCondition::SCRIPT_HASH_VALUE,
241			WitnessCondition::Group(_) => WitnessCondition::GROUP_VALUE,
242			WitnessCondition::CalledByEntry => WitnessCondition::CALLED_BY_ENTRY_VALUE,
243			WitnessCondition::CalledByContract(_) => WitnessCondition::CALLED_BY_CONTRACT_VALUE,
244			WitnessCondition::CalledByGroup(_) => WitnessCondition::CALLED_BY_GROUP_VALUE,
245		}
246	}
247
248	/// Returns the byte value of the witness condition.
249	pub fn byte(&self) -> u8 {
250		match self {
251			WitnessCondition::Boolean(_) => WitnessCondition::BOOLEAN_BYTE,
252			WitnessCondition::Not(_) => WitnessCondition::NOT_BYTE,
253			WitnessCondition::And(_) => WitnessCondition::AND_BYTE,
254			WitnessCondition::Or(_) => WitnessCondition::OR_BYTE,
255			WitnessCondition::ScriptHash(_) => WitnessCondition::SCRIPT_HASH_BYTE,
256			WitnessCondition::Group(_) => WitnessCondition::GROUP_BYTE,
257			WitnessCondition::CalledByEntry => WitnessCondition::CALLED_BY_ENTRY_BYTE,
258			WitnessCondition::CalledByContract(_) => WitnessCondition::CALLED_BY_CONTRACT_BYTE,
259			WitnessCondition::CalledByGroup(_) => WitnessCondition::CALLED_BY_GROUP_BYTE,
260		}
261	}
262
263	/// Returns the boolean expression of the witness condition.
264	pub fn boolean_expression(&self) -> Option<bool> {
265		match self {
266			WitnessCondition::Boolean(b) => Some(*b),
267			_ => None,
268		}
269	}
270
271	/// Returns the expression of the witness condition.
272	pub fn expression(&self) -> Option<&WitnessCondition> {
273		match self {
274			WitnessCondition::Not(exp) => Some(&exp),
275			_ => None,
276		}
277	}
278
279	/// Returns the expression list of the witness condition.
280	pub fn expression_list(&self) -> Option<&[WitnessCondition]> {
281		match self {
282			WitnessCondition::And(exp) | WitnessCondition::Or(exp) => Some(&exp),
283			_ => None,
284		}
285	}
286
287	/// Returns the script hash of the witness condition.
288	pub fn script_hash(&self) -> Option<&H160> {
289		match self {
290			WitnessCondition::ScriptHash(hash) | WitnessCondition::CalledByContract(hash) =>
291				Some(hash),
292			_ => None,
293		}
294	}
295
296	/// Returns the public key group of the witness condition.
297	pub fn group(&self) -> Option<&Secp256r1PublicKey> {
298		match self {
299			WitnessCondition::Group(group) | WitnessCondition::CalledByGroup(group) => Some(group),
300			_ => None,
301		}
302	}
303
304	pub fn from_bytes(bytes: &[u8]) -> Result<WitnessCondition, TransactionError> {
305		let mut reader = Decoder::new(bytes);
306		WitnessCondition::decode(&mut reader)
307	}
308}
309
310impl NeoSerializable for WitnessCondition {
311	type Error = TransactionError;
312
313	fn size(&self) -> usize {
314		match self {
315			WitnessCondition::Boolean(_) => 2,
316			WitnessCondition::Not(_) => 1 + self.expression().unwrap().size(),
317			WitnessCondition::And(_) | WitnessCondition::Or(_) => {
318				let exp = self.expression_list().unwrap();
319				//1 + exp.len() + exp.iter().map(|e| e.size()).sum::<usize>()
320				1 + exp.var_size()
321			},
322			WitnessCondition::ScriptHash(_) | WitnessCondition::CalledByContract(_) => 1 + 20,
323			WitnessCondition::Group(_) | WitnessCondition::CalledByGroup(_) => 1 + 33,
324			WitnessCondition::CalledByEntry => 1,
325		}
326	}
327
328	fn encode(&self, writer: &mut Encoder) {
329		match self {
330			WitnessCondition::Boolean(b) => {
331				writer.write_u8(WitnessCondition::BOOLEAN_BYTE);
332				writer.write_bool(*b);
333			},
334			WitnessCondition::Not(exp) => {
335				writer.write_u8(WitnessCondition::NOT_BYTE);
336				writer.write_serializable_fixed(exp.expression().unwrap());
337			},
338			WitnessCondition::And(exp) => {
339				writer.write_u8(WitnessCondition::AND_BYTE);
340				writer.write_serializable_variable_list(exp);
341			},
342			WitnessCondition::Or(exp) => {
343				writer.write_u8(WitnessCondition::OR_BYTE);
344				writer.write_serializable_variable_list(exp);
345			},
346			WitnessCondition::ScriptHash(hash) => {
347				writer.write_u8(WitnessCondition::SCRIPT_HASH_BYTE);
348				writer.write_serializable_fixed(hash);
349			},
350			WitnessCondition::Group(group) => {
351				writer.write_u8(WitnessCondition::GROUP_BYTE);
352				writer.write_serializable_fixed(group);
353			},
354			WitnessCondition::CalledByEntry => {
355				writer.write_u8(WitnessCondition::CALLED_BY_ENTRY_BYTE);
356			},
357			WitnessCondition::CalledByContract(hash) => {
358				writer.write_u8(WitnessCondition::CALLED_BY_CONTRACT_BYTE);
359				writer.write_serializable_fixed(hash);
360			},
361			WitnessCondition::CalledByGroup(group) => {
362				writer.write_u8(WitnessCondition::CALLED_BY_GROUP_BYTE);
363				writer.write_serializable_fixed(group);
364			},
365		}
366	}
367
368	fn decode(reader: &mut Decoder) -> Result<Self, Self::Error> {
369		let byte = reader.read_u8();
370		match byte {
371			WitnessCondition::BOOLEAN_BYTE => {
372				let b = reader.read_bool();
373				Ok(WitnessCondition::Boolean(b))
374			},
375			WitnessCondition::NOT_BYTE => {
376				let exp = WitnessCondition::decode(reader)?;
377				Ok(WitnessCondition::Not(Box::from(exp)))
378			},
379			WitnessCondition::OR_BYTE | WitnessCondition::AND_BYTE => {
380				let len = reader.read_var_int()? as usize;
381				if len > Self::MAX_SUBITEMS {
382					return Err(TransactionError::InvalidWitnessCondition);
383				}
384				let mut expressions = Vec::with_capacity(len);
385				for _ in 0..len {
386					expressions.push(WitnessCondition::decode(reader)?);
387				}
388				if byte == Self::OR_BYTE {
389					Ok(WitnessCondition::Or(expressions))
390				} else {
391					Ok(WitnessCondition::And(expressions))
392				}
393			},
394			WitnessCondition::SCRIPT_HASH_BYTE | WitnessCondition::CALLED_BY_CONTRACT_BYTE => {
395				let hash = H160::decode(reader)?;
396				if byte == WitnessCondition::SCRIPT_HASH_BYTE {
397					Ok(WitnessCondition::ScriptHash(hash))
398				} else {
399					Ok(WitnessCondition::CalledByContract(hash))
400				}
401			},
402			WitnessCondition::GROUP_BYTE | WitnessCondition::CALLED_BY_GROUP_BYTE => {
403				let group = Secp256r1PublicKey::decode(reader)?;
404				if byte == WitnessCondition::GROUP_BYTE {
405					Ok(WitnessCondition::Group(group))
406				} else {
407					Ok(WitnessCondition::CalledByGroup(group))
408				}
409			},
410			WitnessCondition::CALLED_BY_ENTRY_BYTE => Ok(WitnessCondition::CalledByEntry),
411			_ => Err(TransactionError::InvalidTransaction),
412		}
413	}
414
415	fn to_array(&self) -> Vec<u8> {
416		let mut writer = Encoder::new();
417		self.encode(&mut writer);
418		writer.to_bytes()
419	}
420}