holding_cell_update_fee: Option<u64>,
next_local_htlc_id: u64,
next_remote_htlc_id: u64,
- channel_update_count: u32,
+ update_time_counter: u32,
feerate_per_kw: u64,
#[cfg(debug_assertions)]
cmp::max(at_open_background_feerate * B_OUTPUT_PLUS_SPENDING_INPUT_WEIGHT / 1000, 546) //TODO
}
- fn derive_our_htlc_minimum_msat(_at_open_channel_feerate_per_kw: u64) -> u64 {
- 1000 // TODO
- }
-
// Constructors:
pub fn new_outbound<K: Deref, F: Deref>(fee_estimator: &F, keys_provider: &K, their_node_id: PublicKey, channel_value_satoshis: u64, push_msat: u64, user_id: u64, logger: Arc<Logger>, config: &UserConfig) -> Result<Channel<ChanSigner>, APIError>
where K::Target: KeysInterface<ChanKeySigner = ChanSigner>,
holding_cell_update_fee: None,
next_local_htlc_id: 0,
next_remote_htlc_id: 0,
- channel_update_count: 1,
+ update_time_counter: 1,
resend_order: RAACommitmentOrder::CommitmentFirst,
their_max_htlc_value_in_flight_msat: 0,
their_channel_reserve_satoshis: 0,
their_htlc_minimum_msat: 0,
- our_htlc_minimum_msat: Channel::<ChanSigner>::derive_our_htlc_minimum_msat(feerate),
+ our_htlc_minimum_msat: if config.own_channel_config.our_htlc_minimum_msat == 0 { 1 } else { config.own_channel_config.our_htlc_minimum_msat },
their_to_self_delay: 0,
our_to_self_delay: config.own_channel_config.our_to_self_delay,
their_max_accepted_htlcs: 0,
holding_cell_update_fee: None,
next_local_htlc_id: 0,
next_remote_htlc_id: 0,
- channel_update_count: 1,
+ update_time_counter: 1,
resend_order: RAACommitmentOrder::CommitmentFirst,
their_max_htlc_value_in_flight_msat: cmp::min(msg.max_htlc_value_in_flight_msat, msg.funding_satoshis * 1000),
their_channel_reserve_satoshis: msg.channel_reserve_satoshis,
their_htlc_minimum_msat: msg.htlc_minimum_msat,
- our_htlc_minimum_msat: Channel::<ChanSigner>::derive_our_htlc_minimum_msat(msg.feerate_per_kw as u64),
+ our_htlc_minimum_msat: if config.own_channel_config.our_htlc_minimum_msat == 0 { 1 } else { config.own_channel_config.our_htlc_minimum_msat },
their_to_self_delay: msg.to_self_delay,
our_to_self_delay: config.own_channel_config.our_to_self_delay,
their_max_accepted_htlcs: msg.max_accepted_htlcs,
}
/// Per HTLC, only one get_update_fail_htlc or get_update_fulfill_htlc call may be made.
- /// In such cases we debug_assert!(false) and return an IgnoreError. Thus, will always return
- /// Ok(_) if debug assertions are turned on and preconditions are met.
+ /// In such cases we debug_assert!(false) and return a ChannelError::Ignore. Thus, will always
+ /// return Ok(_) if debug assertions are turned on or preconditions are met.
+ ///
+ /// Note that it is still possible to hit these assertions in case we find a preimage on-chain
+ /// but then have a reorg which settles on an HTLC-failure on chain.
fn get_update_fulfill_htlc(&mut self, htlc_id_arg: u64, payment_preimage_arg: PaymentPreimage) -> Result<(Option<msgs::UpdateFulfillHTLC>, Option<ChannelMonitorUpdate>), ChannelError> {
// Either ChannelFunded got set (which means it won't be unset) or there is no way any
// caller thought we could have something claimed (cause we wouldn't have accepted in an
} else {
log_warn!(self, "Have preimage and want to fulfill HTLC with payment hash {} we already failed against channel {}", log_bytes!(htlc.payment_hash.0), log_bytes!(self.channel_id()));
}
+ debug_assert!(false, "Tried to fulfill an HTLC that was already fail/fulfilled");
return Ok((None, None));
},
_ => {
match pending_update {
&HTLCUpdateAwaitingACK::ClaimHTLC { htlc_id, .. } => {
if htlc_id_arg == htlc_id {
+ // Make sure we don't leave latest_monitor_update_id incremented here:
+ self.latest_monitor_update_id -= 1;
+ debug_assert!(false, "Tried to fulfill an HTLC that was already fulfilled");
return Ok((None, None));
}
},
log_warn!(self, "Have preimage and want to fulfill HTLC with pending failure against channel {}", log_bytes!(self.channel_id()));
// TODO: We may actually be able to switch to a fulfill here, though its
// rare enough it may not be worth the complexity burden.
+ debug_assert!(false, "Tried to fulfill an HTLC that was already failed");
return Ok((None, Some(monitor_update)));
}
},
}
/// Per HTLC, only one get_update_fail_htlc or get_update_fulfill_htlc call may be made.
- /// In such cases we debug_assert!(false) and return an IgnoreError. Thus, will always return
- /// Ok(_) if debug assertions are turned on and preconditions are met.
+ /// In such cases we debug_assert!(false) and return a ChannelError::Ignore. Thus, will always
+ /// return Ok(_) if debug assertions are turned on or preconditions are met.
+ ///
+ /// Note that it is still possible to hit these assertions in case we find a preimage on-chain
+ /// but then have a reorg which settles on an HTLC-failure on chain.
pub fn get_update_fail_htlc(&mut self, htlc_id_arg: u64, err_packet: msgs::OnionErrorPacket) -> Result<Option<msgs::UpdateFailHTLC>, ChannelError> {
if (self.channel_state & (ChannelState::ChannelFunded as u32)) != (ChannelState::ChannelFunded as u32) {
panic!("Was asked to fail an HTLC when channel was not in an operational state");
match htlc.state {
InboundHTLCState::Committed => {},
InboundHTLCState::LocalRemoved(_) => {
+ debug_assert!(false, "Tried to fail an HTLC that was already fail/fulfilled");
return Ok(None);
},
_ => {
match pending_update {
&HTLCUpdateAwaitingACK::ClaimHTLC { htlc_id, .. } => {
if htlc_id_arg == htlc_id {
+ debug_assert!(false, "Tried to fail an HTLC that was already fulfilled");
return Err(ChannelError::Ignore("Unable to find a pending HTLC which matched the given HTLC ID"));
}
},
&HTLCUpdateAwaitingACK::FailHTLC { htlc_id, .. } => {
if htlc_id_arg == htlc_id {
+ debug_assert!(false, "Tried to fail an HTLC that was already failed");
return Err(ChannelError::Ignore("Unable to find a pending HTLC which matched the given HTLC ID"));
}
},
self.channel_state |= ChannelState::TheirFundingLocked as u32;
} else if non_shutdown_state == (ChannelState::FundingSent as u32 | ChannelState::OurFundingLocked as u32) {
self.channel_state = ChannelState::ChannelFunded as u32 | (self.channel_state & MULTI_STATE_FLAGS);
- self.channel_update_count += 1;
+ self.update_time_counter += 1;
} else if (self.channel_state & (ChannelState::ChannelFunded as u32) != 0 &&
// Note that funding_signed/funding_created will have decremented both by 1!
self.cur_local_commitment_transaction_number == INITIAL_COMMITMENT_NUMBER - 1 &&
if msg.amount_msat > self.channel_value_satoshis * 1000 {
return Err(ChannelError::Close("Remote side tried to send more than the total value of the channel"));
}
+ if msg.amount_msat == 0 {
+ return Err(ChannelError::Close("Remote side tried to send a 0-msat HTLC"));
+ }
if msg.amount_msat < self.our_htlc_minimum_msat {
return Err(ChannelError::Close("Remote side tried to send less than our minimum HTLC value"));
}
}
Channel::<ChanSigner>::check_remote_fee(fee_estimator, msg.feerate_per_kw)?;
self.pending_update_fee = Some(msg.feerate_per_kw as u64);
- self.channel_update_count += 1;
+ self.update_time_counter += 1;
Ok(())
}
// From here on out, we may not fail!
self.channel_state |= ChannelState::RemoteShutdownSent as u32;
- self.channel_update_count += 1;
+ self.update_time_counter += 1;
// 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
};
self.channel_state |= ChannelState::LocalShutdownSent as u32;
- self.channel_update_count += 1;
+ self.update_time_counter += 1;
Ok((our_shutdown, self.maybe_propose_first_closing_signed(fee_estimator), dropped_outbound_htlcs))
}
if last_fee == msg.fee_satoshis {
self.build_signed_closing_transaction(&mut closing_tx, &msg.signature, &our_sig);
self.channel_state = ChannelState::ShutdownComplete as u32;
- self.channel_update_count += 1;
+ self.update_time_counter += 1;
return Ok((None, Some(closing_tx)));
}
}
self.build_signed_closing_transaction(&mut closing_tx, &msg.signature, &our_sig);
self.channel_state = ChannelState::ShutdownComplete as u32;
- self.channel_update_count += 1;
+ self.update_time_counter += 1;
Ok((Some(msgs::ClosingSigned {
channel_id: self.channel_id,
}
/// Allowed in any state (including after shutdown)
- pub fn get_channel_update_count(&self) -> u32 {
- self.channel_update_count
+ pub fn get_update_time_counter(&self) -> u32 {
+ self.update_time_counter
}
pub fn get_latest_monitor_update_id(&self) -> u64 {
panic!("Client called ChannelManager::funding_transaction_generated with bogus transaction!");
}
self.channel_state = ChannelState::ShutdownComplete as u32;
- self.channel_update_count += 1;
+ self.update_time_counter += 1;
return Err(msgs::ErrorMessage {
channel_id: self.channel_id(),
data: "funding tx had wrong script/value".to_owned()
}
if header.bitcoin_hash() != self.last_block_connected {
self.last_block_connected = header.bitcoin_hash();
+ self.update_time_counter = cmp::max(self.update_time_counter, header.time);
if let Some(channel_monitor) = self.channel_monitor.as_mut() {
channel_monitor.last_block_hash = self.last_block_connected;
}
true
} else if non_shutdown_state == (ChannelState::FundingSent as u32 | ChannelState::TheirFundingLocked as u32) {
self.channel_state = ChannelState::ChannelFunded as u32 | (self.channel_state & MULTI_STATE_FLAGS);
- self.channel_update_count += 1;
+ self.update_time_counter += 1;
true
} else if non_shutdown_state == (ChannelState::FundingSent as u32 | ChannelState::OurFundingLocked as u32) {
// We got a reorg but not enough to trigger a force close, just update
my_current_per_commitment_point: PublicKey::from_secret_key(&self.secp_ctx, &self.build_local_commitment_secret(self.cur_local_commitment_transaction_number + 1))
})
} else {
- log_debug!(self, "We don't seen yet any revoked secret, if this channnel has already been updated it means we are fallen-behind, you should wait for other peer closing");
+ log_info!(self, "Sending a data_loss_protect with no previous remote per_commitment_secret");
OptionalField::Present(DataLossProtect {
your_last_per_commitment_secret: [0;32],
- my_current_per_commitment_point: PublicKey::from_secret_key(&self.secp_ctx, &self.build_local_commitment_secret(self.cur_local_commitment_transaction_number))
+ my_current_per_commitment_point: PublicKey::from_secret_key(&self.secp_ctx, &self.build_local_commitment_secret(self.cur_local_commitment_transaction_number + 1))
})
};
msgs::ChannelReestablish {
if amount_msat > self.channel_value_satoshis * 1000 {
return Err(ChannelError::Ignore("Cannot send more than the total value of the channel"));
}
+
+ if amount_msat == 0 {
+ return Err(ChannelError::Ignore("Cannot send 0-msat HTLC"));
+ }
+
if amount_msat < self.their_htlc_minimum_msat {
return Err(ChannelError::Ignore("Cannot send less than their minimum HTLC value"));
}
} else {
self.channel_state |= ChannelState::LocalShutdownSent as u32;
}
- self.channel_update_count += 1;
+ self.update_time_counter += 1;
// Go ahead and drop holding cell updates as we'd rather fail payments than wait to send
// our shutdown until we've committed all of the pending changes.
/// those explicitly stated to be allowed after shutdown completes, eg some simple getters).
/// Also returns the list of payment_hashes for channels which we can safely fail backwards
/// immediately (others we will have to allow to time out).
- pub fn force_shutdown(&mut self) -> (Vec<Transaction>, Vec<(HTLCSource, PaymentHash)>) {
+ pub fn force_shutdown(&mut self, should_broadcast: bool) -> (Option<OutPoint>, ChannelMonitorUpdate, Vec<(HTLCSource, PaymentHash)>) {
assert!(self.channel_state != ChannelState::ShutdownComplete as u32);
// We go ahead and "free" any holding cell HTLCs or HTLCs we haven't yet committed to and
}
self.channel_state = ChannelState::ShutdownComplete as u32;
- self.channel_update_count += 1;
- if self.channel_monitor.is_some() {
- (self.channel_monitor.as_mut().unwrap().get_latest_local_commitment_txn(), dropped_outbound_htlcs)
- } else {
- // We aren't even signed funding yet, so can't broadcast anything
- (Vec::new(), dropped_outbound_htlcs)
- }
+ self.update_time_counter += 1;
+ self.latest_monitor_update_id += 1;
+ (self.funding_txo.clone(), ChannelMonitorUpdate {
+ update_id: self.latest_monitor_update_id,
+ updates: vec![ChannelMonitorUpdateStep::ChannelForceClosed { should_broadcast }],
+ }, dropped_outbound_htlcs)
}
}
}
}
-impl<R: ::std::io::Read> Readable<R> for InboundHTLCRemovalReason {
- fn read(reader: &mut R) -> Result<Self, DecodeError> {
- Ok(match <u8 as Readable<R>>::read(reader)? {
+impl Readable for InboundHTLCRemovalReason {
+ fn read<R: ::std::io::Read>(reader: &mut R) -> Result<Self, DecodeError> {
+ Ok(match <u8 as Readable>::read(reader)? {
0 => InboundHTLCRemovalReason::FailRelay(Readable::read(reader)?),
1 => InboundHTLCRemovalReason::FailMalformed((Readable::read(reader)?, Readable::read(reader)?)),
2 => InboundHTLCRemovalReason::Fulfill(Readable::read(reader)?),
}
}
- macro_rules! write_option {
- ($thing: expr) => {
- match &$thing {
- &None => 0u8.write(writer)?,
- &Some(ref v) => {
- 1u8.write(writer)?;
- v.write(writer)?;
- },
- }
- }
- }
-
(self.pending_outbound_htlcs.len() as u64).write(writer)?;
for htlc in self.pending_outbound_htlcs.iter() {
htlc.htlc_id.write(writer)?;
},
&OutboundHTLCState::RemoteRemoved(ref fail_reason) => {
2u8.write(writer)?;
- write_option!(*fail_reason);
+ fail_reason.write(writer)?;
},
&OutboundHTLCState::AwaitingRemoteRevokeToRemove(ref fail_reason) => {
3u8.write(writer)?;
- write_option!(*fail_reason);
+ fail_reason.write(writer)?;
},
&OutboundHTLCState::AwaitingRemovedRemoteRevoke(ref fail_reason) => {
4u8.write(writer)?;
- write_option!(*fail_reason);
+ fail_reason.write(writer)?;
},
}
}
fail_reason.write(writer)?;
}
- write_option!(self.pending_update_fee);
- write_option!(self.holding_cell_update_fee);
+ self.pending_update_fee.write(writer)?;
+ self.holding_cell_update_fee.write(writer)?;
self.next_local_htlc_id.write(writer)?;
(self.next_remote_htlc_id - dropped_inbound_htlcs).write(writer)?;
- self.channel_update_count.write(writer)?;
+ self.update_time_counter.write(writer)?;
self.feerate_per_kw.write(writer)?;
match self.last_sent_closing_fee {
None => 0u8.write(writer)?,
}
- write_option!(self.funding_txo);
- write_option!(self.funding_tx_confirmed_in);
- write_option!(self.short_channel_id);
+ self.funding_txo.write(writer)?;
+ self.funding_tx_confirmed_in.write(writer)?;
+ self.short_channel_id.write(writer)?;
self.last_block_connected.write(writer)?;
self.funding_tx_confirmations.write(writer)?;
self.their_max_accepted_htlcs.write(writer)?;
self.minimum_depth.write(writer)?;
- write_option!(self.their_pubkeys);
- write_option!(self.their_cur_commitment_point);
+ self.their_pubkeys.write(writer)?;
+ self.their_cur_commitment_point.write(writer)?;
- write_option!(self.their_prev_commitment_point);
+ self.their_prev_commitment_point.write(writer)?;
self.their_node_id.write(writer)?;
- write_option!(self.their_shutdown_scriptpubkey);
+ self.their_shutdown_scriptpubkey.write(writer)?;
self.commitment_secrets.write(writer)?;
}
}
-impl<R : ::std::io::Read, ChanSigner: ChannelKeys + Readable<R>> ReadableArgs<R, Arc<Logger>> for Channel<ChanSigner> {
- fn read(reader: &mut R, logger: Arc<Logger>) -> Result<Self, DecodeError> {
+impl<ChanSigner: ChannelKeys + Readable> ReadableArgs<Arc<Logger>> for Channel<ChanSigner> {
+ fn read<R : ::std::io::Read>(reader: &mut R, logger: Arc<Logger>) -> Result<Self, DecodeError> {
let _ver: u8 = Readable::read(reader)?;
let min_ver: u8 = Readable::read(reader)?;
if min_ver > SERIALIZATION_VERSION {
amount_msat: Readable::read(reader)?,
cltv_expiry: Readable::read(reader)?,
payment_hash: Readable::read(reader)?,
- state: match <u8 as Readable<R>>::read(reader)? {
+ state: match <u8 as Readable>::read(reader)? {
1 => InboundHTLCState::AwaitingRemoteRevokeToAnnounce(Readable::read(reader)?),
2 => InboundHTLCState::AwaitingAnnouncedRemoteRevoke(Readable::read(reader)?),
3 => InboundHTLCState::Committed,
cltv_expiry: Readable::read(reader)?,
payment_hash: Readable::read(reader)?,
source: Readable::read(reader)?,
- state: match <u8 as Readable<R>>::read(reader)? {
+ state: match <u8 as Readable>::read(reader)? {
0 => OutboundHTLCState::LocalAnnounced(Box::new(Readable::read(reader)?)),
1 => OutboundHTLCState::Committed,
2 => OutboundHTLCState::RemoteRemoved(Readable::read(reader)?),
let holding_cell_htlc_update_count: u64 = Readable::read(reader)?;
let mut holding_cell_htlc_updates = Vec::with_capacity(cmp::min(holding_cell_htlc_update_count as usize, OUR_MAX_HTLCS as usize*2));
for _ in 0..holding_cell_htlc_update_count {
- holding_cell_htlc_updates.push(match <u8 as Readable<R>>::read(reader)? {
+ holding_cell_htlc_updates.push(match <u8 as Readable>::read(reader)? {
0 => HTLCUpdateAwaitingACK::AddHTLC {
amount_msat: Readable::read(reader)?,
cltv_expiry: Readable::read(reader)?,
});
}
- let resend_order = match <u8 as Readable<R>>::read(reader)? {
+ let resend_order = match <u8 as Readable>::read(reader)? {
0 => RAACommitmentOrder::CommitmentFirst,
1 => RAACommitmentOrder::RevokeAndACKFirst,
_ => return Err(DecodeError::InvalidValue),
let next_local_htlc_id = Readable::read(reader)?;
let next_remote_htlc_id = Readable::read(reader)?;
- let channel_update_count = Readable::read(reader)?;
+ let update_time_counter = Readable::read(reader)?;
let feerate_per_kw = Readable::read(reader)?;
- let last_sent_closing_fee = match <u8 as Readable<R>>::read(reader)? {
+ let last_sent_closing_fee = match <u8 as Readable>::read(reader)? {
0 => None,
1 => Some((Readable::read(reader)?, Readable::read(reader)?, Readable::read(reader)?)),
_ => return Err(DecodeError::InvalidValue),
holding_cell_update_fee,
next_local_htlc_id,
next_remote_htlc_id,
- channel_update_count,
+ update_time_counter,
feerate_per_kw,
#[cfg(debug_assertions)]
#[cfg(test)]
mod tests {
+ use bitcoin::BitcoinHash;
use bitcoin::util::bip143;
use bitcoin::consensus::encode::serialize;
use bitcoin::blockdata::script::{Script, Builder};
- use bitcoin::blockdata::transaction::Transaction;
+ use bitcoin::blockdata::transaction::{Transaction, TxOut};
+ use bitcoin::blockdata::constants::genesis_block;
use bitcoin::blockdata::opcodes;
+ use bitcoin::network::constants::Network;
use bitcoin_hashes::hex::FromHex;
use hex;
use ln::channelmanager::{HTLCSource, PaymentPreimage, PaymentHash};
use ln::channel::{Channel,ChannelKeys,InboundHTLCOutput,OutboundHTLCOutput,InboundHTLCState,OutboundHTLCState,HTLCOutputInCommitment,TxCreationKeys};
use ln::channel::MAX_FUNDING_SATOSHIS;
+ use ln::features::InitFeatures;
+ use ln::msgs::{OptionalField, DataLossProtect};
use ln::chan_utils;
use ln::chan_utils::{LocalCommitmentTransaction, ChannelPublicKeys};
use chain::chaininterface::{FeeEstimator,ConfirmationTarget};
use chain::keysinterface::{InMemoryChannelKeys, KeysInterface};
use chain::transaction::OutPoint;
use util::config::UserConfig;
+ use util::enforcing_trait_impls::EnforcingChannelKeys;
use util::test_utils;
use util::logger::Logger;
use secp256k1::{Secp256k1, Message, Signature, All};
use bitcoin_hashes::hash160::Hash as Hash160;
use bitcoin_hashes::Hash;
use std::sync::Arc;
+ use rand::{thread_rng,Rng};
struct TestFeeEstimator {
fee_est: u64
PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&hex::decode(hex).unwrap()[..]).unwrap())
}
+ #[test]
+ fn channel_reestablish_no_updates() {
+ let feeest = TestFeeEstimator{fee_est: 15000};
+ let logger : Arc<Logger> = Arc::new(test_utils::TestLogger::new());
+ let secp_ctx = Secp256k1::new();
+ let mut seed = [0; 32];
+ let mut rng = thread_rng();
+ rng.fill_bytes(&mut seed);
+ let network = Network::Testnet;
+ let keys_provider = test_utils::TestKeysInterface::new(&seed, network, logger.clone() as Arc<Logger>);
+
+ // Go through the flow of opening a channel between two nodes.
+
+ // Create Node A's channel
+ let node_a_node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap());
+ let config = UserConfig::default();
+ let mut node_a_chan = Channel::<EnforcingChannelKeys>::new_outbound(&&feeest, &&keys_provider, node_a_node_id, 10000000, 100000, 42, Arc::clone(&logger), &config).unwrap();
+
+ // Create Node B's channel by receiving Node A's open_channel message
+ let open_channel_msg = node_a_chan.get_open_channel(genesis_block(network).header.bitcoin_hash(), &&feeest);
+ let node_b_node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[7; 32]).unwrap());
+ let mut node_b_chan = Channel::<EnforcingChannelKeys>::new_from_req(&&feeest, &&keys_provider, node_b_node_id, InitFeatures::supported(), &open_channel_msg, 7, logger, &config).unwrap();
+
+ // Node B --> Node A: accept channel
+ let accept_channel_msg = node_b_chan.get_accept_channel();
+ node_a_chan.accept_channel(&accept_channel_msg, &config, InitFeatures::supported()).unwrap();
+
+ // Node A --> Node B: funding created
+ let output_script = node_a_chan.get_funding_redeemscript();
+ let tx = Transaction { version: 1, lock_time: 0, input: Vec::new(), output: vec![TxOut {
+ value: 10000000, script_pubkey: output_script.clone(),
+ }]};
+ let funding_outpoint = OutPoint::new(tx.txid(), 0);
+ let (funding_created_msg, _) = node_a_chan.get_outbound_funding_created(funding_outpoint).unwrap();
+ let (funding_signed_msg, _) = node_b_chan.funding_created(&funding_created_msg).unwrap();
+
+ // Node B --> Node A: funding signed
+ let _ = node_a_chan.funding_signed(&funding_signed_msg);
+
+ // Now disconnect the two nodes and check that the commitment point in
+ // Node B's channel_reestablish message is sane.
+ node_b_chan.remove_uncommitted_htlcs_and_mark_paused();
+ let expected_commitment_point = PublicKey::from_secret_key(&secp_ctx, &node_b_chan.build_local_commitment_secret(node_b_chan.cur_local_commitment_transaction_number + 1));
+ let msg = node_b_chan.get_channel_reestablish();
+ match msg.data_loss_protect {
+ OptionalField::Present(DataLossProtect { my_current_per_commitment_point, .. }) => {
+ assert_eq!(expected_commitment_point, my_current_per_commitment_point);
+ },
+ _ => panic!()
+ }
+
+ // Check that the commitment point in Node A's channel_reestablish message
+ // is sane.
+ node_a_chan.remove_uncommitted_htlcs_and_mark_paused();
+ let expected_commitment_point = PublicKey::from_secret_key(&secp_ctx, &node_a_chan.build_local_commitment_secret(node_a_chan.cur_local_commitment_transaction_number + 1));
+ let msg = node_a_chan.get_channel_reestablish();
+ match msg.data_loss_protect {
+ OptionalField::Present(DataLossProtect { my_current_per_commitment_point, .. }) => {
+ assert_eq!(expected_commitment_point, my_current_per_commitment_point);
+ },
+ _ => panic!()
+ }
+ }
+
#[test]
fn outbound_commitment_test() {
// Test vectors from BOLT 3 Appendix C:
let logger : Arc<Logger> = Arc::new(test_utils::TestLogger::new());
let secp_ctx = Secp256k1::new();
- let chan_keys = InMemoryChannelKeys::new(
+ let mut chan_keys = InMemoryChannelKeys::new(
&secp_ctx,
SecretKey::from_slice(&hex::decode("30ff4956bbdd3222d44cc5e8a1261dab1e07957bdac5ae88fe3261ef321f3749").unwrap()[..]).unwrap(),
SecretKey::from_slice(&hex::decode("0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()[..]).unwrap(),
// These aren't set in the test vectors:
[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff],
- 7000000000,
+ 10_000_000,
);
assert_eq!(PublicKey::from_secret_key(&secp_ctx, chan_keys.funding_key()).serialize()[..],
hex::decode("023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb").unwrap()[..]);
- let keys_provider = Keys { chan_keys };
+ let keys_provider = Keys { chan_keys: chan_keys.clone() };
let their_node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap());
let mut config = UserConfig::default();
config.channel_options.announced_channel = false;
- let mut chan = Channel::<InMemoryChannelKeys>::new_outbound(&&feeest, &&keys_provider, their_node_id, 10000000, 100000, 42, Arc::clone(&logger), &config).unwrap(); // Nothing uses their network key in this test
+ let mut chan = Channel::<InMemoryChannelKeys>::new_outbound(&&feeest, &&keys_provider, their_node_id, 10_000_000, 100000, 42, Arc::clone(&logger), &config).unwrap(); // Nothing uses their network key in this test
chan.their_to_self_delay = 144;
chan.our_dust_limit_satoshis = 546;
delayed_payment_basepoint: public_from_secret_hex(&secp_ctx, "1552dfba4f6cf29a62a0af13c8d6981d36d0ef8d61ba10fb0fe90da7634d7e13"),
htlc_basepoint: public_from_secret_hex(&secp_ctx, "4444444444444444444444444444444444444444444444444444444444444444")
};
+ chan_keys.set_remote_channel_pubkeys(&their_pubkeys);
assert_eq!(their_pubkeys.payment_basepoint.serialize()[..],
hex::decode("032c0b7cf95324a07d05398b240174dc0c2be444d96b159aa6c7f7b1e668680991").unwrap()[..]);
let mut unsigned_tx: (Transaction, Vec<HTLCOutputInCommitment>);
+ let mut localtx;
macro_rules! test_commitment {
( $their_sig_hex: expr, $our_sig_hex: expr, $tx_hex: expr) => {
unsigned_tx = {
let sighash = Message::from_slice(&bip143::SighashComponents::new(&unsigned_tx.0).sighash_all(&unsigned_tx.0.input[0], &redeemscript, chan.channel_value_satoshis)[..]).unwrap();
secp_ctx.verify(&sighash, &their_signature, chan.their_funding_pubkey()).unwrap();
- let mut localtx = LocalCommitmentTransaction::new_missing_local_sig(unsigned_tx.0.clone(), &their_signature, &PublicKey::from_secret_key(&secp_ctx, chan.local_keys.funding_key()), chan.their_funding_pubkey());
- localtx.add_local_sig(chan.local_keys.funding_key(), &redeemscript, chan.channel_value_satoshis, &chan.secp_ctx);
+ localtx = LocalCommitmentTransaction::new_missing_local_sig(unsigned_tx.0.clone(), &their_signature, &PublicKey::from_secret_key(&secp_ctx, chan.local_keys.funding_key()), chan.their_funding_pubkey());
+ chan_keys.sign_local_commitment(&mut localtx, &chan.secp_ctx);
assert_eq!(serialize(localtx.with_valid_witness())[..],
hex::decode($tx_hex).unwrap()[..]);
}
macro_rules! test_htlc_output {
- ( $htlc_idx: expr, $their_sig_hex: expr, $our_sig_hex: expr, $tx_hex: expr ) => {
+ ( $htlc_idx: expr, $their_sig_hex: expr, $our_sig_hex: expr, $tx_hex: expr) => {
let remote_signature = Signature::from_der(&hex::decode($their_sig_hex).unwrap()[..]).unwrap();
let ref htlc = unsigned_tx.1[$htlc_idx];
- let mut htlc_tx = chan.build_htlc_transaction(&unsigned_tx.0.txid(), &htlc, true, &keys, chan.feerate_per_kw);
+ let htlc_tx = chan.build_htlc_transaction(&unsigned_tx.0.txid(), &htlc, true, &keys, chan.feerate_per_kw);
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();
assert!(preimage.is_some());
}
- chan_utils::sign_htlc_transaction(&mut htlc_tx, &remote_signature, &preimage, &htlc, &keys.a_htlc_key, &keys.b_htlc_key, &keys.revocation_key, &keys.per_commitment_point, chan.local_keys.htlc_base_key(), &chan.secp_ctx).unwrap();
- assert_eq!(serialize(&htlc_tx)[..],
+ let mut per_htlc = Vec::new();
+ per_htlc.push((htlc.clone(), Some(remote_signature), None));
+ localtx.set_htlc_cache(keys.clone(), chan.feerate_per_kw, per_htlc);
+ chan_keys.sign_htlc_transaction(&mut localtx, $htlc_idx, preimage, chan.their_to_self_delay, &chan.secp_ctx);
+
+ assert_eq!(serialize(localtx.htlc_with_valid_witness($htlc_idx).as_ref().unwrap())[..],
hex::decode($tx_hex).unwrap()[..]);
};
}