X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=src%2Fln%2Fchannel.rs;h=0af02e9c8c33ef456cfa9cd4ba22f54b35649e80;hb=89d9f8fb0ed513238cfb49549a6285327e27753f;hp=285cdf7b418a888033438e9ad33e86d792eb88a6;hpb=24e2234be53bc8ca3e325002790b9f3f8115f7a8;p=rust-lightning diff --git a/src/ln/channel.rs b/src/ln/channel.rs index 285cdf7b..0af02e9c 100644 --- a/src/ln/channel.rs +++ b/src/ln/channel.rs @@ -7,15 +7,12 @@ use bitcoin::util::hash::{Sha256dHash, Hash160}; use bitcoin::util::bip143; use bitcoin::network::serialize::BitcoinHash; -use num::FromPrimitive; - use secp256k1::key::{PublicKey,SecretKey}; use secp256k1::{Secp256k1,Message,Signature}; use secp256k1; use crypto::digest::Digest; use crypto::hkdf::{hkdf_extract,hkdf_expand}; -use crypto::sha2::Sha256; use ln::msgs; use ln::msgs::{HandleError, MsgEncodable}; @@ -24,9 +21,8 @@ use ln::channelmanager::PendingForwardHTLCInfo; use ln::chan_utils::{TxCreationKeys,HTLCOutputInCommitment}; use ln::chan_utils; use chain::chaininterface::{FeeEstimator,ConfirmationTarget}; -use util::transaction_utils; - -use rand::{thread_rng,Rng}; +use util::{transaction_utils,rng}; +use util::sha2::Sha256; use std::default::Default; use std::cmp; @@ -45,34 +41,33 @@ pub struct ChannelKeys { impl ChannelKeys { pub fn new_from_seed(seed: &[u8; 32]) -> Result { - let sha = Sha256::new(); let mut prk = [0; 32]; - hkdf_extract(sha, b"rust-lightning key gen salt", seed, &mut prk); + hkdf_extract(Sha256::new(), b"rust-lightning key gen salt", seed, &mut prk); let secp_ctx = Secp256k1::new(); let mut okm = [0; 32]; - hkdf_expand(sha, &prk, b"rust-lightning funding key info", &mut okm); - let funding_key = try!(SecretKey::from_slice(&secp_ctx, &okm)); + hkdf_expand(Sha256::new(), &prk, b"rust-lightning funding key info", &mut okm); + let funding_key = SecretKey::from_slice(&secp_ctx, &okm)?; - hkdf_expand(sha, &prk, b"rust-lightning revocation base key info", &mut okm); - let revocation_base_key = try!(SecretKey::from_slice(&secp_ctx, &okm)); + hkdf_expand(Sha256::new(), &prk, b"rust-lightning revocation base key info", &mut okm); + let revocation_base_key = SecretKey::from_slice(&secp_ctx, &okm)?; - hkdf_expand(sha, &prk, b"rust-lightning payment base key info", &mut okm); - let payment_base_key = try!(SecretKey::from_slice(&secp_ctx, &okm)); + hkdf_expand(Sha256::new(), &prk, b"rust-lightning payment base key info", &mut okm); + let payment_base_key = SecretKey::from_slice(&secp_ctx, &okm)?; - hkdf_expand(sha, &prk, b"rust-lightning delayed payment base key info", &mut okm); - let delayed_payment_base_key = try!(SecretKey::from_slice(&secp_ctx, &okm)); + hkdf_expand(Sha256::new(), &prk, b"rust-lightning delayed payment base key info", &mut okm); + let delayed_payment_base_key = SecretKey::from_slice(&secp_ctx, &okm)?; - hkdf_expand(sha, &prk, b"rust-lightning htlc base key info", &mut okm); - let htlc_base_key = try!(SecretKey::from_slice(&secp_ctx, &okm)); + hkdf_expand(Sha256::new(), &prk, b"rust-lightning htlc base key info", &mut okm); + let htlc_base_key = SecretKey::from_slice(&secp_ctx, &okm)?; - hkdf_expand(sha, &prk, b"rust-lightning channel close key info", &mut okm); - let channel_close_key = try!(SecretKey::from_slice(&secp_ctx, &okm)); + hkdf_expand(Sha256::new(), &prk, b"rust-lightning channel close key info", &mut okm); + let channel_close_key = SecretKey::from_slice(&secp_ctx, &okm)?; - hkdf_expand(sha, &prk, b"rust-lightning channel monitor claim key info", &mut okm); - let channel_monitor_claim_key = try!(SecretKey::from_slice(&secp_ctx, &okm)); + hkdf_expand(Sha256::new(), &prk, b"rust-lightning channel monitor claim key info", &mut okm); + let channel_monitor_claim_key = SecretKey::from_slice(&secp_ctx, &okm)?; - hkdf_expand(sha, &prk, b"rust-lightning local commitment seed info", &mut okm); + hkdf_expand(Sha256::new(), &prk, b"rust-lightning local commitment seed info", &mut okm); Ok(ChannelKeys { funding_key: funding_key, @@ -156,7 +151,7 @@ enum ChannelState { AwaitingRemoteRevoke = (1 << 7), } -// TODO: We should refactor this to be a Inbound/OutboundChannel until initial setup handshaking +// 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 // inbound channel. @@ -216,7 +211,7 @@ pub struct Channel { channel_monitor: ChannelMonitor, } -const OUR_MAX_HTLCS: u16 = 1; //TODO +const OUR_MAX_HTLCS: u16 = 5; //TODO const CONF_TARGET: u32 = 12; //TODO: Should be much higher /// Confirmation count threshold at which we close a channel. Ideally we'd keep the channel around /// on ice until the funding transaction gets more confirmations, but the LN protocol doesn't @@ -277,12 +272,11 @@ impl Channel { panic!("funding value > 2^24"); } - let mut rng = thread_rng(); let feerate = fee_estimator.get_est_sat_per_vbyte(ConfirmationTarget::Normal); let background_feerate = fee_estimator.get_est_sat_per_vbyte(ConfirmationTarget::Background); let mut key_seed = [0u8; 32]; - rng.fill_bytes(&mut key_seed); + rng::fill_bytes(&mut key_seed); let chan_keys = match ChannelKeys::new_from_seed(&key_seed) { Ok(key) => key, Err(_) => panic!("RNG is busted!") @@ -299,7 +293,7 @@ impl Channel { Channel { user_id: user_id, - channel_id: Uint256([rng.gen(), rng.gen(), rng.gen(), rng.gen()]), + channel_id: rng::rand_uint256(), channel_state: ChannelState::OurInitSent as u32, channel_outbound: true, secp_ctx: secp_ctx, @@ -369,14 +363,16 @@ impl Channel { if msg.push_msat > (msg.funding_satoshis - msg.channel_reserve_satoshis) * 1000 { return Err(HandleError{err: "push_msat more than highest possible value", msg: None}); } - //TODO Check if dust_limit is sane? + if msg.dust_limit_satoshis > 21000000 * 100000000 { + return Err(HandleError{err: "Peer never wants payout outputs?", msg: None}); + } if msg.max_htlc_value_in_flight_msat > msg.funding_satoshis * 1000 { return Err(HandleError{err: "Bogus max_htlc_value_in_flight_satoshis", msg: None}); } if msg.htlc_minimum_msat >= (msg.funding_satoshis - msg.channel_reserve_satoshis) * 1000 { return Err(HandleError{err: "Minimum htlc value is full channel value", msg: None}); } - Channel::check_remote_fee(fee_estimator, msg.feerate_per_kw).unwrap(); + Channel::check_remote_fee(fee_estimator, msg.feerate_per_kw)?; if msg.to_self_delay > MAX_LOCAL_BREAKDOWN_TIMEOUT { return Err(HandleError{err: "They wanted our payments to be delayed by a needlessly long period", msg: None}); } @@ -393,9 +389,8 @@ impl Channel { let background_feerate = fee_estimator.get_est_sat_per_vbyte(ConfirmationTarget::Background); - let mut rng = thread_rng(); let mut key_seed = [0u8; 32]; - rng.fill_bytes(&mut key_seed); + rng::fill_bytes(&mut key_seed); let chan_keys = match ChannelKeys::new_from_seed(&key_seed) { Ok(key) => key, Err(_) => panic!("RNG is busted!") @@ -612,7 +607,7 @@ impl Channel { /// The result is a transaction which we can revoke ownership of (ie a "local" transaction) /// TODO Some magic rust shit to compile-time check this? fn build_local_transaction_keys(&self, commitment_number: u64) -> Result { - let per_commitment_point = PublicKey::from_secret_key(&self.secp_ctx, &try!(self.build_local_commitment_secret(commitment_number))).unwrap(); + let per_commitment_point = PublicKey::from_secret_key(&self.secp_ctx, &self.build_local_commitment_secret(commitment_number)?).unwrap(); let delayed_payment_base = PublicKey::from_secret_key(&self.secp_ctx, &self.local_keys.delayed_payment_base_key).unwrap(); let htlc_basepoint = PublicKey::from_secret_key(&self.secp_ctx, &self.local_keys.htlc_base_key).unwrap(); @@ -770,6 +765,7 @@ impl Channel { let mut htlc_id = 0; let mut htlc_amount_msat = 0; + //TODO: swap_remove since we dont need to maintain ordering here self.pending_htlcs.retain(|ref htlc| { if !htlc.outbound && htlc.payment_hash == payment_hash { if htlc_id != 0 { @@ -784,8 +780,9 @@ impl Channel { return Err(HandleError{err: "Unable to find a pending HTLC which matched the given payment preimage", msg: None}); } + //TODO: This is racy af, they may have pending messages in flight to us that will not have + //received this yet! self.value_to_self_msat += htlc_amount_msat; - Ok(msgs::UpdateFulfillHTLC { channel_id: self.channel_id(), htlc_id: htlc_id, @@ -793,17 +790,51 @@ impl Channel { }) } + pub fn get_update_fail_htlc(&mut self, payment_hash: &[u8; 32], err_packet: msgs::OnionErrorPacket) -> Result { + if (self.channel_state & (ChannelState::ChannelFunded as u32)) != (ChannelState::ChannelFunded as u32) { + return Err(HandleError{err: "Was asked to fail an HTLC when channel was not in an operational state", msg: None}); + } + + let mut htlc_id = 0; + let mut htlc_amount_msat = 0; + //TODO: swap_remove since we dont need to maintain ordering here + self.pending_htlcs.retain(|ref htlc| { + if !htlc.outbound && htlc.payment_hash == *payment_hash { + if htlc_id != 0 { + panic!("Duplicate HTLC payment_hash, you probably re-used payment preimages, NEVER DO THIS!"); + } + htlc_id = htlc.htlc_id; + htlc_amount_msat += htlc.amount_msat; + false + } else { true } + }); + if htlc_amount_msat == 0 { + return Err(HandleError{err: "Unable to find a pending HTLC which matched the given payment preimage", msg: None}); + } + + //TODO: This is racy af, they may have pending messages in flight to us that will not have + //received this yet! + + Ok(msgs::UpdateFailHTLC { + channel_id: self.channel_id(), + htlc_id, + reason: err_packet + }) + } + // Message handlers: pub fn accept_channel(&mut self, msg: &msgs::AcceptChannel) -> Result<(), HandleError> { // Check sanity of message fields: - //TODO Check if dust_limit is sane? if !self.channel_outbound { return Err(HandleError{err: "Got an accept_channel message from an inbound peer", msg: None}); } if self.channel_state != ChannelState::OurInitSent as u32 { return Err(HandleError{err: "Got an accept_channel message at a strange time", msg: None}); } + if msg.dust_limit_satoshis > 21000000 * 100000000 { + return Err(HandleError{err: "Peer never wants payout outputs?", msg: None}); + } if msg.max_htlc_value_in_flight_msat > self.channel_value_satoshis * 1000 { return Err(HandleError{err: "Bogus max_htlc_value_in_flight_satoshis", msg: None}); } @@ -847,12 +878,12 @@ impl Channel { fn funding_created_signature(&mut self, sig: &Signature) -> Result<(Transaction, Signature), HandleError> { let funding_script = self.get_funding_redeemscript(); - let remote_keys = try!(self.build_remote_transaction_keys()); - let remote_initial_commitment_tx = try!(self.build_commitment_transaction(self.cur_remote_commitment_transaction_number, &remote_keys, false, false)).0; + let remote_keys = self.build_remote_transaction_keys()?; + let remote_initial_commitment_tx = self.build_commitment_transaction(self.cur_remote_commitment_transaction_number, &remote_keys, false, false)?.0; let remote_sighash = secp_call!(Message::from_slice(&bip143::SighashComponents::new(&remote_initial_commitment_tx).sighash_all(&remote_initial_commitment_tx, 0, &funding_script, self.channel_value_satoshis)[..])); - let local_keys = try!(self.build_local_transaction_keys(self.cur_local_commitment_transaction_number)); - let local_initial_commitment_tx = try!(self.build_commitment_transaction(self.cur_local_commitment_transaction_number, &local_keys, true, false)).0; + let local_keys = self.build_local_transaction_keys(self.cur_local_commitment_transaction_number)?; + let local_initial_commitment_tx = self.build_commitment_transaction(self.cur_local_commitment_transaction_number, &local_keys, true, false)?.0; let local_sighash = secp_call!(Message::from_slice(&bip143::SighashComponents::new(&local_initial_commitment_tx).sighash_all(&local_initial_commitment_tx, 0, &funding_script, self.channel_value_satoshis)[..])); // They sign the "local" commitment transaction, allowing us to broadcast the tx if we wish. @@ -899,7 +930,7 @@ impl Channel { } /// Handles a funding_signed message from the remote end. - /// If this call is successfull, broadcast the funding transaction (and not before!) + /// If this call is successful, broadcast the funding transaction (and not before!) pub fn funding_signed(&mut self, msg: &msgs::FundingSigned) -> Result<(), HandleError> { if !self.channel_outbound { return Err(HandleError{err: "Received funding_signed for an inbound channel?", msg: None}); @@ -913,8 +944,8 @@ impl Channel { let funding_script = self.get_funding_redeemscript(); - let local_keys = try!(self.build_local_transaction_keys(self.cur_local_commitment_transaction_number)); - let local_initial_commitment_tx = try!(self.build_commitment_transaction(self.cur_local_commitment_transaction_number, &local_keys, true, false)).0; + let local_keys = self.build_local_transaction_keys(self.cur_local_commitment_transaction_number)?; + let local_initial_commitment_tx = self.build_commitment_transaction(self.cur_local_commitment_transaction_number, &local_keys, true, false)?.0; let local_sighash = secp_call!(Message::from_slice(&bip143::SighashComponents::new(&local_initial_commitment_tx).sighash_all(&local_initial_commitment_tx, 0, &funding_script, self.channel_value_satoshis)[..])); // They sign the "local" commitment transaction, allowing us to broadcast the tx if we wish. @@ -935,7 +966,7 @@ impl Channel { } //TODO: Note that this must be a duplicate of the previous commitment point they sent us, - //as otherwise we will have a commitment transaction that they cant revoke (well, kinda, + //as otherwise we will have a commitment transaction that they can't revoke (well, kinda, //they can by sending two revoke_and_acks back-to-back, but not really). This appears to be //a protocol oversight, but I assume I'm just missing something. if self.their_cur_commitment_point != msg.next_per_commitment_point { @@ -983,8 +1014,10 @@ impl Channel { if htlc_inbound_value_msat + msg.amount_msat > Channel::get_our_max_htlc_value_in_flight_msat(self.channel_value_satoshis) { return Err(HandleError{err: "Remote HTLC add would put them over their max HTLC value in flight", msg: None}); } - // Check our_channel_reserve_satoshis: - if htlc_inbound_value_msat + htlc_outbound_value_msat + msg.amount_msat > (self.channel_value_satoshis - Channel::get_our_channel_reserve_satoshis(self.channel_value_satoshis)) * 1000 { + // Check our_channel_reserve_satoshis (we're getting paid, so they have to at least meet + // the reserve_satoshis we told them to always have as direct payment so that they lose + // something if we punish them for broadcasting an old state). + if htlc_inbound_value_msat + htlc_outbound_value_msat + msg.amount_msat + self.value_to_self_msat > (self.channel_value_satoshis - Channel::get_our_channel_reserve_satoshis(self.channel_value_satoshis)) * 1000 { return Err(HandleError{err: "Remote HTLC add would put them over their reserve value", msg: None}); } if self.next_remote_htlc_id != msg.htlc_id { @@ -1012,7 +1045,7 @@ impl Channel { } /// Removes an outbound HTLC which has been commitment_signed by the remote end - fn remove_htlc(&mut self, htlc_id: u64, check_preimage: Option<[u8; 32]>) -> Result { + fn remove_outbound_htlc(&mut self, htlc_id: u64, check_preimage: Option<[u8; 32]>) -> Result { let mut found_idx = None; for (idx, ref htlc) in self.pending_htlcs.iter().enumerate() { if htlc.outbound && htlc.htlc_id == htlc_id { @@ -1028,7 +1061,7 @@ impl Channel { } } match found_idx { - None => Err(HandleError{err: "Remote tried to fulfill an HTLC we couldn't find", msg: None}), + None => Err(HandleError{err: "Remote tried to fulfill/fail an HTLC we couldn't find", msg: None}), Some(idx) => { Ok(self.pending_htlcs.swap_remove(idx)) } @@ -1063,7 +1096,7 @@ impl Channel { //TODO: Need to examine the type of err - if its a fee issue or similar we may want to //fail it back the route, if its a temporary issue we can ignore it... if update_add_msgs.len() > 0 { - Ok(Some((update_add_msgs, try!(self.send_commitment())))) + Ok(Some((update_add_msgs, self.send_commitment()?))) } else { Err(err.unwrap()) } @@ -1098,9 +1131,7 @@ impl Channel { let mut payment_hash = [0; 32]; sha.result(&mut payment_hash); - //TODO: Tell channel_monitor about the payment_preimage - - match self.remove_htlc(msg.htlc_id, Some(payment_hash)) { + match self.remove_outbound_htlc(msg.htlc_id, Some(payment_hash)) { Err(e) => return Err(e), Ok(htlc) => { //TODO: Double-check that we didn't exceed some limits (or value_to_self went @@ -1112,43 +1143,40 @@ impl Channel { self.check_and_free_holding_cell_htlcs() } - - pub fn update_fail_htlc(&mut self, msg: &msgs::UpdateFailHTLC) -> Result, msgs::CommitmentSigned)>, HandleError> { + pub fn update_fail_htlc(&mut self, msg: &msgs::UpdateFailHTLC) -> Result<([u8; 32], Option<(Vec, msgs::CommitmentSigned)>), HandleError> { if (self.channel_state & (ChannelState::ChannelFunded as u32)) != (ChannelState::ChannelFunded as u32) { return Err(HandleError{err: "Got add HTLC message when channel was not in an operational state", msg: None}); } - //TODO: Lots of checks here (and implementation after the remove?) - - match self.remove_htlc(msg.htlc_id, None) { + let payment_hash = match self.remove_outbound_htlc(msg.htlc_id, None) { Err(e) => return Err(e), - Ok(_htlc) => { + Ok(htlc) => { //TODO: Double-check that we didn't exceed some limits (or value_to_self went //negative here?) - ////TODO: Something? + htlc.payment_hash } - } + }; - self.check_and_free_holding_cell_htlcs() + let holding_cell_freedom = self.check_and_free_holding_cell_htlcs()?; + Ok((payment_hash, holding_cell_freedom)) } - pub fn update_fail_malformed_htlc(&mut self, msg: &msgs::UpdateFailMalformedHTLC) -> Result, msgs::CommitmentSigned)>, HandleError> { + pub fn update_fail_malformed_htlc(&mut self, msg: &msgs::UpdateFailMalformedHTLC) -> Result<([u8; 32], Option<(Vec, msgs::CommitmentSigned)>), HandleError> { if (self.channel_state & (ChannelState::ChannelFunded as u32)) != (ChannelState::ChannelFunded as u32) { return Err(HandleError{err: "Got add HTLC message when channel was not in an operational state", msg: None}); } - //TODO: Lots of checks here (and implementation after the remove?) - - match self.remove_htlc(msg.htlc_id, None) { + let payment_hash = match self.remove_outbound_htlc(msg.htlc_id, None) { Err(e) => return Err(e), - Ok(_htlc) => { + Ok(htlc) => { //TODO: Double-check that we didn't exceed some limits (or value_to_self went //negative here?) - ////TODO: Something? + htlc.payment_hash } - } + }; - self.check_and_free_holding_cell_htlcs() + let holding_cell_freedom = self.check_and_free_holding_cell_htlcs()?; + Ok((payment_hash, holding_cell_freedom)) } pub fn commitment_signed(&mut self, msg: &msgs::CommitmentSigned) -> Result<(msgs::RevokeAndACK, Vec), HandleError> { @@ -1158,8 +1186,8 @@ impl Channel { let funding_script = self.get_funding_redeemscript(); - let local_keys = try!(self.build_local_transaction_keys(self.cur_local_commitment_transaction_number)); - let local_commitment_tx = try!(self.build_commitment_transaction(self.cur_local_commitment_transaction_number, &local_keys, true, false)); + let local_keys = self.build_local_transaction_keys(self.cur_local_commitment_transaction_number)?; + let local_commitment_tx = self.build_commitment_transaction(self.cur_local_commitment_transaction_number, &local_keys, true, false)?; let local_sighash = secp_call!(Message::from_slice(&bip143::SighashComponents::new(&local_commitment_tx.0).sighash_all(&local_commitment_tx.0, 0, &funding_script, self.channel_value_satoshis)[..])); secp_call!(self.secp_ctx.verify(&local_sighash, &msg.signature, &self.their_funding_pubkey)); @@ -1168,13 +1196,13 @@ impl Channel { } for (idx, ref htlc) in local_commitment_tx.1.iter().enumerate() { - let htlc_tx = try!(self.build_htlc_transaction(&local_commitment_tx.0.txid(), htlc, true, &local_keys)); + let htlc_tx = self.build_htlc_transaction(&local_commitment_tx.0.txid(), htlc, true, &local_keys)?; let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&htlc, &local_keys, htlc.offered); let htlc_sighash = secp_call!(Message::from_slice(&bip143::SighashComponents::new(&htlc_tx).sighash_all(&htlc_tx, 0, &htlc_redeemscript, htlc.amount_msat / 1000)[..])); secp_call!(self.secp_ctx.verify(&htlc_sighash, &msg.htlc_signatures[idx], &local_keys.b_htlc_key)); } - let next_per_commitment_point = PublicKey::from_secret_key(&self.secp_ctx, &try!(self.build_local_commitment_secret(self.cur_local_commitment_transaction_number - 1))).unwrap(); + let next_per_commitment_point = PublicKey::from_secret_key(&self.secp_ctx, &self.build_local_commitment_secret(self.cur_local_commitment_transaction_number - 1)?).unwrap(); let per_commitment_secret = chan_utils::build_commitment_secret(self.local_keys.commitment_seed, self.cur_local_commitment_transaction_number); //TODO: Store htlc keys in our channel_watcher @@ -1210,7 +1238,7 @@ impl Channel { if PublicKey::from_secret_key(&self.secp_ctx, &get_key!(&self.secp_ctx, &msg.per_commitment_secret)).unwrap() != self.their_cur_commitment_point { return Err(HandleError{err: "Got a revoke commitment secret which didn't correspond to their current pubkey", msg: None}); } - try!(self.channel_monitor.provide_secret(self.cur_remote_commitment_transaction_number, msg.per_commitment_secret)); + self.channel_monitor.provide_secret(self.cur_remote_commitment_transaction_number, msg.per_commitment_secret)?; // Update state now that we've passed all the can-fail calls... // (note that we may still fail to generate the new commitment_signed message, but that's @@ -1232,7 +1260,7 @@ impl Channel { if self.channel_outbound { return Err(HandleError{err: "Non-funding remote tried to update channel fee", msg: None}); } - Channel::check_remote_fee(fee_estimator, msg.feerate_per_kw).unwrap(); + Channel::check_remote_fee(fee_estimator, msg.feerate_per_kw)?; self.feerate_per_kw = msg.feerate_per_kw as u64; Ok(()) } @@ -1335,7 +1363,7 @@ impl Channel { self.funding_tx_confirmed_in = header.bitcoin_hash(); //TODO: Note that this must be a duplicate of the previous commitment point they sent us, - //as otherwise we will have a commitment transaction that they cant revoke (well, kinda, + //as otherwise we will have a commitment transaction that they can't revoke (well, kinda, //they can by sending two revoke_and_acks back-to-back, but not really). This appears to be //a protocol oversight, but I assume I'm just missing something. let next_per_commitment_secret = match self.build_local_commitment_secret(self.cur_local_commitment_transaction_number) { @@ -1395,7 +1423,7 @@ impl Channel { panic!("Tried to send an open_channel for a channel that has already advanced"); } - let local_commitment_secret = try!(self.build_local_commitment_secret(self.cur_local_commitment_transaction_number)); + let local_commitment_secret = self.build_local_commitment_secret(self.cur_local_commitment_transaction_number)?; Ok(msgs::OpenChannel { chain_hash: chain_hash, @@ -1431,7 +1459,7 @@ impl Channel { panic!("Tried to send an accept_channel for a channel that has already advanced"); } - let local_commitment_secret = try!(self.build_local_commitment_secret(self.cur_local_commitment_transaction_number)); + let local_commitment_secret = self.build_local_commitment_secret(self.cur_local_commitment_transaction_number)?; Ok(msgs::AcceptChannel { temporary_channel_id: self.channel_id, @@ -1455,8 +1483,8 @@ impl Channel { fn get_outbound_funding_created_signature(&mut self) -> Result { let funding_script = self.get_funding_redeemscript(); - let remote_keys = try!(self.build_remote_transaction_keys()); - let remote_initial_commitment_tx = try!(self.build_commitment_transaction(self.cur_remote_commitment_transaction_number, &remote_keys, false, false)).0; + let remote_keys = self.build_remote_transaction_keys()?; + let remote_initial_commitment_tx = self.build_commitment_transaction(self.cur_remote_commitment_transaction_number, &remote_keys, false, false)?.0; let remote_sighash = secp_call!(Message::from_slice(&bip143::SighashComponents::new(&remote_initial_commitment_tx).sighash_all(&remote_initial_commitment_tx, 0, &funding_script, self.channel_value_satoshis)[..])); // We sign the "remote" commitment transaction, allowing them to broadcast the tx if they wish. @@ -1468,7 +1496,7 @@ impl Channel { /// Panics if called at some time other than immediately after initial handshake, if called twice, /// or if called on an inbound channel. /// Note that channel_id changes during this call! - /// Do NOT broadcast the funding transaction until after a successfull funding_signed call! + /// Do NOT broadcast the funding transaction until after a successful funding_signed call! pub fn get_outbound_funding_created(&mut self, funding_txid: Sha256dHash, funding_output_index: u16) -> Result { if !self.channel_outbound { panic!("Tried to create outbound funding_created message on an inbound channel!"); @@ -1567,7 +1595,7 @@ impl Channel { return Err(HandleError{err: "Cannot send value that would put us over our max HTLC value in flight", msg: None}); } // Check their_channel_reserve_satoshis: - if htlc_outbound_value_msat + amount_msat > (self.channel_value_satoshis - self.their_channel_reserve_satoshis) * 1000 - htlc_inbound_value_msat { + if htlc_inbound_value_msat + htlc_outbound_value_msat + amount_msat + (self.channel_value_satoshis * 1000 - self.value_to_self_msat) > (self.channel_value_satoshis - self.their_channel_reserve_satoshis) * 1000 { return Err(HandleError{err: "Cannot send value that would put us over our reserve value", msg: None}); } @@ -1617,15 +1645,15 @@ impl Channel { let funding_script = self.get_funding_redeemscript(); - let remote_keys = try!(self.build_remote_transaction_keys()); - let remote_commitment_tx = try!(self.build_commitment_transaction(self.cur_remote_commitment_transaction_number, &remote_keys, false, true)); + let remote_keys = self.build_remote_transaction_keys()?; + let remote_commitment_tx = self.build_commitment_transaction(self.cur_remote_commitment_transaction_number, &remote_keys, false, true)?; let remote_sighash = secp_call!(Message::from_slice(&bip143::SighashComponents::new(&remote_commitment_tx.0).sighash_all(&remote_commitment_tx.0, 0, &funding_script, self.channel_value_satoshis)[..])); let our_sig = secp_call!(self.secp_ctx.sign(&remote_sighash, &self.local_keys.funding_key)); let mut htlc_sigs = Vec::new(); for ref htlc in remote_commitment_tx.1.iter() { - let htlc_tx = try!(self.build_htlc_transaction(&remote_commitment_tx.0.txid(), htlc, false, &remote_keys)); + let htlc_tx = self.build_htlc_transaction(&remote_commitment_tx.0.txid(), htlc, false, &remote_keys)?; let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&htlc, &remote_keys, htlc.offered); let htlc_sighash = secp_call!(Message::from_slice(&bip143::SighashComponents::new(&htlc_tx).sighash_all(&htlc_tx, 0, &htlc_redeemscript, htlc.amount_msat / 1000)[..])); let our_htlc_key = secp_call!(chan_utils::derive_private_key(&self.secp_ctx, &remote_keys.per_commitment_point, &self.local_keys.htlc_base_key)); @@ -1647,9 +1675,9 @@ impl Channel { /// Shorthand for calling send_htlc() followed by send_commitment(), see docs on those for /// more info. pub fn send_htlc_and_commit(&mut self, amount_msat: u64, payment_hash: [u8; 32], cltv_expiry: u32, onion_routing_packet: msgs::OnionPacket) -> Result, HandleError> { - match try!(self.send_htlc(amount_msat, payment_hash, cltv_expiry, onion_routing_packet)) { + match self.send_htlc(amount_msat, payment_hash, cltv_expiry, onion_routing_packet)? { Some(update_add_htlc) => - Ok(Some((update_add_htlc, try!(self.send_commitment())))), + Ok(Some((update_add_htlc, self.send_commitment()?))), None => Ok(None) } } @@ -1696,7 +1724,7 @@ mod tests { chan.local_keys.payment_base_key = SecretKey::from_slice(&secp_ctx, &hex_bytes("1111111111111111111111111111111111111111111111111111111111111111").unwrap()[..]).unwrap(); chan.local_keys.delayed_payment_base_key = SecretKey::from_slice(&secp_ctx, &hex_bytes("3333333333333333333333333333333333333333333333333333333333333333").unwrap()[..]).unwrap(); chan.local_keys.htlc_base_key = SecretKey::from_slice(&secp_ctx, &hex_bytes("1111111111111111111111111111111111111111111111111111111111111111").unwrap()[..]).unwrap(); - // chan.local_keys.commitment_seed isnt derived in the test vectors :( + // chan.local_keys.commitment_seed isn't derived in the test vectors :( chan.channel_monitor.set_funding_info(Sha256dHash::from_hex("8984484a580b825b9972d7adb15050b3ab624ccd731946b3eeddb92f4e7ef6be").unwrap(), 0);