bc/
tx.rs

1// Bitcoin protocol consensus library.
2//
3// SPDX-License-Identifier: Apache-2.0
4//
5// Written in 2019-2024 by
6//     Dr Maxim Orlovsky <orlovsky@lnp-bp.org>
7//
8// Copyright (C) 2019-2024 LNP/BP Standards Association. All rights reserved.
9//
10// Licensed under the Apache License, Version 2.0 (the "License");
11// you may not use this file except in compliance with the License.
12// You may obtain a copy of the License at
13//
14//     http://www.apache.org/licenses/LICENSE-2.0
15//
16// Unless required by applicable law or agreed to in writing, software
17// distributed under the License is distributed on an "AS IS" BASIS,
18// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19// See the License for the specific language governing permissions and
20// limitations under the License.
21
22use core::slice;
23use std::fmt::{self, Debug, Display, Formatter, LowerHex};
24use std::iter::Sum;
25use std::num::ParseIntError;
26use std::ops::{Div, Rem};
27use std::str::FromStr;
28
29use amplify::hex::{self, FromHex, ToHex};
30use amplify::{ByteArray, Bytes32StrRev, Wrapper};
31use commit_verify::{DigestExt, Sha256};
32
33use crate::{
34    ConsensusDecode, ConsensusDecodeError, ConsensusEncode, LockTime, NonStandardValue,
35    ScriptPubkey, SeqNo, SigScript, VarIntArray, Witness, Wtxid, LIB_NAME_BITCOIN,
36};
37
38#[derive(Wrapper, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, From)]
39#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)]
40#[strict_type(lib = LIB_NAME_BITCOIN)]
41#[cfg_attr(
42    feature = "serde",
43    derive(Serialize, Deserialize),
44    serde(crate = "serde_crate", transparent)
45)]
46#[wrapper(BorrowSlice, Index, RangeOps, Debug, Hex, Display, FromStr)]
47// all-zeros used in coinbase
48pub struct Txid(
49    #[from]
50    #[from([u8; 32])]
51    Bytes32StrRev,
52);
53
54impl Txid {
55    #[inline]
56    pub const fn coinbase() -> Self { Self(Bytes32StrRev::zero()) }
57    #[inline]
58    pub fn is_coinbase(&self) -> bool { self.to_byte_array() == [0u8; 32] }
59}
60
61#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Display, From)]
62#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)]
63#[strict_type(lib = LIB_NAME_BITCOIN)]
64#[cfg_attr(
65    feature = "serde",
66    derive(Serialize, Deserialize),
67    serde(crate = "serde_crate", transparent)
68)]
69#[display(inner)]
70// 0xFFFFFFFF used in coinbase
71pub struct Vout(u32);
72
73impl Vout {
74    pub const fn from_u32(u: u32) -> Self { Vout(u) }
75    #[inline]
76    pub const fn into_u32(self) -> u32 { self.0 }
77    #[inline]
78    pub const fn into_usize(self) -> usize { self.0 as usize }
79    #[inline]
80    pub const fn to_u32(&self) -> u32 { self.0 }
81    #[inline]
82    pub const fn to_usize(&self) -> usize { self.0 as usize }
83}
84
85impl FromStr for Vout {
86    type Err = ParseIntError;
87
88    #[inline]
89    fn from_str(s: &str) -> Result<Self, Self::Err> { s.parse().map(Self) }
90}
91
92#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Display)]
93#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)]
94#[strict_type(lib = LIB_NAME_BITCOIN)]
95#[display("{txid}:{vout}")]
96pub struct Outpoint {
97    pub txid: Txid,
98    pub vout: Vout,
99}
100
101impl Outpoint {
102    #[inline]
103    pub fn new(txid: Txid, vout: impl Into<Vout>) -> Self {
104        Self {
105            txid,
106            vout: vout.into(),
107        }
108    }
109
110    #[inline]
111    pub const fn coinbase() -> Self {
112        Self {
113            txid: Txid::coinbase(),
114            vout: Vout::from_u32(0),
115        }
116    }
117
118    #[inline]
119    pub fn vout_u32(self) -> u32 { self.vout.into_u32() }
120
121    #[inline]
122    pub fn vout_usize(self) -> usize { self.vout.into_usize() }
123
124    #[inline]
125    pub fn is_coinbase(&self) -> bool { self.txid.is_coinbase() && self.vout.into_u32() == 0 }
126}
127
128#[derive(Clone, Eq, PartialEq, Debug, Display, From, Error)]
129#[display(doc_comments)]
130pub enum OutpointParseError {
131    /// malformed string representation of outoint '{0}' lacking txid and vout
132    /// separator ':'
133    MalformedSeparator(String),
134
135    /// malformed outpoint output number. Details: {0}
136    #[from]
137    InvalidVout(ParseIntError),
138
139    /// malformed outpoint txid value. Details: {0}
140    #[from]
141    InvalidTxid(hex::Error),
142}
143
144impl FromStr for Outpoint {
145    type Err = OutpointParseError;
146
147    fn from_str(s: &str) -> Result<Self, Self::Err> {
148        let (txid, vout) = s
149            .split_once(':')
150            .ok_or_else(|| OutpointParseError::MalformedSeparator(s.to_owned()))?;
151        Ok(Outpoint::new(txid.parse()?, Vout::from_str(vout)?))
152    }
153}
154
155#[cfg(feature = "serde")]
156mod _serde_outpoint {
157    use serde::de::{SeqAccess, Visitor};
158    use serde::ser::SerializeTuple;
159    use serde::{Deserialize, Deserializer, Serialize, Serializer};
160
161    use super::*;
162
163    impl Serialize for Outpoint {
164        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
165        where S: Serializer {
166            if serializer.is_human_readable() {
167                serializer.serialize_str(&self.to_string())
168            } else {
169                let mut ser = serializer.serialize_tuple(2)?;
170                ser.serialize_element(&self.txid)?;
171                ser.serialize_element(&self.vout)?;
172                ser.end()
173            }
174        }
175    }
176
177    impl<'de> Deserialize<'de> for Outpoint {
178        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
179        where D: Deserializer<'de> {
180            use serde::de::Error;
181            if deserializer.is_human_readable() {
182                String::deserialize(deserializer).and_then(|string| {
183                    Self::from_str(&string)
184                        .map_err(|_| D::Error::custom("wrong outpoint string representation"))
185                })
186            } else {
187                struct OutpointVisitor;
188
189                impl<'de> Visitor<'de> for OutpointVisitor {
190                    type Value = Outpoint;
191
192                    fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
193                        write!(formatter, "a transaction outpoint")
194                    }
195
196                    fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
197                    where A: SeqAccess<'de> {
198                        let mut outpoint = Outpoint::coinbase();
199                        outpoint.txid =
200                            seq.next_element()?.ok_or_else(|| Error::invalid_length(0, &self))?;
201                        outpoint.vout =
202                            seq.next_element()?.ok_or_else(|| Error::invalid_length(1, &self))?;
203                        Ok(outpoint)
204                    }
205                }
206
207                deserializer.deserialize_tuple(2, OutpointVisitor)
208            }
209        }
210    }
211}
212
213#[derive(Clone, Eq, PartialEq, Hash, Debug)]
214#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)]
215#[strict_type(lib = LIB_NAME_BITCOIN)]
216#[cfg_attr(
217    feature = "serde",
218    derive(Serialize, Deserialize),
219    serde(crate = "serde_crate", rename_all = "camelCase")
220)]
221pub struct TxIn {
222    pub prev_output: Outpoint,
223    pub sig_script: SigScript,
224    pub sequence: SeqNo,
225    pub witness: Witness,
226}
227
228#[derive(
229    Wrapper, WrapperMut, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, From, Default
230)]
231#[wrapper(Add, Sub, Mul, Div, FromStr)]
232#[wrapper_mut(MathAssign)]
233#[derive(StrictType, StrictEncode, StrictDecode)]
234#[strict_type(lib = LIB_NAME_BITCOIN)]
235#[cfg_attr(
236    feature = "serde",
237    derive(Serialize, Deserialize),
238    serde(crate = "serde_crate", transparent)
239)]
240pub struct Sats(
241    #[from]
242    #[from(u32)]
243    #[from(u16)]
244    #[from(u8)]
245    pub u64,
246);
247
248impl Sats {
249    pub const ZERO: Self = Sats(0);
250    #[allow(clippy::inconsistent_digit_grouping)]
251    pub const BTC: Self = Sats(1_000_000_00);
252
253    pub const fn from_btc(btc: u32) -> Self { Self(btc as u64 * Self::BTC.0) }
254    pub fn from_sats(sats: impl Into<u64>) -> Self { Self(sats.into()) }
255
256    pub const fn is_zero(&self) -> bool { self.0 == 0 }
257    pub const fn is_non_zero(&self) -> bool { self.0 != 0 }
258
259    pub const fn btc_round(&self) -> u64 {
260        if self.0 == 0 {
261            return 0;
262        }
263        let inc = 2 * self.sats_rem() / Self::BTC.0;
264        self.0 / Self::BTC.0 + inc
265    }
266
267    pub const fn btc_ceil(&self) -> u64 {
268        if self.0 == 0 {
269            return 0;
270        }
271        let inc = if self.sats_rem() > 0 { 1 } else { 0 };
272        self.0 / Self::BTC.0 + inc
273    }
274
275    pub const fn btc_floor(&self) -> u64 {
276        if self.0 == 0 {
277            return 0;
278        }
279        self.0 / Self::BTC.0
280    }
281
282    pub const fn sats(&self) -> u64 { self.0 }
283
284    pub fn sats_i64(&self) -> i64 {
285        i64::try_from(self.0).expect("amount of sats exceeds total bitcoin supply")
286    }
287
288    pub const fn sats_rem(&self) -> u64 { self.0 % Self::BTC.0 }
289
290    pub const fn btc_sats(&self) -> (u64, u64) { (self.btc_floor(), self.sats_rem()) }
291
292    #[must_use]
293    pub fn checked_add(&self, other: impl Into<Self>) -> Option<Self> {
294        self.0.checked_add(other.into().0).map(Self)
295    }
296    #[must_use]
297    pub fn checked_sub(&self, other: impl Into<Self>) -> Option<Self> {
298        self.0.checked_sub(other.into().0).map(Self)
299    }
300
301    #[must_use]
302    pub fn checked_add_assign(&mut self, other: impl Into<Self>) -> Option<Self> {
303        *self = Self(self.0.checked_add(other.into().0)?);
304        Some(*self)
305    }
306
307    #[must_use]
308    pub fn checked_sub_assign(&mut self, other: impl Into<Self>) -> Option<Self> {
309        *self = Self(self.0.checked_sub(other.into().0)?);
310        Some(*self)
311    }
312
313    #[must_use]
314    pub fn saturating_add(&self, other: impl Into<Self>) -> Self {
315        self.0.saturating_add(other.into().0).into()
316    }
317
318    #[must_use]
319    pub fn saturating_sub(&self, other: impl Into<Self>) -> Self {
320        self.0.saturating_sub(other.into().0).into()
321    }
322
323    pub fn saturating_add_assign(&mut self, other: impl Into<Self>) {
324        *self = self.0.saturating_add(other.into().0).into();
325    }
326    pub fn saturating_sub_assign(&mut self, other: impl Into<Self>) {
327        *self = self.0.saturating_sub(other.into().0).into();
328    }
329}
330
331impl PartialEq<u64> for Sats {
332    fn eq(&self, other: &u64) -> bool { self.0.eq(other) }
333}
334
335impl Sum for Sats {
336    fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
337        iter.fold(Sats::ZERO, |sum, value| sum.saturating_add(value))
338    }
339}
340
341impl Sum<u64> for Sats {
342    fn sum<I: Iterator<Item = u64>>(iter: I) -> Self {
343        iter.fold(Sats::ZERO, |sum, value| sum.saturating_add(value))
344    }
345}
346
347impl Div<usize> for Sats {
348    type Output = Sats;
349    fn div(self, rhs: usize) -> Self::Output { Sats(self.0 / rhs as u64) }
350}
351
352impl Rem<usize> for Sats {
353    type Output = Sats;
354    fn rem(self, rhs: usize) -> Self::Output { Sats(self.0 % rhs as u64) }
355}
356
357impl Display for Sats {
358    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { Display::fmt(&self.0, f) }
359}
360
361#[derive(Clone, Eq, PartialEq, Hash, Debug, Default)]
362#[derive(StrictType, StrictEncode, StrictDecode)]
363#[strict_type(lib = LIB_NAME_BITCOIN)]
364#[cfg_attr(
365    feature = "serde",
366    derive(Serialize, Deserialize),
367    serde(crate = "serde_crate", rename_all = "camelCase")
368)]
369pub struct TxOut {
370    pub value: Sats,
371    pub script_pubkey: ScriptPubkey,
372}
373
374impl TxOut {
375    pub fn new(script_pubkey: impl Into<ScriptPubkey>, value: impl Into<Sats>) -> Self {
376        TxOut {
377            script_pubkey: script_pubkey.into(),
378            value: value.into(),
379        }
380    }
381}
382
383#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
384#[derive(StrictType, StrictEncode, StrictDecode)]
385#[strict_type(lib = LIB_NAME_BITCOIN)]
386#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(crate = "serde_crate"))]
387pub struct TxVer(i32);
388
389impl Default for TxVer {
390    fn default() -> Self { TxVer(2) }
391}
392
393impl TxVer {
394    /// Pre-BIP68 version.
395    pub const V1: Self = TxVer(1);
396    /// Current version (post-BIP68).
397    pub const V2: Self = TxVer(2);
398
399    #[inline]
400    pub const fn from_consensus_i32(ver: i32) -> Self { TxVer(ver) }
401
402    pub const fn try_from_standard(ver: i32) -> Result<Self, NonStandardValue<i32>> {
403        let ver = TxVer::from_consensus_i32(ver);
404        if !ver.is_standard() {
405            Err(NonStandardValue::with(ver.0, "TxVer"))
406        } else {
407            Ok(ver)
408        }
409    }
410
411    #[inline]
412    pub const fn is_standard(self) -> bool { self.0 <= TxVer::V2.0 }
413
414    #[inline]
415    pub const fn to_consensus_i32(&self) -> i32 { self.0 }
416}
417
418#[derive(Clone, Eq, PartialEq, Hash, Debug, Display)]
419#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)]
420#[strict_type(lib = LIB_NAME_BITCOIN)]
421#[cfg_attr(
422    feature = "serde",
423    derive(Serialize, Deserialize),
424    serde(crate = "serde_crate", rename_all = "camelCase")
425)]
426#[display(LowerHex)]
427pub struct Tx {
428    pub version: TxVer,
429    pub inputs: VarIntArray<TxIn>,
430    pub outputs: VarIntArray<TxOut>,
431    pub lock_time: LockTime,
432}
433
434impl LowerHex for Tx {
435    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
436        f.write_str(&self.consensus_serialize().to_hex())
437    }
438}
439
440#[derive(Clone, PartialEq, Eq, Debug, Display, Error, From)]
441#[display(inner)]
442pub enum BlockDataParseError {
443    #[from]
444    Hex(hex::Error),
445    #[from]
446    Consensus(ConsensusDecodeError),
447}
448
449impl FromStr for Tx {
450    type Err = BlockDataParseError;
451
452    fn from_str(s: &str) -> Result<Self, Self::Err> {
453        let data = Vec::<u8>::from_hex(s)?;
454        Tx::consensus_deserialize(data).map_err(BlockDataParseError::from)
455    }
456}
457
458impl Tx {
459    #[inline]
460    pub fn inputs(&self) -> slice::Iter<TxIn> { self.inputs.iter() }
461
462    #[inline]
463    pub fn outputs(&self) -> slice::Iter<TxOut> { self.outputs.iter() }
464
465    #[inline]
466    pub fn is_segwit(&self) -> bool { self.inputs().any(|txin| !txin.witness.is_empty()) }
467
468    #[inline]
469    pub fn to_unsigned_tx(&self) -> Tx {
470        let mut tx = self.clone();
471        for input in &mut tx.inputs {
472            input.sig_script = SigScript::empty();
473            input.witness = empty!();
474        }
475        tx
476    }
477
478    /// Computes a "normalized TXID" which does not include any signatures.
479    ///
480    /// This gives a way to identify a transaction that is "the same" as
481    /// another in the sense of having same inputs and outputs.
482    pub fn ntxid(&self) -> [u8; 32] { self.to_unsigned_tx().txid().to_byte_array() }
483
484    /// Computes the [`Txid`].
485    ///
486    /// Hashes the transaction **excluding** the segwit data (i.e. the marker,
487    /// flag bytes, and the witness fields themselves). For non-segwit
488    /// transactions which do not have any segwit data, this will be equal
489    /// to [`Tx::wtxid()`].
490    pub fn txid(&self) -> Txid {
491        let mut enc = Sha256::default();
492        self.version.consensus_encode(&mut enc).expect("engines don't error");
493        self.inputs.consensus_encode(&mut enc).expect("engines don't error");
494        self.outputs.consensus_encode(&mut enc).expect("engines don't error");
495        self.lock_time.consensus_encode(&mut enc).expect("engines don't error");
496        let mut double = Sha256::default();
497        double.input_raw(&enc.finish());
498        Txid::from_byte_array(double.finish())
499    }
500
501    /// Computes the segwit version of the transaction id.
502    ///
503    /// Hashes the transaction **including** all segwit data (i.e. the marker,
504    /// flag bytes, and the witness fields themselves). For non-segwit
505    /// transactions which do not have any segwit data, this will be equal
506    /// to [`Transaction::txid()`].
507    pub fn wtxid(&self) -> Wtxid {
508        let mut enc = Sha256::default();
509        self.consensus_encode(&mut enc).expect("engines don't error");
510        let mut double = Sha256::default();
511        double.input_raw(&enc.finish());
512        Wtxid::from_byte_array(double.finish())
513    }
514}
515
516#[cfg(test)]
517mod test {
518    use super::*;
519
520    #[test]
521    fn txid_byteorder() {
522        let hex = "ed9f6388c0360c1861d331a0388d5a54815dd720cc67fa783c348217a0e943ca";
523        let from_str = Txid::from_str(hex).unwrap();
524        let from_hex = Txid::from_hex(hex).unwrap();
525        assert_eq!(from_str, from_hex);
526        assert_eq!(from_str.to_string(), from_str.to_hex());
527        assert_eq!(from_str.to_string(), hex);
528        assert_eq!(format!("{from_str:x}"), hex);
529        assert_eq!(from_str[0], 0xca);
530    }
531
532    #[test]
533    fn sats() {
534        assert_eq!(Sats(0).0, 0);
535        assert_eq!(Sats(0).btc_round(), 0);
536        assert_eq!(Sats(0).btc_ceil(), 0);
537        assert_eq!(Sats(0).btc_floor(), 0);
538        assert_eq!(Sats(0).sats(), 0);
539        assert_eq!(Sats(0).sats_rem(), 0);
540
541        assert_eq!(Sats(1000).0, 1000);
542        assert_eq!(Sats(1000).btc_round(), 0);
543        assert_eq!(Sats(1000).btc_ceil(), 1);
544        assert_eq!(Sats(1000).btc_floor(), 0);
545        assert_eq!(Sats(1000).sats(), 1000);
546        assert_eq!(Sats(1000).sats_rem(), 1000);
547
548        assert_eq!(Sats(49_999_999).btc_round(), 0);
549        assert_eq!(Sats(49_999_999).btc_ceil(), 1);
550        assert_eq!(Sats(49_999_999).btc_floor(), 0);
551        assert_eq!(Sats(50_000_000).0, 50_000_000);
552        assert_eq!(Sats(50_000_000).btc_round(), 1);
553        assert_eq!(Sats(50_000_000).btc_ceil(), 1);
554        assert_eq!(Sats(50_000_000).btc_floor(), 0);
555        assert_eq!(Sats(50_000_000).sats(), 50_000_000);
556        assert_eq!(Sats(50_000_000).sats_rem(), 50_000_000);
557
558        assert_eq!(Sats(99_999_999).btc_round(), 1);
559        assert_eq!(Sats(99_999_999).btc_ceil(), 1);
560        assert_eq!(Sats(99_999_999).btc_floor(), 0);
561        assert_eq!(Sats(100_000_000), Sats::from_btc(1));
562        assert_eq!(Sats(100_000_000).0, 100_000_000);
563        assert_eq!(Sats(100_000_000).btc_round(), 1);
564        assert_eq!(Sats(100_000_000).btc_ceil(), 1);
565        assert_eq!(Sats(100_000_000).btc_floor(), 1);
566        assert_eq!(Sats(100_000_000).sats(), 100_000_000);
567        assert_eq!(Sats(100_000_000).sats_rem(), 0);
568        assert_eq!(Sats(100_000_001).sats(), 100_000_001);
569        assert_eq!(Sats(100_000_001).sats_rem(), 1);
570        assert_eq!(Sats(110_000_000).sats(), 110_000_000);
571        assert_eq!(Sats(110_000_000).sats_rem(), 10_000_000);
572    }
573
574    #[test]
575    fn nonsegwit_transaction() {
576        let tx =
577            "0100000001a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c49\
578            3046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7\
579            f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506e\
580            fdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff0100e1f505000000001976a9140389035a9225b\
581            3839e2bbf32d826a1e222031fd888ac00000000";
582        let realtx = Tx::from_str(tx).unwrap();
583
584        assert_eq!(&realtx.to_string(), tx);
585        assert_eq!(&realtx.to_hex(), tx);
586        assert_eq!(&format!("{realtx:x}"), tx);
587
588        // All these tests aren't really needed because if they fail, the hash check at
589        // the end will also fail. But these will show you where the failure is
590        // so I'll leave them in.
591        assert_eq!(realtx.version, TxVer::V1);
592        assert_eq!(realtx.inputs.len(), 1);
593        // In particular this one is easy to get backward -- in bitcoin hashes are
594        // encoded as little-endian 256-bit numbers rather than as data strings.
595        assert_eq!(
596            format!("{:x}", realtx.inputs[0].prev_output.txid),
597            "ce9ea9f6f5e422c6a9dbcddb3b9a14d1c78fab9ab520cb281aa2a74a09575da1".to_string()
598        );
599        assert_eq!(realtx.inputs[0].prev_output.vout, Vout::from_u32(1));
600        assert_eq!(realtx.outputs.len(), 1);
601        assert_eq!(realtx.lock_time, LockTime::ZERO);
602
603        assert_eq!(
604            format!("{:x}", realtx.txid()),
605            "a6eab3c14ab5272a58a5ba91505ba1a4b6d7a3a9fcbd187b6cd99a7b6d548cb7".to_string()
606        );
607        assert_eq!(
608            format!("{:x}", realtx.wtxid()),
609            "a6eab3c14ab5272a58a5ba91505ba1a4b6d7a3a9fcbd187b6cd99a7b6d548cb7".to_string()
610        );
611        /* TODO: Enable once weight calculation is there
612        assert_eq!(realtx.weight().to_wu() as usize, tx_bytes.len() * WITNESS_SCALE_FACTOR);
613        assert_eq!(realtx.total_size(), tx_bytes.len());
614        assert_eq!(realtx.vsize(), tx_bytes.len());
615        assert_eq!(realtx.base_size(), tx_bytes.len());
616         */
617    }
618
619    #[test]
620    fn segwit_transaction() {
621        let tx =
622            "02000000000101595895ea20179de87052b4046dfe6fd515860505d6511a9004cf12a1f93cac7c01000000\
623            00ffffffff01deb807000000000017a9140f3444e271620c736808aa7b33e370bd87cb5a078702483045022\
624            100fb60dad8df4af2841adc0346638c16d0b8035f5e3f3753b88db122e70c79f9370220756e6633b17fd271\
625            0e626347d28d60b0a2d6cbb41de51740644b9fb3ba7751040121028fa937ca8cba2197a37c007176ed89410\
626            55d3bcb8627d085e94553e62f057dcc00000000";
627        let realtx = Tx::from_str(tx).unwrap();
628
629        assert_eq!(&realtx.to_string(), tx);
630        assert_eq!(&realtx.to_hex(), tx);
631        assert_eq!(&format!("{realtx:x}"), tx);
632
633        // All these tests aren't really needed because if they fail, the hash check at
634        // the end will also fail. But these will show you where the failure is
635        // so I'll leave them in.
636        assert_eq!(realtx.version, TxVer::V2);
637        assert_eq!(realtx.inputs.len(), 1);
638        // In particular this one is easy to get backward -- in bitcoin hashes are
639        // encoded as little-endian 256-bit numbers rather than as data strings.
640        assert_eq!(
641            format!("{:x}", realtx.inputs[0].prev_output.txid),
642            "7cac3cf9a112cf04901a51d605058615d56ffe6d04b45270e89d1720ea955859".to_string()
643        );
644        assert_eq!(realtx.inputs[0].prev_output.vout, Vout::from_u32(1));
645        assert_eq!(realtx.outputs.len(), 1);
646        assert_eq!(realtx.lock_time, LockTime::ZERO);
647
648        assert_eq!(
649            format!("{:x}", realtx.txid()),
650            "f5864806e3565c34d1b41e716f72609d00b55ea5eac5b924c9719a842ef42206".to_string()
651        );
652        assert_eq!(
653            format!("{:x}", realtx.wtxid()),
654            "80b7d8a82d5d5bf92905b06f2014dd699e03837ca172e3a59d51426ebbe3e7f5".to_string()
655        );
656
657        /* TODO: Enable once weight calculation is there
658        const EXPECTED_WEIGHT: Weight = Weight::from_wu(442);
659        assert_eq!(realtx.weight(), EXPECTED_WEIGHT);
660        assert_eq!(realtx.total_size(), tx_bytes.len());
661        assert_eq!(realtx.vsize(), 111);
662
663        let expected_strippedsize = (442 - realtx.total_size()) / 3;
664        assert_eq!(realtx.base_size(), expected_strippedsize);
665
666        // Construct a transaction without the witness data.
667        let mut tx_without_witness = realtx;
668        tx_without_witness.input.iter_mut().for_each(|input| input.witness.clear());
669        assert_eq!(tx_without_witness.total_size(), tx_without_witness.total_size());
670        assert_eq!(tx_without_witness.total_size(), expected_strippedsize);
671         */
672    }
673}