use bitcoin::network::constants::Network;
use bitcoin::hashes::{Hash, HashEngine};
-use bitcoin::hashes::hmac::{Hmac, HmacEngine};
use bitcoin::hashes::sha256::Hash as Sha256;
use bitcoin::hashes::sha256d::Hash as Sha256dHash;
-use bitcoin::hashes::cmp::fixed_time_eq;
use bitcoin::hash_types::{BlockHash, Txid};
use bitcoin::secp256k1::key::{SecretKey,PublicKey};
use ln::msgs::NetAddress;
use ln::onion_utils;
use ln::msgs::{ChannelMessageHandler, DecodeError, LightningError, MAX_VALUE_MSAT, OptionalField};
-use chain::keysinterface::{Sign, KeysInterface, KeysManager, InMemorySigner};
+use chain::keysinterface::{Sign, KeysInterface, KeysManager, InMemorySigner, Recipient};
use util::config::UserConfig;
use util::events::{EventHandler, EventsProvider, MessageSendEvent, MessageSendEventsProvider, ClosureReason};
use util::{byte_utils, events};
use util::ser::{BigSize, FixedLengthReader, Readable, ReadableArgs, MaybeReadable, Writeable, Writer};
-use util::chacha20::{ChaCha20, ChaChaReader};
use util::logger::{Level, Logger};
use util::errors::APIError;
use prelude::*;
use core::{cmp, mem};
use core::cell::RefCell;
-use io::{Cursor, Read};
+use io::Read;
use sync::{Arc, Condvar, Mutex, MutexGuard, RwLock, RwLockReadGuard};
use core::sync::atomic::{AtomicUsize, Ordering};
use core::time::Duration;
use ln::msgs;
use ln::msgs::MAX_VALUE_MSAT;
use util::chacha20::ChaCha20;
+ use util::crypto::hkdf_extract_expand_thrice;
use util::logger::Logger;
use core::convert::TryInto;
impl ExpandedKey {
pub(super) fn new(key_material: &KeyMaterial) -> ExpandedKey {
- hkdf_extract_expand(b"LDK Inbound Payment Key Expansion", &key_material)
+ let (metadata_key, ldk_pmt_hash_key, user_pmt_hash_key) =
+ hkdf_extract_expand_thrice(b"LDK Inbound Payment Key Expansion", &key_material.0);
+ Self {
+ metadata_key,
+ ldk_pmt_hash_key,
+ user_pmt_hash_key,
+ }
}
}
}
return Ok(PaymentPreimage(decoded_payment_preimage))
}
-
- fn hkdf_extract_expand(salt: &[u8], ikm: &KeyMaterial) -> ExpandedKey {
- let mut hmac = HmacEngine::<Sha256>::new(salt);
- hmac.input(&ikm.0);
- let prk = Hmac::from_engine(hmac).into_inner();
- let mut hmac = HmacEngine::<Sha256>::new(&prk[..]);
- hmac.input(&[1; 1]);
- let metadata_key = Hmac::from_engine(hmac).into_inner();
-
- let mut hmac = HmacEngine::<Sha256>::new(&prk[..]);
- hmac.input(&metadata_key);
- hmac.input(&[2; 1]);
- let ldk_pmt_hash_key = Hmac::from_engine(hmac).into_inner();
-
- let mut hmac = HmacEngine::<Sha256>::new(&prk[..]);
- hmac.input(&ldk_pmt_hash_key);
- hmac.input(&[3; 1]);
- let user_pmt_hash_key = Hmac::from_engine(hmac).into_inner();
-
- ExpandedKey {
- metadata_key,
- ldk_pmt_hash_key,
- user_pmt_hash_key,
- }
- }
}
// We hold various information about HTLC relay in the HTLC objects in Channel itself:
macro_rules! handle_chan_restoration_locked {
($self: ident, $channel_lock: expr, $channel_state: expr, $channel_entry: expr,
$raa: expr, $commitment_update: expr, $order: expr, $chanmon_update: expr,
- $pending_forwards: expr, $funding_broadcastable: expr, $funding_locked: expr) => { {
+ $pending_forwards: expr, $funding_broadcastable: expr, $funding_locked: expr, $announcement_sigs: expr) => { {
let mut htlc_forwards = None;
let counterparty_node_id = $channel_entry.get().get_counterparty_node_id();
node_id: counterparty_node_id,
msg,
});
- if let Some(announcement_sigs) = $self.get_announcement_sigs($channel_entry.get()) {
- $channel_state.pending_msg_events.push(events::MessageSendEvent::SendAnnouncementSignatures {
- node_id: counterparty_node_id,
- msg: announcement_sigs,
- });
- }
$channel_state.short_to_id.insert($channel_entry.get().get_short_channel_id().unwrap(), $channel_entry.get().channel_id());
}
+ if let Some(msg) = $announcement_sigs {
+ $channel_state.pending_msg_events.push(events::MessageSendEvent::SendAnnouncementSignatures {
+ node_id: counterparty_node_id,
+ msg,
+ });
+ }
let funding_broadcastable: Option<Transaction> = $funding_broadcastable; // Force type-checking to resolve
if let Some(monitor_update) = chanmon_update {
pending_inbound_payments: Mutex::new(HashMap::new()),
pending_outbound_payments: Mutex::new(HashMap::new()),
- our_network_key: keys_manager.get_node_secret(),
- our_network_pubkey: PublicKey::from_secret_key(&secp_ctx, &keys_manager.get_node_secret()),
+ our_network_key: keys_manager.get_node_secret(Recipient::Node).unwrap(),
+ our_network_pubkey: PublicKey::from_secret_key(&secp_ctx, &keys_manager.get_node_secret(Recipient::Node).unwrap()),
secp_ctx,
inbound_payment_key: expanded_inbound_key,
arr.copy_from_slice(&SharedSecret::new(&msg.onion_routing_packet.public_key.unwrap(), &self.our_network_key)[..]);
arr
};
- let (rho, mu) = onion_utils::gen_rho_mu_from_shared_secret(&shared_secret);
if msg.onion_routing_packet.version != 0 {
//TODO: Spec doesn't indicate if we should only hash hop_data here (and in other
return_malformed_err!("Unknown onion packet version", 0x8000 | 0x4000 | 4);
}
- let mut hmac = HmacEngine::<Sha256>::new(&mu);
- hmac.input(&msg.onion_routing_packet.hop_data);
- hmac.input(&msg.payment_hash.0[..]);
- if !fixed_time_eq(&Hmac::from_engine(hmac).into_inner(), &msg.onion_routing_packet.hmac) {
- return_malformed_err!("HMAC Check failed", 0x8000 | 0x4000 | 5);
- }
-
let mut channel_state = None;
macro_rules! return_err {
($msg: expr, $err_code: expr, $data: expr) => {
}
}
- let mut chacha = ChaCha20::new(&rho, &[0u8; 8]);
- let mut chacha_stream = ChaChaReader { chacha: &mut chacha, read: Cursor::new(&msg.onion_routing_packet.hop_data[..]) };
- let (next_hop_data, next_hop_hmac): (msgs::OnionHopData, _) = {
- match <msgs::OnionHopData as Readable>::read(&mut chacha_stream) {
- Err(err) => {
- let error_code = match err {
- msgs::DecodeError::UnknownVersion => 0x4000 | 1, // unknown realm byte
- msgs::DecodeError::UnknownRequiredFeature|
- msgs::DecodeError::InvalidValue|
- msgs::DecodeError::ShortRead => 0x4000 | 22, // invalid_onion_payload
- _ => 0x2000 | 2, // Should never happen
- };
- return_err!("Unable to decode our hop data", error_code, &[0;0]);
- },
- Ok(msg) => {
- let mut hmac = [0; 32];
- if let Err(_) = chacha_stream.read_exact(&mut hmac[..]) {
- return_err!("Unable to decode hop data", 0x4000 | 22, &[0;0]);
- }
- (msg, hmac)
- },
- }
+ let next_hop = match onion_utils::decode_next_hop(shared_secret, &msg.onion_routing_packet.hop_data[..], msg.onion_routing_packet.hmac, msg.payment_hash) {
+ Ok(res) => res,
+ Err(onion_utils::OnionDecodeErr::Malformed { err_msg, err_code }) => {
+ return_malformed_err!(err_msg, err_code);
+ },
+ Err(onion_utils::OnionDecodeErr::Relay { err_msg, err_code }) => {
+ return_err!(err_msg, err_code, &[0; 0]);
+ },
};
- let pending_forward_info = if next_hop_hmac == [0; 32] {
- #[cfg(test)]
- {
- // In tests, make sure that the initial onion pcket data is, at least, non-0.
- // We could do some fancy randomness test here, but, ehh, whatever.
- // This checks for the issue where you can calculate the path length given the
- // onion data as all the path entries that the originator sent will be here
- // as-is (and were originally 0s).
- // Of course reverse path calculation is still pretty easy given naive routing
- // algorithms, but this fixes the most-obvious case.
- let mut next_bytes = [0; 32];
- chacha_stream.read_exact(&mut next_bytes).unwrap();
- assert_ne!(next_bytes[..], [0; 32][..]);
- chacha_stream.read_exact(&mut next_bytes).unwrap();
- assert_ne!(next_bytes[..], [0; 32][..]);
- }
-
- // OUR PAYMENT!
- // final_expiry_too_soon
- // We have to have some headroom to broadcast on chain if we have the preimage, so make sure
- // we have at least HTLC_FAIL_BACK_BUFFER blocks to go.
- // Also, ensure that, in the case of an unknown preimage for the received payment hash, our
- // payment logic has enough time to fail the HTLC backward before our onchain logic triggers a
- // channel closure (see HTLC_FAIL_BACK_BUFFER rationale).
- if (msg.cltv_expiry as u64) <= self.best_block.read().unwrap().height() as u64 + HTLC_FAIL_BACK_BUFFER as u64 + 1 {
- return_err!("The final CLTV expiry is too soon to handle", 17, &[0;0]);
- }
- // final_incorrect_htlc_amount
- if next_hop_data.amt_to_forward > msg.amount_msat {
- return_err!("Upstream node sent less than we were supposed to receive in payment", 19, &byte_utils::be64_to_array(msg.amount_msat));
- }
- // final_incorrect_cltv_expiry
- if next_hop_data.outgoing_cltv_value != msg.cltv_expiry {
- return_err!("Upstream node set CLTV to the wrong value", 18, &byte_utils::be32_to_array(msg.cltv_expiry));
- }
+ let pending_forward_info = match next_hop {
+ onion_utils::Hop::Receive(next_hop_data) => {
+ // OUR PAYMENT!
+ // final_expiry_too_soon
+ // We have to have some headroom to broadcast on chain if we have the preimage, so make sure
+ // we have at least HTLC_FAIL_BACK_BUFFER blocks to go.
+ // Also, ensure that, in the case of an unknown preimage for the received payment hash, our
+ // payment logic has enough time to fail the HTLC backward before our onchain logic triggers a
+ // channel closure (see HTLC_FAIL_BACK_BUFFER rationale).
+ if (msg.cltv_expiry as u64) <= self.best_block.read().unwrap().height() as u64 + HTLC_FAIL_BACK_BUFFER as u64 + 1 {
+ return_err!("The final CLTV expiry is too soon to handle", 17, &[0;0]);
+ }
+ // final_incorrect_htlc_amount
+ if next_hop_data.amt_to_forward > msg.amount_msat {
+ return_err!("Upstream node sent less than we were supposed to receive in payment", 19, &byte_utils::be64_to_array(msg.amount_msat));
+ }
+ // final_incorrect_cltv_expiry
+ if next_hop_data.outgoing_cltv_value != msg.cltv_expiry {
+ return_err!("Upstream node set CLTV to the wrong value", 18, &byte_utils::be32_to_array(msg.cltv_expiry));
+ }
- let routing = match next_hop_data.format {
- msgs::OnionHopDataFormat::Legacy { .. } => return_err!("We require payment_secrets", 0x4000|0x2000|3, &[0;0]),
- msgs::OnionHopDataFormat::NonFinalNode { .. } => return_err!("Got non final data with an HMAC of 0", 0x4000 | 22, &[0;0]),
- msgs::OnionHopDataFormat::FinalNode { payment_data, keysend_preimage } => {
- if payment_data.is_some() && keysend_preimage.is_some() {
- return_err!("We don't support MPP keysend payments", 0x4000|22, &[0;0]);
- } else if let Some(data) = payment_data {
- PendingHTLCRouting::Receive {
- payment_data: data,
- incoming_cltv_expiry: msg.cltv_expiry,
- }
- } else if let Some(payment_preimage) = keysend_preimage {
- // We need to check that the sender knows the keysend preimage before processing this
- // payment further. Otherwise, an intermediary routing hop forwarding non-keysend-HTLC X
- // could discover the final destination of X, by probing the adjacent nodes on the route
- // with a keysend payment of identical payment hash to X and observing the processing
- // time discrepancies due to a hash collision with X.
- let hashed_preimage = PaymentHash(Sha256::hash(&payment_preimage.0).into_inner());
- if hashed_preimage != msg.payment_hash {
- return_err!("Payment preimage didn't match payment hash", 0x4000|22, &[0;0]);
- }
+ let routing = match next_hop_data.format {
+ msgs::OnionHopDataFormat::Legacy { .. } => return_err!("We require payment_secrets", 0x4000|0x2000|3, &[0;0]),
+ msgs::OnionHopDataFormat::NonFinalNode { .. } => return_err!("Got non final data with an HMAC of 0", 0x4000 | 22, &[0;0]),
+ msgs::OnionHopDataFormat::FinalNode { payment_data, keysend_preimage } => {
+ if payment_data.is_some() && keysend_preimage.is_some() {
+ return_err!("We don't support MPP keysend payments", 0x4000|22, &[0;0]);
+ } else if let Some(data) = payment_data {
+ PendingHTLCRouting::Receive {
+ payment_data: data,
+ incoming_cltv_expiry: msg.cltv_expiry,
+ }
+ } else if let Some(payment_preimage) = keysend_preimage {
+ // We need to check that the sender knows the keysend preimage before processing this
+ // payment further. Otherwise, an intermediary routing hop forwarding non-keysend-HTLC X
+ // could discover the final destination of X, by probing the adjacent nodes on the route
+ // with a keysend payment of identical payment hash to X and observing the processing
+ // time discrepancies due to a hash collision with X.
+ let hashed_preimage = PaymentHash(Sha256::hash(&payment_preimage.0).into_inner());
+ if hashed_preimage != msg.payment_hash {
+ return_err!("Payment preimage didn't match payment hash", 0x4000|22, &[0;0]);
+ }
- PendingHTLCRouting::ReceiveKeysend {
- payment_preimage,
- incoming_cltv_expiry: msg.cltv_expiry,
+ PendingHTLCRouting::ReceiveKeysend {
+ payment_preimage,
+ incoming_cltv_expiry: msg.cltv_expiry,
+ }
+ } else {
+ return_err!("We require payment_secrets", 0x4000|0x2000|3, &[0;0]);
}
- } else {
- return_err!("We require payment_secrets", 0x4000|0x2000|3, &[0;0]);
- }
- },
- };
-
- // Note that we could obviously respond immediately with an update_fulfill_htlc
- // message, however that would leak that we are the recipient of this payment, so
- // instead we stay symmetric with the forwarding case, only responding (after a
- // delay) once they've send us a commitment_signed!
-
- PendingHTLCStatus::Forward(PendingHTLCInfo {
- routing,
- payment_hash: msg.payment_hash.clone(),
- incoming_shared_secret: shared_secret,
- amt_to_forward: next_hop_data.amt_to_forward,
- outgoing_cltv_value: next_hop_data.outgoing_cltv_value,
- })
- } else {
- let mut new_packet_data = [0; 20*65];
- let read_pos = chacha_stream.read(&mut new_packet_data).unwrap();
- #[cfg(debug_assertions)]
- {
- // Check two things:
- // a) that the behavior of our stream here will return Ok(0) even if the TLV
- // read above emptied out our buffer and the unwrap() wont needlessly panic
- // b) that we didn't somehow magically end up with extra data.
- let mut t = [0; 1];
- debug_assert!(chacha_stream.read(&mut t).unwrap() == 0);
- }
- // Once we've emptied the set of bytes our peer gave us, encrypt 0 bytes until we
- // fill the onion hop data we'll forward to our next-hop peer.
- chacha_stream.chacha.process_in_place(&mut new_packet_data[read_pos..]);
-
- let mut new_pubkey = msg.onion_routing_packet.public_key.unwrap();
+ },
+ };
- let blinding_factor = {
- let mut sha = Sha256::engine();
- sha.input(&new_pubkey.serialize()[..]);
- sha.input(&shared_secret);
- Sha256::from_engine(sha).into_inner()
- };
+ // Note that we could obviously respond immediately with an update_fulfill_htlc
+ // message, however that would leak that we are the recipient of this payment, so
+ // instead we stay symmetric with the forwarding case, only responding (after a
+ // delay) once they've send us a commitment_signed!
+
+ PendingHTLCStatus::Forward(PendingHTLCInfo {
+ routing,
+ payment_hash: msg.payment_hash.clone(),
+ incoming_shared_secret: shared_secret,
+ amt_to_forward: next_hop_data.amt_to_forward,
+ outgoing_cltv_value: next_hop_data.outgoing_cltv_value,
+ })
+ },
+ onion_utils::Hop::Forward { next_hop_data, next_hop_hmac, new_packet_bytes } => {
+ let mut new_pubkey = msg.onion_routing_packet.public_key.unwrap();
+
+ let blinding_factor = {
+ let mut sha = Sha256::engine();
+ sha.input(&new_pubkey.serialize()[..]);
+ sha.input(&shared_secret);
+ Sha256::from_engine(sha).into_inner()
+ };
- let public_key = if let Err(e) = new_pubkey.mul_assign(&self.secp_ctx, &blinding_factor[..]) {
- Err(e)
- } else { Ok(new_pubkey) };
+ let public_key = if let Err(e) = new_pubkey.mul_assign(&self.secp_ctx, &blinding_factor[..]) {
+ Err(e)
+ } else { Ok(new_pubkey) };
- let outgoing_packet = msgs::OnionPacket {
- version: 0,
- public_key,
- hop_data: new_packet_data,
- hmac: next_hop_hmac.clone(),
- };
+ let outgoing_packet = msgs::OnionPacket {
+ version: 0,
+ public_key,
+ hop_data: new_packet_bytes,
+ hmac: next_hop_hmac.clone(),
+ };
- let short_channel_id = match next_hop_data.format {
- msgs::OnionHopDataFormat::Legacy { short_channel_id } => short_channel_id,
- msgs::OnionHopDataFormat::NonFinalNode { short_channel_id } => short_channel_id,
- msgs::OnionHopDataFormat::FinalNode { .. } => {
- return_err!("Final Node OnionHopData provided for us as an intermediary node", 0x4000 | 22, &[0;0]);
- },
- };
+ let short_channel_id = match next_hop_data.format {
+ msgs::OnionHopDataFormat::Legacy { short_channel_id } => short_channel_id,
+ msgs::OnionHopDataFormat::NonFinalNode { short_channel_id } => short_channel_id,
+ msgs::OnionHopDataFormat::FinalNode { .. } => {
+ return_err!("Final Node OnionHopData provided for us as an intermediary node", 0x4000 | 22, &[0;0]);
+ },
+ };
- PendingHTLCStatus::Forward(PendingHTLCInfo {
- routing: PendingHTLCRouting::Forward {
- onion_packet: outgoing_packet,
- short_channel_id,
- },
- payment_hash: msg.payment_hash.clone(),
- incoming_shared_secret: shared_secret,
- amt_to_forward: next_hop_data.amt_to_forward,
- outgoing_cltv_value: next_hop_data.outgoing_cltv_value,
- })
+ PendingHTLCStatus::Forward(PendingHTLCInfo {
+ routing: PendingHTLCRouting::Forward {
+ onion_packet: outgoing_packet,
+ short_channel_id,
+ },
+ payment_hash: msg.payment_hash.clone(),
+ incoming_shared_secret: shared_secret,
+ amt_to_forward: next_hop_data.amt_to_forward,
+ outgoing_cltv_value: next_hop_data.outgoing_cltv_value,
+ })
+ }
};
channel_state = Some(self.channel_state.lock().unwrap());
})
}
- fn get_announcement_sigs(&self, chan: &Channel<Signer>) -> Option<msgs::AnnouncementSignatures> {
- if !chan.should_announce() {
- log_trace!(self.logger, "Can't send announcement_signatures for private channel {}", log_bytes!(chan.channel_id()));
- return None
- }
- chan.get_announcement_sigs(self.get_our_node_id(), self.genesis_hash.clone()).ok()
- }
-
#[allow(dead_code)]
// Messages of up to 64KB should never end up more than half full with addresses, as that would
// be absurd. We ensure this by checking that at least 500 (our stated public contract on when
let mut announced_chans = false;
for (_, chan) in channel_state.by_id.iter() {
- if let Some(msg) = chan.get_signed_channel_announcement(self.get_our_node_id(), self.genesis_hash.clone()) {
+ if let Some(msg) = chan.get_signed_channel_announcement(self.get_our_node_id(), self.genesis_hash.clone(), self.best_block.read().unwrap().height()) {
channel_state.pending_msg_events.push(events::MessageSendEvent::BroadcastChannelAnnouncement {
msg,
update_msg: match self.get_channel_update_for_broadcast(chan) {
return;
}
- let updates = channel.get_mut().monitor_updating_restored(&self.logger);
- let channel_update = if updates.funding_locked.is_some() && channel.get().is_usable() && !channel.get().should_announce() {
+ let updates = channel.get_mut().monitor_updating_restored(&self.logger, self.get_our_node_id(), self.genesis_hash, self.best_block.read().unwrap().height());
+ let channel_update = if updates.funding_locked.is_some() && channel.get().is_usable() {
// We only send a channel_update in the case where we are just now sending a
- // funding_locked and the channel is in a usable state. Further, we rely on the
- // normal announcement_signatures process to send a channel_update for public
- // channels, only generating a unicast channel_update if this is a private channel.
+ // funding_locked and the channel is in a usable state. We may re-send a
+ // channel_update later through the announcement_signatures process for public
+ // channels, but there's no reason not to just inform our counterparty of our fees
+ // now.
Some(events::MessageSendEvent::SendChannelUpdate {
node_id: channel.get().get_counterparty_node_id(),
msg: self.get_channel_update_for_unicast(channel.get()).unwrap(),
})
} else { None };
- chan_restoration_res = handle_chan_restoration_locked!(self, channel_lock, channel_state, channel, updates.raa, updates.commitment_update, updates.order, None, updates.accepted_htlcs, updates.funding_broadcastable, updates.funding_locked);
+ chan_restoration_res = handle_chan_restoration_locked!(self, channel_lock, channel_state, channel, updates.raa, updates.commitment_update, updates.order, None, updates.accepted_htlcs, updates.funding_broadcastable, updates.funding_locked, updates.announcement_sigs);
if let Some(upd) = channel_update {
channel_state.pending_msg_events.push(upd);
}
}
}
+ /// Called to accept a request to open a channel after [`Event::OpenChannelRequest`] has been
+ /// triggered.
+ ///
+ /// The `temporary_channel_id` parameter indicates which inbound channel should be accepted.
+ ///
+ /// [`Event::OpenChannelRequest`]: crate::util::events::Event::OpenChannelRequest
+ pub fn accept_inbound_channel(&self, temporary_channel_id: &[u8; 32]) -> Result<(), APIError> {
+ let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier);
+
+ let mut channel_state_lock = self.channel_state.lock().unwrap();
+ let channel_state = &mut *channel_state_lock;
+ match channel_state.by_id.entry(temporary_channel_id.clone()) {
+ hash_map::Entry::Occupied(mut channel) => {
+ if !channel.get().inbound_is_awaiting_accept() {
+ return Err(APIError::APIMisuseError { err: "The channel isn't currently awaiting to be accepted.".to_owned() });
+ }
+ channel_state.pending_msg_events.push(events::MessageSendEvent::SendAcceptChannel {
+ node_id: channel.get().get_counterparty_node_id(),
+ msg: channel.get_mut().accept_inbound_channel(),
+ });
+ }
+ hash_map::Entry::Vacant(_) => {
+ return Err(APIError::ChannelUnavailable { err: "Can't accept a channel that doesn't exist".to_owned() });
+ }
+ }
+ Ok(())
+ }
+
fn internal_open_channel(&self, counterparty_node_id: &PublicKey, their_features: InitFeatures, msg: &msgs::OpenChannel) -> Result<(), MsgHandleErrInternal> {
if msg.chain_hash != self.genesis_hash {
return Err(MsgHandleErrInternal::send_err_msg_no_close("Unknown genesis block hash".to_owned(), msg.temporary_channel_id.clone()));
return Err(MsgHandleErrInternal::send_err_msg_no_close("No inbound channels accepted".to_owned(), msg.temporary_channel_id.clone()));
}
- let channel = Channel::new_from_req(&self.fee_estimator, &self.keys_manager, counterparty_node_id.clone(),
+ let mut channel = Channel::new_from_req(&self.fee_estimator, &self.keys_manager, counterparty_node_id.clone(),
&their_features, msg, 0, &self.default_configuration, self.best_block.read().unwrap().height(), &self.logger)
.map_err(|e| MsgHandleErrInternal::from_chan_no_close(e, msg.temporary_channel_id))?;
let mut channel_state_lock = self.channel_state.lock().unwrap();
match channel_state.by_id.entry(channel.channel_id()) {
hash_map::Entry::Occupied(_) => return Err(MsgHandleErrInternal::send_err_msg_no_close("temporary_channel_id collision!".to_owned(), msg.temporary_channel_id.clone())),
hash_map::Entry::Vacant(entry) => {
- channel_state.pending_msg_events.push(events::MessageSendEvent::SendAcceptChannel {
- node_id: counterparty_node_id.clone(),
- msg: channel.get_accept_channel(),
- });
+ if !self.default_configuration.manually_accept_inbound_channels {
+ channel_state.pending_msg_events.push(events::MessageSendEvent::SendAcceptChannel {
+ node_id: counterparty_node_id.clone(),
+ msg: channel.accept_inbound_channel(),
+ });
+ } else {
+ let mut pending_events = self.pending_events.lock().unwrap();
+ pending_events.push(
+ events::Event::OpenChannelRequest {
+ temporary_channel_id: msg.temporary_channel_id.clone(),
+ counterparty_node_id: counterparty_node_id.clone(),
+ funding_satoshis: msg.funding_satoshis,
+ push_msat: msg.push_msat,
+ }
+ );
+ }
+
entry.insert(channel);
}
}
if chan.get().get_counterparty_node_id() != *counterparty_node_id {
return Err(MsgHandleErrInternal::send_err_msg_no_close("Got a message for a channel from the wrong node!".to_owned(), msg.temporary_channel_id));
}
- try_chan_entry!(self, chan.get_mut().accept_channel(&msg, &self.default_configuration, &their_features), channel_state, chan);
+ try_chan_entry!(self, chan.get_mut().accept_channel(&msg, &self.default_configuration.peer_channel_config_limits, &their_features), channel_state, chan);
(chan.get().get_value_satoshis(), chan.get().get_funding_redeemscript().to_v0_p2wsh(), chan.get().get_user_id())
},
hash_map::Entry::Vacant(_) => return Err(MsgHandleErrInternal::send_err_msg_no_close("Failed to find corresponding channel".to_owned(), msg.temporary_channel_id))
if chan.get().get_counterparty_node_id() != *counterparty_node_id {
return Err(MsgHandleErrInternal::send_err_msg_no_close("Got a message for a channel from the wrong node!".to_owned(), msg.channel_id));
}
- try_chan_entry!(self, chan.get_mut().funding_locked(&msg, &self.logger), channel_state, chan);
- if let Some(announcement_sigs) = self.get_announcement_sigs(chan.get()) {
- log_trace!(self.logger, "Sending announcement_signatures for {} in response to funding_locked", log_bytes!(chan.get().channel_id()));
- // If we see locking block before receiving remote funding_locked, we broadcast our
- // announcement_sigs at remote funding_locked reception. If we receive remote
- // funding_locked before seeing locking block, we broadcast our announcement_sigs at locking
- // block connection. We should guanrantee to broadcast announcement_sigs to our peer whatever
- // the order of the events but our peer may not receive it due to disconnection. The specs
- // lacking an acknowledgement for announcement_sigs we may have to re-send them at peer
- // connection in the future if simultaneous misses by both peers due to network/hardware
- // failures is an issue. Note, to achieve its goal, only one of the announcement_sigs needs
- // to be received, from then sigs are going to be flood to the whole network.
+ let announcement_sigs_opt = try_chan_entry!(self, chan.get_mut().funding_locked(&msg, self.get_our_node_id(),
+ self.genesis_hash.clone(), &self.best_block.read().unwrap(), &self.logger), channel_state, chan);
+ if let Some(announcement_sigs) = announcement_sigs_opt {
+ log_trace!(self.logger, "Sending announcement_signatures for channel {}", log_bytes!(chan.get().channel_id()));
channel_state.pending_msg_events.push(events::MessageSendEvent::SendAnnouncementSignatures {
node_id: counterparty_node_id.clone(),
msg: announcement_sigs,
});
} else if chan.get().is_usable() {
+ // If we're sending an announcement_signatures, we'll send the (public)
+ // channel_update after sending a channel_announcement when we receive our
+ // counterparty's announcement_signatures. Thus, we only bother to send a
+ // channel_update here if the channel is not public, i.e. we're not sending an
+ // announcement_signatures.
+ log_trace!(self.logger, "Sending private initial channel_update for our counterparty on channel {}", log_bytes!(chan.get().channel_id()));
channel_state.pending_msg_events.push(events::MessageSendEvent::SendChannelUpdate {
node_id: counterparty_node_id.clone(),
msg: self.get_channel_update_for_unicast(chan.get()).unwrap(),
}
channel_state.pending_msg_events.push(events::MessageSendEvent::BroadcastChannelAnnouncement {
- msg: try_chan_entry!(self, chan.get_mut().announcement_signatures(self.get_our_node_id(), self.genesis_hash.clone(), msg), channel_state, chan),
+ msg: try_chan_entry!(self, chan.get_mut().announcement_signatures(
+ self.get_our_node_id(), self.genesis_hash.clone(), self.best_block.read().unwrap().height(), msg), channel_state, chan),
// Note that announcement_signatures fails if the channel cannot be announced,
// so get_channel_update_for_broadcast will never fail by the time we get here.
update_msg: self.get_channel_update_for_broadcast(chan.get()).unwrap(),
// disconnect, so Channel's reestablish will never hand us any holding cell
// freed HTLCs to fail backwards. If in the future we no longer drop pending
// add-HTLCs on disconnect, we may be handed HTLCs to fail backwards here.
- let responses = try_chan_entry!(self, chan.get_mut().channel_reestablish(msg, &self.logger), channel_state, chan);
+ let responses = try_chan_entry!(self, chan.get_mut().channel_reestablish(
+ msg, &self.logger, self.our_network_pubkey.clone(), self.genesis_hash,
+ &*self.best_block.read().unwrap()), channel_state, chan);
let mut channel_update = None;
if let Some(msg) = responses.shutdown_msg {
channel_state.pending_msg_events.push(events::MessageSendEvent::SendShutdown {
let need_lnd_workaround = chan.get_mut().workaround_lnd_bug_4006.take();
chan_restoration_res = handle_chan_restoration_locked!(
self, channel_state_lock, channel_state, chan, responses.raa, responses.commitment_update, responses.order,
- responses.mon_update, Vec::new(), None, responses.funding_locked);
+ responses.mon_update, Vec::new(), None, responses.funding_locked, responses.announcement_sigs);
if let Some(upd) = channel_update {
channel_state.pending_msg_events.push(upd);
}
*best_block = BestBlock::new(header.prev_blockhash, new_height)
}
- self.do_chain_event(Some(new_height), |channel| channel.best_block_updated(new_height, header.time, &self.logger));
+ self.do_chain_event(Some(new_height), |channel| channel.best_block_updated(new_height, header.time, self.genesis_hash.clone(), self.get_our_node_id(), &self.logger));
}
}
log_trace!(self.logger, "{} transactions included in block {} at height {} provided", txdata.len(), block_hash, height);
let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier);
- self.do_chain_event(Some(height), |channel| channel.transactions_confirmed(&block_hash, height, txdata, &self.logger).map(|a| (a, Vec::new())));
+ self.do_chain_event(Some(height), |channel| channel.transactions_confirmed(&block_hash, height, txdata, self.genesis_hash.clone(), self.get_our_node_id(), &self.logger)
+ .map(|(a, b)| (a, Vec::new(), b)));
}
fn best_block_updated(&self, header: &BlockHeader, height: u32) {
*self.best_block.write().unwrap() = BestBlock::new(block_hash, height);
- self.do_chain_event(Some(height), |channel| channel.best_block_updated(height, header.time, &self.logger));
+ self.do_chain_event(Some(height), |channel| channel.best_block_updated(height, header.time, self.genesis_hash.clone(), self.get_our_node_id(), &self.logger));
macro_rules! max_time {
($timestamp: expr) => {
self.do_chain_event(None, |channel| {
if let Some(funding_txo) = channel.get_funding_txo() {
if funding_txo.txid == *txid {
- channel.funding_transaction_unconfirmed(&self.logger).map(|_| (None, Vec::new()))
- } else { Ok((None, Vec::new())) }
- } else { Ok((None, Vec::new())) }
+ channel.funding_transaction_unconfirmed(&self.logger).map(|()| (None, Vec::new(), None))
+ } else { Ok((None, Vec::new(), None)) }
+ } else { Ok((None, Vec::new(), None)) }
});
}
}
/// Calls a function which handles an on-chain event (blocks dis/connected, transactions
/// un/confirmed, etc) on each channel, handling any resulting errors or messages generated by
/// the function.
- fn do_chain_event<FN: Fn(&mut Channel<Signer>) -> Result<(Option<msgs::FundingLocked>, Vec<(HTLCSource, PaymentHash)>), ClosureReason>>
+ fn do_chain_event<FN: Fn(&mut Channel<Signer>) -> Result<(Option<msgs::FundingLocked>, Vec<(HTLCSource, PaymentHash)>, Option<msgs::AnnouncementSignatures>), ClosureReason>>
(&self, height_opt: Option<u32>, f: FN) {
// Note that we MUST NOT end up calling methods on self.chain_monitor here - we're called
// during initialization prior to the chain_monitor being fully configured in some cases.
let pending_msg_events = &mut channel_state.pending_msg_events;
channel_state.by_id.retain(|_, channel| {
let res = f(channel);
- if let Ok((chan_res, mut timed_out_pending_htlcs)) = res {
+ if let Ok((funding_locked_opt, mut timed_out_pending_htlcs, announcement_sigs)) = res {
for (source, payment_hash) in timed_out_pending_htlcs.drain(..) {
let chan_update = self.get_channel_update_for_unicast(&channel).map(|u| u.encode_with_len()).unwrap(); // Cannot add/recv HTLCs before we have a short_id so unwrap is safe
timed_out_htlcs.push((source, payment_hash, HTLCFailReason::Reason {
data: chan_update,
}));
}
- if let Some(funding_locked) = chan_res {
+ if let Some(funding_locked) = funding_locked_opt {
pending_msg_events.push(events::MessageSendEvent::SendFundingLocked {
node_id: channel.get_counterparty_node_id(),
msg: funding_locked,
});
- if let Some(announcement_sigs) = self.get_announcement_sigs(channel) {
- log_trace!(self.logger, "Sending funding_locked and announcement_signatures for {}", log_bytes!(channel.channel_id()));
- pending_msg_events.push(events::MessageSendEvent::SendAnnouncementSignatures {
- node_id: channel.get_counterparty_node_id(),
- msg: announcement_sigs,
- });
- } else if channel.is_usable() {
- log_trace!(self.logger, "Sending funding_locked WITHOUT announcement_signatures but with private channel_update for our counterparty on channel {}", log_bytes!(channel.channel_id()));
+ if channel.is_usable() {
+ log_trace!(self.logger, "Sending funding_locked with private initial channel_update for our counterparty on channel {}", log_bytes!(channel.channel_id()));
pending_msg_events.push(events::MessageSendEvent::SendChannelUpdate {
node_id: channel.get_counterparty_node_id(),
msg: self.get_channel_update_for_unicast(channel).unwrap(),
});
} else {
- log_trace!(self.logger, "Sending funding_locked WITHOUT announcement_signatures for {}", log_bytes!(channel.channel_id()));
+ log_trace!(self.logger, "Sending funding_locked WITHOUT channel_update for {}", log_bytes!(channel.channel_id()));
}
short_to_id.insert(channel.get_short_channel_id().unwrap(), channel.channel_id());
}
+ if let Some(announcement_sigs) = announcement_sigs {
+ log_trace!(self.logger, "Sending announcement_signatures for channel {}", log_bytes!(channel.channel_id()));
+ pending_msg_events.push(events::MessageSendEvent::SendAnnouncementSignatures {
+ node_id: channel.get_counterparty_node_id(),
+ msg: announcement_sigs,
+ });
+ if let Some(height) = height_opt {
+ if let Some(announcement) = channel.get_signed_channel_announcement(self.get_our_node_id(), self.genesis_hash, height) {
+ pending_msg_events.push(events::MessageSendEvent::BroadcastChannelAnnouncement {
+ msg: announcement,
+ // Note that announcement_signatures fails if the channel cannot be announced,
+ // so get_channel_update_for_broadcast will never fail by the time we get here.
+ update_msg: self.get_channel_update_for_broadcast(channel).unwrap(),
+ });
+ }
+ }
+ }
} else if let Err(reason) = res {
if let Some(short_id) = channel.get_short_channel_id() {
short_to_id.remove(&short_id);
const SERIALIZATION_VERSION: u8 = 1;
const MIN_SERIALIZATION_VERSION: u8 = 1;
+impl_writeable_tlv_based!(CounterpartyForwardingInfo, {
+ (2, fee_base_msat, required),
+ (4, fee_proportional_millionths, required),
+ (6, cltv_expiry_delta, required),
+});
+
+impl_writeable_tlv_based!(ChannelCounterparty, {
+ (2, node_id, required),
+ (4, features, required),
+ (6, unspendable_punishment_reserve, required),
+ (8, forwarding_info, option),
+});
+
+impl_writeable_tlv_based!(ChannelDetails, {
+ (2, channel_id, required),
+ (4, counterparty, required),
+ (6, funding_txo, option),
+ (8, short_channel_id, option),
+ (10, channel_value_satoshis, required),
+ (12, unspendable_punishment_reserve, option),
+ (14, user_channel_id, required),
+ (16, balance_msat, required),
+ (18, outbound_capacity_msat, required),
+ (20, inbound_capacity_msat, required),
+ (22, confirmations_required, option),
+ (24, force_close_spend_delay, option),
+ (26, is_outbound, required),
+ (28, is_funding_locked, required),
+ (30, is_usable, required),
+ (32, is_public, required),
+});
+
impl_writeable_tlv_based_enum!(PendingHTLCRouting,
(0, Forward) => {
(0, onion_packet, required),
pending_events_read.append(&mut channel_closures);
}
- let our_network_pubkey = PublicKey::from_secret_key(&secp_ctx, &args.keys_manager.get_node_secret());
+ let our_network_key = match args.keys_manager.get_node_secret(Recipient::Node) {
+ Ok(key) => key,
+ Err(()) => return Err(DecodeError::InvalidValue)
+ };
+ let our_network_pubkey = PublicKey::from_secret_key(&secp_ctx, &our_network_key);
if let Some(network_pubkey) = received_network_pubkey {
if network_pubkey != our_network_pubkey {
log_error!(args.logger, "Key that was generated does not match the existing key.");
pending_inbound_payments: Mutex::new(pending_inbound_payments),
pending_outbound_payments: Mutex::new(pending_outbound_payments.unwrap()),
- our_network_key: args.keys_manager.get_node_secret(),
+ our_network_key,
our_network_pubkey,
secp_ctx,
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
- let scorer = test_utils::TestScorer::with_fixed_penalty(0);
+ let scorer = test_utils::TestScorer::with_penalty(0);
// To start (1), send a regular payment but don't claim it.
let expected_route = [&nodes[1]];
};
let network_graph = nodes[0].network_graph;
let first_hops = nodes[0].node.list_usable_channels();
- let scorer = test_utils::TestScorer::with_fixed_penalty(0);
+ let scorer = test_utils::TestScorer::with_penalty(0);
let route = find_route(
&payer_pubkey, &route_params, network_graph, Some(&first_hops.iter().collect::<Vec<_>>()),
nodes[0].logger, &scorer
};
let network_graph = nodes[0].network_graph;
let first_hops = nodes[0].node.list_usable_channels();
- let scorer = test_utils::TestScorer::with_fixed_penalty(0);
+ let scorer = test_utils::TestScorer::with_penalty(0);
let route = find_route(
&payer_pubkey, &route_params, network_graph, Some(&first_hops.iter().collect::<Vec<_>>()),
nodes[0].logger, &scorer
}
}
-#[cfg(all(any(test, feature = "_test_utils"), feature = "unstable"))]
+#[cfg(all(any(test, feature = "_test_utils"), feature = "_bench_unstable"))]
pub mod bench {
use chain::Listen;
use chain::chainmonitor::{ChainMonitor, Persist};
use ln::msgs::{ChannelMessageHandler, Init};
use routing::network_graph::NetworkGraph;
use routing::router::{PaymentParameters, get_route};
- use routing::scoring::Scorer;
use util::test_utils;
use util::config::UserConfig;
use util::events::{Event, MessageSendEvent, MessageSendEventsProvider, PaymentPurpose};
let usable_channels = $node_a.list_usable_channels();
let payment_params = PaymentParameters::from_node_id($node_b.get_our_node_id())
.with_features(InvoiceFeatures::known());
- let scorer = Scorer::with_fixed_penalty(0);
+ let scorer = test_utils::TestScorer::with_penalty(0);
let route = get_route(&$node_a.get_our_node_id(), &payment_params, &dummy_graph,
Some(&usable_channels.iter().map(|r| r).collect::<Vec<_>>()), 10_000, TEST_FINAL_CLTV, &logger_a, &scorer).unwrap();