1use crate::encoding;
16use crate::error::SignerError;
17use std::collections::HashSet;
18
19pub mod global_key {
25 pub const TX_VERSION: u8 = 0x02;
27 pub const FALLBACK_LOCKTIME: u8 = 0x03;
29 pub const INPUT_COUNT: u8 = 0x04;
31 pub const OUTPUT_COUNT: u8 = 0x05;
33 pub const TX_MODIFIABLE: u8 = 0x06;
35 pub const VERSION: u8 = 0xFB;
37}
38
39pub mod input_key {
41 pub const PREVIOUS_TXID: u8 = 0x0E;
43 pub const OUTPUT_INDEX: u8 = 0x0F;
45 pub const SEQUENCE: u8 = 0x10;
47 pub const REQUIRED_TIME_LOCKTIME: u8 = 0x11;
49 pub const REQUIRED_HEIGHT_LOCKTIME: u8 = 0x12;
51 pub const NON_WITNESS_UTXO: u8 = 0x00;
54 pub const WITNESS_UTXO: u8 = 0x01;
56 pub const PARTIAL_SIG: u8 = 0x02;
58 pub const SIGHASH_TYPE: u8 = 0x03;
60}
61
62pub mod output_key {
64 pub const AMOUNT: u8 = 0x03;
66 pub const SCRIPT: u8 = 0x04;
68 pub const REDEEM_SCRIPT: u8 = 0x00;
71 pub const WITNESS_SCRIPT: u8 = 0x01;
73}
74
75#[derive(Debug, Clone, Copy, PartialEq, Eq)]
81pub struct ModifiableFlags(u8);
82
83impl ModifiableFlags {
84 pub const NONE: Self = Self(0);
86 pub const INPUTS_MODIFIABLE: Self = Self(0x01);
88 pub const OUTPUTS_MODIFIABLE: Self = Self(0x02);
90 pub const HAS_SIGHASH_SINGLE: Self = Self(0x04);
92
93 #[must_use]
95 pub const fn from_byte(b: u8) -> Self {
96 Self(b)
97 }
98
99 #[must_use]
101 pub const fn to_byte(self) -> u8 {
102 self.0
103 }
104
105 #[must_use]
107 pub const fn inputs_modifiable(self) -> bool {
108 self.0 & 0x01 != 0
109 }
110
111 #[must_use]
113 pub const fn outputs_modifiable(self) -> bool {
114 self.0 & 0x02 != 0
115 }
116
117 #[must_use]
119 pub const fn union(self, other: Self) -> Self {
120 Self(self.0 | other.0)
121 }
122}
123
124#[derive(Debug, Clone)]
130pub struct PsbtV2Input {
131 pub previous_txid: [u8; 32],
133 pub output_index: u32,
135 pub sequence: u32,
137 pub required_time_locktime: Option<u32>,
139 pub required_height_locktime: Option<u32>,
141 pub extra: Vec<(Vec<u8>, Vec<u8>)>,
143}
144
145impl PsbtV2Input {
146 #[must_use]
148 pub fn new(previous_txid: [u8; 32], output_index: u32) -> Self {
149 Self {
150 previous_txid,
151 output_index,
152 sequence: 0xFFFFFFFF,
153 required_time_locktime: None,
154 required_height_locktime: None,
155 extra: Vec::new(),
156 }
157 }
158
159 #[must_use]
161 pub fn with_sequence(mut self, sequence: u32) -> Self {
162 self.sequence = sequence;
163 self
164 }
165
166 pub fn set_witness_utxo(&mut self, amount: u64, script_pubkey: &[u8]) {
168 let mut value = Vec::with_capacity(8 + script_pubkey.len() + 9);
169 value.extend_from_slice(&amount.to_le_bytes());
170 encoding::encode_compact_size(&mut value, script_pubkey.len() as u64);
172 value.extend_from_slice(script_pubkey);
173 self.extra.push((vec![input_key::WITNESS_UTXO], value));
174 }
175
176 pub fn serialize(&self) -> Vec<u8> {
178 let mut buf = Vec::new();
179
180 write_kv(&mut buf, &[input_key::PREVIOUS_TXID], &self.previous_txid);
182 write_kv(
184 &mut buf,
185 &[input_key::OUTPUT_INDEX],
186 &self.output_index.to_le_bytes(),
187 );
188 write_kv(
190 &mut buf,
191 &[input_key::SEQUENCE],
192 &self.sequence.to_le_bytes(),
193 );
194
195 if let Some(t) = self.required_time_locktime {
197 write_kv(
198 &mut buf,
199 &[input_key::REQUIRED_TIME_LOCKTIME],
200 &t.to_le_bytes(),
201 );
202 }
203 if let Some(h) = self.required_height_locktime {
204 write_kv(
205 &mut buf,
206 &[input_key::REQUIRED_HEIGHT_LOCKTIME],
207 &h.to_le_bytes(),
208 );
209 }
210
211 for (k, v) in &self.extra {
213 write_kv(&mut buf, k, v);
214 }
215
216 buf.push(0x00);
218 buf
219 }
220}
221
222#[derive(Debug, Clone)]
228pub struct PsbtV2Output {
229 pub amount: u64,
231 pub script: Vec<u8>,
233 pub extra: Vec<(Vec<u8>, Vec<u8>)>,
235}
236
237impl PsbtV2Output {
238 #[must_use]
240 pub fn new(amount: u64, script: Vec<u8>) -> Self {
241 Self {
242 amount,
243 script,
244 extra: Vec::new(),
245 }
246 }
247
248 pub fn serialize(&self) -> Vec<u8> {
250 let mut buf = Vec::new();
251
252 write_kv(&mut buf, &[output_key::AMOUNT], &self.amount.to_le_bytes());
254 write_kv(&mut buf, &[output_key::SCRIPT], &self.script);
256
257 for (k, v) in &self.extra {
259 write_kv(&mut buf, k, v);
260 }
261
262 buf.push(0x00);
264 buf
265 }
266}
267
268#[derive(Debug, Clone)]
274pub struct PsbtV2 {
275 pub tx_version: u32,
277 pub fallback_locktime: u32,
279 pub modifiable: ModifiableFlags,
281 pub inputs: Vec<PsbtV2Input>,
283 pub outputs: Vec<PsbtV2Output>,
285 pub global_extra: Vec<(Vec<u8>, Vec<u8>)>,
287}
288
289impl PsbtV2 {
290 #[must_use]
292 pub fn new() -> Self {
293 Self {
294 tx_version: 2,
295 fallback_locktime: 0,
296 modifiable: ModifiableFlags::NONE,
297 inputs: Vec::new(),
298 outputs: Vec::new(),
299 global_extra: Vec::new(),
300 }
301 }
302
303 #[must_use]
307 pub fn new_interactive() -> Self {
308 Self {
309 modifiable: ModifiableFlags::INPUTS_MODIFIABLE
310 .union(ModifiableFlags::OUTPUTS_MODIFIABLE),
311 ..Self::new()
312 }
313 }
314
315 pub fn add_input(&mut self, input: PsbtV2Input) -> usize {
317 self.inputs.push(input);
318 self.inputs.len() - 1
319 }
320
321 pub fn add_output(&mut self, output: PsbtV2Output) -> usize {
323 self.outputs.push(output);
324 self.outputs.len() - 1
325 }
326
327 #[must_use]
332 pub fn computed_locktime(&self) -> u32 {
333 let mut max_time: Option<u32> = None;
334 let mut max_height: Option<u32> = None;
335
336 for input in &self.inputs {
337 if let Some(t) = input.required_time_locktime {
338 max_time = Some(max_time.map_or(t, |m: u32| m.max(t)));
339 }
340 if let Some(h) = input.required_height_locktime {
341 max_height = Some(max_height.map_or(h, |m: u32| m.max(h)));
342 }
343 }
344
345 if let Some(h) = max_height {
347 return h;
348 }
349 if let Some(t) = max_time {
350 return t;
351 }
352
353 self.fallback_locktime
354 }
355
356 pub fn serialize(&self) -> Vec<u8> {
360 let mut buf = Vec::new();
361
362 buf.extend_from_slice(b"psbt\xFF");
364
365 write_kv(&mut buf, &[global_key::VERSION], &2u32.to_le_bytes());
368 write_kv(
370 &mut buf,
371 &[global_key::TX_VERSION],
372 &self.tx_version.to_le_bytes(),
373 );
374 write_kv(
376 &mut buf,
377 &[global_key::FALLBACK_LOCKTIME],
378 &self.fallback_locktime.to_le_bytes(),
379 );
380 write_kv(
382 &mut buf,
383 &[global_key::INPUT_COUNT],
384 &compact_size(self.inputs.len()),
385 );
386 write_kv(
388 &mut buf,
389 &[global_key::OUTPUT_COUNT],
390 &compact_size(self.outputs.len()),
391 );
392 if self.modifiable.to_byte() != 0 {
394 write_kv(
395 &mut buf,
396 &[global_key::TX_MODIFIABLE],
397 &[self.modifiable.to_byte()],
398 );
399 }
400
401 for (k, v) in &self.global_extra {
403 write_kv(&mut buf, k, v);
404 }
405
406 buf.push(0x00);
408
409 for input in &self.inputs {
411 buf.extend_from_slice(&input.serialize());
412 }
413
414 for output in &self.outputs {
416 buf.extend_from_slice(&output.serialize());
417 }
418
419 buf
420 }
421
422 pub fn deserialize(data: &[u8]) -> Result<Self, SignerError> {
424 if data.len() < 5 || &data[0..5] != b"psbt\xFF" {
425 return Err(SignerError::ParseError("invalid PSBT magic".into()));
426 }
427
428 let mut pos = 5;
429 let mut psbt = PsbtV2::new();
430 let mut input_count: Option<usize> = None;
431 let mut output_count: Option<usize> = None;
432 let mut found_version = false;
433 let mut found_tx_version = false;
434 let mut found_global_terminator = false;
435 let mut seen_global_keys: HashSet<Vec<u8>> = HashSet::new();
436
437 while pos < data.len() {
439 if data[pos] == 0x00 {
440 pos += 1;
441 found_global_terminator = true;
442 break;
443 }
444
445 let (key, val, consumed) = read_kv(&data[pos..])?;
446 pos += consumed;
447
448 if !seen_global_keys.insert(key.clone()) {
449 return Err(SignerError::ParseError(
450 "PSBTv2: duplicate key in global map".into(),
451 ));
452 }
453
454 if key.len() == 1 {
455 match key[0] {
456 global_key::VERSION => {
457 if val.len() != 4 {
458 return Err(SignerError::ParseError(
459 "PSBTv2: version must be 4 bytes".into(),
460 ));
461 }
462 let v = u32::from_le_bytes([val[0], val[1], val[2], val[3]]);
463 if v != 2 {
464 return Err(SignerError::ParseError(format!(
465 "expected PSBT version 2, got {v}"
466 )));
467 }
468 found_version = true;
469 }
470 global_key::TX_VERSION => {
471 if val.len() != 4 {
472 return Err(SignerError::ParseError(
473 "PSBTv2: tx version must be 4 bytes".into(),
474 ));
475 }
476 psbt.tx_version = u32::from_le_bytes([val[0], val[1], val[2], val[3]]);
477 found_tx_version = true;
478 }
479 global_key::FALLBACK_LOCKTIME => {
480 if val.len() != 4 {
481 return Err(SignerError::ParseError(
482 "PSBTv2: fallback locktime must be 4 bytes".into(),
483 ));
484 }
485 psbt.fallback_locktime =
486 u32::from_le_bytes([val[0], val[1], val[2], val[3]]);
487 }
488 global_key::INPUT_COUNT => {
489 input_count = Some(read_compact_size(&val)?);
490 }
491 global_key::OUTPUT_COUNT => {
492 output_count = Some(read_compact_size(&val)?);
493 }
494 global_key::TX_MODIFIABLE => {
495 if val.len() != 1 {
496 return Err(SignerError::ParseError(
497 "PSBTv2: tx_modifiable must be 1 byte".into(),
498 ));
499 }
500 psbt.modifiable = ModifiableFlags::from_byte(val[0]);
501 }
502 _ => {
503 psbt.global_extra.push((key, val));
504 }
505 }
506 } else {
507 psbt.global_extra.push((key, val));
508 }
509 }
510
511 if !found_global_terminator {
512 return Err(SignerError::ParseError(
513 "PSBTv2: unterminated global map".into(),
514 ));
515 }
516
517 if !found_version {
518 return Err(SignerError::ParseError("missing PSBT version".into()));
519 }
520 if !found_tx_version {
521 return Err(SignerError::ParseError("missing tx version".into()));
522 }
523
524 let n_inputs =
525 input_count.ok_or_else(|| SignerError::ParseError("missing input count".into()))?;
526 let n_outputs =
527 output_count.ok_or_else(|| SignerError::ParseError("missing output count".into()))?;
528
529 for i in 0..n_inputs {
531 let mut input = PsbtV2Input::new([0; 32], 0);
532 let mut has_previous_txid = false;
533 let mut has_output_index = false;
534 let mut found_terminator = false;
535 let mut seen_input_keys: HashSet<Vec<u8>> = HashSet::new();
536 while pos < data.len() {
537 if data[pos] == 0x00 {
538 pos += 1;
539 found_terminator = true;
540 break;
541 }
542 let (key, val, consumed) = read_kv(&data[pos..])?;
543 pos += consumed;
544
545 if !seen_input_keys.insert(key.clone()) {
546 return Err(SignerError::ParseError(format!(
547 "PSBTv2: duplicate key in input map {i}"
548 )));
549 }
550
551 if key.len() == 1 {
552 match key[0] {
553 input_key::PREVIOUS_TXID => {
554 if has_previous_txid {
555 return Err(SignerError::ParseError(format!(
556 "PSBTv2: duplicate input previous_txid in map {i}",
557 )));
558 }
559 if val.len() != 32 {
560 return Err(SignerError::ParseError(format!(
561 "PSBTv2: input {i} previous_txid must be 32 bytes, got {}",
562 val.len()
563 )));
564 }
565 input.previous_txid.copy_from_slice(&val);
566 has_previous_txid = true;
567 }
568 input_key::OUTPUT_INDEX => {
569 if has_output_index {
570 return Err(SignerError::ParseError(format!(
571 "PSBTv2: duplicate input output_index in map {i}",
572 )));
573 }
574 if val.len() != 4 {
575 return Err(SignerError::ParseError(format!(
576 "PSBTv2: input {i} output_index must be 4 bytes, got {}",
577 val.len()
578 )));
579 }
580 input.output_index =
581 u32::from_le_bytes([val[0], val[1], val[2], val[3]]);
582 has_output_index = true;
583 }
584 input_key::SEQUENCE => {
585 if val.len() != 4 {
586 return Err(SignerError::ParseError(format!(
587 "PSBTv2: input {i} sequence must be 4 bytes, got {}",
588 val.len()
589 )));
590 }
591 input.sequence = u32::from_le_bytes([val[0], val[1], val[2], val[3]]);
592 }
593 input_key::REQUIRED_TIME_LOCKTIME => {
594 if input.required_time_locktime.is_some() {
595 return Err(SignerError::ParseError(format!(
596 "PSBTv2: duplicate input required_time_locktime in map {i}",
597 )));
598 }
599 if val.len() != 4 {
600 return Err(SignerError::ParseError(format!(
601 "PSBTv2: input {i} required_time_locktime must be 4 bytes, got {}",
602 val.len()
603 )));
604 }
605 input.required_time_locktime =
606 Some(u32::from_le_bytes([val[0], val[1], val[2], val[3]]));
607 }
608 input_key::REQUIRED_HEIGHT_LOCKTIME => {
609 if input.required_height_locktime.is_some() {
610 return Err(SignerError::ParseError(format!(
611 "PSBTv2: duplicate input required_height_locktime in map {i}",
612 )));
613 }
614 if val.len() != 4 {
615 return Err(SignerError::ParseError(format!(
616 "PSBTv2: input {i} required_height_locktime must be 4 bytes, got {}",
617 val.len()
618 )));
619 }
620 input.required_height_locktime =
621 Some(u32::from_le_bytes([val[0], val[1], val[2], val[3]]));
622 }
623 _ => {
624 input.extra.push((key, val));
625 }
626 }
627 } else {
628 input.extra.push((key, val));
629 }
630 }
631 if !found_terminator {
632 return Err(SignerError::ParseError(format!(
633 "PSBTv2: unterminated input map {i}"
634 )));
635 }
636 if !has_previous_txid {
637 return Err(SignerError::ParseError(format!(
638 "PSBTv2: missing PREVIOUS_TXID in input map {i}",
639 )));
640 }
641 if !has_output_index {
642 return Err(SignerError::ParseError(format!(
643 "PSBTv2: missing OUTPUT_INDEX in input map {i}",
644 )));
645 }
646 psbt.inputs.push(input);
647 }
648
649 for i in 0..n_outputs {
651 let mut output = PsbtV2Output::new(0, Vec::new());
652 let mut has_amount = false;
653 let mut has_script = false;
654 let mut found_terminator = false;
655 let mut seen_output_keys: HashSet<Vec<u8>> = HashSet::new();
656 while pos < data.len() {
657 if data[pos] == 0x00 {
658 pos += 1;
659 found_terminator = true;
660 break;
661 }
662 let (key, val, consumed) = read_kv(&data[pos..])?;
663 pos += consumed;
664
665 if !seen_output_keys.insert(key.clone()) {
666 return Err(SignerError::ParseError(format!(
667 "PSBTv2: duplicate key in output map {i}"
668 )));
669 }
670
671 if key.len() == 1 {
672 match key[0] {
673 output_key::AMOUNT => {
674 if has_amount {
675 return Err(SignerError::ParseError(format!(
676 "PSBTv2: duplicate output amount in map {i}",
677 )));
678 }
679 if val.len() != 8 {
680 return Err(SignerError::ParseError(format!(
681 "PSBTv2: output {i} amount must be 8 bytes, got {}",
682 val.len()
683 )));
684 }
685 output.amount = u64::from_le_bytes([
686 val[0], val[1], val[2], val[3], val[4], val[5], val[6], val[7],
687 ]);
688 has_amount = true;
689 }
690 output_key::SCRIPT => {
691 if has_script {
692 return Err(SignerError::ParseError(format!(
693 "PSBTv2: duplicate output script in map {i}",
694 )));
695 }
696 output.script = val;
697 has_script = true;
698 }
699 _ => {
700 output.extra.push((key, val));
701 }
702 }
703 } else {
704 output.extra.push((key, val));
705 }
706 }
707 if !found_terminator {
708 return Err(SignerError::ParseError(format!(
709 "PSBTv2: unterminated output map {i}"
710 )));
711 }
712 if !has_amount {
713 return Err(SignerError::ParseError(format!(
714 "PSBTv2: missing AMOUNT in output map {i}",
715 )));
716 }
717 if !has_script {
718 return Err(SignerError::ParseError(format!(
719 "PSBTv2: missing SCRIPT in output map {i}",
720 )));
721 }
722 psbt.outputs.push(output);
723 }
724
725 if pos != data.len() {
727 return Err(SignerError::ParseError(format!(
728 "PSBTv2: {} trailing bytes",
729 data.len() - pos
730 )));
731 }
732
733 Ok(psbt)
734 }
735}
736
737impl Default for PsbtV2 {
738 fn default() -> Self {
739 Self::new()
740 }
741}
742
743fn write_kv(buf: &mut Vec<u8>, key: &[u8], value: &[u8]) {
749 buf.extend_from_slice(&compact_size(key.len()));
750 buf.extend_from_slice(key);
751 buf.extend_from_slice(&compact_size(value.len()));
752 buf.extend_from_slice(value);
753}
754
755fn read_kv(data: &[u8]) -> Result<(Vec<u8>, Vec<u8>, usize), SignerError> {
757 let mut pos = 0;
758
759 let (key_len, consumed) = read_compact_size_at(data, pos)?;
761 pos = pos
762 .checked_add(consumed)
763 .ok_or_else(|| SignerError::ParseError("PSBT key length offset overflow".into()))?;
764 let key_end = pos
765 .checked_add(key_len)
766 .ok_or_else(|| SignerError::ParseError("PSBT key length overflow".into()))?;
767 if key_end > data.len() {
768 return Err(SignerError::ParseError("truncated PSBT key".into()));
769 }
770 let key = data[pos..key_end].to_vec();
771 pos = key_end;
772
773 let (val_len, consumed) = read_compact_size_at(data, pos)?;
775 pos = pos
776 .checked_add(consumed)
777 .ok_or_else(|| SignerError::ParseError("PSBT value length offset overflow".into()))?;
778 let val_end = pos
779 .checked_add(val_len)
780 .ok_or_else(|| SignerError::ParseError("PSBT value length overflow".into()))?;
781 if val_end > data.len() {
782 return Err(SignerError::ParseError("truncated PSBT value".into()));
783 }
784 let value = data[pos..val_end].to_vec();
785 pos = val_end;
786
787 Ok((key, value, pos))
788}
789
790fn compact_size(n: usize) -> Vec<u8> {
792 if n < 0xFD {
793 vec![n as u8]
794 } else if n <= 0xFFFF {
795 let mut v = vec![0xFD];
796 v.extend_from_slice(&(n as u16).to_le_bytes());
797 v
798 } else if n <= 0xFFFF_FFFF {
799 let mut v = vec![0xFE];
800 v.extend_from_slice(&(n as u32).to_le_bytes());
801 v
802 } else {
803 let mut v = vec![0xFF];
804 v.extend_from_slice(&(n as u64).to_le_bytes());
805 v
806 }
807}
808
809fn read_compact_size(data: &[u8]) -> Result<usize, SignerError> {
811 let (value, consumed) = decode_compact_size_with_consumed(data)?;
812 if consumed != data.len() {
813 return Err(SignerError::ParseError(
814 "compact_size: trailing bytes".into(),
815 ));
816 }
817 Ok(value)
818}
819
820fn read_compact_size_at(data: &[u8], pos: usize) -> Result<(usize, usize), SignerError> {
822 if pos >= data.len() {
823 return Err(SignerError::ParseError("unexpected end of PSBT".into()));
824 }
825 decode_compact_size_with_consumed(&data[pos..])
826}
827
828fn decode_compact_size_with_consumed(data: &[u8]) -> Result<(usize, usize), SignerError> {
829 let mut offset = 0usize;
830 let value = encoding::read_compact_size(data, &mut offset)
831 .map_err(|e| SignerError::ParseError(format!("compact_size: {e}")))?;
832 let value = usize::try_from(value).map_err(|_| {
833 SignerError::ParseError("compact_size: value exceeds platform usize".into())
834 })?;
835 Ok((value, offset))
836}
837
838#[cfg(test)]
843#[allow(clippy::unwrap_used, clippy::expect_used)]
844mod tests {
845 use super::*;
846
847 fn minimal_psbt_with_counts(input_count: usize, output_count: usize) -> Vec<u8> {
848 let mut data = Vec::new();
849 data.extend_from_slice(b"psbt\xFF");
850 write_kv(&mut data, &[global_key::VERSION], &2u32.to_le_bytes());
851 write_kv(&mut data, &[global_key::TX_VERSION], &2u32.to_le_bytes());
852 write_kv(
853 &mut data,
854 &[global_key::FALLBACK_LOCKTIME],
855 &0u32.to_le_bytes(),
856 );
857 write_kv(
858 &mut data,
859 &[global_key::INPUT_COUNT],
860 &compact_size(input_count),
861 );
862 write_kv(
863 &mut data,
864 &[global_key::OUTPUT_COUNT],
865 &compact_size(output_count),
866 );
867 data.push(0x00);
868 data
869 }
870
871 #[test]
874 fn test_psbtv2_new_defaults() {
875 let psbt = PsbtV2::new();
876 assert_eq!(psbt.tx_version, 2);
877 assert_eq!(psbt.fallback_locktime, 0);
878 assert_eq!(psbt.modifiable.to_byte(), 0);
879 assert!(psbt.inputs.is_empty());
880 assert!(psbt.outputs.is_empty());
881 }
882
883 #[test]
884 fn test_psbtv2_interactive() {
885 let psbt = PsbtV2::new_interactive();
886 assert!(psbt.modifiable.inputs_modifiable());
887 assert!(psbt.modifiable.outputs_modifiable());
888 }
889
890 #[test]
891 fn test_add_input() {
892 let mut psbt = PsbtV2::new();
893 let idx = psbt.add_input(PsbtV2Input::new([0xAA; 32], 0));
894 assert_eq!(idx, 0);
895 assert_eq!(psbt.inputs.len(), 1);
896 assert_eq!(psbt.inputs[0].previous_txid, [0xAA; 32]);
897 }
898
899 #[test]
900 fn test_add_multiple_inputs() {
901 let mut psbt = PsbtV2::new();
902 let i0 = psbt.add_input(PsbtV2Input::new([0x01; 32], 0));
903 let i1 = psbt.add_input(PsbtV2Input::new([0x02; 32], 1));
904 let i2 = psbt.add_input(PsbtV2Input::new([0x03; 32], 2));
905 assert_eq!(i0, 0);
906 assert_eq!(i1, 1);
907 assert_eq!(i2, 2);
908 assert_eq!(psbt.inputs[2].output_index, 2);
909 }
910
911 #[test]
912 fn test_add_output() {
913 let mut psbt = PsbtV2::new();
914 let idx = psbt.add_output(PsbtV2Output::new(50_000, vec![0x00, 0x14]));
915 assert_eq!(idx, 0);
916 assert_eq!(psbt.outputs.len(), 1);
917 assert_eq!(psbt.outputs[0].amount, 50_000);
918 }
919
920 #[test]
921 fn test_input_default_sequence() {
922 let input = PsbtV2Input::new([0; 32], 0);
923 assert_eq!(input.sequence, 0xFFFFFFFF);
924 }
925
926 #[test]
927 fn test_input_with_sequence() {
928 let input = PsbtV2Input::new([0; 32], 0).with_sequence(0xFFFFFFFD);
929 assert_eq!(input.sequence, 0xFFFFFFFD);
930 }
931
932 #[test]
933 fn test_input_rbf_sequence() {
934 let input = PsbtV2Input::new([0; 32], 0).with_sequence(0xFFFFFFFD);
936 assert_eq!(input.sequence, 0xFFFFFFFD);
937 assert_ne!(input.sequence, 0xFFFFFFFF);
938 }
939
940 #[test]
943 fn test_set_witness_utxo() {
944 let mut input = PsbtV2Input::new([0; 32], 0);
945 let script = vec![0x00, 0x14, 0xAA, 0xBB];
946 input.set_witness_utxo(100_000, &script);
947 assert_eq!(input.extra.len(), 1);
948 assert_eq!(input.extra[0].0, vec![input_key::WITNESS_UTXO]);
949 }
950
951 #[test]
952 fn test_witness_utxo_encoding() {
953 let mut input = PsbtV2Input::new([0; 32], 0);
954 let script = vec![0x00, 0x14, 0xAA, 0xBB];
955 input.set_witness_utxo(100_000, &script);
956 let value = &input.extra[0].1;
957 let amount = u64::from_le_bytes(value[0..8].try_into().unwrap());
959 assert_eq!(amount, 100_000);
960 assert_eq!(value[8], 4); assert_eq!(&value[9..13], &script[..]);
963 }
964
965 #[test]
966 fn test_witness_utxo_encoding_large_script_uses_compact_size() {
967 let mut input = PsbtV2Input::new([0; 32], 0);
968 let script = vec![0xAB; 300];
969 input.set_witness_utxo(100_000, &script);
970 let value = &input.extra[0].1;
971
972 assert_eq!(value[8], 0xFD);
974 assert_eq!(value[9], 0x2C);
975 assert_eq!(value[10], 0x01);
976 assert_eq!(&value[11..], &script[..]);
977 }
978
979 #[test]
982 fn test_computed_locktime_fallback() {
983 let mut psbt = PsbtV2::new();
984 psbt.fallback_locktime = 800_000;
985 assert_eq!(psbt.computed_locktime(), 800_000);
986 }
987
988 #[test]
989 fn test_computed_locktime_no_inputs() {
990 let psbt = PsbtV2::new();
991 assert_eq!(psbt.computed_locktime(), 0);
992 }
993
994 #[test]
995 fn test_computed_locktime_height_priority() {
996 let mut psbt = PsbtV2::new();
997 let mut i1 = PsbtV2Input::new([0; 32], 0);
998 i1.required_time_locktime = Some(1_700_000_000);
999 i1.required_height_locktime = Some(800_000);
1000 psbt.add_input(i1);
1001 assert_eq!(psbt.computed_locktime(), 800_000);
1002 }
1003
1004 #[test]
1005 fn test_computed_locktime_time_only() {
1006 let mut psbt = PsbtV2::new();
1007 let mut i1 = PsbtV2Input::new([0; 32], 0);
1008 i1.required_time_locktime = Some(1_700_000_000);
1009 psbt.add_input(i1);
1010 assert_eq!(psbt.computed_locktime(), 1_700_000_000);
1011 }
1012
1013 #[test]
1014 fn test_computed_locktime_max_across_inputs() {
1015 let mut psbt = PsbtV2::new();
1016 let mut i1 = PsbtV2Input::new([0; 32], 0);
1017 i1.required_height_locktime = Some(100_000);
1018 let mut i2 = PsbtV2Input::new([1; 32], 0);
1019 i2.required_height_locktime = Some(200_000);
1020 psbt.add_input(i1);
1021 psbt.add_input(i2);
1022 assert_eq!(psbt.computed_locktime(), 200_000);
1023 }
1024
1025 #[test]
1026 fn test_computed_locktime_max_time_across_inputs() {
1027 let mut psbt = PsbtV2::new();
1028 let mut i1 = PsbtV2Input::new([0; 32], 0);
1029 i1.required_time_locktime = Some(1_600_000_000);
1030 let mut i2 = PsbtV2Input::new([1; 32], 0);
1031 i2.required_time_locktime = Some(1_700_000_000);
1032 psbt.add_input(i1);
1033 psbt.add_input(i2);
1034 assert_eq!(psbt.computed_locktime(), 1_700_000_000);
1035 }
1036
1037 #[test]
1038 fn test_computed_locktime_inputs_without_timelocks() {
1039 let mut psbt = PsbtV2::new();
1040 psbt.fallback_locktime = 500_000;
1041 psbt.add_input(PsbtV2Input::new([0; 32], 0));
1042 psbt.add_input(PsbtV2Input::new([1; 32], 0));
1043 assert_eq!(psbt.computed_locktime(), 500_000);
1045 }
1046
1047 #[test]
1050 fn test_modifiable_flags_none() {
1051 let f = ModifiableFlags::NONE;
1052 assert!(!f.inputs_modifiable());
1053 assert!(!f.outputs_modifiable());
1054 }
1055
1056 #[test]
1057 fn test_modifiable_flags_inputs_only() {
1058 let f = ModifiableFlags::INPUTS_MODIFIABLE;
1059 assert!(f.inputs_modifiable());
1060 assert!(!f.outputs_modifiable());
1061 }
1062
1063 #[test]
1064 fn test_modifiable_flags_outputs_only() {
1065 let f = ModifiableFlags::OUTPUTS_MODIFIABLE;
1066 assert!(!f.inputs_modifiable());
1067 assert!(f.outputs_modifiable());
1068 }
1069
1070 #[test]
1071 fn test_modifiable_flags_union() {
1072 let f = ModifiableFlags::INPUTS_MODIFIABLE.union(ModifiableFlags::OUTPUTS_MODIFIABLE);
1073 assert!(f.inputs_modifiable());
1074 assert!(f.outputs_modifiable());
1075 assert_eq!(f.to_byte(), 0x03);
1076 }
1077
1078 #[test]
1079 fn test_modifiable_flags_sighash_single() {
1080 let f = ModifiableFlags::HAS_SIGHASH_SINGLE;
1081 assert!(!f.inputs_modifiable());
1082 assert!(!f.outputs_modifiable());
1083 assert_eq!(f.to_byte(), 0x04);
1084 }
1085
1086 #[test]
1087 fn test_modifiable_flags_all() {
1088 let f = ModifiableFlags::INPUTS_MODIFIABLE
1089 .union(ModifiableFlags::OUTPUTS_MODIFIABLE)
1090 .union(ModifiableFlags::HAS_SIGHASH_SINGLE);
1091 assert_eq!(f.to_byte(), 0x07);
1092 }
1093
1094 #[test]
1095 fn test_modifiable_flags_from_byte() {
1096 let f = ModifiableFlags::from_byte(0xFF);
1097 assert!(f.inputs_modifiable());
1098 assert!(f.outputs_modifiable());
1099 assert_eq!(f.to_byte(), 0xFF);
1100 }
1101
1102 #[test]
1105 fn test_serialize_roundtrip() {
1106 let mut psbt = PsbtV2::new();
1107 psbt.tx_version = 2;
1108 psbt.fallback_locktime = 800_000;
1109 psbt.modifiable = ModifiableFlags::INPUTS_MODIFIABLE;
1110
1111 let input = PsbtV2Input::new([0xBB; 32], 1).with_sequence(0xFFFFFFFD);
1112 psbt.add_input(input);
1113
1114 let output = PsbtV2Output::new(50_000, vec![0xCC; 20]);
1115 psbt.add_output(output);
1116
1117 let serialized = psbt.serialize();
1118 let deserialized = PsbtV2::deserialize(&serialized).unwrap();
1119
1120 assert_eq!(deserialized.tx_version, 2);
1121 assert_eq!(deserialized.fallback_locktime, 800_000);
1122 assert!(deserialized.modifiable.inputs_modifiable());
1123 assert!(!deserialized.modifiable.outputs_modifiable());
1124 assert_eq!(deserialized.inputs.len(), 1);
1125 assert_eq!(deserialized.outputs.len(), 1);
1126 assert_eq!(deserialized.inputs[0].previous_txid, [0xBB; 32]);
1127 assert_eq!(deserialized.inputs[0].output_index, 1);
1128 assert_eq!(deserialized.inputs[0].sequence, 0xFFFFFFFD);
1129 assert_eq!(deserialized.outputs[0].amount, 50_000);
1130 }
1131
1132 #[test]
1133 fn test_serialize_empty_psbt_roundtrip() {
1134 let psbt = PsbtV2::new();
1135 let data = psbt.serialize();
1136 let rt = PsbtV2::deserialize(&data).unwrap();
1137 assert_eq!(rt.tx_version, 2);
1138 assert_eq!(rt.inputs.len(), 0);
1139 assert_eq!(rt.outputs.len(), 0);
1140 }
1141
1142 #[test]
1143 fn test_serialize_starts_with_magic() {
1144 let psbt = PsbtV2::new();
1145 let data = psbt.serialize();
1146 assert_eq!(&data[0..5], b"psbt\xFF");
1147 }
1148
1149 #[test]
1150 fn test_serialize_output_script_preserved() {
1151 let script = vec![0x76, 0xA9, 0x14, 0xAA, 0xBB, 0xCC];
1152 let mut psbt = PsbtV2::new();
1153 psbt.add_output(PsbtV2Output::new(1_000_000, script.clone()));
1154 let data = psbt.serialize();
1155 let rt = PsbtV2::deserialize(&data).unwrap();
1156 assert_eq!(rt.outputs[0].script, script);
1157 }
1158
1159 #[test]
1160 fn test_serialize_large_amount() {
1161 let mut psbt = PsbtV2::new();
1162 psbt.add_output(PsbtV2Output::new(21_000_000 * 100_000_000, vec![0x00]));
1163 let data = psbt.serialize();
1164 let rt = PsbtV2::deserialize(&data).unwrap();
1165 assert_eq!(rt.outputs[0].amount, 21_000_000 * 100_000_000);
1166 }
1167
1168 #[test]
1169 fn test_serialize_roundtrip_with_timelocks() {
1170 let mut psbt = PsbtV2::new();
1171 let mut input = PsbtV2Input::new([0xAA; 32], 0);
1172 input.required_time_locktime = Some(1_700_000_000);
1173 input.required_height_locktime = Some(800_000);
1174 psbt.add_input(input);
1175
1176 let data = psbt.serialize();
1177 let rt = PsbtV2::deserialize(&data).unwrap();
1178 assert_eq!(rt.inputs[0].required_time_locktime, Some(1_700_000_000));
1179 assert_eq!(rt.inputs[0].required_height_locktime, Some(800_000));
1180 }
1181
1182 #[test]
1185 fn test_deserialize_invalid_magic() {
1186 let result = PsbtV2::deserialize(b"not_a_psbt");
1187 assert!(result.is_err());
1188 }
1189
1190 #[test]
1191 fn test_deserialize_too_short() {
1192 let result = PsbtV2::deserialize(b"psbt");
1193 assert!(result.is_err());
1194 }
1195
1196 #[test]
1197 fn test_deserialize_empty() {
1198 let result = PsbtV2::deserialize(b"");
1199 assert!(result.is_err());
1200 }
1201
1202 #[test]
1203 fn test_deserialize_wrong_version() {
1204 let psbt = PsbtV2::new();
1206 let data = psbt.serialize();
1207 let mut patched = data.clone();
1209 patched[8] = 1; let result = PsbtV2::deserialize(&patched);
1214 assert!(result.is_err());
1215 }
1216
1217 #[test]
1218 fn test_deserialize_rejects_tx_modifiable_invalid_len() {
1219 let mut data = Vec::new();
1220 data.extend_from_slice(b"psbt\xFF");
1221 write_kv(&mut data, &[global_key::VERSION], &2u32.to_le_bytes());
1222 write_kv(&mut data, &[global_key::TX_VERSION], &2u32.to_le_bytes());
1223 write_kv(
1224 &mut data,
1225 &[global_key::FALLBACK_LOCKTIME],
1226 &0u32.to_le_bytes(),
1227 );
1228 write_kv(&mut data, &[global_key::INPUT_COUNT], &compact_size(0));
1229 write_kv(&mut data, &[global_key::OUTPUT_COUNT], &compact_size(0));
1230 write_kv(&mut data, &[global_key::TX_MODIFIABLE], &[0x01, 0x02]); data.push(0x00); let result = PsbtV2::deserialize(&data);
1234 assert!(result.is_err());
1235 }
1236
1237 #[test]
1238 fn test_deserialize_rejects_missing_tx_version() {
1239 let mut data = Vec::new();
1240 data.extend_from_slice(b"psbt\xFF");
1241 write_kv(&mut data, &[global_key::VERSION], &2u32.to_le_bytes());
1242 write_kv(
1243 &mut data,
1244 &[global_key::FALLBACK_LOCKTIME],
1245 &0u32.to_le_bytes(),
1246 );
1247 write_kv(&mut data, &[global_key::INPUT_COUNT], &compact_size(0));
1248 write_kv(&mut data, &[global_key::OUTPUT_COUNT], &compact_size(0));
1249 data.push(0x00); let result = PsbtV2::deserialize(&data);
1252 assert!(result.is_err());
1253 }
1254
1255 #[test]
1256 fn test_deserialize_rejects_duplicate_global_key() {
1257 let mut data = Vec::new();
1258 data.extend_from_slice(b"psbt\xFF");
1259 write_kv(&mut data, &[global_key::VERSION], &2u32.to_le_bytes());
1260 write_kv(&mut data, &[global_key::TX_VERSION], &2u32.to_le_bytes());
1261 write_kv(&mut data, &[global_key::TX_VERSION], &2u32.to_le_bytes()); write_kv(
1263 &mut data,
1264 &[global_key::FALLBACK_LOCKTIME],
1265 &0u32.to_le_bytes(),
1266 );
1267 write_kv(&mut data, &[global_key::INPUT_COUNT], &compact_size(0));
1268 write_kv(&mut data, &[global_key::OUTPUT_COUNT], &compact_size(0));
1269 data.push(0x00);
1270
1271 let result = PsbtV2::deserialize(&data);
1272 assert!(result.is_err());
1273 }
1274
1275 #[test]
1276 fn test_deserialize_rejects_unterminated_global_map() {
1277 let mut data = Vec::new();
1278 data.extend_from_slice(b"psbt\xFF");
1279 write_kv(&mut data, &[global_key::VERSION], &2u32.to_le_bytes());
1280 write_kv(&mut data, &[global_key::TX_VERSION], &2u32.to_le_bytes());
1281 write_kv(
1282 &mut data,
1283 &[global_key::FALLBACK_LOCKTIME],
1284 &0u32.to_le_bytes(),
1285 );
1286 write_kv(&mut data, &[global_key::INPUT_COUNT], &compact_size(0));
1287 write_kv(&mut data, &[global_key::OUTPUT_COUNT], &compact_size(0));
1288 assert!(PsbtV2::deserialize(&data).is_err());
1290 }
1291
1292 #[test]
1293 fn test_deserialize_rejects_input_missing_previous_txid() {
1294 let mut data = minimal_psbt_with_counts(1, 0);
1295 write_kv(&mut data, &[input_key::OUTPUT_INDEX], &0u32.to_le_bytes());
1296 data.push(0x00);
1297
1298 let result = PsbtV2::deserialize(&data);
1299 assert!(result.is_err());
1300 }
1301
1302 #[test]
1303 fn test_deserialize_rejects_input_missing_output_index() {
1304 let mut data = minimal_psbt_with_counts(1, 0);
1305 write_kv(&mut data, &[input_key::PREVIOUS_TXID], &[0xAA; 32]);
1306 data.push(0x00);
1307
1308 let result = PsbtV2::deserialize(&data);
1309 assert!(result.is_err());
1310 }
1311
1312 #[test]
1313 fn test_deserialize_rejects_duplicate_input_key() {
1314 let mut data = minimal_psbt_with_counts(1, 0);
1315 write_kv(&mut data, &[input_key::PREVIOUS_TXID], &[0xAA; 32]);
1316 write_kv(&mut data, &[input_key::PREVIOUS_TXID], &[0xBB; 32]); write_kv(&mut data, &[input_key::OUTPUT_INDEX], &0u32.to_le_bytes());
1318 data.push(0x00);
1319
1320 let result = PsbtV2::deserialize(&data);
1321 assert!(result.is_err());
1322 }
1323
1324 #[test]
1325 fn test_deserialize_rejects_output_missing_amount() {
1326 let mut data = minimal_psbt_with_counts(0, 1);
1327 write_kv(&mut data, &[output_key::SCRIPT], &[0x51]);
1328 data.push(0x00);
1329
1330 let result = PsbtV2::deserialize(&data);
1331 assert!(result.is_err());
1332 }
1333
1334 #[test]
1335 fn test_deserialize_rejects_output_missing_script() {
1336 let mut data = minimal_psbt_with_counts(0, 1);
1337 write_kv(&mut data, &[output_key::AMOUNT], &50_000u64.to_le_bytes());
1338 data.push(0x00);
1339
1340 let result = PsbtV2::deserialize(&data);
1341 assert!(result.is_err());
1342 }
1343
1344 #[test]
1345 fn test_deserialize_rejects_duplicate_output_key() {
1346 let mut data = minimal_psbt_with_counts(0, 1);
1347 write_kv(&mut data, &[output_key::AMOUNT], &50_000u64.to_le_bytes());
1348 write_kv(&mut data, &[output_key::AMOUNT], &60_000u64.to_le_bytes()); write_kv(&mut data, &[output_key::SCRIPT], &[0x51]);
1350 data.push(0x00);
1351
1352 let result = PsbtV2::deserialize(&data);
1353 assert!(result.is_err());
1354 }
1355
1356 #[test]
1359 fn test_roundtrip_multiple_io() {
1360 let mut psbt = PsbtV2::new();
1361 for i in 0..3u8 {
1362 psbt.add_input(PsbtV2Input::new([i; 32], i as u32));
1363 psbt.add_output(PsbtV2Output::new(
1364 (i as u64 + 1) * 10_000,
1365 vec![0x00, 0x14, i],
1366 ));
1367 }
1368
1369 let data = psbt.serialize();
1370 let rt = PsbtV2::deserialize(&data).unwrap();
1371 assert_eq!(rt.inputs.len(), 3);
1372 assert_eq!(rt.outputs.len(), 3);
1373 assert_eq!(rt.inputs[2].previous_txid, [2; 32]);
1374 assert_eq!(rt.outputs[1].amount, 20_000);
1375 }
1376
1377 #[test]
1378 fn test_roundtrip_10_inputs() {
1379 let mut psbt = PsbtV2::new();
1380 for i in 0..10u8 {
1381 psbt.add_input(PsbtV2Input::new([i; 32], i as u32));
1382 }
1383 psbt.add_output(PsbtV2Output::new(1_000_000, vec![0x00]));
1384
1385 let data = psbt.serialize();
1386 let rt = PsbtV2::deserialize(&data).unwrap();
1387 assert_eq!(rt.inputs.len(), 10);
1388 for i in 0..10u8 {
1389 assert_eq!(rt.inputs[i as usize].previous_txid, [i; 32]);
1390 assert_eq!(rt.inputs[i as usize].output_index, i as u32);
1391 }
1392 }
1393
1394 #[test]
1395 fn test_roundtrip_asymmetric_io() {
1396 let mut psbt = PsbtV2::new();
1398 for i in 0..5u8 {
1399 psbt.add_input(PsbtV2Input::new([i; 32], 0));
1400 }
1401 for i in 0..2u8 {
1402 psbt.add_output(PsbtV2Output::new(50_000, vec![i]));
1403 }
1404
1405 let data = psbt.serialize();
1406 let rt = PsbtV2::deserialize(&data).unwrap();
1407 assert_eq!(rt.inputs.len(), 5);
1408 assert_eq!(rt.outputs.len(), 2);
1409 }
1410
1411 #[test]
1414 fn test_compact_size_small() {
1415 assert_eq!(compact_size(0), vec![0]);
1416 assert_eq!(compact_size(252), vec![252]);
1417 }
1418
1419 #[test]
1420 fn test_compact_size_boundary_253() {
1421 let cs = compact_size(253);
1423 assert_eq!(cs[0], 0xFD);
1424 assert_eq!(u16::from_le_bytes([cs[1], cs[2]]), 253);
1425 }
1426
1427 #[test]
1428 fn test_compact_size_medium() {
1429 let cs = compact_size(300);
1430 assert_eq!(cs[0], 0xFD);
1431 assert_eq!(u16::from_le_bytes([cs[1], cs[2]]), 300);
1432 }
1433
1434 #[test]
1435 fn test_compact_size_max_u16() {
1436 let cs = compact_size(65535);
1437 assert_eq!(cs[0], 0xFD);
1438 assert_eq!(u16::from_le_bytes([cs[1], cs[2]]), 65535);
1439 }
1440
1441 #[test]
1442 fn test_compact_size_large() {
1443 let cs = compact_size(70000);
1444 assert_eq!(cs[0], 0xFE);
1445 assert_eq!(u32::from_le_bytes([cs[1], cs[2], cs[3], cs[4]]), 70000);
1446 }
1447
1448 #[test]
1449 #[cfg(target_pointer_width = "64")]
1450 fn test_compact_size_very_large_uses_u64_variant() {
1451 let n = 0x1_0000_0000usize;
1452 let cs = compact_size(n);
1453 assert_eq!(cs[0], 0xFF);
1454 assert_eq!(
1455 u64::from_le_bytes([cs[1], cs[2], cs[3], cs[4], cs[5], cs[6], cs[7], cs[8]]),
1456 n as u64
1457 );
1458 }
1459
1460 #[test]
1463 fn test_read_compact_size_small() {
1464 assert_eq!(read_compact_size(&[42]).unwrap(), 42);
1465 assert_eq!(read_compact_size(&[0]).unwrap(), 0);
1466 assert_eq!(read_compact_size(&[252]).unwrap(), 252);
1467 }
1468
1469 #[test]
1470 fn test_read_compact_size_medium() {
1471 let data = [0xFD, 0x00, 0x01]; assert_eq!(read_compact_size(&data).unwrap(), 256);
1473 }
1474
1475 #[test]
1476 fn test_read_compact_size_rejects_non_canonical() {
1477 let data = [0xFD, 0xFC, 0x00];
1479 assert!(read_compact_size(&data).is_err());
1480 }
1481
1482 #[test]
1483 fn test_read_compact_size_rejects_non_canonical_u32_form() {
1484 let data = [0xFE, 0xFF, 0xFF, 0x00, 0x00];
1486 assert!(read_compact_size(&data).is_err());
1487 }
1488
1489 #[test]
1490 fn test_read_compact_size_rejects_non_canonical_u64_form() {
1491 let data = [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00];
1493 assert!(read_compact_size(&data).is_err());
1494 }
1495
1496 #[test]
1497 fn test_read_compact_size_rejects_trailing_bytes() {
1498 let data = [0x01, 0x00];
1499 assert!(read_compact_size(&data).is_err());
1500 }
1501
1502 #[test]
1503 fn test_read_compact_size_empty() {
1504 assert!(read_compact_size(&[]).is_err());
1505 }
1506
1507 #[test]
1508 fn test_read_compact_size_at_reports_consumed_bytes() {
1509 let data = [0xFD, 0x00, 0x01, 0xAA];
1510 let (v1, c1) = read_compact_size_at(&data, 0).unwrap();
1511 assert_eq!(v1, 256);
1512 assert_eq!(c1, 3);
1513 let (v2, c2) = read_compact_size_at(&data, 3).unwrap();
1514 assert_eq!(v2, 0xAA);
1515 assert_eq!(c2, 1);
1516 }
1517
1518 #[test]
1519 fn test_read_compact_size_at_rejects_non_canonical() {
1520 let data = [0xFE, 0x01, 0x00, 0x00, 0x00];
1521 assert!(read_compact_size_at(&data, 0).is_err());
1522 }
1523
1524 #[test]
1527 fn test_write_kv_roundtrip() {
1528 let mut buf = Vec::new();
1529 write_kv(&mut buf, &[0x42], &[0xAA, 0xBB, 0xCC]);
1530 let (key, val, consumed) = read_kv(&buf).unwrap();
1531 assert_eq!(key, vec![0x42]);
1532 assert_eq!(val, vec![0xAA, 0xBB, 0xCC]);
1533 assert_eq!(consumed, buf.len());
1534 }
1535
1536 #[test]
1537 fn test_write_kv_empty_value() {
1538 let mut buf = Vec::new();
1539 write_kv(&mut buf, &[0x01], &[]);
1540 let (key, val, consumed) = read_kv(&buf).unwrap();
1541 assert_eq!(key, vec![0x01]);
1542 assert!(val.is_empty());
1543 assert_eq!(consumed, buf.len());
1544 }
1545
1546 #[test]
1549 fn test_input_serialize_basic() {
1550 let input = PsbtV2Input::new([0xAA; 32], 5);
1551 let data = input.serialize();
1552 assert_eq!(data[data.len() - 1], 0x00);
1554 }
1555
1556 #[test]
1557 fn test_input_serialize_with_witness_utxo() {
1558 let mut input = PsbtV2Input::new([0; 32], 0);
1559 input.set_witness_utxo(50_000, &[0x00, 0x14]);
1560 let data = input.serialize();
1561 assert!(data.len() > 40); }
1563
1564 #[test]
1567 fn test_output_serialize_basic() {
1568 let output = PsbtV2Output::new(100_000, vec![0xAA, 0xBB]);
1569 let data = output.serialize();
1570 assert_eq!(data[data.len() - 1], 0x00);
1571 }
1572
1573 #[test]
1576 fn test_default_trait() {
1577 let psbt = PsbtV2::default();
1578 assert_eq!(psbt.tx_version, 2);
1579 }
1580
1581 #[test]
1584 fn test_global_key_values() {
1585 assert_eq!(global_key::TX_VERSION, 0x02);
1586 assert_eq!(global_key::FALLBACK_LOCKTIME, 0x03);
1587 assert_eq!(global_key::INPUT_COUNT, 0x04);
1588 assert_eq!(global_key::OUTPUT_COUNT, 0x05);
1589 assert_eq!(global_key::TX_MODIFIABLE, 0x06);
1590 assert_eq!(global_key::VERSION, 0xFB);
1591 }
1592
1593 #[test]
1594 fn test_input_key_values() {
1595 assert_eq!(input_key::PREVIOUS_TXID, 0x0E);
1596 assert_eq!(input_key::OUTPUT_INDEX, 0x0F);
1597 assert_eq!(input_key::SEQUENCE, 0x10);
1598 assert_eq!(input_key::REQUIRED_TIME_LOCKTIME, 0x11);
1599 assert_eq!(input_key::REQUIRED_HEIGHT_LOCKTIME, 0x12);
1600 assert_eq!(input_key::NON_WITNESS_UTXO, 0x00);
1601 assert_eq!(input_key::WITNESS_UTXO, 0x01);
1602 }
1603
1604 #[test]
1605 fn test_output_key_values() {
1606 assert_eq!(output_key::AMOUNT, 0x03);
1607 assert_eq!(output_key::SCRIPT, 0x04);
1608 assert_eq!(output_key::REDEEM_SCRIPT, 0x00);
1609 assert_eq!(output_key::WITNESS_SCRIPT, 0x01);
1610 }
1611}