neo3/neo_builder/transaction/witness_rule/
witness_condition.rs1use 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#[derive(Clone, Debug, PartialEq)]
17pub enum WitnessCondition {
18 Boolean(bool),
20 Not(Box<WitnessCondition>),
22 And(Vec<WitnessCondition>),
24 Or(Vec<WitnessCondition>),
26 ScriptHash(H160),
28 Group(Secp256r1PublicKey),
30 CalledByEntry,
32 CalledByContract(H160),
34 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(
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 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 const MAX_SUBITEMS: usize = 16;
192 pub(crate) const MAX_NESTING_DEPTH: usize = 2;
194
195 const BOOLEAN_VALUE: &'static str = "Boolean";
197 const NOT_VALUE: &'static str = "Not";
199 const AND_VALUE: &'static str = "And";
201 const OR_VALUE: &'static str = "Or";
203 const SCRIPT_HASH_VALUE: &'static str = "ScriptHash";
205 const GROUP_VALUE: &'static str = "Group";
207 const CALLED_BY_ENTRY_VALUE: &'static str = "CalledByEntry";
209 const CALLED_BY_CONTRACT_VALUE: &'static str = "CalledByContract";
211 const CALLED_BY_GROUP_VALUE: &'static str = "CalledByGroup";
213
214 const BOOLEAN_BYTE: u8 = 0x00;
216 const NOT_BYTE: u8 = 0x01;
218 const AND_BYTE: u8 = 0x02;
220 const OR_BYTE: u8 = 0x03;
222 const SCRIPT_HASH_BYTE: u8 = 0x18;
224 const GROUP_BYTE: u8 = 0x19;
226 const CALLED_BY_ENTRY_BYTE: u8 = 0x20;
228 const CALLED_BY_CONTRACT_BYTE: u8 = 0x28;
230 const CALLED_BY_GROUP_BYTE: u8 = 0x29;
232
233 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 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 pub fn boolean_expression(&self) -> Option<bool> {
265 match self {
266 WitnessCondition::Boolean(b) => Some(*b),
267 _ => None,
268 }
269 }
270
271 pub fn expression(&self) -> Option<&WitnessCondition> {
273 match self {
274 WitnessCondition::Not(exp) => Some(&exp),
275 _ => None,
276 }
277 }
278
279 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 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 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.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}