]> git.bitcoin.ninja Git - rust-lightning/commitdiff
Add anchor output when we have HTLCs or a to_local output
authorMatt Corallo <git@bluematt.me>
Tue, 24 Mar 2020 00:20:37 +0000 (20:20 -0400)
committerMatt Corallo <git@bluematt.me>
Mon, 25 May 2020 19:36:59 +0000 (15:36 -0400)
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
lightning/src/ln/functional_tests.rs
lightning/src/ln/reorg_tests.rs

index f2f1ad766a9a195ff2306379c18cf9c878f6704f..e22186ec2d8aae254b6f869fece0ab4ffa0548b6 100644 (file)
@@ -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<ChanSigner: ChannelKeys> Channel<ChanSigner> {
                // 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<ChanSigner: ChannelKeys> Channel<ChanSigner> {
 
                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::<ChanSigner>::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<Logger> = Arc::new(test_utils::TestLogger::new());
index dcda5ef0fa8079ae8fe348cde585c3cd36e078a4..aa2b3e88eb67f4530a4a92c86b57bef79c7f2e01 100644 (file)
@@ -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]);
index 49a55ade080f3717f92c263d73b3603d38b9feb1..b610c15da1e8b31a50c3bea592eec1a7f68860de 100644 (file)
@@ -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]);