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>,
}
counterparty_parameters: None,
funding_outpoint: None,
opt_anchors: if opt_anchors { Some(()) } else { None },
+ opt_non_zero_fee_anchors: None
},
funding_transaction: None,
})
}
- fn check_remote_fee<F: Deref>(fee_estimator: &LowerBoundedFeeEstimator<F>, feerate_per_kw: u32) -> Result<(), ChannelError>
- where F::Target: FeeEstimator
+ fn check_remote_fee<F: Deref, L: Deref>(fee_estimator: &LowerBoundedFeeEstimator<F>,
+ feerate_per_kw: u32, cur_feerate_per_kw: Option<u32>, logger: &L)
+ -> Result<(), ChannelError> where F::Target: FeeEstimator, L::Target: Logger,
{
// We only bound the fee updates on the upper side to prevent completely absurd feerates,
// always accepting up to 25 sat/vByte or 10x our fee estimator's "High Priority" fee.
// of 1.1 sat/vbyte and a receiver that wants 1.1 rounded up to 2. Thus, we always add 250
// sat/kw before the comparison here.
if feerate_per_kw + 250 < lower_limit {
+ if let Some(cur_feerate) = cur_feerate_per_kw {
+ if feerate_per_kw > cur_feerate {
+ log_warn!(logger,
+ "Accepting feerate that may prevent us from closing this channel because it's higher than what we have now. Had {} s/kW, now {} s/kW.",
+ cur_feerate, feerate_per_kw);
+ return Ok(());
+ }
+ }
return Err(ChannelError::Close(format!("Peer's feerate much too low. Actual: {}. Our expected lower limit: {} (- 250)", feerate_per_kw, lower_limit)));
}
Ok(())
if msg.htlc_minimum_msat >= full_channel_value_msat {
return Err(ChannelError::Close(format!("Minimum htlc value ({}) was larger than full channel value ({})", msg.htlc_minimum_msat, full_channel_value_msat)));
}
- Channel::<Signer>::check_remote_fee(fee_estimator, msg.feerate_per_kw)?;
+ Channel::<Signer>::check_remote_fee(fee_estimator, msg.feerate_per_kw, None, logger)?;
let max_counterparty_selected_contest_delay = u16::min(config.channel_handshake_limits.their_to_self_delay, MAX_LOCAL_BREAKDOWN_TIMEOUT);
if msg.to_self_delay > max_counterparty_selected_contest_delay {
}),
funding_outpoint: None,
opt_anchors: if opt_anchors { Some(()) } else { None },
+ opt_non_zero_fee_anchors: None
},
funding_transaction: None,
/// our counterparty!)
/// The result is a transaction which we can revoke broadcastership of (ie a "local" transaction)
/// TODO Some magic rust shit to compile-time check this?
- fn build_holder_transaction_keys(&self, commitment_number: u64) -> Result<TxCreationKeys, ChannelError> {
+ fn build_holder_transaction_keys(&self, commitment_number: u64) -> TxCreationKeys {
let per_commitment_point = self.holder_signer.get_per_commitment_point(commitment_number, &self.secp_ctx);
let delayed_payment_base = &self.get_holder_pubkeys().delayed_payment_basepoint;
let htlc_basepoint = &self.get_holder_pubkeys().htlc_basepoint;
let counterparty_pubkeys = self.get_counterparty_pubkeys();
- Ok(secp_check!(TxCreationKeys::derive_new(&self.secp_ctx, &per_commitment_point, delayed_payment_base, htlc_basepoint, &counterparty_pubkeys.revocation_basepoint, &counterparty_pubkeys.htlc_basepoint), "Local tx keys generation got bogus keys".to_owned()))
+ TxCreationKeys::derive_new(&self.secp_ctx, &per_commitment_point, delayed_payment_base, htlc_basepoint, &counterparty_pubkeys.revocation_basepoint, &counterparty_pubkeys.htlc_basepoint)
}
#[inline]
/// Creates a set of keys for build_commitment_transaction to generate a transaction which we
/// will sign and send to our counterparty.
/// If an Err is returned, it is a ChannelError::Close (for get_outbound_funding_created)
- fn build_remote_transaction_keys(&self) -> Result<TxCreationKeys, ChannelError> {
+ fn build_remote_transaction_keys(&self) -> TxCreationKeys {
//TODO: Ensure that the payment_key derived here ends up in the library users' wallet as we
//may see payments to it!
let revocation_basepoint = &self.get_holder_pubkeys().revocation_basepoint;
let htlc_basepoint = &self.get_holder_pubkeys().htlc_basepoint;
let counterparty_pubkeys = self.get_counterparty_pubkeys();
- Ok(secp_check!(TxCreationKeys::derive_new(&self.secp_ctx, &self.counterparty_cur_commitment_point.unwrap(), &counterparty_pubkeys.delayed_payment_basepoint, &counterparty_pubkeys.htlc_basepoint, revocation_basepoint, htlc_basepoint), "Remote tx keys generation got bogus keys".to_owned()))
+ TxCreationKeys::derive_new(&self.secp_ctx, &self.counterparty_cur_commitment_point.unwrap(), &counterparty_pubkeys.delayed_payment_basepoint, &counterparty_pubkeys.htlc_basepoint, revocation_basepoint, htlc_basepoint)
}
/// Gets the redeemscript for the funding transaction output (ie the funding transaction output
fn funding_created_signature<L: Deref>(&mut self, sig: &Signature, logger: &L) -> Result<(Txid, CommitmentTransaction, Signature), ChannelError> where L::Target: Logger {
let funding_script = self.get_funding_redeemscript();
- let keys = self.build_holder_transaction_keys(self.cur_holder_commitment_transaction_number)?;
+ let keys = self.build_holder_transaction_keys(self.cur_holder_commitment_transaction_number);
let initial_commitment_tx = self.build_commitment_transaction(self.cur_holder_commitment_transaction_number, &keys, true, false, logger).tx;
{
let trusted_tx = initial_commitment_tx.trust();
secp_check!(self.secp_ctx.verify_ecdsa(&sighash, &sig, self.counterparty_funding_pubkey()), "Invalid funding_created signature from peer".to_owned());
}
- let counterparty_keys = self.build_remote_transaction_keys()?;
+ let counterparty_keys = self.build_remote_transaction_keys();
let counterparty_initial_commitment_tx = self.build_commitment_transaction(self.cur_counterparty_commitment_transaction_number, &counterparty_keys, false, false, logger).tx;
let counterparty_trusted_tx = counterparty_initial_commitment_tx.trust();
let funding_script = self.get_funding_redeemscript();
- let counterparty_keys = self.build_remote_transaction_keys()?;
+ let counterparty_keys = self.build_remote_transaction_keys();
let counterparty_initial_commitment_tx = self.build_commitment_transaction(self.cur_counterparty_commitment_transaction_number, &counterparty_keys, false, false, logger).tx;
let counterparty_trusted_tx = counterparty_initial_commitment_tx.trust();
let counterparty_initial_bitcoin_tx = counterparty_trusted_tx.built_transaction();
log_trace!(logger, "Initial counterparty tx for channel {} is: txid {} tx {}",
log_bytes!(self.channel_id()), counterparty_initial_bitcoin_tx.txid, encode::serialize_hex(&counterparty_initial_bitcoin_tx.transaction));
- let holder_signer = self.build_holder_transaction_keys(self.cur_holder_commitment_transaction_number)?;
+ let holder_signer = self.build_holder_transaction_keys(self.cur_holder_commitment_transaction_number);
let initial_commitment_tx = self.build_commitment_transaction(self.cur_holder_commitment_transaction_number, &holder_signer, true, false, logger).tx;
{
let trusted_tx = initial_commitment_tx.trust();
let funding_script = self.get_funding_redeemscript();
- let keys = self.build_holder_transaction_keys(self.cur_holder_commitment_transaction_number).map_err(|e| (None, e))?;
+ let keys = self.build_holder_transaction_keys(self.cur_holder_commitment_transaction_number);
let commitment_stats = self.build_commitment_transaction(self.cur_holder_commitment_transaction_number, &keys, true, false, logger);
let commitment_txid = {
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 };
// Before proposing a feerate update, check that we can actually afford the new fee.
let inbound_stats = self.get_inbound_pending_htlc_stats(Some(feerate_per_kw));
let outbound_stats = self.get_outbound_pending_htlc_stats(Some(feerate_per_kw));
- let keys = if let Ok(keys) = self.build_holder_transaction_keys(self.cur_holder_commitment_transaction_number) { keys } else { return None; };
+ let keys = self.build_holder_transaction_keys(self.cur_holder_commitment_transaction_number);
let commitment_stats = self.build_commitment_transaction(self.cur_holder_commitment_transaction_number, &keys, true, true, logger);
let buffer_fee_msat = Channel::<Signer>::commit_tx_fee_sat(feerate_per_kw, commitment_stats.num_nondust_htlcs + outbound_stats.on_holder_tx_holding_cell_htlcs_count as usize + CONCURRENT_INBOUND_HTLC_FEE_BUFFER as usize, self.opt_anchors()) * 1000;
let holder_balance_msat = commitment_stats.local_balance_msat - outbound_stats.holding_cell_msat;
}
}
- pub fn update_fee<F: Deref>(&mut self, fee_estimator: &LowerBoundedFeeEstimator<F>, msg: &msgs::UpdateFee) -> Result<(), ChannelError>
- where F::Target: FeeEstimator
+ pub fn update_fee<F: Deref, L: Deref>(&mut self, fee_estimator: &LowerBoundedFeeEstimator<F>, msg: &msgs::UpdateFee, logger: &L) -> Result<(), ChannelError>
+ where F::Target: FeeEstimator, L::Target: Logger
{
if self.is_outbound() {
return Err(ChannelError::Close("Non-funding remote tried to update channel fee".to_owned()));
if self.channel_state & (ChannelState::PeerDisconnected as u32) == ChannelState::PeerDisconnected as u32 {
return Err(ChannelError::Close("Peer sent update_fee when we needed a channel_reestablish".to_owned()));
}
- Channel::<Signer>::check_remote_fee(fee_estimator, msg.feerate_per_kw)?;
+ Channel::<Signer>::check_remote_fee(fee_estimator, msg.feerate_per_kw, Some(self.feerate_per_kw), logger)?;
let feerate_over_dust_buffer = msg.feerate_per_kw > self.get_dust_buffer_feerate(None);
self.pending_update_fee = Some((msg.feerate_per_kw, FeeUpdateState::RemoteAnnounced));
// 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
}
/// If an Err is returned, it is a ChannelError::Close (for get_outbound_funding_created)
fn get_outbound_funding_created_signature<L: Deref>(&mut self, logger: &L) -> Result<Signature, ChannelError> where L::Target: Logger {
- let counterparty_keys = self.build_remote_transaction_keys()?;
+ let counterparty_keys = self.build_remote_transaction_keys();
let counterparty_initial_commitment_tx = self.build_commitment_transaction(self.cur_counterparty_commitment_transaction_number, &counterparty_keys, false, false, logger).tx;
Ok(self.holder_signer.sign_counterparty_commitment(&counterparty_initial_commitment_tx, Vec::new(), &self.secp_ctx)
.map_err(|_| ChannelError::Close("Failed to get signatures for new commitment_signed".to_owned()))?.0)
return Err(ChannelError::Ignore(format!("Cannot send value that would put us over the max HTLC value in flight our peer will accept ({})", self.counterparty_max_htlc_value_in_flight_msat)));
}
- let keys = self.build_holder_transaction_keys(self.cur_holder_commitment_transaction_number)?;
+ let keys = self.build_holder_transaction_keys(self.cur_holder_commitment_transaction_number);
let commitment_stats = self.build_commitment_transaction(self.cur_holder_commitment_transaction_number, &keys, true, true, logger);
if !self.is_outbound() {
// Check that we won't violate the remote channel reserve by adding this HTLC.
/// Only fails in case of bad keys. Used for channel_reestablish commitment_signed generation
/// when we shouldn't change HTLC/channel state.
fn send_commitment_no_state_update<L: Deref>(&self, logger: &L) -> Result<(msgs::CommitmentSigned, (Txid, Vec<(HTLCOutputInCommitment, Option<&HTLCSource>)>)), ChannelError> where L::Target: Logger {
- let counterparty_keys = self.build_remote_transaction_keys()?;
+ let counterparty_keys = self.build_remote_transaction_keys();
let commitment_stats = self.build_commitment_transaction(self.cur_counterparty_commitment_transaction_number, &counterparty_keys, false, true, logger);
let counterparty_commitment_txid = commitment_stats.tx.trust().txid();
let (signature, htlc_signatures);
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;
// arithmetic, causing a panic with debug assertions enabled.
let fee_est = TestFeeEstimator { fee_est: 42 };
let bounded_fee_estimator = LowerBoundedFeeEstimator::new(&fee_est);
- assert!(Channel::<InMemorySigner>::check_remote_fee(&bounded_fee_estimator, u32::max_value()).is_err());
+ assert!(Channel::<InMemorySigner>::check_remote_fee(&bounded_fee_estimator,
+ u32::max_value(), None, &&test_utils::TestLogger::new()).is_err());
}
struct Keys {
// 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()[..],
let per_commitment_secret = SecretKey::from_slice(&hex::decode("1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100").unwrap()[..]).unwrap();
let per_commitment_point = PublicKey::from_secret_key(&secp_ctx, &per_commitment_secret);
let htlc_basepoint = &chan.holder_signer.pubkeys().htlc_basepoint;
- let keys = TxCreationKeys::derive_new(&secp_ctx, &per_commitment_point, delayed_payment_base, htlc_basepoint, &counterparty_pubkeys.revocation_basepoint, &counterparty_pubkeys.htlc_basepoint).unwrap();
+ let keys = TxCreationKeys::derive_new(&secp_ctx, &per_commitment_point, delayed_payment_base, htlc_basepoint, &counterparty_pubkeys.revocation_basepoint, &counterparty_pubkeys.htlc_basepoint);
macro_rules! test_commitment {
( $counterparty_sig_hex: expr, $sig_hex: expr, $tx_hex: expr, $($remain:tt)* ) => {
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();
let per_commitment_point = PublicKey::from_secret_key(&secp_ctx, &per_commitment_secret);
assert_eq!(per_commitment_point.serialize()[..], hex::decode("025f7117a78150fe2ef97db7cfc83bd57b2e2c0d0dd25eaf467a4a1c2a45ce1486").unwrap()[..]);
- assert_eq!(chan_utils::derive_public_key(&secp_ctx, &per_commitment_point, &base_point).unwrap().serialize()[..],
+ assert_eq!(chan_utils::derive_public_key(&secp_ctx, &per_commitment_point, &base_point).serialize()[..],
hex::decode("0235f2dbfaa89b57ec7b055afe29849ef7ddfeb1cefdb9ebdc43f5494984db29e5").unwrap()[..]);
- assert_eq!(chan_utils::derive_private_key(&secp_ctx, &per_commitment_point, &base_secret).unwrap(),
+ assert_eq!(chan_utils::derive_private_key(&secp_ctx, &per_commitment_point, &base_secret),
SecretKey::from_slice(&hex::decode("cbced912d3b21bf196a766651e436aff192362621ce317704ea2f75d87e7be0f").unwrap()[..]).unwrap());
- assert_eq!(chan_utils::derive_public_revocation_key(&secp_ctx, &per_commitment_point, &base_point).unwrap().serialize()[..],
+ assert_eq!(chan_utils::derive_public_revocation_key(&secp_ctx, &per_commitment_point, &base_point).serialize()[..],
hex::decode("02916e326636d19c33f13e8c0c3a03dd157f332f3e99c317c141dd865eb01f8ff0").unwrap()[..]);
- assert_eq!(chan_utils::derive_private_revocation_key(&secp_ctx, &per_commitment_secret, &base_secret).unwrap(),
+ assert_eq!(chan_utils::derive_private_revocation_key(&secp_ctx, &per_commitment_secret, &base_secret),
SecretKey::from_slice(&hex::decode("d09ffff62ddb2297ab000cc85bcb4283fdeb6aa052affbc9dddcf33b61078110").unwrap()[..]).unwrap());
}