Skip to content

Commit 20742f4

Browse files
committed
Disallow empty fee estimates on Mainnet
We generally want to properly be able to detect whenever a fee estimation would fail, as we need to fail startup if we can't retrieve the latest fee rates. However, currently the `convert_fee_estimates` function would fallback to a default of 1sat/vbyte if the retrieved estimate map is empty. This is fine/potentially needed for, e.g., Signet where Esplora's `fee-estimates` endpoint would return an empty dictionary. However, we need to detect the empty map and fail our fee estimation if we encounter such a case, rather than using the 1 sat/vbyte fallback on mainnet, where differences in fee estimation could lead to costly force-closures. Here we do this and just return a `FeerateEstimationFailed` if we hit such a case.
1 parent 6fef493 commit 20742f4

File tree

2 files changed

+26
-8
lines changed

2 files changed

+26
-8
lines changed

src/builder.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -508,8 +508,11 @@ fn build_with_store_internal<K: KVStore + Sync + Send + 'static>(
508508
tx_sync.client().clone(),
509509
Arc::clone(&logger),
510510
));
511-
let fee_estimator =
512-
Arc::new(OnchainFeeEstimator::new(tx_sync.client().clone(), Arc::clone(&logger)));
511+
let fee_estimator = Arc::new(OnchainFeeEstimator::new(
512+
tx_sync.client().clone(),
513+
Arc::clone(&config),
514+
Arc::clone(&logger),
515+
));
513516
(blockchain, tx_sync, tx_broadcaster, fee_estimator)
514517
}
515518
None => {
@@ -523,8 +526,11 @@ fn build_with_store_internal<K: KVStore + Sync + Send + 'static>(
523526
tx_sync.client().clone(),
524527
Arc::clone(&logger),
525528
));
526-
let fee_estimator =
527-
Arc::new(OnchainFeeEstimator::new(tx_sync.client().clone(), Arc::clone(&logger)));
529+
let fee_estimator = Arc::new(OnchainFeeEstimator::new(
530+
tx_sync.client().clone(),
531+
Arc::clone(&config),
532+
Arc::clone(&logger),
533+
));
528534
(blockchain, tx_sync, tx_broadcaster, fee_estimator)
529535
}
530536
};

src/fee_estimator.rs

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::logger::{log_error, log_trace, Logger};
2-
use crate::Error;
2+
use crate::{Config, Error};
33

44
use lightning::chain::chaininterface::{
55
ConfirmationTarget, FeeEstimator, FEERATE_FLOOR_SATS_PER_KW,
@@ -8,28 +8,30 @@ use lightning::chain::chaininterface::{
88
use bdk::FeeRate;
99
use esplora_client::AsyncClient as EsploraClient;
1010

11+
use bitcoin::Network;
1112
use bitcoin::blockdata::weight::Weight;
1213

1314
use std::collections::HashMap;
1415
use std::ops::Deref;
15-
use std::sync::RwLock;
16+
use std::sync::{Arc, RwLock};
1617

1718
pub(crate) struct OnchainFeeEstimator<L: Deref>
1819
where
1920
L::Target: Logger,
2021
{
2122
fee_rate_cache: RwLock<HashMap<ConfirmationTarget, FeeRate>>,
2223
esplora_client: EsploraClient,
24+
config: Arc<Config>,
2325
logger: L,
2426
}
2527

2628
impl<L: Deref> OnchainFeeEstimator<L>
2729
where
2830
L::Target: Logger,
2931
{
30-
pub(crate) fn new(esplora_client: EsploraClient, logger: L) -> Self {
32+
pub(crate) fn new(esplora_client: EsploraClient, config: Arc<Config>, logger: L) -> Self {
3133
let fee_rate_cache = RwLock::new(HashMap::new());
32-
Self { fee_rate_cache, esplora_client, logger }
34+
Self { fee_rate_cache, esplora_client, config, logger }
3335
}
3436

3537
pub(crate) async fn update_fee_estimates(&self) -> Result<(), Error> {
@@ -61,6 +63,16 @@ where
6163
Error::FeerateEstimationUpdateFailed
6264
})?;
6365

66+
if estimates.is_empty() && self.config.network == Network::Bitcoin {
67+
// Ensure we fail if we didn't receive any estimates.
68+
log_error!(
69+
self.logger,
70+
"Failed to retrieve fee rate estimates for {:?}: empty fee estimates are dissallowed on Mainnet.",
71+
target,
72+
);
73+
return Err(Error::FeerateEstimationUpdateFailed);
74+
}
75+
6476
let converted_estimates = esplora_client::convert_fee_rate(num_blocks, estimates)
6577
.map_err(|e| {
6678
log_error!(

0 commit comments

Comments
 (0)