1use core::str::FromStr;
15use core::{cmp, fmt};
16
17use hashes::{sha256d, Hash};
18use internals::write_err;
19use io::{Read, Write};
20use units::parse::{self, ParseIntError};
21
22use super::Weight;
23use crate::blockdata::locktime::absolute::{self, Height, Time};
24use crate::blockdata::locktime::relative::{self, TimeOverflowError};
25use crate::blockdata::script::{Script, ScriptBuf};
26use crate::blockdata::witness::Witness;
27use crate::blockdata::FeeRate;
28use crate::consensus::{encode, Decodable, Encodable};
29use crate::error::{ContainsPrefixError, MissingPrefixError, PrefixedHexError, UnprefixedHexError};
30use crate::internal_macros::{impl_consensus_encoding, impl_hashencode};
31use crate::prelude::*;
32#[cfg(doc)]
33use crate::sighash::{EcdsaSighashType, TapSighashType};
34use crate::{Amount, SignedAmount, VarInt};
35
36#[rustfmt::skip] #[cfg(feature = "bitcoinconsensus")]
38#[doc(inline)]
39pub use crate::consensus::validation::TxVerifyError;
40
41hashes::hash_newtype! {
42 pub struct Txid(sha256d::Hash);
49
50 pub struct Wtxid(sha256d::Hash);
52}
53impl_hashencode!(Txid);
54impl_hashencode!(Wtxid);
55
56const SEGWIT_MARKER: u8 = 0x00;
58const SEGWIT_FLAG: u8 = 0x01;
60
61#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
67pub struct OutPoint {
68 pub txid: Txid,
70 pub vout: u32,
72}
73#[cfg(feature = "serde")]
74crate::serde_utils::serde_struct_human_string_impl!(OutPoint, "an OutPoint", txid, vout);
75
76impl OutPoint {
77 const SIZE: usize = 32 + 4; #[inline]
82 pub const fn new(txid: Txid, vout: u32) -> OutPoint { OutPoint { txid, vout } }
83
84 #[inline]
88 pub fn null() -> OutPoint { OutPoint { txid: Hash::all_zeros(), vout: u32::MAX } }
89
90 #[inline]
106 pub fn is_null(&self) -> bool { *self == OutPoint::null() }
107}
108
109impl Default for OutPoint {
110 fn default() -> Self { OutPoint::null() }
111}
112
113impl fmt::Display for OutPoint {
114 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
115 write!(f, "{}:{}", self.txid, self.vout)
116 }
117}
118
119#[derive(Debug, Clone, PartialEq, Eq)]
121#[non_exhaustive]
122pub enum ParseOutPointError {
123 Txid(hex::HexToArrayError),
125 Vout(crate::error::ParseIntError),
127 Format,
129 TooLong,
131 VoutNotCanonical,
133}
134
135internals::impl_from_infallible!(ParseOutPointError);
136
137impl fmt::Display for ParseOutPointError {
138 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
139 use ParseOutPointError::*;
140
141 match *self {
142 Txid(ref e) => write_err!(f, "error parsing TXID"; e),
143 Vout(ref e) => write_err!(f, "error parsing vout"; e),
144 Format => write!(f, "OutPoint not in <txid>:<vout> format"),
145 TooLong => write!(f, "vout should be at most 10 digits"),
146 VoutNotCanonical => write!(f, "no leading zeroes or + allowed in vout part"),
147 }
148 }
149}
150
151#[cfg(feature = "std")]
152impl std::error::Error for ParseOutPointError {
153 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
154 use ParseOutPointError::*;
155
156 match self {
157 Txid(e) => Some(e),
158 Vout(e) => Some(e),
159 Format | TooLong | VoutNotCanonical => None,
160 }
161 }
162}
163
164fn parse_vout(s: &str) -> Result<u32, ParseOutPointError> {
168 if s.len() > 1 {
169 let first = s.chars().next().unwrap();
170 if first == '0' || first == '+' {
171 return Err(ParseOutPointError::VoutNotCanonical);
172 }
173 }
174 parse::int(s).map_err(ParseOutPointError::Vout)
175}
176
177impl core::str::FromStr for OutPoint {
178 type Err = ParseOutPointError;
179
180 fn from_str(s: &str) -> Result<Self, Self::Err> {
181 if s.len() > 75 {
182 return Err(ParseOutPointError::TooLong);
184 }
185 let find = s.find(':');
186 if find.is_none() || find != s.rfind(':') {
187 return Err(ParseOutPointError::Format);
188 }
189 let colon = find.unwrap();
190 if colon == 0 || colon == s.len() - 1 {
191 return Err(ParseOutPointError::Format);
192 }
193 Ok(OutPoint {
194 txid: s[..colon].parse().map_err(ParseOutPointError::Txid)?,
195 vout: parse_vout(&s[colon + 1..])?,
196 })
197 }
198}
199
200#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
210#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
211#[cfg_attr(feature = "serde", serde(crate = "actual_serde"))]
212pub struct TxIn {
213 pub previous_output: OutPoint,
215 pub script_sig: ScriptBuf,
218 pub sequence: Sequence,
223 pub witness: Witness,
229}
230
231impl TxIn {
232 const BASE_WEIGHT: Weight =
236 Weight::from_vb_unwrap(OutPoint::SIZE as u64 + Sequence::SIZE as u64);
237
238 pub fn enables_lock_time(&self) -> bool { self.sequence != Sequence::MAX }
248
249 pub fn legacy_weight(&self) -> Weight {
259 Weight::from_non_witness_data_size(self.base_size() as u64)
260 }
261
262 pub fn segwit_weight(&self) -> Weight {
274 Weight::from_non_witness_data_size(self.base_size() as u64)
275 + Weight::from_witness_data_size(self.witness.size() as u64)
276 }
277
278 pub fn base_size(&self) -> usize {
282 let mut size = OutPoint::SIZE;
283
284 size += VarInt::from(self.script_sig.len()).size();
285 size += self.script_sig.len();
286
287 size + Sequence::SIZE
288 }
289
290 pub fn total_size(&self) -> usize { self.base_size() + self.witness.size() }
294}
295
296impl Default for TxIn {
297 fn default() -> TxIn {
298 TxIn {
299 previous_output: OutPoint::default(),
300 script_sig: ScriptBuf::new(),
301 sequence: Sequence::MAX,
302 witness: Witness::default(),
303 }
304 }
305}
306
307#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
322#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
323#[cfg_attr(feature = "serde", serde(crate = "actual_serde"))]
324pub struct Sequence(pub u32);
325
326impl Sequence {
327 pub const MAX: Self = Sequence(0xFFFFFFFF);
331 pub const ZERO: Self = Sequence(0);
335 pub const ENABLE_LOCKTIME_NO_RBF: Self = Sequence::MIN_NO_RBF;
338 pub const ENABLE_RBF_NO_LOCKTIME: Self = Sequence(0xFFFFFFFD);
341
342 const SIZE: usize = 4; const MIN_NO_RBF: Self = Sequence(0xFFFFFFFE);
353 const LOCK_TIME_DISABLE_FLAG_MASK: u32 = 0x80000000;
355 const LOCK_TYPE_MASK: u32 = 0x00400000;
357
358 #[inline]
360 pub fn enables_absolute_lock_time(&self) -> bool { *self != Sequence::MAX }
361
362 #[inline]
382 pub fn is_final(&self) -> bool { !self.enables_absolute_lock_time() }
383
384 #[inline]
389 pub fn is_rbf(&self) -> bool { *self < Sequence::MIN_NO_RBF }
390
391 #[inline]
393 pub fn is_relative_lock_time(&self) -> bool {
394 self.0 & Sequence::LOCK_TIME_DISABLE_FLAG_MASK == 0
395 }
396
397 #[inline]
399 pub fn is_height_locked(&self) -> bool {
400 self.is_relative_lock_time() & (self.0 & Sequence::LOCK_TYPE_MASK == 0)
401 }
402
403 #[inline]
405 pub fn is_time_locked(&self) -> bool {
406 self.is_relative_lock_time() & (self.0 & Sequence::LOCK_TYPE_MASK > 0)
407 }
408
409 pub fn from_hex(s: &str) -> Result<Self, PrefixedHexError> {
411 let stripped = if let Some(stripped) = s.strip_prefix("0x") {
412 stripped
413 } else if let Some(stripped) = s.strip_prefix("0X") {
414 stripped
415 } else {
416 return Err(MissingPrefixError::new(s).into());
417 };
418
419 let sequence = parse::hex_u32(stripped)?;
420 Ok(Self::from_consensus(sequence))
421 }
422
423 pub fn from_unprefixed_hex(s: &str) -> Result<Self, UnprefixedHexError> {
425 if s.starts_with("0x") || s.starts_with("0X") {
426 return Err(ContainsPrefixError::new(s).into());
427 }
428 let lock_time = parse::hex_u32(s)?;
429 Ok(Self::from_consensus(lock_time))
430 }
431
432 #[inline]
434 pub fn from_height(height: u16) -> Self { Sequence(u32::from(height)) }
435
436 #[inline]
441 pub fn from_512_second_intervals(intervals: u16) -> Self {
442 Sequence(u32::from(intervals) | Sequence::LOCK_TYPE_MASK)
443 }
444
445 #[inline]
450 pub fn from_seconds_floor(seconds: u32) -> Result<Self, TimeOverflowError> {
451 if let Ok(interval) = u16::try_from(seconds / 512) {
452 Ok(Sequence::from_512_second_intervals(interval))
453 } else {
454 Err(TimeOverflowError::new(seconds))
455 }
456 }
457
458 #[inline]
463 pub fn from_seconds_ceil(seconds: u32) -> Result<Self, TimeOverflowError> {
464 if let Ok(interval) = u16::try_from((seconds + 511) / 512) {
465 Ok(Sequence::from_512_second_intervals(interval))
466 } else {
467 Err(TimeOverflowError::new(seconds))
468 }
469 }
470
471 #[inline]
473 pub fn from_consensus(n: u32) -> Self { Sequence(n) }
474
475 #[inline]
477 pub fn to_consensus_u32(self) -> u32 { self.0 }
478
479 #[inline]
481 pub fn to_relative_lock_time(&self) -> Option<relative::LockTime> {
482 use crate::locktime::relative::{Height, LockTime, Time};
483
484 if !self.is_relative_lock_time() {
485 return None;
486 }
487
488 let lock_value = self.low_u16();
489
490 if self.is_time_locked() {
491 Some(LockTime::from(Time::from_512_second_intervals(lock_value)))
492 } else {
493 Some(LockTime::from(Height::from(lock_value)))
494 }
495 }
496
497 fn low_u16(&self) -> u16 { self.0 as u16 }
501}
502
503impl Default for Sequence {
504 fn default() -> Self { Sequence::MAX }
506}
507
508impl From<Sequence> for u32 {
509 fn from(sequence: Sequence) -> u32 { sequence.0 }
510}
511
512impl fmt::Display for Sequence {
513 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, f) }
514}
515
516impl fmt::LowerHex for Sequence {
517 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::LowerHex::fmt(&self.0, f) }
518}
519
520impl fmt::UpperHex for Sequence {
521 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::UpperHex::fmt(&self.0, f) }
522}
523
524impl fmt::Debug for Sequence {
525 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
526 write!(f, "Sequence({:#010x})", self.0)
528 }
529}
530
531impl FromStr for Sequence {
532 type Err = ParseIntError;
533
534 fn from_str(s: &str) -> Result<Self, Self::Err> {
535 parse::int::<u32, &str>(s).map(Sequence::from_consensus)
536 }
537}
538
539impl TryFrom<&str> for Sequence {
540 type Error = ParseIntError;
541
542 fn try_from(s: &str) -> Result<Self, Self::Error> { Sequence::from_str(s) }
543}
544
545impl TryFrom<String> for Sequence {
546 type Error = ParseIntError;
547
548 fn try_from(s: String) -> Result<Self, Self::Error> { Sequence::from_str(&s) }
549}
550
551impl TryFrom<Box<str>> for Sequence {
552 type Error = ParseIntError;
553
554 fn try_from(s: Box<str>) -> Result<Self, Self::Error> { Sequence::from_str(&s) }
555}
556
557#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
569#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
570#[cfg_attr(feature = "serde", serde(crate = "actual_serde"))]
571pub struct TxOut {
572 pub value: Amount,
574 pub script_pubkey: ScriptBuf,
576}
577
578impl TxOut {
579 pub const NULL: Self =
581 TxOut { value: Amount::from_sat(0xffffffffffffffff), script_pubkey: ScriptBuf::new() };
582
583 pub fn weight(&self) -> Weight {
594 Weight::from_vb(self.size() as u64).expect("should never happen under normal conditions")
596 }
597
598 pub fn size(&self) -> usize { size_from_script_pubkey(&self.script_pubkey) }
602
603 pub fn minimal_non_dust(script_pubkey: ScriptBuf) -> Self {
613 TxOut { value: script_pubkey.minimal_non_dust(), script_pubkey }
614 }
615
616 pub fn minimal_non_dust_custom(script_pubkey: ScriptBuf, dust_relay_fee: FeeRate) -> Self {
628 TxOut { value: script_pubkey.minimal_non_dust_custom(dust_relay_fee), script_pubkey }
629 }
630}
631
632fn size_from_script_pubkey(script_pubkey: &Script) -> usize {
634 let len = script_pubkey.len();
635 Amount::SIZE + VarInt::from(len).size() + len
636}
637
638#[derive(Clone, PartialEq, Eq, Debug, Hash)]
694#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
695#[cfg_attr(feature = "serde", serde(crate = "actual_serde"))]
696pub struct Transaction {
697 pub version: Version,
699 pub lock_time: absolute::LockTime,
706 pub input: Vec<TxIn>,
708 pub output: Vec<TxOut>,
710}
711
712impl cmp::PartialOrd for Transaction {
713 fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> { Some(self.cmp(other)) }
714}
715impl cmp::Ord for Transaction {
716 fn cmp(&self, other: &Self) -> cmp::Ordering {
717 self.version
718 .cmp(&other.version)
719 .then(self.lock_time.to_consensus_u32().cmp(&other.lock_time.to_consensus_u32()))
720 .then(self.input.cmp(&other.input))
721 .then(self.output.cmp(&other.output))
722 }
723}
724
725impl Transaction {
726 pub const MAX_STANDARD_WEIGHT: Weight = Weight::from_wu(400_000);
729
730 #[deprecated(
734 since = "0.31.0",
735 note = "ntxid has been renamed to compute_ntxid to note that it's computationally expensive. use compute_ntxid() instead."
736 )]
737 pub fn ntxid(&self) -> sha256d::Hash { self.compute_ntxid() }
738
739 #[doc(alias = "ntxid")]
744 pub fn compute_ntxid(&self) -> sha256d::Hash {
745 let cloned_tx = Transaction {
746 version: self.version,
747 lock_time: self.lock_time,
748 input: self
749 .input
750 .iter()
751 .map(|txin| TxIn {
752 script_sig: ScriptBuf::new(),
753 witness: Witness::default(),
754 ..*txin
755 })
756 .collect(),
757 output: self.output.clone(),
758 };
759 cloned_tx.compute_txid().into()
760 }
761
762 #[deprecated(
766 since = "0.31.0",
767 note = "txid has been renamed to compute_txid to note that it's computationally expensive. use compute_txid() instead."
768 )]
769 pub fn txid(&self) -> Txid { self.compute_txid() }
770
771 #[doc(alias = "txid")]
777 pub fn compute_txid(&self) -> Txid {
778 let mut enc = Txid::engine();
779 self.version.consensus_encode(&mut enc).expect("engines don't error");
780 self.input.consensus_encode(&mut enc).expect("engines don't error");
781 self.output.consensus_encode(&mut enc).expect("engines don't error");
782 self.lock_time.consensus_encode(&mut enc).expect("engines don't error");
783 Txid::from_engine(enc)
784 }
785
786 #[deprecated(
790 since = "0.31.0",
791 note = "wtxid has been renamed to compute_wtxid to note that it's computationally expensive. use compute_wtxid() instead."
792 )]
793 pub fn wtxid(&self) -> Wtxid { self.compute_wtxid() }
794
795 #[doc(alias = "wtxid")]
801 pub fn compute_wtxid(&self) -> Wtxid {
802 let mut enc = Wtxid::engine();
803 self.consensus_encode(&mut enc).expect("engines don't error");
804 Wtxid::from_engine(enc)
805 }
806
807 #[inline]
826 pub fn weight(&self) -> Weight {
827 let wu = self.base_size() * 3 + self.total_size();
829 Weight::from_wu_usize(wu)
830 }
831
832 pub fn base_size(&self) -> usize {
836 let mut size: usize = 4; size += VarInt::from(self.input.len()).size();
839 size += self.input.iter().map(|input| input.base_size()).sum::<usize>();
840
841 size += VarInt::from(self.output.len()).size();
842 size += self.output.iter().map(|output| output.size()).sum::<usize>();
843
844 size + absolute::LockTime::SIZE
845 }
846
847 #[inline]
852 pub fn total_size(&self) -> usize {
853 let mut size: usize = 4; let uses_segwit = self.uses_segwit_serialization();
855
856 if uses_segwit {
857 size += 2; }
859
860 size += VarInt::from(self.input.len()).size();
861 size += self
862 .input
863 .iter()
864 .map(|input| if uses_segwit { input.total_size() } else { input.base_size() })
865 .sum::<usize>();
866
867 size += VarInt::from(self.output.len()).size();
868 size += self.output.iter().map(|output| output.size()).sum::<usize>();
869
870 size + absolute::LockTime::SIZE
871 }
872
873 #[inline]
885 pub fn vsize(&self) -> usize {
886 self.weight().to_vbytes_ceil() as usize
888 }
889
890 #[doc(alias = "is_coin_base")] pub fn is_coinbase(&self) -> bool {
898 self.input.len() == 1 && self.input[0].previous_output.is_null()
899 }
900
901 pub fn is_explicitly_rbf(&self) -> bool {
911 self.input.iter().any(|input| input.sequence.is_rbf())
912 }
913
914 pub fn is_absolute_timelock_satisfied(&self, height: Height, time: Time) -> bool {
922 if !self.is_lock_time_enabled() {
923 return true;
924 }
925 self.lock_time.is_satisfied_by(height, time)
926 }
927
928 pub fn is_lock_time_enabled(&self) -> bool { self.input.iter().any(|i| i.enables_lock_time()) }
932
933 pub fn script_pubkey_lens(&self) -> impl Iterator<Item = usize> + '_ {
939 self.output.iter().map(|txout| txout.script_pubkey.len())
940 }
941
942 pub fn total_sigop_cost<S>(&self, mut spent: S) -> usize
955 where
956 S: FnMut(&OutPoint) -> Option<TxOut>,
957 {
958 let mut cost = self.count_p2pk_p2pkh_sigops().saturating_mul(4);
959
960 cost = cost.saturating_add(self.count_p2sh_sigops(&mut spent).saturating_mul(4));
962 cost.saturating_add(self.count_witness_sigops(&mut spent))
963 }
964
965 fn count_p2pk_p2pkh_sigops(&self) -> usize {
971 let mut count: usize = 0;
972 for input in &self.input {
973 count = count.saturating_add(input.script_sig.count_sigops_legacy());
975 }
976 for output in &self.output {
977 count = count.saturating_add(output.script_pubkey.count_sigops_legacy());
978 }
979 count
980 }
981
982 fn count_p2sh_sigops<S>(&self, spent: &mut S) -> usize
984 where
985 S: FnMut(&OutPoint) -> Option<TxOut>,
986 {
987 fn count_sigops(prevout: &TxOut, input: &TxIn) -> usize {
988 let mut count: usize = 0;
989 if prevout.script_pubkey.is_p2sh() {
990 if let Some(redeem) = input.script_sig.last_pushdata() {
991 count =
992 count.saturating_add(Script::from_bytes(redeem.as_bytes()).count_sigops());
993 }
994 }
995 count
996 }
997
998 let mut count: usize = 0;
999 for input in &self.input {
1000 if let Some(prevout) = spent(&input.previous_output) {
1001 count = count.saturating_add(count_sigops(&prevout, input));
1002 }
1003 }
1004 count
1005 }
1006
1007 fn count_witness_sigops<S>(&self, spent: &mut S) -> usize
1009 where
1010 S: FnMut(&OutPoint) -> Option<TxOut>,
1011 {
1012 fn count_sigops_with_witness_program(witness: &Witness, witness_program: &Script) -> usize {
1013 if witness_program.is_p2wpkh() {
1014 1
1015 } else if witness_program.is_p2wsh() {
1016 witness.last().map(Script::from_bytes).map(|s| s.count_sigops()).unwrap_or(0)
1018 } else {
1019 0
1020 }
1021 }
1022
1023 fn count_sigops(prevout: TxOut, input: &TxIn) -> usize {
1024 let script_sig = &input.script_sig;
1025 let witness = &input.witness;
1026
1027 let witness_program = if prevout.script_pubkey.is_witness_program() {
1028 &prevout.script_pubkey
1029 } else if prevout.script_pubkey.is_p2sh() && script_sig.is_push_only() {
1030 if let Some(push_bytes) = script_sig.last_pushdata() {
1033 Script::from_bytes(push_bytes.as_bytes())
1034 } else {
1035 return 0;
1036 }
1037 } else {
1038 return 0;
1039 };
1040
1041 count_sigops_with_witness_program(witness, witness_program)
1043 }
1044
1045 let mut count: usize = 0;
1046 for input in &self.input {
1047 if let Some(prevout) = spent(&input.previous_output) {
1048 count = count.saturating_add(count_sigops(prevout, input));
1049 }
1050 }
1051 count
1052 }
1053
1054 fn uses_segwit_serialization(&self) -> bool {
1056 if self.input.iter().any(|input| !input.witness.is_empty()) {
1057 return true;
1058 }
1059 self.input.is_empty()
1062 }
1063
1064 #[inline]
1066 pub fn tx_in(&self, input_index: usize) -> Result<&TxIn, InputsIndexError> {
1067 self.input
1068 .get(input_index)
1069 .ok_or(IndexOutOfBoundsError { index: input_index, length: self.input.len() }.into())
1070 }
1071
1072 #[inline]
1074 pub fn tx_out(&self, output_index: usize) -> Result<&TxOut, OutputsIndexError> {
1075 self.output
1076 .get(output_index)
1077 .ok_or(IndexOutOfBoundsError { index: output_index, length: self.output.len() }.into())
1078 }
1079}
1080
1081#[derive(Debug, Clone, PartialEq, Eq)]
1083pub struct InputsIndexError(pub IndexOutOfBoundsError);
1084
1085impl fmt::Display for InputsIndexError {
1086 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1087 write_err!(f, "invalid input index"; self.0)
1088 }
1089}
1090
1091#[cfg(feature = "std")]
1092impl std::error::Error for InputsIndexError {
1093 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { Some(&self.0) }
1094}
1095
1096impl From<IndexOutOfBoundsError> for InputsIndexError {
1097 fn from(e: IndexOutOfBoundsError) -> Self { Self(e) }
1098}
1099
1100#[derive(Debug, Clone, PartialEq, Eq)]
1102pub struct OutputsIndexError(pub IndexOutOfBoundsError);
1103
1104impl fmt::Display for OutputsIndexError {
1105 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1106 write_err!(f, "invalid output index"; self.0)
1107 }
1108}
1109
1110#[cfg(feature = "std")]
1111impl std::error::Error for OutputsIndexError {
1112 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { Some(&self.0) }
1113}
1114
1115impl From<IndexOutOfBoundsError> for OutputsIndexError {
1116 fn from(e: IndexOutOfBoundsError) -> Self { Self(e) }
1117}
1118
1119#[derive(Debug, Clone, PartialEq, Eq)]
1121#[non_exhaustive]
1122pub struct IndexOutOfBoundsError {
1123 pub index: usize,
1125 pub length: usize,
1127}
1128
1129impl fmt::Display for IndexOutOfBoundsError {
1130 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1131 write!(f, "index {} is out-of-bounds for vector with length {}", self.index, self.length)
1132 }
1133}
1134
1135#[cfg(feature = "std")]
1136impl std::error::Error for IndexOutOfBoundsError {
1137 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
1138}
1139
1140#[derive(Copy, PartialEq, Eq, Clone, Debug, PartialOrd, Ord, Hash)]
1150#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1151#[cfg_attr(feature = "serde", serde(crate = "actual_serde"))]
1152pub struct Version(pub i32);
1153
1154impl Version {
1155 pub const ONE: Self = Self(1);
1157
1158 pub const TWO: Self = Self(2);
1160
1161 pub fn non_standard(version: i32) -> Version { Self(version) }
1163
1164 pub fn is_standard(&self) -> bool { *self == Version::ONE || *self == Version::TWO }
1166}
1167
1168impl Encodable for Version {
1169 fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
1170 self.0.consensus_encode(w)
1171 }
1172}
1173
1174impl Decodable for Version {
1175 fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
1176 Decodable::consensus_decode(r).map(Version)
1177 }
1178}
1179
1180impl fmt::Display for Version {
1181 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Display::fmt(&self.0, f) }
1182}
1183
1184impl_consensus_encoding!(TxOut, value, script_pubkey);
1185
1186impl Encodable for OutPoint {
1187 fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
1188 let len = self.txid.consensus_encode(w)?;
1189 Ok(len + self.vout.consensus_encode(w)?)
1190 }
1191}
1192impl Decodable for OutPoint {
1193 fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
1194 Ok(OutPoint {
1195 txid: Decodable::consensus_decode(r)?,
1196 vout: Decodable::consensus_decode(r)?,
1197 })
1198 }
1199}
1200
1201impl Encodable for TxIn {
1202 fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
1203 let mut len = 0;
1204 len += self.previous_output.consensus_encode(w)?;
1205 len += self.script_sig.consensus_encode(w)?;
1206 len += self.sequence.consensus_encode(w)?;
1207 Ok(len)
1208 }
1209}
1210impl Decodable for TxIn {
1211 #[inline]
1212 fn consensus_decode_from_finite_reader<R: Read + ?Sized>(
1213 r: &mut R,
1214 ) -> Result<Self, encode::Error> {
1215 Ok(TxIn {
1216 previous_output: Decodable::consensus_decode_from_finite_reader(r)?,
1217 script_sig: Decodable::consensus_decode_from_finite_reader(r)?,
1218 sequence: Decodable::consensus_decode_from_finite_reader(r)?,
1219 witness: Witness::default(),
1220 })
1221 }
1222}
1223
1224impl Encodable for Sequence {
1225 fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
1226 self.0.consensus_encode(w)
1227 }
1228}
1229
1230impl Decodable for Sequence {
1231 fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
1232 Decodable::consensus_decode(r).map(Sequence)
1233 }
1234}
1235
1236impl Encodable for Transaction {
1237 fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
1238 let mut len = 0;
1239 len += self.version.consensus_encode(w)?;
1240
1241 if !self.uses_segwit_serialization() {
1243 len += self.input.consensus_encode(w)?;
1244 len += self.output.consensus_encode(w)?;
1245 } else {
1246 len += SEGWIT_MARKER.consensus_encode(w)?;
1248 len += SEGWIT_FLAG.consensus_encode(w)?;
1249 len += self.input.consensus_encode(w)?;
1250 len += self.output.consensus_encode(w)?;
1251 for input in &self.input {
1252 len += input.witness.consensus_encode(w)?;
1253 }
1254 }
1255 len += self.lock_time.consensus_encode(w)?;
1256 Ok(len)
1257 }
1258}
1259
1260impl Decodable for Transaction {
1261 fn consensus_decode_from_finite_reader<R: Read + ?Sized>(
1262 r: &mut R,
1263 ) -> Result<Self, encode::Error> {
1264 let version = Version::consensus_decode_from_finite_reader(r)?;
1265 let input = Vec::<TxIn>::consensus_decode_from_finite_reader(r)?;
1266 if input.is_empty() {
1268 let segwit_flag = u8::consensus_decode_from_finite_reader(r)?;
1269 match segwit_flag {
1270 1 => {
1272 let mut input = Vec::<TxIn>::consensus_decode_from_finite_reader(r)?;
1273 let output = Vec::<TxOut>::consensus_decode_from_finite_reader(r)?;
1274 for txin in input.iter_mut() {
1275 txin.witness = Decodable::consensus_decode_from_finite_reader(r)?;
1276 }
1277 if !input.is_empty() && input.iter().all(|input| input.witness.is_empty()) {
1278 Err(encode::Error::ParseFailed("witness flag set but no witnesses present"))
1279 } else {
1280 Ok(Transaction {
1281 version,
1282 input,
1283 output,
1284 lock_time: Decodable::consensus_decode_from_finite_reader(r)?,
1285 })
1286 }
1287 }
1288 x => Err(encode::Error::UnsupportedSegwitFlag(x)),
1290 }
1291 } else {
1293 Ok(Transaction {
1294 version,
1295 input,
1296 output: Decodable::consensus_decode_from_finite_reader(r)?,
1297 lock_time: Decodable::consensus_decode_from_finite_reader(r)?,
1298 })
1299 }
1300 }
1301}
1302
1303impl From<Transaction> for Txid {
1304 fn from(tx: Transaction) -> Txid { tx.compute_txid() }
1305}
1306
1307impl From<&Transaction> for Txid {
1308 fn from(tx: &Transaction) -> Txid { tx.compute_txid() }
1309}
1310
1311impl From<Transaction> for Wtxid {
1312 fn from(tx: Transaction) -> Wtxid { tx.compute_wtxid() }
1313}
1314
1315impl From<&Transaction> for Wtxid {
1316 fn from(tx: &Transaction) -> Wtxid { tx.compute_wtxid() }
1317}
1318
1319pub fn effective_value(
1333 fee_rate: FeeRate,
1334 satisfaction_weight: Weight,
1335 value: Amount,
1336) -> Option<SignedAmount> {
1337 let weight = satisfaction_weight.checked_add(TxIn::BASE_WEIGHT)?;
1338 let signed_input_fee = fee_rate.checked_mul_by_weight(weight)?.to_signed().ok()?;
1339 value.to_signed().ok()?.checked_sub(signed_input_fee)
1340}
1341
1342pub fn predict_weight<I, O>(inputs: I, output_script_lens: O) -> Weight
1386where
1387 I: IntoIterator<Item = InputWeightPrediction>,
1388 O: IntoIterator<Item = usize>,
1389{
1390 let (input_count, partial_input_weight, inputs_with_witnesses) = inputs.into_iter().fold(
1398 (0, 0, 0),
1399 |(count, partial_input_weight, inputs_with_witnesses), prediction| {
1400 (
1401 count + 1,
1402 partial_input_weight + prediction.weight().to_wu() as usize,
1403 inputs_with_witnesses + (prediction.witness_size > 0) as usize,
1404 )
1405 },
1406 );
1407
1408 let (output_count, output_scripts_size) = output_script_lens.into_iter().fold(
1413 (0, 0),
1414 |(output_count, total_scripts_size), script_len| {
1415 let script_size = script_len + VarInt(script_len as u64).size();
1416 (output_count + 1, total_scripts_size + script_size)
1417 },
1418 );
1419 predict_weight_internal(
1420 input_count,
1421 partial_input_weight,
1422 inputs_with_witnesses,
1423 output_count,
1424 output_scripts_size,
1425 )
1426}
1427
1428const fn predict_weight_internal(
1429 input_count: usize,
1430 partial_input_weight: usize,
1431 inputs_with_witnesses: usize,
1432 output_count: usize,
1433 output_scripts_size: usize,
1434) -> Weight {
1435 let input_weight = partial_input_weight + input_count * 4 * (32 + 4 + 4);
1438
1439 let output_size = 8 * output_count + output_scripts_size;
1441 let non_input_size =
1442 4 +
1444 VarInt(input_count as u64).size() +
1446 VarInt(output_count as u64).size() +
1447 output_size +
1448 4;
1450 let weight = if inputs_with_witnesses == 0 {
1451 non_input_size * 4 + input_weight
1452 } else {
1453 non_input_size * 4 + input_weight + input_count - inputs_with_witnesses + 2
1454 };
1455 Weight::from_wu(weight as u64)
1456}
1457
1458pub const fn predict_weight_from_slices(
1466 inputs: &[InputWeightPrediction],
1467 output_script_lens: &[usize],
1468) -> Weight {
1469 let mut partial_input_weight = 0;
1470 let mut inputs_with_witnesses = 0;
1471
1472 let mut i = 0;
1474 while i < inputs.len() {
1475 let prediction = inputs[i];
1476 partial_input_weight += prediction.weight().to_wu() as usize;
1477 inputs_with_witnesses += (prediction.witness_size > 0) as usize;
1478 i += 1;
1479 }
1480
1481 let mut output_scripts_size = 0;
1482
1483 i = 0;
1484 while i < output_script_lens.len() {
1485 let script_len = output_script_lens[i];
1486 output_scripts_size += script_len + VarInt(script_len as u64).size();
1487 i += 1;
1488 }
1489
1490 predict_weight_internal(
1491 inputs.len(),
1492 partial_input_weight,
1493 inputs_with_witnesses,
1494 output_script_lens.len(),
1495 output_scripts_size,
1496 )
1497}
1498
1499#[derive(Copy, Clone, Debug)]
1505pub struct InputWeightPrediction {
1506 script_size: usize,
1507 witness_size: usize,
1508}
1509
1510impl InputWeightPrediction {
1511 pub const P2WPKH_MAX: Self = InputWeightPrediction::from_slice(0, &[72, 33]);
1522
1523 pub const P2PKH_COMPRESSED_MAX: Self = InputWeightPrediction::from_slice(107, &[]);
1535
1536 pub const P2PKH_UNCOMPRESSED_MAX: Self = InputWeightPrediction::from_slice(139, &[]);
1542
1543 pub const P2TR_KEY_DEFAULT_SIGHASH: Self = InputWeightPrediction::from_slice(0, &[64]);
1549
1550 pub const P2TR_KEY_NON_DEFAULT_SIGHASH: Self = InputWeightPrediction::from_slice(0, &[65]);
1556
1557 pub const fn ground_p2wpkh(bytes_to_grind: usize) -> Self {
1572 let der_signature_size = 10 + (62 - bytes_to_grind);
1574 InputWeightPrediction::from_slice(0, &[der_signature_size, 33])
1575 }
1576
1577 pub const fn ground_p2pkh_compressed(bytes_to_grind: usize) -> Self {
1592 let der_signature_size = 10 + (62 - bytes_to_grind);
1594
1595 InputWeightPrediction::from_slice(2 + 33 + der_signature_size, &[])
1596 }
1597
1598 pub fn new<T>(input_script_len: usize, witness_element_lengths: T) -> Self
1600 where
1601 T: IntoIterator,
1602 T::Item: Borrow<usize>,
1603 {
1604 let (count, total_size) =
1605 witness_element_lengths.into_iter().fold((0, 0), |(count, total_size), elem_len| {
1606 let elem_len = *elem_len.borrow();
1607 let elem_size = elem_len + VarInt(elem_len as u64).size();
1608 (count + 1, total_size + elem_size)
1609 });
1610 let witness_size = if count > 0 { total_size + VarInt(count as u64).size() } else { 0 };
1611 let script_size = input_script_len + VarInt(input_script_len as u64).size();
1612
1613 InputWeightPrediction { script_size, witness_size }
1614 }
1615
1616 pub const fn from_slice(input_script_len: usize, witness_element_lengths: &[usize]) -> Self {
1622 let mut i = 0;
1623 let mut total_size = 0;
1624 while i < witness_element_lengths.len() {
1626 let elem_len = witness_element_lengths[i];
1627 let elem_size = elem_len + VarInt(elem_len as u64).size();
1628 total_size += elem_size;
1629 i += 1;
1630 }
1631 let witness_size = if !witness_element_lengths.is_empty() {
1632 total_size + VarInt(witness_element_lengths.len() as u64).size()
1633 } else {
1634 0
1635 };
1636 let script_size = input_script_len + VarInt(input_script_len as u64).size();
1637
1638 InputWeightPrediction { script_size, witness_size }
1639 }
1640
1641 pub const fn weight(&self) -> Weight {
1644 Weight::from_wu_usize(self.script_size * 4 + self.witness_size)
1645 }
1646}
1647
1648#[cfg(test)]
1649mod tests {
1650 use core::str::FromStr;
1651
1652 use hex::{test_hex_unwrap as hex, FromHex};
1653
1654 use super::*;
1655 use crate::blockdata::constants::WITNESS_SCALE_FACTOR;
1656 use crate::consensus::encode::{deserialize, serialize};
1657 use crate::sighash::EcdsaSighashType;
1658
1659 const SOME_TX: &str = "0100000001a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff0100e1f505000000001976a9140389035a9225b3839e2bbf32d826a1e222031fd888ac00000000";
1660
1661 #[test]
1662 fn encode_to_unsized_writer() {
1663 let mut buf = [0u8; 1024];
1664 let raw_tx = hex!(SOME_TX);
1665 let tx: Transaction = Decodable::consensus_decode(&mut raw_tx.as_slice()).unwrap();
1666
1667 let size = tx.consensus_encode(&mut &mut buf[..]).unwrap();
1668 assert_eq!(size, SOME_TX.len() / 2);
1669 assert_eq!(raw_tx, &buf[..size]);
1670 }
1671
1672 #[test]
1673 fn outpoint() {
1674 assert_eq!(OutPoint::from_str("i don't care"), Err(ParseOutPointError::Format));
1675 assert_eq!(
1676 OutPoint::from_str(
1677 "5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456:1:1"
1678 ),
1679 Err(ParseOutPointError::Format)
1680 );
1681 assert_eq!(
1682 OutPoint::from_str("5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456:"),
1683 Err(ParseOutPointError::Format)
1684 );
1685 assert_eq!(
1686 OutPoint::from_str(
1687 "5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456:11111111111"
1688 ),
1689 Err(ParseOutPointError::TooLong)
1690 );
1691 assert_eq!(
1692 OutPoint::from_str(
1693 "5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456:01"
1694 ),
1695 Err(ParseOutPointError::VoutNotCanonical)
1696 );
1697 assert_eq!(
1698 OutPoint::from_str(
1699 "5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456:+42"
1700 ),
1701 Err(ParseOutPointError::VoutNotCanonical)
1702 );
1703 assert_eq!(
1704 OutPoint::from_str("i don't care:1"),
1705 Err(ParseOutPointError::Txid("i don't care".parse::<Txid>().unwrap_err()))
1706 );
1707 assert_eq!(
1708 OutPoint::from_str(
1709 "5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c945X:1"
1710 ),
1711 Err(ParseOutPointError::Txid(
1712 "5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c945X"
1713 .parse::<Txid>()
1714 .unwrap_err()
1715 ))
1716 );
1717 assert_eq!(
1718 OutPoint::from_str(
1719 "5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456:lol"
1720 ),
1721 Err(ParseOutPointError::Vout(parse::int::<u32, _>("lol").unwrap_err()))
1722 );
1723
1724 assert_eq!(
1725 OutPoint::from_str(
1726 "5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456:42"
1727 ),
1728 Ok(OutPoint {
1729 txid: "5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456"
1730 .parse()
1731 .unwrap(),
1732 vout: 42,
1733 })
1734 );
1735 assert_eq!(
1736 OutPoint::from_str(
1737 "5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456:0"
1738 ),
1739 Ok(OutPoint {
1740 txid: "5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456"
1741 .parse()
1742 .unwrap(),
1743 vout: 0,
1744 })
1745 );
1746 }
1747
1748 #[test]
1749 fn txin() {
1750 let txin: Result<TxIn, _> = deserialize(&hex!("a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff"));
1751 assert!(txin.is_ok());
1752 }
1753
1754 #[test]
1755 fn txin_default() {
1756 let txin = TxIn::default();
1757 assert_eq!(txin.previous_output, OutPoint::default());
1758 assert_eq!(txin.script_sig, ScriptBuf::new());
1759 assert_eq!(txin.sequence, Sequence::from_consensus(0xFFFFFFFF));
1760 assert_eq!(txin.previous_output, OutPoint::default());
1761 assert_eq!(txin.witness.len(), 0);
1762 }
1763
1764 #[test]
1765 fn is_coinbase() {
1766 use crate::blockdata::constants;
1767 use crate::network::Network;
1768
1769 let genesis = constants::genesis_block(Network::Bitcoin);
1770 assert!(genesis.txdata[0].is_coinbase());
1771 let tx_bytes = hex!("0100000001a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff0100e1f505000000001976a9140389035a9225b3839e2bbf32d826a1e222031fd888ac00000000");
1772 let tx: Transaction = deserialize(&tx_bytes).unwrap();
1773 assert!(!tx.is_coinbase());
1774 }
1775
1776 #[test]
1777 fn nonsegwit_transaction() {
1778 let tx_bytes = hex!("0100000001a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff0100e1f505000000001976a9140389035a9225b3839e2bbf32d826a1e222031fd888ac00000000");
1779 let tx: Result<Transaction, _> = deserialize(&tx_bytes);
1780 assert!(tx.is_ok());
1781 let realtx = tx.unwrap();
1782 assert_eq!(realtx.version, Version::ONE);
1785 assert_eq!(realtx.input.len(), 1);
1786 assert_eq!(
1789 format!("{:x}", realtx.input[0].previous_output.txid),
1790 "ce9ea9f6f5e422c6a9dbcddb3b9a14d1c78fab9ab520cb281aa2a74a09575da1".to_string()
1791 );
1792 assert_eq!(realtx.input[0].previous_output.vout, 1);
1793 assert_eq!(realtx.output.len(), 1);
1794 assert_eq!(realtx.lock_time, absolute::LockTime::ZERO);
1795
1796 assert_eq!(
1797 format!("{:x}", realtx.compute_txid()),
1798 "a6eab3c14ab5272a58a5ba91505ba1a4b6d7a3a9fcbd187b6cd99a7b6d548cb7".to_string()
1799 );
1800 assert_eq!(
1801 format!("{:x}", realtx.compute_wtxid()),
1802 "a6eab3c14ab5272a58a5ba91505ba1a4b6d7a3a9fcbd187b6cd99a7b6d548cb7".to_string()
1803 );
1804 assert_eq!(realtx.weight().to_wu() as usize, tx_bytes.len() * WITNESS_SCALE_FACTOR);
1805 assert_eq!(realtx.total_size(), tx_bytes.len());
1806 assert_eq!(realtx.vsize(), tx_bytes.len());
1807 assert_eq!(realtx.base_size(), tx_bytes.len());
1808 }
1809
1810 #[test]
1811 fn segwit_invalid_transaction() {
1812 let tx_bytes = hex!("0000fd000001021921212121212121212121f8b372b0239cc1dff600000000004f4f4f4f4f4f4f4f000000000000000000000000000000333732343133380d000000000000000000000000000000ff000000000009000dff000000000000000800000000000000000d");
1813 let tx: Result<Transaction, _> = deserialize(&tx_bytes);
1814 assert!(tx.is_err());
1815 assert!(tx.unwrap_err().to_string().contains("witness flag set but no witnesses present"));
1816 }
1817
1818 #[test]
1819 fn segwit_transaction() {
1820 let tx_bytes = hex!(
1821 "02000000000101595895ea20179de87052b4046dfe6fd515860505d6511a9004cf12a1f93cac7c01000000\
1822 00ffffffff01deb807000000000017a9140f3444e271620c736808aa7b33e370bd87cb5a078702483045022\
1823 100fb60dad8df4af2841adc0346638c16d0b8035f5e3f3753b88db122e70c79f9370220756e6633b17fd271\
1824 0e626347d28d60b0a2d6cbb41de51740644b9fb3ba7751040121028fa937ca8cba2197a37c007176ed89410\
1825 55d3bcb8627d085e94553e62f057dcc00000000"
1826 );
1827 let tx: Result<Transaction, _> = deserialize(&tx_bytes);
1828 assert!(tx.is_ok());
1829 let realtx = tx.unwrap();
1830 assert_eq!(realtx.version, Version::TWO);
1833 assert_eq!(realtx.input.len(), 1);
1834 assert_eq!(
1837 format!("{:x}", realtx.input[0].previous_output.txid),
1838 "7cac3cf9a112cf04901a51d605058615d56ffe6d04b45270e89d1720ea955859".to_string()
1839 );
1840 assert_eq!(realtx.input[0].previous_output.vout, 1);
1841 assert_eq!(realtx.output.len(), 1);
1842 assert_eq!(realtx.lock_time, absolute::LockTime::ZERO);
1843
1844 assert_eq!(
1845 format!("{:x}", realtx.compute_txid()),
1846 "f5864806e3565c34d1b41e716f72609d00b55ea5eac5b924c9719a842ef42206".to_string()
1847 );
1848 assert_eq!(
1849 format!("{:x}", realtx.compute_wtxid()),
1850 "80b7d8a82d5d5bf92905b06f2014dd699e03837ca172e3a59d51426ebbe3e7f5".to_string()
1851 );
1852 const EXPECTED_WEIGHT: Weight = Weight::from_wu(442);
1853 assert_eq!(realtx.weight(), EXPECTED_WEIGHT);
1854 assert_eq!(realtx.total_size(), tx_bytes.len());
1855 assert_eq!(realtx.vsize(), 111);
1856
1857 let expected_strippedsize = (442 - realtx.total_size()) / 3;
1858 assert_eq!(realtx.base_size(), expected_strippedsize);
1859
1860 let mut tx_without_witness = realtx;
1862 tx_without_witness.input.iter_mut().for_each(|input| input.witness.clear());
1863 assert_eq!(tx_without_witness.total_size(), tx_without_witness.total_size());
1864 assert_eq!(tx_without_witness.total_size(), expected_strippedsize);
1865 }
1866
1867 #[cfg(feature = "serde")]
1869 #[test]
1870 fn consensus_serde() {
1871 use crate::consensus::serde as con_serde;
1872 let json = "\"010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff3603da1b0e00045503bd5704c7dd8a0d0ced13bb5785010800000000000a636b706f6f6c122f4e696e6a61506f6f6c2f5345475749542fffffffff02b4e5a212000000001976a914876fbb82ec05caa6af7a3b5e5a983aae6c6cc6d688ac0000000000000000266a24aa21a9edf91c46b49eb8a29089980f02ee6b57e7d63d33b18b4fddac2bcd7db2a39837040120000000000000000000000000000000000000000000000000000000000000000000000000\"";
1873 let mut deserializer = serde_json::Deserializer::from_str(json);
1874 let tx =
1875 con_serde::With::<con_serde::Hex>::deserialize::<'_, Transaction, _>(&mut deserializer)
1876 .unwrap();
1877 let tx_bytes = Vec::from_hex(&json[1..(json.len() - 1)]).unwrap();
1878 let expected = deserialize::<Transaction>(&tx_bytes).unwrap();
1879 assert_eq!(tx, expected);
1880 let mut bytes = Vec::new();
1881 let mut serializer = serde_json::Serializer::new(&mut bytes);
1882 con_serde::With::<con_serde::Hex>::serialize(&tx, &mut serializer).unwrap();
1883 assert_eq!(bytes, json.as_bytes())
1884 }
1885
1886 #[test]
1887 fn transaction_version() {
1888 let tx_bytes = hex!("ffffff7f0100000000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000");
1889 let tx: Result<Transaction, _> = deserialize(&tx_bytes);
1890 assert!(tx.is_ok());
1891 let realtx = tx.unwrap();
1892 assert_eq!(realtx.version, Version::non_standard(2147483647));
1893
1894 let tx2_bytes = hex!("000000800100000000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000");
1895 let tx2: Result<Transaction, _> = deserialize(&tx2_bytes);
1896 assert!(tx2.is_ok());
1897 let realtx2 = tx2.unwrap();
1898 assert_eq!(realtx2.version, Version::non_standard(-2147483648));
1899 }
1900
1901 #[test]
1902 fn tx_no_input_deserialization() {
1903 let tx_bytes = hex!(
1904 "010000000001000100e1f505000000001976a9140389035a9225b3839e2bbf32d826a1e222031fd888ac00000000"
1905 );
1906 let tx: Transaction = deserialize(&tx_bytes).expect("deserialize tx");
1907
1908 assert_eq!(tx.input.len(), 0);
1909 assert_eq!(tx.output.len(), 1);
1910
1911 let reser = serialize(&tx);
1912 assert_eq!(tx_bytes, reser);
1913 }
1914
1915 #[test]
1916 fn ntxid() {
1917 let tx_bytes = hex!("0100000001a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff0100e1f505000000001976a9140389035a9225b3839e2bbf32d826a1e222031fd888ac00000000");
1918 let mut tx: Transaction = deserialize(&tx_bytes).unwrap();
1919
1920 let old_ntxid = tx.compute_ntxid();
1921 assert_eq!(
1922 format!("{:x}", old_ntxid),
1923 "c3573dbea28ce24425c59a189391937e00d255150fa973d59d61caf3a06b601d"
1924 );
1925 tx.input[0].script_sig = ScriptBuf::new();
1927 assert_eq!(old_ntxid, tx.compute_ntxid());
1928 tx.output[0].script_pubkey = ScriptBuf::new();
1930 assert!(old_ntxid != tx.compute_ntxid());
1931 }
1932
1933 #[test]
1934 fn txid() {
1935 let tx_bytes = hex!(
1937 "01000000000102ff34f95a672bb6a4f6ff4a7e90fa8c7b3be7e70ffc39bc99be3bda67942e836c00000000\
1938 23220020cde476664d3fa347b8d54ef3aee33dcb686a65ced2b5207cbf4ec5eda6b9b46e4f414d4c934ad8\
1939 1d330314e888888e3bd22c7dde8aac2ca9227b30d7c40093248af7812201000000232200200af6f6a071a6\
1940 9d5417e592ed99d256ddfd8b3b2238ac73f5da1b06fc0b2e79d54f414d4c0ba0c8f505000000001976a914\
1941 dcb5898d9036afad9209e6ff0086772795b1441088ac033c0f000000000017a914889f8c10ff2bd4bb9dab\
1942 b68c5c0d700a46925e6c87033c0f000000000017a914889f8c10ff2bd4bb9dabb68c5c0d700a46925e6c87\
1943 033c0f000000000017a914889f8c10ff2bd4bb9dabb68c5c0d700a46925e6c87033c0f000000000017a914\
1944 889f8c10ff2bd4bb9dabb68c5c0d700a46925e6c87033c0f000000000017a914889f8c10ff2bd4bb9dabb6\
1945 8c5c0d700a46925e6c87033c0f000000000017a914889f8c10ff2bd4bb9dabb68c5c0d700a46925e6c8703\
1946 3c0f000000000017a914889f8c10ff2bd4bb9dabb68c5c0d700a46925e6c87033c0f000000000017a91488\
1947 9f8c10ff2bd4bb9dabb68c5c0d700a46925e6c87033c0f000000000017a914889f8c10ff2bd4bb9dabb68c\
1948 5c0d700a46925e6c87033c0f000000000017a914889f8c10ff2bd4bb9dabb68c5c0d700a46925e6c870500\
1949 47304402200380b8663e727d7e8d773530ef85d5f82c0b067c97ae927800a0876a1f01d8e2022021ee611e\
1950 f6507dfd217add2cd60a8aea3cbcfec034da0bebf3312d19577b8c290147304402207bd9943ce1c2c5547b\
1951 120683fd05d78d23d73be1a5b5a2074ff586b9c853ed4202202881dcf435088d663c9af7b23efb3c03b9db\
1952 c0c899b247aa94a74d9b4b3c84f501483045022100ba12bba745af3f18f6e56be70f8382ca8e107d1ed5ce\
1953 aa3e8c360d5ecf78886f022069b38ebaac8fe6a6b97b497cbbb115f3176f7213540bef08f9292e5a72de52\
1954 de01695321023c9cd9c6950ffee24772be948a45dc5ef1986271e46b686cb52007bac214395a2102756e27\
1955 cb004af05a6e9faed81fd68ff69959e3c64ac8c9f6cd0e08fd0ad0e75d2103fa40da236bd82202a985a910\
1956 4e851080b5940812685769202a3b43e4a8b13e6a53ae050048304502210098b9687b81d725a7970d1eee91\
1957 ff6b89bc9832c2e0e3fb0d10eec143930b006f02206f77ce19dc58ecbfef9221f81daad90bb4f468df3912\
1958 12abc4f084fe2cc9bdef01483045022100e5479f81a3ad564103da5e2ec8e12f61f3ac8d312ab68763c1dd\
1959 d7bae94c20610220789b81b7220b27b681b1b2e87198897376ba9d033bc387f084c8b8310c8539c2014830\
1960 45022100aa1cc48a2d256c0e556616444cc08ae4959d464e5ffff2ae09e3550bdab6ce9f02207192d5e332\
1961 9a56ba7b1ead724634d104f1c3f8749fe6081e6233aee3e855817a016953210260de9cc68658c61af984e3\
1962 ab0281d17cfca1cc035966d335f474932d5e6c5422210355fbb768ce3ce39360277345dbb5f376e706459e\
1963 5a2b5e0e09a535e61690647021023222ceec58b94bd25925dd9743dae6b928737491bd940fc5dd7c6f5d5f\
1964 2adc1e53ae00000000"
1965 );
1966 let tx: Transaction = deserialize(&tx_bytes).unwrap();
1967
1968 assert_eq!(
1969 format!("{:x}", tx.compute_wtxid()),
1970 "d6ac4a5e61657c4c604dcde855a1db74ec6b3e54f32695d72c5e11c7761ea1b4"
1971 );
1972 assert_eq!(
1973 format!("{:x}", tx.compute_txid()),
1974 "9652aa62b0e748caeec40c4cb7bc17c6792435cc3dfe447dd1ca24f912a1c6ec"
1975 );
1976 assert_eq!(format!("{:.10x}", tx.compute_txid()), "9652aa62b0");
1977 assert_eq!(tx.weight(), Weight::from_wu(2718));
1978
1979 let tx_bytes = hex!(
1981 "01000000010c7196428403d8b0c88fcb3ee8d64f56f55c8973c9ab7dd106bb4f3527f5888d000000006a47\
1982 30440220503a696f55f2c00eee2ac5e65b17767cd88ed04866b5637d3c1d5d996a70656d02202c9aff698f\
1983 343abb6d176704beda63fcdec503133ea4f6a5216b7f925fa9910c0121024d89b5a13d6521388969209df2\
1984 7a8469bd565aff10e8d42cef931fad5121bfb8ffffffff02b825b404000000001976a914ef79e7ee9fff98\
1985 bcfd08473d2b76b02a48f8c69088ac0000000000000000296a273236303039343836393731373233313237\
1986 3633313032313332353630353838373931323132373000000000"
1987 );
1988 let tx: Transaction = deserialize(&tx_bytes).unwrap();
1989
1990 assert_eq!(
1991 format!("{:x}", tx.compute_wtxid()),
1992 "971ed48a62c143bbd9c87f4bafa2ef213cfa106c6e140f111931d0be307468dd"
1993 );
1994 assert_eq!(
1995 format!("{:x}", tx.compute_txid()),
1996 "971ed48a62c143bbd9c87f4bafa2ef213cfa106c6e140f111931d0be307468dd"
1997 );
1998 }
1999
2000 #[test]
2001 #[cfg(feature = "serde")]
2002 fn txn_encode_decode() {
2003 let tx_bytes = hex!("0100000001a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff0100e1f505000000001976a9140389035a9225b3839e2bbf32d826a1e222031fd888ac00000000");
2004 let tx: Transaction = deserialize(&tx_bytes).unwrap();
2005 serde_round_trip!(tx);
2006 }
2007
2008 #[test]
2011 #[cfg(feature = "serde")]
2012 fn segwit_tx_decode() {
2013 let tx_bytes = hex!("010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff3603da1b0e00045503bd5704c7dd8a0d0ced13bb5785010800000000000a636b706f6f6c122f4e696e6a61506f6f6c2f5345475749542fffffffff02b4e5a212000000001976a914876fbb82ec05caa6af7a3b5e5a983aae6c6cc6d688ac0000000000000000266a24aa21a9edf91c46b49eb8a29089980f02ee6b57e7d63d33b18b4fddac2bcd7db2a39837040120000000000000000000000000000000000000000000000000000000000000000000000000");
2014 let tx: Transaction = deserialize(&tx_bytes).unwrap();
2015 assert_eq!(tx.weight(), Weight::from_wu(780));
2016 serde_round_trip!(tx);
2017
2018 let consensus_encoded = serialize(&tx);
2019 assert_eq!(consensus_encoded, tx_bytes);
2020 }
2021
2022 #[test]
2023 fn sighashtype_fromstr_display() {
2024 let sighashtypes = vec![
2025 ("SIGHASH_ALL", EcdsaSighashType::All),
2026 ("SIGHASH_NONE", EcdsaSighashType::None),
2027 ("SIGHASH_SINGLE", EcdsaSighashType::Single),
2028 ("SIGHASH_ALL|SIGHASH_ANYONECANPAY", EcdsaSighashType::AllPlusAnyoneCanPay),
2029 ("SIGHASH_NONE|SIGHASH_ANYONECANPAY", EcdsaSighashType::NonePlusAnyoneCanPay),
2030 ("SIGHASH_SINGLE|SIGHASH_ANYONECANPAY", EcdsaSighashType::SinglePlusAnyoneCanPay),
2031 ];
2032 for (s, sht) in sighashtypes {
2033 assert_eq!(sht.to_string(), s);
2034 assert_eq!(EcdsaSighashType::from_str(s).unwrap(), sht);
2035 }
2036 let sht_mistakes = vec![
2037 "SIGHASH_ALL | SIGHASH_ANYONECANPAY",
2038 "SIGHASH_NONE |SIGHASH_ANYONECANPAY",
2039 "SIGHASH_SINGLE| SIGHASH_ANYONECANPAY",
2040 "SIGHASH_ALL SIGHASH_ANYONECANPAY",
2041 "SIGHASH_NONE |",
2042 "SIGHASH_SIGNLE",
2043 "sighash_none",
2044 "Sighash_none",
2045 "SigHash_None",
2046 "SigHash_NONE",
2047 ];
2048 for s in sht_mistakes {
2049 assert_eq!(
2050 EcdsaSighashType::from_str(s).unwrap_err().to_string(),
2051 format!("unrecognized SIGHASH string '{}'", s)
2052 );
2053 }
2054 }
2055
2056 #[test]
2057 fn huge_witness() {
2058 deserialize::<Transaction>(&hex!(include_str!("../../tests/data/huge_witness.hex").trim()))
2059 .unwrap();
2060 }
2061
2062 #[test]
2063 #[cfg(feature = "bitcoinconsensus")]
2064 fn transaction_verify() {
2065 use std::collections::HashMap;
2066
2067 use crate::blockdata::witness::Witness;
2068
2069 let mut spending: Transaction = deserialize(hex!("020000000001031cfbc8f54fbfa4a33a30068841371f80dbfe166211242213188428f437445c91000000006a47304402206fbcec8d2d2e740d824d3d36cc345b37d9f65d665a99f5bd5c9e8d42270a03a8022013959632492332200c2908459547bf8dbf97c65ab1a28dec377d6f1d41d3d63e012103d7279dfb90ce17fe139ba60a7c41ddf605b25e1c07a4ddcb9dfef4e7d6710f48feffffff476222484f5e35b3f0e43f65fc76e21d8be7818dd6a989c160b1e5039b7835fc00000000171600140914414d3c94af70ac7e25407b0689e0baa10c77feffffffa83d954a62568bbc99cc644c62eb7383d7c2a2563041a0aeb891a6a4055895570000000017160014795d04cc2d4f31480d9a3710993fbd80d04301dffeffffff06fef72f000000000017a91476fd7035cd26f1a32a5ab979e056713aac25796887a5000f00000000001976a914b8332d502a529571c6af4be66399cd33379071c588ac3fda0500000000001976a914fc1d692f8de10ae33295f090bea5fe49527d975c88ac522e1b00000000001976a914808406b54d1044c429ac54c0e189b0d8061667e088ac6eb68501000000001976a914dfab6085f3a8fb3e6710206a5a959313c5618f4d88acbba20000000000001976a914eb3026552d7e3f3073457d0bee5d4757de48160d88ac0002483045022100bee24b63212939d33d513e767bc79300051f7a0d433c3fcf1e0e3bf03b9eb1d70220588dc45a9ce3a939103b4459ce47500b64e23ab118dfc03c9caa7d6bfc32b9c601210354fd80328da0f9ae6eef2b3a81f74f9a6f66761fadf96f1d1d22b1fd6845876402483045022100e29c7e3a5efc10da6269e5fc20b6a1cb8beb92130cc52c67e46ef40aaa5cac5f0220644dd1b049727d991aece98a105563416e10a5ac4221abac7d16931842d5c322012103960b87412d6e169f30e12106bdf70122aabb9eb61f455518322a18b920a4dfa887d30700")
2071 .as_slice()).unwrap();
2072 let spent1: Transaction = deserialize(hex!("020000000001040aacd2c49f5f3c0968cfa8caf9d5761436d95385252e3abb4de8f5dcf8a582f20000000017160014bcadb2baea98af0d9a902e53a7e9adff43b191e9feffffff96cd3c93cac3db114aafe753122bd7d1afa5aa4155ae04b3256344ecca69d72001000000171600141d9984579ceb5c67ebfbfb47124f056662fe7adbfeffffffc878dd74d3a44072eae6178bb94b9253177db1a5aaa6d068eb0e4db7631762e20000000017160014df2a48cdc53dae1aba7aa71cb1f9de089d75aac3feffffffe49f99275bc8363f5f593f4eec371c51f62c34ff11cc6d8d778787d340d6896c0100000017160014229b3b297a0587e03375ab4174ef56eeb0968735feffffff03360d0f00000000001976a9149f44b06f6ee92ddbc4686f71afe528c09727a5c788ac24281b00000000001976a9140277b4f68ff20307a2a9f9b4487a38b501eb955888ac227c0000000000001976a9148020cd422f55eef8747a9d418f5441030f7c9c7788ac0247304402204aa3bd9682f9a8e101505f6358aacd1749ecf53a62b8370b97d59243b3d6984f02200384ad449870b0e6e89c92505880411285ecd41cf11e7439b973f13bad97e53901210205b392ffcb83124b1c7ce6dd594688198ef600d34500a7f3552d67947bbe392802473044022033dfd8d190a4ae36b9f60999b217c775b96eb10dee3a1ff50fb6a75325719106022005872e4e36d194e49ced2ebcf8bb9d843d842e7b7e0eb042f4028396088d292f012103c9d7cbf369410b090480de2aa15c6c73d91b9ffa7d88b90724614b70be41e98e0247304402207d952de9e59e4684efed069797e3e2d993e9f98ec8a9ccd599de43005fe3f713022076d190cc93d9513fc061b1ba565afac574e02027c9efbfa1d7b71ab8dbb21e0501210313ad44bc030cc6cb111798c2bf3d2139418d751c1e79ec4e837ce360cc03b97a024730440220029e75edb5e9413eb98d684d62a077b17fa5b7cc19349c1e8cc6c4733b7b7452022048d4b9cae594f03741029ff841e35996ef233701c1ea9aa55c301362ea2e2f68012103590657108a72feb8dc1dec022cf6a230bb23dc7aaa52f4032384853b9f8388baf9d20700")
2073 .as_slice()).unwrap();
2074 let spent2: Transaction = deserialize(hex!("0200000000010166c3d39490dc827a2594c7b17b7d37445e1f4b372179649cd2ce4475e3641bbb0100000017160014e69aa750e9bff1aca1e32e57328b641b611fc817fdffffff01e87c5d010000000017a914f3890da1b99e44cd3d52f7bcea6a1351658ea7be87024830450221009eb97597953dc288de30060ba02d4e91b2bde1af2ecf679c7f5ab5989549aa8002202a98f8c3bd1a5a31c0d72950dd6e2e3870c6c5819a6c3db740e91ebbbc5ef4800121023f3d3b8e74b807e32217dea2c75c8d0bd46b8665b3a2d9b3cb310959de52a09bc9d20700")
2075 .as_slice()).unwrap();
2076 let spent3: Transaction = deserialize(hex!("01000000027a1120a30cef95422638e8dab9dedf720ec614b1b21e451a4957a5969afb869d000000006a47304402200ecc318a829a6cad4aa9db152adbf09b0cd2de36f47b53f5dade3bc7ef086ca702205722cda7404edd6012eedd79b2d6f24c0a0c657df1a442d0a2166614fb164a4701210372f4b97b34e9c408741cd1fc97bcc7ffdda6941213ccfde1cb4075c0f17aab06ffffffffc23b43e5a18e5a66087c0d5e64d58e8e21fcf83ce3f5e4f7ecb902b0e80a7fb6010000006b483045022100f10076a0ea4b4cf8816ed27a1065883efca230933bf2ff81d5db6258691ff75202206b001ef87624e76244377f57f0c84bc5127d0dd3f6e0ef28b276f176badb223a01210309a3a61776afd39de4ed29b622cd399d99ecd942909c36a8696cfd22fc5b5a1affffffff0200127a000000000017a914f895e1dd9b29cb228e9b06a15204e3b57feaf7cc8769311d09000000001976a9144d00da12aaa51849d2583ae64525d4a06cd70fde88ac00000000")
2077 .as_slice()).unwrap();
2078
2079 let mut spent = HashMap::new();
2080 spent.insert(spent1.compute_txid(), spent1);
2081 spent.insert(spent2.compute_txid(), spent2);
2082 spent.insert(spent3.compute_txid(), spent3);
2083 let mut spent2 = spent.clone();
2084 let mut spent3 = spent.clone();
2085
2086 spending
2087 .verify(|point: &OutPoint| {
2088 if let Some(tx) = spent.remove(&point.txid) {
2089 return tx.output.get(point.vout as usize).cloned();
2090 }
2091 None
2092 })
2093 .unwrap();
2094
2095 let mut double_spending = spending.clone();
2097 let re_use = double_spending.input[0].clone();
2098 double_spending.input.push(re_use);
2099
2100 assert!(double_spending
2101 .verify(|point: &OutPoint| {
2102 if let Some(tx) = spent2.remove(&point.txid) {
2103 return tx.output.get(point.vout as usize).cloned();
2104 }
2105 None
2106 })
2107 .is_err());
2108
2109 let mut witness: Vec<_> = spending.input[1].witness.to_vec();
2111 witness[0][10] = 42;
2112 spending.input[1].witness = Witness::from_slice(&witness);
2113
2114 let error = spending
2115 .verify(|point: &OutPoint| {
2116 if let Some(tx) = spent3.remove(&point.txid) {
2117 return tx.output.get(point.vout as usize).cloned();
2118 }
2119 None
2120 })
2121 .err()
2122 .unwrap();
2123
2124 match error {
2125 TxVerifyError::ScriptVerification(_) => {}
2126 _ => panic!("Wrong error type"),
2127 }
2128 }
2129
2130 #[test]
2131 fn sequence_number() {
2132 let seq_final = Sequence::from_consensus(0xFFFFFFFF);
2133 let seq_non_rbf = Sequence::from_consensus(0xFFFFFFFE);
2134 let block_time_lock = Sequence::from_consensus(0xFFFF);
2135 let unit_time_lock = Sequence::from_consensus(0x40FFFF);
2136 let lock_time_disabled = Sequence::from_consensus(0x80000000);
2137
2138 assert!(seq_final.is_final());
2139 assert!(!seq_final.is_rbf());
2140 assert!(!seq_final.is_relative_lock_time());
2141 assert!(!seq_non_rbf.is_rbf());
2142 assert!(block_time_lock.is_relative_lock_time());
2143 assert!(block_time_lock.is_height_locked());
2144 assert!(block_time_lock.is_rbf());
2145 assert!(unit_time_lock.is_relative_lock_time());
2146 assert!(unit_time_lock.is_time_locked());
2147 assert!(unit_time_lock.is_rbf());
2148 assert!(!lock_time_disabled.is_relative_lock_time());
2149 }
2150
2151 #[test]
2152 fn sequence_from_hex_lower() {
2153 let sequence = Sequence::from_hex("0xffffffff").unwrap();
2154 assert_eq!(sequence, Sequence::MAX);
2155 }
2156
2157 #[test]
2158 fn sequence_from_hex_upper() {
2159 let sequence = Sequence::from_hex("0XFFFFFFFF").unwrap();
2160 assert_eq!(sequence, Sequence::MAX);
2161 }
2162
2163 #[test]
2164 fn sequence_from_unprefixed_hex_lower() {
2165 let sequence = Sequence::from_unprefixed_hex("ffffffff").unwrap();
2166 assert_eq!(sequence, Sequence::MAX);
2167 }
2168
2169 #[test]
2170 fn sequence_from_unprefixed_hex_upper() {
2171 let sequence = Sequence::from_unprefixed_hex("FFFFFFFF").unwrap();
2172 assert_eq!(sequence, Sequence::MAX);
2173 }
2174
2175 #[test]
2176 fn sequence_from_str_hex_invalid_hex_should_err() {
2177 let hex = "0xzb93";
2178 let result = Sequence::from_hex(hex);
2179 assert!(result.is_err());
2180 }
2181
2182 #[test]
2183 fn effective_value_happy_path() {
2184 let value = Amount::from_str("1 cBTC").unwrap();
2185 let fee_rate = FeeRate::from_sat_per_kwu(10);
2186 let satisfaction_weight = Weight::from_wu(204);
2187 let effective_value = effective_value(fee_rate, satisfaction_weight, value).unwrap();
2188
2189 let expected_fee = SignedAmount::from_str("4 sats").unwrap();
2191 let expected_effective_value = value.to_signed().unwrap() - expected_fee;
2192 assert_eq!(effective_value, expected_effective_value);
2193 }
2194
2195 #[test]
2196 fn effective_value_fee_rate_does_not_overflow() {
2197 let eff_value = effective_value(FeeRate::MAX, Weight::ZERO, Amount::ZERO);
2198 assert!(eff_value.is_none());
2199 }
2200
2201 #[test]
2202 fn effective_value_weight_does_not_overflow() {
2203 let eff_value = effective_value(FeeRate::ZERO, Weight::MAX, Amount::ZERO);
2204 assert!(eff_value.is_none());
2205 }
2206
2207 #[test]
2208 fn effective_value_value_does_not_overflow() {
2209 let eff_value = effective_value(FeeRate::ZERO, Weight::ZERO, Amount::MAX);
2210 assert!(eff_value.is_none());
2211 }
2212
2213 #[test]
2214 fn txin_txout_weight() {
2215 let txs = [
2217 (true, "020000000001018a763b78d3e17acea0625bf9e52b0dc1beb2241b2502185348ba8ff4a253176e0100000000ffffffff0280d725000000000017a914c07ed639bd46bf7087f2ae1dfde63b815a5f8b488767fda20300000000160014869ec8520fa2801c8a01bfdd2e82b19833cd0daf02473044022016243edad96b18c78b545325aaff80131689f681079fb107a67018cb7fb7830e02205520dae761d89728f73f1a7182157f6b5aecf653525855adb7ccb998c8e6143b012103b9489bde92afbcfa85129a82ffa512897105d1a27ad9806bded27e0532fc84e700000000", Weight::from_wu(565)),
2219 (true, "01000000000101a3ccad197118a2d4975fadc47b90eacfdeaf8268adfdf10ed3b4c3b7e1ad14530300000000ffffffff0200cc5501000000001976a91428ec6f21f4727bff84bb844e9697366feeb69f4d88aca2a5100d00000000220020701a8d401c84fb13e6baf169d59684e17abd9fa216c8cc5b9fc63d622ff8c58d04004730440220548f11130353b3a8f943d2f14260345fc7c20bde91704c9f1cbb5456355078cd0220383ed4ed39b079b618bcb279bbc1f2ca18cb028c4641cb522c9c5868c52a0dc20147304402203c332ecccb3181ca82c0600520ee51fee80d3b4a6ab110945e59475ec71e44ac0220679a11f3ca9993b04ccebda3c834876f353b065bb08f50076b25f5bb93c72ae1016952210375e00eb72e29da82b89367947f29ef34afb75e8654f6ea368e0acdfd92976b7c2103a1b26313f430c4b15bb1fdce663207659d8cac749a0e53d70eff01874496feff2103c96d495bfdd5ba4145e3e046fee45e84a8a48ad05bd8dbb395c011a32cf9f88053ae00000000", Weight::from_wu(766)),
2221 (true, "010000000001036b6b6ac7e34e97c53c1cc74c99c7948af2e6aac75d8778004ae458d813456764000000006a473044022001deec7d9075109306320b3754188f81a8236d0d232b44bc69f8309115638b8f02204e17a5194a519cf994d0afeea1268740bdc10616b031a521113681cc415e815c012103488d3272a9fad78ee887f0684cb8ebcfc06d0945e1401d002e590c7338b163feffffffffc75bd7aa6424aee972789ec28ba181254ee6d8311b058d165bd045154d7660b0000000006b483045022100c8641bcbee3e4c47a00417875015d8c5d5ea918fb7e96f18c6ffe51bc555b401022074e2c46f5b1109cd79e39a9aa203eadd1d75356415e51d80928a5fb5feb0efee0121033504b4c6dfc3a5daaf7c425aead4c2dbbe4e7387ce8e6be2648805939ecf7054ffffffff494df3b205cd9430a26f8e8c0dc0bb80496fbc555a524d6ea307724bc7e60eee0100000000ffffffff026d861500000000001976a9145c54ed1360072ebaf56e87693b88482d2c6a101588ace407000000000000160014761e31e2629c6e11936f2f9888179d60a5d4c1f900000247304402201fa38a67a63e58b67b6cfffd02f59121ca1c8a1b22e1efe2573ae7e4b4f06c2b022002b9b431b58f6e36b3334fb14eaecee7d2f06967a77ef50d8d5f90dda1057f0c01210257dc6ce3b1100903306f518ee8fa113d778e403f118c080b50ce079fba40e09a00000000", Weight::from_wu(1755)),
2223 (false, "0100000003e4d7be4314204a239d8e00691128dca7927e19a7339c7948bde56f669d27d797010000006b483045022100b988a858e2982e2daaf0755b37ad46775d6132057934877a5badc91dee2f66ff022020b967c1a2f0916007662ec609987e951baafa6d4fda23faaad70715611d6a2501210254a2dccd8c8832d4677dc6f0e562eaaa5d11feb9f1de2c50a33832e7c6190796ffffffff9e22eb1b3f24c260187d716a8a6c2a7efb5af14a30a4792a6eeac3643172379c000000006a47304402207df07f0cd30dca2cf7bed7686fa78d8a37fe9c2254dfdca2befed54e06b779790220684417b8ff9f0f6b480546a9e90ecee86a625b3ea1e4ca29b080da6bd6c5f67e01210254a2dccd8c8832d4677dc6f0e562eaaa5d11feb9f1de2c50a33832e7c6190796ffffffff1123df3bfb503b59769731da103d4371bc029f57979ebce68067768b958091a1000000006a47304402207a016023c2b0c4db9a7d4f9232fcec2193c2f119a69125ad5bcedcba56dd525e02206a734b3a321286c896759ac98ebfd9d808df47f1ce1fbfbe949891cc3134294701210254a2dccd8c8832d4677dc6f0e562eaaa5d11feb9f1de2c50a33832e7c6190796ffffffff0200c2eb0b000000001976a914e5eb3e05efad136b1405f5c2f9adb14e15a35bb488ac88cfff1b000000001976a9144846db516db3130b7a3c92253599edec6bc9630b88ac00000000", Weight::from_wu(2080)),
2225 (true, "01000000000101b5cee87f1a60915c38bb0bc26aaf2b67be2b890bbc54bb4be1e40272e0d2fe0b0000000000ffffffff025529000000000000225120106daad8a5cb2e6fc74783714273bad554a148ca2d054e7a19250e9935366f3033760000000000002200205e6d83c44f57484fd2ef2a62b6d36cdcd6b3e06b661e33fd65588a28ad0dbe060141df9d1bfce71f90d68bf9e9461910b3716466bfe035c7dbabaa7791383af6c7ef405a3a1f481488a91d33cd90b098d13cb904323a3e215523aceaa04e1bb35cdb0100000000", Weight::from_wu(617)),
2227 (false, "0100000001c336895d9fa674f8b1e294fd006b1ac8266939161600e04788c515089991b50a030000006a47304402204213769e823984b31dcb7104f2c99279e74249eacd4246dabcf2575f85b365aa02200c3ee89c84344ae326b637101a92448664a8d39a009c8ad5d147c752cbe112970121028b1b44b4903c9103c07d5a23e3c7cf7aeb0ba45ddbd2cfdce469ab197381f195fdffffff040000000000000000536a4c5058325bb7b7251cf9e36cac35d691bd37431eeea426d42cbdecca4db20794f9a4030e6cb5211fabf887642bcad98c9994430facb712da8ae5e12c9ae5ff314127d33665000bb26c0067000bb0bf00322a50c300000000000017a9145ca04fdc0a6d2f4e3f67cfeb97e438bb6287725f8750c30000000000001976a91423086a767de0143523e818d4273ddfe6d9e4bbcc88acc8465003000000001976a914c95cbacc416f757c65c942f9b6b8a20038b9b12988ac00000000", Weight::from_wu(1396)),
2229 ];
2230
2231 let empty_transaction_weight = Transaction {
2232 version: Version::TWO,
2233 lock_time: absolute::LockTime::ZERO,
2234 input: vec![],
2235 output: vec![],
2236 }
2237 .weight();
2238
2239 for (is_segwit, tx, expected_weight) in &txs {
2240 let txin_weight = if *is_segwit { TxIn::segwit_weight } else { TxIn::legacy_weight };
2241 let tx: Transaction = deserialize(Vec::from_hex(tx).unwrap().as_slice()).unwrap();
2242 assert_eq!(*is_segwit, tx.uses_segwit_serialization());
2243
2244 let mut calculated_weight = empty_transaction_weight
2245 + tx.input.iter().fold(Weight::ZERO, |sum, i| sum + txin_weight(i))
2246 + tx.output.iter().fold(Weight::ZERO, |sum, o| sum + o.weight());
2247
2248 if !tx.uses_segwit_serialization() {
2250 calculated_weight -= Weight::from_wu(2);
2251 }
2252
2253 assert_eq!(calculated_weight, *expected_weight);
2254 assert_eq!(tx.weight(), *expected_weight);
2255 }
2256 }
2257
2258 #[test]
2259 fn tx_sigop_count() {
2260 let tx_hexes = [
2261 (
2263 "0200000001725aab4d23f76ad10bb569a68f8702ebfb8b076e015179ff9b9425234953\
2264 ac63000000006a47304402204cae7dc9bb68b588dd6b8afb8b881b752fd65178c25693e\
2265 a6d5d9a08388fd2a2022011c753d522d5c327741a6d922342c86e05c928309d7e566f68\
2266 8148432e887028012103f14b11cfb58b113716e0fa277ab4a32e4d3ed64c6b09b1747ef\
2267 7c828d5b06a94fdffffff01e5d4830100000000160014e98527b55cae861e5b9c3a6794\
2268 86514c012d6fce00000000",
2269 0, return_none as fn(&OutPoint) -> Option<TxOut>, 0, ),
2273 (
2275 "020000000001018c47330b1c4d30e7e2244e8ccb56d411b71e10073bb42fa1813f3f01\
2276 e144cc4d0100000000fdffffff01f7e30300000000001976a9143b49fd16f7562cfeedc\
2277 6a4ba84805f8c2f8e1a2c88ac024830450221009a4dbf077a63f6e4c3628a5fef2a09ec\
2278 6f7ca4a4d95bc8bb69195b6b671e9272022074da9ffff5a677fc7b37d66bb4ff1f316c9\
2279 dbacb92058291d84cd4b83f7c63c9012103d013e9e53c9ca8dd2ddffab1e9df27811503\
2280 feea7eb0700ff058851bbb37d99000000000",
2281 5,
2282 return_p2wpkh,
2283 4,
2284 ),
2285 (
2287 "01000000000101e70d7b4d957122909a665070b0c5bbb693982d09e4e66b9e6b7a8390\
2288 ce65ef1f0100000000ffffffff02095f2b0000000000220020800a016ea57a08f30c273\
2289 ae7624f8f91c505ccbd3043829349533f317168248c52594500000000001976a914607f\
2290 643372477c044c6d40b814288e40832a602688ac05004730440220282943649e687b5a3\
2291 bda9403c16f363c2ee2be0ec43fb8df40a08b96a4367d47022014e8f36938eef41a09ee\
2292 d77a815b0fa120a35f25e3a185310f050959420cee360147304402201e555f894036dd5\
2293 78045701e03bf10e093d7e93cd9997e44c1fc65a7b669852302206893f7261e52c9d779\
2294 5ba39d99aad30663da43ed675c389542805469fa8eb26a014730440220510fc99bc37d6\
2295 dbfa7e8724f4802cebdb17b012aaf70ce625e22e6158b139f40022022e9b811751d491f\
2296 bdec7691b697e88ba84315f6739b9e3bd4425ac40563aed2018b5321029ddecf0cc2013\
2297 514961550e981a0b8b60e7952f70561a5bb552aa7f075e71e3c2103316195a59c35a3b2\
2298 7b6dfcc3192cc10a7a6bbccd5658dfbe98ca62a13d6a02c121034629d906165742def4e\
2299 f53c6dade5dcbf88b775774cad151e35ae8285e613b0221035826a29938de2076950811\
2300 13c58bcf61fe6adacc3aacceb21c4827765781572d54ae00000000",
2301 8,
2302 return_p2wsh,
2303 4,
2304 ),
2305 (
2307 "010000000001018aec7e0729ba5a2d284303c89b3f397e92d54472a225d28eb0ae2fa6\
2308 5a7d1a2e02000000171600145ad5db65f313ab76726eb178c2fd8f21f977838dfdfffff\
2309 f03102700000000000017a914dca89e03ba124c2c70e55533f91100f2d9dab04587f2d7\
2310 1d00000000001976a91442a34f4b0a65bc81278b665d37fd15910d261ec588ac292c3b0\
2311 00000000017a91461978dcebd0db2da0235c1ba3e8087f9fd74c57f8702473044022000\
2312 9226f8def30a8ffa53e55ca5d71a72a64cd20ae7f3112562e3413bd0731d2c0220360d2\
2313 20435e67eef7f2bf0258d1dded706e3824f06d961ba9eeaed300b16c2cc012103180cff\
2314 753d3e4ee1aa72b2b0fd72ce75956d04f4c19400a3daed0b18c3ab831e00000000",
2315 5,
2316 return_p2sh,
2317 4,
2318 ),
2319 (
2321 "010000000115fe9ec3dc964e41f5267ea26cfe505f202bf3b292627496b04bece84da9\
2322 b18903000000fc004730440220442827f1085364bda58c5884cee7b289934083362db6d\
2323 fb627dc46f6cdbf5793022078cfa524252c381f2a572f0c41486e2838ca94aa268f2384\
2324 d0e515744bf0e1e9014730440220160e49536bb29a49c7626744ee83150174c22fa40d5\
2325 8fb4cd554a907a6a7b825022045f6cf148504b334064686795f0968c689e542f475b8ef\
2326 5a5fa42383948226a3014c69522103e54bc61efbcb8eeff3a5ab2a92a75272f5f6820e3\
2327 8e3d28edb54beb06b86c0862103a553e30733d7a8df6d390d59cc136e2c9d9cf4e808f3\
2328 b6ab009beae68dd60822210291c5a54bb8b00b6f72b90af0ac0ecaf78fab026d8eded28\
2329 2ad95d4d65db268c953aeffffffff024c4f0d000000000017a9146ebf0484bd5053f727\
2330 c755a750aa4c815dfa112887a06b12020000000017a91410065dd50b3a7f299fef3b1c5\
2331 3b8216399916ab08700000000",
2332 12,
2333 return_p2sh,
2334 0,
2335 ),
2336 (
2338 "0100000000010117a31277a8ba3957be351fe4cffd080e05e07f9ee1594d638f55dd7d\
2339 707a983c01000000232200203a33fc9628c29f36a492d9fd811fd20231fbd563f7863e7\
2340 9c4dc0ed34ea84b15ffffffff033bed03000000000017a914fb00d9a49663fd8ae84339\
2341 8ae81299a1941fb8d287429404000000000017a9148fe08d81882a339cf913281eca8af\
2342 39110507c798751ab1300000000002200208819e4bac0109b659de6b9168b83238a050b\
2343 ef16278e470083b39d28d2aa5a6904004830450221009faf81f72ec9b14a39f0f0e12f0\
2344 1a7175a4fe3239cd9a015ff2085985a9b0e3f022059e1aaf96c9282298bdc9968a46d8a\
2345 d28e7299799835cf982b02c35e217caeae0147304402202b1875355ee751e0c8b21990b\
2346 7ea73bd84dfd3bd17477b40fc96552acba306ad02204913bc43acf02821a3403132aa0c\
2347 33ac1c018d64a119f6cb55dfb8f408d997ef01695221023c15bf3436c0b4089e0ed0428\
2348 5101983199d0967bd6682d278821c1e2ac3583621034d924ccabac6d190ce8343829834\
2349 cac737aa65a9abe521bcccdcc3882d97481f21035d01d092bb0ebcb793ba3ffa0aeb143\
2350 2868f5277d5d3d2a7d2bc1359ec13abbd53aee1560c00",
2351 3,
2352 return_p2sh,
2353 0,
2354 ),
2355 (
2357 "0100000001628c1726fecd23331ae9ff2872341b82d2c03180aa64f9bceefe457448db\
2358 e579020000006a47304402204799581a5b34ae5adca21ef22c55dbfcee58527127c95d0\
2359 1413820fe7556ed970220391565b24dc47ce57fe56bf029792f821a392cdb5a3d45ed85\
2360 c158997e7421390121037b2fb5b602e51c493acf4bf2d2423bcf63a09b3b99dfb7bd3c8\
2361 d74733b5d66f5ffffffff011c0300000000000069512103a29472a1848105b2225f0eca\
2362 5c35ada0b0abbc3c538818a53eca177f4f4dcd9621020c8fd41b65ae6b980c072c5a9f3\
2363 aec9f82162c92eb4c51d914348f4390ac39122102222222222222222222222222222222\
2364 222222222222222222222222222222222253ae00000000",
2365 80,
2366 return_none,
2367 80,
2368 ),
2369 ];
2370
2371 fn return_p2sh(_outpoint: &OutPoint) -> Option<TxOut> {
2373 Some(
2374 deserialize(&hex!(
2375 "cc721b000000000017a91428203c10cc8f18a77412caaa83dabaf62b8fbb0f87"
2376 ))
2377 .unwrap(),
2378 )
2379 }
2380 fn return_p2wpkh(_outpoint: &OutPoint) -> Option<TxOut> {
2381 Some(
2382 deserialize(&hex!(
2383 "e695779d000000001600141c6977423aa4b82a0d7f8496cdf3fc2f8b4f580c"
2384 ))
2385 .unwrap(),
2386 )
2387 }
2388 fn return_p2wsh(_outpoint: &OutPoint) -> Option<TxOut> {
2389 Some(
2390 deserialize(&hex!(
2391 "66b51e0900000000220020dbd6c9d5141617eff823176aa226eb69153c1e31334ac37469251a2539fc5c2b"
2392 ))
2393 .unwrap(),
2394 )
2395 }
2396 fn return_none(_outpoint: &OutPoint) -> Option<TxOut> { None }
2397
2398 for (hx, expected, spent_fn, expected_none) in tx_hexes.iter() {
2399 let tx_bytes = hex!(hx);
2400 let tx: Transaction = deserialize(&tx_bytes).unwrap();
2401 assert_eq!(tx.total_sigop_cost(spent_fn), *expected);
2402 assert_eq!(tx.total_sigop_cost(return_none), *expected_none);
2403 }
2404 }
2405
2406 #[test]
2407 fn weight_predictions() {
2408 let tx_raw = hex!(
2410 "01000000000103fc9aa70afba04da865f9821734b556cca9fb5710\
2411 fc1338b97fba811033f755e308000000000000000019b37457784d\
2412 d04936f011f733b8016c247a9ef08d40007a54a5159d1fc62ee216\
2413 00000000000000004c4f2937c6ccf8256d9711a19df1ae62172297\
2414 0bf46be925ff15f490efa1633d01000000000000000002c0e1e400\
2415 0000000017a9146983f776902c1d1d0355ae0962cb7bc69e9afbde\
2416 8706a1e600000000001600144257782711458506b89f255202d645\
2417 e25c41144702483045022100dcada0499865a49d0aab8cb113c5f8\
2418 3fd5a97abc793f97f3f53aa4b9d1192ed702202094c7934666a30d\
2419 6adb1cc9e3b6bc14d2ffebd3200f3908c40053ef2df640b5012103\
2420 15434bb59b615a383ae87316e784fc11835bb97fab33fdd2578025\
2421 e9968d516e0247304402201d90b3197650569eba4bc0e0b1e2dca7\
2422 7dfac7b80d4366f335b67e92e0546e4402203b4be1d443ad7e3a5e\
2423 a92aafbcdc027bf9ccf5fe68c0bc8f3ebb6ab806c5464c012103e0\
2424 0d92b0fe60731a54fdbcc6920934159db8ffd69d55564579b69a22\
2425 ec5bb7530247304402205ab83b734df818e64d8b9e86a8a75f9d00\
2426 5c0c6e1b988d045604853ab9ccbde002205a580235841df609d6bd\
2427 67534bdcd301999b18e74e197e9e476cdef5fdcbf822012102ebb3\
2428 e8a4638ede4721fb98e44e3a3cd61fecfe744461b85e0b6a6a1017\
2429 5d5aca00000000"
2430 );
2431
2432 let tx = Transaction::consensus_decode::<&[u8]>(&mut tx_raw.as_ref()).unwrap();
2433 let input_weights = vec![
2434 InputWeightPrediction::P2WPKH_MAX,
2435 InputWeightPrediction::ground_p2wpkh(1),
2436 InputWeightPrediction::ground_p2wpkh(1),
2437 ];
2438 let predicted = predict_weight(input_weights, tx.script_pubkey_lens());
2442 let expected = tx.weight();
2443 assert_eq!(predicted, expected);
2444
2445 assert_eq!(
2447 InputWeightPrediction::ground_p2wpkh(0).weight(),
2448 InputWeightPrediction::P2WPKH_MAX.weight()
2449 );
2450 assert_eq!(
2451 InputWeightPrediction::ground_p2pkh_compressed(0).weight(),
2452 InputWeightPrediction::P2PKH_COMPRESSED_MAX.weight()
2453 );
2454 }
2455
2456 #[test]
2457 fn sequence_debug_output() {
2458 let seq = Sequence::from_seconds_floor(1000);
2459 println!("{:?}", seq)
2460 }
2461
2462 #[test]
2463 fn outpoint_format() {
2464 let outpoint = OutPoint::default();
2465
2466 let debug = "OutPoint { txid: 0000000000000000000000000000000000000000000000000000000000000000, vout: 4294967295 }";
2467 assert_eq!(debug, format!("{:?}", &outpoint));
2468
2469 let display = "0000000000000000000000000000000000000000000000000000000000000000:4294967295";
2470 assert_eq!(display, format!("{}", &outpoint));
2471
2472 let pretty_debug = "OutPoint {\n txid: 0000000000000000000000000000000000000000000000000000000000000000,\n vout: 4294967295,\n}";
2473 assert_eq!(pretty_debug, format!("{:#?}", &outpoint));
2474
2475 let debug_txid = "0000000000000000000000000000000000000000000000000000000000000000";
2476 assert_eq!(debug_txid, format!("{:?}", &outpoint.txid));
2477
2478 let display_txid = "0000000000000000000000000000000000000000000000000000000000000000";
2479 assert_eq!(display_txid, format!("{}", &outpoint.txid));
2480
2481 let pretty_txid = "0x0000000000000000000000000000000000000000000000000000000000000000";
2482 assert_eq!(pretty_txid, format!("{:#}", &outpoint.txid));
2483 }
2484}
2485
2486#[cfg(bench)]
2487mod benches {
2488 use hex_lit::hex;
2489 use io::sink;
2490 use test::{black_box, Bencher};
2491
2492 use super::Transaction;
2493 use crate::consensus::{deserialize, Encodable};
2494
2495 const SOME_TX: &str = "0100000001a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff0100e1f505000000001976a9140389035a9225b3839e2bbf32d826a1e222031fd888ac00000000";
2496
2497 #[bench]
2498 pub fn bench_transaction_size(bh: &mut Bencher) {
2499 let raw_tx = hex!(SOME_TX);
2500
2501 let mut tx: Transaction = deserialize(&raw_tx).unwrap();
2502
2503 bh.iter(|| {
2504 black_box(black_box(&mut tx).total_size());
2505 });
2506 }
2507
2508 #[bench]
2509 pub fn bench_transaction_serialize(bh: &mut Bencher) {
2510 let raw_tx = hex!(SOME_TX);
2511 let tx: Transaction = deserialize(&raw_tx).unwrap();
2512
2513 let mut data = Vec::with_capacity(raw_tx.len());
2514
2515 bh.iter(|| {
2516 let result = tx.consensus_encode(&mut data);
2517 black_box(&result);
2518 data.clear();
2519 });
2520 }
2521
2522 #[bench]
2523 pub fn bench_transaction_serialize_logic(bh: &mut Bencher) {
2524 let raw_tx = hex!(SOME_TX);
2525 let tx: Transaction = deserialize(&raw_tx).unwrap();
2526
2527 bh.iter(|| {
2528 let size = tx.consensus_encode(&mut sink());
2529 black_box(&size);
2530 });
2531 }
2532
2533 #[bench]
2534 pub fn bench_transaction_deserialize(bh: &mut Bencher) {
2535 let raw_tx = hex!(SOME_TX);
2536
2537 bh.iter(|| {
2538 let tx: Transaction = deserialize(&raw_tx).unwrap();
2539 black_box(&tx);
2540 });
2541 }
2542}