use crate::chain::chaininterface::{FeeEstimator, ConfirmationTarget, LowerBoundedFeeEstimator};
use crate::chain::channelmonitor::{ChannelMonitor, ChannelMonitorUpdate, ChannelMonitorUpdateStep, LATENCY_GRACE_PERIOD_BLOCKS};
use crate::chain::transaction::{OutPoint, TransactionData};
-use crate::chain::keysinterface::{Sign, KeysInterface};
+use crate::chain::keysinterface::{Sign, KeysInterface, BaseSign};
use crate::util::events::ClosureReason;
use crate::util::ser::{Readable, ReadableArgs, Writeable, Writer, VecWriter};
use crate::util::logger::Logger;
pub raa: Option<msgs::RevokeAndACK>,
pub commitment_update: Option<msgs::CommitmentUpdate>,
pub order: RAACommitmentOrder,
- pub mon_update: Option<ChannelMonitorUpdate>,
- pub holding_cell_failed_htlcs: Vec<(HTLCSource, PaymentHash)>,
pub announcement_sigs: Option<msgs::AnnouncementSignatures>,
pub shutdown_msg: Option<msgs::Shutdown>,
}
// We track whether we already emitted a `ChannelReady` event.
channel_ready_event_emitted: bool,
+
+ /// The unique identifier used to re-derive the private key material for the channel through
+ /// [`KeysInterface::derive_channel_signer`].
+ channel_keys_id: [u8; 32],
}
#[cfg(any(test, fuzzing))]
let opt_anchors = false; // TODO - should be based on features
let holder_selected_contest_delay = config.channel_handshake_config.our_to_self_delay;
- let holder_signer = keys_provider.get_channel_signer(false, channel_value_satoshis);
+ let channel_keys_id = keys_provider.generate_channel_keys_id(false, channel_value_satoshis, user_id);
+ let holder_signer = keys_provider.derive_channel_signer(channel_value_satoshis, channel_keys_id);
let pubkeys = holder_signer.pubkeys().clone();
if !their_features.supports_wumbo() && channel_value_satoshis > MAX_FUNDING_SATOSHIS_NO_WUMBO {
counterparty_parameters: None,
funding_outpoint: None,
opt_anchors: if opt_anchors { Some(()) } else { None },
+ opt_non_zero_fee_anchors: None
},
funding_transaction: None,
historical_inbound_htlc_fulfills: HashSet::new(),
channel_type: Self::get_initial_channel_type(&config),
+ channel_keys_id,
})
}
return Err(ChannelError::Close("Channel Type was not understood - we require static remote key".to_owned()));
}
- let holder_signer = keys_provider.get_channel_signer(true, msg.funding_satoshis);
+ let channel_keys_id = keys_provider.generate_channel_keys_id(true, msg.funding_satoshis, user_id);
+ let holder_signer = keys_provider.derive_channel_signer(msg.funding_satoshis, channel_keys_id);
let pubkeys = holder_signer.pubkeys().clone();
let counterparty_pubkeys = ChannelPublicKeys {
funding_pubkey: msg.funding_pubkey,
}),
funding_outpoint: None,
opt_anchors: if opt_anchors { Some(()) } else { None },
+ opt_non_zero_fee_anchors: None
},
funding_transaction: None,
historical_inbound_htlc_fulfills: HashSet::new(),
channel_type,
+ channel_keys_id,
};
Ok(chan)
&self.get_counterparty_pubkeys().funding_pubkey
}
- pub fn funding_created<L: Deref>(&mut self, msg: &msgs::FundingCreated, best_block: BestBlock, logger: &L) -> Result<(msgs::FundingSigned, ChannelMonitor<Signer>, Option<msgs::ChannelReady>), ChannelError> where L::Target: Logger {
+ pub fn funding_created<K: Deref, L: Deref>(
+ &mut self, msg: &msgs::FundingCreated, best_block: BestBlock, keys_source: &K, logger: &L
+ ) -> Result<(msgs::FundingSigned, ChannelMonitor<<K::Target as KeysInterface>::Signer>, Option<msgs::ChannelReady>), ChannelError>
+ where
+ K::Target: KeysInterface,
+ L::Target: Logger
+ {
if self.is_outbound() {
return Err(ChannelError::Close("Received funding_created for an outbound channel?".to_owned()));
}
self.channel_transaction_parameters.funding_outpoint = Some(funding_txo);
// This is an externally observable change before we finish all our checks. In particular
// funding_created_signature may fail.
- self.holder_signer.ready_channel(&self.channel_transaction_parameters);
+ self.holder_signer.provide_channel_parameters(&self.channel_transaction_parameters);
let (counterparty_initial_commitment_txid, initial_commitment_tx, signature) = match self.funding_created_signature(&msg.signature, logger) {
Ok(res) => res,
let funding_txo_script = funding_redeemscript.to_v0_p2wsh();
let obscure_factor = get_commitment_transaction_number_obscure_factor(&self.get_holder_pubkeys().payment_point, &self.get_counterparty_pubkeys().payment_point, self.is_outbound());
let shutdown_script = self.shutdown_scriptpubkey.clone().map(|script| script.into_inner());
- let channel_monitor = ChannelMonitor::new(self.secp_ctx.clone(), self.holder_signer.clone(),
+ let mut monitor_signer = keys_source.derive_channel_signer(self.channel_value_satoshis, self.channel_keys_id);
+ monitor_signer.provide_channel_parameters(&self.channel_transaction_parameters);
+ let channel_monitor = ChannelMonitor::new(self.secp_ctx.clone(), monitor_signer,
shutdown_script, self.get_holder_selected_contest_delay(),
&self.destination_script, (funding_txo, funding_txo_script.clone()),
&self.channel_transaction_parameters,
/// Handles a funding_signed message from the remote end.
/// If this call is successful, broadcast the funding transaction (and not before!)
- pub fn funding_signed<L: Deref>(&mut self, msg: &msgs::FundingSigned, best_block: BestBlock, logger: &L) -> Result<(ChannelMonitor<Signer>, Transaction, Option<msgs::ChannelReady>), ChannelError> where L::Target: Logger {
+ pub fn funding_signed<K: Deref, L: Deref>(
+ &mut self, msg: &msgs::FundingSigned, best_block: BestBlock, keys_source: &K, logger: &L
+ ) -> Result<(ChannelMonitor<<K::Target as KeysInterface>::Signer>, Transaction, Option<msgs::ChannelReady>), ChannelError>
+ where
+ K::Target: KeysInterface,
+ L::Target: Logger
+ {
if !self.is_outbound() {
return Err(ChannelError::Close("Received funding_signed for an inbound channel?".to_owned()));
}
let funding_txo_script = funding_redeemscript.to_v0_p2wsh();
let obscure_factor = get_commitment_transaction_number_obscure_factor(&self.get_holder_pubkeys().payment_point, &self.get_counterparty_pubkeys().payment_point, self.is_outbound());
let shutdown_script = self.shutdown_scriptpubkey.clone().map(|script| script.into_inner());
- let channel_monitor = ChannelMonitor::new(self.secp_ctx.clone(), self.holder_signer.clone(),
+ let mut monitor_signer = keys_source.derive_channel_signer(self.channel_value_satoshis, self.channel_keys_id);
+ monitor_signer.provide_channel_parameters(&self.channel_transaction_parameters);
+ let channel_monitor = ChannelMonitor::new(self.secp_ctx.clone(), monitor_signer,
shutdown_script, self.get_holder_selected_contest_delay(),
&self.destination_script, (funding_txo, funding_txo_script),
&self.channel_transaction_parameters,
if let Some(_) = htlc.transaction_output_index {
let htlc_tx = chan_utils::build_htlc_transaction(&commitment_txid, commitment_stats.feerate_per_kw,
self.get_counterparty_selected_contest_delay().unwrap(), &htlc, self.opt_anchors(),
- &keys.broadcaster_delayed_payment_key, &keys.revocation_key);
+ false, &keys.broadcaster_delayed_payment_key, &keys.revocation_key);
let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&htlc, self.opt_anchors(), &keys);
let htlc_sighashtype = if self.opt_anchors() { EcdsaSighashType::SinglePlusAnyoneCanPay } else { EcdsaSighashType::All };
// Short circuit the whole handler as there is nothing we can resend them
return Ok(ReestablishResponses {
channel_ready: None,
- raa: None, commitment_update: None, mon_update: None,
+ raa: None, commitment_update: None,
order: RAACommitmentOrder::CommitmentFirst,
- holding_cell_failed_htlcs: Vec::new(),
shutdown_msg, announcement_sigs,
});
}
next_per_commitment_point,
short_channel_id_alias: Some(self.outbound_scid_alias),
}),
- raa: None, commitment_update: None, mon_update: None,
+ raa: None, commitment_update: None,
order: RAACommitmentOrder::CommitmentFirst,
- holding_cell_failed_htlcs: Vec::new(),
shutdown_msg, announcement_sigs,
});
}
log_debug!(logger, "Reconnected channel {} with no loss", log_bytes!(self.channel_id()));
}
- if (self.channel_state & (ChannelState::AwaitingRemoteRevoke as u32 | ChannelState::MonitorUpdateInProgress as u32)) == 0 {
- // We're up-to-date and not waiting on a remote revoke (if we are our
- // channel_reestablish should result in them sending a revoke_and_ack), but we may
- // have received some updates while we were disconnected. Free the holding cell
- // now!
- match self.free_holding_cell_htlcs(logger) {
- Err(ChannelError::Close(msg)) => Err(ChannelError::Close(msg)),
- Err(ChannelError::Warn(_)) | Err(ChannelError::Ignore(_)) =>
- panic!("Got non-channel-failing result from free_holding_cell_htlcs"),
- Ok((Some((commitment_update, monitor_update)), holding_cell_failed_htlcs)) => {
- Ok(ReestablishResponses {
- channel_ready, shutdown_msg, announcement_sigs,
- raa: required_revoke,
- commitment_update: Some(commitment_update),
- order: self.resend_order.clone(),
- mon_update: Some(monitor_update),
- holding_cell_failed_htlcs,
- })
- },
- Ok((None, holding_cell_failed_htlcs)) => {
- Ok(ReestablishResponses {
- channel_ready, shutdown_msg, announcement_sigs,
- raa: required_revoke,
- commitment_update: None,
- order: self.resend_order.clone(),
- mon_update: None,
- holding_cell_failed_htlcs,
- })
- },
- }
- } else {
- Ok(ReestablishResponses {
- channel_ready, shutdown_msg, announcement_sigs,
- raa: required_revoke,
- commitment_update: None,
- order: self.resend_order.clone(),
- mon_update: None,
- holding_cell_failed_htlcs: Vec::new(),
- })
- }
+ Ok(ReestablishResponses {
+ channel_ready, shutdown_msg, announcement_sigs,
+ raa: required_revoke,
+ commitment_update: None,
+ order: self.resend_order.clone(),
+ })
} else if msg.next_local_commitment_number == next_counterparty_commitment_number - 1 {
if required_revoke.is_some() {
log_debug!(logger, "Reconnected channel {} with lost outbound RAA and lost remote commitment tx", log_bytes!(self.channel_id()));
self.monitor_pending_commitment_signed = true;
Ok(ReestablishResponses {
channel_ready, shutdown_msg, announcement_sigs,
- commitment_update: None, raa: None, mon_update: None,
+ commitment_update: None, raa: None,
order: self.resend_order.clone(),
- holding_cell_failed_htlcs: Vec::new(),
})
} else {
Ok(ReestablishResponses {
raa: required_revoke,
commitment_update: Some(self.get_last_commitment_update(logger)),
order: self.resend_order.clone(),
- mon_update: None,
- holding_cell_failed_htlcs: Vec::new(),
})
}
} else {
self.funding_tx_confirmed_in
}
+ /// Returns the current number of confirmations on the funding transaction.
+ pub fn get_funding_tx_confirmations(&self, height: u32) -> u32 {
+ if self.funding_tx_confirmation_height == 0 {
+ // We either haven't seen any confirmation yet, or observed a reorg.
+ return 0;
+ }
+
+ height.checked_sub(self.funding_tx_confirmation_height).map_or(0, |c| c + 1)
+ }
+
fn get_holder_selected_contest_delay(&self) -> u16 {
self.channel_transaction_parameters.holder_selected_contest_delay
}
}
self.channel_transaction_parameters.funding_outpoint = Some(funding_txo);
- self.holder_signer.ready_channel(&self.channel_transaction_parameters);
+ self.holder_signer.provide_channel_parameters(&self.channel_transaction_parameters);
let signature = match self.get_outbound_funding_created_signature(logger) {
Ok(res) => res,
for (ref htlc_sig, ref htlc) in htlc_signatures.iter().zip(htlcs) {
log_trace!(logger, "Signed remote HTLC tx {} with redeemscript {} with pubkey {} -> {} in channel {}",
- encode::serialize_hex(&chan_utils::build_htlc_transaction(&counterparty_commitment_txid, commitment_stats.feerate_per_kw, self.get_holder_selected_contest_delay(), htlc, self.opt_anchors(), &counterparty_keys.broadcaster_delayed_payment_key, &counterparty_keys.revocation_key)),
+ encode::serialize_hex(&chan_utils::build_htlc_transaction(&counterparty_commitment_txid, commitment_stats.feerate_per_kw, self.get_holder_selected_contest_delay(), htlc, self.opt_anchors(), false, &counterparty_keys.broadcaster_delayed_payment_key, &counterparty_keys.revocation_key)),
encode::serialize_hex(&chan_utils::get_htlc_redeemscript(&htlc, self.opt_anchors(), &counterparty_keys)),
log_bytes!(counterparty_keys.broadcaster_htlc_key.serialize()),
log_bytes!(htlc_sig.serialize_compact()[..]), log_bytes!(self.channel_id()));
self.update_time_counter += 1;
(monitor_update, dropped_outbound_htlcs)
}
+
+ pub fn inflight_htlc_sources(&self) -> impl Iterator<Item=&HTLCSource> {
+ self.holding_cell_htlc_updates.iter()
+ .flat_map(|htlc_update| {
+ match htlc_update {
+ HTLCUpdateAwaitingACK::AddHTLC { source, .. } => { Some(source) }
+ _ => None
+ }
+ })
+ .chain(self.pending_outbound_htlcs.iter().map(|htlc| &htlc.source))
+ }
}
-const SERIALIZATION_VERSION: u8 = 2;
+const SERIALIZATION_VERSION: u8 = 3;
const MIN_SERIALIZATION_VERSION: u8 = 2;
impl_writeable_tlv_based_enum!(InboundHTLCRemovalReason,;
// Note that we write out as if remove_uncommitted_htlcs_and_mark_paused had just been
// called.
- write_ver_prefix!(writer, SERIALIZATION_VERSION, MIN_SERIALIZATION_VERSION);
+ write_ver_prefix!(writer, MIN_SERIALIZATION_VERSION, MIN_SERIALIZATION_VERSION);
// `user_id` used to be a single u64 value. In order to remain backwards compatible with
// versions prior to 0.0.113, the u128 is serialized as two separate u64 values. We write
(21, self.outbound_scid_alias, required),
(23, channel_ready_event_emitted, option),
(25, user_id_high_opt, option),
+ (27, self.channel_keys_id, required),
});
Ok(())
let latest_monitor_update_id = Readable::read(reader)?;
- let keys_len: u32 = Readable::read(reader)?;
- let mut keys_data = Vec::with_capacity(cmp::min(keys_len as usize, MAX_ALLOC_SIZE));
- while keys_data.len() != keys_len as usize {
- // Read 1KB at a time to avoid accidentally allocating 4GB on corrupted channel keys
- let mut data = [0; 1024];
- let read_slice = &mut data[0..cmp::min(1024, keys_len as usize - keys_data.len())];
- reader.read_exact(read_slice)?;
- keys_data.extend_from_slice(read_slice);
+ let mut keys_data = None;
+ if ver <= 2 {
+ // Read the serialize signer bytes. We'll choose to deserialize them or not based on whether
+ // the `channel_keys_id` TLV is present below.
+ let keys_len: u32 = Readable::read(reader)?;
+ keys_data = Some(Vec::with_capacity(cmp::min(keys_len as usize, MAX_ALLOC_SIZE)));
+ while keys_data.as_ref().unwrap().len() != keys_len as usize {
+ // Read 1KB at a time to avoid accidentally allocating 4GB on corrupted channel keys
+ let mut data = [0; 1024];
+ let read_slice = &mut data[0..cmp::min(1024, keys_len as usize - keys_data.as_ref().unwrap().len())];
+ reader.read_exact(read_slice)?;
+ keys_data.as_mut().unwrap().extend_from_slice(read_slice);
+ }
}
- let holder_signer = keys_source.read_chan_signer(&keys_data)?;
// Read the old serialization for shutdown_pubkey, preferring the TLV field later if set.
let mut shutdown_scriptpubkey = match <PublicKey as Readable>::read(reader) {
let mut channel_ready_event_emitted = None;
let mut user_id_high_opt: Option<u64> = None;
+ let mut channel_keys_id: Option<[u8; 32]> = None;
read_tlv_fields!(reader, {
(0, announcement_sigs, option),
(21, outbound_scid_alias, option),
(23, channel_ready_event_emitted, option),
(25, user_id_high_opt, option),
+ (27, channel_keys_id, option),
});
+ let (channel_keys_id, holder_signer) = if let Some(channel_keys_id) = channel_keys_id {
+ let mut holder_signer = keys_source.derive_channel_signer(channel_value_satoshis, channel_keys_id);
+ // If we've gotten to the funding stage of the channel, populate the signer with its
+ // required channel parameters.
+ let non_shutdown_state = channel_state & (!MULTI_STATE_FLAGS);
+ if non_shutdown_state >= (ChannelState::FundingCreated as u32) {
+ holder_signer.provide_channel_parameters(&channel_parameters);
+ }
+ (channel_keys_id, holder_signer)
+ } else {
+ // `keys_data` can be `None` if we had corrupted data.
+ let keys_data = keys_data.ok_or(DecodeError::InvalidValue)?;
+ let holder_signer = keys_source.read_chan_signer(&keys_data)?;
+ (holder_signer.channel_keys_id(), holder_signer)
+ };
+
if let Some(preimages) = preimages_opt {
let mut iter = preimages.into_iter();
for htlc in pending_outbound_htlcs.iter_mut() {
historical_inbound_htlc_fulfills,
channel_type: channel_type.unwrap(),
+ channel_keys_id,
})
}
}
use crate::ln::chan_utils::{htlc_success_tx_weight, htlc_timeout_tx_weight};
use crate::chain::BestBlock;
use crate::chain::chaininterface::{FeeEstimator, LowerBoundedFeeEstimator, ConfirmationTarget};
- use crate::chain::keysinterface::{InMemorySigner, Recipient, KeyMaterial, KeysInterface};
+ use crate::chain::keysinterface::{BaseSign, InMemorySigner, Recipient, KeyMaterial, KeysInterface};
use crate::chain::transaction::OutPoint;
use crate::util::config::UserConfig;
use crate::util::enforcing_trait_impls::EnforcingSigner;
ShutdownScript::new_p2wpkh_from_pubkey(PublicKey::from_secret_key(&secp_ctx, &channel_close_key))
}
- fn get_channel_signer(&self, _inbound: bool, _channel_value_satoshis: u64) -> InMemorySigner {
+ fn generate_channel_keys_id(&self, _inbound: bool, _channel_value_satoshis: u64, _user_channel_id: u128) -> [u8; 32] {
+ self.signer.channel_keys_id()
+ }
+ fn derive_channel_signer(&self, _channel_value_satoshis: u64, _channel_keys_id: [u8; 32]) -> Self::Signer {
self.signer.clone()
}
fn get_secure_random_bytes(&self) -> [u8; 32] { [0; 32] }
}]};
let funding_outpoint = OutPoint{ txid: tx.txid(), index: 0 };
let funding_created_msg = node_a_chan.get_outbound_funding_created(tx.clone(), funding_outpoint, &&logger).unwrap();
- let (funding_signed_msg, _, _) = node_b_chan.funding_created(&funding_created_msg, best_block, &&logger).unwrap();
+ let (funding_signed_msg, _, _) = node_b_chan.funding_created(&funding_created_msg, best_block, &&keys_provider, &&logger).unwrap();
// Node B --> Node A: funding signed
- let _ = node_a_chan.funding_signed(&funding_signed_msg, best_block, &&logger);
+ let _ = node_a_chan.funding_signed(&funding_signed_msg, best_block, &&keys_provider, &&logger);
// Now disconnect the two nodes and check that the commitment point in
// Node B's channel_reestablish message is sane.
// 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],
10_000_000,
- [0; 32]
+ [0; 32],
);
assert_eq!(signer.pubkeys().funding_pubkey.serialize()[..],
selected_contest_delay: 144
});
chan.channel_transaction_parameters.funding_outpoint = Some(funding_info);
- signer.ready_channel(&chan.channel_transaction_parameters);
+ signer.provide_channel_parameters(&chan.channel_transaction_parameters);
assert_eq!(counterparty_pubkeys.payment_point.serialize()[..],
hex::decode("032c0b7cf95324a07d05398b240174dc0c2be444d96b159aa6c7f7b1e668680991").unwrap()[..]);
let ref htlc = htlcs[$htlc_idx];
let htlc_tx = chan_utils::build_htlc_transaction(&unsigned_tx.txid, chan.feerate_per_kw,
chan.get_counterparty_selected_contest_delay().unwrap(),
- &htlc, $opt_anchors, &keys.broadcaster_delayed_payment_key, &keys.revocation_key);
+ &htlc, $opt_anchors, false, &keys.broadcaster_delayed_payment_key, &keys.revocation_key);
let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&htlc, $opt_anchors, &keys);
let htlc_sighashtype = if $opt_anchors { EcdsaSighashType::SinglePlusAnyoneCanPay } else { EcdsaSighashType::All };
let htlc_sighash = Message::from_slice(&sighash::SighashCache::new(&htlc_tx).segwit_signature_hash(0, &htlc_redeemscript, htlc.amount_msat / 1000, htlc_sighashtype).unwrap()[..]).unwrap();