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			},
207			StackItem::Integer { value } => Some(value.to_string()),
208			StackItem::Boolean { value } => Some(value.to_string()),
209			_ => None,
210		}
211	}
212
213	/// Returns the string representation of a `StackItem`.
214	pub fn to_string(&self) -> String {
215		match self {
216			StackItem::Any => "Any".to_string(),
217			StackItem::Pointer { value: pointer } => format!("Pointer{{value={}}}", pointer),
218			StackItem::Boolean { value: boolean } => format!("Boolean{{value={}}}", boolean),
219			StackItem::Integer { value: integer } => format!("Integer{{value={}}}", integer),
220			StackItem::ByteString { value: byteString } => {
221				format!("ByteString{{value={:?}}}", byteString)
222			},
223			StackItem::Buffer { value: buffer } => format!("Buffer{{value={:?}}}", buffer),
224			StackItem::Array { value: array } => {
225				let values = array.iter().map(StackItem::to_string).collect::<Vec<_>>().join(", ");
226				format!("Array{{value=[{}]}}", values)
227			},
228			StackItem::Struct { value: _struct } => {
229				let values =
230					_struct.iter().map(StackItem::to_string).collect::<Vec<_>>().join(", ");
231				format!("Struct{{value=[{}]}}", values)
232			},
233			StackItem::Map { value: map_value } => {
234				// Iterate over pairs of elements in the vector
235				// (assuming the vector has an even number of elements)
236				let entries = map_value
237					.iter()
238					.map(|entry| {
239						format!("{} -> {}", entry.key.to_string(), entry.value.to_string())
240					})
241					.collect::<Vec<_>>()
242					.join(", ");
243				format!("Map{{{{{}}}}}", entries)
244			},
245			StackItem::InteropInterface { id, interface } => {
246				format!("InteropInterface{{id={}, interface={}}}", id, interface)
247			},
248		}
249	}
250
251	/// Returns the byte representation of a `StackItem::ByteString`, `StackItem::Buffer`, or `StackItem::Integer`.
252	pub fn as_bytes(&self) -> Option<Vec<u8>> {
253		match self {
254			StackItem::ByteString { value } | StackItem::Buffer { value } =>
255			// Some(hex::decode(value).unwrap()),
256			{
257				Some(
258					base64::decode(value.trim_end())
259						.expect(&format!("Failed to decode the string: {}", value)),
260				)
261			},
262			//Some(value.trim_end().as_bytes().to_vec()),
263			StackItem::Integer { value } => {
264				let mut bytes = value.to_be_bytes().to_vec();
265				bytes.reverse();
266				Some(bytes)
267			},
268			_ => None,
269		}
270	}
271
272	/// Returns the array value of a `StackItem::Array` or `StackItem::Struct`.
273	pub fn as_array(&self) -> Option<Vec<StackItem>> {
274		match self {
275			StackItem::Array { value } | StackItem::Struct { value } => Some(value.clone()),
276			_ => None,
277		}
278	}
279
280	/// Returns the integer value of a `StackItem::Integer` or `StackItem::Boolean`.
281	pub fn as_int(&self) -> Option<i64> {
282		match self {
283			StackItem::Integer { value } => Some(*value),
284			StackItem::Boolean { value } => Some(if *value { 1 } else { 0 }),
285			StackItem::Pointer { value } => Some(*value),
286			_ => None,
287		}
288	}
289
290	/// Returns the map value of a `StackItem::Map`.
291	pub fn as_map(&self) -> Option<HashMap<StackItem, StackItem>> {
292		match self {
293			StackItem::Map { value } => {
294				let mut map = HashMap::new();
295				for entry in value {
296					map.insert(entry.key.clone(), entry.value.clone());
297				}
298				Some(map)
299			},
300			_ => None,
301		}
302	}
303
304	/// Returns the `Address` value of a `StackItem::ByteString` or `StackItem::Buffer`.
305	pub fn as_address(&self) -> Option<Address> {
306		self.as_bytes().and_then(|mut bytes| {
307			bytes.reverse();
308			Some(H160::from_slice(&bytes).to_address())
309		})
310	}
311
312	/// Returns the `Secp256r1PublicKey` value of a `StackItem::ByteString` or `StackItem::Buffer`.
313	pub fn as_public_key(&self) -> Option<Secp256r1PublicKey> {
314		self.as_bytes().and_then(|bytes| Secp256r1PublicKey::from_bytes(&bytes).ok())
315	}
316
317	/// Returns the `H160` value of a `StackItem::ByteString` or `StackItem::Buffer`.
318	pub fn as_hash160(&self) -> Option<H160> {
319		self.as_bytes().and_then(|bytes| Some(H160::from_slice(&bytes)))
320	}
321
322	/// Returns the `H256` value of a `StackItem::ByteString` or `StackItem::Buffer`.
323	pub fn as_hash256(&self) -> Option<H256> {
324		self.as_bytes().and_then(|bytes| Some(H256::from_slice(&bytes)))
325	}
326
327	pub fn as_interop(&self, interface_name: &str) -> Option<StackItem> {
328		match self {
329			StackItem::Integer { value } => Some(StackItem::InteropInterface {
330				id: value.to_string(),
331				interface: interface_name.to_string(),
332			}),
333			StackItem::Boolean { value } => Some(StackItem::InteropInterface {
334				id: value.to_string(),
335				interface: interface_name.to_string(),
336			}),
337			StackItem::ByteString { value } => Some(StackItem::InteropInterface {
338				id: value.to_string(),
339				interface: interface_name.to_string(),
340			}),
341			StackItem::Buffer { value } => Some(StackItem::InteropInterface {
342				id: value.to_string(),
343				interface: interface_name.to_string(),
344			}),
345			_ => None,
346		}
347	}
348
349	pub fn len(&self) -> Option<usize> {
350		match self {
351			StackItem::Array { value } | StackItem::Struct { value } => Some(value.len()),
352			_ => None,
353		}
354	}
355
356	pub fn is_empty(&self) -> Option<bool> {
357		self.len().map(|len| len == 0)
358	}
359
360	pub fn get(&self, index: usize) -> Option<StackItem> {
361		self.as_array().and_then(|arr| arr.get(index).cloned())
362	}
363
364	pub fn get_iterator_id(&self) -> Option<&String> {
365		if let StackItem::InteropInterface { id, .. } = self {
366			Some(id)
367		} else {
368			None
369		}
370	}
371
372	pub fn get_interface_name(&self) -> Option<&String> {
373		if let StackItem::InteropInterface { interface, .. } = self {
374			Some(interface)
375		} else {
376			None
377		}
378	}
379}
380
381impl From<String> for StackItem {
382	fn from(value: String) -> Self {
383		StackItem::ByteString { value }
384	}
385}
386
387impl From<H160> for StackItem {
388	fn from(value: H160) -> Self {
389		StackItem::ByteString { value: ToString::to_string(&value) }
390	}
391}
392
393impl From<u8> for StackItem {
394	fn from(value: u8) -> Self {
395		StackItem::Integer { value: value as i64 }
396	}
397}
398
399impl From<i8> for StackItem {
400	fn from(value: i8) -> Self {
401		StackItem::Integer { value: value as i64 }
402	}
403}
404
405impl From<u16> for StackItem {
406	fn from(value: u16) -> Self {
407		StackItem::Integer { value: value as i64 }
408	}
409}
410
411impl From<i16> for StackItem {
412	fn from(value: i16) -> Self {
413		StackItem::Integer { value: value as i64 }
414	}
415}
416
417impl From<u32> for StackItem {
418	fn from(value: u32) -> Self {
419		StackItem::Integer { value: value as i64 }
420	}
421}
422
423impl From<i32> for StackItem {
424	fn from(value: i32) -> Self {
425		StackItem::Integer { value: value as i64 }
426	}
427}
428
429impl From<u64> for StackItem {
430	fn from(value: u64) -> Self {
431		StackItem::Integer { value: value as i64 }
432	}
433}
434impl From<&str> for StackItem {
435	fn from(value: &str) -> Self {
436		StackItem::ByteString { value: value.to_string() }
437	}
438}