@@ -6,7 +6,6 @@ use bdk::wallet::coin_selection::LargestFirstCoinSelection;
6
6
use bdk:: wallet:: AddressIndex :: * ;
7
7
use bdk:: wallet:: { AddressIndex , AddressInfo , Balance , Wallet } ;
8
8
use bdk:: { Error , FeeRate , KeychainKind } ;
9
- use bdk_chain:: tx_graph:: CalculateFeeError ;
10
9
use bdk_chain:: COINBASE_MATURITY ;
11
10
use bdk_chain:: { BlockId , ConfirmationTime } ;
12
11
use bitcoin:: hashes:: Hash ;
@@ -84,63 +83,60 @@ fn test_descriptor_checksum() {
84
83
#[ test]
85
84
fn test_get_funded_wallet_balance ( ) {
86
85
let ( wallet, _) = get_funded_wallet ( get_test_wpkh ( ) ) ;
87
- assert_eq ! ( wallet. get_balance( ) . confirmed, 50000 ) ;
86
+
87
+ // The funded wallet contains a tx with a 76_000 sats input and two outputs, one spending 25_000
88
+ // to a foreign address and one returning 50_000 back to the wallet as change. The remaining 1000
89
+ // sats are the transaction fee.
90
+ assert_eq ! ( wallet. get_balance( ) . confirmed, 50_000 ) ;
88
91
}
89
92
90
93
#[ test]
91
94
fn test_get_funded_wallet_sent_and_received ( ) {
92
- let ( wallet, _ ) = get_funded_wallet ( get_test_wpkh ( ) ) ;
93
- assert_eq ! ( wallet . get_balance ( ) . confirmed , 50000 ) ;
95
+ let ( wallet, txid ) = get_funded_wallet ( get_test_wpkh ( ) ) ;
96
+
94
97
let mut tx_amounts: Vec < ( Txid , ( u64 , u64 ) ) > = wallet
95
98
. transactions ( )
96
- . map ( |ct| ( ct. node . txid , wallet. sent_and_received ( ct. node . tx ) ) )
99
+ . map ( |ct| ( ct. tx_node . txid , wallet. sent_and_received ( ct. tx_node . tx ) ) )
97
100
. collect ( ) ;
98
101
tx_amounts. sort_by ( |a1, a2| a1. 0 . cmp ( & a2. 0 ) ) ;
99
102
100
- assert_eq ! ( tx_amounts. len( ) , 2 ) ;
101
- assert_matches ! ( tx_amounts. get( 0 ) , Some ( ( _, ( 76_000 , 50_000 ) ) ) )
103
+ let tx = wallet. get_tx ( txid) . expect ( "transaction" ) . tx_node . tx ;
104
+ let ( sent, received) = wallet. sent_and_received ( tx) ;
105
+
106
+ // The funded wallet contains a tx with a 76_000 sats input and two outputs, one spending 25_000
107
+ // to a foreign address and one returning 50_000 back to the wallet as change. The remaining 1000
108
+ // sats are the transaction fee.
109
+ assert_eq ! ( sent, 76_000 ) ;
110
+ assert_eq ! ( received, 50_000 ) ;
102
111
}
103
112
104
113
#[ test]
105
114
fn test_get_funded_wallet_tx_fees ( ) {
106
- let ( wallet, _) = get_funded_wallet ( get_test_wpkh ( ) ) ;
107
- assert_eq ! ( wallet. get_balance( ) . confirmed, 50000 ) ;
108
- let mut tx_fee_amounts: Vec < ( Txid , Result < u64 , CalculateFeeError > ) > = wallet
109
- . transactions ( )
110
- . map ( |ct| {
111
- let fee = wallet. calculate_fee ( ct. node . tx ) ;
112
- ( ct. node . txid , fee)
113
- } )
114
- . collect ( ) ;
115
- tx_fee_amounts. sort_by ( |a1, a2| a1. 0 . cmp ( & a2. 0 ) ) ;
115
+ let ( wallet, txid) = get_funded_wallet ( get_test_wpkh ( ) ) ;
116
116
117
- assert_eq ! ( tx_fee_amounts. len( ) , 2 ) ;
118
- assert_matches ! (
119
- tx_fee_amounts. get( 1 ) ,
120
- Some ( ( _, Err ( CalculateFeeError :: MissingTxOut ( _) ) ) )
121
- ) ;
122
- assert_matches ! ( tx_fee_amounts. get( 0 ) , Some ( ( _, Ok ( 1000 ) ) ) )
117
+ let tx = wallet. get_tx ( txid) . expect ( "transaction" ) . tx_node . tx ;
118
+ let tx_fee = wallet. calculate_fee ( tx) . expect ( "transaction fee" ) ;
119
+
120
+ // The funded wallet contains a tx with a 76_000 sats input and two outputs, one spending 25_000
121
+ // to a foreign address and one returning 50_000 back to the wallet as change. The remaining 1000
122
+ // sats are the transaction fee.
123
+ assert_eq ! ( tx_fee, 1000 )
123
124
}
124
125
125
126
#[ test]
126
127
fn test_get_funded_wallet_tx_fee_rate ( ) {
127
- let ( wallet, _) = get_funded_wallet ( get_test_wpkh ( ) ) ;
128
- assert_eq ! ( wallet. get_balance( ) . confirmed, 50000 ) ;
129
- let mut tx_fee_rates: Vec < ( Txid , Result < FeeRate , CalculateFeeError > ) > = wallet
130
- . transactions ( )
131
- . map ( |ct| {
132
- let fee_rate = wallet. calculate_fee_rate ( ct. node . tx ) ;
133
- ( ct. node . txid , fee_rate)
134
- } )
135
- . collect ( ) ;
136
- tx_fee_rates. sort_by ( |a1, a2| a1. 0 . cmp ( & a2. 0 ) ) ;
128
+ let ( wallet, txid) = get_funded_wallet ( get_test_wpkh ( ) ) ;
137
129
138
- assert_eq ! ( tx_fee_rates. len( ) , 2 ) ;
139
- assert_matches ! (
140
- tx_fee_rates. get( 1 ) ,
141
- Some ( ( _, Err ( CalculateFeeError :: MissingTxOut ( _) ) ) )
142
- ) ;
143
- assert_matches ! ( tx_fee_rates. get( 0 ) , Some ( ( _, Ok ( _) ) ) )
130
+ let tx = wallet. get_tx ( txid) . expect ( "transaction" ) . tx_node . tx ;
131
+ let tx_fee_rate = wallet. calculate_fee_rate ( tx) . expect ( "transaction fee rate" ) ;
132
+
133
+ // The funded wallet contains a tx with a 76_000 sats input and two outputs, one spending 25_000
134
+ // to a foreign address and one returning 50_000 back to the wallet as change. The remaining 1000
135
+ // sats are the transaction fee.
136
+
137
+ // tx weight = 452 bytes, as vbytes = (452+3)/4 = 113
138
+ // fee rate (sats per vbyte) = fee / vbytes = 1000 / 113 = 8.8495575221 rounded to 8.849558
139
+ assert_eq ! ( tx_fee_rate. as_sat_per_vb( ) , 8.849558 ) ;
144
140
}
145
141
146
142
macro_rules! assert_fee_rate {
@@ -1098,6 +1094,77 @@ fn test_add_foreign_utxo() {
1098
1094
assert ! ( finished, "all the inputs should have been signed now" ) ;
1099
1095
}
1100
1096
1097
+ #[ test]
1098
+ #[ should_panic(
1099
+ expected = "MissingTxOut([OutPoint { txid: 0x21d7fb1bceda00ab4069fc52d06baa13470803e9050edd16f5736e5d8c4925fd, vout: 0 }])"
1100
+ ) ]
1101
+ fn test_calculate_fee_with_missing_foreign_utxo ( ) {
1102
+ let ( mut wallet1, _) = get_funded_wallet ( get_test_wpkh ( ) ) ;
1103
+ let ( wallet2, _) =
1104
+ get_funded_wallet ( "wpkh(cVbZ8ovhye9AoAHFsqobCf7LxbXDAECy9Kb8TZdfsDYMZGBUyCnm)" ) ;
1105
+
1106
+ let addr = Address :: from_str ( "2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX" )
1107
+ . unwrap ( )
1108
+ . assume_checked ( ) ;
1109
+ let utxo = wallet2. list_unspent ( ) . next ( ) . expect ( "must take!" ) ;
1110
+ #[ allow( deprecated) ]
1111
+ let foreign_utxo_satisfaction = wallet2
1112
+ . get_descriptor_for_keychain ( KeychainKind :: External )
1113
+ . max_satisfaction_weight ( )
1114
+ . unwrap ( ) ;
1115
+
1116
+ let psbt_input = psbt:: Input {
1117
+ witness_utxo : Some ( utxo. txout . clone ( ) ) ,
1118
+ ..Default :: default ( )
1119
+ } ;
1120
+
1121
+ let mut builder = wallet1. build_tx ( ) ;
1122
+ builder
1123
+ . add_recipient ( addr. script_pubkey ( ) , 60_000 )
1124
+ . only_witness_utxo ( )
1125
+ . add_foreign_utxo ( utxo. outpoint , psbt_input, foreign_utxo_satisfaction)
1126
+ . unwrap ( ) ;
1127
+ let psbt = builder. finish ( ) . unwrap ( ) ;
1128
+ let tx = psbt. extract_tx ( ) ;
1129
+ wallet1. calculate_fee ( & tx) . unwrap ( ) ;
1130
+ }
1131
+
1132
+ #[ test]
1133
+ fn test_calculate_fee_with_inserted_foreign_utxo ( ) {
1134
+ let ( mut wallet1, _) = get_funded_wallet ( get_test_wpkh ( ) ) ;
1135
+ let ( wallet2, _) =
1136
+ get_funded_wallet ( "wpkh(cVbZ8ovhye9AoAHFsqobCf7LxbXDAECy9Kb8TZdfsDYMZGBUyCnm)" ) ;
1137
+
1138
+ let addr = Address :: from_str ( "2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX" )
1139
+ . unwrap ( )
1140
+ . assume_checked ( ) ;
1141
+ let utxo = wallet2. list_unspent ( ) . next ( ) . expect ( "must take!" ) ;
1142
+ #[ allow( deprecated) ]
1143
+ let foreign_utxo_satisfaction = wallet2
1144
+ . get_descriptor_for_keychain ( KeychainKind :: External )
1145
+ . max_satisfaction_weight ( )
1146
+ . unwrap ( ) ;
1147
+
1148
+ let psbt_input = psbt:: Input {
1149
+ witness_utxo : Some ( utxo. txout . clone ( ) ) ,
1150
+ ..Default :: default ( )
1151
+ } ;
1152
+
1153
+ let mut builder = wallet1. build_tx ( ) ;
1154
+ builder
1155
+ . add_recipient ( addr. script_pubkey ( ) , 60_000 )
1156
+ . only_witness_utxo ( )
1157
+ . add_foreign_utxo ( utxo. outpoint , psbt_input, foreign_utxo_satisfaction)
1158
+ . unwrap ( ) ;
1159
+ let psbt = builder. finish ( ) . unwrap ( ) ;
1160
+ let psbt_fee = psbt. fee_amount ( ) . expect ( "psbt fee" ) ;
1161
+ let tx = psbt. extract_tx ( ) ;
1162
+
1163
+ wallet1. insert_txout ( utxo. outpoint , utxo. txout ) ;
1164
+ let wallet1_fee = wallet1. calculate_fee ( & tx) . expect ( "wallet fee" ) ;
1165
+ assert_eq ! ( psbt_fee, wallet1_fee) ;
1166
+ }
1167
+
1101
1168
#[ test]
1102
1169
#[ should_panic( expected = "Generic(\" Foreign utxo missing witness_utxo or non_witness_utxo\" )" ) ]
1103
1170
fn test_add_foreign_utxo_invalid_psbt_input ( ) {
@@ -1122,8 +1189,8 @@ fn test_add_foreign_utxo_where_outpoint_doesnt_match_psbt_input() {
1122
1189
get_funded_wallet ( "wpkh(cVbZ8ovhye9AoAHFsqobCf7LxbXDAECy9Kb8TZdfsDYMZGBUyCnm)" ) ;
1123
1190
1124
1191
let utxo2 = wallet2. list_unspent ( ) . next ( ) . unwrap ( ) ;
1125
- let tx1 = wallet1. get_tx ( txid1) . unwrap ( ) . node . tx . clone ( ) ;
1126
- let tx2 = wallet2. get_tx ( txid2) . unwrap ( ) . node . tx . clone ( ) ;
1192
+ let tx1 = wallet1. get_tx ( txid1) . unwrap ( ) . tx_node . tx . clone ( ) ;
1193
+ let tx2 = wallet2. get_tx ( txid2) . unwrap ( ) . tx_node . tx . clone ( ) ;
1127
1194
1128
1195
#[ allow( deprecated) ]
1129
1196
let satisfaction_weight = wallet2
@@ -1212,7 +1279,7 @@ fn test_add_foreign_utxo_only_witness_utxo() {
1212
1279
1213
1280
{
1214
1281
let mut builder = builder. clone ( ) ;
1215
- let tx2 = wallet2. get_tx ( txid2) . unwrap ( ) . node . tx ;
1282
+ let tx2 = wallet2. get_tx ( txid2) . unwrap ( ) . tx_node . tx ;
1216
1283
let psbt_input = psbt:: Input {
1217
1284
non_witness_utxo : Some ( tx2. clone ( ) ) ,
1218
1285
..Default :: default ( )
@@ -2842,7 +2909,7 @@ fn test_taproot_sign_using_non_witness_utxo() {
2842
2909
let mut psbt = builder. finish ( ) . unwrap ( ) ;
2843
2910
2844
2911
psbt. inputs [ 0 ] . witness_utxo = None ;
2845
- psbt. inputs [ 0 ] . non_witness_utxo = Some ( wallet. get_tx ( prev_txid) . unwrap ( ) . node . tx . clone ( ) ) ;
2912
+ psbt. inputs [ 0 ] . non_witness_utxo = Some ( wallet. get_tx ( prev_txid) . unwrap ( ) . tx_node . tx . clone ( ) ) ;
2846
2913
assert ! (
2847
2914
psbt. inputs[ 0 ] . non_witness_utxo. is_some( ) ,
2848
2915
"Previous tx should be present in the database"
0 commit comments