Skip to content

Commit 43e6141

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 3a509b0 commit 43e6141

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
@@ -2846,7 +2846,7 @@ mod tests {
28462846
let secp_ctx = Secp256k1::new();
28472847
let logger = Arc::new(TestLogger::new());
28482848
let broadcaster = Arc::new(TestBroadcaster{txn_broadcasted: Mutex::new(Vec::new()), blocks: Arc::new(Mutex::new(Vec::new()))});
2849-
let fee_estimator = Arc::new(TestFeeEstimator { sat_per_kw: 253 });
2849+
let fee_estimator = Arc::new(TestFeeEstimator { sat_per_kw: Mutex::new(253) });
28502850

28512851
let dummy_key = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap());
28522852
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
@@ -1540,7 +1540,9 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
15401540
if *amt_to_forward < chan.get_counterparty_htlc_minimum_msat() { // amount_below_minimum
15411541
break Some(("HTLC amount was below the htlc_minimum_msat", 0x1000 | 11, Some(self.get_channel_update(chan).unwrap())));
15421542
}
1543-
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) });
1543+
let fee = amt_to_forward.checked_mul(chan.get_fee_proportional_millionths() as u64)
1544+
.and_then(|prop_fee| { (prop_fee / 1000000)
1545+
.checked_add(chan.get_holder_fee_base_msat() as u64) });
15441546
if fee.is_none() || msg.amount_msat < fee.unwrap() || (msg.amount_msat - fee.unwrap()) < *amt_to_forward { // fee_insufficient
15451547
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())));
15461548
}
@@ -1605,7 +1607,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
16051607
cltv_expiry_delta: chan.get_cltv_expiry_delta(),
16061608
htlc_minimum_msat: chan.get_counterparty_htlc_minimum_msat(),
16071609
htlc_maximum_msat: OptionalField::Present(chan.get_announced_htlc_max_msat()),
1608-
fee_base_msat: chan.get_holder_fee_base_msat(&self.fee_estimator),
1610+
fee_base_msat: chan.get_holder_fee_base_msat(),
16091611
fee_proportional_millionths: chan.get_fee_proportional_millionths(),
16101612
excess_data: Vec::new(),
16111613
};

lightning/src/ln/functional_test_utils.rs

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ impl<'a, 'b, 'c> Drop for Node<'a, 'b, 'c> {
269269
// Check that if we serialize and then deserialize all our channel monitors we get the
270270
// same set of outputs to watch for on chain as we have now. Note that if we write
271271
// tests that fully close channels and remove the monitors at some point this may break.
272-
let feeest = test_utils::TestFeeEstimator { sat_per_kw: 253 };
272+
let feeest = test_utils::TestFeeEstimator { sat_per_kw: Mutex::new(253) };
273273
let mut deserialized_monitors = Vec::new();
274274
{
275275
let old_monitors = self.chain_monitor.chain_monitor.monitors.read().unwrap();
@@ -295,7 +295,7 @@ impl<'a, 'b, 'c> Drop for Node<'a, 'b, 'c> {
295295
<(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 {
296296
default_config: *self.node.get_current_default_configuration(),
297297
keys_manager: self.keys_manager,
298-
fee_estimator: &test_utils::TestFeeEstimator { sat_per_kw: 253 },
298+
fee_estimator: &test_utils::TestFeeEstimator { sat_per_kw: Mutex::new(253) },
299299
chain_monitor: self.chain_monitor,
300300
tx_broadcaster: &test_utils::TestBroadcaster {
301301
txn_broadcasted: Mutex::new(self.tx_broadcaster.txn_broadcasted.lock().unwrap().clone()),
@@ -1316,7 +1316,7 @@ pub fn create_chanmon_cfgs(node_count: usize) -> Vec<TestChanMonCfg> {
13161316
txn_broadcasted: Mutex::new(Vec::new()),
13171317
blocks: Arc::new(Mutex::new(vec![(genesis_block(Network::Testnet).header, 0)])),
13181318
};
1319-
let fee_estimator = test_utils::TestFeeEstimator { sat_per_kw: 253 };
1319+
let fee_estimator = test_utils::TestFeeEstimator { sat_per_kw: Mutex::new(253) };
13201320
let chain_source = test_utils::TestChainSource::new(Network::Testnet);
13211321
let logger = test_utils::TestLogger::with_id(format!("node {}", i));
13221322
let persister = test_utils::TestPersister::new();
@@ -1341,22 +1341,27 @@ pub fn create_node_cfgs<'a>(node_count: usize, chanmon_cfgs: &'a Vec<TestChanMon
13411341
nodes
13421342
}
13431343

1344+
pub fn test_default_channel_config() -> UserConfig {
1345+
let mut default_config = UserConfig::default();
1346+
// Set cltv_expiry_delta slightly lower to keep the final CLTV values inside one byte in our
1347+
// tests so that our script-length checks don't fail (see ACCEPTED_HTLC_SCRIPT_WEIGHT).
1348+
default_config.channel_options.cltv_expiry_delta = 6*6;
1349+
default_config.channel_options.announced_channel = true;
1350+
default_config.peer_channel_config_limits.force_announced_channel_preference = false;
1351+
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
1352+
default_config
1353+
}
1354+
13441355
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>> {
13451356
let mut chanmgrs = Vec::new();
13461357
for i in 0..node_count {
1347-
let mut default_config = UserConfig::default();
1348-
// Set cltv_expiry_delta slightly lower to keep the final CLTV values inside one byte in our
1349-
// tests so that our script-length checks don't fail (see ACCEPTED_HTLC_SCRIPT_WEIGHT).
1350-
default_config.channel_options.cltv_expiry_delta = 6*6;
1351-
default_config.channel_options.announced_channel = true;
1352-
default_config.peer_channel_config_limits.force_announced_channel_preference = false;
1353-
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
13541358
let network = Network::Testnet;
13551359
let params = ChainParameters {
13561360
network,
13571361
best_block: BestBlock::from_genesis(network),
13581362
};
1359-
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);
1363+
let node = ChannelManager::new(cfgs[i].fee_estimator, &cfgs[i].chain_monitor, cfgs[i].tx_broadcaster, cfgs[i].logger, cfgs[i].keys_manager,
1364+
if node_config[i].is_some() { node_config[i].clone().unwrap() } else { test_default_channel_config() }, params);
13601365
chanmgrs.push(node);
13611366
}
13621367

0 commit comments

Comments
 (0)