X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;ds=sidebyside;f=lightning%2Fsrc%2Fln%2Fchannel.rs;h=bd00d671ee2af106ddc5015652deb81aea1fe7f8;hb=dfb02f1878f7f80cd9eab345db5a4589d803fe21;hp=46209a0c402d3a181c699579eb21daad00b50631;hpb=a2b2fb0ceb9ac8815d5bc902668e54c29284380d;p=rust-lightning diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs index 46209a0c..bd00d671 100644 --- a/lightning/src/ln/channel.rs +++ b/lightning/src/ln/channel.rs @@ -35,14 +35,14 @@ use crate::ln::chan_utils; use crate::ln::onion_utils::HTLCFailReason; use crate::chain::BestBlock; use crate::chain::chaininterface::{FeeEstimator, ConfirmationTarget, LowerBoundedFeeEstimator}; -use crate::chain::channelmonitor::{ChannelMonitor, ChannelMonitorUpdate, ChannelMonitorUpdateStep, LATENCY_GRACE_PERIOD_BLOCKS, CLOSED_CHANNEL_UPDATE_ID}; +use crate::chain::channelmonitor::{ChannelMonitor, ChannelMonitorUpdate, ChannelMonitorUpdateStep, WithChannelMonitor, LATENCY_GRACE_PERIOD_BLOCKS, CLOSED_CHANNEL_UPDATE_ID}; use crate::chain::transaction::{OutPoint, TransactionData}; use crate::sign::ecdsa::{EcdsaChannelSigner, WriteableEcdsaChannelSigner}; use crate::sign::{EntropySource, ChannelSigner, SignerProvider, NodeSigner, Recipient}; use crate::events::ClosureReason; use crate::routing::gossip::NodeId; use crate::util::ser::{Readable, ReadableArgs, Writeable, Writer}; -use crate::util::logger::Logger; +use crate::util::logger::{Logger, Record, WithContext}; use crate::util::errors::APIError; use crate::util::config::{UserConfig, ChannelConfig, LegacyChannelConfig, ChannelHandshakeConfig, ChannelHandshakeLimits, MaxDustHTLCExposure}; use crate::util::scid_utils::scid_from_parts; @@ -166,6 +166,7 @@ struct InboundHTLCOutput { state: InboundHTLCState, } +#[cfg_attr(test, derive(Clone, Debug, PartialEq))] enum OutboundHTLCState { /// Added by us and included in a commitment_signed (if we were AwaitingRemoteRevoke when we /// created it we would have put it in the holding cell instead). When they next revoke_and_ack @@ -199,6 +200,7 @@ enum OutboundHTLCState { } #[derive(Clone)] +#[cfg_attr(test, derive(Debug, PartialEq))] enum OutboundHTLCOutcome { /// LDK version 0.0.105+ will always fill in the preimage here. Success(Option), @@ -223,6 +225,7 @@ impl<'a> Into> for &'a OutboundHTLCOutcome { } } +#[cfg_attr(test, derive(Clone, Debug, PartialEq))] struct OutboundHTLCOutput { htlc_id: u64, amount_msat: u64, @@ -235,6 +238,7 @@ struct OutboundHTLCOutput { } /// See AwaitingRemoteRevoke ChannelState for more info +#[cfg_attr(test, derive(Clone, Debug, PartialEq))] enum HTLCUpdateAwaitingACK { AddHTLC { // TODO: Time out if we're getting close to cltv_expiry // always outbound @@ -410,6 +414,33 @@ impl fmt::Display for ChannelError { } } +pub(super) struct WithChannelContext<'a, L: Deref> where L::Target: Logger { + pub logger: &'a L, + pub peer_id: Option, + pub channel_id: Option, +} + +impl<'a, L: Deref> Logger for WithChannelContext<'a, L> where L::Target: Logger { + fn log(&self, mut record: Record) { + record.peer_id = self.peer_id; + record.channel_id = self.channel_id; + self.logger.log(record) + } +} + +impl<'a, 'b, L: Deref> WithChannelContext<'a, L> +where L::Target: Logger { + pub(super) fn from(logger: &'a L, context: &'b ChannelContext) -> Self + where S::Target: SignerProvider + { + WithChannelContext { + logger, + peer_id: Some(context.counterparty_node_id), + channel_id: Some(context.channel_id), + } + } +} + macro_rules! secp_check { ($res: expr, $err: expr) => { match $res { @@ -2742,14 +2773,14 @@ impl Channel where funding_redeemscript.clone(), self.context.channel_value_satoshis, obscure_factor, holder_commitment_tx, best_block, self.context.counterparty_node_id); - + let logger_with_chan_monitor = WithChannelMonitor::from(logger, &channel_monitor); channel_monitor.provide_initial_counterparty_commitment_tx( counterparty_initial_bitcoin_tx.txid, Vec::new(), self.context.cur_counterparty_commitment_transaction_number, self.context.counterparty_cur_commitment_point.unwrap(), counterparty_initial_commitment_tx.feerate_per_kw(), counterparty_initial_commitment_tx.to_broadcaster_value_sat(), - counterparty_initial_commitment_tx.to_countersignatory_value_sat(), logger); + counterparty_initial_commitment_tx.to_countersignatory_value_sat(), &&logger_with_chan_monitor); assert_eq!(self.context.channel_state & (ChannelState::MonitorUpdateInProgress as u32), 0); // We have no had any monitor(s) yet to fail update! if self.context.is_batch_funding() { @@ -6459,6 +6490,7 @@ impl InboundV1Channel where SP::Target: SignerProvider { F::Target: FeeEstimator, L::Target: Logger, { + let logger = WithContext::from(logger, Some(counterparty_node_id), Some(msg.temporary_channel_id)); let announced_channel = if (msg.channel_flags & 1) == 1 { true } else { false }; // First check the channel type is known, failing before we do anything else if we don't @@ -6525,7 +6557,7 @@ impl InboundV1Channel where SP::Target: SignerProvider { 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::::check_remote_fee(&channel_type, fee_estimator, msg.feerate_per_kw, None, logger)?; + Channel::::check_remote_fee(&channel_type, 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 { @@ -6944,13 +6976,13 @@ impl InboundV1Channel where SP::Target: SignerProvider { funding_redeemscript.clone(), self.context.channel_value_satoshis, obscure_factor, holder_commitment_tx, best_block, self.context.counterparty_node_id); - + let logger_with_chan_monitor = WithChannelMonitor::from(logger, &channel_monitor); channel_monitor.provide_initial_counterparty_commitment_tx( counterparty_initial_commitment_tx.trust().txid(), Vec::new(), self.context.cur_counterparty_commitment_transaction_number + 1, self.context.counterparty_cur_commitment_point.unwrap(), self.context.feerate_per_kw, counterparty_initial_commitment_tx.to_broadcaster_value_sat(), - counterparty_initial_commitment_tx.to_countersignatory_value_sat(), logger); + counterparty_initial_commitment_tx.to_countersignatory_value_sat(), &&logger_with_chan_monitor); log_info!(logger, "{} funding_signed for peer for channel {}", if funding_signed.is_some() { "Generated" } else { "Waiting for signature on" }, &self.context.channel_id()); @@ -7889,13 +7921,14 @@ mod tests { use bitcoin::blockdata::transaction::{Transaction, TxOut}; use bitcoin::blockdata::opcodes; use bitcoin::network::constants::Network; - use crate::ln::PaymentHash; + use crate::ln::{PaymentHash, PaymentPreimage}; use crate::ln::channel_keys::{RevocationKey, RevocationBasepoint}; -use crate::ln::channelmanager::{self, HTLCSource, PaymentId}; + use crate::ln::channelmanager::{self, HTLCSource, PaymentId}; use crate::ln::channel::InitFeatures; - use crate::ln::channel::{ChannelState, InboundHTLCOutput, OutboundV1Channel, InboundV1Channel, OutboundHTLCOutput, InboundHTLCState, OutboundHTLCState, HTLCCandidate, HTLCInitiator, commit_tx_fee_msat}; + use crate::ln::channel::{Channel, ChannelState, InboundHTLCOutput, OutboundV1Channel, InboundV1Channel, OutboundHTLCOutput, InboundHTLCState, OutboundHTLCState, HTLCCandidate, HTLCInitiator, HTLCUpdateAwaitingACK, commit_tx_fee_msat}; use crate::ln::channel::{MAX_FUNDING_SATOSHIS_NO_WUMBO, TOTAL_BITCOIN_SUPPLY_SATOSHIS, MIN_THEIR_CHAN_RESERVE_SATOSHIS}; - use crate::ln::features::ChannelTypeFeatures; + use crate::ln::features::{ChannelFeatures, ChannelTypeFeatures, NodeFeatures}; + use crate::ln::msgs; use crate::ln::msgs::{ChannelUpdate, DecodeError, UnsignedChannelUpdate, MAX_VALUE_MSAT}; use crate::ln::script::ShutdownScript; use crate::ln::chan_utils::{self, htlc_success_tx_weight, htlc_timeout_tx_weight}; @@ -7903,9 +7936,10 @@ use crate::ln::channelmanager::{self, HTLCSource, PaymentId}; use crate::chain::chaininterface::{FeeEstimator, LowerBoundedFeeEstimator, ConfirmationTarget}; use crate::sign::{ChannelSigner, InMemorySigner, EntropySource, SignerProvider}; use crate::chain::transaction::OutPoint; - use crate::routing::router::Path; + use crate::routing::router::{Path, RouteHop}; use crate::util::config::UserConfig; use crate::util::errors::APIError; + use crate::util::ser::{ReadableArgs, Writeable}; use crate::util::test_utils; use crate::util::test_utils::{OnGetShutdownScriptpubkey, TestKeysInterface}; use bitcoin::secp256k1::{Secp256k1, ecdsa::Signature}; @@ -8419,6 +8453,96 @@ use crate::ln::channelmanager::{self, HTLCSource, PaymentId}; assert!(!node_a_chan.channel_update(&update).unwrap()); } + #[test] + fn blinding_point_ser() { + // Ensure that channel blinding points are (de)serialized properly. + let feeest = LowerBoundedFeeEstimator::new(&TestFeeEstimator{fee_est: 15000}); + let secp_ctx = Secp256k1::new(); + let seed = [42; 32]; + let network = Network::Testnet; + let keys_provider = test_utils::TestKeysInterface::new(&seed, network); + + let node_b_node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap()); + let config = UserConfig::default(); + let features = channelmanager::provided_init_features(&config); + let outbound_chan = OutboundV1Channel::<&TestKeysInterface>::new(&feeest, &&keys_provider, &&keys_provider, node_b_node_id, &features, 10000000, 100000, 42, &config, 0, 42, None).unwrap(); + let mut chan = Channel { context: outbound_chan.context }; + + let dummy_htlc_source = HTLCSource::OutboundRoute { + path: Path { + hops: vec![RouteHop { + pubkey: test_utils::pubkey(2), channel_features: ChannelFeatures::empty(), + node_features: NodeFeatures::empty(), short_channel_id: 0, fee_msat: 0, + cltv_expiry_delta: 0, maybe_announced_channel: false, + }], + blinded_tail: None + }, + session_priv: test_utils::privkey(42), + first_hop_htlc_msat: 0, + payment_id: PaymentId([42; 32]), + }; + let dummy_outbound_output = OutboundHTLCOutput { + htlc_id: 0, + amount_msat: 0, + payment_hash: PaymentHash([43; 32]), + cltv_expiry: 0, + state: OutboundHTLCState::Committed, + source: dummy_htlc_source.clone(), + skimmed_fee_msat: None, + blinding_point: None, + }; + let mut pending_outbound_htlcs = vec![dummy_outbound_output.clone(); 10]; + for (idx, htlc) in pending_outbound_htlcs.iter_mut().enumerate() { + if idx % 2 == 0 { + htlc.blinding_point = Some(test_utils::pubkey(42 + idx as u8)); + } + } + chan.context.pending_outbound_htlcs = pending_outbound_htlcs.clone(); + + let dummy_holding_cell_add_htlc = HTLCUpdateAwaitingACK::AddHTLC { + amount_msat: 0, + cltv_expiry: 0, + payment_hash: PaymentHash([43; 32]), + source: dummy_htlc_source.clone(), + onion_routing_packet: msgs::OnionPacket { + version: 0, + public_key: Ok(test_utils::pubkey(1)), + hop_data: [0; 20*65], + hmac: [0; 32] + }, + skimmed_fee_msat: None, + blinding_point: None, + }; + let dummy_holding_cell_claim_htlc = HTLCUpdateAwaitingACK::ClaimHTLC { + payment_preimage: PaymentPreimage([42; 32]), + htlc_id: 0, + }; + let mut holding_cell_htlc_updates = Vec::with_capacity(10); + for i in 0..10 { + if i % 3 == 0 { + holding_cell_htlc_updates.push(dummy_holding_cell_add_htlc.clone()); + } else if i % 3 == 1 { + holding_cell_htlc_updates.push(dummy_holding_cell_claim_htlc.clone()); + } else { + let mut dummy_add = dummy_holding_cell_add_htlc.clone(); + if let HTLCUpdateAwaitingACK::AddHTLC { ref mut blinding_point, .. } = &mut dummy_add { + *blinding_point = Some(test_utils::pubkey(42 + i)); + } else { panic!() } + holding_cell_htlc_updates.push(dummy_add); + } + } + chan.context.holding_cell_htlc_updates = holding_cell_htlc_updates.clone(); + + // Encode and decode the channel and ensure that the HTLCs within are the same. + let encoded_chan = chan.encode(); + let mut s = crate::io::Cursor::new(&encoded_chan); + let mut reader = crate::util::ser::FixedLengthReader::new(&mut s, encoded_chan.len() as u64); + let features = channelmanager::provided_channel_type_features(&config); + let decoded_chan = Channel::read(&mut reader, (&&keys_provider, &&keys_provider, 0, &features)).unwrap(); + assert_eq!(decoded_chan.context.pending_outbound_htlcs, pending_outbound_htlcs); + assert_eq!(decoded_chan.context.holding_cell_htlc_updates, holding_cell_htlc_updates); + } + #[cfg(feature = "_test_vectors")] #[test] fn outbound_commitment_test() {