neo3/neo_protocol/responses/
neo_application_log.rs

1use primitive_types::H256;
2use serde::{Deserialize, Serialize};
3
4use crate::{neo_protocol::LogNotification, TypeError};
5use neo3::prelude::{deserialize_h256, serialize_h256, StackItem, VMState};
6
7#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Hash, Debug)]
8pub struct ApplicationLog {
9	#[serde(rename = "txid")]
10	#[serde(serialize_with = "serialize_h256")]
11	#[serde(deserialize_with = "deserialize_h256")]
12	pub transaction_id: H256,
13	#[serde(default)]
14	pub executions: Vec<Execution>,
15}
16
17impl Default for ApplicationLog {
18	fn default() -> Self {
19		Self { transaction_id: H256::zero(), executions: vec![] }
20	}
21}
22
23impl ApplicationLog {
24	pub fn get_first_execution(&self) -> Result<&Execution, TypeError> {
25		if self.executions.is_empty() {
26			return Err(TypeError::IndexOutOfBounds(
27				"This transaction does not have any executions.".to_string(),
28			));
29		}
30		self.get_execution(0)
31	}
32
33	pub fn get_execution(&self, index: usize) -> Result<&Execution, TypeError> {
34		if index >= self.executions.len() {
35			return Err(TypeError::IndexOutOfBounds(format!(
36				"This transaction has only {} executions.",
37				self.executions.len()
38			)));
39		}
40		Ok(&self.executions[index])
41	}
42}
43
44#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Hash, Debug)]
45pub struct Execution {
46	pub trigger: String,
47	#[serde(rename = "vmstate")]
48	pub state: VMState,
49	pub exception: Option<String>,
50	#[serde(rename = "gasconsumed")]
51	pub gas_consumed: String,
52	#[serde(default)]
53	pub stack: Vec<StackItem>,
54	#[serde(default)]
55	pub notifications: Vec<LogNotification>,
56}
57
58impl Execution {
59	pub fn get_first_stack_item(&self) -> Result<&StackItem, TypeError> {
60		if self.stack.is_empty() {
61			return Err(TypeError::IndexOutOfBounds(
62                "The stack is empty. This means that no items were left on the NeoVM stack after this execution."
63                    .to_string(),
64            ));
65		}
66		self.get_stack_item(0)
67	}
68
69	pub fn get_stack_item(&self, index: usize) -> Result<&StackItem, TypeError> {
70		if index >= self.stack.len() {
71			return Err(TypeError::IndexOutOfBounds(format!(
72				"There were only {} items left on the NeoVM stack after this execution.",
73				self.stack.len()
74			)));
75		}
76		Ok(&self.stack[index])
77	}
78
79	pub fn get_first_notification(&self) -> Result<&LogNotification, TypeError> {
80		if self.notifications.is_empty() {
81			return Err(TypeError::IndexOutOfBounds(
82				"This execution did not send any notifications.".to_string(),
83			));
84		}
85		self.get_notification(0)
86	}
87
88	pub fn get_notification(&self, index: usize) -> Result<&LogNotification, TypeError> {
89		if index >= self.notifications.len() {
90			return Err(TypeError::IndexOutOfBounds(format!(
91				"This execution only sent {} notifications.",
92				self.notifications.len()
93			)));
94		}
95		Ok(&self.notifications[index])
96	}
97}
98
99impl Default for Execution {
100	fn default() -> Self {
101		Self {
102			trigger: "".to_string(),
103			state: VMState::Halt,
104			exception: None,
105			gas_consumed: "0".to_string(),
106			stack: vec![],
107			notifications: vec![],
108		}
109	}
110}