1use crate::constants::{DECIMAL_MULTIPLIER, MAX_COIN_SUPPLY};
2use crate::helpers::with_metadata_hashable::{WithMetadataHashable, WithMetadataHashableFields};
3use crate::proto_serde::ProtoHashable;
4use crate::structs::TransactionType;
5use crate::structs::{Address, CurrencyAmount, ErrorInfo, ExternalTransactionId, FloatingUtxoId, Hash, HashType, Input, NetworkEnvironment, NodeMetadata, Observation, ObservationProof, Output, OutputType, PoWProof, PortfolioRequest, ProductId, Proof, PublicKey, StakeDeposit, StakeRequest, StakeWithdrawal, StandardContractType, StandardData, StandardRequest, StandardResponse, StructMetadata, SupportedCurrency, SwapFulfillment, SwapRequest, Transaction, TransactionOptions, TypedValue, UtxoEntry, UtxoId};
6use crate::{bytes_data, error_info, structs, ErrorInfoContext, HashClear, PeerMetadata, RgResult, SafeOption};
7use itertools::Itertools;
8use serde::{Deserialize, Serialize};
9use std::collections::{HashMap, HashSet};
10use std::str::FromStr;
11
12pub const MAX_TRANSACTION_MESSAGE_SIZE: usize = 40;
13
14
15impl UtxoId {
16
17 pub fn new(hash: &Hash, output_index: i64) -> Self {
18 Self {
19 transaction_hash: Some(hash.clone()),
20 output_index,
21 }
22 }
23 pub fn format_str(&self) -> String {
24 format!("UtxoId: {} output: {}", self.transaction_hash.clone().expect("").hex(), self.output_index)
25 }
26
27 pub fn utxo_id_vec(&self) -> Vec<u8> {
29 let mut merged: Vec<u8> = vec![];
30 merged.extend(self.transaction_hash.clone().expect("hash").vec());
31 merged.extend(self.output_index.to_le_bytes().to_vec());
32 merged
33 }
34
35 pub fn as_hash(&self) -> Hash {
36 let mut h = Hash::new_direct_transaction(&self.utxo_id_vec());
37 h.hash_type = HashType::UtxoId as i32;
38 h
39 }
40 pub fn utxo_id_hex(&self) -> String {
41 hex::encode(self.utxo_id_vec())
42 }
43}
44
45
46pub fn amount_to_raw_amount(redgold: u64) -> u64 {
47 assert!(redgold <= MAX_COIN_SUPPLY as u64);
48 return redgold * (DECIMAL_MULTIPLIER as u64);
49}
50
51trait BalanceConversion {
52 fn rounded_float(&self) -> f64;
53}
54
55impl BalanceConversion for i64 {
56 fn rounded_float(&self) -> f64 {
57 rounded_balance_i64(*self)
58 }
59}
60
61pub fn rounded_balance(redgold_amount: u64) -> f64 {
62 (redgold_amount as f64) / (DECIMAL_MULTIPLIER as f64)
63}
64
65pub fn rounded_balance_i64(redgold_amount: i64) -> f64 {
66 (redgold_amount as f64) / (DECIMAL_MULTIPLIER as f64)
67}
68
69impl WithMetadataHashableFields for Transaction {
70 fn struct_metadata_opt(&mut self) -> Option<&mut StructMetadata> {
71 self.struct_metadata.as_mut()
72 }
73
74 fn struct_metadata_opt_ref(&self) -> Option<&StructMetadata> {
75 self.struct_metadata.as_ref()
76 }
77}
78
79impl HashClear for Input {
80 fn hash_clear(&mut self) {
81 self.address = None;
82 self.output = None;
83 }
84}
85
86impl HashClear for Transaction {
87 fn hash_clear(&mut self) {
88 for x in self.inputs.iter_mut() {
90 x.hash_clear();
91 }
92 if let Some(s) = self.struct_metadata_opt() {
93 s.hash_clear();
94 }
95 }
96}
97
98#[derive(PartialEq, PartialOrd, Debug, Clone, serde::Serialize, serde::Deserialize)]
99pub struct AddressBalance {
100 pub address: String,
101 pub rounded_balance: f64,
102}
103
104
105impl Transaction {
106
107 pub fn combine_multisig_proofs(&mut self, other: &Transaction, address: &Address) -> RgResult<Transaction> {
108 let mut updated = self.clone();
109 for (idx, input) in updated.inputs.iter_mut().enumerate() {
110 let other_input = other.inputs.get(idx).ok_msg("Missing input")?;
111 for proof in other_input.proof.iter() {
112 if input.proof.iter().any(|p| p.public_key == proof.public_key) {
113 continue;
114 } else {
115 input.proof.push(proof.clone());
116 }
117 }
118 }
119 Ok(updated)
120 }
121
122 pub fn with_pow(mut self) -> RgResult<Self> {
123 let hash = self.signable_hash();
124 let proof = PoWProof::from_hash_sha3_256(&hash, 1)?;
125 let opts = self.options.as_mut().expect("");
126 opts.pow_proof = Some(proof);
127 Ok(self)
128 }
129
130 pub fn signable_hash_or(&self) -> Hash {
131 self.struct_metadata_opt_ref()
132 .and_then(|s| s.signable_hash.clone()) .unwrap_or(self.signable_hash())
134 }
135
136 pub fn sponsored_time(&self) -> RgResult<i64> {
137 let t = self.options()?.time_sponsor.safe_get_msg("Missing sponsored time")?.time;
138 Ok(t)
139 }
140
141 pub fn transaction_type(&self) -> RgResult<structs::TransactionType> {
142 let t = self.options()?.transaction_type;
143 TransactionType::from_i32(t).ok_msg("Invalid transaction type")
144 }
145
146 pub fn is_metadata_or_obs(&self) -> bool {
147 self.outputs.iter().all(|o| o.is_metadata() || o.observation().is_ok())
148 }
149 pub fn validate_network(&self, network: &NetworkEnvironment) -> RgResult<()> {
150 let opts = self.options()?;
151 let net = opts.network_type.safe_get_msg("Missing network type")?;
152 let net = NetworkEnvironment::from_i32(net.clone());
153 let net = net.safe_get_msg("Invalid network type")?;
154 if net != network {
155 Err(ErrorInfo::error_info("Invalid network type"))?
156 }
157 Ok(())
158 }
159 pub fn network(&self) -> RgResult<NetworkEnvironment> {
160 let opts = self.options()?;
161 let net = opts.network_type.safe_get_msg("Missing network type")?;
162 let net = NetworkEnvironment::from_i32(net.clone());
163 let net = net.safe_get_msg("Invalid network type")?;
164 Ok(net.clone())
165 }
166
167 pub fn is_test(&self) -> bool {
168 self.options.as_ref().and_then(|o| o.is_test).unwrap_or(false)
169 }
170 pub fn input_of(&self, f: &UtxoId) -> Option<&Input> {
173 self.inputs.iter().find(|i| i.utxo_id.as_ref().filter(|&u| u == f).is_some())
174 }
175
176 pub fn is_swap(&self) -> bool {
177 self.outputs.iter().filter(|o| o.is_swap()).count() > 0
178 }
179
180 pub fn is_swap_fulfillment(&self) -> bool {
181 self.outputs.iter().filter(|o| o.is_swap_fulfillment()).count() > 0
182 }
183
184 pub fn swap_fulfillment(&self) -> Option<&SwapFulfillment> {
185 self.outputs.iter().filter_map(|o| o.swap_fulfillment()).next()
186 }
187
188 pub fn swap_fulfillment_amount_and_destination_and_origin(&self) -> Option<(&SwapFulfillment, &CurrencyAmount, &Address, Address)> {
189 self.first_input_address().and_then(|origin|
190 self.outputs.iter().filter_map(|o| {
191 o.swap_fulfillment().and_then(|f| {
192 o.opt_amount_typed_ref().and_then(|a|
193 o.address.as_ref().map(|addr| (f, a, addr, origin.clone()))
194 )
195 })
196 }).next()
197 )
198 }
199
200 pub fn output_data(&self) -> impl Iterator<Item=&StandardData> {
201 self.outputs.iter().filter_map(|o| o.data.as_ref())
202 }
203
204 pub fn output_request(&self) -> impl Iterator<Item=&StandardRequest> {
205 self.output_data().map(|d| d.standard_request.as_ref()).flatten()
206 }
207
208 pub fn output_response(&self) -> impl Iterator<Item=&StandardResponse> {
209 self.output_data().map(|d| d.standard_response.as_ref()).flatten()
210 }
211
212 pub fn swap_request(&self) -> Option<&SwapRequest> {
213 self.output_request().filter_map(|d| d.swap_request.as_ref()).next()
214 }
215
216 pub fn swap_request_and_amount_and_party_address(&self) -> Option<(&SwapRequest, &CurrencyAmount, &Address)> {
217 self.outputs.iter().filter_map(|o| {
218 o.opt_amount_typed_ref()
219 .and_then(|a|
220 o.address.as_ref()
221 .and_then(|addr| o.swap_request()
222 .map(|r| (r, a, addr))
223 ))
224 }).next()
225 }
226
227 pub fn swap_destination(&self) -> Option<&Address> {
228 self.swap_request().and_then(|r| r.destination.as_ref())
229 }
230
231 pub fn stake_request(&self) -> Option<&StakeRequest> {
232 self.output_request().filter_map(|d| d.stake_request.as_ref()).next()
233 }
234
235 pub fn stake_deposit_request(&self) -> Option<&StakeDeposit> {
236 self.stake_request().and_then(|d| d.deposit.as_ref())
237 }
238
239 pub fn stake_withdrawal_request(&self) -> Option<&StakeWithdrawal> {
240 self.stake_request().and_then(|d| d.withdrawal.as_ref())
241 }
242
243 pub fn stake_withdrawal_fulfillments(&self) -> impl Iterator<Item =&structs::StakeWithdrawalFulfillment> {
244 self.output_response().flat_map(|r| r.stake_withdrawal_fulfillment.as_ref())
245 }
246
247 pub fn stake_deposit_destination(&self) -> Option<&Address> {
248 self.stake_deposit_request()
249 .and_then(|d| d.deposit.as_ref())
250 .and_then(|d| d.address.as_ref())
251 }
252
253 pub fn stake_destination(&self) -> Option<&Address> {
254 self.stake_deposit_destination().or(self.stake_withdrawal_destination())
255 }
256
257 pub fn stake_withdrawal_destination(&self) -> Option<&Address> {
258 self.stake_withdrawal_request()
259 .and_then(|d| d.destination.as_ref())
260 }
261
262 pub fn swap_destination_currency(&self) -> Option<SupportedCurrency> {
263 self.swap_destination().map(|a| a.currency_or())
264 }
265
266 pub fn external_destination_currency(&self) -> Option<SupportedCurrency> {
267 self.swap_destination().or(self.stake_destination())
268 .map(|d| d.clone().mark_external().clone())
269 .map(|a| a.currency_or())
270 }
271
272 pub fn is_stake(&self) -> bool {
273 self.outputs.iter().filter(|o| o.is_stake()).count() > 0
274 }
275
276 pub fn has_portfolio_request(&self) -> bool {
277 self.portfolio_request().is_some()
278 }
279
280 pub fn portfolio_request(&self) -> Option<&PortfolioRequest> {
281 self.outputs.iter()
282 .filter_map(|o| o.request())
283 .filter_map(|r| r.portfolio_request.as_ref())
284 .next()
285 }
286
287
288 pub fn is_metadata(&self) -> bool {
289 self.outputs.iter().filter(|o| o.is_metadata()).count() > 0
290 }
291 pub fn is_request(&self) -> bool {
292 self.outputs.iter().filter(|o| o.is_request()).count() > 0
293 }
294 pub fn is_deploy(&self) -> bool {
295 self.outputs.iter().filter(|o| o.is_deploy()).count() > 0
296 }
297
298 pub fn observation_output_index(&self) -> RgResult<i64> {
299 self.outputs.iter().enumerate().find(|(_i, o)| o.observation().is_ok()
300 ).map(|o| o.0 as i64).ok_or(error_info("Missing observation output"))
301 }
302
303 pub fn observation_as_utxo_id(&self) -> RgResult<UtxoId> {
304 let o = self.observation_output_index();
305 Ok(UtxoId {
306 transaction_hash: Some(self.hash_or()),
307 output_index: o?,
308 })
309 }
310
311 pub fn observation_output(&self) -> RgResult<&Output> {
312 let o = self.observation_output_index()?;
313 let option = self.outputs.get(o as usize);
314 option.safe_get_msg("Missing observation output").cloned()
315 }
316
317 pub fn observation_output_as(&self) -> RgResult<UtxoEntry> {
318 let idx = self.observation_output_index()?;
319 let o = self.observation_output()?;
320 let u = o.utxo_entry(&self.hash_or(), idx as i64, self.time()?.clone());
321 Ok(u)
322 }
323
324 pub fn observation(&self) -> RgResult<&Observation> {
325 let mut map = self.outputs.iter().filter_map(|o| o.observation().ok());
326 let option = map.next();
327 option.ok_or(error_info("Missing observation"))
328 }
329
330 pub fn observation_proof(&self) -> RgResult<&Proof> {
331 let o = self.observation()?;
332 let p = o.parent_id.safe_get_msg("Missing parent id")?;
333 let input_opt = self.input_of(&p);
334 let input = input_opt.safe_get_msg("Missing input")?;
335 let proof = input.proof.get(0);
336 let proof_act = proof.safe_get_msg("Missing input proof")?;
337 Ok(*proof_act)
338 }
339 pub fn observation_public_key(&self) -> RgResult<&PublicKey> {
340 let proof_act = self.observation_proof()?;
341 let pk = proof_act.public_key.safe_get_msg("Missing public key")?;
342 Ok(pk)
343 }
344
345 pub fn build_observation_proofs(&self) -> RgResult<Vec<ObservationProof>> {
346 let h = self.hash_or();
347 let p = self.observation_proof()?;
348 let o = self.observation()?;
349 Ok(o.build_observation_proofs(&h, &p))
350 }
351
352 pub fn with_hashes(&mut self) -> &mut Self {
353 self.with_hash();
354 self.with_signable_hash().expect("signable hash");
355 self
356 }
357
358 pub fn with_signable_hash(&mut self) -> Result<&mut Self, ErrorInfo> {
359 self.struct_metadata()?.signable_hash = Some(self.signable_hash());
360 Ok(self)
361 }
362
363 pub fn add_proof_per_input(&mut self, proof: &Proof) -> &Transaction {
364 for i in self.inputs.iter_mut() {
365 i.proof.push(proof.clone());
366 }
367 self
368 }
369
370 pub fn utxo_inputs(&self) -> impl Iterator<Item = &UtxoId> {
371 self.inputs.iter().filter_map(|i| i.utxo_id.as_ref())
372 }
373
374 pub fn fixed_utxo_ids_of_inputs(&self) -> Result<Vec<UtxoId>, ErrorInfo> {
376 let mut utxo_ids = Vec::new();
377 for input in &self.inputs {
378 if let Some(f) = &input.utxo_id {
379 utxo_ids.push(f.clone());
380 }
381 }
382 Ok(utxo_ids)
383 }
384
385 pub fn input_utxo_ids(&self) -> impl Iterator<Item = &UtxoId> {
387 self.inputs.iter().flat_map(|i| i.utxo_id.as_ref())
388 }
389
390 pub fn output_amounts(&self) -> impl Iterator<Item=AddressBalance> + '_ {
391 self.outputs
392 .iter()
393 .flat_map(|o| o.address.as_ref()
394 .and_then(|a| a.render_string().ok())
395 .and_then(|a| o.opt_amount_typed().map(|aa|
396 AddressBalance {
397 address: a,
398 rounded_balance: aa.to_fractional()
399 })
400 )
401 )
402 }
403 pub fn output_amount_total(&self) -> CurrencyAmount {
404 self.output_amounts_opt().cloned().sum::<CurrencyAmount>()
405 }
406
407 pub fn output_amounts_opt(&self) -> impl Iterator<Item = &CurrencyAmount> {
408 self.outputs
409 .iter()
410 .flat_map(|o| o.data.as_ref().and_then(|d| d.amount.as_ref()))
411 }
412
413 pub fn output_address_amounts_opt(&self) -> impl Iterator<Item = (&Address, CurrencyAmount)> {
414 self.outputs
415 .iter()
416 .flat_map(|o| o.opt_amount_typed()
417 .and_then(|a| o.address.as_ref().map(|addr| (addr, a)))
418 )
419 }
420
421 pub fn output_amount_map<'a>(&'a self) -> HashMap<&'a Address, i64> {
422 self.outputs
423 .iter()
424 .filter_map(|o| {
425 o.address.as_ref().and_then(|ad| o.opt_amount().map(|a| (ad, a)))
429 })
430 .fold(HashMap::new(), |mut acc: HashMap<&'a Address, i64>, (ad, a)| {
431 *acc.entry(&ad).or_insert(0) += a;
432 acc
433 })
434 }
435
436 pub fn non_remainder_amount_rdg(&self) -> i64 {
438 let inputs = self.input_address_set();
439 self.outputs.iter().filter_map(|o| {
440 o.address.as_ref()
441 .filter(|&a| !inputs.contains(a))
442 .and_then(|_| o.opt_amount())}
443 ).sum::<i64>()
444 }
445 pub fn non_remainder_amount_rdg_typed(&self) -> CurrencyAmount {
446 let inputs = self.input_address_set();
447 self.outputs.iter().filter_map(|o| {
448 o.address.as_ref()
449 .filter(|&a| !inputs.contains(a))
450 .and_then(|_| o.opt_amount_typed())}
451 ).sum::<CurrencyAmount>()
452 }
453
454 pub fn remainder_amount(&self) -> i64 {
456 let inputs = self.input_address_set();
457 self.outputs.iter().filter_map(|o| {
458 o.address.as_ref()
459 .filter(|&a| inputs.contains(a))
460 .and_then(|_| o.opt_amount())}
461 ).sum::<i64>()
462 }
463 pub fn fee_amount(&self) -> i64 {
464 self.outputs.iter()
465 .filter(|o| o.is_fee())
466 .flat_map(|o| o.opt_amount())
467 .sum::<i64>()
468 }
469
470 pub fn first_output_external_txid(&self) -> Option<&ExternalTransactionId> {
471 self.output_external_txids().next()
472 }
473 pub fn output_external_txids(&self) -> impl Iterator<Item = &ExternalTransactionId> {
474 self.output_response()
475 .filter_map(|r| r.swap_fulfillment.as_ref())
476 .filter_map(|d| d.external_transaction_id.as_ref())
477 }
478
479 pub fn output_rdg_amount_of(&self, address: &Address) -> i64 {
480 self.outputs
481 .iter()
482 .filter_map(|o| o.address.as_ref().filter(|&a| a == address)
483 .and_then(|_| o.opt_amount_typed()))
484 .filter(|a| a.currency_or() == SupportedCurrency::Redgold)
485 .map(|a| a.amount)
486 .sum::<i64>()
487 }
488
489 pub fn output_of(&self, address: &Address) -> Vec<&structs::Output> {
490 self.outputs
491 .iter()
492 .filter_map(|o| o.address.as_ref().filter(|&a| a == address).map(|_| o))
493 .collect_vec()
494 }
495
496 pub fn output_of_with_index(&self, address: &Address) -> Vec<(usize, &structs::Output)> {
497 self.outputs
498 .iter()
499 .enumerate()
500 .filter_map(|(index, o)| o.address.as_ref().filter(|&a| a == address).map(|_| (index, o)))
501 .collect_vec()
502 }
503
504 pub fn first_peer_utxo(&self) -> RgResult<UtxoEntry> {
505 let vec = self.utxo_outputs()?;
506 let option = vec.iter()
507 .filter(|f| f.output.as_ref().filter(|o| o.is_peer_data()).is_some())
508 .next();
509 let x = option.ok_or(error_info("Missing peer utxo"))?.clone();
510 Ok(x)
511 }
512
513 pub fn output_swap_amount_of(&self, address: &Address) -> i64 {
514 self.outputs
515 .iter()
516 .filter_map(|o| {
517 if o.is_swap() {
518 o.address.as_ref()
519 .filter(|&a| a == address)
520 .and_then(|_| o.opt_amount())
521 } else {
522 None
523 }
524 }).sum::<i64>()
525 }
526
527 pub fn has_swap_to(&self, address: &Address) -> bool {
528 self.output_swap_amount_of(address) > 0
529 }
530
531 pub fn output_bitcoin_address_of(&self, address: &Address) -> Option<&Address> {
532 address.render_string().ok().and_then(|s| {
533 self.outputs
534 .iter()
535 .filter(|o| {
536 o.is_swap()
537 .then(|| o.address.as_ref())
538 .flatten()
539 .and_then(|a| a.render_string().ok())
540 .filter(|a| {
541 a == &s
542 })
543 .is_some()
544 })
545 .filter_map(|o| o.data.as_ref().and_then(|d| d.address.as_ref()))
546 .next()
547 })
548 }
549
550 pub fn output_index(&self, output: &Output) -> RgResult<i64> {
551 let index = self.outputs.iter().position(|o| o == output);
552 index.safe_get_msg("Missing output index").map(|i| i.clone() as i64)
553 }
554
555 pub fn utxo_id_at(&self, index: usize) -> RgResult<UtxoId> {
556 let hash = self.hash_or();
557 let output = self.outputs.get(index);
558 output.safe_get_msg("Missing output")?;
559 let utxo_id = UtxoId::new(&hash, index as i64);
560 Ok(utxo_id)
561 }
562
563 pub fn liquidity_of(&self, a: &Address) -> Vec<(UtxoId, &StakeRequest)> {
564 self.output_of_with_index(a)
565 .iter()
566 .flat_map(|(u, o)|
567 self.utxo_id_at(*u).ok().and_then(|utxo_id|
568 o.data.as_ref()
569 .and_then(|d| d.standard_request.as_ref())
570 .and_then(|d| d.stake_request.as_ref())
571 .map(|l| (utxo_id, l))
572 ))
573 .collect_vec()
574 }
575 pub fn stake_requests(&self) -> Vec<(UtxoId, &StakeRequest)> {
576 self.outputs
577 .iter()
578 .enumerate()
579 .flat_map(|(u, o)|
580 self.utxo_id_at(u).ok().and_then(|utxo_id|
581 o.stake_request()
582 .map(|l| (utxo_id, l))
583 ))
584 .collect_vec()
585 }
586
587 pub fn total_output_amount(&self) -> i64 {
588 let mut total = 0;
589 for o in &self.outputs {
590 if let Some(a) = o.opt_amount() {
591 total += a
592 }
593 }
594 total
595 }
596
597 pub fn floating_inputs(&self) -> impl Iterator<Item = &FloatingUtxoId> {
598 self.inputs.iter().filter_map(|i| i.floating_utxo_id.as_ref())
599 }
600
601 pub fn total_input_amount(&self) -> i64 {
602 self.inputs.iter()
603 .filter_map(|i| i.output.as_ref())
604 .filter_map(|o| o.opt_amount())
605 .sum()
606 }
607
608 pub fn total_output_amount_float(&self) -> f64 {
609 CurrencyAmount::from(
610 self.total_output_amount()
611 ).to_fractional()
612 }
613
614 pub fn output_amounts_by_product(&self) -> HashMap<ProductId, CurrencyAmount> {
615 let mut map = HashMap::new();
616 for output in &self.outputs {
617 if let Some(product_id) = output.product_id.as_ref() {
618 if let Some(a) = output.opt_amount() {
619 let aa = map.get(product_id).map(|x: &CurrencyAmount| x.amount + a).unwrap_or(a);
620 map.insert(product_id.clone(), CurrencyAmount::from(aa));
621 }
622 }
623 }
624 map
625 }
626
627 #[allow(dead_code)]
628 fn clear_input_proofs(&mut self) {
629 for i in 0..self.inputs.len() {
630 self.inputs.get_mut(i).unwrap().proof.clear();
631 }
632 }
633
634 #[allow(dead_code)]
635 fn clear_counter_party_proofs(&mut self) {
636 for i in 0..self.outputs.len() {
637 self.outputs
638 .get_mut(i)
639 .unwrap()
640 .counter_party_proofs
641 .clear();
642 }
643 }
644 #[allow(dead_code)]
645 fn clear_confirmation_proofs(&mut self) {
646 for o in self.options.iter_mut() {
647 for c in o.contract.iter_mut() {
648 c.confirmation_proofs.clear()
649 }
650 }
651 }
652 #[allow(dead_code)]
653 pub fn signable_hash(&self) -> Hash {
654 let mut clone = self.clone();
655 clone.clear_input_proofs();
656 clone.clear_counter_party_proofs();
657 clone.clear_confirmation_proofs();
658 return clone.calculate_hash();
659 }
660
661 #[allow(dead_code)]
662 pub fn signed_hash(&self) -> Hash {
663 let mut clone = self.clone();
664 clone.clear_counter_party_proofs();
665 clone.clear_confirmation_proofs();
666 return clone.calculate_hash();
667 }
668
669
670 #[allow(dead_code)]
671 fn pre_counter_party_hash(&self) -> Hash {
672 self.signed_hash()
673 }
674
675 #[allow(dead_code)]
676 fn confirmation_hash(&self) -> Hash {
677 let mut clone = self.clone();
678 clone.clear_confirmation_proofs();
679 return clone.calculate_hash();
680 }
681
682 pub fn to_utxo_entries(&self, time: u64) -> Vec<UtxoEntry> {
683 return UtxoEntry::from_transaction(self, time as i64);
684 }
685
686 pub fn to_utxo_address(&self, address: &Address) -> Vec<UtxoEntry> {
687 let mut res = vec![];
688 let time = self.time();
689 if let Ok(time) = time {
690 for u in UtxoEntry::from_transaction(self, time.clone()) {
691 if u.address() == Ok(address) {
692 res.push(u);
693 }
694 }
695 }
696 res
697 }
698
699 pub fn utxo_outputs(&self) -> RgResult<Vec<UtxoEntry>> {
700 let t = self.time()?;
701 return Ok(UtxoEntry::from_transaction(self, t.clone()));
702 }
703
704 pub fn output_utxo_ids(&self) -> impl Iterator<Item = &UtxoId>{
705 self.outputs.iter().flat_map(|o| o.utxo_id.as_ref())
706 }
707
708 pub fn head_utxo(&self) -> RgResult<UtxoEntry> {
709 let utxos = self.utxo_outputs()?;
710 let head_utxo = utxos.get(0);
711 let utxo = *head_utxo.safe_get_msg("Missing UTXO output for node metadata")?;
712 Ok(utxo.clone())
713 }
714
715 pub fn nmd_utxo(&self) -> RgResult<UtxoEntry> {
716 let utxos = self.utxo_outputs()?.iter().filter(|u|
717 u.output.as_ref().map(|o| o.is_node_metadata()).unwrap_or(false)
718 ).cloned().collect_vec();
719 let head_utxo = utxos.get(0);
720 let utxo = *head_utxo.safe_get_msg("Missing UTXO output for node metadata")?;
721 Ok(utxo.clone())
722 }
723
724 pub fn height(&self) -> RgResult<i64> {
725 let h = self.options.as_ref()
726 .and_then(|o| o.data.as_ref())
727 .and_then(|d| d.standard_data.as_ref())
728 .and_then(|s| s.height);
729 h.safe_get_msg("Missing height").cloned()
730 }
731
732 pub fn options(&self) -> RgResult<&TransactionOptions> {
733 self.options.safe_get_msg("Missing options")
734 }
735 pub fn salt(&self) -> RgResult<i64> {
736 let s = self.options()?.salt;
737 s.safe_get_msg("Missing salt").cloned()
738 }
739
740 pub fn peer_data(&self) -> Result<PeerMetadata, ErrorInfo> {
762 let mut res = vec![];
763 for o in &self.outputs {
764 if let Some(data) = &o.data {
765 if let Some(d) = &data.peer_data {
766 res.push(d.clone());
767 }
768 }
769 }
770 if res.len() == 1 {
771 return Ok(res[0].clone());
772 } else {
773 return Err(ErrorInfo::error_info("Missing peer data in transaction"));
774 }
775 }
776
777 pub fn node_metadata(&self) -> Result<NodeMetadata, ErrorInfo> {
778 let mut res = vec![];
779 for o in &self.outputs {
780 if let Some(data) = &o.data {
781 if let Some(d) = &data.node_metadata {
782 res.push(d.clone());
783 }
784 }
785 }
786 if res.len() == 1 {
787 return Ok(res[0].clone());
788 } else {
789 return Err(ErrorInfo::error_info("Missing node metadata in transaction"));
790 }
791 }
792
793 #[deprecated]
794 pub fn addresses(&self) -> Vec<Address> {
795 self.outputs.iter().filter_map(|o| o.address.clone()).collect_vec()
796 }
797
798 #[deprecated]
799 pub fn input_addresses(&self) -> Vec<Address> {
800 self.inputs.iter().filter_map(|o| o.address().ok()).collect_vec()
801 }
802
803 pub fn input_address_descriptor_address_or_public_key(&self) -> Vec<Address> {
804 self.inputs.iter().filter_map(|i| {
805 if let Some(d) = i.address_descriptor.as_ref() {
806 Some(d.to_address())
807 } else {
808 i.proof.get(0)
809 .and_then(|p| p.public_key.as_ref())
810 .and_then(|pk| pk.address().ok())
811 }
812 }).collect_vec()
813 }
814
815 #[deprecated]
816 pub fn input_address_set(&self) -> HashSet<Address> {
817 self.inputs.iter().filter_map(|o| o.address().ok()).collect()
818 }
819
820 #[deprecated]
821 pub fn first_input_address(&self) -> Option<Address> {
822 self.inputs.iter().flat_map(|o| o.address().ok()).next()
823 }
824
825 #[deprecated]
826 pub fn first_input_proof_public_key(&self) -> Option<&structs::PublicKey> {
827 self.inputs.first()
828 .and_then(|o| o.proof.get(0))
829 .and_then(|o| o.public_key.as_ref())
830 }
831
832 pub fn first_output_non_input_or_fee(&self) -> Option<&Output> {
833 let input_addrs = self.input_addresses();
834 self.outputs.iter()
835 .filter(|o| o.output_type != Some(OutputType::Fee as i32))
836 .filter(|o| o.address.as_ref().map(|a| !input_addrs.contains(a)).unwrap_or(true))
837 .next()
838 }
839
840 pub fn has_input_address_as_output_address(&self) -> bool {
841 let input_addrs = self.input_addresses();
842 self.outputs.iter()
843 .filter(|o| o.address.as_ref().map(|a| input_addrs.contains(a)).unwrap_or(false))
844 .next()
845 .is_some()
846 }
847
848 pub fn has_relation_to_address(&self, a: &Address) -> bool {
849 self.input_address_descriptor_address_or_public_key().contains(a) ||
850 self.output_address_amounts_opt().map(|(addr, _)| addr).any(|addr| addr == a)
851 }
852
853 pub fn is_outgoing(&self) -> bool {
854 self.has_input_address_as_output_address()
855 }
856
857 pub fn first_output_address_non_input_or_fee(&self) -> Option<Address> {
858 self.first_output_non_input_or_fee()
859 .and_then(|o| o.address.clone())
860 }
861
862 pub fn first_output_amount(&self) -> Option<f64> {
863 self.first_output_amount_typed().map(|o| o.to_fractional())
864 }
865
866 pub fn first_output_amount_i64(&self) -> Option<i64> {
867 self.first_output_non_input_or_fee().and_then(|o| o.opt_amount())
868 }
869
870 pub fn first_output_amount_typed(&self) -> Option<CurrencyAmount> {
871 self.first_output_non_input_or_fee().and_then(|o| o.opt_amount_typed())
872 }
873
874 pub fn first_contract_type(&self) -> Option<StandardContractType> {
875 self.outputs.iter()
876 .flat_map(|o| o.contract.as_ref())
877 .flat_map(|c| c.standard_contract_type.as_ref())
878 .flat_map(|c| StandardContractType::from_i32(c.clone()))
879 .next()
880 }
881
882}
883
884pub fn amount_data(amount: u64) -> Option<StandardData> {
890 StandardData::amount_data(amount)
891}
892
893impl StandardData {
894
895 pub fn observation(o: Observation) -> Self {
896 let mut sd = Self::default();
897 sd.observation = Some(o);
898 sd
899 }
900
901 pub fn empty() -> Self {
902 Self::default()
903 }
904 pub fn peer_data(pd: PeerMetadata) -> Option<Self> {
905 let mut mt = Self::empty();
906 mt.peer_data = Some(pd);
907 Some(mt)
908 }
909 pub fn amount_data(amount: u64) -> Option<Self> {
910 let mut mt = Self::empty();
911 mt.amount = Some(CurrencyAmount::from(amount as i64));
912 Some(mt)
913 }
914
915
916}
917
918impl TypedValue {
919 pub fn bytes(bytes: &Vec<u8>) -> Self {
920 let mut s = Self::default();
921 s.bytes_value = bytes_data(bytes.clone());
922 s
923 }
924}
925
926
927#[derive(Serialize, Deserialize, Clone, Debug)]
928pub struct TransactionMaybeError {
929 pub transaction: Transaction,
930 pub error: Option<ErrorInfo>,
931}
932
933impl TransactionMaybeError {
934 pub fn new(transaction: Transaction) -> Self {
935 Self {
936 transaction,
937 error: None,
938 }
939 }
940 pub fn new_error(transaction: Transaction, error: ErrorInfo) -> Self {
941 Self {
942 transaction,
943 error: Some(error),
944 }
945 }
946}