neo3/neo_types/
stack_item.rs

1use std::{collections::HashMap, fmt};
2
3/// This module defines the `StackItem` enum and `MapEntry` struct, which are used to represent items on the Neo virtual machine stack.
4/// `StackItem` is a recursive enum that can represent any type of value that can be stored on the stack, including arrays, maps, and custom types.
5/// `MapEntry` is a simple struct that represents a key-value pair in a `StackItem::Map`.
6/// The `StackItem` enum also provides several utility methods for converting between different types and formats.
7use primitive_types::{H160, H256};
8use serde::{
9	de::{Unexpected, Visitor},
10	Deserialize, Deserializer, Serialize,
11};
12
13use crate::crypto::Secp256r1PublicKey;
14use neo3::prelude::{Address, ScriptHashExtension};
15
16/// The `StackItem` enum represents an item on the Neo virtual machine stack.
17#[derive(Clone, Debug, Hash, Eq, PartialEq, Serialize, Deserialize)]
18#[serde(tag = "type")]
19pub enum StackItem {
20	/// Represents any type of value.
21	#[serde(rename = "Any")]
22	Any,
23
24	/// Represents a pointer to another stack item.
25	#[serde(rename = "Pointer")]
26	Pointer {
27		#[serde(deserialize_with = "deserialize_integer_from_string")]
28		value: i64,
29	},
30
31	/// Represents a boolean value.
32	#[serde(rename = "Boolean")]
33	Boolean { value: bool },
34
35	/// Represents an integer value.
36	#[serde(rename = "Integer")]
37	Integer {
38		#[serde(deserialize_with = "deserialize_integer_from_string")]
39		value: i64,
40	},
41
42	/// Represents a byte string value.
43	#[serde(rename = "ByteString")]
44	ByteString {
45		value: String, // base64 encoded
46	},
47
48	/// Represents a buffer value.
49	#[serde(rename = "Buffer")]
50	Buffer {
51		value: String, // base64 encoded
52	},
53
54	/// Represents an array of stack items.
55	#[serde(rename = "Array")]
56	Array { value: Vec<StackItem> },
57
58	/// Represents a struct of stack items.
59	#[serde(rename = "Struct")]
60	Struct { value: Vec<StackItem> },
61
62	/// Represents a map of stack items.
63	#[serde(rename = "Map")]
64	Map { value: Vec<MapEntry> },
65
66	/// Represents an interop interface.
67	#[serde(rename = "InteropInterface")]
68	InteropInterface { id: String, interface: String },
69}
70
71fn deserialize_integer_from_string<'de, D>(deserializer: D) -> Result<i64, D::Error>
72where
73	D: Deserializer<'de>,
74{
75	// let value_str = String::deserialize(deserializer)?;
76	// value_str.parse::<i64>().map_err(serde::de::Error::custom)
77	// First, try to deserialize the input as a string
78	struct StringOrIntVisitor;
79
80	impl<'de> Visitor<'de> for StringOrIntVisitor {
81		type Value = i64;
82
83		fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
84			formatter.write_str("a string or integer")
85		}
86
87		fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
88		where
89			E: serde::de::Error,
90		{
91			value.parse::<i64>().map_err(serde::de::Error::custom)
92		}
93
94		fn visit_string<E>(self, value: String) -> Result<Self::Value, E>
95		where
96			E: serde::de::Error,
97		{
98			value.parse::<i64>().map_err(serde::de::Error::custom)
99		}
100
101		fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E>
102		where
103			E: serde::de::Error,
104		{
105			Ok(value)
106		}
107
108		fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
109		where
110			E: serde::de::Error,
111		{
112			Ok(value as i64)
113		}
114	}
115
116	deserializer.deserialize_any(StringOrIntVisitor)
117}
118
119/// The `MapEntry` struct represents a key-value pair in a `StackItem::Map`.
120#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
121pub struct MapEntry {
122	key: StackItem,
123	value: StackItem,
124}
125
126impl StackItem {
127	/// The string value for `StackItem::Any`.
128	pub const ANY_VALUE: &'static str = "Any";
129
130	/// The string value for `StackItem::Pointer`.
131	pub const POINTER_VALUE: &'static str = "Pointer";
132
133	/// The string value for `StackItem::Boolean`.
134	pub const BOOLEAN_VALUE: &'static str = "Boolean";
135
136	/// The string value for `StackItem::Integer`.
137	pub const INTEGER_VALUE: &'static str = "Integer";
138
139	/// The string value for `StackItem::ByteString`.
140	pub const BYTE_STRING_VALUE: &'static str = "ByteString";
141
142	/// The string value for `StackItem::Buffer`.
143	pub const BUFFER_VALUE: &'static str = "Buffer";
144
145	/// The string value for `StackItem::Array`.
146	pub const ARRAY_VALUE: &'static str = "Array";
147
148	/// The string value for `StackItem::Struct`.
149	pub const STRUCT_VALUE: &'static str = "Struct";
150
151	/// The string value for `StackItem::Map`.
152	pub const MAP_VALUE: &'static str = "Map";
153
154	/// The string value for `StackItem::InteropInterface`.
155	pub const INTEROP_INTERFACE_VALUE: &'static str = "InteropInterface";
156
157	/// The byte value for `StackItem::Any`.
158	pub const ANY_BYTE: u8 = 0x00;
159
160	/// The byte value for `StackItem::Pointer`.
161	pub const POINTER_BYTE: u8 = 0x10;
162
163	/// The byte value for `StackItem::Boolean`.
164	pub const BOOLEAN_BYTE: u8 = 0x20;
165
166	/// The byte value for `StackItem::Integer`.
167	pub const INTEGER_BYTE: u8 = 0x21;
168
169	/// The byte value for `StackItem::ByteString`.
170	pub const BYTE_STRING_BYTE: u8 = 0x28;
171
172	/// The byte value for `StackItem::Buffer`.
173	pub const BUFFER_BYTE: u8 = 0x30;
174
175	/// The byte value for `StackItem::Array`.
176	pub const ARRAY_BYTE: u8 = 0x40;
177
178	/// The byte value for `StackItem::Struct`.
179	pub const STRUCT_BYTE: u8 = 0x41;
180
181	/// The byte value for `StackItem::Map`.
182	pub const MAP_BYTE: u8 = 0x48;
183
184	/// The byte value for `StackItem::InteropInterface`.
185	pub const INTEROP_INTERFACE_BYTE: u8 = 0x60;
186
187	pub fn new_byte_string(byte_array: Vec<u8>) -> Self {
188		let byte_string = base64::encode(byte_array);
189		StackItem::ByteString { value: byte_string }
190	}
191
192	/// Returns the boolean value of a `StackItem::Boolean` or `StackItem::Integer`.
193	pub fn as_bool(&self) -> Option<bool> {
194		match self {
195			StackItem::Boolean { value } => Some(*value),
196			StackItem::Integer { value } => Some(value != &0),
197			_ => None,
198		}
199	}
200
201	/// Returns the string value of a `StackItem::ByteString`, `StackItem::Buffer`, `StackItem::Integer`, or `StackItem::Boolean`.
202	pub fn as_string(&self) -> Option<String> {
203		match self {
204			StackItem::ByteString { value } | StackItem::Buffer { value } =>
205				Some(String::from_utf8_lossy(&base64::decode(value).unwrap()).to_string()),
206			StackItem::Integer { value } => Some(value.to_string()),
207			StackItem::Boolean { value } => Some(value.to_string()),
208			_ => None,
209		}
210	}
211
212	/// Returns the string representation of a `StackItem`.
213	pub fn to_string(&self) -> String {
214		match self {
215			StackItem::Any => "Any".to_string(),
216			StackItem::Pointer { value: pointer } => format!("Pointer{{value={}}}", pointer),
217			StackItem::Boolean { value: boolean } => format!("Boolean{{value={}}}", boolean),
218			StackItem::Integer { value: integer } => format!("Integer{{value={}}}", integer),
219			StackItem::ByteString { value: byteString } =>
220				format!("ByteString{{value={:?}}}", byteString),
221			StackItem::Buffer { value: buffer } => format!("Buffer{{value={:?}}}", buffer),
222			StackItem::Array { value: array } => {
223				let values = array.iter().map(StackItem::to_string).collect::<Vec<_>>().join(", ");
224				format!("Array{{value=[{}]}}", values)
225			},
226			StackItem::Struct { value: _struct } => {
227				let values =
228					_struct.iter().map(StackItem::to_string).collect::<Vec<_>>().join(", ");
229				format!("Struct{{value=[{}]}}", values)
230			},
231			StackItem::Map { value: map_value } => {
232				// Iterate over pairs of elements in the vector
233				// (assuming the vector has an even number of elements)
234				let entries = map_value
235					.iter()
236					.map(|entry| {
237						format!("{} -> {}", entry.key.to_string(), entry.value.to_string())
238					})
239					.collect::<Vec<_>>()
240					.join(", ");
241				format!("Map{{{{{}}}}}", entries)
242			},
243			StackItem::InteropInterface { id, interface } => {
244				format!("InteropInterface{{id={}, interface={}}}", id, interface)
245			},
246		}
247	}
248
249	/// Returns the byte representation of a `StackItem::ByteString`, `StackItem::Buffer`, or `StackItem::Integer`.
250	pub fn as_bytes(&self) -> Option<Vec<u8>> {
251		match self {
252			StackItem::ByteString { value } | StackItem::Buffer { value } =>
253			// Some(hex::decode(value).unwrap()),
254				Some(
255					base64::decode(value.trim_end())
256						.expect(&format!("Failed to decode the string: {}", value)),
257				),
258			//Some(value.trim_end().as_bytes().to_vec()),
259			StackItem::Integer { value } => {
260				let mut bytes = value.to_be_bytes().to_vec();
261				bytes.reverse();
262				Some(bytes)
263			},
264			_ => None,
265		}
266	}
267
268	/// Returns the array value of a `StackItem::Array` or `StackItem::Struct`.
269	pub fn as_array(&self) -> Option<Vec<StackItem>> {
270		match self {
271			StackItem::Array { value } | StackItem::Struct { value } => Some(value.clone()),
272			_ => None,
273		}
274	}
275
276	/// Returns the integer value of a `StackItem::Integer` or `StackItem::Boolean`.
277	pub fn as_int(&self) -> Option<i64> {
278		match self {
279			StackItem::Integer { value } => Some(*value),
280			StackItem::Boolean { value } => Some(if *value { 1 } else { 0 }),
281			StackItem::Pointer { value } => Some(*value),
282			_ => None,
283		}
284	}
285
286	/// Returns the map value of a `StackItem::Map`.
287	pub fn as_map(&self) -> Option<HashMap<StackItem, StackItem>> {
288		match self {
289			StackItem::Map { value } => {
290				let mut map = HashMap::new();
291				for entry in value {
292					map.insert(entry.key.clone(), entry.value.clone());
293				}
294				Some(map)
295			},
296			_ => None,
297		}
298	}
299
300	/// Returns the `Address` value of a `StackItem::ByteString` or `StackItem::Buffer`.
301	pub fn as_address(&self) -> Option<Address> {
302		self.as_bytes().and_then(|mut bytes| {
303			bytes.reverse();
304			Some(H160::from_slice(&bytes).to_address())
305		})
306	}
307
308	/// Returns the `Secp256r1PublicKey` value of a `StackItem::ByteString` or `StackItem::Buffer`.
309	pub fn as_public_key(&self) -> Option<Secp256r1PublicKey> {
310		self.as_bytes().and_then(|bytes| Secp256r1PublicKey::from_bytes(&bytes).ok())
311	}
312
313	/// Returns the `H160` value of a `StackItem::ByteString` or `StackItem::Buffer`.
314	pub fn as_hash160(&self) -> Option<H160> {
315		self.as_bytes().and_then(|bytes| Some(H160::from_slice(&bytes)))
316	}
317
318	/// Returns the `H256` value of a `StackItem::ByteString` or `StackItem::Buffer`.
319	pub fn as_hash256(&self) -> Option<H256> {
320		self.as_bytes().and_then(|bytes| Some(H256::from_slice(&bytes)))
321	}
322
323	pub fn as_interop(&self, interface_name: &str) -> Option<StackItem> {
324		match self {
325			StackItem::Integer { value } => Some(StackItem::InteropInterface {
326				id: value.to_string(),
327				interface: interface_name.to_string(),
328			}),
329			StackItem::Boolean { value } => Some(StackItem::InteropInterface {
330				id: value.to_string(),
331				interface: interface_name.to_string(),
332			}),
333			StackItem::ByteString { value } => Some(StackItem::InteropInterface {
334				id: value.to_string(),
335				interface: interface_name.to_string(),
336			}),
337			StackItem::Buffer { value } => Some(StackItem::InteropInterface {
338				id: value.to_string(),
339				interface: interface_name.to_string(),
340			}),
341			_ => None,
342		}
343	}
344
345	pub fn len(&self) -> Option<usize> {
346		match self {
347			StackItem::Array { value } | StackItem::Struct { value } => Some(value.len()),
348			_ => None,
349		}
350	}
351
352	pub fn is_empty(&self) -> Option<bool> {
353		self.len().map(|len| len == 0)
354	}
355
356	pub fn get(&self, index: usize) -> Option<StackItem> {
357		self.as_array().and_then(|arr| arr.get(index).cloned())
358	}
359
360	pub fn get_iterator_id(&self) -> Option<&String> {
361		if let StackItem::InteropInterface { id, .. } = self {
362			Some(id)
363		} else {
364			None
365		}
366	}
367
368	pub fn get_interface_name(&self) -> Option<&String> {
369		if let StackItem::InteropInterface { interface, .. } = self {
370			Some(interface)
371		} else {
372			None
373		}
374	}
375}
376
377impl From<String> for StackItem {
378	fn from(value: String) -> Self {
379		StackItem::ByteString { value }
380	}
381}
382
383impl From<H160> for StackItem {
384	fn from(value: H160) -> Self {
385		StackItem::ByteString { value: ToString::to_string(&value) }
386	}
387}
388
389impl From<u8> for StackItem {
390	fn from(value: u8) -> Self {
391		StackItem::Integer { value: value as i64 }
392	}
393}
394
395impl From<i8> for StackItem {
396	fn from(value: i8) -> Self {
397		StackItem::Integer { value: value as i64 }
398	}
399}
400
401impl From<u16> for StackItem {
402	fn from(value: u16) -> Self {
403		StackItem::Integer { value: value as i64 }
404	}
405}
406
407impl From<i16> for StackItem {
408	fn from(value: i16) -> Self {
409		StackItem::Integer { value: value as i64 }
410	}
411}
412
413impl From<u32> for StackItem {
414	fn from(value: u32) -> Self {
415		StackItem::Integer { value: value as i64 }
416	}
417}
418
419impl From<i32> for StackItem {
420	fn from(value: i32) -> Self {
421		StackItem::Integer { value: value as i64 }
422	}
423}
424
425impl From<u64> for StackItem {
426	fn from(value: u64) -> Self {
427		StackItem::Integer { value: value as i64 }
428	}
429}
430impl From<&str> for StackItem {
431	fn from(value: &str) -> Self {
432		StackItem::ByteString { value: value.to_string() }
433	}
434}