1#![allow(unused)]
2use crate::constants::*;
3use crate::crypto::sign_ed25519::{PublicKey, Signature};
4use crate::primitives::{
5 asset::{Asset, ItemAsset, TokenAmount},
6 druid::{DdeValues, DruidExpectation},
7};
8use crate::script::lang::Script;
9use crate::script::{OpCodes, StackEntry};
10use crate::utils::is_valid_amount;
11use bincode::serialize;
12use bytes::Bytes;
13use serde::{Deserialize, Serialize};
14use std::fmt;
15
16#[derive(Debug, Clone, Serialize, Deserialize)]
17pub enum GenesisTxHashSpec {
18 Create,
19 Default,
20 }
22
23impl GenesisTxHashSpec {
24 pub fn get_genesis_hash(&self) -> Option<String> {
25 match self {
26 GenesisTxHashSpec::Create => None, GenesisTxHashSpec::Default => Some(ITEM_DEFAULT_DRS_TX_HASH.to_string()),
28 }
29 }
30}
31
32#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
34pub struct TxConstructor {
35 pub previous_out: OutPoint,
36 pub signatures: Vec<Signature>,
37 pub pub_keys: Vec<PublicKey>,
38 pub address_version: Option<u64>,
39}
40
41#[derive(Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd, Serialize, Deserialize)]
43pub struct OutPoint {
44 pub t_hash: String,
45 pub n: i32,
46}
47
48impl fmt::Display for OutPoint {
49 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
50 write!(f, "t_hash:{}-n:{}", self.t_hash, self.n)
51 }
52}
53
54impl OutPoint {
55 pub fn new(t_hash: String, n: i32) -> OutPoint {
57 OutPoint { t_hash, n }
58 }
59}
60
61impl Default for OutPoint {
62 fn default() -> Self {
63 Self::new(String::new(), 0)
64 }
65}
66
67#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
71pub struct TxIn {
72 pub previous_out: Option<OutPoint>,
73 pub script_signature: Script,
74}
75
76impl Default for TxIn {
77 fn default() -> Self {
78 Self::new()
79 }
80}
81
82impl TxIn {
83 pub fn new() -> TxIn {
85 let mut script_sig = Script::new();
86 script_sig.stack.push(StackEntry::Op(OpCodes::OP_0));
87
88 TxIn {
89 previous_out: None,
90 script_signature: script_sig,
91 }
92 }
93
94 pub fn new_from_script(script_sig: Script) -> TxIn {
100 TxIn {
101 previous_out: None,
102 script_signature: script_sig,
103 }
104 }
105
106 pub fn new_from_input(previous_out: OutPoint, script_sig: Script) -> TxIn {
113 TxIn {
114 previous_out: Some(previous_out),
115 script_signature: script_sig,
116 }
117 }
118}
119
120#[derive(Default, Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
124pub struct TxOut {
125 pub value: Asset,
126 pub locktime: u64,
127 pub script_public_key: Option<String>,
128}
129
130impl TxOut {
131 pub fn new() -> TxOut {
133 Default::default()
134 }
135
136 pub fn new_token_amount(
137 to_address: String,
138 amount: TokenAmount,
139 locktime: Option<u64>,
140 ) -> TxOut {
141 TxOut {
142 value: Asset::Token(amount),
143 locktime: locktime.unwrap_or(ZERO as u64),
144 script_public_key: Some(to_address),
145 }
146 }
147
148 pub fn new_item_amount(to_address: String, item: ItemAsset, locktime: Option<u64>) -> TxOut {
152 TxOut {
153 value: Asset::Item(item),
154 locktime: locktime.unwrap_or(ZERO as u64),
155 script_public_key: Some(to_address),
156 }
157 }
158
159 pub fn new_asset(to_address: String, asset: Asset, locktime: Option<u64>) -> TxOut {
161 match asset {
162 Asset::Token(amount) => TxOut::new_token_amount(to_address, amount, locktime),
163 Asset::Item(item) => TxOut::new_item_amount(to_address, item, locktime),
164 _ => panic!("Cannot create TxOut for asset of type {:?}", asset),
165 }
166 }
167
168 pub fn is_p2sh_tx_out(&self) -> bool {
170 if let Some(pk) = &self.script_public_key {
171 let pk_bytes = pk.as_bytes();
172 return pk_bytes[0] == P2SH_PREPEND;
173 }
174
175 false
176 }
177}
178
179#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
182pub struct Transaction {
183 pub inputs: Vec<TxIn>,
184 pub outputs: Vec<TxOut>,
185 pub version: usize,
186 pub fees: Vec<TxOut>,
187 pub druid_info: Option<DdeValues>,
188}
189
190impl Default for Transaction {
191 fn default() -> Self {
192 Self::new()
193 }
194}
195
196impl Transaction {
197 pub fn new() -> Transaction {
199 Transaction {
200 inputs: Vec::new(),
201 outputs: Vec::new(),
202 fees: Vec::new(),
203 version: NETWORK_VERSION as usize,
204 druid_info: None,
205 }
206 }
207
208 pub fn get_total_size(&self) -> usize {
210 let bytes = match serialize(self) {
211 Ok(bytes) => bytes,
212 Err(_) => vec![],
213 };
214 bytes.len()
215 }
216
217 fn get_create_asset(&self) -> Option<&Asset> {
219 let is_create = self.inputs.len() == 1
220 && self.inputs[0].previous_out.is_none()
221 && self.outputs.len() == 1;
222
223 is_create.then(|| &self.outputs[0].value)
224 }
225
226 pub fn is_coinbase(&self) -> bool {
228 self.get_create_asset()
229 .map(|a| a.is_token())
230 .unwrap_or_default()
231 }
232
233 pub fn is_create_tx(&self) -> bool {
235 self.get_create_asset()
236 .map(|a| !a.is_token())
237 .unwrap_or_default()
238 }
239
240 pub fn is_p2sh_tx(&self) -> bool {
242 if self.outputs.len() != 1 {
243 return false;
244 }
245
246 if let Some(pk) = &self.outputs[0].script_public_key {
247 let pk_bytes = pk.as_bytes();
248 return pk_bytes[0] == P2SH_PREPEND;
249 }
250
251 false
252 }
253}