neo3/neo_protocol/responses/
reponse_transaction.rs

1use std::{
2	hash::{Hash, Hasher},
3	str::FromStr,
4};
5
6use super::{RTransactionSigner, TransactionAttributeEnum};
7use crate::{neo_clients::JsonRpcProvider, neo_protocol::NeoWitness, TypeError};
8use futures_util::TryFutureExt;
9use getset::{CopyGetters, Getters, MutGetters, Setters};
10use neo3::VMState;
11use primitive_types::{H256, U256};
12use serde::{Deserialize, Deserializer, Serialize};
13use serde_json::Value;
14use serde_with::__private__::DeError;
15
16#[derive(Serialize, Deserialize, Getters, Setters, MutGetters, CopyGetters, Debug, Clone)]
17pub struct RTransaction {
18	#[serde(rename = "hash")]
19	#[getset(get = "pub", set = "pub")]
20	pub hash: H256,
21
22	#[serde(rename = "size")]
23	#[getset(get = "pub", set = "pub")]
24	pub size: u64,
25
26	#[serde(rename = "version")]
27	#[getset(get = "pub", set = "pub")]
28	pub version: u8,
29
30	#[serde(rename = "nonce")]
31	#[getset(get = "pub", set = "pub")]
32	pub nonce: u64,
33
34	#[serde(rename = "sender")]
35	#[getset(get = "pub", set = "pub")]
36	pub sender: String,
37
38	#[serde(rename = "sysfee")]
39	#[getset(get = "pub", set = "pub")]
40	pub sys_fee: String,
41
42	#[serde(rename = "netfee")]
43	#[getset(get = "pub", set = "pub")]
44	pub net_fee: String,
45
46	#[serde(rename = "validuntilblock")]
47	#[getset(get = "pub", set = "pub")]
48	pub valid_until_block: u64,
49
50	#[serde(rename = "signers", default)]
51	#[getset(get = "pub", set = "pub")]
52	pub signers: Vec<RTransactionSigner>,
53
54	#[serde(rename = "attributes", default)]
55	#[getset(get = "pub", set = "pub")]
56	pub attributes: Vec<TransactionAttributeEnum>,
57
58	#[serde(rename = "script")]
59	#[getset(get = "pub", set = "pub")]
60	pub script: String,
61
62	#[serde(rename = "witnesses", default)]
63	#[getset(get = "pub", set = "pub")]
64	pub witnesses: Vec<NeoWitness>,
65
66	#[serde(rename = "blockhash", default)]
67	#[getset(get = "pub", set = "pub")]
68	pub block_hash: H256,
69
70	#[serde(rename = "confirmations", default)]
71	#[getset(get = "pub", set = "pub")]
72	pub confirmations: i32,
73
74	#[serde(rename = "blocktime", default)]
75	#[getset(get = "pub", set = "pub")]
76	pub block_time: i64,
77
78	#[serde(rename = "vmstate", default)]
79	#[getset(get = "pub", set = "pub")]
80	pub vmstate: VMState,
81}
82
83impl RTransaction {
84	pub fn new(
85		hash: H256,
86		size: u64,
87		version: u8,
88		nonce: u64,
89		sender: String,
90		sys_fee: String,
91		net_fee: String,
92		valid_until_block: u64,
93		signers: Vec<RTransactionSigner>,
94		attributes: Vec<TransactionAttributeEnum>,
95		script: String,
96		witnesses: Vec<NeoWitness>,
97	) -> Self {
98		Self {
99			hash,
100			size,
101			version,
102			nonce,
103			sender,
104			sys_fee,
105			net_fee,
106			valid_until_block,
107			signers,
108			attributes,
109			script,
110			witnesses,
111			block_hash: Default::default(),
112			confirmations: Default::default(),
113			block_time: Default::default(),
114			vmstate: Default::default(),
115		}
116	}
117
118	pub fn get_first_signer(&self) -> Result<&RTransactionSigner, TypeError> {
119		if self.signers.is_empty() {
120			return Err(TypeError::IndexOutOfBounds(
121				"This transaction does not have any signers. It might be malformed, since every transaction requires at least one signer.".to_string(),
122			));
123		}
124		self.get_signer(0)
125	}
126
127	pub fn get_signer(&self, index: usize) -> Result<&RTransactionSigner, TypeError> {
128		if index >= self.signers.len() {
129			return Err(TypeError::IndexOutOfBounds(format!(
130				"This transaction only has {} signers.",
131				self.signers.len()
132			)));
133		}
134		Ok(&self.signers[index])
135	}
136
137	pub fn get_first_attribute(&self) -> Result<&TransactionAttributeEnum, TypeError> {
138		if self.attributes.is_empty() {
139			return Err(TypeError::IndexOutOfBounds(
140				"This transaction does not have any attributes.".to_string(),
141			));
142		}
143		self.get_attribute(0)
144	}
145
146	pub fn get_attribute(&self, index: usize) -> Result<&TransactionAttributeEnum, TypeError> {
147		if index >= self.attributes.len() {
148			return Err(TypeError::IndexOutOfBounds(format!(
149				"This transaction only has {} attributes. Tried to access index {}.",
150				self.attributes.len(),
151				index
152			)));
153		}
154		Ok(&self.attributes[index])
155	}
156}
157
158// Production-ready RTransaction uses derive macros for proper deserialization
159// Professional implementation with comprehensive transaction field handling
160
161impl Eq for RTransaction {}
162
163impl PartialEq for RTransaction {
164	fn eq(&self, other: &Self) -> bool {
165		self.size == other.size
166			&& self.version == other.version
167			&& self.hash == other.hash
168			&& self.nonce == other.nonce
169			&& self.sender == other.sender
170			&& self.sys_fee == other.sys_fee
171			&& self.net_fee == other.net_fee
172			&& self.valid_until_block == other.valid_until_block
173			&& self.signers == other.signers
174			&& self.attributes == other.attributes
175			&& self.script == other.script
176			&& self.witnesses == other.witnesses
177			&& self.block_hash == other.block_hash
178			&& self.confirmations == other.confirmations
179			&& self.block_time == other.block_time
180			&& self.vmstate == other.vmstate
181	}
182}
183
184// impl PartialEq for Transaction {
185// 	fn eq(&self, other: &Self) -> bool {
186// 		self.to_array() == other.to_array()
187// 	}
188// }