/// 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
channel_update_count: u32,
feerate_per_kw: u64,
+ 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
their_cur_commitment_point: PublicKey,
their_node_id: PublicKey,
+ their_shutdown_scriptpubkey: Option<Script>,
+
channel_monitor: ChannelMonitor,
}
const B_OUTPUT_PLUS_SPENDING_INPUT_WEIGHT: u64 = 104; // prevout: 40, nSequence: 4, script len: 1, witness lengths: 3/4, sig: 73/4, pubkey: 33/4, output: 31 (TODO: Wrong? Useless?)
macro_rules! secp_call {
- ( $res : expr ) => {
+ ( $res: expr, $err: expr ) => {
match $res {
Ok(key) => key,
//TODO: make the error a parameter
- Err(_) => return Err(HandleError{err: "Secp call failed - probably bad signature or evil data generated a bad pubkey/privkey", msg: None})
+ Err(_) => return Err(HandleError{err: $err, msg: Some(msgs::ErrorAction::DisconnectPeer{})})
}
};
}
-macro_rules! get_key {
- ( $ctx : expr, $slice : expr ) => {
- secp_call! (SecretKey::from_slice($ctx, $slice))
- };
+macro_rules! secp_derived_key {
+ ( $res: expr ) => {
+ secp_call!($res, "Derived invalid key, peer is maliciously selecting parameters")
+ }
}
-
impl Channel {
// Convert constants + channel value to limits:
fn get_our_max_htlc_value_in_flight_msat(channel_value_satoshis: u64) -> u64 {
next_remote_htlc_id: 0,
channel_update_count: 0,
+ last_sent_closing_fee: None,
+
funding_tx_confirmed_in: Default::default(),
short_channel_id: None,
last_block_connected: Default::default(),
their_cur_commitment_point: PublicKey::new(),
their_node_id: their_node_id,
+ their_shutdown_scriptpubkey: None,
+
channel_monitor: channel_monitor,
}
}
fn check_remote_fee(fee_estimator: &FeeEstimator, feerate_per_kw: u32) -> Result<(), HandleError> {
if (feerate_per_kw as u64) < fee_estimator.get_est_sat_per_vbyte(ConfirmationTarget::Background) * 250 {
- return Err(HandleError{err: "Peer's feerate much too low", msg: None});
+ return Err(HandleError{err: "Peer's feerate much too low", msg: Some(msgs::ErrorAction::DisconnectPeer{})});
}
if (feerate_per_kw as u64) > fee_estimator.get_est_sat_per_vbyte(ConfirmationTarget::HighPriority) * 375 { // 375 = 250 * 1.5x
- return Err(HandleError{err: "Peer's feerate much too high", msg: None});
+ return Err(HandleError{err: "Peer's feerate much too high", msg: Some(msgs::ErrorAction::DisconnectPeer{})});
}
Ok(())
}
/// Creates a new channel from a remote sides' request for one.
/// Assumes chain_hash has already been checked and corresponds with what we expect!
+ /// Generally prefers to take the DisconnectPeer action on failure, as a notice to the sender
+ /// that we're rejecting the new channel.
pub fn new_from_req(fee_estimator: &FeeEstimator, their_node_id: PublicKey, msg: &msgs::OpenChannel, user_id: u64, announce_publicly: bool) -> Result<Channel, HandleError> {
// Check sanity of message fields:
if msg.funding_satoshis >= (1 << 24) {
- return Err(HandleError{err: "funding value > 2^24", msg: None});
+ return Err(HandleError{err: "funding value > 2^24", msg: Some(msgs::ErrorAction::DisconnectPeer{})});
}
if msg.funding_satoshis > 21000000 * 100000000 {
- return Err(HandleError{err: "More funding_satoshis than there are satoshis!", msg: None});
+ return Err(HandleError{err: "More funding_satoshis than there are satoshis!", msg: Some(msgs::ErrorAction::DisconnectPeer{})});
}
if msg.channel_reserve_satoshis > msg.funding_satoshis {
- return Err(HandleError{err: "Bogus channel_reserve_satoshis", msg: None});
+ return Err(HandleError{err: "Bogus channel_reserve_satoshis", msg: Some(msgs::ErrorAction::DisconnectPeer{})});
}
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});
+ return Err(HandleError{err: "push_msat more than highest possible value", msg: Some(msgs::ErrorAction::DisconnectPeer{})});
}
- if msg.dust_limit_satoshis > 21000000 * 100000000 {
- return Err(HandleError{err: "Peer never wants payout outputs?", msg: None});
+ if msg.dust_limit_satoshis > msg.funding_satoshis {
+ return Err(HandleError{err: "Peer never wants payout outputs?", msg: Some(msgs::ErrorAction::DisconnectPeer{})});
}
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});
+ return Err(HandleError{err: "Bogus max_htlc_value_in_flight_satoshis", msg: Some(msgs::ErrorAction::DisconnectPeer{})});
}
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});
+ return Err(HandleError{err: "Minimum htlc value is full channel value", msg: Some(msgs::ErrorAction::DisconnectPeer{})});
}
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});
+ return Err(HandleError{err: "They wanted our payments to be delayed by a needlessly long period", msg: Some(msgs::ErrorAction::DisconnectPeer{})});
}
if msg.max_accepted_htlcs < 1 {
- return Err(HandleError{err: "0 max_accpted_htlcs makes for a useless channel", msg: None});
+ return Err(HandleError{err: "0 max_accpted_htlcs makes for a useless channel", msg: Some(msgs::ErrorAction::DisconnectPeer{})});
}
if (msg.channel_flags & 254) != 0 {
- return Err(HandleError{err: "unknown channel_flags", msg: None});
+ return Err(HandleError{err: "unknown channel_flags", msg: Some(msgs::ErrorAction::DisconnectPeer{})});
}
// Convert things into internal flags and prep our state:
next_remote_htlc_id: 0,
channel_update_count: 0,
+ last_sent_closing_fee: None,
+
funding_tx_confirmed_in: Default::default(),
short_channel_id: None,
last_block_connected: Default::default(),
their_cur_commitment_point: msg.first_per_commitment_point,
their_node_id: their_node_id,
+ their_shutdown_scriptpubkey: None,
+
channel_monitor: channel_monitor,
};
// Utilities to derive keys:
- fn build_local_commitment_secret(&self, idx: u64) -> Result<SecretKey, HandleError> {
+ fn build_local_commitment_secret(&self, idx: u64) -> SecretKey {
let res = chan_utils::build_commitment_secret(self.local_keys.commitment_seed, idx);
- Ok(get_key!(&self.secp_ctx, &res))
+ SecretKey::from_slice(&self.secp_ctx, &res).unwrap()
}
// Utilities to build transactions:
/// generated by the peer which proposed adding the HTLCs, and thus we need to understand both
/// which peer generated this transaction and "to whom" this transaction flows.
#[inline]
- fn build_commitment_transaction(&self, commitment_number: u64, keys: &TxCreationKeys, local: bool, generated_by_local: bool) -> Result<(Transaction, Vec<HTLCOutputInCommitment>), HandleError> {
+ fn build_commitment_transaction(&self, commitment_number: u64, keys: &TxCreationKeys, local: bool, generated_by_local: bool) -> (Transaction, Vec<HTLCOutputInCommitment>) {
let obscured_commitment_transaction_number = self.get_commitment_transaction_number_obscure_factor() ^ commitment_number;
let txins = {
prev_hash: self.channel_monitor.get_funding_txo().unwrap().0,
prev_index: self.channel_monitor.get_funding_txo().unwrap().1 as u32,
script_sig: Script::new(),
- sequence: ((0x80 as u32) << 8*3) | ((obscured_commitment_transaction_number >> 3*8) as u32)
+ sequence: ((0x80 as u32) << 8*3) | ((obscured_commitment_transaction_number >> 3*8) as u32),
+ witness: Vec::new(),
});
ins
};
- let mut witness: Vec<Vec<Vec<u8>>> = Vec::new();
- witness.push(Vec::new());
let mut txouts: Vec<(TxOut, Option<HTLCOutputInCommitment>)> = Vec::new();
if htlc.amount_msat / 1000 >= dust_limit_satoshis + (self.feerate_per_kw * HTLC_TIMEOUT_TX_WEIGHT / 1000) {
let htlc_in_tx = htlc.get_in_commitment(true);
txouts.push((TxOut {
- script_pubkey: chan_utils::get_htlc_redeemscript(&htlc_in_tx, &keys, true).to_v0_p2wsh(),
+ script_pubkey: chan_utils::get_htlc_redeemscript(&htlc_in_tx, &keys).to_v0_p2wsh(),
value: htlc.amount_msat / 1000
}, Some(htlc_in_tx)));
}
if htlc.amount_msat / 1000 >= dust_limit_satoshis + (self.feerate_per_kw * HTLC_SUCCESS_TX_WEIGHT / 1000) {
let htlc_in_tx = htlc.get_in_commitment(false);
txouts.push((TxOut { // "received HTLC output"
- script_pubkey: chan_utils::get_htlc_redeemscript(&htlc_in_tx, &keys, false).to_v0_p2wsh(),
+ script_pubkey: chan_utils::get_htlc_redeemscript(&htlc_in_tx, &keys).to_v0_p2wsh(),
value: htlc.amount_msat / 1000
}, Some(htlc_in_tx)));
}
}
}
- Ok((Transaction {
+ (Transaction {
version: 2,
lock_time: ((0x20 as u32) << 8*3) | ((obscured_commitment_transaction_number & 0xffffffu64) as u32),
input: txins,
output: outputs,
- witness: witness
- }, htlcs_used))
+ }, htlcs_used)
+ }
+
+ #[inline]
+ fn get_closing_scriptpubkey(&self) -> Script {
+ let our_channel_close_key_hash = Hash160::from_data(&PublicKey::from_secret_key(&self.secp_ctx, &self.local_keys.channel_close_key).unwrap().serialize());
+ Builder::new().push_opcode(opcodes::All::OP_PUSHBYTES_0).push_slice(&our_channel_close_key_hash[..]).into_script()
+ }
+
+ #[inline]
+ fn get_closing_transaction_weight(a_scriptpubkey: &Script, b_scriptpubkey: &Script) -> u64 {
+ (4 + 1 + 36 + 4 + 1 + 1 + 2*(8+1) + 4 + a_scriptpubkey.len() as u64 + b_scriptpubkey.len() as u64)*4 + 2 + 1 + 1 + 2*(1 + 72)
+ }
+
+ #[inline]
+ fn build_closing_transaction(&self, proposed_total_fee_satoshis: u64, skip_remote_output: bool) -> (Transaction, u64) {
+ let txins = {
+ let mut ins: Vec<TxIn> = Vec::new();
+ ins.push(TxIn {
+ prev_hash: self.channel_monitor.get_funding_txo().unwrap().0,
+ prev_index: self.channel_monitor.get_funding_txo().unwrap().1 as u32,
+ script_sig: Script::new(),
+ sequence: 0xffffffff,
+ witness: Vec::new(),
+ });
+ ins
+ };
+
+ assert!(self.pending_htlcs.is_empty());
+ let mut txouts: Vec<(TxOut, ())> = Vec::new();
+
+ let mut total_fee_satoshis = proposed_total_fee_satoshis;
+ let value_to_self: i64 = (self.value_to_self_msat as i64) / 1000 - if self.channel_outbound { total_fee_satoshis as i64 } else { 0 };
+ let value_to_remote: i64 = ((self.channel_value_satoshis * 1000 - self.value_to_self_msat) as i64 / 1000) - if self.channel_outbound { 0 } else { total_fee_satoshis as i64 };
+
+ if value_to_self < 0 {
+ assert!(self.channel_outbound);
+ total_fee_satoshis += (-value_to_self) as u64;
+ } else if value_to_remote < 0 {
+ assert!(!self.channel_outbound);
+ total_fee_satoshis += (-value_to_remote) as u64;
+ }
+
+ if !skip_remote_output && value_to_remote as u64 > self.our_dust_limit_satoshis {
+ txouts.push((TxOut {
+ script_pubkey: self.their_shutdown_scriptpubkey.clone().unwrap(),
+ value: value_to_remote as u64
+ }, ()));
+ }
+
+ if value_to_self as u64 > self.our_dust_limit_satoshis {
+ txouts.push((TxOut {
+ script_pubkey: self.get_closing_scriptpubkey(),
+ value: value_to_self as u64
+ }, ()));
+ }
+
+ transaction_utils::sort_outputs(&mut txouts);
+
+ let mut outputs: Vec<TxOut> = Vec::new();
+ for out in txouts.drain(..) {
+ outputs.push(out.0);
+ }
+
+ (Transaction {
+ version: 2,
+ lock_time: 0,
+ input: txins,
+ output: outputs,
+ }, total_fee_satoshis)
}
#[inline]
/// 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<TxCreationKeys, HandleError> {
- let per_commitment_point = PublicKey::from_secret_key(&self.secp_ctx, &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();
- Ok(secp_call!(TxCreationKeys::new(&self.secp_ctx, &per_commitment_point, &delayed_payment_base, &htlc_basepoint, &self.their_revocation_basepoint, &self.their_payment_basepoint, &self.their_htlc_basepoint)))
+ Ok(secp_derived_key!(TxCreationKeys::new(&self.secp_ctx, &per_commitment_point, &delayed_payment_base, &htlc_basepoint, &self.their_revocation_basepoint, &self.their_payment_basepoint, &self.their_htlc_basepoint)))
}
#[inline]
let revocation_basepoint = PublicKey::from_secret_key(&self.secp_ctx, &self.local_keys.revocation_base_key).unwrap();
let htlc_basepoint = PublicKey::from_secret_key(&self.secp_ctx, &self.local_keys.htlc_base_key).unwrap();
- Ok(secp_call!(TxCreationKeys::new(&self.secp_ctx, &self.their_cur_commitment_point, &self.their_delayed_payment_basepoint, &self.their_htlc_basepoint, &revocation_basepoint, &payment_basepoint, &htlc_basepoint)))
+ Ok(secp_derived_key!(TxCreationKeys::new(&self.secp_ctx, &self.their_cur_commitment_point, &self.their_delayed_payment_basepoint, &self.their_htlc_basepoint, &revocation_basepoint, &payment_basepoint, &htlc_basepoint)))
}
/// Gets the redeemscript for the funding transaction output (ie the funding transaction output
}.push_opcode(opcodes::All::OP_PUSHNUM_2).push_opcode(opcodes::All::OP_CHECKMULTISIG).into_script()
}
- fn sign_commitment_transaction(&self, tx: &mut Transaction, their_sig: &Signature) -> Result<(), HandleError> {
+ fn sign_commitment_transaction(&self, tx: &mut Transaction, their_sig: &Signature) -> Signature {
if tx.input.len() != 1 {
panic!("Tried to sign commitment transaction that had input count != 1!");
}
- if tx.witness.len() != 1 || tx.witness[0].len() != 0 {
+ if tx.input[0].witness.len() != 0 {
panic!("Tried to re-sign commitment transaction");
}
let funding_redeemscript = self.get_funding_redeemscript();
- let sighash = secp_call!(Message::from_slice(&bip143::SighashComponents::new(&tx).sighash_all(&tx, 0, &funding_redeemscript, self.channel_value_satoshis)[..]));
- let our_sig = secp_call!(self.secp_ctx.sign(&sighash, &self.local_keys.funding_key));
+ let sighash = Message::from_slice(&bip143::SighashComponents::new(&tx).sighash_all(&tx.input[0], &funding_redeemscript, self.channel_value_satoshis)[..]).unwrap();
+ let our_sig = self.secp_ctx.sign(&sighash, &self.local_keys.funding_key).unwrap();
- tx.witness[0].push(Vec::new()); // First is the multisig dummy
+ tx.input[0].witness.push(Vec::new()); // First is the multisig dummy
let our_funding_key = PublicKey::from_secret_key(&self.secp_ctx, &self.local_keys.funding_key).unwrap().serialize();
let their_funding_key = self.their_funding_pubkey.serialize();
if our_funding_key[..] < their_funding_key[..] {
- tx.witness[0].push(our_sig.serialize_der(&self.secp_ctx).to_vec());
- tx.witness[0].push(their_sig.serialize_der(&self.secp_ctx).to_vec());
+ tx.input[0].witness.push(our_sig.serialize_der(&self.secp_ctx).to_vec());
+ tx.input[0].witness.push(their_sig.serialize_der(&self.secp_ctx).to_vec());
} else {
- tx.witness[0].push(their_sig.serialize_der(&self.secp_ctx).to_vec());
- tx.witness[0].push(our_sig.serialize_der(&self.secp_ctx).to_vec());
+ tx.input[0].witness.push(their_sig.serialize_der(&self.secp_ctx).to_vec());
+ tx.input[0].witness.push(our_sig.serialize_der(&self.secp_ctx).to_vec());
}
- tx.witness[0][1].push(SigHashType::All as u8);
- tx.witness[0][2].push(SigHashType::All as u8);
+ tx.input[0].witness[1].push(SigHashType::All as u8);
+ tx.input[0].witness[2].push(SigHashType::All as u8);
- tx.witness[0].push(funding_redeemscript.into_vec());
+ tx.input[0].witness.push(funding_redeemscript.into_vec());
- Ok(())
+ our_sig
}
/// Builds the htlc-success or htlc-timeout transaction which spends a given HTLC output
prev_hash: prev_hash.clone(),
prev_index: htlc.transaction_output_index,
script_sig: Script::new(),
- sequence: 0
+ sequence: 0,
+ witness: Vec::new(),
});
- let mut witnesses: Vec<Vec<Vec<u8>>> = Vec::new();
- witnesses.push(Vec::new());
-
let total_fee = if htlc.offered {
self.feerate_per_kw * HTLC_TIMEOUT_TX_WEIGHT / 1000
} else {
lock_time: if htlc.offered { htlc.cltv_expiry } else { 0 },
input: txins,
output: txouts,
- witness: witnesses
})
}
if tx.input.len() != 1 {
panic!("Tried to sign HTLC transaction that had input count != 1!");
}
- if tx.witness.len() != 1 || tx.witness[0].len() != 0 {
+ if tx.input[0].witness.len() != 0 {
panic!("Tried to re-sign HTLC transaction");
}
- let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&htlc, &keys, htlc.offered);
+ let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&htlc, &keys);
- let our_htlc_key = secp_call!(chan_utils::derive_private_key(&self.secp_ctx, &keys.per_commitment_point, &self.local_keys.htlc_base_key));
- let sighash = secp_call!(Message::from_slice(&bip143::SighashComponents::new(&tx).sighash_all(&tx, 0, &htlc_redeemscript, htlc.amount_msat / 1000)[..]));
- let our_sig = secp_call!(self.secp_ctx.sign(&sighash, &our_htlc_key));
+ let our_htlc_key = secp_derived_key!(chan_utils::derive_private_key(&self.secp_ctx, &keys.per_commitment_point, &self.local_keys.htlc_base_key));
+ let sighash = Message::from_slice(&bip143::SighashComponents::new(&tx).sighash_all(&tx.input[0], &htlc_redeemscript, htlc.amount_msat / 1000)[..]).unwrap();
+ let our_sig = self.secp_ctx.sign(&sighash, &our_htlc_key).unwrap();
let local_tx = PublicKey::from_secret_key(&self.secp_ctx, &our_htlc_key).unwrap() == keys.a_htlc_key;
- tx.witness[0].push(Vec::new()); // First is the multisig dummy
+ tx.input[0].witness.push(Vec::new()); // First is the multisig dummy
if local_tx { // b, then a
- tx.witness[0].push(their_sig.serialize_der(&self.secp_ctx).to_vec());
- tx.witness[0].push(our_sig.serialize_der(&self.secp_ctx).to_vec());
+ tx.input[0].witness.push(their_sig.serialize_der(&self.secp_ctx).to_vec());
+ tx.input[0].witness.push(our_sig.serialize_der(&self.secp_ctx).to_vec());
} else {
- tx.witness[0].push(our_sig.serialize_der(&self.secp_ctx).to_vec());
- tx.witness[0].push(their_sig.serialize_der(&self.secp_ctx).to_vec());
+ tx.input[0].witness.push(our_sig.serialize_der(&self.secp_ctx).to_vec());
+ tx.input[0].witness.push(their_sig.serialize_der(&self.secp_ctx).to_vec());
}
- tx.witness[0][1].push(SigHashType::All as u8);
- tx.witness[0][2].push(SigHashType::All as u8);
+ tx.input[0].witness[1].push(SigHashType::All as u8);
+ tx.input[0].witness[2].push(SigHashType::All as u8);
if htlc.offered {
- tx.witness[0].push(Vec::new());
+ tx.input[0].witness.push(Vec::new());
} else {
- tx.witness[0].push(preimage.unwrap().to_vec());
+ tx.input[0].witness.push(preimage.unwrap().to_vec());
}
- tx.witness[0].push(htlc_redeemscript.into_vec());
+ tx.input[0].witness.push(htlc_redeemscript.into_vec());
Ok(())
}
pub fn get_update_fulfill_htlc(&mut self, payment_preimage: [u8; 32]) -> Result<msgs::UpdateFulfillHTLC, HandleError> {
+ // Either ChannelFunded got set (which means it wont bet unset) or there is no way any
+ // caller thought we could have something claimed (cause we wouldn't have accepted in an
+ // incoming HTLC anyway). If we got to ShutdownComplete, callers aren't allowed to call us,
+ // either.
if (self.channel_state & (ChannelState::ChannelFunded as u32)) != (ChannelState::ChannelFunded as u32) {
- return Err(HandleError{err: "Was asked to fulfill an HTLC when channel was not in an operational state", msg: None});
+ panic!("Was asked to fulfill an HTLC when channel was not in an operational state");
}
+ assert_eq!(self.channel_state & ChannelState::ShutdownComplete as u32, 0);
let mut sha = Sha256::new();
sha.input(&payment_preimage);
if htlc_amount_msat == 0 {
return Err(HandleError{err: "Unable to find a pending HTLC which matched the given payment preimage", msg: None});
}
+ self.channel_monitor.provide_payment_preimage(&payment_preimage);
//TODO: This is racy af, they may have pending messages in flight to us that will not have
//received this yet!
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});
}
+ assert_eq!(self.channel_state & ChannelState::ShutdownComplete as u32, 0);
let mut htlc_id = 0;
let mut htlc_amount_msat = 0;
let funding_script = self.get_funding_redeemscript();
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 remote_initial_commitment_tx = self.build_commitment_transaction(self.cur_remote_commitment_transaction_number, &remote_keys, false, false).0;
+ let remote_sighash = Message::from_slice(&bip143::SighashComponents::new(&remote_initial_commitment_tx).sighash_all(&remote_initial_commitment_tx.input[0], &funding_script, self.channel_value_satoshis)[..]).unwrap();
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)[..]));
+ let local_initial_commitment_tx = self.build_commitment_transaction(self.cur_local_commitment_transaction_number, &local_keys, true, false).0;
+ let local_sighash = Message::from_slice(&bip143::SighashComponents::new(&local_initial_commitment_tx).sighash_all(&local_initial_commitment_tx.input[0], &funding_script, self.channel_value_satoshis)[..]).unwrap();
// They sign the "local" commitment transaction, allowing us to broadcast the tx if we wish.
- secp_call!(self.secp_ctx.verify(&local_sighash, &sig, &self.their_funding_pubkey));
+ secp_call!(self.secp_ctx.verify(&local_sighash, &sig, &self.their_funding_pubkey), "Invalid funding_created signature from peer");
// We sign the "remote" commitment transaction, allowing them to broadcast the tx if they wish.
- Ok((remote_initial_commitment_tx, secp_call!(self.secp_ctx.sign(&remote_sighash, &self.local_keys.funding_key))))
+ Ok((remote_initial_commitment_tx, self.secp_ctx.sign(&remote_sighash, &self.local_keys.funding_key).unwrap()))
}
pub fn funding_created(&mut self, msg: &msgs::FundingCreated) -> Result<msgs::FundingSigned, HandleError> {
let funding_script = self.get_funding_redeemscript();
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)[..]));
+ let local_initial_commitment_tx = self.build_commitment_transaction(self.cur_local_commitment_transaction_number, &local_keys, true, false).0;
+ let local_sighash = Message::from_slice(&bip143::SighashComponents::new(&local_initial_commitment_tx).sighash_all(&local_initial_commitment_tx.input[0], &funding_script, self.channel_value_satoshis)[..]).unwrap();
// They sign the "local" commitment transaction, allowing us to broadcast the tx if we wish.
- secp_call!(self.secp_ctx.verify(&local_sighash, &msg.signature, &self.their_funding_pubkey));
+ secp_call!(self.secp_ctx.verify(&local_sighash, &msg.signature, &self.their_funding_pubkey), "Invalid funding_signed signature from peer");
self.channel_state = ChannelState::FundingSent as u32;
}
pub fn funding_locked(&mut self, msg: &msgs::FundingLocked) -> Result<(), HandleError> {
- if self.channel_state == ChannelState::FundingSent as u32 {
+ let non_shutdown_state = self.channel_state & (!BOTH_SIDES_SHUTDOWN_MASK);
+ if non_shutdown_state == ChannelState::FundingSent as u32 {
self.channel_state |= ChannelState::TheirFundingLocked as u32;
- } else if self.channel_state == (ChannelState::FundingSent as u32 | ChannelState::OurFundingLocked as u32) {
- self.channel_state = ChannelState::ChannelFunded as u32;
- } else if self.channel_state < ChannelState::FundingSent as u32 {
- return Err(HandleError{err: "Peer sent a funding_locked before we'd even been told the funding txid", msg: None});
+ } else if non_shutdown_state == (ChannelState::FundingSent as u32 | ChannelState::OurFundingLocked as u32) {
+ self.channel_state = ChannelState::ChannelFunded as u32 | (self.channel_state & BOTH_SIDES_SHUTDOWN_MASK);
+ } else {
+ return Err(HandleError{err: "Peer sent a funding_locked at a strange time", msg: None});
}
//TODO: Note that this must be a duplicate of the previous commitment point they sent us,
}
pub fn update_add_htlc(&mut self, msg: &msgs::UpdateAddHTLC, pending_forward_state: PendingForwardHTLCInfo) -> Result<(), HandleError> {
- if (self.channel_state & (ChannelState::ChannelFunded as u32)) != (ChannelState::ChannelFunded as u32) {
+ if (self.channel_state & (ChannelState::ChannelFunded as u32 | ChannelState::RemoteShutdownSent as u32)) != (ChannelState::ChannelFunded as u32) {
return Err(HandleError{err: "Got add HTLC message when channel was not in an operational state", msg: None});
}
if msg.amount_msat > self.channel_value_satoshis * 1000 {
self.value_to_self_msat -= htlc.amount_msat;
}
}
+ self.channel_monitor.provide_payment_preimage(&msg.payment_preimage);
Ok(())
}
let funding_script = self.get_funding_redeemscript();
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));
+ let local_commitment_tx = self.build_commitment_transaction(self.cur_local_commitment_transaction_number, &local_keys, true, false);
+ let local_commitment_txid = local_commitment_tx.0.txid();
+ let local_sighash = Message::from_slice(&bip143::SighashComponents::new(&local_commitment_tx.0).sighash_all(&local_commitment_tx.0.input[0], &funding_script, self.channel_value_satoshis)[..]).unwrap();
+ secp_call!(self.secp_ctx.verify(&local_sighash, &msg.signature, &self.their_funding_pubkey), "Invalid commitment tx signature from peer");
if msg.htlc_signatures.len() != local_commitment_tx.1.len() {
return Err(HandleError{err: "Got wrong number of HTLC signatures from remote", msg: None});
}
for (idx, ref htlc) in local_commitment_tx.1.iter().enumerate() {
- 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 htlc_tx = self.build_htlc_transaction(&local_commitment_txid, htlc, true, &local_keys)?;
+ let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&htlc, &local_keys);
+ let htlc_sighash = Message::from_slice(&bip143::SighashComponents::new(&htlc_tx).sighash_all(&htlc_tx.input[0], &htlc_redeemscript, htlc.amount_msat / 1000)[..]).unwrap();
+ secp_call!(self.secp_ctx.verify(&htlc_sighash, &msg.htlc_signatures[idx], &local_keys.b_htlc_key), "Invalid HTLC tx siganture from peer");
}
- 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 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
if (self.channel_state & (ChannelState::ChannelFunded as u32)) != (ChannelState::ChannelFunded as u32) {
return Err(HandleError{err: "Got revoke/ACK message when channel was not in an operational state", msg: None});
}
- if PublicKey::from_secret_key(&self.secp_ctx, &get_key!(&self.secp_ctx, &msg.per_commitment_secret)).unwrap() != self.their_cur_commitment_point {
+ if PublicKey::from_secret_key(&self.secp_ctx, &secp_call!(SecretKey::from_slice(&self.secp_ctx, &msg.per_commitment_secret), "Peer provided an invalid 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});
}
self.channel_monitor.provide_secret(self.cur_remote_commitment_transaction_number, msg.per_commitment_secret)?;
Ok(())
}
+ pub fn shutdown(&mut self, fee_estimator: &FeeEstimator, msg: &msgs::Shutdown) -> Result<(Option<msgs::Shutdown>, Option<msgs::ClosingSigned>, Vec<[u8; 32]>), HandleError> {
+ if self.channel_state < ChannelState::FundingSent as u32 {
+ self.channel_state = ChannelState::ShutdownComplete as u32;
+ return Ok((None, None, Vec::new()));
+ }
+ for htlc in self.pending_htlcs.iter() {
+ if htlc.state == HTLCState::RemoteAnnounced {
+ return Err(HandleError{err: "Got shutdown with remote pending HTLCs", msg: None});
+ }
+ }
+ if (self.channel_state & ChannelState::RemoteShutdownSent as u32) == ChannelState::RemoteShutdownSent as u32 {
+ return Err(HandleError{err: "Remote peer sent duplicate shutdown message", msg: None});
+ }
+ assert_eq!(self.channel_state & ChannelState::ShutdownComplete as u32, 0);
+
+ // BOLT 2 says we must only send a scriptpubkey of certain standard forms, which are up to
+ // 34 bytes in length, so dont let the remote peer feed us some super fee-heavy script.
+ if self.channel_outbound && msg.scriptpubkey.len() > 34 {
+ return Err(HandleError{err: "Got shutdown_scriptpubkey of absurd length from remote peer", msg: None});
+ }
+ //TODO: Check shutdown_scriptpubkey form as BOLT says we must? WHYYY
+
+ if self.their_shutdown_scriptpubkey.is_some() {
+ if Some(&msg.scriptpubkey) != self.their_shutdown_scriptpubkey.as_ref() {
+ return Err(HandleError{err: "Got shutdown request with a scriptpubkey which did not match their previous scriptpubkey", msg: None});
+ }
+ } else {
+ self.their_shutdown_scriptpubkey = Some(msg.scriptpubkey.clone());
+ }
+
+ let our_closing_script = self.get_closing_scriptpubkey();
+
+ let (proposed_feerate, proposed_fee, our_sig) = if self.channel_outbound && self.pending_htlcs.is_empty() {
+ let mut proposed_feerate = fee_estimator.get_est_sat_per_vbyte(ConfirmationTarget::Background);
+ if self.feerate_per_kw > proposed_feerate * 250 {
+ proposed_feerate = self.feerate_per_kw / 250;
+ }
+ let tx_weight = Self::get_closing_transaction_weight(&our_closing_script, &msg.scriptpubkey);
+ let proposed_total_fee_satoshis = proposed_feerate * tx_weight / 4;
+
+ let (closing_tx, total_fee_satoshis) = self.build_closing_transaction(proposed_total_fee_satoshis, false);
+ let funding_redeemscript = self.get_funding_redeemscript();
+ let sighash = Message::from_slice(&bip143::SighashComponents::new(&closing_tx).sighash_all(&closing_tx.input[0], &funding_redeemscript, self.channel_value_satoshis)[..]).unwrap();
+
+ (Some(proposed_feerate), Some(total_fee_satoshis), Some(self.secp_ctx.sign(&sighash, &self.local_keys.funding_key).unwrap()))
+ } else { (None, None, None) };
+
+ // From here on out, we may not fail!
+
+ self.channel_state |= ChannelState::RemoteShutdownSent as u32;
+
+ // We can't send our shutdown until we've committed all of our pending HTLCs, but the
+ // remote side is unlikely to accept any new HTLCs, so we go ahead and "free" any holding
+ // cell HTLCs and return them to fail the payment.
+ let mut dropped_outbound_htlcs = Vec::with_capacity(self.holding_cell_htlcs.len());
+ for htlc in self.holding_cell_htlcs.drain(..) {
+ dropped_outbound_htlcs.push(htlc.payment_hash);
+ }
+ for htlc in self.pending_htlcs.iter() {
+ if htlc.state == HTLCState::LocalAnnounced {
+ return Ok((None, None, dropped_outbound_htlcs));
+ }
+ }
+
+ let our_shutdown = if (self.channel_state & ChannelState::LocalShutdownSent as u32) == ChannelState::LocalShutdownSent as u32 {
+ None
+ } else {
+ Some(msgs::Shutdown {
+ channel_id: self.channel_id,
+ scriptpubkey: our_closing_script,
+ })
+ };
+
+ self.channel_state |= ChannelState::LocalShutdownSent as u32;
+ if self.pending_htlcs.is_empty() && self.channel_outbound {
+ // There are no more HTLCs and we're the funder, this means we start the closing_signed
+ // dance with an initial fee proposal!
+ self.last_sent_closing_fee = Some((proposed_feerate.unwrap(), proposed_fee.unwrap()));
+ Ok((our_shutdown, Some(msgs::ClosingSigned {
+ channel_id: self.channel_id,
+ fee_satoshis: proposed_fee.unwrap(),
+ signature: our_sig.unwrap(),
+ }), dropped_outbound_htlcs))
+ } else {
+ Ok((our_shutdown, None, dropped_outbound_htlcs))
+ }
+ }
+
+ pub fn closing_signed(&mut self, fee_estimator: &FeeEstimator, msg: &msgs::ClosingSigned) -> Result<(Option<msgs::ClosingSigned>, Option<Transaction>), HandleError> {
+ if self.channel_state & BOTH_SIDES_SHUTDOWN_MASK != BOTH_SIDES_SHUTDOWN_MASK {
+ return Err(HandleError{err: "Remote end sent us a closing_signed before both sides provided a shutdown", msg: None});
+ }
+ if !self.pending_htlcs.is_empty() {
+ return Err(HandleError{err: "Remote end sent us a closing_signed while there were still pending HTLCs", msg: None});
+ }
+ if msg.fee_satoshis > 21000000 * 10000000 {
+ return Err(HandleError{err: "Remote tried to send us a closing tx with > 21 million BTC fee", msg: None});
+ }
+
+ let funding_redeemscript = self.get_funding_redeemscript();
+ let (mut closing_tx, used_total_fee) = self.build_closing_transaction(msg.fee_satoshis, false);
+ if used_total_fee != msg.fee_satoshis {
+ return Err(HandleError{err: "Remote sent us a closing_signed with a fee greater than the value they can claim", msg: None});
+ }
+ let mut sighash = Message::from_slice(&bip143::SighashComponents::new(&closing_tx).sighash_all(&closing_tx.input[0], &funding_redeemscript, self.channel_value_satoshis)[..]).unwrap();
+
+ match self.secp_ctx.verify(&sighash, &msg.signature, &self.their_funding_pubkey) {
+ Ok(_) => {},
+ Err(_) => {
+ // The remote end may have decided to revoke their output due to inconsistent dust
+ // limits, so check for that case by re-checking the signature here.
+ closing_tx = self.build_closing_transaction(msg.fee_satoshis, true).0;
+ sighash = Message::from_slice(&bip143::SighashComponents::new(&closing_tx).sighash_all(&closing_tx.input[0], &funding_redeemscript, self.channel_value_satoshis)[..]).unwrap();
+ secp_call!(self.secp_ctx.verify(&sighash, &msg.signature, &self.their_funding_pubkey), "Invalid closing tx signature from peer");
+ },
+ };
+
+ if let Some((_, last_fee)) = self.last_sent_closing_fee {
+ if last_fee == msg.fee_satoshis {
+ self.sign_commitment_transaction(&mut closing_tx, &msg.signature);
+ self.channel_state = ChannelState::ShutdownComplete as u32;
+ return Ok((None, Some(closing_tx)));
+ }
+ }
+
+ macro_rules! propose_new_feerate {
+ ($new_feerate: expr) => {
+ let closing_tx_max_weight = Self::get_closing_transaction_weight(&self.get_closing_scriptpubkey(), self.their_shutdown_scriptpubkey.as_ref().unwrap());
+ let (closing_tx, used_total_fee) = self.build_closing_transaction($new_feerate * closing_tx_max_weight / 4, false);
+ sighash = Message::from_slice(&bip143::SighashComponents::new(&closing_tx).sighash_all(&closing_tx.input[0], &funding_redeemscript, self.channel_value_satoshis)[..]).unwrap();
+ let our_sig = self.secp_ctx.sign(&sighash, &self.local_keys.funding_key).unwrap();
+ self.last_sent_closing_fee = Some(($new_feerate, used_total_fee));
+ return Ok((Some(msgs::ClosingSigned {
+ channel_id: self.channel_id,
+ fee_satoshis: used_total_fee,
+ signature: our_sig,
+ }), None))
+ }
+ }
+
+ let proposed_sat_per_vbyte = msg.fee_satoshis * 4 / closing_tx.get_weight();
+ if self.channel_outbound {
+ let our_max_feerate = fee_estimator.get_est_sat_per_vbyte(ConfirmationTarget::Normal);
+ if proposed_sat_per_vbyte > our_max_feerate {
+ if let Some((last_feerate, _)) = self.last_sent_closing_fee {
+ if our_max_feerate <= last_feerate {
+ return Err(HandleError{err: "Unable to come to consensus about closing feerate, remote wanted something higher than our Normal feerate", msg: None});
+ }
+ }
+ propose_new_feerate!(our_max_feerate);
+ }
+ } else {
+ let our_min_feerate = fee_estimator.get_est_sat_per_vbyte(ConfirmationTarget::Background);
+ if proposed_sat_per_vbyte < our_min_feerate {
+ if let Some((last_feerate, _)) = self.last_sent_closing_fee {
+ if our_min_feerate >= last_feerate {
+ return Err(HandleError{err: "Unable to come to consensus about closing feerate, remote wanted something lower than our Background feerate", msg: None});
+ }
+ }
+ propose_new_feerate!(our_min_feerate);
+ }
+ }
+
+ let our_sig = self.sign_commitment_transaction(&mut closing_tx, &msg.signature);
+ self.channel_state = ChannelState::ShutdownComplete as u32;
+
+ Ok((Some(msgs::ClosingSigned {
+ channel_id: self.channel_id,
+ fee_satoshis: msg.fee_satoshis,
+ signature: our_sig,
+ }), Some(closing_tx)))
+ }
+
// Public utilities:
pub fn channel_id(&self) -> Uint256 {
/// Returns true if this channel is fully established and not known to be closing.
pub fn is_usable(&self) -> bool {
- (self.channel_state & (ChannelState::ChannelFunded as u32)) == (ChannelState::ChannelFunded as u32)
+ let mask = ChannelState::ChannelFunded as u32 | BOTH_SIDES_SHUTDOWN_MASK;
+ (self.channel_state & mask) == (ChannelState::ChannelFunded as u32)
}
/// Returns true if this channel is currently available for use. This is a superset of
self.is_usable()
}
+ /// Returns true if this channel is fully shut down. True here implies that no further actions
+ /// may/will be taken on this channel, and thus this object should be freed. Any future changes
+ /// will be handled appropriately by the chain monitor.
+ pub fn is_shutdown(&self) -> bool {
+ if (self.channel_state & ChannelState::ShutdownComplete as u32) == ChannelState::ShutdownComplete as u32 {
+ assert!(self.channel_state == ChannelState::ShutdownComplete as u32);
+ true
+ } else { false }
+ }
+
/// Called by channelmanager based on chain blocks being connected.
/// Note that we only need to use this to detect funding_signed, anything else is handled by
/// the channel_monitor.
pub fn block_connected(&mut self, header: &BlockHeader, height: u32, txn_matched: &[&Transaction], indexes_of_txn_matched: &[u32]) -> Option<msgs::FundingLocked> {
+ let non_shutdown_state = self.channel_state & (!BOTH_SIDES_SHUTDOWN_MASK);
if self.funding_tx_confirmations > 0 {
if header.bitcoin_hash() != self.last_block_connected {
self.last_block_connected = header.bitcoin_hash();
self.funding_tx_confirmations += 1;
if self.funding_tx_confirmations == CONF_TARGET as u64 {
- if self.channel_state == ChannelState::FundingSent as u32 {
+ if non_shutdown_state == ChannelState::FundingSent as u32 {
self.channel_state |= ChannelState::OurFundingLocked as u32;
- } else if self.channel_state == (ChannelState::FundingSent as u32 | ChannelState::TheirFundingLocked as u32) {
- self.channel_state = ChannelState::ChannelFunded as u32;
+ } else if non_shutdown_state == (ChannelState::FundingSent as u32 | ChannelState::TheirFundingLocked as u32) {
+ self.channel_state = ChannelState::ChannelFunded as u32 | (self.channel_state & BOTH_SIDES_SHUTDOWN_MASK);
//TODO: Something about a state where we "lost confirmation"
} else if self.channel_state < ChannelState::ChannelFunded as u32 {
panic!("Started confirming a channel in a state pre-FundingSent?");
//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) {
- Ok(secret) => secret,
- Err(_) => return None
- };
-
+ let next_per_commitment_secret = self.build_local_commitment_secret(self.cur_local_commitment_transaction_number);
let next_per_commitment_point = PublicKey::from_secret_key(&self.secp_ctx, &next_per_commitment_secret).unwrap();
return Some(msgs::FundingLocked {
channel_id: self.channel_id,
}
}
}
- if self.channel_state & !(ChannelState::TheirFundingLocked as u32) == ChannelState::FundingSent as u32 {
+ if non_shutdown_state & !(ChannelState::TheirFundingLocked as u32) == ChannelState::FundingSent as u32 {
for (ref tx, index_in_block) in txn_matched.iter().zip(indexes_of_txn_matched) {
if tx.txid() == self.channel_monitor.get_funding_txo().unwrap().0 {
- self.funding_tx_confirmations = 1;
- self.short_channel_id = Some(((height as u64) << (5*8)) |
- ((*index_in_block as u64) << (2*8)) |
- ((self.channel_monitor.get_funding_txo().unwrap().1 as u64) << (2*8)));
+ let txo_idx = self.channel_monitor.get_funding_txo().unwrap().1 as usize;
+ if txo_idx >= tx.output.len() || tx.output[txo_idx].script_pubkey != self.get_funding_redeemscript().to_v0_p2wsh() ||
+ tx.output[txo_idx].value != self.channel_value_satoshis {
+ self.channel_state = ChannelState::ShutdownComplete as u32;
+ } else {
+ self.funding_tx_confirmations = 1;
+ self.short_channel_id = Some(((height as u64) << (5*8)) |
+ ((*index_in_block as u64) << (2*8)) |
+ ((self.channel_monitor.get_funding_txo().unwrap().1 as u64) << (2*8)));
+ }
}
}
}
panic!("Tried to send an open_channel for a channel that has already advanced");
}
- let local_commitment_secret = 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,
panic!("Tried to send an accept_channel for a channel that has already advanced");
}
- let local_commitment_secret = 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,
let funding_script = self.get_funding_redeemscript();
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 remote_initial_commitment_tx = self.build_commitment_transaction(self.cur_remote_commitment_transaction_number, &remote_keys, false, false).0;
+ let remote_sighash = Message::from_slice(&bip143::SighashComponents::new(&remote_initial_commitment_tx).sighash_all(&remote_initial_commitment_tx.input[0], &funding_script, self.channel_value_satoshis)[..]).unwrap();
// We sign the "remote" commitment transaction, allowing them to broadcast the tx if they wish.
- Ok(secp_call!(self.secp_ctx.sign(&remote_sighash, &self.local_keys.funding_key)))
+ Ok(self.secp_ctx.sign(&remote_sighash, &self.local_keys.funding_key).unwrap())
}
/// Updates channel state with knowledge of the funding transaction's txid/index, and generates
/// bitcoin_key, if available, for this channel. The channel must be publicly announceable and
/// available for use (have exchanged FundingLocked messages in both directions. Should be used
/// for both loose and in response to an AnnouncementSignatures message from the remote peer.
+ /// Note that you can get an announcement for a channel which is closing, though you should
+ /// likely not announce such a thing. In case its already been announced, a channel_update
+ /// message can mark the channel disabled.
pub fn get_channel_announcement(&self, our_node_id: PublicKey, chain_hash: Sha256dHash) -> Result<(msgs::UnsignedChannelAnnouncement, Signature), HandleError> {
if !self.announce_publicly {
return Err(HandleError{err: "Channel is not available for public announcements", msg: None});
}
- if self.channel_state < ChannelState::ChannelFunded as u32 {
+ if self.channel_state & (ChannelState::ChannelFunded as u32) != (ChannelState::ChannelFunded as u32) {
return Err(HandleError{err: "Cannot get a ChannelAnnouncement until the channel funding has been locked", msg: None});
}
};
let msghash = Message::from_slice(&Sha256dHash::from_data(&msg.encode()[..])[..]).unwrap();
- let sig = secp_call!(self.secp_ctx.sign(&msghash, &self.local_keys.funding_key));
+ let sig = self.secp_ctx.sign(&msghash, &self.local_keys.funding_key).unwrap();
Ok((msg, sig))
}
/// waiting on the remote peer to send us a revoke_and_ack during which time we cannot add new
/// HTLCs on the wire or we wouldn't be able to determine what they actually ACK'ed.
pub fn send_htlc(&mut self, amount_msat: u64, payment_hash: [u8; 32], cltv_expiry: u32, onion_routing_packet: msgs::OnionPacket) -> Result<Option<msgs::UpdateAddHTLC>, HandleError> {
- if (self.channel_state & (ChannelState::ChannelFunded as u32)) != (ChannelState::ChannelFunded as u32) {
- return Err(HandleError{err: "Cannot send HTLC until channel is fully established", msg: None});
+ if (self.channel_state & (ChannelState::ChannelFunded as u32 | BOTH_SIDES_SHUTDOWN_MASK)) != (ChannelState::ChannelFunded as u32) {
+ return Err(HandleError{err: "Cannot send HTLC until channel is fully established and we haven't started shutting down", msg: None});
}
if amount_msat > self.channel_value_satoshis * 1000 {
let funding_script = self.get_funding_redeemscript();
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 remote_commitment_tx = self.build_commitment_transaction(self.cur_remote_commitment_transaction_number, &remote_keys, false, true);
+ let remote_commitment_txid = remote_commitment_tx.0.txid();
+ let remote_sighash = Message::from_slice(&bip143::SighashComponents::new(&remote_commitment_tx.0).sighash_all(&remote_commitment_tx.0.input[0], &funding_script, self.channel_value_satoshis)[..]).unwrap();
+ let our_sig = self.secp_ctx.sign(&remote_sighash, &self.local_keys.funding_key).unwrap();
let mut htlc_sigs = Vec::new();
for ref htlc in remote_commitment_tx.1.iter() {
- 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));
- htlc_sigs.push(secp_call!(self.secp_ctx.sign(&htlc_sighash, &our_htlc_key)));
+ let htlc_tx = self.build_htlc_transaction(&remote_commitment_txid, htlc, false, &remote_keys)?;
+ let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&htlc, &remote_keys);
+ let htlc_sighash = Message::from_slice(&bip143::SighashComponents::new(&htlc_tx).sighash_all(&htlc_tx.input[0], &htlc_redeemscript, htlc.amount_msat / 1000)[..]).unwrap();
+ let our_htlc_key = secp_derived_key!(chan_utils::derive_private_key(&self.secp_ctx, &remote_keys.per_commitment_point, &self.local_keys.htlc_base_key));
+ htlc_sigs.push(self.secp_ctx.sign(&htlc_sighash, &our_htlc_key).unwrap());
}
// Update state now that we've passed all the can-fail calls...
None => Ok(None)
}
}
+
+ /// Begins the shutdown process, getting a message for the remote peer and returning all
+ /// holding cell HTLCs for payment failure.
+ pub fn get_shutdown(&mut self) -> Result<(msgs::Shutdown, Vec<[u8; 32]>), HandleError> {
+ for htlc in self.pending_htlcs.iter() {
+ if htlc.state == HTLCState::LocalAnnounced {
+ return Err(HandleError{err: "Cannot begin shutdown with pending HTLCs, call send_commitment first", msg: None});
+ }
+ }
+ if self.channel_state & BOTH_SIDES_SHUTDOWN_MASK != 0 {
+ return Err(HandleError{err: "Shutdown already in progress", msg: None});
+ }
+ assert_eq!(self.channel_state & ChannelState::ShutdownComplete as u32, 0);
+
+ let our_closing_script = self.get_closing_scriptpubkey();
+
+ // From here on out, we may not fail!
+ if self.channel_state < ChannelState::FundingSent as u32 {
+ self.channel_state = ChannelState::ShutdownComplete as u32;
+ } else {
+ self.channel_state |= ChannelState::LocalShutdownSent as u32;
+ }
+
+ // We can't send our shutdown until we've committed all of our pending HTLCs, but the
+ // remote side is unlikely to accept any new HTLCs, so we go ahead and "free" any holding
+ // cell HTLCs and return them to fail the payment.
+ let mut dropped_outbound_htlcs = Vec::with_capacity(self.holding_cell_htlcs.len());
+ for htlc in self.holding_cell_htlcs.drain(..) {
+ dropped_outbound_htlcs.push(htlc.payment_hash);
+ }
+
+ Ok((msgs::Shutdown {
+ channel_id: self.channel_id,
+ scriptpubkey: our_closing_script,
+ }, dropped_outbound_htlcs))
+ }
}
#[cfg(test)]
macro_rules! test_commitment {
( $their_sig_hex: expr, $our_sig_hex: expr, $tx_hex: expr) => {
- unsigned_tx = chan.build_commitment_transaction(42, &keys, true, false).unwrap();
+ unsigned_tx = chan.build_commitment_transaction(42, &keys, true, false);
let their_signature = Signature::from_der(&secp_ctx, &hex_bytes($their_sig_hex).unwrap()[..]).unwrap();
- let sighash = Message::from_slice(&bip143::SighashComponents::new(&unsigned_tx.0).sighash_all(&unsigned_tx.0, 0, &chan.get_funding_redeemscript(), chan.channel_value_satoshis)[..]).unwrap();
+ let sighash = Message::from_slice(&bip143::SighashComponents::new(&unsigned_tx.0).sighash_all(&unsigned_tx.0.input[0], &chan.get_funding_redeemscript(), chan.channel_value_satoshis)[..]).unwrap();
secp_ctx.verify(&sighash, &their_signature, &chan.their_funding_pubkey).unwrap();
- chan.sign_commitment_transaction(&mut unsigned_tx.0, &their_signature).unwrap();
+ chan.sign_commitment_transaction(&mut unsigned_tx.0, &their_signature);
assert_eq!(serialize(&unsigned_tx.0).unwrap()[..],
hex_bytes($tx_hex).unwrap()[..]);
let ref htlc = unsigned_tx.1[$htlc_idx];
let mut htlc_tx = chan.build_htlc_transaction(&unsigned_tx.0.txid(), &htlc, true, &keys).unwrap();
- let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&htlc, &keys, htlc.offered);
- let htlc_sighash = Message::from_slice(&bip143::SighashComponents::new(&htlc_tx).sighash_all(&htlc_tx, 0, &htlc_redeemscript, htlc.amount_msat / 1000)[..]).unwrap();
+ let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&htlc, &keys);
+ let htlc_sighash = Message::from_slice(&bip143::SighashComponents::new(&htlc_tx).sighash_all(&htlc_tx.input[0], &htlc_redeemscript, htlc.amount_msat / 1000)[..]).unwrap();
secp_ctx.verify(&htlc_sighash, &remote_signature, &keys.b_htlc_key).unwrap();
let mut preimage: Option<[u8; 32]> = None;