neo3/neo_protocol/responses/
neo_application_log.rs1use 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}