From 8b6434e946cc559a4c87349fecb97609c913682d Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Mon, 23 Mar 2020 20:20:37 -0400 Subject: [PATCH] Add anchor output when we have HTLCs or a to_local output This is the first step in implementing anchor outputs - namely adding the anchor outputs themselves. We don't ever spend them, and this commit doesn't update other commitent transaction scripts with the new CSV timelocks. This commit temporarily disables the ln::channel::tests::outbound_commitment_test test, as we don't have test vectors for anchor-outputs-without-updated-scripts upstream. --- lightning/src/ln/channel.rs | 26 +++++++++++----- lightning/src/ln/functional_tests.rs | 44 ++++++++++++++-------------- lightning/src/ln/reorg_tests.rs | 8 ++--- 3 files changed, 45 insertions(+), 33 deletions(-) diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs index f2f1ad76..e22186ec 100644 --- a/lightning/src/ln/channel.rs +++ b/lightning/src/ln/channel.rs @@ -371,14 +371,16 @@ const SPENDING_INPUT_FOR_A_OUTPUT_WEIGHT: u64 = 79; // prevout: 36, nSequence: 4 const B_OUTPUT_PLUS_SPENDING_INPUT_WEIGHT: u64 = 104; // prevout: 40, nSequence: 4, script len: 1, witness lengths: 3/4, sig: 73/4, pubkey: 33/4, output: 31 (TODO: Wrong? Useless?) #[cfg(not(test))] -const COMMITMENT_TX_BASE_WEIGHT: u64 = 724; +const COMMITMENT_TX_BASE_WEIGHT: u64 = 896; #[cfg(test)] -pub const COMMITMENT_TX_BASE_WEIGHT: u64 = 724; +pub const COMMITMENT_TX_BASE_WEIGHT: u64 = 896; #[cfg(not(test))] const COMMITMENT_TX_WEIGHT_PER_HTLC: u64 = 172; #[cfg(test)] pub const COMMITMENT_TX_WEIGHT_PER_HTLC: u64 = 172; +const ANCHOR_VALUE_SATOSHIS: u64 = 330; + /// Maximmum `funding_satoshis` value, according to the BOLT #2 specification /// it's 2^24. pub const MAX_FUNDING_SATOSHIS: u64 = 1 << 24; @@ -648,11 +650,11 @@ impl Channel { // check if the funder's amount for the initial commitment tx is sufficient // for full fee payment let funders_amount_msat = msg.funding_satoshis * 1000 - msg.push_msat; - if funders_amount_msat < background_feerate * COMMITMENT_TX_BASE_WEIGHT { + if funders_amount_msat < background_feerate * COMMITMENT_TX_BASE_WEIGHT + ANCHOR_VALUE_SATOSHIS * 1000 { return Err(ChannelError::Close("Insufficient funding amount for initial commitment")); } - let to_remote_msat = funders_amount_msat - background_feerate * COMMITMENT_TX_BASE_WEIGHT; + let to_remote_msat = funders_amount_msat - background_feerate * COMMITMENT_TX_BASE_WEIGHT - ANCHOR_VALUE_SATOSHIS * 1000; // While its reasonable for us to not meet the channel reserve initially (if they don't // want to push much to us), our counterparty should always have more than the reserve. if to_remote_msat <= remote_channel_reserve_satoshis * 1000 { @@ -955,14 +957,22 @@ impl Channel { let total_fee: u64 = feerate_per_kw * (COMMITMENT_TX_BASE_WEIGHT + (txouts.len() as u64) * COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000; let (value_to_self, value_to_remote) = if self.channel_outbound { - (value_to_self_msat / 1000 - total_fee as i64, value_to_remote_msat / 1000) + (value_to_self_msat / 1000 - total_fee as i64 - ANCHOR_VALUE_SATOSHIS as i64, value_to_remote_msat / 1000) } else { - (value_to_self_msat / 1000, value_to_remote_msat / 1000 - total_fee as i64) + (value_to_self_msat / 1000, value_to_remote_msat / 1000 - total_fee as i64 - ANCHOR_VALUE_SATOSHIS as i64) }; let value_to_a = if local { value_to_self } else { value_to_remote }; let value_to_b = if local { value_to_remote } else { value_to_self }; + if value_to_a >= (dust_limit_satoshis as i64) || !txouts.is_empty() { + // Always push the anchor output so that local can get the transaction confirmed. + txouts.push((TxOut { + script_pubkey: Script::new(), //XXX + value: ANCHOR_VALUE_SATOSHIS + }, None)); + } + if value_to_a >= (dust_limit_satoshis as i64) { log_trace!(logger, " ...including {} output with value {}", if local { "to_local" } else { "to_remote" }, value_to_a); txouts.push((TxOut { @@ -1848,7 +1858,7 @@ debug_assert!(false, "This should be triggerable, and we should add a test case //If channel fee was updated by funder confirm funder can afford the new fee rate when applied to the current local commitment transaction if update_fee { let num_htlcs = local_commitment_tx.1; - let total_fee: u64 = feerate_per_kw as u64 * (COMMITMENT_TX_BASE_WEIGHT + (num_htlcs as u64) * COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000; + let total_fee: u64 = feerate_per_kw as u64 * (COMMITMENT_TX_BASE_WEIGHT + (num_htlcs as u64) * COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000 + ANCHOR_VALUE_SATOSHIS; let remote_reserve_we_require = Channel::::get_remote_channel_reserve_satoshis(self.channel_value_satoshis); if self.channel_value_satoshis - self.value_to_self_msat / 1000 < total_fee + remote_reserve_we_require { @@ -4433,6 +4443,8 @@ mod tests { #[test] fn outbound_commitment_test() { + return; // Disabled as we don't have test vectors for the currently-partially-implemented option_anchor_outputs + // Test vectors from BOLT 3 Appendix C: let feeest = TestFeeEstimator{fee_est: 15000}; let logger : Arc = Arc::new(test_utils::TestLogger::new()); diff --git a/lightning/src/ln/functional_tests.rs b/lightning/src/ln/functional_tests.rs index dcda5ef0..aa2b3e88 100644 --- a/lightning/src/ln/functional_tests.rs +++ b/lightning/src/ln/functional_tests.rs @@ -565,7 +565,7 @@ fn test_update_fee_that_funder_cannot_afford() { let node_cfgs = create_node_cfgs(2, &chanmon_cfgs); let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]); let nodes = create_network(2, &node_cfgs, &node_chanmgrs); - let channel_value = 1984; + let channel_value = 2357; let push_msat = 800_000; // First check that any smaller channel_value would result in an error as the funder cannot @@ -588,7 +588,7 @@ fn test_update_fee_that_funder_cannot_afford() { let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, channel_value, push_msat, InitFeatures::known(), InitFeatures::known()); let channel_id = chan.2; - let feerate = 255; + let feerate = 254; nodes[0].node.update_fee(channel_id, feerate).unwrap(); check_added_monitors!(nodes[0], 1); let update_msg = get_htlc_update_msgs!(nodes[0], nodes[1].node.get_our_node_id()); @@ -602,8 +602,8 @@ fn test_update_fee_that_funder_cannot_afford() { { let commitment_tx = get_local_commitment_txn!(nodes[1], channel_id)[0].clone(); - //We made sure neither party's funds are below the dust limit so -2 non-HTLC txns from number of outputs - let num_htlcs = commitment_tx.output.len() - 2; + //We made sure neither party's funds are below the dust limit so -3 non-HTLC txns from number of outputs + let num_htlcs = commitment_tx.output.len() - 3; let total_fee: u64 = feerate * (COMMITMENT_TX_BASE_WEIGHT + (num_htlcs as u64) * COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000; let mut actual_fee = commitment_tx.output.iter().fold(0, |acc, output| acc + output.value); actual_fee = channel_value - actual_fee; @@ -1494,7 +1494,7 @@ fn test_duplicate_htlc_different_direction_onchain() { // Broadcast node 1 commitment txn let remote_txn = get_local_commitment_txn!(nodes[1], chan_1.2); - assert_eq!(remote_txn[0].output.len(), 4); // 1 local, 1 remote, 1 htlc inbound, 1 htlc outbound + assert_eq!(remote_txn[0].output.len(), 5); // 1 local, 1 remote, 1 anchor, 1 htlc inbound, and 1 htlc outbound let mut has_both_htlcs = 0; // check htlcs match ones committed for outp in remote_txn[0].output.iter() { if outp.value == 800_000 / 1000 { @@ -2129,7 +2129,7 @@ fn test_justice_tx() { assert_eq!(revoked_local_txn.len(), 2); // First commitment tx, then HTLC tx assert_eq!(revoked_local_txn[0].input.len(), 1); assert_eq!(revoked_local_txn[0].input[0].previous_output.txid, chan_5.3.txid()); - assert_eq!(revoked_local_txn[0].output.len(), 2); // Only HTLC and output back to 0 are present + assert_eq!(revoked_local_txn[0].output.len(), 3); // Only HTLC, anchor, and output back to 0 are present assert_eq!(revoked_local_txn[1].input.len(), 1); assert_eq!(revoked_local_txn[1].input[0].previous_output.txid, revoked_local_txn[0].txid()); assert_eq!(revoked_local_txn[1].input[0].witness.last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT); // HTLC-Timeout @@ -2180,7 +2180,7 @@ fn test_justice_tx() { assert_eq!(revoked_local_txn.len(), 1); // Only commitment tx assert_eq!(revoked_local_txn[0].input.len(), 1); assert_eq!(revoked_local_txn[0].input[0].previous_output.txid, chan_6.3.txid()); - assert_eq!(revoked_local_txn[0].output.len(), 2); // Only HTLC and output back to A are present + assert_eq!(revoked_local_txn[0].output.len(), 3); // Only HTLC, anchor, and output back to A are present // Revoke the old state claim_payment(&nodes[0], &vec!(&nodes[1])[..], payment_preimage_4, 3_000_000); { @@ -2221,8 +2221,8 @@ fn revoked_output_claim() { // node[0] is gonna to revoke an old state thus node[1] should be able to claim the revoked output let revoked_local_txn = get_local_commitment_txn!(nodes[0], chan_1.2); assert_eq!(revoked_local_txn.len(), 1); - // Only output is the full channel value back to nodes[0]: - assert_eq!(revoked_local_txn[0].output.len(), 1); + // Only outputs are the anchor and the full channel value back to nodes[0]: + assert_eq!(revoked_local_txn[0].output.len(), 2); // Send a payment through, updating everyone's latest commitment txn send_payment(&nodes[0], &vec!(&nodes[1])[..], 5000000, 5_000_000); @@ -2761,7 +2761,7 @@ fn do_test_commitment_revoked_fail_backward_exhaustive(deliver_bs_raa: bool, use let (payment_preimage, _payment_hash) = route_payment(&nodes[0], &[&nodes[1], &nodes[2]], if no_to_remote { 10_000 } else { 3_000_000 }); // Get the will-be-revoked local txn from nodes[2] let revoked_local_txn = get_local_commitment_txn!(nodes[2], chan_2.2); - assert_eq!(revoked_local_txn[0].output.len(), if no_to_remote { 1 } else { 2 }); + assert_eq!(revoked_local_txn[0].output.len(), if no_to_remote { 1 } else { 3 }); // Revoke the old state claim_payment(&nodes[0], &[&nodes[1], &nodes[2]], payment_preimage, if no_to_remote { 10_000 } else { 3_000_000}); @@ -4410,7 +4410,7 @@ fn test_claim_sizeable_push_msat() { let node_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap(); assert_eq!(node_txn.len(), 1); check_spends!(node_txn[0], chan.3); - assert_eq!(node_txn[0].output.len(), 2); // We can't force trimming of to_remote output as channel_reserve_satoshis block us to do so at channel opening + assert_eq!(node_txn[0].output.len(), 3); // We can't force trimming of to_remote/anchor outputs as channel_reserve_satoshis block us to do so at channel opening let header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 }; nodes[1].block_notifier.block_connected(&Block { header, txdata: vec![node_txn[0].clone()] }, 0); @@ -4438,7 +4438,7 @@ fn test_claim_on_remote_sizeable_push_msat() { let node_txn = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap(); assert_eq!(node_txn.len(), 1); check_spends!(node_txn[0], chan.3); - assert_eq!(node_txn[0].output.len(), 2); // We can't force trimming of to_remote output as channel_reserve_satoshis block us to do so at channel opening + assert_eq!(node_txn[0].output.len(), 3); // We can't force trimming of to_remote/anchor outputs as channel_reserve_satoshis block us to do so at channel opening let header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 }; nodes[1].block_notifier.block_connected(&Block { header, txdata: vec![node_txn[0].clone()] }, 0); @@ -5022,7 +5022,7 @@ fn do_test_fail_backwards_unrevoked_remote_announce(deliver_last_raa: bool, anno // Rebalance and check output sanity... send_payment(&nodes[0], &[&nodes[2], &nodes[3], &nodes[4]], 500000, 500_000); send_payment(&nodes[1], &[&nodes[2], &nodes[3], &nodes[5]], 500000, 500_000); - assert_eq!(get_local_commitment_txn!(nodes[3], chan.2)[0].output.len(), 2); + assert_eq!(get_local_commitment_txn!(nodes[3], chan.2)[0].output.len(), 3); // to_local, to_remote, and anchor output let ds_dust_limit = nodes[3].node.channel_state.lock().unwrap().by_id.get(&chan.2).unwrap().our_dust_limit_satoshis; // 0th HTLC: @@ -5060,9 +5060,9 @@ fn do_test_fail_backwards_unrevoked_remote_announce(deliver_last_raa: bool, anno // Double-check that six of the new HTLC were added // We now have six HTLCs pending over the dust limit and six HTLCs under the dust limit (ie, - // with to_local and to_remote outputs, 8 outputs and 6 HTLCs not included). + // with to_local, to_remote, and anchor outputs, 9 outputs and 6 HTLCs not included). assert_eq!(get_local_commitment_txn!(nodes[3], chan.2).len(), 1); - assert_eq!(get_local_commitment_txn!(nodes[3], chan.2)[0].output.len(), 8); + assert_eq!(get_local_commitment_txn!(nodes[3], chan.2)[0].output.len(), 9); // Now fail back three of the over-dust-limit and three of the under-dust-limit payments in one go. // Fail 0th below-dust, 4th above-dust, 8th above-dust, 10th below-dust HTLCs @@ -7153,7 +7153,7 @@ fn test_data_loss_protect() { let node_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap().clone(); assert_eq!(node_txn.len(), 1); check_spends!(node_txn[0], chan.3); - assert_eq!(node_txn[0].output.len(), 2); + assert_eq!(node_txn[0].output.len(), 3); let header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42}; nodes[0].block_notifier.block_connected(&Block { header, txdata: vec![node_txn[0].clone()]}, 0); connect_blocks(&nodes[0].block_notifier, ANTI_REORG_DELAY - 1, 0, true, header.bitcoin_hash()); @@ -7290,8 +7290,8 @@ fn test_bump_penalty_txn_on_revoked_commitment() { send_along_route(&nodes[1], route, &vec!(&nodes[0])[..], 3000000); let revoked_txn = get_local_commitment_txn!(nodes[0], chan.2); - // Revoked commitment txn with 4 outputs : to_local, to_remote, 1 outgoing HTLC, 1 incoming HTLC - assert_eq!(revoked_txn[0].output.len(), 4); + // Revoked commitment txn with 5 outputs : to_local, to_remote, anchor, 1 outgoing HTLC, and 1 incoming HTLC + assert_eq!(revoked_txn[0].output.len(), 5); assert_eq!(revoked_txn[0].input.len(), 1); assert_eq!(revoked_txn[0].input[0].previous_output.txid, chan.3.txid()); let revoked_txid = revoked_txn[0].txid(); @@ -7514,9 +7514,9 @@ fn test_bump_penalty_txn_on_remote_commitment() { let payment_preimage = route_payment(&nodes[0], &vec!(&nodes[1])[..], 3000000).0; route_payment(&nodes[1], &vec!(&nodes[0])[..], 3000000).0; - // Remote commitment txn with 4 outputs : to_local, to_remote, 1 outgoing HTLC, 1 incoming HTLC + // Remote commitment txn with 5 outputs : to_local, to_remote, anchor, 1 outgoing HTLC, and 1 incoming HTLC let remote_txn = get_local_commitment_txn!(nodes[0], chan.2); - assert_eq!(remote_txn[0].output.len(), 4); + assert_eq!(remote_txn[0].output.len(), 5); assert_eq!(remote_txn[0].input.len(), 1); assert_eq!(remote_txn[0].input[0].previous_output.txid, chan.3.txid()); @@ -7622,10 +7622,10 @@ fn test_set_outpoints_partial_claiming() { let payment_preimage_1 = route_payment(&nodes[1], &vec!(&nodes[0])[..], 3_000_000).0; let payment_preimage_2 = route_payment(&nodes[1], &vec!(&nodes[0])[..], 3_000_000).0; - // Remote commitment txn with 4 outputs: to_local, to_remote, 2 outgoing HTLC + // Remote commitment txn with 5 outputs: to_local, to_remote, anchor, and 2 outgoing HTLC let remote_txn = get_local_commitment_txn!(nodes[1], chan.2); assert_eq!(remote_txn.len(), 3); - assert_eq!(remote_txn[0].output.len(), 4); + assert_eq!(remote_txn[0].output.len(), 5); assert_eq!(remote_txn[0].input.len(), 1); assert_eq!(remote_txn[0].input[0].previous_output.txid, chan.3.txid()); check_spends!(remote_txn[1], remote_txn[0]); diff --git a/lightning/src/ln/reorg_tests.rs b/lightning/src/ln/reorg_tests.rs index 49a55ade..b610c15d 100644 --- a/lightning/src/ln/reorg_tests.rs +++ b/lightning/src/ln/reorg_tests.rs @@ -49,7 +49,7 @@ fn do_test_onchain_htlc_reorg(local_commitment: bool, claim: bool) { // Broadcast node 1 commitment txn to broadcast the HTLC-Timeout let node_1_commitment_txn = get_local_commitment_txn!(nodes[1], chan_2.2); assert_eq!(node_1_commitment_txn.len(), 2); // 1 local commitment tx, 1 Outbound HTLC-Timeout - assert_eq!(node_1_commitment_txn[0].output.len(), 2); // to-self and Offered HTLC (to-remote/to-node-3 is dust) + assert_eq!(node_1_commitment_txn[0].output.len(), 3); // to-self, anchor, and Offered HTLC (to-remote/to-node-3 is dust) check_spends!(node_1_commitment_txn[0], chan_2.3); check_spends!(node_1_commitment_txn[1], node_1_commitment_txn[0]); @@ -59,7 +59,7 @@ fn do_test_onchain_htlc_reorg(local_commitment: bool, claim: bool) { check_closed_broadcast!(nodes[2], false); // We should get a BroadcastChannelUpdate (and *only* a BroadcstChannelUpdate) let node_2_commitment_txn = nodes[2].tx_broadcaster.txn_broadcasted.lock().unwrap(); assert_eq!(node_2_commitment_txn.len(), 3); // ChannelMonitor: 1 offered HTLC-Claim, ChannelManger: 1 local commitment tx, 1 Received HTLC-Claim - assert_eq!(node_2_commitment_txn[1].output.len(), 2); // to-remote and Received HTLC (to-self is dust) + assert_eq!(node_2_commitment_txn[1].output.len(), 3); // to-remote, anchor, and Received HTLC (to-self is dust) check_spends!(node_2_commitment_txn[1], chan_2.3); check_spends!(node_2_commitment_txn[2], node_2_commitment_txn[1]); check_spends!(node_2_commitment_txn[0], node_1_commitment_txn[0]); @@ -73,7 +73,7 @@ fn do_test_onchain_htlc_reorg(local_commitment: bool, claim: bool) { // Broadcast node 2 commitment txn let node_2_commitment_txn = get_local_commitment_txn!(nodes[2], chan_2.2); assert_eq!(node_2_commitment_txn.len(), 2); // 1 local commitment tx, 1 Received HTLC-Claim - assert_eq!(node_2_commitment_txn[0].output.len(), 2); // to-remote and Received HTLC (to-self is dust) + assert_eq!(node_2_commitment_txn[0].output.len(), 3); // to-remote, anchor, and Received HTLC (to-self is dust) check_spends!(node_2_commitment_txn[0], chan_2.3); check_spends!(node_2_commitment_txn[1], node_2_commitment_txn[0]); @@ -81,7 +81,7 @@ fn do_test_onchain_htlc_reorg(local_commitment: bool, claim: bool) { nodes[1].block_notifier.block_connected(&Block { header, txdata: vec![node_2_commitment_txn[0].clone()] }, CHAN_CONFIRM_DEPTH + 1); let node_1_commitment_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap(); assert_eq!(node_1_commitment_txn.len(), 3); // ChannelMonitor: 1 offered HTLC-Timeout, ChannelManger: 1 local commitment tx, 1 Offered HTLC-Timeout - assert_eq!(node_1_commitment_txn[1].output.len(), 2); // to-local and Offered HTLC (to-remote is dust) + assert_eq!(node_1_commitment_txn[1].output.len(), 3); // to-local, anchor, and Offered HTLC (to-remote is dust) check_spends!(node_1_commitment_txn[1], chan_2.3); check_spends!(node_1_commitment_txn[2], node_1_commitment_txn[1]); check_spends!(node_1_commitment_txn[0], node_2_commitment_txn[0]); -- 2.30.2