Skip to content

Commit ab0be29

Browse files
committed
Make the base fee configurable in ChannelConfig
Currently the base fee we apply is always the expected cost to claim an HTLC on-chain in case of closure. This results in significantly higher than market rate fees [1], and doesn't really match the actual forwarding trust model anyway - as long as channel counterparties are honest, our HTLCs shouldn't end up on-chain no matter what the HTLC sender/recipient do. While some users may wish to use a feerate that implies they will not lose funds even if they go to chain (assuming no flood-and-loot style attacks), they should do so by calculating fees themselves; since they're already charging well above market-rate, over-estimating some won't have a large impact. This commit adds a configuration knob to set the base fee explicitly, defaulting to 1 sat, which appears to be market-rate today. [1] Note that due to an msat-vs-sat bug we currently actually charge 1000x *less* than the calculated cost.
1 parent 41501a8 commit ab0be29

File tree

9 files changed

+131
-64
lines changed

9 files changed

+131
-64
lines changed

lightning-background-processor/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ mod tests {
239239
let mut nodes = Vec::new();
240240
for i in 0..num_nodes {
241241
let tx_broadcaster = Arc::new(test_utils::TestBroadcaster{txn_broadcasted: Mutex::new(Vec::new()), blocks: Arc::new(Mutex::new(Vec::new()))});
242-
let fee_estimator = Arc::new(test_utils::TestFeeEstimator { sat_per_kw: 253 });
242+
let fee_estimator = Arc::new(test_utils::TestFeeEstimator { sat_per_kw: Mutex::new(253) });
243243
let chain_source = Arc::new(test_utils::TestChainSource::new(Network::Testnet));
244244
let logger = Arc::new(test_utils::TestLogger::with_id(format!("node {}", i)));
245245
let persister = Arc::new(FilesystemPersister::new(format!("{}_persister_{}", persist_dir, i)));

lightning/src/chain/channelmonitor.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2826,7 +2826,7 @@ mod tests {
28262826
let secp_ctx = Secp256k1::new();
28272827
let logger = Arc::new(TestLogger::new());
28282828
let broadcaster = Arc::new(TestBroadcaster{txn_broadcasted: Mutex::new(Vec::new()), blocks: Arc::new(Mutex::new(Vec::new()))});
2829-
let fee_estimator = Arc::new(TestFeeEstimator { sat_per_kw: 253 });
2829+
let fee_estimator = Arc::new(TestFeeEstimator { sat_per_kw: Mutex::new(253) });
28302830

28312831
let dummy_key = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap());
28322832
let dummy_tx = Transaction { version: 0, lock_time: 0, input: Vec::new(), output: Vec::new() };

lightning/src/ln/channel.rs

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -455,7 +455,6 @@ struct CommitmentTxInfoCached {
455455
}
456456

457457
pub const OUR_MAX_HTLCS: u16 = 50; //TODO
458-
const SPENDING_INPUT_FOR_A_OUTPUT_WEIGHT: u64 = 79; // prevout: 36, nSequence: 4, script len: 1, witness lengths: (3+1)/4, sig: 73/4, if-selector: 1, redeemScript: (6 ops + 2*33 pubkeys + 1*2 delay)/4
459458

460459
#[cfg(not(test))]
461460
const COMMITMENT_TX_BASE_WEIGHT: u64 = 724;
@@ -3477,24 +3476,8 @@ impl<Signer: Sign> Channel<Signer> {
34773476

34783477
/// Gets the fee we'd want to charge for adding an HTLC output to this Channel
34793478
/// Allowed in any state (including after shutdown)
3480-
pub fn get_holder_fee_base_msat<F: Deref>(&self, fee_estimator: &F) -> u32
3481-
where F::Target: FeeEstimator
3482-
{
3483-
// For lack of a better metric, we calculate what it would cost to consolidate the new HTLC
3484-
// output value back into a transaction with the regular channel output:
3485-
3486-
// the fee cost of the HTLC-Success/HTLC-Timeout transaction:
3487-
let mut res = self.feerate_per_kw as u64 * cmp::max(HTLC_TIMEOUT_TX_WEIGHT, HTLC_SUCCESS_TX_WEIGHT) / 1000;
3488-
3489-
if self.is_outbound() {
3490-
// + the marginal fee increase cost to us in the commitment transaction:
3491-
res += self.feerate_per_kw as u64 * COMMITMENT_TX_WEIGHT_PER_HTLC / 1000;
3492-
}
3493-
3494-
// + the marginal cost of an input which spends the HTLC-Success/HTLC-Timeout output:
3495-
res += fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::Normal) as u64 * SPENDING_INPUT_FOR_A_OUTPUT_WEIGHT / 1000;
3496-
3497-
res as u32
3479+
pub fn get_holder_fee_base_msat(&self) -> u32 {
3480+
self.config.fee_base_msat
34983481
}
34993482

35003483
/// Returns true if we've ever received a message from the remote end for this Channel

lightning/src/ln/channelmanager.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1541,7 +1541,9 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
15411541
if *amt_to_forward < chan.get_counterparty_htlc_minimum_msat() { // amount_below_minimum
15421542
break Some(("HTLC amount was below the htlc_minimum_msat", 0x1000 | 11, Some(self.get_channel_update(chan).unwrap())));
15431543
}
1544-
let fee = amt_to_forward.checked_mul(chan.get_fee_proportional_millionths() as u64).and_then(|prop_fee| { (prop_fee / 1000000).checked_add(chan.get_holder_fee_base_msat(&self.fee_estimator) as u64) });
1544+
let fee = amt_to_forward.checked_mul(chan.get_fee_proportional_millionths() as u64)
1545+
.and_then(|prop_fee| { (prop_fee / 1000000)
1546+
.checked_add(chan.get_holder_fee_base_msat() as u64) });
15451547
if fee.is_none() || msg.amount_msat < fee.unwrap() || (msg.amount_msat - fee.unwrap()) < *amt_to_forward { // fee_insufficient
15461548
break Some(("Prior hop has deviated from specified fees parameters or origin node has obsolete ones", 0x1000 | 12, Some(self.get_channel_update(chan).unwrap())));
15471549
}
@@ -1606,7 +1608,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
16061608
cltv_expiry_delta: chan.get_cltv_expiry_delta(),
16071609
htlc_minimum_msat: chan.get_counterparty_htlc_minimum_msat(),
16081610
htlc_maximum_msat: OptionalField::Present(chan.get_announced_htlc_max_msat()),
1609-
fee_base_msat: chan.get_holder_fee_base_msat(&self.fee_estimator),
1611+
fee_base_msat: chan.get_holder_fee_base_msat(),
16101612
fee_proportional_millionths: chan.get_fee_proportional_millionths(),
16111613
excess_data: Vec::new(),
16121614
};

lightning/src/ln/functional_test_utils.rs

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,7 @@ impl<'a, 'b, 'c> Drop for Node<'a, 'b, 'c> {
266266
// Check that if we serialize and then deserialize all our channel monitors we get the
267267
// same set of outputs to watch for on chain as we have now. Note that if we write
268268
// tests that fully close channels and remove the monitors at some point this may break.
269-
let feeest = test_utils::TestFeeEstimator { sat_per_kw: 253 };
269+
let feeest = test_utils::TestFeeEstimator { sat_per_kw: Mutex::new(253) };
270270
let mut deserialized_monitors = Vec::new();
271271
{
272272
let old_monitors = self.chain_monitor.chain_monitor.monitors.read().unwrap();
@@ -292,7 +292,7 @@ impl<'a, 'b, 'c> Drop for Node<'a, 'b, 'c> {
292292
<(BlockHash, ChannelManager<EnforcingSigner, &test_utils::TestChainMonitor, &test_utils::TestBroadcaster, &test_utils::TestKeysInterface, &test_utils::TestFeeEstimator, &test_utils::TestLogger>)>::read(&mut ::std::io::Cursor::new(w.0), ChannelManagerReadArgs {
293293
default_config: *self.node.get_current_default_configuration(),
294294
keys_manager: self.keys_manager,
295-
fee_estimator: &test_utils::TestFeeEstimator { sat_per_kw: 253 },
295+
fee_estimator: &test_utils::TestFeeEstimator { sat_per_kw: Mutex::new(253) },
296296
chain_monitor: self.chain_monitor,
297297
tx_broadcaster: &test_utils::TestBroadcaster {
298298
txn_broadcasted: Mutex::new(self.tx_broadcaster.txn_broadcasted.lock().unwrap().clone()),
@@ -1289,7 +1289,7 @@ pub fn create_chanmon_cfgs(node_count: usize) -> Vec<TestChanMonCfg> {
12891289
txn_broadcasted: Mutex::new(Vec::new()),
12901290
blocks: Arc::new(Mutex::new(vec![(genesis_block(Network::Testnet).header, 0)])),
12911291
};
1292-
let fee_estimator = test_utils::TestFeeEstimator { sat_per_kw: 253 };
1292+
let fee_estimator = test_utils::TestFeeEstimator { sat_per_kw: Mutex::new(253) };
12931293
let chain_source = test_utils::TestChainSource::new(Network::Testnet);
12941294
let logger = test_utils::TestLogger::with_id(format!("node {}", i));
12951295
let persister = test_utils::TestPersister::new();
@@ -1314,22 +1314,27 @@ pub fn create_node_cfgs<'a>(node_count: usize, chanmon_cfgs: &'a Vec<TestChanMon
13141314
nodes
13151315
}
13161316

1317+
pub fn test_default_channel_config() -> UserConfig {
1318+
let mut default_config = UserConfig::default();
1319+
// Set cltv_expiry_delta slightly lower to keep the final CLTV values inside one byte in our
1320+
// tests so that our script-length checks don't fail (see ACCEPTED_HTLC_SCRIPT_WEIGHT).
1321+
default_config.channel_options.cltv_expiry_delta = 6*6;
1322+
default_config.channel_options.announced_channel = true;
1323+
default_config.peer_channel_config_limits.force_announced_channel_preference = false;
1324+
default_config.own_channel_config.our_htlc_minimum_msat = 1000; // sanitization being done by the sender, to exerce receiver logic we need to lift of limit
1325+
default_config
1326+
}
1327+
13171328
pub fn create_node_chanmgrs<'a, 'b>(node_count: usize, cfgs: &'a Vec<NodeCfg<'b>>, node_config: &[Option<UserConfig>]) -> Vec<ChannelManager<EnforcingSigner, &'a TestChainMonitor<'b>, &'b test_utils::TestBroadcaster, &'a test_utils::TestKeysInterface, &'b test_utils::TestFeeEstimator, &'b test_utils::TestLogger>> {
13181329
let mut chanmgrs = Vec::new();
13191330
for i in 0..node_count {
1320-
let mut default_config = UserConfig::default();
1321-
// Set cltv_expiry_delta slightly lower to keep the final CLTV values inside one byte in our
1322-
// tests so that our script-length checks don't fail (see ACCEPTED_HTLC_SCRIPT_WEIGHT).
1323-
default_config.channel_options.cltv_expiry_delta = 6*6;
1324-
default_config.channel_options.announced_channel = true;
1325-
default_config.peer_channel_config_limits.force_announced_channel_preference = false;
1326-
default_config.own_channel_config.our_htlc_minimum_msat = 1000; // sanitization being done by the sender, to exerce receiver logic we need to lift of limit
13271331
let network = Network::Testnet;
13281332
let params = ChainParameters {
13291333
network,
13301334
best_block: BestBlock::from_genesis(network),
13311335
};
1332-
let node = ChannelManager::new(cfgs[i].fee_estimator, &cfgs[i].chain_monitor, cfgs[i].tx_broadcaster, cfgs[i].logger, cfgs[i].keys_manager, if node_config[i].is_some() { node_config[i].clone().unwrap() } else { default_config }, params);
1336+
let node = ChannelManager::new(cfgs[i].fee_estimator, &cfgs[i].chain_monitor, cfgs[i].tx_broadcaster, cfgs[i].logger, cfgs[i].keys_manager,
1337+
if node_config[i].is_some() { node_config[i].clone().unwrap() } else { test_default_channel_config() }, params);
13331338
chanmgrs.push(node);
13341339
}
13351340

0 commit comments

Comments
 (0)