From ad147a20e62b108f0bdae407dd47dfaa1258a600 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Mon, 23 Jul 2018 19:45:59 -0400 Subject: [PATCH] Half-ass some CLTV fixes for real channel creation --- src/ln/channelmanager.rs | 25 ++++++++++++++++--------- src/ln/router.rs | 2 +- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/ln/channelmanager.rs b/src/ln/channelmanager.rs index 7c28a122..06aa6d05 100644 --- a/src/ln/channelmanager.rs +++ b/src/ln/channelmanager.rs @@ -27,10 +27,11 @@ use crypto::digest::Digest; use crypto::symmetriccipher::SynchronousStreamCipher; use crypto::chacha20::ChaCha20; -use std::sync::{Mutex,MutexGuard,Arc}; +use std::{ptr, mem}; use std::collections::HashMap; use std::collections::hash_map; -use std::{ptr, mem}; +use std::sync::{Mutex,MutexGuard,Arc}; +use std::sync::atomic::{AtomicUsize, Ordering}; use std::time::{Instant,Duration}; mod channel_held_info { @@ -151,6 +152,7 @@ pub struct ChannelManager { announce_channels_publicly: bool, fee_proportional_millionths: u32, + latest_block_height: AtomicUsize, //TODO: Compile-time assert this is at least 32-bits long secp_ctx: Secp256k1, channel_state: Mutex, @@ -214,6 +216,7 @@ impl ChannelManager { announce_channels_publicly, fee_proportional_millionths, + latest_block_height: AtomicUsize::new(0), //TODO: Get an init value (generally need to replay recent chain on chain_monitor registration) secp_ctx, channel_state: Mutex::new(ChannelHolder{ @@ -446,9 +449,9 @@ impl ChannelManager { } /// returns the hop data, as well as the first-hop value_msat and CLTV value we should send. - fn build_onion_payloads(route: &Route) -> Result<(Vec, u64, u32), HandleError> { + fn build_onion_payloads(route: &Route, starting_htlc_offset: u32) -> Result<(Vec, u64, u32), HandleError> { let mut cur_value_msat = 0u64; - let mut cur_cltv = 0u32; + let mut cur_cltv = starting_htlc_offset; let mut last_short_channel_id = 0; let mut res: Vec = Vec::with_capacity(route.hops.len()); internal_traits::test_no_dealloc::(None); @@ -459,7 +462,7 @@ impl ChannelManager { // exactly as it should be (and the next hop isn't trying to probe to find out if we're // the intended recipient). let value_msat = if cur_value_msat == 0 { hop.fee_msat } else { cur_value_msat }; - let cltv = if cur_cltv == 0 { hop.cltv_expiry_delta } else { cur_cltv }; + let cltv = if cur_cltv == starting_htlc_offset { hop.cltv_expiry_delta + starting_htlc_offset } else { cur_cltv }; res[idx] = msgs::OnionHopData { realm: 0, data: msgs::OnionRealm0HopData { @@ -652,9 +655,10 @@ impl ChannelManager { session_key })); + let cur_height = self.latest_block_height.load(Ordering::Acquire) as u32 + 1; let onion_keys = ChannelManager::construct_onion_keys(&self.secp_ctx, &route, &session_priv)?; - let (onion_payloads, htlc_msat, htlc_cltv) = ChannelManager::build_onion_payloads(&route)?; + let (onion_payloads, htlc_msat, htlc_cltv) = ChannelManager::build_onion_payloads(&route, cur_height)?; let onion_packet = ChannelManager::construct_onion_packet(onion_payloads, onion_keys, &payment_hash)?; let (first_hop_node_id, (update_add, commitment_signed, chan_monitor)) = { @@ -704,7 +708,6 @@ impl ChannelManager { /// Call this upon creation of a funding transaction for the given channel. /// Panics if a funding transaction has already been provided for this channel. pub fn funding_transaction_generated(&self, temporary_channel_id: &[u8; 32], funding_txo: OutPoint) { - macro_rules! add_pending_event { ($event: expr) => { { @@ -1122,6 +1125,7 @@ impl ChainListener for ChannelManager { for funding_locked in new_events.drain(..) { pending_events.push(funding_locked); } + self.latest_block_height.store(height as usize, Ordering::Release); } /// We force-close the channel without letting our counterparty participate in the shutdown @@ -1143,6 +1147,7 @@ impl ChainListener for ChannelManager { true } }); + self.latest_block_height.fetch_sub(1, Ordering::AcqRel); } } @@ -1428,6 +1433,8 @@ impl ChannelMessageHandler for ChannelManager { } }; + //TODO: Check that msg.cltv_expiry is within acceptable bounds! + let mut pending_forward_info = if next_hop_data.hmac == [0; 32] { // OUR PAYMENT! if next_hop_data.data.amt_to_forward != msg.amount_msat { @@ -2909,7 +2916,7 @@ mod tests { { let mut header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 }; nodes[3].chain_monitor.block_connected_checked(&header, 1, &Vec::new()[..], &[0; 0]); - for i in 2..TEST_FINAL_CLTV - 5 { + for i in 2..TEST_FINAL_CLTV - 3 { header = BlockHeader { version: 0x20000000, prev_blockhash: header.bitcoin_hash(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 }; nodes[3].chain_monitor.block_connected_checked(&header, i, &Vec::new()[..], &[0; 0]); } @@ -2921,7 +2928,7 @@ mod tests { header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 }; nodes[4].chain_monitor.block_connected_checked(&header, 1, &Vec::new()[..], &[0; 0]); - for i in 2..TEST_FINAL_CLTV - 5 { + for i in 2..TEST_FINAL_CLTV - 3 { header = BlockHeader { version: 0x20000000, prev_blockhash: header.bitcoin_hash(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 }; nodes[4].chain_monitor.block_connected_checked(&header, i, &Vec::new()[..], &[0; 0]); } diff --git a/src/ln/router.rs b/src/ln/router.rs index 0ee6450f..ad7ae675 100644 --- a/src/ln/router.rs +++ b/src/ln/router.rs @@ -21,7 +21,7 @@ pub struct RouteHop { /// The fee taken on this hop. For the last hop, this should be the full value of the payment. pub fee_msat: u64, /// The CLTV delta added for this hop. For the last hop, this should be the full CLTV value - /// expected at the destination, NOT a delta. + /// expected at the destination, in excess of the current block height. pub cltv_expiry_delta: u32, } -- 2.30.2