1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
use chrono::prelude::*;
use reqwest::r#async::{Client, Response};
use reqwest::Error;
use tokio::prelude::*;
use iota_conversion;
use iota_model::*;
use iota_pow::PearlDiver;
use iota_validation::input_validator;
use crate::Result;
use super::responses::AttachToTangleResponse;
lazy_static! {
pub static ref MAX_TIMESTAMP_VALUE: i64 = (3_i64.pow(27) - 1) / 2;
}
pub fn attach_to_tangle(
client: &Client,
uri: String,
trunk_transaction: String,
branch_transaction: String,
min_weight_magnitude: usize,
trytes: Vec<String>,
) -> impl Future<Item = Response, Error = Error> {
let body = json!({
"command": "attachToTangle",
"trunkTransaction": trunk_transaction,
"branchTransaction": branch_transaction,
"minWeightMagnitude": min_weight_magnitude,
"trytes": trytes,
});
client
.post(&uri)
.header("ContentType", "application/json")
.header("X-IOTA-API-Version", "1")
.body(body.to_string())
.send()
}
pub fn attach_to_tangle_local<T: Copy + Into<Option<usize>>>(
threads: T,
trunk_transaction: String,
branch_transaction: String,
min_weight_magnitude: usize,
trytes: Vec<String>,
) -> Result<AttachToTangleResponse> {
ensure!(
input_validator::is_hash(&trunk_transaction),
"Provided trunk transaction is not valid: {:?}",
trunk_transaction
);
ensure!(
input_validator::is_hash(&branch_transaction),
"Provided branch transaction is not valid: {:?}",
branch_transaction
);
ensure!(
input_validator::is_array_of_trytes(&trytes),
"Provided trytes are not valid: {:?}",
trytes
);
let mut result_trytes: Vec<String> = Vec::with_capacity(trytes.len());
let mut previous_transaction: Option<String> = None;
for i in 0..trytes.len() {
let mut tx: Transaction = trytes[i].parse()?;
let new_trunk_tx = if let Some(previous_transaction) = &previous_transaction {
previous_transaction.clone()
} else {
trunk_transaction.clone()
};
tx.set_trunk_transaction(new_trunk_tx);
let new_branch_tx = if previous_transaction.is_some() {
trunk_transaction.clone()
} else {
branch_transaction.clone()
};
tx.set_branch_transaction(new_branch_tx);
let tag = tx.tag().unwrap_or_default();
if tag.is_empty() || tag == "9".repeat(27) {
*tx.tag_mut() = tx.obsolete_tag();
}
tx.set_attachment_timestamp(Utc::now().timestamp_millis());
tx.set_attachment_timestamp_lower_bound(0);
tx.set_attachment_timestamp_upper_bound(*MAX_TIMESTAMP_VALUE);
let tx_trits = iota_conversion::trits_from_string(&tx.to_trytes());
let result_trits = PearlDiver::default().search(
TrinaryData::Trits(tx_trits),
min_weight_magnitude,
threads.into(),
)?;
result_trytes.push(iota_conversion::trits_to_string(&result_trits)?);
previous_transaction = result_trytes[i].parse::<Transaction>()?.hash();
}
result_trytes.reverse();
Ok(AttachToTangleResponse::new(
None,
None,
None,
Some(result_trytes),
))
}