+//! The top-level channel management and payment tracking stuff lives here.
+//!
+//! The ChannelManager is the main chunk of logic implementing the lightning protocol and is
+//! responsible for tracking which channels are open, HTLCs are in flight and reestablishing those
+//! upon reconnect to the relevant peer(s).
+//!
+//! It does not manage routing logic (see ln::router for that) nor does it manage constructing
+//! on-chain transactions (it only monitors the chain to watch for any force-closes that might
+//! imply it needs to fail HTLCs/payments/channels it manages).
+
use bitcoin::blockdata::block::BlockHeader;
use bitcoin::blockdata::transaction::Transaction;
use bitcoin::blockdata::constants::genesis_block;
Fail(HTLCFailureMsg),
}
- #[cfg(feature = "fuzztarget")]
- impl PendingHTLCStatus {
- pub fn dummy() -> Self {
- let secp_ctx = ::secp256k1::Secp256k1::signing_only();
- PendingHTLCStatus::Forward(PendingForwardHTLCInfo {
- onion_packet: None,
- incoming_shared_secret: SharedSecret::new(&secp_ctx,
- &::secp256k1::key::PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&secp_ctx, &[1; 32]).unwrap()),
- &SecretKey::from_slice(&secp_ctx, &[1; 32]).unwrap()),
- payment_hash: [0; 32],
- short_channel_id: 0,
- amt_to_forward: 0,
- outgoing_cltv_value: 0,
- })
- }
- }
-
/// Tracks the inbound corresponding to an outbound HTLC
#[derive(Clone)]
pub struct HTLCPreviousHopData {
session_priv: SecretKey,
},
}
- #[cfg(any(test, feature = "fuzztarget"))]
+ #[cfg(test)]
impl HTLCSource {
pub fn dummy() -> Self {
HTLCSource::OutboundRoute {
}
#[derive(Clone)] // See Channel::revoke_and_ack for why, tl;dr: Rust bug
- pub enum HTLCFailReason {
+ pub(crate) enum HTLCFailReason {
ErrorPacket {
err: msgs::OnionErrorPacket,
},
data: Vec<u8>,
}
}
-
- #[cfg(feature = "fuzztarget")]
- impl HTLCFailReason {
- pub fn dummy() -> Self {
- HTLCFailReason::Reason {
- failure_code: 0, data: Vec::new(),
- }
- }
- }
}
-#[cfg(feature = "fuzztarget")]
-pub use self::channel_held_info::*;
-#[cfg(not(feature = "fuzztarget"))]
-pub(crate) use self::channel_held_info::*;
+pub(super) use self::channel_held_info::*;
struct MsgHandleErrInternal {
err: msgs::HandleError,
/// Manager which keeps track of a number of channels and sends messages to the appropriate
/// channel, also tracking HTLC preimages and forwarding onion packets appropriately.
+///
/// Implements ChannelMessageHandler, handling the multi-channel parts and passing things through
/// to individual Channels.
pub struct ChannelManager {
mu: [u8; 32],
}
+/// Details of a channel, as returned by ChannelManager::list_channels and ChannelManager::list_usable_channels
pub struct ChannelDetails {
/// The channel's ID (prior to funding transaction generation, this is a random 32 bytes,
/// thereafter this is the txid of the funding transaction xor the funding transaction output).
/// The position of the funding transaction in the chain. None if the funding transaction has
/// not yet been confirmed and the channel fully opened.
pub short_channel_id: Option<u64>,
+ /// The node_id of our counterparty
pub remote_network_id: PublicKey,
+ /// The value, in satoshis, of this channel as appears in the funding output
pub channel_value_satoshis: u64,
/// The user_id passed in to create_channel, or 0 if the channel was inbound.
pub user_id: u64,
}
impl ChannelManager {
- /// Constructs a new ChannelManager to hold several channels and route between them. This is
- /// the main "logic hub" for all channel-related actions, and implements ChannelMessageHandler.
+ /// Constructs a new ChannelManager to hold several channels and route between them.
+ ///
+ /// This is the main "logic hub" for all channel-related actions, and implements
+ /// ChannelMessageHandler.
+ ///
/// fee_proportional_millionths is an optional fee to charge any payments routed through us.
/// Non-proportional fees are fixed according to our risk using the provided fee estimator.
+ ///
/// panics if channel_value_satoshis is >= `MAX_FUNDING_SATOSHIS`!
pub fn new(our_network_key: SecretKey, fee_proportional_millionths: u32, announce_channels_publicly: bool, network: Network, feeest: Arc<FeeEstimator>, monitor: Arc<ManyChannelMonitor>, chain_monitor: Arc<ChainWatchInterface>, tx_broadcaster: Arc<BroadcasterInterface>, logger: Arc<Logger>) -> Result<Arc<ChannelManager>, secp256k1::Error> {
let secp_ctx = Secp256k1::new();
}
/// Creates a new outbound channel to the given remote node and with the given value.
+ ///
/// user_id will be provided back as user_channel_id in FundingGenerationReady and
/// FundingBroadcastSafe events to allow tracking of which events correspond with which
/// create_channel call. Note that user_channel_id defaults to 0 for inbound channels, so you
/// may wish to avoid using 0 for user_id here.
+ ///
/// If successful, will generate a SendOpenChannel event, so you should probably poll
/// PeerManager::process_events afterwards.
+ ///
/// Raises APIError::APIMisuseError when channel_value_satoshis > 2**24 or push_msat being greater than channel_value_satoshis * 1k
pub fn create_channel(&self, their_network_key: PublicKey, channel_value_satoshis: u64, push_msat: u64, user_id: u64) -> Result<(), APIError> {
let chan_keys = if cfg!(feature = "fuzztarget") {
let channel = Channel::new_outbound(&*self.fee_estimator, chan_keys, their_network_key, channel_value_satoshis, push_msat, self.announce_channels_publicly, user_id, Arc::clone(&self.logger))?;
let res = channel.get_open_channel(self.genesis_hash.clone(), &*self.fee_estimator);
let mut channel_state = self.channel_state.lock().unwrap();
- match channel_state.by_id.insert(channel.channel_id(), channel) {
- Some(_) => panic!("RNG is bad???"),
- None => {}
+ match channel_state.by_id.entry(channel.channel_id()) {
+ hash_map::Entry::Occupied(_) => {
+ if cfg!(feature = "fuzztarget") {
+ return Err(APIError::APIMisuseError { err: "Fuzzy bad RNG" });
+ } else {
+ panic!("RNG is bad???");
+ }
+ },
+ hash_map::Entry::Vacant(entry) => { entry.insert(channel); }
}
let mut events = self.pending_events.lock().unwrap();
/// Begins the process of closing a channel. After this call (plus some timeout), no new HTLCs
/// will be accepted on the given channel, and after additional timeout/the closing of all
/// pending HTLCs, the channel will be closed on chain.
+ ///
/// May generate a SendShutdown event on success, which should be relayed.
pub fn close_channel(&self, channel_id: &[u8; 32]) -> Result<(), HandleError> {
let (mut res, node_id, chan_option) = {
match msgs::OnionHopData::read(&mut Cursor::new(&decoded[..])) {
Err(err) => {
let error_code = match err {
- msgs::DecodeError::UnknownRealmByte => 0x4000 | 1,
+ msgs::DecodeError::UnknownVersion => 0x4000 | 1, // unknown realm byte
_ => 0x2000 | 2, // Should never happen
};
return_err!("Unable to decode our hop data", error_code, &[0;0]);
}
/// Sends a payment along a given route.
+ ///
/// Value parameters are provided via the last hop in route, see documentation for RouteHop
/// fields for more info.
+ ///
/// Note that if the payment_hash already exists elsewhere (eg you're sending a duplicative
/// payment), we don't do anything to stop you! We always try to ensure that if the provided
/// next hop knows the preimage to payment_hash they can claim an additional amount as
/// specified in the last hop in the route! Thus, you should probably do your own
/// payment_preimage tracking (which you should already be doing as they represent "proof of
/// payment") and prevent double-sends yourself.
- /// See-also docs on Channel::send_htlc_and_commit.
+ ///
/// May generate a SendHTLCs event on success, which should be relayed.
+ ///
/// Raises APIError::RoutError when invalid route or forward parameter
/// (cltv_delta, fee, node public key) is specified
pub fn send_payment(&self, route: Route, payment_hash: [u8; 32]) -> Result<(), APIError> {
}
/// Call this upon creation of a funding transaction for the given channel.
+ ///
/// Panics if a funding transaction has already been provided for this channel.
+ ///
/// May panic if the funding_txo is duplicative with some other channel (note that this should
/// be trivially prevented by using unique funding transaction keys per-channel).
pub fn funding_transaction_generated(&self, temporary_channel_id: &[u8; 32], funding_txo: OutPoint) {
}
/// Processes HTLCs which are pending waiting on random forward delay.
+ ///
/// Should only really ever be called in response to an PendingHTLCsForwardable event.
/// Will likely generate further events.
pub fn process_pending_htlc_forwards(&self) {
/// Provides a payment preimage in response to a PaymentReceived event, returning true and
/// generating message events for the net layer to claim the payment, if possible. Thus, you
/// should probably kick the net layer to go send messages if this returns true!
+ ///
/// May panic if called except in response to a PaymentReceived event.
pub fn claim_funds(&self, payment_preimage: [u8; 32]) -> bool {
let mut sha = Sha256::new();
}
impl Drop for Node {
fn drop(&mut self) {
- // Check that we processed all pending events
- assert_eq!(self.node.get_and_clear_pending_events().len(), 0);
- assert_eq!(self.chan_monitor.added_monitors.lock().unwrap().len(), 0);
+ if !::std::thread::panicking() {
+ // Check that we processed all pending events
+ assert_eq!(self.node.get_and_clear_pending_events().len(), 0);
+ assert_eq!(self.chan_monitor.added_monitors.lock().unwrap().len(), 0);
+ }
}
}
}
}
+ macro_rules! check_added_monitors {
+ ($node: expr, $count: expr) => {
+ {
+ let mut added_monitors = $node.chan_monitor.added_monitors.lock().unwrap();
+ assert_eq!(added_monitors.len(), $count);
+ added_monitors.clear();
+ }
+ }
+ }
+
macro_rules! commitment_signed_dance {
($node_a: expr, $node_b: expr, $commitment_signed: expr, $fail_backwards: expr) => {
{
- {
- let added_monitors = $node_a.chan_monitor.added_monitors.lock().unwrap();
- assert!(added_monitors.is_empty());
- }
+ check_added_monitors!($node_a, 0);
let (as_revoke_and_ack, as_commitment_signed) = $node_a.node.handle_commitment_signed(&$node_b.node.get_our_node_id(), &$commitment_signed).unwrap();
- {
- let mut added_monitors = $node_a.chan_monitor.added_monitors.lock().unwrap();
- assert_eq!(added_monitors.len(), 1);
- added_monitors.clear();
- }
- {
- let added_monitors = $node_b.chan_monitor.added_monitors.lock().unwrap();
- assert!(added_monitors.is_empty());
- }
+ check_added_monitors!($node_a, 1);
+ check_added_monitors!($node_b, 0);
assert!($node_b.node.handle_revoke_and_ack(&$node_a.node.get_our_node_id(), &as_revoke_and_ack).unwrap().is_none());
- {
- let mut added_monitors = $node_b.chan_monitor.added_monitors.lock().unwrap();
- assert_eq!(added_monitors.len(), 1);
- added_monitors.clear();
- }
+ check_added_monitors!($node_b, 1);
let (bs_revoke_and_ack, bs_none) = $node_b.node.handle_commitment_signed(&$node_a.node.get_our_node_id(), &as_commitment_signed.unwrap()).unwrap();
assert!(bs_none.is_none());
- {
- let mut added_monitors = $node_b.chan_monitor.added_monitors.lock().unwrap();
- assert_eq!(added_monitors.len(), 1);
- added_monitors.clear();
- }
+ check_added_monitors!($node_b, 1);
if $fail_backwards {
assert!($node_a.node.get_and_clear_pending_events().is_empty());
}
}
}
+ macro_rules! get_payment_preimage_hash {
+ ($node: expr) => {
+ {
+ let payment_preimage = [*$node.network_payment_count.borrow(); 32];
+ *$node.network_payment_count.borrow_mut() += 1;
+ let mut payment_hash = [0; 32];
+ let mut sha = Sha256::new();
+ sha.input(&payment_preimage[..]);
+ sha.result(&mut payment_hash);
+ (payment_preimage, payment_hash)
+ }
+ }
+ }
+
fn send_along_route(origin_node: &Node, route: Route, expected_route: &[&Node], recv_value: u64) -> ([u8; 32], [u8; 32]) {
- let our_payment_preimage = [*origin_node.network_payment_count.borrow(); 32];
- *origin_node.network_payment_count.borrow_mut() += 1;
- let our_payment_hash = {
- let mut sha = Sha256::new();
- sha.input(&our_payment_preimage[..]);
- let mut ret = [0; 32];
- sha.result(&mut ret);
- ret
- };
+ let (our_payment_preimage, our_payment_hash) = get_payment_preimage_hash!(origin_node);
let mut payment_event = {
origin_node.node.send_payment(route, our_payment_hash).unwrap();
- {
- let mut added_monitors = origin_node.chan_monitor.added_monitors.lock().unwrap();
- assert_eq!(added_monitors.len(), 1);
- added_monitors.clear();
- }
+ check_added_monitors!(origin_node, 1);
let mut events = origin_node.node.get_and_clear_pending_events();
assert_eq!(events.len(), 1);
assert_eq!(node.node.get_our_node_id(), payment_event.node_id);
node.node.handle_update_add_htlc(&prev_node.node.get_our_node_id(), &payment_event.msgs[0]).unwrap();
- {
- let added_monitors = node.chan_monitor.added_monitors.lock().unwrap();
- assert_eq!(added_monitors.len(), 0);
- }
-
+ check_added_monitors!(node, 0);
commitment_signed_dance!(node, prev_node, payment_event.commitment_msg, false);
let events_1 = node.node.get_and_clear_pending_events();
_ => panic!("Unexpected event"),
}
} else {
- {
- let mut added_monitors = node.chan_monitor.added_monitors.lock().unwrap();
- assert_eq!(added_monitors.len(), 1);
- added_monitors.clear();
- }
+ check_added_monitors!(node, 1);
payment_event = SendEvent::from_event(events_2.remove(0));
assert_eq!(payment_event.msgs.len(), 1);
}
fn claim_payment_along_route(origin_node: &Node, expected_route: &[&Node], skip_last: bool, our_payment_preimage: [u8; 32]) {
assert!(expected_route.last().unwrap().node.claim_funds(our_payment_preimage));
- {
- let mut added_monitors = expected_route.last().unwrap().chan_monitor.added_monitors.lock().unwrap();
- assert_eq!(added_monitors.len(), 1);
- added_monitors.clear();
- }
+ check_added_monitors!(expected_route.last().unwrap(), 1);
let mut next_msgs: Option<(msgs::UpdateFulfillHTLC, msgs::CommitmentSigned)> = None;
macro_rules! update_fulfill_dance {
($node: expr, $prev_node: expr, $last_node: expr) => {
{
$node.node.handle_update_fulfill_htlc(&$prev_node.node.get_our_node_id(), &next_msgs.as_ref().unwrap().0).unwrap();
- {
- let mut added_monitors = $node.chan_monitor.added_monitors.lock().unwrap();
- if $last_node {
- assert_eq!(added_monitors.len(), 0);
- } else {
- assert_eq!(added_monitors.len(), 1);
- }
- added_monitors.clear();
+ if $last_node {
+ check_added_monitors!($node, 0);
+ } else {
+ check_added_monitors!($node, 1);
}
commitment_signed_dance!($node, $prev_node, next_msgs.as_ref().unwrap().1, false);
}
assert_eq!(hop.pubkey, node.node.get_our_node_id());
}
- let our_payment_preimage = [*origin_node.network_payment_count.borrow(); 32];
- *origin_node.network_payment_count.borrow_mut() += 1;
- let our_payment_hash = {
- let mut sha = Sha256::new();
- sha.input(&our_payment_preimage[..]);
- let mut ret = [0; 32];
- sha.result(&mut ret);
- ret
- };
+ let (_, our_payment_hash) = get_payment_preimage_hash!(origin_node);
let err = origin_node.node.send_payment(route, our_payment_hash).err().unwrap();
match err {
fn fail_payment_along_route(origin_node: &Node, expected_route: &[&Node], skip_last: bool, our_payment_hash: [u8; 32]) {
assert!(expected_route.last().unwrap().node.fail_htlc_backwards(&our_payment_hash));
- {
- let mut added_monitors = expected_route.last().unwrap().chan_monitor.added_monitors.lock().unwrap();
- assert_eq!(added_monitors.len(), 1);
- added_monitors.clear();
- }
+ check_added_monitors!(expected_route.last().unwrap(), 1);
let mut next_msgs: Option<(msgs::UpdateFailHTLC, msgs::CommitmentSigned)> = None;
macro_rules! update_fail_dance {
($node: expr, $prev_node: expr, $preimage: expr) => {
{
assert!($node.node.claim_funds($preimage));
- {
- let mut added_monitors = $node.chan_monitor.added_monitors.lock().unwrap();
- assert_eq!(added_monitors.len(), 1);
- added_monitors.clear();
- }
+ check_added_monitors!($node, 1);
let events = $node.node.get_and_clear_pending_events();
assert_eq!(events.len(), 1);
let route = nodes[0].router.get_route(&nodes[2].node.get_our_node_id(), None, &Vec::new(), 1000000, 42).unwrap();
- let our_payment_preimage = [*nodes[0].network_payment_count.borrow(); 32];
- *nodes[0].network_payment_count.borrow_mut() += 1;
- let our_payment_hash = {
- let mut sha = Sha256::new();
- sha.input(&our_payment_preimage[..]);
- let mut ret = [0; 32];
- sha.result(&mut ret);
- ret
- };
+ let (our_payment_preimage, our_payment_hash) = get_payment_preimage_hash!(nodes[0]);
let mut payment_event = {
nodes[0].node.send_payment(route, our_payment_hash).unwrap();
- {
- let mut added_monitors = nodes[0].chan_monitor.added_monitors.lock().unwrap();
- assert_eq!(added_monitors.len(), 1);
- added_monitors.clear();
- }
+ check_added_monitors!(nodes[0], 1);
let mut events = nodes[0].node.get_and_clear_pending_events();
assert_eq!(events.len(), 1);
payment_event = SendEvent::from_event(events_2.remove(0));
assert_eq!(payment_event.msgs.len(), 1);
- {
- let mut added_monitors = nodes[1].chan_monitor.added_monitors.lock().unwrap();
- assert_eq!(added_monitors.len(), 1);
- added_monitors.clear();
- }
-
+ check_added_monitors!(nodes[1], 1);
nodes[2].node.handle_update_add_htlc(&nodes[1].node.get_our_node_id(), &payment_event.msgs[0]).unwrap();
nodes[2].node.handle_commitment_signed(&nodes[1].node.get_our_node_id(), &payment_event.commitment_msg).unwrap();
-
- {
- let mut added_monitors = nodes[2].chan_monitor.added_monitors.lock().unwrap();
- assert_eq!(added_monitors.len(), 1);
- added_monitors.clear();
- }
+ check_added_monitors!(nodes[2], 1);
// nodes[2] now has the latest commitment transaction, but hasn't revoked its previous
// state or updated nodes[1]' state. Now force-close and broadcast that commitment/HTLC
for msg in reestablish_1 {
resp_1.push(node_b.node.handle_channel_reestablish(&node_a.node.get_our_node_id(), &msg).unwrap());
}
- {
- let mut added_monitors = node_b.chan_monitor.added_monitors.lock().unwrap();
- if pending_htlc_claims.0 != 0 || pending_htlc_fails.0 != 0 {
- assert_eq!(added_monitors.len(), 1);
- } else {
- assert!(added_monitors.is_empty());
- }
- added_monitors.clear();
+ if pending_htlc_claims.0 != 0 || pending_htlc_fails.0 != 0 {
+ check_added_monitors!(node_b, 1);
+ } else {
+ check_added_monitors!(node_b, 0);
}
let mut resp_2 = Vec::new();
for msg in reestablish_2 {
resp_2.push(node_a.node.handle_channel_reestablish(&node_b.node.get_our_node_id(), &msg).unwrap());
}
- {
- let mut added_monitors = node_a.chan_monitor.added_monitors.lock().unwrap();
- if pending_htlc_claims.1 != 0 || pending_htlc_fails.1 != 0 {
- assert_eq!(added_monitors.len(), 1);
- } else {
- assert!(added_monitors.is_empty());
- }
- added_monitors.clear();
+ if pending_htlc_claims.1 != 0 || pending_htlc_fails.1 != 0 {
+ check_added_monitors!(node_a, 1);
+ } else {
+ check_added_monitors!(node_a, 0);
}
// We dont yet support both needing updates, as that would require a different commitment dance: