From: github-actions Date: Tue, 13 Sep 2022 16:41:39 +0000 (+0000) Subject: Publish autogenerated nightly docs X-Git-Url: http://internal-gitweb-vhost/script/%22https:/database/crate::database::Database?a=commitdiff_plain;h=887af7dd832b8bb3f454b5ef5c24072bee447c7b;p=bitcoindevkit.org Publish autogenerated nightly docs --- diff --git a/docs/.vuepress/public/docs-rs/bdk/nightly/latest/src/bdk/psbt/mod.rs.html b/docs/.vuepress/public/docs-rs/bdk/nightly/latest/src/bdk/psbt/mod.rs.html index 19df1f58b3..7017b57f09 100644 --- a/docs/.vuepress/public/docs-rs/bdk/nightly/latest/src/bdk/psbt/mod.rs.html +++ b/docs/.vuepress/public/docs-rs/bdk/nightly/latest/src/bdk/psbt/mod.rs.html @@ -126,6 +126,118 @@ 119 120 121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233
// Bitcoin Dev Kit
 // Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
 //
@@ -137,11 +249,22 @@
 // You may not use this file except in accordance with one or both of these
 // licenses.
 
+use crate::FeeRate;
 use bitcoin::util::psbt::PartiallySignedTransaction as Psbt;
 use bitcoin::TxOut;
 
 pub trait PsbtUtils {
     fn get_utxo_for(&self, input_index: usize) -> Option<TxOut>;
+
+    /// The total transaction fee amount, sum of input amounts minus sum of output amounts, in Sats.
+    /// If the PSBT is missing a TxOut for an input returns None.
+    fn fee_amount(&self) -> Option<u64>;
+
+    /// The transaction's fee rate. This value will only be accurate if calculated AFTER the
+    /// `PartiallySignedTransaction` is finalized and all witness/signature data is added to the
+    /// transaction.
+    /// If the PSBT is missing a TxOut for an input returns None.
+    fn fee_rate(&self) -> Option<FeeRate>;
 }
 
 impl PsbtUtils for Psbt {
@@ -165,6 +288,27 @@
             None
         }
     }
+
+    fn fee_amount(&self) -> Option<u64> {
+        let tx = &self.unsigned_tx;
+        let utxos: Option<Vec<TxOut>> = (0..tx.input.len()).map(|i| self.get_utxo_for(i)).collect();
+
+        utxos.map(|inputs| {
+            let input_amount: u64 = inputs.iter().map(|i| i.value).sum();
+            let output_amount: u64 = self.unsigned_tx.output.iter().map(|o| o.value).sum();
+            input_amount
+                .checked_sub(output_amount)
+                .expect("input amount must be greater than output amount")
+        })
+    }
+
+    fn fee_rate(&self) -> Option<FeeRate> {
+        let fee_amount = self.fee_amount();
+        fee_amount.map(|fee| {
+            let weight = self.clone().extract_tx().weight();
+            FeeRate::from_wu(fee, weight)
+        })
+    }
 }
 
 #[cfg(test)]
@@ -172,8 +316,9 @@
     use crate::bitcoin::TxIn;
     use crate::psbt::Psbt;
     use crate::wallet::AddressIndex;
+    use crate::wallet::AddressIndex::New;
     use crate::wallet::{get_funded_wallet, test::get_test_wpkh};
-    use crate::SignOptions;
+    use crate::{psbt, FeeRate, SignOptions};
     use std::str::FromStr;
 
     // from bip 174
@@ -246,6 +391,85 @@
 
         let _ = wallet.sign(&mut psbt, SignOptions::default()).unwrap();
     }
+
+    #[test]
+    fn test_psbt_fee_rate_with_witness_utxo() {
+        use psbt::PsbtUtils;
+
+        let expected_fee_rate = 1.2345;
+
+        let (wallet, _, _) = get_funded_wallet("wpkh(tprv8ZgxMBicQKsPd3EupYiPRhaMooHKUHJxNsTfYuScep13go8QFfHdtkG9nRkFGb7busX4isf6X9dURGCoKgitaApQ6MupRhZMcELAxTBRJgS/*)");
+        let addr = wallet.get_address(New).unwrap();
+        let mut builder = wallet.build_tx();
+        builder.drain_to(addr.script_pubkey()).drain_wallet();
+        builder.fee_rate(FeeRate::from_sat_per_vb(expected_fee_rate));
+        let (mut psbt, _) = builder.finish().unwrap();
+        let fee_amount = psbt.fee_amount();
+        assert!(fee_amount.is_some());
+
+        let unfinalized_fee_rate = psbt.fee_rate().unwrap();
+
+        let finalized = wallet.sign(&mut psbt, Default::default()).unwrap();
+        assert!(finalized);
+
+        let finalized_fee_rate = psbt.fee_rate().unwrap();
+        assert!(finalized_fee_rate.as_sat_per_vb() >= expected_fee_rate);
+        assert!(finalized_fee_rate.as_sat_per_vb() < unfinalized_fee_rate.as_sat_per_vb());
+    }
+
+    #[test]
+    fn test_psbt_fee_rate_with_nonwitness_utxo() {
+        use psbt::PsbtUtils;
+
+        let expected_fee_rate = 1.2345;
+
+        let (wallet, _, _) = get_funded_wallet("pkh(tprv8ZgxMBicQKsPd3EupYiPRhaMooHKUHJxNsTfYuScep13go8QFfHdtkG9nRkFGb7busX4isf6X9dURGCoKgitaApQ6MupRhZMcELAxTBRJgS/*)");
+        let addr = wallet.get_address(New).unwrap();
+        let mut builder = wallet.build_tx();
+        builder.drain_to(addr.script_pubkey()).drain_wallet();
+        builder.fee_rate(FeeRate::from_sat_per_vb(expected_fee_rate));
+        let (mut psbt, _) = builder.finish().unwrap();
+        let fee_amount = psbt.fee_amount();
+        assert!(fee_amount.is_some());
+        let unfinalized_fee_rate = psbt.fee_rate().unwrap();
+
+        let finalized = wallet.sign(&mut psbt, Default::default()).unwrap();
+        assert!(finalized);
+
+        let finalized_fee_rate = psbt.fee_rate().unwrap();
+        assert!(finalized_fee_rate.as_sat_per_vb() >= expected_fee_rate);
+        assert!(finalized_fee_rate.as_sat_per_vb() < unfinalized_fee_rate.as_sat_per_vb());
+    }
+
+    #[test]
+    fn test_psbt_fee_rate_with_missing_txout() {
+        use psbt::PsbtUtils;
+
+        let expected_fee_rate = 1.2345;
+
+        let (wpkh_wallet, _, _) = get_funded_wallet("wpkh(tprv8ZgxMBicQKsPd3EupYiPRhaMooHKUHJxNsTfYuScep13go8QFfHdtkG9nRkFGb7busX4isf6X9dURGCoKgitaApQ6MupRhZMcELAxTBRJgS/*)");
+        let addr = wpkh_wallet.get_address(New).unwrap();
+        let mut builder = wpkh_wallet.build_tx();
+        builder.drain_to(addr.script_pubkey()).drain_wallet();
+        builder.fee_rate(FeeRate::from_sat_per_vb(expected_fee_rate));
+        let (mut wpkh_psbt, _) = builder.finish().unwrap();
+
+        wpkh_psbt.inputs[0].witness_utxo = None;
+        wpkh_psbt.inputs[0].non_witness_utxo = None;
+        assert!(wpkh_psbt.fee_amount().is_none());
+        assert!(wpkh_psbt.fee_rate().is_none());
+
+        let (pkh_wallet, _, _) = get_funded_wallet("pkh(tprv8ZgxMBicQKsPd3EupYiPRhaMooHKUHJxNsTfYuScep13go8QFfHdtkG9nRkFGb7busX4isf6X9dURGCoKgitaApQ6MupRhZMcELAxTBRJgS/*)");
+        let addr = pkh_wallet.get_address(New).unwrap();
+        let mut builder = pkh_wallet.build_tx();
+        builder.drain_to(addr.script_pubkey()).drain_wallet();
+        builder.fee_rate(FeeRate::from_sat_per_vb(expected_fee_rate));
+        let (mut pkh_psbt, _) = builder.finish().unwrap();
+
+        pkh_psbt.inputs[0].non_witness_utxo = None;
+        assert!(pkh_psbt.fee_amount().is_none());
+        assert!(pkh_psbt.fee_rate().is_none());
+    }
 }