X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=src%2Fln%2Fchannel.rs;h=44875fcd698089c4d8e9966b195c105fb1eebfb8;hb=4ca5bcf8cfc5cb3868974028b23ab7829c21426b;hp=fe1cfd24a25d74ce890ee6336a1311539af1a365;hpb=2018782d119219d9dbde3b993e165b687c3ec268;p=rust-lightning diff --git a/src/ln/channel.rs b/src/ln/channel.rs index fe1cfd24..44875fcd 100644 --- a/src/ln/channel.rs +++ b/src/ln/channel.rs @@ -2,7 +2,6 @@ use bitcoin::blockdata::block::BlockHeader; use bitcoin::blockdata::script::{Script,Builder}; use bitcoin::blockdata::transaction::{TxIn, TxOut, Transaction, SigHashType}; use bitcoin::blockdata::opcodes; -use bitcoin::util::uint::Uint256; use bitcoin::util::hash::{Sha256dHash, Hash160}; use bitcoin::util::bip143; use bitcoin::network::serialize::BitcoinHash; @@ -15,18 +14,23 @@ use crypto::digest::Digest; use crypto::hkdf::{hkdf_extract,hkdf_expand}; use ln::msgs; -use ln::msgs::{HandleError, MsgEncodable}; +use ln::msgs::{ErrorAction, HandleError, MsgEncodable}; use ln::channelmonitor::ChannelMonitor; -use ln::channelmanager::PendingForwardHTLCInfo; -use ln::chan_utils::{TxCreationKeys,HTLCOutputInCommitment}; +use ln::channelmanager::{PendingHTLCStatus, PendingForwardHTLCInfo, HTLCFailReason, HTLCFailureMsg}; +use ln::chan_utils::{TxCreationKeys,HTLCOutputInCommitment,HTLC_SUCCESS_TX_WEIGHT,HTLC_TIMEOUT_TX_WEIGHT}; use ln::chan_utils; use chain::chaininterface::{FeeEstimator,ConfirmationTarget}; +use chain::transaction::OutPoint; use util::{transaction_utils,rng}; use util::sha2::Sha256; +use util::logger::Logger; +use util::errors::APIError; +use std; use std::default::Default; -use std::cmp; +use std::{cmp,mem}; use std::time::Instant; +use std::sync::{Arc}; pub struct ChannelKeys { pub funding_key: SecretKey, @@ -43,7 +47,7 @@ impl ChannelKeys { pub fn new_from_seed(seed: &[u8; 32]) -> Result { let mut prk = [0; 32]; hkdf_extract(Sha256::new(), b"rust-lightning key gen salt", seed, &mut prk); - let secp_ctx = Secp256k1::new(); + let secp_ctx = Secp256k1::without_caps(); let mut okm = [0; 32]; hkdf_expand(Sha256::new(), &prk, b"rust-lightning funding key info", &mut okm); @@ -84,20 +88,83 @@ impl ChannelKeys { #[derive(PartialEq)] enum HTLCState { + /// Added by remote, to be included in next local commitment tx. + /// Implies HTLCOutput::outbound: false RemoteAnnounced, + /// Included in a received commitment_signed message (implying we've revoke_and_ack'ed it), but + /// the remote side hasn't yet revoked their previous state, which we need them to do before we + /// accept this HTLC. Implies AwaitingRemoteRevoke. + /// We also have not yet included this HTLC in a commitment_signed message, and are waiting on + /// a remote revoke_and_ack on a previous state before we can do so. + /// Implies HTLCOutput::outbound: false + AwaitingRemoteRevokeToAnnounce, + /// Included in a received commitment_signed message (implying we've revoke_and_ack'ed it), but + /// the remote side hasn't yet revoked their previous state, which we need them to do before we + /// accept this HTLC. Implies AwaitingRemoteRevoke. + /// We have included this HTLC in our latest commitment_signed and are now just waiting on a + /// revoke_and_ack. + /// Implies HTLCOutput::outbound: true + AwaitingAnnouncedRemoteRevoke, + /// Added by us and included in a commitment_signed (if we were AwaitingRemoteRevoke when we + /// created it we would have put it in the holding cell instead). When they next revoke_and_ack + /// we will promote to Committed (note that they may not accept it until the next time we + /// revoke, but we dont really care about that: + /// * they've revoked, so worst case we can announce an old state and get our (option on) + /// money back (though we wont), and, + /// * we'll send them a revoke when they send a commitment_signed, and since only they're + /// allowed to remove it, the "can only be removed once committed on both sides" requirement + /// doesn't matter to us and its up to them to enforce it, worst-case they jump ahead but + /// we'll never get out of sync). + /// Implies HTLCOutput::outbound: true LocalAnnounced, Committed, + /// Remote removed this (outbound) HTLC. We're waiting on their commitment_signed to finalize + /// the change (though they'll need to revoke before we fail the payment). + /// Implies HTLCOutput::outbound: true + RemoteRemoved, + /// Remote removed this and sent a commitment_signed (implying we've revoke_and_ack'ed it), but + /// the remote side hasn't yet revoked their previous state, which we need them to do before we + /// can do any backwards failing. Implies AwaitingRemoteRevoke. + /// We also have not yet removed this HTLC in a commitment_signed message, and are waiting on a + /// remote revoke_and_ack on a previous state before we can do so. + /// Implies HTLCOutput::outbound: true + AwaitingRemoteRevokeToRemove, + /// Remote removed this and sent a commitment_signed (implying we've revoke_and_ack'ed it), but + /// the remote side hasn't yet revoked their previous state, which we need them to do before we + /// can do any backwards failing. Implies AwaitingRemoteRevoke. + /// We have removed this HTLC in our latest commitment_signed and are now just waiting on a + /// revoke_and_ack to drop completely. + /// Implies HTLCOutput::outbound: true + AwaitingRemovedRemoteRevoke, + /// Removed by us and a new commitment_signed was sent (if we were AwaitingRemoteRevoke when we + /// created it we would have put it in the holding cell instead). When they next revoke_and_ack + /// we'll promote to LocalRemovedAwaitingCommitment if we fulfilled, otherwise we'll drop at + /// that point. + /// Note that we have to keep an eye on the HTLC until we've received a broadcastable + /// commitment transaction without it as otherwise we'll have to force-close the channel to + /// claim it before the timeout (obviously doesn't apply to revoked HTLCs that we can't claim + /// anyway). + /// Implies HTLCOutput::outbound: false + LocalRemoved, + /// Removed by us, sent a new commitment_signed and got a revoke_and_ack. Just waiting on an + /// updated local commitment transaction. Implies local_removed_fulfilled. + /// Implies HTLCOutput::outbound: false + LocalRemovedAwaitingCommitment, } -struct HTLCOutput { +struct HTLCOutput { //TODO: Refactor into Outbound/InboundHTLCOutput (will save memory and fewer panics) outbound: bool, // ie to an HTLC-Timeout transaction htlc_id: u64, amount_msat: u64, cltv_expiry: u32, payment_hash: [u8; 32], state: HTLCState, - // state == RemoteAnnounced implies pending_forward_state, otherwise it must be None - pending_forward_state: Option, + /// If we're in a Remote* removed state, set if they failed, otherwise None + fail_reason: Option, + /// If we're in LocalRemoved*, set to true if we fulfilled the HTLC, and can claim money + local_removed_fulfilled: bool, + /// state pre-committed Remote* implies pending_forward_state, otherwise it must be None + pending_forward_state: Option, } impl HTLCOutput { @@ -113,13 +180,23 @@ impl HTLCOutput { } /// See AwaitingRemoteRevoke ChannelState for more info -struct HTLCOutputAwaitingACK { - // always outbound - amount_msat: u64, - cltv_expiry: u32, - payment_hash: [u8; 32], - onion_routing_packet: msgs::OnionPacket, - time_created: Instant, //TODO: Some kind of timeout thing-a-majig +enum HTLCUpdateAwaitingACK { + AddHTLC { + // always outbound + amount_msat: u64, + cltv_expiry: u32, + payment_hash: [u8; 32], + onion_routing_packet: msgs::OnionPacket, + time_created: Instant, //TODO: Some kind of timeout thing-a-majig + }, + ClaimHTLC { + payment_preimage: [u8; 32], + payment_hash: [u8; 32], // Only here for effecient duplicate detection + }, + FailHTLC { + payment_hash: [u8; 32], + err_packet: msgs::OnionErrorPacket, + }, } enum ChannelState { @@ -149,39 +226,64 @@ enum ChannelState { /// later. /// Flag is set on ChannelFunded. AwaitingRemoteRevoke = (1 << 7), + /// Flag which is set on ChannelFunded or FundingSent after receiving a shutdown message from + /// the remote end. If set, they may not add any new HTLCs to the channel, and we are expected + /// to respond with our own shutdown message when possible. + RemoteShutdownSent = (1 << 8), + /// Flag which is set on ChannelFunded or FundingSent after sending a shutdown message. At this + /// point, we may not add any new HTLCs to the channel. + /// TODO: Investigate some kind of timeout mechanism by which point the remote end must provide + /// us their shutdown. + LocalShutdownSent = (1 << 9), + /// We've successfully negotiated a closing_signed dance. At this point ChannelManager is about + /// to drop us, but we store this anyway. + ShutdownComplete = (1 << 10), } +const BOTH_SIDES_SHUTDOWN_MASK: u32 = (ChannelState::LocalShutdownSent as u32 | ChannelState::RemoteShutdownSent as u32); // TODO: We should refactor this to be an Inbound/OutboundChannel until initial setup handshaking // has been completed, and then turn into a Channel to get compiler-time enforcement of things like -// calling get_channel_id() before we're set up or things like get_outbound_funding_signed on an +// calling channel_id() before we're set up or things like get_outbound_funding_signed on an // inbound channel. pub struct Channel { user_id: u64, - channel_id: Uint256, + channel_id: [u8; 32], channel_state: u32, channel_outbound: bool, - secp_ctx: Secp256k1, + secp_ctx: Secp256k1, announce_publicly: bool, channel_value_satoshis: u64, local_keys: ChannelKeys, + // Our commitment numbers start at 2^48-1 and count down, whereas the ones used in transaction + // generation start at 0 and count up...this simplifies some parts of implementation at the + // cost of others, but should really just be changed. + cur_local_commitment_transaction_number: u64, cur_remote_commitment_transaction_number: u64, value_to_self_msat: u64, // Excluding all pending_htlcs, excluding fees pending_htlcs: Vec, - holding_cell_htlcs: Vec, + holding_cell_htlc_updates: Vec, next_local_htlc_id: u64, next_remote_htlc_id: u64, channel_update_count: u32, feerate_per_kw: u64, + #[cfg(test)] + // Used in ChannelManager's tests to send a revoked transaction + pub last_local_commitment_txn: Vec, + #[cfg(not(test))] + last_local_commitment_txn: Vec, + + last_sent_closing_fee: Option<(u64, u64)>, // (feerate, fee) + /// The hash of the block in which the funding transaction reached our CONF_TARGET. We use this /// to detect unconfirmation after a serialize-unserialize roudtrip where we may not see a full /// series of block_connected/block_disconnected calls. Obviously this is not a guarantee as we /// could miss the funding_tx_confirmed_in block as well, but it serves as a useful fallback. - funding_tx_confirmed_in: Sha256dHash, + funding_tx_confirmed_in: Option, short_channel_id: Option, /// Used to deduplicate block_connected callbacks last_block_connected: Sha256dHash, @@ -200,19 +302,24 @@ pub struct Channel { their_max_accepted_htlcs: u16, //implied by OUR_MAX_HTLCS: our_max_accepted_htlcs: u16, - their_funding_pubkey: PublicKey, - their_revocation_basepoint: PublicKey, - their_payment_basepoint: PublicKey, - their_delayed_payment_basepoint: PublicKey, - their_htlc_basepoint: PublicKey, - their_cur_commitment_point: PublicKey, + their_funding_pubkey: Option, + their_revocation_basepoint: Option, + their_payment_basepoint: Option, + their_delayed_payment_basepoint: Option, + their_htlc_basepoint: Option, + their_cur_commitment_point: Option, + + their_prev_commitment_point: Option, their_node_id: PublicKey, + their_shutdown_scriptpubkey: Option