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 },
293 _ => None,
294 }
295 }
296
297 pub fn group(&self) -> Option<&Secp256r1PublicKey> {
299 match self {
300 WitnessCondition::Group(group) | WitnessCondition::CalledByGroup(group) => Some(group),
301 _ => None,
302 }
303 }
304
305 pub fn from_bytes(bytes: &[u8]) -> Result<WitnessCondition, TransactionError> {
306 let mut reader = Decoder::new(bytes);
307 WitnessCondition::decode(&mut reader)
308 }
309}
310
311impl NeoSerializable for WitnessCondition {
312 type Error = TransactionError;
313
314 fn size(&self) -> usize {
315 match self {
316 WitnessCondition::Boolean(_) => 2,
317 WitnessCondition::Not(_) => 1 + self.expression().unwrap().size(),
318 WitnessCondition::And(_) | WitnessCondition::Or(_) => {
319 let exp = self.expression_list().unwrap();
320 1 + exp.var_size()
322 },
323 WitnessCondition::ScriptHash(_) | WitnessCondition::CalledByContract(_) => 1 + 20,
324 WitnessCondition::Group(_) | WitnessCondition::CalledByGroup(_) => 1 + 33,
325 WitnessCondition::CalledByEntry => 1,
326 }
327 }
328
329 fn encode(&self, writer: &mut Encoder) {
330 match self {
331 WitnessCondition::Boolean(b) => {
332 writer.write_u8(WitnessCondition::BOOLEAN_BYTE);
333 writer.write_bool(*b);
334 },
335 WitnessCondition::Not(exp) => {
336 writer.write_u8(WitnessCondition::NOT_BYTE);
337 writer.write_serializable_fixed(exp.expression().unwrap());
338 },
339 WitnessCondition::And(exp) => {
340 writer.write_u8(WitnessCondition::AND_BYTE);
341 writer.write_serializable_variable_list(exp);
342 },
343 WitnessCondition::Or(exp) => {
344 writer.write_u8(WitnessCondition::OR_BYTE);
345 writer.write_serializable_variable_list(exp);
346 },
347 WitnessCondition::ScriptHash(hash) => {
348 writer.write_u8(WitnessCondition::SCRIPT_HASH_BYTE);
349 writer.write_serializable_fixed(hash);
350 },
351 WitnessCondition::Group(group) => {
352 writer.write_u8(WitnessCondition::GROUP_BYTE);
353 writer.write_serializable_fixed(group);
354 },
355 WitnessCondition::CalledByEntry => {
356 writer.write_u8(WitnessCondition::CALLED_BY_ENTRY_BYTE);
357 },
358 WitnessCondition::CalledByContract(hash) => {
359 writer.write_u8(WitnessCondition::CALLED_BY_CONTRACT_BYTE);
360 writer.write_serializable_fixed(hash);
361 },
362 WitnessCondition::CalledByGroup(group) => {
363 writer.write_u8(WitnessCondition::CALLED_BY_GROUP_BYTE);
364 writer.write_serializable_fixed(group);
365 },
366 }
367 }
368
369 fn decode(reader: &mut Decoder) -> Result<Self, Self::Error> {
370 let byte = reader.read_u8();
371 match byte {
372 WitnessCondition::BOOLEAN_BYTE => {
373 let b = reader.read_bool();
374 Ok(WitnessCondition::Boolean(b))
375 },
376 WitnessCondition::NOT_BYTE => {
377 let exp = WitnessCondition::decode(reader)?;
378 Ok(WitnessCondition::Not(Box::from(exp)))
379 },
380 WitnessCondition::OR_BYTE | WitnessCondition::AND_BYTE => {
381 let len = reader.read_var_int()? as usize;
382 if len > Self::MAX_SUBITEMS {
383 return Err(TransactionError::InvalidWitnessCondition);
384 }
385 let mut expressions = Vec::with_capacity(len);
386 for _ in 0..len {
387 expressions.push(WitnessCondition::decode(reader)?);
388 }
389 if byte == Self::OR_BYTE {
390 Ok(WitnessCondition::Or(expressions))
391 } else {
392 Ok(WitnessCondition::And(expressions))
393 }
394 },
395 WitnessCondition::SCRIPT_HASH_BYTE | WitnessCondition::CALLED_BY_CONTRACT_BYTE => {
396 let hash = H160::decode(reader)?;
397 if byte == WitnessCondition::SCRIPT_HASH_BYTE {
398 Ok(WitnessCondition::ScriptHash(hash))
399 } else {
400 Ok(WitnessCondition::CalledByContract(hash))
401 }
402 },
403 WitnessCondition::GROUP_BYTE | WitnessCondition::CALLED_BY_GROUP_BYTE => {
404 let group = Secp256r1PublicKey::decode(reader)?;
405 if byte == WitnessCondition::GROUP_BYTE {
406 Ok(WitnessCondition::Group(group))
407 } else {
408 Ok(WitnessCondition::CalledByGroup(group))
409 }
410 },
411 WitnessCondition::CALLED_BY_ENTRY_BYTE => Ok(WitnessCondition::CalledByEntry),
412 _ => Err(TransactionError::InvalidTransaction),
413 }
414 }
415
416 fn to_array(&self) -> Vec<u8> {
417 let mut writer = Encoder::new();
418 self.encode(&mut writer);
419 writer.to_bytes()
420 }
421}