1use std::{
2 cmp::Ordering,
3 io::{self, Error, ErrorKind},
4};
5
6use crate::{codec, key};
7use serde::{Deserialize, Serialize};
8
9#[derive(Debug, Serialize, Deserialize, Eq, Clone, Default)]
14pub struct Output {
15 pub amount: u64,
16
17 #[serde(flatten)]
19 pub output_owners: key::secp256k1::txs::OutputOwners,
20}
21
22impl Output {
23 pub fn new(amount: u64, output_owners: key::secp256k1::txs::OutputOwners) -> Self {
24 Self {
25 amount,
26 output_owners,
27 }
28 }
29
30 pub fn type_name() -> String {
31 "secp256k1fx.TransferOutput".to_string()
32 }
33
34 pub fn type_id() -> u32 {
35 *(codec::X_TYPES.get(&Self::type_name()).unwrap()) as u32
36 }
37}
38
39#[test]
41fn test_transfer_output_custom_de_serializer() {
42 use crate::ids::short;
43
44 let d = Output {
45 amount: 1234,
46 output_owners: key::secp256k1::txs::OutputOwners {
47 locktime: 1,
48 threshold: 2,
49 addresses: vec![short::Id::empty()],
50 },
51 };
52
53 let yaml_encoded = serde_yaml::to_string(&d).unwrap();
54 println!("yaml_encoded:\n{}", yaml_encoded);
55 let yaml_decoded = serde_yaml::from_str(&yaml_encoded).unwrap();
56 assert_eq!(d, yaml_decoded);
57
58 let json_encoded = serde_json::to_string(&d).unwrap();
59 println!("json_encoded:\n{}", json_encoded);
60 let json_decoded = serde_json::from_str(&json_encoded).unwrap();
61 assert_eq!(d, json_decoded);
62}
63
64impl Ord for Output {
65 fn cmp(&self, other: &Output) -> Ordering {
66 self.amount
67 .cmp(&(other.amount)) .then_with(
69 || self.output_owners.cmp(&(other.output_owners)), )
71 }
72}
73
74impl PartialOrd for Output {
75 fn partial_cmp(&self, other: &Output) -> Option<Ordering> {
76 Some(self.cmp(other))
77 }
78}
79
80impl PartialEq for Output {
81 fn eq(&self, other: &Output) -> bool {
82 self.cmp(other) == Ordering::Equal
83 }
84}
85
86#[test]
88fn test_sort_transfer_outputs() {
89 use crate::ids::short;
90
91 let mut outputs: Vec<Output> = Vec::new();
92 for i in (0..10).rev() {
93 outputs.push(Output {
94 amount: i as u64,
95 output_owners: key::secp256k1::txs::OutputOwners {
96 locktime: (i + 1) as u64,
97 threshold: (i + 1) as u32,
98 addresses: vec![
99 short::Id::from_slice(&[i as u8, 1, 2, 3, 4, 5]),
100 short::Id::from_slice(&[i as u8, 2, 2, 3, 4, 5]),
101 ],
102 },
103 });
104 outputs.push(Output {
105 amount: i as u64,
106 output_owners: key::secp256k1::txs::OutputOwners {
107 locktime: (i + 1) as u64,
108 threshold: (i + 1) as u32,
109 addresses: vec![
110 short::Id::from_slice(&[i as u8, 1, 2, 3, 4, 5]),
111 short::Id::from_slice(&[i as u8, 1, 2, 3, 4, 5]),
112 ],
113 },
114 });
115 outputs.push(Output {
116 amount: i as u64,
117 output_owners: key::secp256k1::txs::OutputOwners {
118 locktime: (i + 1) as u64,
119 threshold: (i + 1) as u32,
120 addresses: vec![short::Id::from_slice(&[i as u8, 1, 2, 3, 4, 5])],
121 },
122 });
123 outputs.push(Output {
124 amount: i as u64,
125 output_owners: key::secp256k1::txs::OutputOwners {
126 locktime: (i + 1) as u64,
127 threshold: i as u32,
128 addresses: vec![short::Id::from_slice(&[i as u8, 1, 2, 3, 4, 5])],
129 },
130 });
131 outputs.push(Output {
132 amount: i as u64,
133 output_owners: key::secp256k1::txs::OutputOwners {
134 locktime: i as u64,
135 threshold: i as u32,
136 addresses: vec![short::Id::from_slice(&[i as u8, 1, 2, 3, 4, 5])],
137 },
138 });
139 }
140 assert!(!cmp_manager::is_sorted_and_unique(&outputs));
141 outputs.sort();
142
143 let mut sorted_outputs: Vec<Output> = Vec::new();
144 for i in 0..10 {
145 sorted_outputs.push(Output {
146 amount: i as u64,
147 output_owners: key::secp256k1::txs::OutputOwners {
148 locktime: i as u64,
149 threshold: i as u32,
150 addresses: vec![short::Id::from_slice(&[i as u8, 1, 2, 3, 4, 5])],
151 },
152 });
153 sorted_outputs.push(Output {
154 amount: i as u64,
155 output_owners: key::secp256k1::txs::OutputOwners {
156 locktime: (i + 1) as u64,
157 threshold: i as u32,
158 addresses: vec![short::Id::from_slice(&[i as u8, 1, 2, 3, 4, 5])],
159 },
160 });
161 sorted_outputs.push(Output {
162 amount: i as u64,
163 output_owners: key::secp256k1::txs::OutputOwners {
164 locktime: (i + 1) as u64,
165 threshold: (i + 1) as u32,
166 addresses: vec![short::Id::from_slice(&[i as u8, 1, 2, 3, 4, 5])],
167 },
168 });
169 sorted_outputs.push(Output {
170 amount: i as u64,
171 output_owners: key::secp256k1::txs::OutputOwners {
172 locktime: (i + 1) as u64,
173 threshold: (i + 1) as u32,
174 addresses: vec![
175 short::Id::from_slice(&[i as u8, 1, 2, 3, 4, 5]),
176 short::Id::from_slice(&[i as u8, 1, 2, 3, 4, 5]),
177 ],
178 },
179 });
180 sorted_outputs.push(Output {
181 amount: i as u64,
182 output_owners: key::secp256k1::txs::OutputOwners {
183 locktime: (i + 1) as u64,
184 threshold: (i + 1) as u32,
185 addresses: vec![
186 short::Id::from_slice(&[i as u8, 1, 2, 3, 4, 5]),
187 short::Id::from_slice(&[i as u8, 2, 2, 3, 4, 5]),
188 ],
189 },
190 });
191 }
192 assert!(cmp_manager::is_sorted_and_unique(&sorted_outputs));
193 assert_eq!(outputs, sorted_outputs);
194}
195
196#[derive(Debug, Serialize, Deserialize, Eq, Clone, Default)]
201pub struct Input {
202 pub amount: u64,
203 #[serde(rename = "signatureIndices")]
204 pub sig_indices: Vec<u32>,
205}
206
207impl Input {
208 pub fn new(amount: u64, sig_indices: Vec<u32>) -> Self {
209 Self {
210 amount,
211 sig_indices,
212 }
213 }
214
215 pub fn type_name() -> String {
216 "secp256k1fx.TransferInput".to_string()
217 }
218
219 pub fn type_id() -> u32 {
220 *(codec::X_TYPES.get(&Self::type_name()).unwrap()) as u32
221 }
222
223 pub fn verify(&self) -> io::Result<()> {
224 if self.amount == 0 {
225 return Err(Error::new(
226 ErrorKind::InvalidInput,
227 "input has no value", ));
229 }
230 if !cmp_manager::is_sorted_and_unique(&self.sig_indices) {
231 return Err(Error::new(
232 ErrorKind::InvalidInput,
233 "signatures not sorted and unique", ));
235 }
236 Ok(())
237 }
238
239 pub fn sig_costs(&self) -> u64 {
241 let sigs = self.sig_indices.len();
242 (sigs as u64) * 1000
243 }
244}
245
246impl Ord for Input {
247 fn cmp(&self, other: &Input) -> Ordering {
248 self.amount
249 .cmp(&(other.amount)) .then_with(
251 || {
252 key::secp256k1::txs::SigIndices::new(&self.sig_indices)
253 .cmp(&key::secp256k1::txs::SigIndices::new(&other.sig_indices))
254 }, )
256 }
257}
258
259impl PartialOrd for Input {
260 fn partial_cmp(&self, other: &Input) -> Option<Ordering> {
261 Some(self.cmp(other))
262 }
263}
264
265impl PartialEq for Input {
266 fn eq(&self, other: &Input) -> bool {
267 self.cmp(other) == Ordering::Equal
268 }
269}
270
271#[test]
273fn test_sort_transfer_inputs() {
274 let mut inputs: Vec<Input> = Vec::new();
275 for i in (0..10).rev() {
276 inputs.push(Input {
277 amount: 5,
278 sig_indices: vec![i as u32, 2, 2, 3, 4, 5, 6, 7, 8, 9],
279 });
280 inputs.push(Input {
281 amount: 5,
282 sig_indices: vec![i as u32, 1, 2, 3, 4, 5, 6, 7, 8, 9],
283 });
284 inputs.push(Input {
285 amount: 50,
286 sig_indices: vec![i as u32, 1, 2, 3, 4, 5],
287 });
288 inputs.push(Input {
289 amount: 5,
290 sig_indices: vec![i as u32, 1, 2, 3, 4, 5],
291 });
292 inputs.push(Input {
293 amount: 1,
294 sig_indices: vec![(i + 100) as u32, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9],
295 });
296 }
297 assert!(!cmp_manager::is_sorted_and_unique(&inputs));
298 inputs.sort();
299
300 let mut sorted_inputs: Vec<Input> = Vec::new();
301 for i in 0..10 {
302 sorted_inputs.push(Input {
303 amount: 1,
304 sig_indices: vec![(i + 100) as u32, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9],
305 });
306 }
307 for i in 0..10 {
308 sorted_inputs.push(Input {
309 amount: 5,
310 sig_indices: vec![i as u32, 1, 2, 3, 4, 5],
311 });
312 }
313 for i in 0..10 {
314 sorted_inputs.push(Input {
315 amount: 5,
316 sig_indices: vec![i as u32, 1, 2, 3, 4, 5, 6, 7, 8, 9],
317 });
318 sorted_inputs.push(Input {
319 amount: 5,
320 sig_indices: vec![i as u32, 2, 2, 3, 4, 5, 6, 7, 8, 9],
321 });
322 }
323 for i in 0..10 {
324 sorted_inputs.push(Input {
325 amount: 50,
326 sig_indices: vec![i as u32, 1, 2, 3, 4, 5],
327 });
328 }
329 assert!(cmp_manager::is_sorted_and_unique(&sorted_inputs));
330 assert_eq!(inputs, sorted_inputs);
331}