@@ -5,15 +5,15 @@ use crate::convert::{
5
5
use crate :: disk:: FilesystemLogger ;
6
6
use crate :: hex_utils;
7
7
use base64;
8
- use bitcoin:: address:: { Address , Payload , WitnessVersion } ;
8
+ use bitcoin:: address:: Address ;
9
9
use bitcoin:: blockdata:: constants:: WITNESS_SCALE_FACTOR ;
10
10
use bitcoin:: blockdata:: script:: ScriptBuf ;
11
11
use bitcoin:: blockdata:: transaction:: Transaction ;
12
12
use bitcoin:: consensus:: { encode, Decodable , Encodable } ;
13
13
use bitcoin:: hash_types:: { BlockHash , Txid } ;
14
14
use bitcoin:: hashes:: Hash ;
15
15
use bitcoin:: key:: XOnlyPublicKey ;
16
- use bitcoin:: psbt:: PartiallySignedTransaction ;
16
+ use bitcoin:: psbt:: Psbt ;
17
17
use bitcoin:: { Network , OutPoint , TxOut , WPubkeyHash } ;
18
18
use lightning:: chain:: chaininterface:: { BroadcasterInterface , ConfirmationTarget , FeeEstimator } ;
19
19
use lightning:: events:: bump_transaction:: { Utxo , WalletSource } ;
@@ -80,7 +80,8 @@ impl BitcoindClient {
80
80
"Failed to make initial call to bitcoind - please check your RPC user/password and access settings" )
81
81
} ) ?;
82
82
let mut fees: HashMap < ConfirmationTarget , AtomicU32 > = HashMap :: new ( ) ;
83
- fees. insert ( ConfirmationTarget :: OnChainSweep , AtomicU32 :: new ( 5000 ) ) ;
83
+ fees. insert ( ConfirmationTarget :: MaximumFeeEstimate , AtomicU32 :: new ( 50000 ) ) ;
84
+ fees. insert ( ConfirmationTarget :: UrgentOnChainSweep , AtomicU32 :: new ( 5000 ) ) ;
84
85
fees. insert (
85
86
ConfirmationTarget :: MinAllowedAnchorChannelRemoteFee ,
86
87
AtomicU32 :: new ( MIN_FEERATE ) ,
@@ -92,6 +93,7 @@ impl BitcoindClient {
92
93
fees. insert ( ConfirmationTarget :: AnchorChannelFee , AtomicU32 :: new ( MIN_FEERATE ) ) ;
93
94
fees. insert ( ConfirmationTarget :: NonAnchorChannelFee , AtomicU32 :: new ( 2000 ) ) ;
94
95
fees. insert ( ConfirmationTarget :: ChannelCloseMinimum , AtomicU32 :: new ( MIN_FEERATE ) ) ;
96
+ fees. insert ( ConfirmationTarget :: OutputSpendingFee , AtomicU32 :: new ( MIN_FEERATE ) ) ;
95
97
96
98
let client = Self {
97
99
bitcoind_rpc_client : Arc :: new ( bitcoind_rpc_client) ,
@@ -177,7 +179,27 @@ impl BitcoindClient {
177
179
}
178
180
} ;
179
181
180
- fees. get ( & ConfirmationTarget :: OnChainSweep )
182
+ let very_high_prio_estimate = {
183
+ let high_prio_conf_target = serde_json:: json!( 2 ) ;
184
+ let high_prio_estimate_mode = serde_json:: json!( "CONSERVATIVE" ) ;
185
+ let resp = rpc_client
186
+ . call_method :: < FeeResponse > (
187
+ "estimatesmartfee" ,
188
+ & vec ! [ high_prio_conf_target, high_prio_estimate_mode] ,
189
+ )
190
+ . await
191
+ . unwrap ( ) ;
192
+
193
+ match resp. feerate_sat_per_kw {
194
+ Some ( feerate) => std:: cmp:: max ( feerate, MIN_FEERATE ) ,
195
+ None => 50000 ,
196
+ }
197
+ } ;
198
+
199
+ fees. get ( & ConfirmationTarget :: MaximumFeeEstimate )
200
+ . unwrap ( )
201
+ . store ( very_high_prio_estimate, Ordering :: Release ) ;
202
+ fees. get ( & ConfirmationTarget :: UrgentOnChainSweep )
181
203
. unwrap ( )
182
204
. store ( high_prio_estimate, Ordering :: Release ) ;
183
205
fees. get ( & ConfirmationTarget :: MinAllowedAnchorChannelRemoteFee )
@@ -195,6 +217,9 @@ impl BitcoindClient {
195
217
fees. get ( & ConfirmationTarget :: ChannelCloseMinimum )
196
218
. unwrap ( )
197
219
. store ( background_estimate, Ordering :: Release ) ;
220
+ fees. get ( & ConfirmationTarget :: OutputSpendingFee )
221
+ . unwrap ( )
222
+ . store ( background_estimate, Ordering :: Release ) ;
198
223
199
224
tokio:: time:: sleep ( Duration :: from_secs ( 60 ) ) . await ;
200
225
}
@@ -289,32 +314,42 @@ impl FeeEstimator for BitcoindClient {
289
314
290
315
impl BroadcasterInterface for BitcoindClient {
291
316
fn broadcast_transactions ( & self , txs : & [ & Transaction ] ) {
292
- // TODO: Rather than calling `sendrawtransaction` in a a loop, we should probably use
293
- // `submitpackage` once it becomes available.
294
- for tx in txs {
295
- let bitcoind_rpc_client = Arc :: clone ( & self . bitcoind_rpc_client ) ;
296
- let tx_serialized = encode:: serialize_hex ( tx) ;
297
- let tx_json = serde_json:: json!( tx_serialized) ;
298
- let logger = Arc :: clone ( & self . logger ) ;
299
- self . handle . spawn ( async move {
300
- // This may error due to RL calling `broadcast_transactions` with the same transaction
301
- // multiple times, but the error is safe to ignore.
302
- match bitcoind_rpc_client
303
- . call_method :: < Txid > ( "sendrawtransaction" , & vec ! [ tx_json] )
317
+ // As of Bitcoin Core 28, using `submitpackage` allows us to broadcast multiple
318
+ // transactions at once and have them propagate through the network as a whole, avoiding
319
+ // some pitfalls with anchor channels where the first transaction doesn't make it into the
320
+ // mempool at all. Several older versions of Bitcoin Core also support `submitpackage`,
321
+ // however, so we just use it unconditionally here.
322
+ // Sadly, Bitcoin Core has an arbitrary restriction on `submitpackage` - it must actually
323
+ // contain a package (see https://github.com/bitcoin/bitcoin/issues/31085).
324
+ let txn = txs. iter ( ) . map ( |tx| encode:: serialize_hex ( tx) ) . collect :: < Vec < _ > > ( ) ;
325
+ let bitcoind_rpc_client = Arc :: clone ( & self . bitcoind_rpc_client ) ;
326
+ let logger = Arc :: clone ( & self . logger ) ;
327
+ self . handle . spawn ( async move {
328
+ let res = if txn. len ( ) == 1 {
329
+ let tx_json = serde_json:: json!( txn[ 0 ] ) ;
330
+ bitcoind_rpc_client
331
+ . call_method :: < serde_json:: Value > ( "sendrawtransaction" , & [ tx_json] )
304
332
. await
305
- {
306
- Ok ( _) => { }
307
- Err ( e) => {
308
- let err_str = e. get_ref ( ) . unwrap ( ) . to_string ( ) ;
309
- log_error ! ( logger,
310
- "Warning, failed to broadcast a transaction, this is likely okay but may indicate an error: {}\n Transaction: {}" ,
311
- err_str,
312
- tx_serialized) ;
313
- print ! ( "Warning, failed to broadcast a transaction, this is likely okay but may indicate an error: {}\n > " , err_str) ;
314
- }
315
- }
316
- } ) ;
317
- }
333
+ } else {
334
+ let tx_json = serde_json:: json!( txn) ;
335
+ bitcoind_rpc_client
336
+ . call_method :: < serde_json:: Value > ( "submitpackage" , & [ tx_json] )
337
+ . await
338
+ } ;
339
+ // This may error due to RL calling `broadcast_transactions` with the same transaction
340
+ // multiple times, but the error is safe to ignore.
341
+ match res {
342
+ Ok ( _) => { }
343
+ Err ( e) => {
344
+ let err_str = e. get_ref ( ) . unwrap ( ) . to_string ( ) ;
345
+ log_error ! ( logger,
346
+ "Warning, failed to broadcast a transaction, this is likely okay but may indicate an error: {}\n Transactions: {:?}" ,
347
+ err_str,
348
+ txn) ;
349
+ print ! ( "Warning, failed to broadcast a transaction, this is likely okay but may indicate an error: {}\n > " , err_str) ;
350
+ }
351
+ }
352
+ } ) ;
318
353
}
319
354
}
320
355
@@ -335,24 +370,26 @@ impl WalletSource for BitcoindClient {
335
370
. into_iter ( )
336
371
. filter_map ( |utxo| {
337
372
let outpoint = OutPoint { txid : utxo. txid , vout : utxo. vout } ;
338
- match utxo. address . payload . clone ( ) {
339
- Payload :: WitnessProgram ( wp) => match wp. version ( ) {
340
- WitnessVersion :: V0 => WPubkeyHash :: from_slice ( wp. program ( ) . as_bytes ( ) )
341
- . map ( |wpkh| Utxo :: new_v0_p2wpkh ( outpoint, utxo. amount , & wpkh) )
342
- . ok ( ) ,
373
+ let value = bitcoin:: Amount :: from_sat ( utxo. amount ) ;
374
+ match utxo. address . witness_program ( ) {
375
+ Some ( prog) if prog. is_p2wpkh ( ) => {
376
+ WPubkeyHash :: from_slice ( prog. program ( ) . as_bytes ( ) )
377
+ . map ( |wpkh| Utxo :: new_v0_p2wpkh ( outpoint, value, & wpkh) )
378
+ . ok ( )
379
+ } ,
380
+ Some ( prog) if prog. is_p2tr ( ) => {
343
381
// TODO: Add `Utxo::new_v1_p2tr` upstream.
344
- WitnessVersion :: V1 => XOnlyPublicKey :: from_slice ( wp . program ( ) . as_bytes ( ) )
382
+ XOnlyPublicKey :: from_slice ( prog . program ( ) . as_bytes ( ) )
345
383
. map ( |_| Utxo {
346
384
outpoint,
347
385
output : TxOut {
348
- value : utxo . amount ,
349
- script_pubkey : ScriptBuf :: new_witness_program ( & wp ) ,
386
+ value,
387
+ script_pubkey : utxo . address . script_pubkey ( ) ,
350
388
} ,
351
389
satisfaction_weight : 1 /* empty script_sig */ * WITNESS_SCALE_FACTOR as u64 +
352
390
1 /* witness items */ + 1 /* schnorr sig len */ + 64 , /* schnorr sig */
353
391
} )
354
- . ok ( ) ,
355
- _ => None ,
392
+ . ok ( )
356
393
} ,
357
394
_ => None ,
358
395
}
@@ -366,7 +403,7 @@ impl WalletSource for BitcoindClient {
366
403
} )
367
404
}
368
405
369
- fn sign_psbt ( & self , tx : PartiallySignedTransaction ) -> Result < Transaction , ( ) > {
406
+ fn sign_psbt ( & self , tx : Psbt ) -> Result < Transaction , ( ) > {
370
407
let mut tx_bytes = Vec :: new ( ) ;
371
408
let _ = tx. unsigned_tx . consensus_encode ( & mut tx_bytes) . map_err ( |_| ( ) ) ;
372
409
let tx_hex = hex_utils:: hex_str ( & tx_bytes) ;
0 commit comments