diff --git a/fuzz/src/chanmon_consistency.rs b/fuzz/src/chanmon_consistency.rs index a84dd498932..29b52a57613 100644 --- a/fuzz/src/chanmon_consistency.rs +++ b/fuzz/src/chanmon_consistency.rs @@ -600,7 +600,7 @@ pub fn do_test(data: &[u8], underlying_out: Out) { let expect_drop_id = if let Some(id) = expect_drop_node { Some(nodes[id].get_our_node_id()) } else { None }; for event in $excess_events { let push_a = match event { - events::MessageSendEvent::UpdateHTLCs { ref node_id, .. } => { + events::MessageSendEvent::UpdateCommitmentOutputs { ref node_id, .. } => { if Some(*node_id) == expect_drop_id { panic!("peer_disconnected should drop msgs bound for the disconnected peer"); } *node_id == a_id }, @@ -670,7 +670,7 @@ pub fn do_test(data: &[u8], underlying_out: Out) { for event in &mut events_iter { had_events = true; match event { - events::MessageSendEvent::UpdateHTLCs { node_id, updates: CommitmentUpdate { update_add_htlcs, update_fail_htlcs, update_fulfill_htlcs, update_fail_malformed_htlcs, update_fee, commitment_signed } } => { +events::MessageSendEvent::UpdateCommitmentOutputs { node_id, updates: CommitmentUpdate { update_add_htlcs, update_fail_htlcs, update_fulfill_htlcs, update_fail_malformed_htlcs, update_fee, commitment_signed } } => { for (idx, dest) in nodes.iter().enumerate() { if dest.get_our_node_id() == node_id { for update_add in update_add_htlcs.iter() { @@ -708,7 +708,7 @@ pub fn do_test(data: &[u8], underlying_out: Out) { !update_fail_htlcs.is_empty() || !update_fail_malformed_htlcs.is_empty(); if $limit_events != ProcessMessages::AllMessages && processed_change { // If we only want to process some messages, don't deliver the CS until later. - extra_ev = Some(events::MessageSendEvent::UpdateHTLCs { node_id, updates: CommitmentUpdate { +extra_ev = Some(events::MessageSendEvent::UpdateCommitmentOutputs { node_id, updates: CommitmentUpdate { update_add_htlcs: Vec::new(), update_fail_htlcs: Vec::new(), update_fulfill_htlcs: Vec::new(), @@ -783,7 +783,7 @@ pub fn do_test(data: &[u8], underlying_out: Out) { if $counterparty_id == 0 { for event in nodes[0].get_and_clear_pending_msg_events() { match event { - events::MessageSendEvent::UpdateHTLCs { .. } => {}, +events::MessageSendEvent::UpdateCommitmentOutputs { .. } => {}, events::MessageSendEvent::SendRevokeAndACK { .. } => {}, events::MessageSendEvent::SendChannelReestablish { .. } => {}, events::MessageSendEvent::SendChannelReady { .. } => {}, @@ -804,7 +804,7 @@ pub fn do_test(data: &[u8], underlying_out: Out) { } else { for event in nodes[2].get_and_clear_pending_msg_events() { match event { - events::MessageSendEvent::UpdateHTLCs { .. } => {}, +events::MessageSendEvent::UpdateCommitmentOutputs { .. } => {}, events::MessageSendEvent::SendRevokeAndACK { .. } => {}, events::MessageSendEvent::SendChannelReestablish { .. } => {}, events::MessageSendEvent::SendChannelReady { .. } => {}, diff --git a/lightning-invoice/Cargo.toml b/lightning-invoice/Cargo.toml index 39ca3a1badc..1c32167b039 100644 --- a/lightning-invoice/Cargo.toml +++ b/lightning-invoice/Cargo.toml @@ -25,6 +25,7 @@ lightning = { version = "0.0.112", path = "../lightning", default-features = fal secp256k1 = { version = "0.24.0", default-features = false, features = ["recovery", "alloc"] } num-traits = { version = "0.2.8", default-features = false } bitcoin_hashes = { version = "0.11", default-features = false } +bitcoin = { version = "0.29.0", default-features = false } hashbrown = { version = "0.8", optional = true } serde = { version = "1.0.118", optional = true } diff --git a/lightning-invoice/src/payment.rs b/lightning-invoice/src/payment.rs index 4b2a682b3fa..fbfa5ecedfc 100644 --- a/lightning-invoice/src/payment.rs +++ b/lightning-invoice/src/payment.rs @@ -64,6 +64,10 @@ //! # fn send_spontaneous_payment( //! # &self, route: &Route, payment_preimage: PaymentPreimage //! # ) -> Result { unimplemented!() } +//! +//! # fn add_custom_output(&self, route: &Route) -> Result<(), String> { +//! # todo!() +//! # } //! # fn retry_payment( //! # &self, route: &Route, payment_id: PaymentId //! # ) -> Result<(), PaymentSendFailure> { unimplemented!() } @@ -107,7 +111,7 @@ //! match event { //! Event::PaymentPathFailed { .. } => println!("payment failed after retries"), //! Event::PaymentSent { .. } => println!("payment successful"), -//! _ => {}, +//! _ => {} //! } //! }; //! # let payer = FakePayer {}; @@ -138,14 +142,15 @@ use crate::Invoice; use bitcoin_hashes::Hash; use bitcoin_hashes::sha256::Hash as Sha256; +use bitcoin::Script; use crate::prelude::*; use lightning::io; use lightning::ln::{PaymentHash, PaymentPreimage, PaymentSecret}; -use lightning::ln::channelmanager::{ChannelDetails, PaymentId, PaymentSendFailure}; -use lightning::ln::msgs::LightningError; +use lightning::ln::channelmanager::{ChannelDetails, CustomOutputId, PaymentId, PaymentSendFailure, RemoveCustomOutputError, CustomOutputDetails}; +use lightning::ln::msgs::{LightningError, ErrorAction}; use lightning::routing::gossip::NodeId; -use lightning::routing::router::{PaymentParameters, Route, RouteHop, RouteParameters}; +use lightning::routing::router::{PaymentParameters, Route, RouteHop, RouteParameters, AddCustomOutputRouteDetails, RemoveCustomOutputDetails}; use lightning::util::errors::APIError; use lightning::util::events::{Event, EventHandler}; use lightning::util::logger::Logger; @@ -259,6 +264,16 @@ pub trait Payer { &self, route: &Route, payment_preimage: PaymentPreimage ) -> Result; + /// Adds a custom output over the Lightning Network using the given [`Route`]. + fn add_custom_output( + &self, route_details: AddCustomOutputRouteDetails, script: Script + ) -> Result; + + /// Removes a custom output with the provided values. + fn remove_custom_output( + &self, route_details: RemoveCustomOutputDetails, + ) -> Result<(), RemoveCustomOutputError>; + /// Retries a failed payment path for the [`PaymentId`] using the given [`Route`]. fn retry_payment(&self, route: &Route, payment_id: PaymentId) -> Result<(), PaymentSendFailure>; @@ -273,6 +288,15 @@ pub trait Router { &self, payer: &PublicKey, route_params: &RouteParameters, payment_hash: &PaymentHash, first_hops: Option<&[&ChannelDetails]>, inflight_htlcs: InFlightHtlcs ) -> Result; + /// Gets custom output route details. + fn add_custom_output_route_details( + &self, local_pk: &PublicKey, local_amount_msats: u64, remote_amount_msats: u64, cltv_expiry: u32, channel_details: ChannelDetails, + ) -> Result; + + /// Gets custom output route details to remove a custom output. + fn remove_custom_output_route_details( + &self, custom_output_id: CustomOutputId, local_amount_msats: u64, channel_details: ChannelDetails, + ) -> Result; /// Lets the router know that payment through a specific path has failed. fn notify_payment_path_failed(&self, path: &[&RouteHop], short_channel_id: u64); /// Lets the router know that payment through a specific path was successful. @@ -320,6 +344,12 @@ pub enum PaymentError { Routing(LightningError), /// An error occurring when sending a payment. Sending(PaymentSendFailure), + /// An error occurring when creating a custom output. + /// TODO(10101): Should remove this variant. + CreatingCustomOutput(String), + /// An error occurring when creating a custom output. + /// TODO(10101): Should remove this variant. + RemovingCustomOutput(RemoveCustomOutputError), } impl InvoicePayerUsingTime @@ -433,6 +463,71 @@ where .map_err(|e| { self.payment_cache.lock().unwrap().remove(&payment_hash); e }) } + /// TODO(10101): Docs + /// TODO(10101): Probably shouldn't be defined on the [`InvoicePayer`]. + pub fn add_custom_output( + &self, pubkey: PublicKey, amount_local_msats: u64, amount_remote_msats: u64, final_cltv_expiry_delta: u32, script: Script + ) -> Result { + // TODO: We might have more than one channel with the peer identified by the + // `pubkey` argument. We will need to use a heuristic to select a channel among all + // the candidates + let channel_details = self.payer + .first_hops() + .iter() + .find(|details| details.counterparty.node_id == pubkey) + .ok_or_else(|| PaymentError::Routing( + LightningError { + err: "Cannot create custom output: No channel with peer {pubkey}".to_owned(), + action: ErrorAction::IgnoreError + } + ))? + .clone(); + + let route_details = self.router.add_custom_output_route_details( + &self.payer.node_id(), // The node ID of the sender OK + amount_local_msats, + amount_remote_msats, + final_cltv_expiry_delta, + channel_details, + ).map_err(|e| PaymentError::Routing(e))?; + + let custom_output_details = self.payer.add_custom_output(route_details, script).map_err(PaymentError::CreatingCustomOutput)?; + + Ok(custom_output_details) + } + + + /// TODO(10101): Docs + /// TODO(10101): Probably shouldn't be defined on the [`InvoicePayer`]. + pub fn remove_custom_output( + &self, pubkey: PublicKey, custom_output_id: CustomOutputId, amount_local_msats: u64 + ) -> Result<(), PaymentError> { + // TODO: We might have more than one channel with the peer identified by the + // `pubkey` argument. We will need to use a heuristic to select a channel among all + // the candidates + let channel_details = self.payer + .first_hops() + .iter() + .find(|details| details.counterparty.node_id == pubkey) + .ok_or_else(|| PaymentError::Routing( + LightningError { + err: "Cannot create custom output: No channel with peer {pubkey}".to_owned(), + action: ErrorAction::IgnoreError + } + ))? + .clone(); + + let route_details = self.router.remove_custom_output_route_details( + custom_output_id, + amount_local_msats, + channel_details, + ).map_err(|e| PaymentError::Routing(e))?; + + self.payer.remove_custom_output(route_details).map_err(PaymentError::RemovingCustomOutput)?; + + Ok(()) + } + fn pay_internal Result + Copy>( &self, params: &RouteParameters, payment_hash: PaymentHash, send_payment: F, ) -> Result { @@ -1845,6 +1940,18 @@ mod tests { }) } + fn add_custom_output_route_details( + &self, _dialer_pk: &PublicKey, _local_amount_msats: u64, _remote_amount_msats: u64, _cltv_expiry: u32, _channel_details: ChannelDetails, + ) -> Result { + todo!() + } + + fn remove_custom_output_route_details( + &self, _custom_output_id: CustomOutputId, _local_amount_msats: u64, _channel_details: ChannelDetails, + ) -> Result { + todo!() + } + fn notify_payment_path_failed(&self, path: &[&RouteHop], short_channel_id: u64) { self.scorer.lock().payment_path_failed(path, short_channel_id); } @@ -1860,6 +1967,7 @@ mod tests { fn notify_payment_probe_failed(&self, path: &[&RouteHop], short_channel_id: u64) { self.scorer.lock().probe_failed(path, short_channel_id); } + } struct FailingRouter; @@ -1872,13 +1980,25 @@ mod tests { Err(LightningError { err: String::new(), action: ErrorAction::IgnoreError }) } + fn add_custom_output_route_details( + &self, _dialer_pk: &PublicKey, _local_amount_msats: u64, _remote_amount_msats: u64, _cltv_expiry: u32, _channel_details: ChannelDetails, + ) -> Result { + todo!() + } + + fn remove_custom_output_route_details( + &self, _custom_output_id: CustomOutputId, _local_amount_msats: u64, _channel_details: ChannelDetails, + ) -> Result { + todo!() + } + fn notify_payment_path_failed(&self, _path: &[&RouteHop], _short_channel_id: u64) {} fn notify_payment_path_successful(&self, _path: &[&RouteHop]) {} fn notify_payment_probe_successful(&self, _path: &[&RouteHop]) {} - fn notify_payment_probe_failed(&self, _path: &[&RouteHop], _short_channel_id: u64) {} +fn notify_payment_probe_failed(&self, _path: &[&RouteHop], _short_channel_id: u64) {} } struct TestScorer { @@ -2113,6 +2233,18 @@ mod tests { self.check_attempts() } + fn add_custom_output( + &self, _route_details: AddCustomOutputRouteDetails, _script: Script + ) -> Result { + todo!() + } + + fn remove_custom_output( + &self, _route_details: RemoveCustomOutputDetails, + ) -> Result<(), RemoveCustomOutputError> { + todo!() + } + fn retry_payment( &self, route: &Route, _payment_id: PaymentId ) -> Result<(), PaymentSendFailure> { @@ -2121,6 +2253,7 @@ mod tests { } fn abandon_payment(&self, _payment_id: PaymentId) { } + } // *** Full Featured Functional Tests with a Real ChannelManager *** @@ -2134,6 +2267,18 @@ mod tests { self.0.borrow_mut().pop_front().unwrap() } + fn add_custom_output_route_details( + &self, _dialer_pk: &PublicKey, _local_amount_msats: u64, _remote_amount_msats: u64, _cltv_expiry_delta: u32, _channel_details: ChannelDetails, + ) -> Result { + todo!() + } + + fn remove_custom_output_route_details( + &self, _custom_output_id: CustomOutputId, _local_amount_msats: u64, _channel_details: ChannelDetails, + ) -> Result { + todo!() + } + fn notify_payment_path_failed(&self, _path: &[&RouteHop], _short_channel_id: u64) {} fn notify_payment_path_successful(&self, _path: &[&RouteHop]) {} diff --git a/lightning-invoice/src/utils.rs b/lightning-invoice/src/utils.rs index 5b16da45993..5269773bd02 100644 --- a/lightning-invoice/src/utils.rs +++ b/lightning-invoice/src/utils.rs @@ -5,18 +5,19 @@ use crate::payment::{InFlightHtlcs, Payer, Router}; use crate::{prelude::*, Description, InvoiceDescription, Sha256}; use bech32::ToBase32; +use bitcoin::Script; use bitcoin_hashes::{Hash, sha256}; use lightning::chain; use lightning::chain::chaininterface::{BroadcasterInterface, FeeEstimator}; use lightning::chain::keysinterface::{Recipient, KeysInterface, Sign}; use lightning::ln::{PaymentHash, PaymentPreimage, PaymentSecret}; -use lightning::ln::channelmanager::{ChannelDetails, ChannelManager, PaymentId, PaymentSendFailure, MIN_FINAL_CLTV_EXPIRY}; +use lightning::ln::channelmanager::{ChannelDetails, ChannelManager, PaymentId, PaymentSendFailure, MIN_FINAL_CLTV_EXPIRY, CustomOutputId, RemoveCustomOutputError, CustomOutputDetails}; #[cfg(feature = "std")] use lightning::ln::channelmanager::{PhantomRouteHints, MIN_CLTV_EXPIRY_DELTA}; use lightning::ln::inbound_payment::{create, create_from_hash, ExpandedKey}; -use lightning::ln::msgs::LightningError; +use lightning::ln::msgs::{LightningError, ErrorAction}; use lightning::routing::gossip::{NetworkGraph, NodeId, RoutingFees}; -use lightning::routing::router::{Route, RouteHint, RouteHintHop, RouteParameters, find_route, RouteHop}; +use lightning::routing::router::{Route, RouteHint, RouteHintHop, RouteParameters, find_route, RouteHop, AddCustomOutputRouteDetails, RemoveCustomOutputDetails}; use lightning::routing::scoring::{ChannelUsage, LockableScore, Score}; use lightning::util::logger::Logger; use secp256k1::PublicKey; @@ -583,6 +584,58 @@ impl>, L: Deref, S: Deref> Router for DefaultR fn notify_payment_probe_failed(&self, path: &[&RouteHop], short_channel_id: u64) { self.scorer.lock().probe_failed(path, short_channel_id); } + + fn add_custom_output_route_details( + &self, _local_pk: &PublicKey, local_amount_msats: u64, remote_amount_msats: u64, cltv_expiry: u32, channel_details: ChannelDetails, + ) -> Result { + let ChannelDetails { outbound_capacity_msat, inbound_capacity_msat, short_channel_id, counterparty, .. } = channel_details; + + let short_channel_id = short_channel_id.ok_or_else(|| LightningError { + err: format!("Cannot create custom output if funding transaction has not been confirmed yet"), + action: ErrorAction::IgnoreError + })?; + + if local_amount_msats > outbound_capacity_msat { + return Err(LightningError { + err: format!( + "Cannot create custom output with insufficient outbound liquidity. + Needed: {local_amount_msats}; + available: {outbound_capacity_msat}" + ), + action: ErrorAction::IgnoreError + }); + } + + if remote_amount_msats > inbound_capacity_msat { + return Err(LightningError { + err: format!( + "Cannot create custom output with insufficient inbound liquidity. + Needed: {remote_amount_msats}; + available: {inbound_capacity_msat}" + ), + action: ErrorAction::IgnoreError + }); + } + + + Ok(AddCustomOutputRouteDetails { + short_channel_id, pk_counterparty: counterparty.node_id, local_amount_msats, amount_counterparty_msat: remote_amount_msats, cltv_expiry }) + } + + fn remove_custom_output_route_details(&self, custom_output_id: CustomOutputId, local_amount_msats: u64, channel_details: ChannelDetails) -> Result { + let ChannelDetails { short_channel_id, .. } = channel_details; + + let _short_channel_id = short_channel_id.ok_or_else(|| LightningError { + err: format!("Cannot create custom output if funding transaction has not been confirmed yet"), + action: ErrorAction::IgnoreError + })?; + + // TODO(10101): we should do some sanity checks here for the amounts + + Ok(RemoveCustomOutputDetails { custom_output_id, local_amount_msats }) + } + + } impl Payer for ChannelManager @@ -607,6 +660,22 @@ where self.send_payment(route, payment_hash, payment_secret) } + fn add_custom_output( + &self, route_details: AddCustomOutputRouteDetails, script: Script + ) -> Result { + let AddCustomOutputRouteDetails { short_channel_id, pk_counterparty, local_amount_msats: amount_us_msat, amount_counterparty_msat, cltv_expiry } = route_details; + + self.add_custom_output(short_channel_id, pk_counterparty, amount_us_msat, amount_counterparty_msat, cltv_expiry, script) + } + + fn remove_custom_output( + &self, route_details: RemoveCustomOutputDetails, + ) -> Result<(), RemoveCustomOutputError> { + let RemoveCustomOutputDetails { custom_output_id, local_amount_msats } = route_details; + + self.remove_custom_output(custom_output_id, local_amount_msats) + } + fn send_spontaneous_payment( &self, route: &Route, payment_preimage: PaymentPreimage, ) -> Result { @@ -1054,7 +1123,7 @@ mod test { let mut events = nodes[0].node.get_and_clear_pending_msg_events(); assert_eq!(events.len(), 1); let fwd_idx = match events[0] { - MessageSendEvent::UpdateHTLCs { node_id, .. } => { + MessageSendEvent::UpdateCommitmentOutputs { node_id, .. } => { if node_id == nodes[1].node.get_our_node_id() { 1 } else { 2 } diff --git a/lightning-net-tokio/src/lib.rs b/lightning-net-tokio/src/lib.rs index 3fbe6aab949..dfd7eabdd1a 100644 --- a/lightning-net-tokio/src/lib.rs +++ b/lightning-net-tokio/src/lib.rs @@ -41,28 +41,28 @@ //! //! // Connect to node with pubkey their_node_id at addr: //! async fn connect_to_node(peer_manager: PeerManager, chain_monitor: Arc, channel_manager: ChannelManager, their_node_id: PublicKey, addr: SocketAddr) { -//! lightning_net_tokio::connect_outbound(peer_manager, their_node_id, addr).await; -//! loop { -//! let event_handler = |event: &Event| { -//! // Handle the event! -//! }; -//! channel_manager.await_persistable_update(); -//! channel_manager.process_pending_events(&event_handler); -//! chain_monitor.process_pending_events(&event_handler); -//! } +//! lightning_net_tokio::connect_outbound(peer_manager, their_node_id, addr).await; +//! loop { +//! let event_handler = |event: &Event| { +//! // Handle the event! +//! }; +//! channel_manager.await_persistable_update(); +//! channel_manager.process_pending_events(&event_handler); +//! chain_monitor.process_pending_events(&event_handler); +//! } //! } //! //! // Begin reading from a newly accepted socket and talk to the peer: //! async fn accept_socket(peer_manager: PeerManager, chain_monitor: Arc, channel_manager: ChannelManager, socket: TcpStream) { -//! lightning_net_tokio::setup_inbound(peer_manager, socket); -//! loop { -//! let event_handler = |event: &Event| { -//! // Handle the event! -//! }; -//! channel_manager.await_persistable_update(); -//! channel_manager.process_pending_events(&event_handler); -//! chain_monitor.process_pending_events(&event_handler); -//! } +//! lightning_net_tokio::setup_inbound(peer_manager, socket); +//! loop { +//! let event_handler = |event: &Event| { +//! // Handle the event! +//! }; +//! channel_manager.await_persistable_update(); +//! channel_manager.process_pending_events(&event_handler); +//! chain_monitor.process_pending_events(&event_handler); +//! } //! } //! ``` @@ -154,7 +154,7 @@ impl Connection { OMH::Target: OnionMessageHandler + 'static + Send + Sync, L::Target: Logger + 'static + Send + Sync, UMH::Target: CustomMessageHandler + 'static + Send + Sync, - { + { // Create a waker to wake up poll_event_process, above let (event_waker, event_receiver) = mpsc::channel(1); tokio::spawn(Self::poll_event_process(Arc::clone(&peer_manager), event_receiver)); @@ -594,6 +594,8 @@ mod tests { fn handle_shutdown(&self, _their_node_id: &PublicKey, _their_features: &InitFeatures, _msg: &Shutdown) {} fn handle_closing_signed(&self, _their_node_id: &PublicKey, _msg: &ClosingSigned) {} fn handle_update_add_htlc(&self, _their_node_id: &PublicKey, _msg: &UpdateAddHTLC) {} + fn handle_update_add_custom_output(&self, _their_node_id: &PublicKey, _msg: &UpdateAddCustomOutput) {} + fn handle_update_remove_custom_output(&self, _their_node_id: &PublicKey, _msg: &UpdateRemoveCustomOutput) {} fn handle_update_fulfill_htlc(&self, _their_node_id: &PublicKey, _msg: &UpdateFulfillHTLC) {} fn handle_update_fail_htlc(&self, _their_node_id: &PublicKey, _msg: &UpdateFailHTLC) {} fn handle_update_fail_malformed_htlc(&self, _their_node_id: &PublicKey, _msg: &UpdateFailMalformedHTLC) {} @@ -601,7 +603,6 @@ mod tests { fn handle_revoke_and_ack(&self, _their_node_id: &PublicKey, _msg: &RevokeAndACK) {} fn handle_update_fee(&self, _their_node_id: &PublicKey, _msg: &UpdateFee) {} fn handle_announcement_signatures(&self, _their_node_id: &PublicKey, _msg: &AnnouncementSignatures) {} - fn handle_channel_update(&self, _their_node_id: &PublicKey, _msg: &ChannelUpdate) {} fn peer_disconnected(&self, their_node_id: &PublicKey, _no_connection_possible: bool) { if *their_node_id == self.expected_pubkey { self.disconnected_flag.store(true, Ordering::SeqCst); @@ -615,6 +616,7 @@ mod tests { Ok(()) } fn handle_channel_reestablish(&self, _their_node_id: &PublicKey, _msg: &ChannelReestablish) {} + fn handle_channel_update(&self, _their_node_id: &PublicKey, _msg: &ChannelUpdate) {} fn handle_error(&self, _their_node_id: &PublicKey, _msg: &ErrorMessage) {} fn provided_node_features(&self) -> NodeFeatures { NodeFeatures::empty() } fn provided_init_features(&self, _their_node_id: &PublicKey) -> InitFeatures { InitFeatures::empty() } diff --git a/lightning/src/chain/channelmonitor.rs b/lightning/src/chain/channelmonitor.rs index 79d589c6521..c4c826204ed 100644 --- a/lightning/src/chain/channelmonitor.rs +++ b/lightning/src/chain/channelmonitor.rs @@ -219,7 +219,7 @@ pub(crate) const LATENCY_GRACE_PERIOD_BLOCKS: u32 = 3; // It may cause spurious generation of bumped claim txn but that's alright given the outpoint is already // solved by a previous claim tx. What we want to avoid is reorg evicting our claim tx and us not // keep bumping another claim tx to solve the outpoint. -pub const ANTI_REORG_DELAY: u32 = 6; +pub const ANTI_REORG_DELAY: u32 = 0; /// Number of blocks before confirmation at which we fail back an un-relayed HTLC or at which we /// refuse to accept a new HTLC. /// diff --git a/lightning/src/ln/chan_utils.rs b/lightning/src/ln/chan_utils.rs index a8c9dcc826e..2605d22ef60 100644 --- a/lightning/src/ln/chan_utils.rs +++ b/lightning/src/ln/chan_utils.rs @@ -41,6 +41,8 @@ use core::ops::Deref; use crate::chain; use crate::util::crypto::sign; +use super::channelmanager::CustomOutputId; + pub(crate) const MAX_HTLCS: u16 = 483; pub(crate) const OFFERED_HTLC_SCRIPT_WEIGHT: usize = 133; pub(crate) const OFFERED_HTLC_SCRIPT_WEIGHT_ANCHORS: usize = 136; @@ -65,6 +67,13 @@ pub fn htlc_timeout_tx_weight(opt_anchors: bool) -> u64 { if opt_anchors { HTLC_TIMEOUT_ANCHOR_TX_WEIGHT } else { HTLC_TIMEOUT_TX_WEIGHT } } +/// Gets the weight for a custom output transaction. +#[inline] +pub fn custom_output_tx_weight() -> u64 { + // TODO(10101): Come up with the real number + 600 +} + #[derive(PartialEq, Eq)] pub(crate) enum HTLCClaim { OfferedTimeout, @@ -167,23 +176,23 @@ pub fn build_closing_transaction(to_holder_value_sat: u64, to_counterparty_value ins }; - let mut txouts: Vec<(TxOut, ())> = Vec::new(); + let mut txouts: Vec<(TxOut, (), ())> = Vec::new(); if to_counterparty_value_sat > 0 { txouts.push((TxOut { script_pubkey: to_counterparty_script, value: to_counterparty_value_sat - }, ())); + }, (), ())); } if to_holder_value_sat > 0 { txouts.push((TxOut { script_pubkey: to_holder_script, value: to_holder_value_sat - }, ())); + }, (), ())); } - transaction_utils::sort_outputs(&mut txouts, |_, _| { cmp::Ordering::Equal }); // Ordering doesnt matter if they used our pubkey... + transaction_utils::sort_outputs(&mut txouts, |_, _| { cmp::Ordering::Equal }, |_, _| { cmp::Ordering::Equal }); // Ordering doesnt matter if they used our pubkey... let mut outputs: Vec = Vec::new(); for out in txouts.drain(..) { @@ -420,7 +429,7 @@ pub fn derive_public_revocation_key(secp_ctx: &Secp2 /// channel basepoints via the new function, or they were obtained via /// CommitmentTransaction.trust().keys() because we trusted the source of the /// pre-calculated keys. -#[derive(PartialEq, Eq, Clone)] +#[derive(PartialEq, Eq, Clone, Debug)] pub struct TxCreationKeys { /// The broadcaster's per-commitment public key which was used to derive the other keys. pub per_commitment_point: PublicKey, @@ -513,15 +522,15 @@ pub const REVOKEABLE_REDEEMSCRIPT_MAX_LENGTH: usize = 6 + 3 + 34*2; /// Encumbering a `to_holder` output on a commitment transaction or 2nd-stage HTLC transactions. pub fn get_revokeable_redeemscript(revocation_key: &PublicKey, contest_delay: u16, broadcaster_delayed_payment_key: &PublicKey) -> Script { let res = Builder::new().push_opcode(opcodes::all::OP_IF) - .push_slice(&revocation_key.serialize()) - .push_opcode(opcodes::all::OP_ELSE) - .push_int(contest_delay as i64) - .push_opcode(opcodes::all::OP_CSV) - .push_opcode(opcodes::all::OP_DROP) - .push_slice(&broadcaster_delayed_payment_key.serialize()) - .push_opcode(opcodes::all::OP_ENDIF) - .push_opcode(opcodes::all::OP_CHECKSIG) - .into_script(); + .push_slice(&revocation_key.serialize()) + .push_opcode(opcodes::all::OP_ELSE) + .push_int(contest_delay as i64) + .push_opcode(opcodes::all::OP_CSV) + .push_opcode(opcodes::all::OP_DROP) + .push_slice(&broadcaster_delayed_payment_key.serialize()) + .push_opcode(opcodes::all::OP_ENDIF) + .push_opcode(opcodes::all::OP_CHECKSIG) + .into_script(); debug_assert!(res.len() <= REVOKEABLE_REDEEMSCRIPT_MAX_LENGTH); res } @@ -555,35 +564,64 @@ impl_writeable_tlv_based!(HTLCOutputInCommitment, { (8, transaction_output_index, option), }); +/// Information about a custom output. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct CustomOutputInCommitment { + /// ID. + pub id: CustomOutputId, + /// The value, in msat, of the custom output provided by the local node. + pub local_amount_msat: u64, + /// The value, in msat, of the custom output provided by the remote node. + pub remote_amount_msat: u64, + /// The CLTV lock-time at which this custom output expires. + pub cltv_expiry: u32, + /// The position within the commitment transactions' outputs. + /// + /// This is set to [`None`] until all the outputs of the commitment transaction are ordered. + /// (I hate this, but we are just following the existing patterns of this library). + pub transaction_output_index: Option, + /// The script that defines the spend conditions of the custom output. + pub script: Script, +} + +impl_writeable_tlv_based!(CustomOutputInCommitment, { + (0, id, required), + (2, local_amount_msat, required), + (4, remote_amount_msat, required), + (6, cltv_expiry, required), + (8, transaction_output_index, option), + (10, script, required), +}); + #[inline] pub(crate) fn get_htlc_redeemscript_with_explicit_keys(htlc: &HTLCOutputInCommitment, opt_anchors: bool, broadcaster_htlc_key: &PublicKey, countersignatory_htlc_key: &PublicKey, revocation_key: &PublicKey) -> Script { let payment_hash160 = Ripemd160::hash(&htlc.payment_hash.0[..]).into_inner(); if htlc.offered { let mut bldr = Builder::new().push_opcode(opcodes::all::OP_DUP) - .push_opcode(opcodes::all::OP_HASH160) - .push_slice(&PubkeyHash::hash(&revocation_key.serialize())[..]) - .push_opcode(opcodes::all::OP_EQUAL) - .push_opcode(opcodes::all::OP_IF) - .push_opcode(opcodes::all::OP_CHECKSIG) - .push_opcode(opcodes::all::OP_ELSE) - .push_slice(&countersignatory_htlc_key.serialize()[..]) - .push_opcode(opcodes::all::OP_SWAP) - .push_opcode(opcodes::all::OP_SIZE) - .push_int(32) - .push_opcode(opcodes::all::OP_EQUAL) - .push_opcode(opcodes::all::OP_NOTIF) - .push_opcode(opcodes::all::OP_DROP) - .push_int(2) - .push_opcode(opcodes::all::OP_SWAP) - .push_slice(&broadcaster_htlc_key.serialize()[..]) - .push_int(2) - .push_opcode(opcodes::all::OP_CHECKMULTISIG) - .push_opcode(opcodes::all::OP_ELSE) - .push_opcode(opcodes::all::OP_HASH160) - .push_slice(&payment_hash160) - .push_opcode(opcodes::all::OP_EQUALVERIFY) - .push_opcode(opcodes::all::OP_CHECKSIG) - .push_opcode(opcodes::all::OP_ENDIF); + .push_opcode(opcodes::all::OP_HASH160) + .push_slice(&PubkeyHash::hash(&revocation_key.serialize())[..]) + .push_opcode(opcodes::all::OP_EQUAL) + .push_opcode(opcodes::all::OP_IF) + .push_opcode(opcodes::all::OP_CHECKSIG) + .push_opcode(opcodes::all::OP_ELSE) + .push_slice(&countersignatory_htlc_key.serialize()[..]) + .push_opcode(opcodes::all::OP_SWAP) + .push_opcode(opcodes::all::OP_SIZE) + .push_int(32) + .push_opcode(opcodes::all::OP_EQUAL) + .push_opcode(opcodes::all::OP_NOTIF) + .push_opcode(opcodes::all::OP_DROP) + .push_int(2) + .push_opcode(opcodes::all::OP_SWAP) + .push_slice(&broadcaster_htlc_key.serialize()[..]) + .push_int(2) + .push_opcode(opcodes::all::OP_CHECKMULTISIG) + .push_opcode(opcodes::all::OP_ELSE) + .push_opcode(opcodes::all::OP_HASH160) + .push_slice(&payment_hash160) + .push_opcode(opcodes::all::OP_EQUALVERIFY) + .push_opcode(opcodes::all::OP_CHECKSIG) + .push_opcode(opcodes::all::OP_ENDIF); if opt_anchors { bldr = bldr.push_opcode(opcodes::all::OP_PUSHNUM_1) .push_opcode(opcodes::all::OP_CSV) @@ -593,33 +631,33 @@ pub(crate) fn get_htlc_redeemscript_with_explicit_keys(htlc: &HTLCOutputInCommit .into_script() } else { let mut bldr = Builder::new().push_opcode(opcodes::all::OP_DUP) - .push_opcode(opcodes::all::OP_HASH160) - .push_slice(&PubkeyHash::hash(&revocation_key.serialize())[..]) - .push_opcode(opcodes::all::OP_EQUAL) - .push_opcode(opcodes::all::OP_IF) - .push_opcode(opcodes::all::OP_CHECKSIG) - .push_opcode(opcodes::all::OP_ELSE) - .push_slice(&countersignatory_htlc_key.serialize()[..]) - .push_opcode(opcodes::all::OP_SWAP) - .push_opcode(opcodes::all::OP_SIZE) - .push_int(32) - .push_opcode(opcodes::all::OP_EQUAL) - .push_opcode(opcodes::all::OP_IF) - .push_opcode(opcodes::all::OP_HASH160) - .push_slice(&payment_hash160) - .push_opcode(opcodes::all::OP_EQUALVERIFY) - .push_int(2) - .push_opcode(opcodes::all::OP_SWAP) - .push_slice(&broadcaster_htlc_key.serialize()[..]) - .push_int(2) - .push_opcode(opcodes::all::OP_CHECKMULTISIG) - .push_opcode(opcodes::all::OP_ELSE) - .push_opcode(opcodes::all::OP_DROP) - .push_int(htlc.cltv_expiry as i64) - .push_opcode(opcodes::all::OP_CLTV) - .push_opcode(opcodes::all::OP_DROP) - .push_opcode(opcodes::all::OP_CHECKSIG) - .push_opcode(opcodes::all::OP_ENDIF); + .push_opcode(opcodes::all::OP_HASH160) + .push_slice(&PubkeyHash::hash(&revocation_key.serialize())[..]) + .push_opcode(opcodes::all::OP_EQUAL) + .push_opcode(opcodes::all::OP_IF) + .push_opcode(opcodes::all::OP_CHECKSIG) + .push_opcode(opcodes::all::OP_ELSE) + .push_slice(&countersignatory_htlc_key.serialize()[..]) + .push_opcode(opcodes::all::OP_SWAP) + .push_opcode(opcodes::all::OP_SIZE) + .push_int(32) + .push_opcode(opcodes::all::OP_EQUAL) + .push_opcode(opcodes::all::OP_IF) + .push_opcode(opcodes::all::OP_HASH160) + .push_slice(&payment_hash160) + .push_opcode(opcodes::all::OP_EQUALVERIFY) + .push_int(2) + .push_opcode(opcodes::all::OP_SWAP) + .push_slice(&broadcaster_htlc_key.serialize()[..]) + .push_int(2) + .push_opcode(opcodes::all::OP_CHECKMULTISIG) + .push_opcode(opcodes::all::OP_ELSE) + .push_opcode(opcodes::all::OP_DROP) + .push_int(htlc.cltv_expiry as i64) + .push_opcode(opcodes::all::OP_CLTV) + .push_opcode(opcodes::all::OP_DROP) + .push_opcode(opcodes::all::OP_CHECKSIG) + .push_opcode(opcodes::all::OP_ENDIF); if opt_anchors { bldr = bldr.push_opcode(opcodes::all::OP_PUSHNUM_1) .push_opcode(opcodes::all::OP_CSV) @@ -630,6 +668,12 @@ pub(crate) fn get_htlc_redeemscript_with_explicit_keys(htlc: &HTLCOutputInCommit } } +#[inline] +pub(crate) fn get_custom_output_redeemscript_with_explicit_keys(script: Script) -> Script { + // TODO: Embed this into a different script to make the custom output revocable! + script +} + /// Gets the witness redeemscript for an HTLC output in a commitment transaction. Note that htlc /// does not need to have its previous_output_index filled. #[inline] @@ -637,6 +681,12 @@ pub fn get_htlc_redeemscript(htlc: &HTLCOutputInCommitment, opt_anchors: bool, k get_htlc_redeemscript_with_explicit_keys(htlc, opt_anchors, &keys.broadcaster_htlc_key, &keys.countersignatory_htlc_key, &keys.revocation_key) } +/// Gets the witness redeemscript for a custom output in a commitment transaction. +#[inline] +pub fn get_custom_output_redeemscript(script: Script) -> Script { + get_custom_output_redeemscript_with_explicit_keys(script) +} + /// Gets the redeemscript for a funding output from the two funding public keys. /// Note that the order of funding public keys does not matter. pub fn make_funding_redeemscript(broadcaster: &PublicKey, countersignatory: &PublicKey) -> Script { @@ -945,7 +995,8 @@ impl HolderCommitmentTransaction { opt_anchors: None }; let mut htlcs_with_aux: Vec<(_, ())> = Vec::new(); - let inner = CommitmentTransaction::new_with_auxiliary_htlc_data(0, 0, 0, false, dummy_key.clone(), dummy_key.clone(), keys, 0, &mut htlcs_with_aux, &channel_parameters.as_counterparty_broadcastable()); + let mut custom_outputs = Vec::new(); + let inner = CommitmentTransaction::new_with_auxiliary_htlc_data(0, 0, 0, false, dummy_key.clone(), dummy_key.clone(), keys, 0, &mut htlcs_with_aux, &mut custom_outputs, &channel_parameters.as_counterparty_broadcastable()); HolderCommitmentTransaction { inner, counterparty_sig: dummy_sig, @@ -988,7 +1039,7 @@ impl HolderCommitmentTransaction { } /// A pre-built Bitcoin commitment transaction and its txid. -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct BuiltCommitmentTransaction { /// The commitment transaction pub transaction: Transaction, @@ -1151,19 +1202,21 @@ impl<'a> TrustedClosingTransaction<'a> { /// /// This class can be used inside a signer implementation to generate a signature given the relevant /// secret key. -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct CommitmentTransaction { commitment_number: u64, to_broadcaster_value_sat: u64, to_countersignatory_value_sat: u64, feerate_per_kw: u32, htlcs: Vec, + /// TODO(10101): add doc + pub custom_outputs: Vec, // A boolean that is serialization backwards-compatible opt_anchors: Option<()>, // A cache of the parties' pubkeys required to construct the transaction, see doc for trust() keys: TxCreationKeys, - // For access to the pre-built transaction, see doc for trust() - built: BuiltCommitmentTransaction, + /// For access to the pre-built transaction, see doc for trust() + pub built: BuiltCommitmentTransaction, } impl Eq for CommitmentTransaction {} @@ -1193,6 +1246,7 @@ impl_writeable_tlv_based!(CommitmentTransaction, { (10, built, required), (12, htlcs, vec_type), (14, opt_anchors, option), + (16, custom_outputs, vec_type), }); impl CommitmentTransaction { @@ -1206,9 +1260,9 @@ impl CommitmentTransaction { /// Only include HTLCs that are above the dust limit for the channel. /// /// (C-not exported) due to the generic though we likely should expose a version without - pub fn new_with_auxiliary_htlc_data(commitment_number: u64, to_broadcaster_value_sat: u64, to_countersignatory_value_sat: u64, opt_anchors: bool, broadcaster_funding_key: PublicKey, countersignatory_funding_key: PublicKey, keys: TxCreationKeys, feerate_per_kw: u32, htlcs_with_aux: &mut Vec<(HTLCOutputInCommitment, T)>, channel_parameters: &DirectedChannelTransactionParameters) -> CommitmentTransaction { + pub fn new_with_auxiliary_htlc_data(commitment_number: u64, to_broadcaster_value_sat: u64, to_countersignatory_value_sat: u64, opt_anchors: bool, broadcaster_funding_key: PublicKey, countersignatory_funding_key: PublicKey, keys: TxCreationKeys, feerate_per_kw: u32, htlcs_with_aux: &mut Vec<(HTLCOutputInCommitment, T)>, custom_outputs: &mut Vec, channel_parameters: &DirectedChannelTransactionParameters) -> CommitmentTransaction { // Sort outputs and populate output indices while keeping track of the auxiliary data - let (outputs, htlcs) = Self::internal_build_outputs(&keys, to_broadcaster_value_sat, to_countersignatory_value_sat, htlcs_with_aux, channel_parameters, opt_anchors, &broadcaster_funding_key, &countersignatory_funding_key).unwrap(); + let (outputs, htlcs, custom_outputs) = Self::internal_build_outputs(&keys, to_broadcaster_value_sat, to_countersignatory_value_sat, htlcs_with_aux, custom_outputs, channel_parameters, opt_anchors, &broadcaster_funding_key, &countersignatory_funding_key).unwrap(); let (obscured_commitment_transaction_number, txins) = Self::internal_build_inputs(commitment_number, channel_parameters); let transaction = Self::make_transaction(obscured_commitment_transaction_number, txins, outputs); @@ -1219,6 +1273,7 @@ impl CommitmentTransaction { to_countersignatory_value_sat, feerate_per_kw, htlcs, + custom_outputs, opt_anchors: if opt_anchors { Some(()) } else { None }, keys, built: BuiltCommitmentTransaction { @@ -1232,7 +1287,8 @@ impl CommitmentTransaction { let (obscured_commitment_transaction_number, txins) = Self::internal_build_inputs(self.commitment_number, channel_parameters); let mut htlcs_with_aux = self.htlcs.iter().map(|h| (h.clone(), ())).collect(); - let (outputs, _) = Self::internal_build_outputs(keys, self.to_broadcaster_value_sat, self.to_countersignatory_value_sat, &mut htlcs_with_aux, channel_parameters, self.opt_anchors.is_some(), broadcaster_funding_key, countersignatory_funding_key)?; + let mut custom_outputs = self.custom_outputs.clone(); + let (outputs, _, _) = Self::internal_build_outputs(keys, self.to_broadcaster_value_sat, self.to_countersignatory_value_sat, &mut htlcs_with_aux, &mut custom_outputs, channel_parameters, self.opt_anchors.is_some(), broadcaster_funding_key, countersignatory_funding_key)?; let transaction = Self::make_transaction(obscured_commitment_transaction_number, txins, outputs); let txid = transaction.txid(); @@ -1256,11 +1312,11 @@ impl CommitmentTransaction { // - initial sorting of outputs / HTLCs in the constructor, in which case T is auxiliary data the // caller needs to have sorted together with the HTLCs so it can keep track of the output index // - building of a bitcoin transaction during a verify() call, in which case T is just () - fn internal_build_outputs(keys: &TxCreationKeys, to_broadcaster_value_sat: u64, to_countersignatory_value_sat: u64, htlcs_with_aux: &mut Vec<(HTLCOutputInCommitment, T)>, channel_parameters: &DirectedChannelTransactionParameters, opt_anchors: bool, broadcaster_funding_key: &PublicKey, countersignatory_funding_key: &PublicKey) -> Result<(Vec, Vec), ()> { + fn internal_build_outputs(keys: &TxCreationKeys, to_broadcaster_value_sat: u64, to_countersignatory_value_sat: u64, htlcs_with_aux: &mut Vec<(HTLCOutputInCommitment, T)>, custom_outputs_in_commitment: &mut Vec, channel_parameters: &DirectedChannelTransactionParameters, opt_anchors: bool, broadcaster_funding_key: &PublicKey, countersignatory_funding_key: &PublicKey) -> Result<(Vec, Vec, Vec), ()> { let countersignatory_pubkeys = channel_parameters.countersignatory_pubkeys(); let contest_delay = channel_parameters.contest_delay(); - let mut txouts: Vec<(TxOut, Option<&mut HTLCOutputInCommitment>)> = Vec::new(); + let mut txouts: Vec<(TxOut, Option<&mut HTLCOutputInCommitment>, Option<&mut CustomOutputInCommitment>)> = Vec::new(); if to_countersignatory_value_sat > 0 { let script = if opt_anchors { @@ -1274,6 +1330,7 @@ impl CommitmentTransaction { value: to_countersignatory_value_sat, }, None, + None, )) } @@ -1289,6 +1346,7 @@ impl CommitmentTransaction { value: to_broadcaster_value_sat, }, None, + None, )); } @@ -1301,6 +1359,7 @@ impl CommitmentTransaction { value: ANCHOR_OUTPUT_VALUE_SATOSHI, }, None, + None, )); } @@ -1312,6 +1371,7 @@ impl CommitmentTransaction { value: ANCHOR_OUTPUT_VALUE_SATOSHI, }, None, + None, )); } } @@ -1323,34 +1383,62 @@ impl CommitmentTransaction { script_pubkey: script.to_v0_p2wsh(), value: htlc.amount_msat / 1000, }; - txouts.push((txout, Some(htlc))); + txouts.push((txout, Some(htlc), None)); + } + + let mut custom_outputs = Vec::with_capacity(custom_outputs_in_commitment.len()); + for custom_output_in_commitment in custom_outputs_in_commitment { + let txout = TxOut { + script_pubkey: custom_output_in_commitment.script.to_v0_p2wsh(), + value: (custom_output_in_commitment.local_amount_msat + custom_output_in_commitment.remote_amount_msat) / 1000, + }; + txouts.push((txout, None, Some(custom_output_in_commitment))); } // Sort output in BIP-69 order (amount, scriptPubkey). Tie-breaks based on HTLC // CLTV expiration height. - sort_outputs(&mut txouts, |a, b| { - if let &Some(ref a_htlcout) = a { - if let &Some(ref b_htlcout) = b { - a_htlcout.cltv_expiry.cmp(&b_htlcout.cltv_expiry) - // Note that due to hash collisions, we have to have a fallback comparison - // here for fuzzing mode (otherwise at least chanmon_fail_consistency - // may fail)! - .then(a_htlcout.payment_hash.0.cmp(&b_htlcout.payment_hash.0)) - // For non-HTLC outputs, if they're copying our SPK we don't really care if we - // close the channel due to mismatches - they're doing something dumb: - } else { cmp::Ordering::Equal } - } else { cmp::Ordering::Equal } - }); + sort_outputs(&mut txouts, + |a: &Option<&mut HTLCOutputInCommitment>, b: &Option<&mut HTLCOutputInCommitment>| { + if let &Some(ref a_htlcout) = a { + if let &Some(ref b_htlcout) = b { + a_htlcout.cltv_expiry.cmp(&b_htlcout.cltv_expiry) + // Note that due to hash collisions, we have to have a fallback comparison + // here for fuzzing mode (otherwise at least chanmon_fail_consistency + // may fail)! + .then(a_htlcout.payment_hash.0.cmp(&b_htlcout.payment_hash.0)) + // For non-HTLC outputs, if they're copying our SPK we don't really care if we + // close the channel due to mismatches - they're doing something dumb: + } else { cmp::Ordering::Equal } + } else { cmp::Ordering::Equal } + }, + |a: &Option<&mut CustomOutputInCommitment>, b: &Option<&mut CustomOutputInCommitment>| { + if let &Some(ref a_custom_output) = a { + if let &Some(ref b_custom_output) = b { + a_custom_output.cltv_expiry.cmp(&b_custom_output.cltv_expiry) + } else { cmp::Ordering::Equal } + } else { cmp::Ordering::Equal } + } + ); let mut outputs = Vec::with_capacity(txouts.len()); for (idx, out) in txouts.drain(..).enumerate() { - if let Some(htlc) = out.1 { - htlc.transaction_output_index = Some(idx as u32); - htlcs.push(htlc.clone()); + match (out.1, out.2) { + (None, None) => {}, + (Some(htlc), None) => { + htlc.transaction_output_index = Some(idx as u32); + htlcs.push(htlc.clone()); + }, + (None, Some(custom_output)) => { + custom_output.transaction_output_index = Some(idx as u32); + custom_outputs.push(custom_output.clone()); + }, + (Some(_), Some(_)) => unreachable!("Output cannot be both HTLC and custom!"), } + outputs.push(out.0); } - Ok((outputs, htlcs)) + + Ok((outputs, htlcs, custom_outputs)) } fn internal_build_inputs(commitment_number: u64, channel_parameters: &DirectedChannelTransactionParameters) -> (u64, Vec) { @@ -1618,6 +1706,7 @@ mod tests { }; let mut htlcs_with_aux: Vec<(_, ())> = Vec::new(); + let mut custom_outputs: Vec<_> = Vec::new(); // Generate broadcaster and counterparty outputs let tx = CommitmentTransaction::new_with_auxiliary_htlc_data( @@ -1626,7 +1715,9 @@ mod tests { holder_pubkeys.funding_pubkey, counterparty_pubkeys.funding_pubkey, keys.clone(), 1, - &mut htlcs_with_aux, &channel_parameters.as_holder_broadcastable() + &mut htlcs_with_aux, + &mut custom_outputs, + &channel_parameters.as_holder_broadcastable() ); assert_eq!(tx.built.transaction.output.len(), 2); assert_eq!(tx.built.transaction.output[1].script_pubkey, get_p2wpkh_redeemscript(&counterparty_pubkeys.payment_point)); @@ -1638,7 +1729,9 @@ mod tests { holder_pubkeys.funding_pubkey, counterparty_pubkeys.funding_pubkey, keys.clone(), 1, - &mut htlcs_with_aux, &channel_parameters.as_holder_broadcastable() + &mut htlcs_with_aux, + &mut custom_outputs, + &channel_parameters.as_holder_broadcastable() ); assert_eq!(tx.built.transaction.output.len(), 4); assert_eq!(tx.built.transaction.output[3].script_pubkey, get_to_countersignatory_with_anchors_redeemscript(&counterparty_pubkeys.payment_point).to_v0_p2wsh()); @@ -1650,7 +1743,9 @@ mod tests { holder_pubkeys.funding_pubkey, counterparty_pubkeys.funding_pubkey, keys.clone(), 1, - &mut htlcs_with_aux, &channel_parameters.as_holder_broadcastable() + &mut htlcs_with_aux, + &mut custom_outputs, + &channel_parameters.as_holder_broadcastable() ); assert_eq!(tx.built.transaction.output.len(), 2); @@ -1661,7 +1756,9 @@ mod tests { holder_pubkeys.funding_pubkey, counterparty_pubkeys.funding_pubkey, keys.clone(), 1, - &mut htlcs_with_aux, &channel_parameters.as_holder_broadcastable() + &mut htlcs_with_aux, + &mut custom_outputs, + &channel_parameters.as_holder_broadcastable() ); assert_eq!(tx.built.transaction.output.len(), 2); @@ -1689,6 +1786,7 @@ mod tests { counterparty_pubkeys.funding_pubkey, keys.clone(), 1, &mut vec![(received_htlc.clone(), ()), (offered_htlc.clone(), ())], + &mut custom_outputs, &channel_parameters.as_holder_broadcastable() ); assert_eq!(tx.built.transaction.output.len(), 3); @@ -1708,6 +1806,7 @@ mod tests { counterparty_pubkeys.funding_pubkey, keys.clone(), 1, &mut vec![(received_htlc.clone(), ()), (offered_htlc.clone(), ())], + &mut custom_outputs, &channel_parameters.as_holder_broadcastable() ); assert_eq!(tx.built.transaction.output.len(), 5); diff --git a/lightning/src/ln/chanmon_update_fail_tests.rs b/lightning/src/ln/chanmon_update_fail_tests.rs index f1687525242..bf72c05735b 100644 --- a/lightning/src/ln/chanmon_update_fail_tests.rs +++ b/lightning/src/ln/chanmon_update_fail_tests.rs @@ -141,7 +141,7 @@ fn test_monitor_and_persister_update_fail() { assert_eq!(updates.update_fulfill_htlcs.len(), 1); nodes[0].node.handle_update_fulfill_htlc(&nodes[1].node.get_our_node_id(), &updates.update_fulfill_htlcs[0]); if let Some(ref mut channel) = nodes[0].node.channel_state.lock().unwrap().by_id.get_mut(&chan.2) { - if let Ok((_, _, update)) = channel.commitment_signed(&updates.commitment_signed, &node_cfgs[0].logger) { + if let Ok((_, _, update, _, _)) = channel.commitment_signed(&updates.commitment_signed, &node_cfgs[0].logger) { // Check that even though the persister is returning a InProgress, // because the update is bogus, ultimately the error that's returned // should be a PermanentFailure. @@ -302,7 +302,7 @@ fn do_test_monitor_temporary_update_fail(disconnect_count: usize) { let events_2 = nodes[1].node.get_and_clear_pending_msg_events(); assert_eq!(events_2.len(), 1); let (bs_initial_fulfill, bs_initial_commitment_signed) = match events_2[0] { - MessageSendEvent::UpdateHTLCs { ref node_id, updates: msgs::CommitmentUpdate { ref update_add_htlcs, ref update_fulfill_htlcs, ref update_fail_htlcs, ref update_fail_malformed_htlcs, ref update_fee, ref commitment_signed } } => { + MessageSendEvent::UpdateCommitmentOutputs { ref node_id, updates: msgs::CommitmentUpdate { ref update_add_htlcs, ref update_fulfill_htlcs, ref update_fail_htlcs, ref update_fail_malformed_htlcs, ref update_fee, ref commitment_signed, .. } } => { assert_eq!(*node_id, nodes[0].node.get_our_node_id()); assert!(update_add_htlcs.is_empty()); assert_eq!(update_fulfill_htlcs.len(), 1); @@ -654,7 +654,7 @@ fn test_monitor_update_fail_cs() { _ => panic!("Unexpected event"), } match responses[1] { - MessageSendEvent::UpdateHTLCs { ref updates, ref node_id } => { + MessageSendEvent::UpdateCommitmentOutputs { ref updates, ref node_id } => { assert!(updates.update_add_htlcs.is_empty()); assert!(updates.update_fulfill_htlcs.is_empty()); assert!(updates.update_fail_htlcs.is_empty()); @@ -936,7 +936,7 @@ fn do_test_monitor_update_fail_raa(test_ignore_second_cs: bool) { // Note that the ordering of the events for different nodes is non-prescriptive, though the // ordering of the two events that both go to nodes[2] have to stay in the same order. let messages_a = match events_3.pop().unwrap() { - MessageSendEvent::UpdateHTLCs { node_id, mut updates } => { + MessageSendEvent::UpdateCommitmentOutputs { node_id, mut updates } => { assert_eq!(node_id, nodes[0].node.get_our_node_id()); assert!(updates.update_fulfill_htlcs.is_empty()); assert_eq!(updates.update_fail_htlcs.len(), 1); @@ -1004,7 +1004,7 @@ fn do_test_monitor_update_fail_raa(test_ignore_second_cs: bool) { as_cs = get_htlc_update_msgs!(nodes[1], nodes[2].node.get_our_node_id()); match bs_revoke_and_commit[1] { - MessageSendEvent::UpdateHTLCs { ref node_id, ref updates } => { + MessageSendEvent::UpdateCommitmentOutputs { ref node_id, ref updates } => { assert_eq!(*node_id, nodes[1].node.get_our_node_id()); assert!(updates.update_add_htlcs.is_empty()); assert!(updates.update_fail_htlcs.is_empty()); @@ -1364,7 +1364,7 @@ fn claim_while_disconnected_monitor_update_fail() { assert_eq!(bs_msgs.len(), 2); match bs_msgs[0] { - MessageSendEvent::UpdateHTLCs { ref node_id, ref updates } => { + MessageSendEvent::UpdateCommitmentOutputs { ref node_id, ref updates } => { assert_eq!(*node_id, nodes[0].node.get_our_node_id()); nodes[0].node.handle_update_fulfill_htlc(&nodes[1].node.get_our_node_id(), &updates.update_fulfill_htlcs[0]); nodes[0].node.handle_commitment_signed(&nodes[1].node.get_our_node_id(), &updates.commitment_signed); @@ -2040,7 +2040,7 @@ fn test_pending_update_fee_ack_on_reconnect() { nodes[1].node.handle_channel_reestablish(&nodes[0].node.get_our_node_id(), &as_connect_msg); let bs_resend_msgs = nodes[1].node.get_and_clear_pending_msg_events(); assert_eq!(bs_resend_msgs.len(), 3); - if let MessageSendEvent::UpdateHTLCs { ref updates, .. } = bs_resend_msgs[0] { + if let MessageSendEvent::UpdateCommitmentOutputs { ref updates, .. } = bs_resend_msgs[0] { assert_eq!(*updates, bs_initial_send_msgs); } else { panic!(); } if let MessageSendEvent::SendRevokeAndACK { ref msg, .. } = bs_resend_msgs[1] { @@ -2173,7 +2173,7 @@ fn do_update_fee_resend_test(deliver_update: bool, parallel_updates: bool) { let mut as_reconnect_msgs = nodes[0].node.get_and_clear_pending_msg_events(); assert_eq!(as_reconnect_msgs.len(), 2); if let MessageSendEvent::SendChannelUpdate { .. } = as_reconnect_msgs.pop().unwrap() {} else { panic!(); } - let update_msgs = if let MessageSendEvent::UpdateHTLCs { updates, .. } = as_reconnect_msgs.pop().unwrap() + let update_msgs = if let MessageSendEvent::UpdateCommitmentOutputs { updates, .. } = as_reconnect_msgs.pop().unwrap() { updates } else { panic!(); }; assert!(update_msgs.update_fee.is_some()); nodes[1].node.handle_update_fee(&nodes[0].node.get_our_node_id(), update_msgs.update_fee.as_ref().unwrap()); @@ -2379,7 +2379,7 @@ fn do_channel_holding_cell_serialize(disconnect: bool, reload_a: bool) { check_added_monitors!(nodes[0], 1); let commitment_msg = match events.pop().unwrap() { - MessageSendEvent::UpdateHTLCs { node_id, updates } => { + MessageSendEvent::UpdateCommitmentOutputs { node_id, updates } => { assert_eq!(node_id, nodes[1].node.get_our_node_id()); assert!(updates.update_fail_htlcs.is_empty()); assert!(updates.update_fail_malformed_htlcs.is_empty()); @@ -2686,7 +2686,7 @@ fn double_temp_error() { assert_eq!(events.len(), 1); let (update_fulfill_1, commitment_signed_b1, node_id) = { match &events[0] { - &MessageSendEvent::UpdateHTLCs { ref node_id, updates: msgs::CommitmentUpdate { ref update_add_htlcs, ref update_fulfill_htlcs, ref update_fail_htlcs, ref update_fail_malformed_htlcs, ref update_fee, ref commitment_signed } } => { + &MessageSendEvent::UpdateCommitmentOutputs { ref node_id, updates: msgs::CommitmentUpdate { ref update_add_htlcs, ref update_fulfill_htlcs, ref update_fail_htlcs, ref update_fail_malformed_htlcs, ref update_fee, ref commitment_signed, .. } } => { assert!(update_add_htlcs.is_empty()); assert_eq!(update_fulfill_htlcs.len(), 1); assert!(update_fail_htlcs.is_empty()); @@ -2717,7 +2717,7 @@ fn double_temp_error() { let events = nodes[1].node.get_and_clear_pending_msg_events(); assert_eq!(events.len(), 2); (match &events[0] { - MessageSendEvent::UpdateHTLCs { node_id, updates } => { + MessageSendEvent::UpdateCommitmentOutputs { node_id, updates } => { assert_eq!(*node_id, nodes[0].node.get_our_node_id()); assert!(updates.update_add_htlcs.is_empty()); assert!(updates.update_fail_htlcs.is_empty()); diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs index 7af90c4f843..64171dac299 100644 --- a/lightning/src/ln/channel.rs +++ b/lightning/src/ln/channel.rs @@ -27,8 +27,8 @@ use crate::ln::features::{ChannelTypeFeatures, InitFeatures}; use crate::ln::msgs; use crate::ln::msgs::{DecodeError, OptionalField, DataLossProtect}; use crate::ln::script::{self, ShutdownScript}; -use crate::ln::channelmanager::{self, CounterpartyForwardingInfo, PendingHTLCStatus, HTLCSource, HTLCFailReason, HTLCFailureMsg, PendingHTLCInfo, RAACommitmentOrder, BREAKDOWN_TIMEOUT, MIN_CLTV_EXPIRY_DELTA, MAX_LOCAL_BREAKDOWN_TIMEOUT}; -use crate::ln::chan_utils::{CounterpartyCommitmentSecrets, TxCreationKeys, HTLCOutputInCommitment, htlc_success_tx_weight, htlc_timeout_tx_weight, make_funding_redeemscript, ChannelPublicKeys, CommitmentTransaction, HolderCommitmentTransaction, ChannelTransactionParameters, CounterpartyChannelTransactionParameters, MAX_HTLCS, get_commitment_transaction_number_obscure_factor, ClosingTransaction}; +use crate::ln::channelmanager::{self, CounterpartyForwardingInfo, PendingHTLCStatus, HTLCSource, HTLCFailReason, HTLCFailureMsg, PendingHTLCInfo, RAACommitmentOrder, BREAKDOWN_TIMEOUT, MIN_CLTV_EXPIRY_DELTA, MAX_LOCAL_BREAKDOWN_TIMEOUT, CustomOutputId, CustomOutputDetails}; +use crate::ln::chan_utils::{CounterpartyCommitmentSecrets, TxCreationKeys, HTLCOutputInCommitment, htlc_success_tx_weight, htlc_timeout_tx_weight, make_funding_redeemscript, ChannelPublicKeys, CommitmentTransaction, HolderCommitmentTransaction, ChannelTransactionParameters, CounterpartyChannelTransactionParameters, MAX_HTLCS, get_commitment_transaction_number_obscure_factor, ClosingTransaction, CustomOutputInCommitment, get_custom_output_redeemscript}; use crate::ln::chan_utils; use crate::chain::BestBlock; use crate::chain::chaininterface::{FeeEstimator, ConfirmationTarget, LowerBoundedFeeEstimator}; @@ -221,6 +221,65 @@ struct OutboundHTLCOutput { source: HTLCSource, } +#[derive(Debug)] +struct CustomOutput { + custom_output_id: CustomOutputId, + /// Initial amount provided by local node + local_amount_msat: u64, + /// Initial amount provided by remote node + remote_amount_msat: u64, + cltv_expiry: u32, + script: Script, + state: CustomOutputState, +} + +// TODO(10101): The variants are tentative +#[derive(PartialEq, Debug)] +enum CustomOutputState { + Alpha(AlphaCustomOutputState), + Beta(BetaCustomOutputState), +} + +#[derive(PartialEq, Debug)] +enum AlphaCustomOutputState { + LocalAddedCustomOutput, + ReceivedRemoteCommitmentSignature, + LocalCommitmentSignatureSent, + RevokeAndAckSent, + RevokeAndAckReceived, + // Removing states + LocalRemoved { + local_profit: i64, + }, + RemoteRemoved { + local_profit: i64, + }, + AwaitingRemoteToRevokeAfterRemoval{ + local_profit: i64, + }, +} + +#[derive(PartialEq, Debug)] +enum BetaCustomOutputState { + ReceivedAddCustomOutputRequest, + LocalAddedCustomOutput, + LocalCommitmentSignatureSent, + RemoteCommitmentSignatureReceived, + RevokeAndAckReceived, + RevokeAndAckSent, + // Removing states + LocalRemoved{ + local_profit: i64, + }, + RemoteRemoved{ + local_profit: i64, + }, + AwaitingRemoteToRevokeAfterRemoval{ + local_profit: i64, + }, +} + + /// See AwaitingRemoteRevoke ChannelState for more info enum HTLCUpdateAwaitingACK { AddHTLC { // TODO: Time out if we're getting close to cltv_expiry @@ -316,6 +375,16 @@ pub(super) enum ChannelUpdateStatus { Disabled, } +pub enum ShouldRevoke { + Yes, + No +} + +pub enum DidRemoteSendCustomOutputCommitmentSignature { + Yes, + No +} + /// We track when we sent an `AnnouncementSignatures` to our peer in a few states, described here. #[derive(PartialEq)] pub enum AnnouncementSigsState { @@ -352,12 +421,29 @@ struct HTLCStats { on_holder_tx_holding_cell_htlcs_count: u32, // dust HTLCs *non*-included } +// Gathering stats on pending custom outputs, inbound side +#[allow(dead_code)] +struct CustomOutputInboundStats { + pending_custom_outputs: u32, + pending_custom_outputs_msat: u64, +} + +// Gathering stats on pending custom outputs, outbound side +#[allow(dead_code)] +struct CustomOutputOutboundStats { + pending_custom_outputs: u32, + pending_custom_outputs_msat: u64, +} + + /// An enum gathering stats on commitment transaction, either local or remote. -struct CommitmentStats<'a> { +#[derive(Debug)] +pub struct CommitmentStats<'a> { tx: CommitmentTransaction, // the transaction info feerate_per_kw: u32, // the feerate included to build the transaction total_fee_sat: u64, // the total fee included in the transaction num_nondust_htlcs: usize, // the number of HTLC outputs (dust HTLCs *non*-included) + num_nondust_custom_outputs: usize, // the number of custom outputs (dust custom outputs *non*included) htlcs_included: Vec<(HTLCOutputInCommitment, Option<&'a HTLCSource>)>, // the list of HTLCs (dust HTLCs *included*) which were not ignored when building the transaction local_balance_msat: u64, // local balance before fees but considering dust limits remote_balance_msat: u64, // remote balance before fees but considering dust limits @@ -540,10 +626,11 @@ pub(super) struct Channel { // cost of others, but should really just be changed. cur_holder_commitment_transaction_number: u64, - cur_counterparty_commitment_transaction_number: u64, + pub cur_counterparty_commitment_transaction_number: u64, value_to_self_msat: u64, // Excluding all pending_htlcs, excluding fees pending_inbound_htlcs: Vec, pending_outbound_htlcs: Vec, + pending_custom_outputs: HashMap, holding_cell_htlc_updates: Vec, /// When resending CS/RAA messages on channel monitor restoration or on reconnect, we always @@ -576,7 +663,9 @@ pub(super) struct Channel { // further `send_update_fee` calls, dropping the previous holding cell update entirely. holding_cell_update_fee: Option, next_holder_htlc_id: u64, + next_holder_custom_output_id: u64, next_counterparty_htlc_id: u64, + next_counterparty_custom_output_id: u64, feerate_per_kw: u32, /// The timestamp set on our latest `channel_update` message for this channel. It is updated @@ -757,6 +846,8 @@ pub(crate) fn commitment_tx_base_weight(opt_anchors: bool) -> u64 { #[cfg(not(test))] const COMMITMENT_TX_WEIGHT_PER_HTLC: u64 = 172; +// TODO(10101): this needs to updated once we know the custom output script +const COMMITMENT_TX_WEIGHT_PER_CUSTOM_OUTPUT: u64 = 172; #[cfg(test)] pub const COMMITMENT_TX_WEIGHT_PER_HTLC: u64 = 172; @@ -934,7 +1025,7 @@ impl Channel { let feerate = fee_estimator.bounded_sat_per_1000_weight(ConfirmationTarget::Normal); let value_to_self_msat = channel_value_satoshis * 1000 - push_msat; - let commitment_tx_fee = Self::commit_tx_fee_msat(feerate, MIN_AFFORDABLE_HTLC_COUNT, opt_anchors); + let commitment_tx_fee = Self::commit_tx_fee_msat(feerate, MIN_AFFORDABLE_HTLC_COUNT, 0, opt_anchors); if value_to_self_msat < commitment_tx_fee { return Err(APIError::APIMisuseError{ err: format!("Funding amount ({}) can't even pay fee for initial commitment transaction fee of {}.", value_to_self_msat / 1000, commitment_tx_fee / 1000) }); } @@ -983,11 +1074,14 @@ impl Channel { pending_inbound_htlcs: Vec::new(), pending_outbound_htlcs: Vec::new(), + pending_custom_outputs: HashMap::new(), holding_cell_htlc_updates: Vec::new(), pending_update_fee: None, holding_cell_update_fee: None, next_holder_htlc_id: 0, + next_holder_custom_output_id: 0, next_counterparty_htlc_id: 0, + next_counterparty_custom_output_id: 0, update_time_counter: 1, resend_order: RAACommitmentOrder::CommitmentFirst, @@ -1238,7 +1332,7 @@ impl Channel { // check if the funder's amount for the initial commitment tx is sufficient // for full fee payment plus a few HTLCs to ensure the channel will be useful. let funders_amount_msat = msg.funding_satoshis * 1000 - msg.push_msat; - let commitment_tx_fee = Self::commit_tx_fee_msat(msg.feerate_per_kw, MIN_AFFORDABLE_HTLC_COUNT, opt_anchors) / 1000; + let commitment_tx_fee = Self::commit_tx_fee_msat(msg.feerate_per_kw, MIN_AFFORDABLE_HTLC_COUNT, 0,opt_anchors) / 1000; if funders_amount_msat / 1000 < commitment_tx_fee { return Err(ChannelError::Close(format!("Funding amount ({} sats) can't even pay fee for initial commitment transaction fee of {} sats.", funders_amount_msat / 1000, commitment_tx_fee))); } @@ -1313,11 +1407,14 @@ impl Channel { pending_inbound_htlcs: Vec::new(), pending_outbound_htlcs: Vec::new(), + pending_custom_outputs: HashMap::new(), holding_cell_htlc_updates: Vec::new(), pending_update_fee: None, holding_cell_update_fee: None, next_holder_htlc_id: 0, + next_holder_custom_output_id: 0, next_counterparty_htlc_id: 0, + next_counterparty_custom_output_id: 0, update_time_counter: 1, resend_order: RAACommitmentOrder::CommitmentFirst, @@ -1427,6 +1524,8 @@ impl Channel { let num_htlcs = self.pending_inbound_htlcs.len() + self.pending_outbound_htlcs.len(); let mut included_non_dust_htlcs: Vec<(HTLCOutputInCommitment, Option<&HTLCSource>)> = Vec::with_capacity(num_htlcs); + let mut included_custom_outputs: Vec = Vec::with_capacity(self.pending_custom_outputs.len()); + let broadcaster_dust_limit_satoshis = if local { self.holder_dust_limit_satoshis } else { self.counterparty_dust_limit_satoshis }; let mut remote_htlc_total_msat = 0; let mut local_htlc_total_msat = 0; @@ -1437,9 +1536,18 @@ impl Channel { if match update_state { // Note that these match the inclusion criteria when scanning // pending_inbound_htlcs below. - FeeUpdateState::RemoteAnnounced => { debug_assert!(!self.is_outbound()); !generated_by_local }, - FeeUpdateState::AwaitingRemoteRevokeToAnnounce => { debug_assert!(!self.is_outbound()); !generated_by_local }, - FeeUpdateState::Outbound => { assert!(self.is_outbound()); generated_by_local }, + FeeUpdateState::RemoteAnnounced => { + debug_assert!(!self.is_outbound()); + !generated_by_local + }, + FeeUpdateState::AwaitingRemoteRevokeToAnnounce => { + debug_assert!(!self.is_outbound()); + !generated_by_local + }, + FeeUpdateState::Outbound => { + assert!(self.is_outbound()); + generated_by_local + }, } { feerate_per_kw = feerate; } @@ -1551,7 +1659,7 @@ impl Channel { } else { log_trace!(logger, " ...not including outbound HTLC {} (hash {}) with value {} due to state ({})", htlc.htlc_id, log_bytes!(htlc.payment_hash.0), htlc.amount_msat, state_name); match htlc.state { - OutboundHTLCState::AwaitingRemoteRevokeToRemove(OutboundHTLCOutcome::Success(_))|OutboundHTLCState::AwaitingRemovedRemoteRevoke(OutboundHTLCOutcome::Success(_)) => { + OutboundHTLCState::AwaitingRemoteRevokeToRemove(OutboundHTLCOutcome::Success(_)) | OutboundHTLCState::AwaitingRemovedRemoteRevoke(OutboundHTLCOutcome::Success(_)) => { value_to_self_msat_offset -= htlc.amount_msat as i64; }, OutboundHTLCState::RemoteRemoved(OutboundHTLCOutcome::Success(_)) => { @@ -1564,13 +1672,94 @@ impl Channel { } } - let mut value_to_self_msat: i64 = (self.value_to_self_msat - local_htlc_total_msat) as i64 + value_to_self_msat_offset; + let mut from_self_custom_output_msat = 0; + let mut from_remote_custom_output_msat = 0; + let mut local_settlement_profit_msat = 0; + for (_, ref custom_output) in self.pending_custom_outputs.iter() { + let state_name = match &custom_output.state { + CustomOutputState::Alpha(AlphaCustomOutputState::RemoteRemoved { .. }) => { "AlphaRemoteRemoved" } + CustomOutputState::Alpha(AlphaCustomOutputState::LocalAddedCustomOutput) => { "AlphaLocalAddedCustomOutput" } + CustomOutputState::Alpha(AlphaCustomOutputState::ReceivedRemoteCommitmentSignature) => { "AlphaRemoteCommitmentSignatureReceived" } + CustomOutputState::Alpha(AlphaCustomOutputState::LocalCommitmentSignatureSent) => { "AlphaLocalCommitmentSignatureSent" } + CustomOutputState::Alpha(AlphaCustomOutputState::RevokeAndAckSent) => { "AlphaRevokeAndAckSent" } + CustomOutputState::Alpha(AlphaCustomOutputState::RevokeAndAckReceived) => { "AlphaRevokeAndAckReceived" } + CustomOutputState::Alpha(AlphaCustomOutputState::LocalRemoved { .. }) => { "AlphaLocalRemoved" } + CustomOutputState::Alpha(AlphaCustomOutputState::AwaitingRemoteToRevokeAfterRemoval { .. }) => { "AlphaAwaitingRemoteToRevokeAfterRemoval" } + CustomOutputState::Beta(BetaCustomOutputState::ReceivedAddCustomOutputRequest) => { "BetaReceivedAddCustomOutputRequest" } + CustomOutputState::Beta(BetaCustomOutputState::LocalAddedCustomOutput) => { "BetaLocalAddedCustomOutput" } + CustomOutputState::Beta(BetaCustomOutputState::LocalCommitmentSignatureSent) => { "BetaLocalCommitmentSignatureSent" } + CustomOutputState::Beta(BetaCustomOutputState::RemoteCommitmentSignatureReceived) => { "BetaRemoteCommitmentSignatureReceived" } + CustomOutputState::Beta(BetaCustomOutputState::RevokeAndAckReceived) => { "BetaRevokeAndAckReceived" } + CustomOutputState::Beta(BetaCustomOutputState::RevokeAndAckSent) => { "BetaRevokeAndAckSent" } + CustomOutputState::Beta(BetaCustomOutputState::LocalRemoved { .. }) => { "BetaLocalRemoved" } + CustomOutputState::Beta(BetaCustomOutputState::RemoteRemoved { .. }) => { "BetaRemoteRemoved" } + CustomOutputState::Beta(BetaCustomOutputState::AwaitingRemoteToRevokeAfterRemoval { .. }) => { "BetaAwaitingRemoteToRevokeAfterRemoval" } + }; + + // TODO(10101): Use `generated_by_local` and `custom_output.state` to determine if the output should be included in the transaction? + + // Ignoring inbound or outbound + // Ignoring `self.opt_anchors()` for now? + + + let script = get_custom_output_redeemscript(custom_output.script.clone()); + let custom_output_in_tx = CustomOutputInCommitment { + id: custom_output.custom_output_id, + local_amount_msat: custom_output.local_amount_msat, + remote_amount_msat: custom_output.remote_amount_msat, + cltv_expiry: custom_output.cltv_expiry, + script, + transaction_output_index: None, + }; + // let custom_output_tx_fee = feerate_per_kw as u64 * custom_output_tx_weight / 1000; + + // assume custom output is > dust limit + associated tx fee, therefore always include + + if let CustomOutputState::Alpha(AlphaCustomOutputState::LocalAddedCustomOutput) | + CustomOutputState::Alpha(AlphaCustomOutputState::ReceivedRemoteCommitmentSignature) | + CustomOutputState::Alpha(AlphaCustomOutputState::LocalCommitmentSignatureSent) | + CustomOutputState::Beta(BetaCustomOutputState::LocalAddedCustomOutput) | + CustomOutputState::Beta(BetaCustomOutputState::ReceivedAddCustomOutputRequest) | + CustomOutputState::Beta(BetaCustomOutputState::LocalCommitmentSignatureSent) = &custom_output.state { + included_custom_outputs.push(custom_output_in_tx); + log_trace!( + logger, + " ...including {} custom output {} with value {}", + state_name, + custom_output.custom_output_id, + custom_output.local_amount_msat + custom_output.remote_amount_msat + ); + } + + match custom_output.state { + CustomOutputState::Alpha(AlphaCustomOutputState::LocalAddedCustomOutput) | + CustomOutputState::Alpha(AlphaCustomOutputState::ReceivedRemoteCommitmentSignature) | + CustomOutputState::Beta( + BetaCustomOutputState::ReceivedAddCustomOutputRequest | + BetaCustomOutputState::LocalAddedCustomOutput | + BetaCustomOutputState::LocalCommitmentSignatureSent + ) => { + from_self_custom_output_msat += custom_output.local_amount_msat; + from_remote_custom_output_msat += custom_output.remote_amount_msat; + } + CustomOutputState::Alpha(AlphaCustomOutputState::LocalRemoved { local_profit }) | CustomOutputState::Alpha(AlphaCustomOutputState::RemoteRemoved { local_profit }) | CustomOutputState::Alpha(AlphaCustomOutputState::AwaitingRemoteToRevokeAfterRemoval { local_profit }) | + CustomOutputState::Beta(BetaCustomOutputState::LocalRemoved { local_profit }) | CustomOutputState::Beta(BetaCustomOutputState::RemoteRemoved { local_profit }) | CustomOutputState::Beta(BetaCustomOutputState::AwaitingRemoteToRevokeAfterRemoval { local_profit }) + => { + local_settlement_profit_msat += local_profit; + } + _ => { + // not needed + } + } + } + + let mut value_to_self_msat: i64 = (self.value_to_self_msat - local_htlc_total_msat - from_self_custom_output_msat) as i64 + value_to_self_msat_offset + local_settlement_profit_msat as i64; assert!(value_to_self_msat >= 0); // Note that in case they have several just-awaiting-last-RAA fulfills in-progress (ie // AwaitingRemoteRevokeToRemove or AwaitingRemovedRemoteRevoke) we may have allowed them to - // "violate" their reserve value by couting those against it. Thus, we have to convert + // "violate" their reserve value by counting those against it. Thus, we have to convert // everything to i64 before subtracting as otherwise we can overflow. - let mut value_to_remote_msat: i64 = (self.channel_value_satoshis * 1000) as i64 - (self.value_to_self_msat as i64) - (remote_htlc_total_msat as i64) - value_to_self_msat_offset; + let mut value_to_remote_msat: i64 = (self.channel_value_satoshis * 1000) as i64 - (self.value_to_self_msat) as i64 - (remote_htlc_total_msat as i64) - value_to_self_msat_offset - from_remote_custom_output_msat as i64 - local_settlement_profit_msat; assert!(value_to_remote_msat >= 0); #[cfg(debug_assertions)] @@ -1588,7 +1777,7 @@ impl Channel { broadcaster_max_commitment_tx_output.1 = cmp::max(broadcaster_max_commitment_tx_output.1, value_to_remote_msat as u64); } - let total_fee_sat = Channel::::commit_tx_fee_sat(feerate_per_kw, included_non_dust_htlcs.len(), self.channel_transaction_parameters.opt_anchors.is_some()); + let total_fee_sat = Channel::::commit_tx_fee_sat(feerate_per_kw, included_non_dust_htlcs.len(), included_custom_outputs.len(), self.channel_transaction_parameters.opt_anchors.is_some()); let anchors_val = if self.channel_transaction_parameters.opt_anchors.is_some() { ANCHOR_OUTPUT_VALUE_SATOSHI * 2 } else { 0 } as i64; let (value_to_self, value_to_remote) = if self.is_outbound() { (value_to_self_msat / 1000 - anchors_val - total_fee_sat as i64, value_to_remote_msat / 1000) @@ -1619,18 +1808,19 @@ impl Channel { let num_nondust_htlcs = included_non_dust_htlcs.len(); let channel_parameters = - if local { self.channel_transaction_parameters.as_holder_broadcastable() } - else { self.channel_transaction_parameters.as_counterparty_broadcastable() }; - let tx = CommitmentTransaction::new_with_auxiliary_htlc_data(commitment_number, - value_to_a as u64, - value_to_b as u64, - self.channel_transaction_parameters.opt_anchors.is_some(), - funding_pubkey_a, - funding_pubkey_b, - keys.clone(), - feerate_per_kw, - &mut included_non_dust_htlcs, - &channel_parameters + if local { self.channel_transaction_parameters.as_holder_broadcastable() } else { self.channel_transaction_parameters.as_counterparty_broadcastable() }; + let tx = CommitmentTransaction::new_with_auxiliary_htlc_data( + commitment_number, + value_to_a as u64, + value_to_b as u64, + self.channel_transaction_parameters.opt_anchors.is_some(), + funding_pubkey_a, + funding_pubkey_b, + keys.clone(), + feerate_per_kw, + &mut included_non_dust_htlcs, + &mut included_custom_outputs, + &channel_parameters, ); let mut htlcs_included = included_non_dust_htlcs; // The unwrap is safe, because all non-dust HTLCs have been assigned an output index @@ -1646,10 +1836,11 @@ impl Channel { feerate_per_kw, total_fee_sat, num_nondust_htlcs, + num_nondust_custom_outputs: included_custom_outputs.len(), htlcs_included, local_balance_msat: value_to_self_msat as u64, remote_balance_msat: value_to_remote_msat as u64, - preimages + preimages, } } @@ -2230,12 +2421,12 @@ impl Channel { 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(), - shutdown_script, self.get_holder_selected_contest_delay(), - &self.destination_script, (funding_txo, funding_txo_script.clone()), - &self.channel_transaction_parameters, - funding_redeemscript.clone(), self.channel_value_satoshis, - obscure_factor, - holder_commitment_tx, best_block, self.counterparty_node_id); + shutdown_script, self.get_holder_selected_contest_delay(), + &self.destination_script, (funding_txo, funding_txo_script.clone()), + &self.channel_transaction_parameters, + funding_redeemscript.clone(), self.channel_value_satoshis, + obscure_factor, + holder_commitment_tx, best_block, self.counterparty_node_id); channel_monitor.provide_latest_counterparty_commitment_tx(counterparty_initial_commitment_txid, Vec::new(), self.cur_counterparty_commitment_transaction_number, self.counterparty_cur_commitment_point.unwrap(), logger); @@ -2307,12 +2498,12 @@ impl Channel { 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(), - shutdown_script, self.get_holder_selected_contest_delay(), - &self.destination_script, (funding_txo, funding_txo_script), - &self.channel_transaction_parameters, - funding_redeemscript.clone(), self.channel_value_satoshis, - obscure_factor, - holder_commitment_tx, best_block, self.counterparty_node_id); + shutdown_script, self.get_holder_selected_contest_delay(), + &self.destination_script, (funding_txo, funding_txo_script), + &self.channel_transaction_parameters, + funding_redeemscript.clone(), self.channel_value_satoshis, + obscure_factor, + holder_commitment_tx, best_block, self.counterparty_node_id); channel_monitor.provide_latest_counterparty_commitment_tx(counterparty_initial_bitcoin_tx.txid, Vec::new(), self.cur_counterparty_commitment_transaction_number, self.counterparty_cur_commitment_point.unwrap(), logger); @@ -2354,7 +2545,7 @@ impl Channel { } else if self.channel_state & (ChannelState::ChannelFunded as u32) != 0 || // If we reconnected before sending our `channel_ready` they may still resend theirs: (self.channel_state & (ChannelState::FundingSent as u32 | ChannelState::TheirChannelReady as u32) == - (ChannelState::FundingSent as u32 | ChannelState::TheirChannelReady as u32)) + (ChannelState::FundingSent as u32 | ChannelState::TheirChannelReady as u32)) { // They probably disconnected/reconnected and re-sent the channel_ready, which is // required, or they're sending a fresh SCID alias. @@ -2427,6 +2618,83 @@ impl Channel { stats } + fn get_inbound_pending_custom_output_stats(&self) -> CustomOutputInboundStats { + let mut sum_msats = 0i64; + for (_, ref output) in self.pending_custom_outputs.iter() { + // TODO(10101): do we need to handle `< holder_dust_limit_success_sat` here as above? + match output.state { + CustomOutputState::Alpha(AlphaCustomOutputState::LocalAddedCustomOutput) | + CustomOutputState::Alpha(AlphaCustomOutputState::ReceivedRemoteCommitmentSignature) | + CustomOutputState::Alpha(AlphaCustomOutputState::LocalCommitmentSignatureSent) | + CustomOutputState::Alpha(AlphaCustomOutputState::RevokeAndAckSent) | + CustomOutputState::Alpha(AlphaCustomOutputState::RevokeAndAckReceived) | + CustomOutputState::Beta(BetaCustomOutputState::LocalAddedCustomOutput) | + CustomOutputState::Beta(BetaCustomOutputState::ReceivedAddCustomOutputRequest) | + CustomOutputState::Beta(BetaCustomOutputState::LocalCommitmentSignatureSent) | + CustomOutputState::Beta(BetaCustomOutputState::RemoteCommitmentSignatureReceived) | + CustomOutputState::Beta(BetaCustomOutputState::RevokeAndAckReceived) | + CustomOutputState::Beta(BetaCustomOutputState::RevokeAndAckSent) => { + sum_msats += output.remote_amount_msat as i64; + } + CustomOutputState::Alpha(AlphaCustomOutputState::LocalRemoved { local_profit }) | + CustomOutputState::Alpha(AlphaCustomOutputState::RemoteRemoved { local_profit }) | + CustomOutputState::Alpha(AlphaCustomOutputState::AwaitingRemoteToRevokeAfterRemoval { local_profit }) | + CustomOutputState::Beta(BetaCustomOutputState::LocalRemoved { local_profit }) | + CustomOutputState::Beta(BetaCustomOutputState::RemoteRemoved { local_profit }) | + CustomOutputState::Beta(BetaCustomOutputState::AwaitingRemoteToRevokeAfterRemoval { local_profit }) => { + // + sum_msats += local_profit * -1; + } + } + } + + let pending_custom_outputs_msat = if sum_msats < 0 { 0 } else { sum_msats as u64 }; + + CustomOutputInboundStats { + pending_custom_outputs: self.pending_custom_outputs.len() as u32, + pending_custom_outputs_msat + } + + } + + fn get_outbound_pending_custom_output_stats(&self) -> CustomOutputOutboundStats { + let mut sum_msats = 0i64; + for (_, ref output) in self.pending_custom_outputs.iter() { + // TODO(10101): do we need to handle `< holder_dust_limit_success_sat` here as above? + match output.state { + CustomOutputState::Alpha(AlphaCustomOutputState::LocalAddedCustomOutput) | + CustomOutputState::Alpha(AlphaCustomOutputState::ReceivedRemoteCommitmentSignature) | + CustomOutputState::Alpha(AlphaCustomOutputState::LocalCommitmentSignatureSent) | + CustomOutputState::Alpha(AlphaCustomOutputState::RevokeAndAckSent) | + CustomOutputState::Alpha(AlphaCustomOutputState::RevokeAndAckReceived) | + CustomOutputState::Beta(BetaCustomOutputState::LocalAddedCustomOutput) | + CustomOutputState::Beta(BetaCustomOutputState::ReceivedAddCustomOutputRequest) | + CustomOutputState::Beta(BetaCustomOutputState::LocalCommitmentSignatureSent) | + CustomOutputState::Beta(BetaCustomOutputState::RemoteCommitmentSignatureReceived) | + CustomOutputState::Beta(BetaCustomOutputState::RevokeAndAckReceived) | + CustomOutputState::Beta(BetaCustomOutputState::RevokeAndAckSent) => { + sum_msats += output.local_amount_msat as i64; + } + CustomOutputState::Alpha(AlphaCustomOutputState::LocalRemoved { local_profit }) | + CustomOutputState::Alpha(AlphaCustomOutputState::RemoteRemoved { local_profit }) | + CustomOutputState::Alpha(AlphaCustomOutputState::AwaitingRemoteToRevokeAfterRemoval { local_profit }) | + CustomOutputState::Beta(BetaCustomOutputState::LocalRemoved { local_profit }) | + CustomOutputState::Beta(BetaCustomOutputState::RemoteRemoved { local_profit }) | + CustomOutputState::Beta(BetaCustomOutputState::AwaitingRemoteToRevokeAfterRemoval { local_profit }) => { + // + sum_msats += local_profit; + } + } + } + + let pending_custom_outputs_msat = if sum_msats < 0 { 0 } else { sum_msats as u64 }; + + CustomOutputOutboundStats { + pending_custom_outputs: self.pending_custom_outputs.len() as u32, + pending_custom_outputs_msat + } + } + /// Returns a HTLCStats about pending outbound htlcs, *including* pending adds in our holding cell. fn get_outbound_pending_htlc_stats(&self, outbound_feerate_update: Option) -> HTLCStats { let mut stats = HTLCStats { @@ -2490,15 +2758,69 @@ impl Channel { } } balance_msat -= outbound_stats.pending_htlcs_value_msat; + let mut sum_profit = 0; + + for (_, ref custom_output) in self.pending_custom_outputs.iter() { + match custom_output.state { + /*CustomOutputState::LocalAnnounced => { + balance_msat -= custom_output.local_amount_msat; + } + CustomOutputState::RemoteAnnounced => { + balance_msat -= custom_output.remote_amount_msat; + }, + CustomOutputState::AwaitingRemoteRevoke => { + balance_msat -= custom_output.remote_amount_msat; + }, + CustomOutputState::LocalRemoved { local_profit } | CustomOutputState::RemoteRemoved { local_profit } | CustomOutputState::AwaitingRemoteRemoveToRevoke { local_profit } => { + sum_profit += local_profit; + }, + CustomOutputState::Committed | CustomOutputState::RemoteSettled | CustomOutputState::AwaitingRemoteRevokeToSettle | CustomOutputState::AwaitingRemovedRemoteRevoke => { + unimplemented!("Not used so far") + }*/ + CustomOutputState::Alpha(AlphaCustomOutputState::LocalAddedCustomOutput) | + CustomOutputState::Alpha(AlphaCustomOutputState::ReceivedRemoteCommitmentSignature) | + CustomOutputState::Alpha(AlphaCustomOutputState::LocalCommitmentSignatureSent) | + CustomOutputState::Alpha(AlphaCustomOutputState::RevokeAndAckSent) | + CustomOutputState::Alpha(AlphaCustomOutputState::RevokeAndAckReceived) => { + balance_msat -= custom_output.local_amount_msat; + } + CustomOutputState::Alpha(AlphaCustomOutputState::LocalRemoved { local_profit }) | + CustomOutputState::Alpha(AlphaCustomOutputState::RemoteRemoved { local_profit }) | + CustomOutputState::Alpha(AlphaCustomOutputState::AwaitingRemoteToRevokeAfterRemoval { local_profit }) => { + sum_profit += local_profit; + } + CustomOutputState::Beta(BetaCustomOutputState::LocalAddedCustomOutput) | + CustomOutputState::Beta(BetaCustomOutputState::ReceivedAddCustomOutputRequest) | + CustomOutputState::Beta(BetaCustomOutputState::LocalCommitmentSignatureSent) | + CustomOutputState::Beta(BetaCustomOutputState::RemoteCommitmentSignatureReceived) | + CustomOutputState::Beta(BetaCustomOutputState::RevokeAndAckReceived) | + CustomOutputState::Beta(BetaCustomOutputState::RevokeAndAckSent) | + CustomOutputState::Beta(BetaCustomOutputState::LocalRemoved { .. }) | + CustomOutputState::Beta(BetaCustomOutputState::RemoteRemoved { .. }) | + CustomOutputState::Beta(BetaCustomOutputState::AwaitingRemoteToRevokeAfterRemoval { .. }) => { + // ignoring because we only deal with local balances here + } + } + } + + + let balance_msat = if sum_profit > 0 { + balance_msat.checked_add(sum_profit as u64).unwrap_or_default() + } else { + balance_msat.checked_sub((sum_profit * -1) as u64).unwrap_or_default() + }; + let outbound_capacity_msat = cmp::max(self.value_to_self_msat as i64 - outbound_stats.pending_htlcs_value_msat as i64 - - self.counterparty_selected_channel_reserve_satoshis.unwrap_or(0) as i64 * 1000, - 0) as u64; + - self.counterparty_selected_channel_reserve_satoshis.unwrap_or(0) as i64 * 1000 + - self.get_outbound_pending_custom_output_stats().pending_custom_outputs_msat as i64, + 0) as u64; AvailableBalances { inbound_capacity_msat: cmp::max(self.channel_value_satoshis as i64 * 1000 - self.value_to_self_msat as i64 - self.get_inbound_pending_htlc_stats(None).pending_htlcs_value_msat as i64 + - self.get_inbound_pending_custom_output_stats().pending_custom_outputs_msat as i64 - self.holder_selected_channel_reserve_satoshis as i64 * 1000, 0) as u64, outbound_capacity_msat, @@ -2514,19 +2836,19 @@ impl Channel { (self.holder_selected_channel_reserve_satoshis, self.counterparty_selected_channel_reserve_satoshis) } - // Get the fee cost in MSATS of a commitment tx with a given number of HTLC outputs. - // Note that num_htlcs should not include dust HTLCs. - fn commit_tx_fee_msat(feerate_per_kw: u32, num_htlcs: usize, opt_anchors: bool) -> u64 { + // Get the fee cost in MSATS of a commitment tx with a given number of HTLC outputs and custom outputs. + // Note that num_htlcs should not include dust HTLCs nor dust custom outputs. + fn commit_tx_fee_msat(feerate_per_kw: u32, num_htlcs: usize, num_custom_outputs: usize, opt_anchors: bool) -> u64 { // Note that we need to divide before multiplying to round properly, // since the lowest denomination of bitcoin on-chain is the satoshi. - (commitment_tx_base_weight(opt_anchors) + num_htlcs as u64 * COMMITMENT_TX_WEIGHT_PER_HTLC) * feerate_per_kw as u64 / 1000 * 1000 + (commitment_tx_base_weight(opt_anchors) + num_htlcs as u64 * COMMITMENT_TX_WEIGHT_PER_HTLC + num_custom_outputs as u64 * COMMITMENT_TX_WEIGHT_PER_CUSTOM_OUTPUT) * feerate_per_kw as u64 / 1000 * 1000 } - // Get the fee cost in SATS of a commitment tx with a given number of HTLC outputs. - // Note that num_htlcs should not include dust HTLCs. + // Get the fee cost in SATS of a commitment tx with a given number of HTLC outputs and custom outputs. + // Note that num_htlcs should not include dust HTLCs nor dust custom outputs #[inline] - fn commit_tx_fee_sat(feerate_per_kw: u32, num_htlcs: usize, opt_anchors: bool) -> u64 { - feerate_per_kw as u64 * (commitment_tx_base_weight(opt_anchors) + num_htlcs as u64 * COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000 + fn commit_tx_fee_sat(feerate_per_kw: u32, num_htlcs: usize, num_custom_outputs: usize, opt_anchors: bool) -> u64 { + feerate_per_kw as u64 * (commitment_tx_base_weight(opt_anchors) + num_htlcs as u64 * COMMITMENT_TX_WEIGHT_PER_HTLC + num_custom_outputs as u64 * COMMITMENT_TX_WEIGHT_PER_CUSTOM_OUTPUT) / 1000 } // Get the commitment tx fee for the local's (i.e. our) next commitment transaction based on the @@ -2594,17 +2916,19 @@ impl Channel { included_htlcs += 1 }, _ => {}, // Don't include claims/fails that are awaiting ack, because once we get the - // ack we're guaranteed to never include them in commitment txs anymore. + // ack we're guaranteed to never include them in commitment txs anymore. } } let num_htlcs = included_htlcs + addl_htlcs; - let res = Self::commit_tx_fee_msat(self.feerate_per_kw, num_htlcs, self.opt_anchors()); + // TODO(10101): do we need to know how many custom outputs are here? + let res = Self::commit_tx_fee_msat(self.feerate_per_kw, num_htlcs, 0, self.opt_anchors()); #[cfg(any(test, fuzzing))] { let mut fee = res; if fee_spike_buffer_htlc.is_some() { - fee = Self::commit_tx_fee_msat(self.feerate_per_kw, num_htlcs - 1, self.opt_anchors()); + // TODO(10101): do we need to know how many custom outputs are here? + fee = Self::commit_tx_fee_msat(self.feerate_per_kw, num_htlcs - 1, 0, self.opt_anchors()); } let total_pending_htlcs = self.pending_inbound_htlcs.len() + self.pending_outbound_htlcs.len() + self.holding_cell_htlc_updates.len(); @@ -2683,12 +3007,14 @@ impl Channel { } let num_htlcs = included_htlcs + addl_htlcs; - let res = Self::commit_tx_fee_msat(self.feerate_per_kw, num_htlcs, self.opt_anchors()); + // TODO(10101): do we need to know how many custom outputs are here? + let res = Self::commit_tx_fee_msat(self.feerate_per_kw, num_htlcs, 0,self.opt_anchors()); #[cfg(any(test, fuzzing))] { let mut fee = res; if fee_spike_buffer_htlc.is_some() { - fee = Self::commit_tx_fee_msat(self.feerate_per_kw, num_htlcs - 1, self.opt_anchors()); + // TODO(10101): do we need to know how many custom outputs are here? + fee = Self::commit_tx_fee_msat(self.feerate_per_kw, num_htlcs - 1, 0,self.opt_anchors()); } let total_pending_htlcs = self.pending_inbound_htlcs.len() + self.pending_outbound_htlcs.len(); let commitment_tx_info = CommitmentTxInfoCached { @@ -2862,6 +3188,153 @@ impl Channel { Ok(()) } + pub fn update_add_custom_output(&mut self, _channel_id: [u8; 32], custom_output_id: CustomOutputId, local_amount_msat: u64, remote_amount_msat: u64, cltv_expiry: u32, script: Script, logger: &L) -> Result + where L::Target: Logger { + // We can't accept HTLCs sent after we've sent a shutdown. + let local_sent_shutdown = (self.channel_state & (ChannelState::ChannelFunded as u32 | ChannelState::LocalShutdownSent as u32)) != (ChannelState::ChannelFunded as u32); + if local_sent_shutdown { + todo!("Do we have to do something like what `update_add_htlc` does?") + } + + // If the remote has sent a shutdown prior to adding this custom output, then they are in violation of the spec (what spec?). + let remote_sent_shutdown = (self.channel_state & (ChannelState::ChannelFunded as u32 | ChannelState::RemoteShutdownSent as u32)) != (ChannelState::ChannelFunded as u32); + if remote_sent_shutdown { + return Err(ChannelError::Close("Got add custom output message when channel was not in an operational state".to_owned())); + } + if self.channel_state & (ChannelState::PeerDisconnected as u32) == ChannelState::PeerDisconnected as u32 { + return Err(ChannelError::Close("Peer sent update_add_custom_output when we needed a channel_reestablish".to_owned())); + } + + let custom_output_amount_msat = local_amount_msat + remote_amount_msat; + if custom_output_amount_msat > self.channel_value_satoshis * 1000 { + return Err(ChannelError::Close( + "Remote side tried to create custom output with a value greater than the total value of the channel".to_owned() + )); + } + if custom_output_amount_msat == 0 { + return Err(ChannelError::Close("Remote side tried to create a 0-msat custom output".to_owned())); + } + + // TODO(10101): Introduce checks similar to what we see in `update_add_htlc` + + // TODO(10101): Do we need this check? + // if self.next_counterparty_custom_output_id != msg.custom_output_id { + // return Err(ChannelError::Close(format!("Remote skipped custom output ID (skipped ID: {})", self.next_counterparty_custom_output_id))); + // } + if cltv_expiry >= 500000000 { + return Err(ChannelError::Close("Remote provided CLTV expiry in seconds instead of block height".to_owned())); + } + + // Now update local state: + self.next_counterparty_custom_output_id += 1; + self.pending_custom_outputs.insert(custom_output_id, + CustomOutput { + custom_output_id, + local_amount_msat, + remote_amount_msat, + cltv_expiry, + script: script.clone(), + state: CustomOutputState::Beta(BetaCustomOutputState::ReceivedAddCustomOutputRequest), + } + ); + + let (outpoint_commit_local, amount) = { + let keys_local = self.build_holder_transaction_keys(self.cur_holder_commitment_transaction_number)?; + let commitment_stats_local = self.build_commitment_transaction(self.cur_counterparty_commitment_transaction_number, &keys_local, true, true, logger); + + let custom_output_local = commitment_stats_local.tx.custom_outputs.iter().find(|output| output.id == custom_output_id).unwrap(); + + let outpoint = OutPoint { + txid: commitment_stats_local.tx.built.txid, + index: custom_output_local.transaction_output_index.unwrap() as u16, + }; + let amount = (custom_output_local.local_amount_msat + custom_output_local.remote_amount_msat) / 1000; + + (outpoint, amount) + }; + + let outpoint_commit_remote = { + let keys_remote = self.build_remote_transaction_keys()?; + let commitment_stats_remote = self.build_commitment_transaction(self.cur_counterparty_commitment_transaction_number, &keys_remote, false, true, logger); + + let custom_output_remote = commitment_stats_remote.tx.custom_outputs.iter().find(|output| output.id == custom_output_id).unwrap(); + + OutPoint { + txid: commitment_stats_remote.tx.built.txid, + index: custom_output_remote.transaction_output_index.unwrap() as u16, + } + }; + + let script_to_sign = script; // TODO(10101): We think this is wrong. + + let custom_output_details = CustomOutputDetails { + id: custom_output_id, + outpoint_commit_local, + outpoint_commit_remote, + script: script_to_sign, + amount, + }; + + Ok(custom_output_details) + } + + pub fn update_remove_custom_output(&mut self, _channel_id: [u8; 32], custom_output_id: CustomOutputId, local_settlement_amount_msat: u64, remote_settlement_amount_msat: u64, _logger: &L) -> Result<(), ChannelError> + where L::Target: Logger { + // We can't remove custom outputs after we've sent a shutdown. + let local_sent_shutdown = (self.channel_state & (ChannelState::ChannelFunded as u32 | ChannelState::LocalShutdownSent as u32)) != (ChannelState::ChannelFunded as u32); + if local_sent_shutdown { + todo!("Do we have to do something like what `update_add_htlc` does?") + } + + // If the remote has sent a shutdown prior to removing this custom output, then they are in violation of the spec (what spec?). + let remote_sent_shutdown = (self.channel_state & (ChannelState::ChannelFunded as u32 | ChannelState::RemoteShutdownSent as u32)) != (ChannelState::ChannelFunded as u32); + if remote_sent_shutdown { + return Err(ChannelError::Close("Got remove custom output message when channel was not in an operational state".to_owned())); + } + if self.channel_state & (ChannelState::PeerDisconnected as u32) == ChannelState::PeerDisconnected as u32 { + return Err(ChannelError::Close("Peer sent update_remove_custom_output when we needed a channel_reestablish".to_owned())); + } + + let custom_output = self.pending_custom_outputs + .get(&custom_output_id) + .ok_or(ChannelError::Warn("Remote tried to remove unknown custom output".to_owned()))?; + + if (local_settlement_amount_msat + remote_settlement_amount_msat) != (custom_output.local_amount_msat + custom_output.remote_amount_msat) { + return Err(ChannelError::Close( + "Remote side tried to remove custom output with total settlement value different to the value of the custom output".to_owned() + )); + } + + let local_profit = (local_settlement_amount_msat as i64) - (custom_output.local_amount_msat as i64); + let state = match custom_output.state { + CustomOutputState::Alpha(_) => { + CustomOutputState::Alpha(AlphaCustomOutputState::RemoteRemoved { + local_profit + }) + } + CustomOutputState::Beta(_) => { + CustomOutputState::Beta(BetaCustomOutputState::RemoteRemoved { + local_profit + }) + } + }; + + + // Now update local state: + self.pending_custom_outputs.insert(custom_output_id, + CustomOutput { + custom_output_id: custom_output.custom_output_id, + local_amount_msat: custom_output.local_amount_msat, + remote_amount_msat: custom_output.remote_amount_msat, + cltv_expiry: custom_output.cltv_expiry, + script: custom_output.script.clone(), + state, + } + ); + + Ok(()) + } + /// Marks an outbound HTLC which we have received update_fail/fulfill/malformed #[inline] fn mark_outbound_htlc_removed(&mut self, htlc_id: u64, check_preimage: Option, fail_reason: Option) -> Result<&OutboundHTLCOutput, ChannelError> { @@ -2928,7 +3401,7 @@ impl Channel { Ok(()) } - pub fn commitment_signed(&mut self, msg: &msgs::CommitmentSigned, logger: &L) -> Result<(msgs::RevokeAndACK, Option, ChannelMonitorUpdate), (Option, ChannelError)> + pub fn commitment_signed(&mut self, msg: &msgs::CommitmentSigned, logger: &L) -> Result<(msgs::RevokeAndACK, Option, ChannelMonitorUpdate, ShouldRevoke, DidRemoteSendCustomOutputCommitmentSignature), (Option, ChannelError)> where L::Target: Logger { if (self.channel_state & (ChannelState::ChannelFunded as u32)) != (ChannelState::ChannelFunded as u32) { @@ -3034,6 +3507,8 @@ impl Channel { // Update state now that we've passed all the can-fail calls... let mut need_commitment = false; + let mut should_revoke = ShouldRevoke::Yes; + let mut did_remote_send_custom_output_commitment_sig = DidRemoteSendCustomOutputCommitmentSignature::No; if let &mut Some((_, ref mut update_state)) = &mut self.pending_update_fee { if *update_state == FeeUpdateState::RemoteAnnounced { *update_state = FeeUpdateState::AwaitingRemoteRevokeToAnnounce; @@ -3072,6 +3547,56 @@ impl Channel { need_commitment = true; } } + for (_, custom_output) in self.pending_custom_outputs.iter_mut() { + match &custom_output.state { + CustomOutputState::Alpha(AlphaCustomOutputState::LocalAddedCustomOutput) => { + log_trace!(logger, "Updating CustomOutput {} to Alpha::RemoteCommitmentSignatureReceived due to commitment_signed in channel {}.", + custom_output.custom_output_id, log_bytes!(self.channel_id)); + custom_output.state = CustomOutputState::Alpha(AlphaCustomOutputState::ReceivedRemoteCommitmentSignature); + need_commitment = true; + should_revoke = ShouldRevoke::No; + did_remote_send_custom_output_commitment_sig = DidRemoteSendCustomOutputCommitmentSignature::Yes; + } + CustomOutputState::Alpha(AlphaCustomOutputState::ReceivedRemoteCommitmentSignature) => { + log_trace!(logger, "Updating CustomOutput {} to Alpha::LocalCommitmentSignatureSent due to commitment_signed in channel {}.", + custom_output.custom_output_id, log_bytes!(self.channel_id)); + custom_output.state = CustomOutputState::Alpha(AlphaCustomOutputState::LocalCommitmentSignatureSent); + need_commitment = true; + should_revoke = ShouldRevoke::Yes; + } + CustomOutputState::Beta(BetaCustomOutputState::LocalAddedCustomOutput) => { + log_trace!(logger, "Updating CustomOutput {} to Beta::LocalCommitmentSignatureSent due to commitment_signed in channel {}.", + custom_output.custom_output_id, log_bytes!(self.channel_id)); + custom_output.state = CustomOutputState::Beta(BetaCustomOutputState::LocalCommitmentSignatureSent); + need_commitment = true; + } + CustomOutputState::Alpha(AlphaCustomOutputState::RemoteRemoved { local_profit }) => { + log_trace!(logger, "Updating CustomOutput {} to Alpha::AwaitingRemoteToRevokeAfterRemoval due to commitment_signed in channel {}.", + custom_output.custom_output_id, log_bytes!(self.channel_id)); + custom_output.state = CustomOutputState::Alpha(AlphaCustomOutputState::AwaitingRemoteToRevokeAfterRemoval { local_profit: *local_profit}); + need_commitment = true; + } + CustomOutputState::Beta(BetaCustomOutputState::RemoteRemoved { local_profit }) => { + log_trace!(logger, "Updating CustomOutput {} to Beta::AwaitingRemoteToRevokeAfterRemoval due to commitment_signed in channel {}.", + custom_output.custom_output_id, log_bytes!(self.channel_id)); + custom_output.state = CustomOutputState::Beta(BetaCustomOutputState::AwaitingRemoteToRevokeAfterRemoval { local_profit: *local_profit}); + need_commitment = true; + } + _ => { + // ignored + } + } + // TODO(10101): we might need this because we merged inbound and outbound + // if let &mut CustomOutputState::RemoteSettled = &mut custom_output.state { + // log_trace!(logger, "Updating CustomOutput {} to AwaitingRemoteRevokeToSettle due to commitment_signed in channel {}.", + // custom_output.custom_output_id, log_bytes!(self.channel_id)); + // // Grab the preimage, if it exists, instead of cloning + // // TODO: we might need our own reason here saying the custom output was removed + // // let mut reason = OutboundHTLCOutcome::Success(None); + // custom_output.state = CustomOutputState::AwaitingRemoteRevokeToSettle; + // need_commitment = true; + // } + } self.cur_holder_commitment_transaction_number -= 1; // Note that if we need_commitment & !AwaitingRemoteRevoke we'll call @@ -3117,7 +3642,7 @@ impl Channel { channel_id: self.channel_id, per_commitment_secret, next_per_commitment_point, - }, commitment_signed, monitor_update)) + }, commitment_signed, monitor_update, should_revoke, did_remote_send_custom_output_commitment_sig)) } /// Public version of the below, checking relevant preconditions first. @@ -3238,6 +3763,8 @@ impl Channel { update_fail_malformed_htlcs: Vec::new(), update_fee, commitment_signed, + update_add_custom_output: Vec::new(), + update_remove_custom_output: Vec::new() }, monitor_update)), htlcs_to_fail)) } else { Ok((None, Vec::new())) @@ -3329,6 +3856,7 @@ impl Channel { // Take references explicitly so that we can hold multiple references to self. let pending_inbound_htlcs: &mut Vec<_> = &mut self.pending_inbound_htlcs; let pending_outbound_htlcs: &mut Vec<_> = &mut self.pending_outbound_htlcs; + let custom_outputs: &mut HashMap<_, _> = &mut self.pending_custom_outputs; // We really shouldnt have two passes here, but retain gives a non-mutable ref (Rust bug) pending_inbound_htlcs.retain(|htlc| { @@ -3353,6 +3881,21 @@ impl Channel { false } else { true } }); + + custom_outputs.retain(|id, custom_output| { + match custom_output.state { + CustomOutputState::Alpha(AlphaCustomOutputState::AwaitingRemoteToRevokeAfterRemoval { local_profit }) | + CustomOutputState::Beta(BetaCustomOutputState::AwaitingRemoteToRevokeAfterRemoval { local_profit }) => { + log_trace!(logger, " ...removing custom output with state AwaitingRemovedToRevokeAfterRemoval: {}", id); + value_to_self_msat_diff += local_profit; + false + }, + _ => { + true + }, + } + }); + for htlc in pending_inbound_htlcs.iter_mut() { let swap = if let &InboundHTLCState::AwaitingRemoteRevokeToAnnounce(_) = &htlc.state { true @@ -3497,7 +4040,9 @@ impl Channel { update_fail_htlcs, update_fail_malformed_htlcs, update_fee: None, - commitment_signed + commitment_signed, + update_add_custom_output: Vec::new(), + update_remove_custom_output: Vec::new() }), finalized_claimed_htlcs, accepted_htlcs: to_forward_infos, failed_htlcs: revoked_htlcs, @@ -3537,7 +4082,7 @@ impl Channel { 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 commitment_stats = self.build_commitment_transaction(self.cur_holder_commitment_transaction_number, &keys, true, true, logger); - let buffer_fee_msat = Channel::::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 buffer_fee_msat = Channel::::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, commitment_stats.num_nondust_custom_outputs, self.opt_anchors()) * 1000; let holder_balance_msat = commitment_stats.local_balance_msat - outbound_stats.holding_cell_msat; if holder_balance_msat < buffer_fee_msat + self.counterparty_selected_channel_reserve_satoshis.unwrap() * 1000 { //TODO: auto-close after a number of failures? @@ -3860,6 +4405,8 @@ impl Channel { msgs::CommitmentUpdate { update_add_htlcs, update_fulfill_htlcs, update_fail_htlcs, update_fail_malformed_htlcs, update_fee, commitment_signed: self.send_commitment_no_state_update(logger).expect("It looks like we failed to re-generate a commitment_signed we had previously sent?").0, + update_add_custom_output: Vec::new(), + update_remove_custom_output: Vec::new() } } @@ -5612,6 +6159,150 @@ impl Channel { Ok(Some(res)) } + pub fn add_custom_output( + &mut self, + custom_output_id: CustomOutputId, + local_amount_msat: u64, + remote_amount_msat: u64, + cltv_expiry: u32, + script: Script, + logger: &L + ) -> Result where L::Target: Logger { + if (self.channel_state & (ChannelState::ChannelFunded as u32 | BOTH_SIDES_SHUTDOWN_MASK)) != (ChannelState::ChannelFunded as u32) { + return Err(ChannelError::Ignore("Cannot add custom output until channel is fully established and we haven't started shutting down".to_owned())); + } + + let custom_output_amount_msat = local_amount_msat + remote_amount_msat; + let channel_total_msat = self.channel_value_satoshis * 1000; + if custom_output_amount_msat > channel_total_msat { + return Err(ChannelError::Ignore(format!( + "Cannot create custom output with amount {custom_output_amount_msat}, + because it is more than the total value of the channel {channel_total_msat}" + ))); + } + + if custom_output_amount_msat == 0 { + return Err(ChannelError::Ignore("Cannot create 0-msat custom output".to_owned())); + } + + if (self.channel_state & (ChannelState::PeerDisconnected as u32)) != 0 { + // Note that this should never really happen + return Err(ChannelError::Ignore("Cannot create custom output while disconnected from channel counterparty".to_owned())); + } + + // Now update local state: + if (self.channel_state & (ChannelState::AwaitingRemoteRevoke as u32 | ChannelState::MonitorUpdateInProgress as u32)) != 0 { + // TODO(10101): Improve error message + return Err(ChannelError::Ignore("Cannot create custom output while things are happening".to_owned())); + } + + // We only build this to run checks based on the _current_ commitment transaction i.e. + // before adding the custom output + 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); + + // TODO(10101): Run similar checks for a custom output. The difference is that the custom outputs should be partially funded by both sides! + // if !self.is_outbound() { + // // Check that we won't violate the remote channel reserve by adding this HTLC. + // let htlc_candidate = HTLCCandidate::new(amount_msat, HTLCInitiator::LocalOffered); + // let counterparty_commit_tx_fee_msat = self.next_remote_commit_tx_fee_msat(htlc_candidate, None); + // let holder_selected_chan_reserve_msat = self.holder_selected_channel_reserve_satoshis * 1000; + // if commitment_stats.remote_balance_msat < counterparty_commit_tx_fee_msat + holder_selected_chan_reserve_msat { + // return Err(ChannelError::Ignore("Cannot send value that would put counterparty balance under holder-announced channel reserve value".to_owned())); + // } + // } + // + // let holder_balance_msat = commitment_stats.local_balance_msat - outbound_stats.holding_cell_msat; + // if holder_balance_msat < amount_msat { + // return Err(ChannelError::Ignore(format!("Cannot send value that would overdraw remaining funds. Amount: {}, pending value to self {}", amount_msat, holder_balance_msat))); + // } + // + // There might be more checks to run. Look at `send_htlc` for inspiration. + + + self.pending_custom_outputs.insert( + custom_output_id, + CustomOutput { + custom_output_id, + local_amount_msat, + remote_amount_msat, + cltv_expiry, + script: script.clone(), + state: CustomOutputState::Alpha(AlphaCustomOutputState::LocalAddedCustomOutput) + } + ); + + let msg = msgs::UpdateAddCustomOutput { + channel_id: self.channel_id, + custom_output_id, + sender_amount_msat: local_amount_msat, + receiver_amount_msat: remote_amount_msat, + cltv_expiry, + script, + }; + self.next_holder_custom_output_id += 1; + + Ok(msg) + } + + pub fn remove_custom_output( + &mut self, + custom_output_id: CustomOutputId, + local_settlement_amount_msat: u64, + remote_settlement_amount_msat: u64, + logger: &L + ) -> Result where L::Target: Logger { + let custom_output = self.pending_custom_outputs.get(&custom_output_id).ok_or(ChannelError::Ignore("Cannot remove custom output which we don't know about".to_owned()))?; + + if (self.channel_state & (ChannelState::ChannelFunded as u32 | BOTH_SIDES_SHUTDOWN_MASK)) != (ChannelState::ChannelFunded as u32) { + return Err(ChannelError::Ignore("Cannot remove custom output until channel is fully established and we haven't started shutting down".to_owned())); + } + + + if (self.channel_state & (ChannelState::PeerDisconnected as u32)) != 0 { + // Note that this should never really happen + return Err(ChannelError::Ignore("Cannot remove custom output while disconnected from channel counterparty".to_owned())); + } + + // We only build this to run checks based on the _current_ commitment transaction i.e. + // before removing the custom output + 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.channel_state & (ChannelState::AwaitingRemoteRevoke as u32 | ChannelState::MonitorUpdateInProgress as u32)) != 0 { + // TODO(10101): Improve error message + return Err(ChannelError::Ignore("Cannot create custom output while things are happening".to_owned())); + } + + let local_profit = local_settlement_amount_msat as i64 - custom_output.local_amount_msat as i64; + let state = match custom_output.state { + CustomOutputState::Alpha(_) => {CustomOutputState::Alpha(AlphaCustomOutputState::LocalRemoved {local_profit})} + CustomOutputState::Beta(_) => {CustomOutputState::Beta(BetaCustomOutputState::LocalRemoved {local_profit})} + }; + + + self.pending_custom_outputs.insert(custom_output_id, + CustomOutput { + custom_output_id, + local_amount_msat: local_settlement_amount_msat, + remote_amount_msat: remote_settlement_amount_msat, + cltv_expiry: custom_output.cltv_expiry, + script: custom_output.script.clone(), + state + } + ); + + let res = msgs::UpdateRemoveCustomOutput { + channel_id: self.channel_id, + custom_output_id, + sender_amount_msat: local_settlement_amount_msat, + receiver_amount_msat: remote_settlement_amount_msat, + }; + + Ok(res) + } + + /// Creates a signed commitment transaction to send to the remote peer. /// Always returns a ChannelError::Close if an immediately-preceding (read: the /// last call to this Channel) send_htlc returned Ok(Some(_)) and there is an Err. @@ -5701,6 +6392,7 @@ impl Channel { updates: vec![ChannelMonitorUpdateStep::LatestCounterpartyCommitmentTXInfo { commitment_txid: counterparty_commitment_txid, htlc_outputs: htlcs.clone(), + // TODO(10101): we might need to pass in the custom ouptuts to monitor them commitment_number: self.cur_counterparty_commitment_transaction_number, their_per_commitment_point: self.counterparty_cur_commitment_point.unwrap() }] @@ -5714,6 +6406,7 @@ impl Channel { fn send_commitment_no_state_update(&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 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); @@ -5728,7 +6421,7 @@ impl Channel { && info.next_holder_htlc_id == self.next_holder_htlc_id && info.next_counterparty_htlc_id == self.next_counterparty_htlc_id && info.feerate == self.feerate_per_kw { - let actual_fee = Self::commit_tx_fee_msat(self.feerate_per_kw, commitment_stats.num_nondust_htlcs, self.opt_anchors()); + let actual_fee = Self::commit_tx_fee_msat(self.feerate_per_kw, commitment_stats.num_nondust_htlcs, commitment_stats.num_nondust_custom_outputs, self.opt_anchors()); assert_eq!(actual_fee, info.fee); } } @@ -5781,6 +6474,73 @@ impl Channel { } } + pub fn add_custom_output_and_build_commits( + &mut self, + custom_output_id: CustomOutputId, + local_amount_msat: u64, + remote_amount_msat: u64, + cltv_expiry: u32, + script: Script, + logger: &L + ) -> Result<(CustomOutputDetails, msgs::UpdateAddCustomOutput), ChannelError> where L::Target: Logger { + let update_add_custom_output = self.add_custom_output(custom_output_id, local_amount_msat, remote_amount_msat, cltv_expiry, script.clone(), logger)?; + + let (outpoint_commit_local, amount) = { + let keys_local = self.build_holder_transaction_keys(self.cur_holder_commitment_transaction_number)?; + let commitment_stats_local = self.build_commitment_transaction(self.cur_counterparty_commitment_transaction_number, &keys_local, true, true, logger); + + let custom_output_local = commitment_stats_local.tx.custom_outputs.iter().find(|output| output.id == custom_output_id).unwrap(); + + let outpoint = OutPoint { + txid: commitment_stats_local.tx.built.txid, + index: custom_output_local.transaction_output_index.unwrap() as u16, + }; + let amount = (custom_output_local.local_amount_msat + custom_output_local.remote_amount_msat) / 1000; + + (outpoint, amount) + }; + + let outpoint_commit_remote = { + let keys_remote = self.build_remote_transaction_keys()?; + let commitment_stats_remote = self.build_commitment_transaction(self.cur_counterparty_commitment_transaction_number, &keys_remote, false, true, logger); + + let custom_output_remote = commitment_stats_remote.tx.custom_outputs.iter().find(|output| output.id == custom_output_id).unwrap(); + + OutPoint { + txid: commitment_stats_remote.tx.built.txid, + index: custom_output_remote.transaction_output_index.unwrap() as u16, + } + }; + + let script_to_sign = script; // TODO(10101): We think this is wrong. + + let custom_output_details = CustomOutputDetails { + id: custom_output_id, + outpoint_commit_local, + outpoint_commit_remote, + script: script_to_sign, + amount, + }; + + Ok((custom_output_details, update_add_custom_output)) + } + + pub fn continue_remote_add_custom_output_and_commit( + &mut self, channel_id: [u8; 32], custom_output_id: CustomOutputId, local_amount_msat: u64, + remote_amount_msat: u64, cltv_expiry: u32, script: Script, logger: &L + ) -> Result<(CustomOutputDetails, msgs::CommitmentSigned, ChannelMonitorUpdate), ChannelError> where L::Target: Logger { + let custom_output_details = self.update_add_custom_output(channel_id, custom_output_id, local_amount_msat, remote_amount_msat, cltv_expiry, script, logger)?; + let (commitment_signed, monitor_update) = self.send_commitment_no_status_check(logger)?; + + Ok((custom_output_details, commitment_signed, monitor_update)) + } + + pub fn remove_custom_output_and_commit(&mut self, custom_output_id: CustomOutputId, local_amount: u64, remote_amount: u64, logger: &L) -> Result<(msgs::UpdateRemoveCustomOutput, msgs::CommitmentSigned, ChannelMonitorUpdate), ChannelError> where L::Target: Logger{ + let update_remove_custom_output = self.remove_custom_output(custom_output_id, local_amount, remote_amount, logger)?; + let (commitment_signed, monitor_update) = self.send_commitment_no_status_check(logger)?; + Ok((update_remove_custom_output, commitment_signed, monitor_update)) + } + /// Get forwarding information for the counterparty. pub fn counterparty_forwarding_info(&self) -> Option { self.counterparty_forwarding_info.clone() @@ -6093,6 +6853,52 @@ impl Writeable for Channel { } } + (self.pending_custom_outputs.len() as u64).write(writer)?; + for (_, custom_output) in self.pending_custom_outputs.iter() { + custom_output.custom_output_id.write(writer)?; + custom_output.local_amount_msat.write(writer)?; + custom_output.remote_amount_msat.write(writer)?; + custom_output.cltv_expiry.write(writer)?; + custom_output.script.write(writer)?; + match &custom_output.state { + CustomOutputState::Alpha(AlphaCustomOutputState::LocalAddedCustomOutput) => { 0u8.write(writer)?; } + CustomOutputState::Alpha(AlphaCustomOutputState::ReceivedRemoteCommitmentSignature) => { 1u8.write(writer)?; } + CustomOutputState::Alpha(AlphaCustomOutputState::LocalCommitmentSignatureSent) => { 2u8.write(writer)?; } + CustomOutputState::Alpha(AlphaCustomOutputState::RevokeAndAckSent) => { 3u8.write(writer)?; } + CustomOutputState::Alpha(AlphaCustomOutputState::RevokeAndAckReceived) => { 4u8.write(writer)?; } + CustomOutputState::Alpha(AlphaCustomOutputState::LocalRemoved { local_profit }) => { + 5u8.write(writer)?; + local_profit.write(writer)?; + } + CustomOutputState::Alpha(AlphaCustomOutputState::RemoteRemoved { local_profit }) => { + 6u8.write(writer)?; + local_profit.write(writer)?; + } + CustomOutputState::Alpha(AlphaCustomOutputState::AwaitingRemoteToRevokeAfterRemoval { local_profit }) => { + 7u8.write(writer)?; + local_profit.write(writer)?; + } + CustomOutputState::Beta(BetaCustomOutputState::LocalAddedCustomOutput) => { 8u8.write(writer)?; } + CustomOutputState::Beta(BetaCustomOutputState::ReceivedAddCustomOutputRequest) => { 9u8.write(writer)?; } + CustomOutputState::Beta(BetaCustomOutputState::LocalCommitmentSignatureSent) => { 10u8.write(writer)?; } + CustomOutputState::Beta(BetaCustomOutputState::RemoteCommitmentSignatureReceived) => { 11u8.write(writer)?; } + CustomOutputState::Beta(BetaCustomOutputState::RevokeAndAckReceived) => { 12u8.write(writer)?; } + CustomOutputState::Beta(BetaCustomOutputState::RevokeAndAckSent) => { 13u8.write(writer)?; } + CustomOutputState::Beta(BetaCustomOutputState::LocalRemoved { local_profit }) => { + 14u8.write(writer)?; + local_profit.write(writer)?; + } + CustomOutputState::Beta(BetaCustomOutputState::RemoteRemoved { local_profit }) => { + 15u8.write(writer)?; + local_profit.write(writer)?; + } + CustomOutputState::Beta(BetaCustomOutputState::AwaitingRemoteToRevokeAfterRemoval { local_profit }) => { + 16u8.write(writer)?; + local_profit.write(writer)?; + } + } + } + (self.holding_cell_htlc_updates.len() as u64).write(writer)?; for update in self.holding_cell_htlc_updates.iter() { match update { @@ -6151,7 +6957,9 @@ impl Writeable for Channel { self.holding_cell_update_fee.write(writer)?; self.next_holder_htlc_id.write(writer)?; + self.next_holder_custom_output_id.write(writer)?; (self.next_counterparty_htlc_id - dropped_inbound_htlcs).write(writer)?; + self.next_counterparty_custom_output_id.write(writer)?; self.update_time_counter.write(writer)?; self.feerate_per_kw.write(writer)?; @@ -6354,8 +7162,63 @@ impl<'a, Signer: Sign, K: Deref> ReadableArgs<(&'a K, u32)> for Channel }); } + let pending_custom_output_count: u64 = Readable::read(reader)?; + let mut pending_custom_outputs_vec = Vec::with_capacity(pending_custom_output_count as usize); + for _ in 0..pending_custom_output_count { + pending_custom_outputs_vec.push(CustomOutput { + custom_output_id: Readable::read(reader)?, + local_amount_msat: Readable::read(reader)?, + remote_amount_msat: Readable::read(reader)?, + cltv_expiry: Readable::read(reader)?, + script: Readable::read(reader)?, + state: match ::read(reader)? { + 0 => CustomOutputState::Alpha(AlphaCustomOutputState::LocalAddedCustomOutput), + 1 => CustomOutputState::Alpha(AlphaCustomOutputState::ReceivedRemoteCommitmentSignature), + 2 => CustomOutputState::Alpha(AlphaCustomOutputState::LocalCommitmentSignatureSent), + 3 => CustomOutputState::Alpha(AlphaCustomOutputState::RevokeAndAckSent), + 4 => CustomOutputState::Alpha(AlphaCustomOutputState::RevokeAndAckReceived), + 5 => { + let local_profit = Readable::read(reader)?; + CustomOutputState::Alpha(AlphaCustomOutputState::LocalRemoved { local_profit }) + } + 6 => { + let local_profit = Readable::read(reader)?; + CustomOutputState::Alpha(AlphaCustomOutputState::RemoteRemoved { local_profit }) + } + 7 => { + let local_profit = Readable::read(reader)?; + CustomOutputState::Alpha(AlphaCustomOutputState::AwaitingRemoteToRevokeAfterRemoval { local_profit }) + } + 8 => CustomOutputState::Beta(BetaCustomOutputState::LocalAddedCustomOutput), + 9 => CustomOutputState::Beta(BetaCustomOutputState::ReceivedAddCustomOutputRequest), + 10 => CustomOutputState::Beta(BetaCustomOutputState::LocalCommitmentSignatureSent), + 11 => CustomOutputState::Beta(BetaCustomOutputState::RemoteCommitmentSignatureReceived), + 12 => CustomOutputState::Beta(BetaCustomOutputState::RevokeAndAckReceived), + 13 => CustomOutputState::Beta(BetaCustomOutputState::RevokeAndAckSent), + 14 => { + let local_profit = Readable::read(reader)?; + CustomOutputState::Beta(BetaCustomOutputState::LocalRemoved { local_profit }) + } + 15 => { + let local_profit = Readable::read(reader)?; + CustomOutputState::Beta(BetaCustomOutputState::RemoteRemoved { local_profit }) + } + 16 => { + let local_profit = Readable::read(reader)?; + CustomOutputState::Beta(BetaCustomOutputState::AwaitingRemoteToRevokeAfterRemoval { local_profit }) + } + _ => return Err(DecodeError::InvalidValue), + }, + }); + } + + let mut pending_custom_outputs = HashMap::new(); + for co in pending_custom_outputs_vec.into_iter() { + pending_custom_outputs.insert(co.custom_output_id, co); + } + 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)); + 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 ::read(reader)? { 0 => HTLCUpdateAwaitingACK::AddHTLC { @@ -6404,7 +7267,9 @@ impl<'a, Signer: Sign, K: Deref> ReadableArgs<(&'a K, u32)> for Channel let holding_cell_update_fee = Readable::read(reader)?; let next_holder_htlc_id = Readable::read(reader)?; + let next_holder_custom_output_id = Readable::read(reader)?; let next_counterparty_htlc_id = Readable::read(reader)?; + let next_counterparty_custom_output_id = Readable::read(reader)?; let update_time_counter = Readable::read(reader)?; let feerate_per_kw = Readable::read(reader)?; @@ -6419,7 +7284,9 @@ impl<'a, Signer: Sign, K: Deref> ReadableArgs<(&'a K, u32)> for Channel let _: u64 = Readable::read(reader)?; let _: Signature = Readable::read(reader)?; }, - _ => return Err(DecodeError::InvalidValue), + _ => { + return Err(DecodeError::InvalidValue); + }, } let funding_tx_confirmed_in = Readable::read(reader)?; @@ -6474,7 +7341,7 @@ impl<'a, Signer: Sign, K: Deref> ReadableArgs<(&'a K, u32)> for Channel let channel_update_status = Readable::read(reader)?; #[cfg(any(test, fuzzing))] - let mut historical_inbound_htlc_fulfills = HashSet::new(); + let mut historical_inbound_htlc_fulfills = HashSet::new(); #[cfg(any(test, fuzzing))] { let htlc_fulfills_len: u64 = Readable::read(reader)?; @@ -6591,6 +7458,7 @@ impl<'a, Signer: Sign, K: Deref> ReadableArgs<(&'a K, u32)> for Channel pending_inbound_htlcs, pending_outbound_htlcs, + pending_custom_outputs, holding_cell_htlc_updates, resend_order, @@ -6605,7 +7473,9 @@ impl<'a, Signer: Sign, K: Deref> ReadableArgs<(&'a K, u32)> for Channel pending_update_fee, holding_cell_update_fee, next_holder_htlc_id, + next_holder_custom_output_id, next_counterparty_htlc_id, + next_counterparty_custom_output_id, update_time_counter, feerate_per_kw, @@ -6727,7 +7597,7 @@ mod tests { fn test_max_funding_satoshis_no_wumbo() { assert_eq!(TOTAL_BITCOIN_SUPPLY_SATOSHIS, 21_000_000 * 100_000_000); assert!(MAX_FUNDING_SATOSHIS_NO_WUMBO <= TOTAL_BITCOIN_SUPPLY_SATOSHIS, - "MAX_FUNDING_SATOSHIS_NO_WUMBO is greater than all satoshis in existence"); + "MAX_FUNDING_SATOSHIS_NO_WUMBO is greater than all satoshis in existence"); } #[test] @@ -6883,13 +7753,13 @@ mod tests { // the dust limit check. let htlc_candidate = HTLCCandidate::new(htlc_amount_msat, HTLCInitiator::LocalOffered); let local_commit_tx_fee = node_a_chan.next_local_commit_tx_fee_msat(htlc_candidate, None); - let local_commit_fee_0_htlcs = Channel::::commit_tx_fee_msat(node_a_chan.feerate_per_kw, 0, node_a_chan.opt_anchors()); + let local_commit_fee_0_htlcs = Channel::::commit_tx_fee_msat(node_a_chan.feerate_per_kw, 0, 0,node_a_chan.opt_anchors()); assert_eq!(local_commit_tx_fee, local_commit_fee_0_htlcs); // Finally, make sure that when Node A calculates the remote's commitment transaction fees, all // of the HTLCs are seen to be above the dust limit. node_a_chan.channel_transaction_parameters.is_outbound_from_holder = false; - let remote_commit_fee_3_htlcs = Channel::::commit_tx_fee_msat(node_a_chan.feerate_per_kw, 3, node_a_chan.opt_anchors()); + let remote_commit_fee_3_htlcs = Channel::::commit_tx_fee_msat(node_a_chan.feerate_per_kw, 3, 0, node_a_chan.opt_anchors()); let htlc_candidate = HTLCCandidate::new(htlc_amount_msat, HTLCInitiator::LocalOffered); let remote_commit_tx_fee = node_a_chan.next_remote_commit_tx_fee_msat(htlc_candidate, None); assert_eq!(remote_commit_tx_fee, remote_commit_fee_3_htlcs); @@ -6911,8 +7781,9 @@ mod tests { let config = UserConfig::default(); let mut chan = Channel::::new_outbound(&fee_est, &&keys_provider, node_id, &channelmanager::provided_init_features(), 10000000, 100000, 42, &config, 0, 42).unwrap(); - let commitment_tx_fee_0_htlcs = Channel::::commit_tx_fee_msat(chan.feerate_per_kw, 0, chan.opt_anchors()); - let commitment_tx_fee_1_htlc = Channel::::commit_tx_fee_msat(chan.feerate_per_kw, 1, chan.opt_anchors()); + let commitment_tx_fee_0_htlcs = Channel::::commit_tx_fee_msat(chan.feerate_per_kw, 0, 0,chan.opt_anchors()); + let commitment_tx_fee_1_htlc = Channel::::commit_tx_fee_msat(chan.feerate_per_kw, 1, 0, chan.opt_anchors()); + // TODO(10101): we could write a similar test for calculating the fees // If HTLC_SUCCESS_TX_WEIGHT and HTLC_TIMEOUT_TX_WEIGHT were swapped: then this HTLC would be // counted as dust when it shouldn't be. @@ -7252,13 +8123,13 @@ mod tests { signer.ready_channel(&chan.channel_transaction_parameters); assert_eq!(counterparty_pubkeys.payment_point.serialize()[..], - hex::decode("032c0b7cf95324a07d05398b240174dc0c2be444d96b159aa6c7f7b1e668680991").unwrap()[..]); + hex::decode("032c0b7cf95324a07d05398b240174dc0c2be444d96b159aa6c7f7b1e668680991").unwrap()[..]); assert_eq!(counterparty_pubkeys.funding_pubkey.serialize()[..], - hex::decode("030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c1").unwrap()[..]); + hex::decode("030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c1").unwrap()[..]); assert_eq!(counterparty_pubkeys.htlc_basepoint.serialize()[..], - hex::decode("032c0b7cf95324a07d05398b240174dc0c2be444d96b159aa6c7f7b1e668680991").unwrap()[..]); + hex::decode("032c0b7cf95324a07d05398b240174dc0c2be444d96b159aa6c7f7b1e668680991").unwrap()[..]); // We can't just use build_holder_transaction_keys here as the per_commitment_secret is not // derived from a commitment_seed, so instead we copy it here and call @@ -7448,33 +8319,33 @@ mod tests { chan.feerate_per_kw = 0; test_commitment!("3044022009b048187705a8cbc9ad73adbe5af148c3d012e1f067961486c822c7af08158c022006d66f3704cfab3eb2dc49dae24e4aa22a6910fc9b424007583204e3621af2e5", - "304402206fc2d1f10ea59951eefac0b4b7c396a3c3d87b71ff0b019796ef4535beaf36f902201765b0181e514d04f4c8ad75659d7037be26cdb3f8bb6f78fe61decef484c3ea", - "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8007e80300000000000022002052bfef0479d7b293c27e0f1eb294bea154c63a3294ef092c19af51409bce0e2ad007000000000000220020403d394747cae42e98ff01734ad5c08f82ba123d3d9a620abda88989651e2ab5d007000000000000220020748eba944fedc8827f6b06bc44678f93c0f9e6078b35c6331ed31e75f8ce0c2db80b000000000000220020c20b5d1f8584fd90443e7b7b720136174fa4b9333c261d04dbbd012635c0f419a00f0000000000002200208c48d15160397c9731df9bc3b236656efb6665fbfe92b4a6878e88a499f741c4c0c62d0000000000160014cc1b07838e387deacd0e5232e1e8b49f4c29e484e0a06a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e040047304402206fc2d1f10ea59951eefac0b4b7c396a3c3d87b71ff0b019796ef4535beaf36f902201765b0181e514d04f4c8ad75659d7037be26cdb3f8bb6f78fe61decef484c3ea01473044022009b048187705a8cbc9ad73adbe5af148c3d012e1f067961486c822c7af08158c022006d66f3704cfab3eb2dc49dae24e4aa22a6910fc9b424007583204e3621af2e501475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", { - - { 0, - "3045022100d9e29616b8f3959f1d3d7f7ce893ffedcdc407717d0de8e37d808c91d3a7c50d022078c3033f6d00095c8720a4bc943c1b45727818c082e4e3ddbc6d3116435b624b", - "30440220636de5682ef0c5b61f124ec74e8aa2461a69777521d6998295dcea36bc3338110220165285594b23c50b28b82df200234566628a27bcd17f7f14404bd865354eb3ce", - "02000000000101ab84ff284f162cfbfef241f853b47d4368d171f9e2a1445160cd591c4c7d882b00000000000000000001e8030000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100d9e29616b8f3959f1d3d7f7ce893ffedcdc407717d0de8e37d808c91d3a7c50d022078c3033f6d00095c8720a4bc943c1b45727818c082e4e3ddbc6d3116435b624b014730440220636de5682ef0c5b61f124ec74e8aa2461a69777521d6998295dcea36bc3338110220165285594b23c50b28b82df200234566628a27bcd17f7f14404bd865354eb3ce012000000000000000000000000000000000000000000000000000000000000000008a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a914b8bcb07f6344b42ab04250c86a6e8b75d3fdbbc688527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f401b175ac686800000000" }, - - { 1, - "30440220649fe8b20e67e46cbb0d09b4acea87dbec001b39b08dee7bdd0b1f03922a8640022037c462dff79df501cecfdb12ea7f4de91f99230bb544726f6e04527b1f896004", - "3045022100803159dee7935dba4a1d36a61055ce8fd62caa528573cc221ae288515405a252022029c59e7cffce374fe860100a4a63787e105c3cf5156d40b12dd53ff55ac8cf3f", - "02000000000101ab84ff284f162cfbfef241f853b47d4368d171f9e2a1445160cd591c4c7d882b01000000000000000001d0070000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e05004730440220649fe8b20e67e46cbb0d09b4acea87dbec001b39b08dee7bdd0b1f03922a8640022037c462dff79df501cecfdb12ea7f4de91f99230bb544726f6e04527b1f89600401483045022100803159dee7935dba4a1d36a61055ce8fd62caa528573cc221ae288515405a252022029c59e7cffce374fe860100a4a63787e105c3cf5156d40b12dd53ff55ac8cf3f01008576a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a914b43e1b38138a41b37f7cd9a1d274bc63e3a9b5d188ac6868f6010000" }, - - { 2, - "30440220770fc321e97a19f38985f2e7732dd9fe08d16a2efa4bcbc0429400a447faf49102204d40b417f3113e1b0944ae0986f517564ab4acd3d190503faf97a6e420d43352", - "3045022100a437cc2ce77400ecde441b3398fea3c3ad8bdad8132be818227fe3c5b8345989022069d45e7fa0ae551ec37240845e2c561ceb2567eacf3076a6a43a502d05865faa", - "02000000000101ab84ff284f162cfbfef241f853b47d4368d171f9e2a1445160cd591c4c7d882b02000000000000000001d0070000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e05004730440220770fc321e97a19f38985f2e7732dd9fe08d16a2efa4bcbc0429400a447faf49102204d40b417f3113e1b0944ae0986f517564ab4acd3d190503faf97a6e420d4335201483045022100a437cc2ce77400ecde441b3398fea3c3ad8bdad8132be818227fe3c5b8345989022069d45e7fa0ae551ec37240845e2c561ceb2567eacf3076a6a43a502d05865faa012001010101010101010101010101010101010101010101010101010101010101018a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a9144b6b2e5444c2639cc0fb7bcea5afba3f3cdce23988527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f501b175ac686800000000" }, - - { 3, - "304402207bcbf4f60a9829b05d2dbab84ed593e0291836be715dc7db6b72a64caf646af802201e489a5a84f7c5cc130398b841d138d031a5137ac8f4c49c770a4959dc3c1363", - "304402203121d9b9c055f354304b016a36662ee99e1110d9501cb271b087ddb6f382c2c80220549882f3f3b78d9c492de47543cb9a697cecc493174726146536c5954dac7487", - "02000000000101ab84ff284f162cfbfef241f853b47d4368d171f9e2a1445160cd591c4c7d882b03000000000000000001b80b0000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e050047304402207bcbf4f60a9829b05d2dbab84ed593e0291836be715dc7db6b72a64caf646af802201e489a5a84f7c5cc130398b841d138d031a5137ac8f4c49c770a4959dc3c13630147304402203121d9b9c055f354304b016a36662ee99e1110d9501cb271b087ddb6f382c2c80220549882f3f3b78d9c492de47543cb9a697cecc493174726146536c5954dac748701008576a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a9148a486ff2e31d6158bf39e2608864d63fefd09d5b88ac6868f7010000" }, - - { 4, - "3044022076dca5cb81ba7e466e349b7128cdba216d4d01659e29b96025b9524aaf0d1899022060de85697b88b21c749702b7d2cfa7dfeaa1f472c8f1d7d9c23f2bf968464b87", - "3045022100d9080f103cc92bac15ec42464a95f070c7fb6925014e673ee2ea1374d36a7f7502200c65294d22eb20d48564954d5afe04a385551919d8b2ddb4ae2459daaeee1d95", - "02000000000101ab84ff284f162cfbfef241f853b47d4368d171f9e2a1445160cd591c4c7d882b04000000000000000001a00f0000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500473044022076dca5cb81ba7e466e349b7128cdba216d4d01659e29b96025b9524aaf0d1899022060de85697b88b21c749702b7d2cfa7dfeaa1f472c8f1d7d9c23f2bf968464b8701483045022100d9080f103cc92bac15ec42464a95f070c7fb6925014e673ee2ea1374d36a7f7502200c65294d22eb20d48564954d5afe04a385551919d8b2ddb4ae2459daaeee1d95012004040404040404040404040404040404040404040404040404040404040404048a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a91418bc1a114ccf9c052d3d23e28d3b0a9d1227434288527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f801b175ac686800000000" } + "304402206fc2d1f10ea59951eefac0b4b7c396a3c3d87b71ff0b019796ef4535beaf36f902201765b0181e514d04f4c8ad75659d7037be26cdb3f8bb6f78fe61decef484c3ea", + "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8007e80300000000000022002052bfef0479d7b293c27e0f1eb294bea154c63a3294ef092c19af51409bce0e2ad007000000000000220020403d394747cae42e98ff01734ad5c08f82ba123d3d9a620abda88989651e2ab5d007000000000000220020748eba944fedc8827f6b06bc44678f93c0f9e6078b35c6331ed31e75f8ce0c2db80b000000000000220020c20b5d1f8584fd90443e7b7b720136174fa4b9333c261d04dbbd012635c0f419a00f0000000000002200208c48d15160397c9731df9bc3b236656efb6665fbfe92b4a6878e88a499f741c4c0c62d0000000000160014cc1b07838e387deacd0e5232e1e8b49f4c29e484e0a06a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e040047304402206fc2d1f10ea59951eefac0b4b7c396a3c3d87b71ff0b019796ef4535beaf36f902201765b0181e514d04f4c8ad75659d7037be26cdb3f8bb6f78fe61decef484c3ea01473044022009b048187705a8cbc9ad73adbe5af148c3d012e1f067961486c822c7af08158c022006d66f3704cfab3eb2dc49dae24e4aa22a6910fc9b424007583204e3621af2e501475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", { + + { 0, + "3045022100d9e29616b8f3959f1d3d7f7ce893ffedcdc407717d0de8e37d808c91d3a7c50d022078c3033f6d00095c8720a4bc943c1b45727818c082e4e3ddbc6d3116435b624b", + "30440220636de5682ef0c5b61f124ec74e8aa2461a69777521d6998295dcea36bc3338110220165285594b23c50b28b82df200234566628a27bcd17f7f14404bd865354eb3ce", + "02000000000101ab84ff284f162cfbfef241f853b47d4368d171f9e2a1445160cd591c4c7d882b00000000000000000001e8030000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100d9e29616b8f3959f1d3d7f7ce893ffedcdc407717d0de8e37d808c91d3a7c50d022078c3033f6d00095c8720a4bc943c1b45727818c082e4e3ddbc6d3116435b624b014730440220636de5682ef0c5b61f124ec74e8aa2461a69777521d6998295dcea36bc3338110220165285594b23c50b28b82df200234566628a27bcd17f7f14404bd865354eb3ce012000000000000000000000000000000000000000000000000000000000000000008a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a914b8bcb07f6344b42ab04250c86a6e8b75d3fdbbc688527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f401b175ac686800000000" }, + + { 1, + "30440220649fe8b20e67e46cbb0d09b4acea87dbec001b39b08dee7bdd0b1f03922a8640022037c462dff79df501cecfdb12ea7f4de91f99230bb544726f6e04527b1f896004", + "3045022100803159dee7935dba4a1d36a61055ce8fd62caa528573cc221ae288515405a252022029c59e7cffce374fe860100a4a63787e105c3cf5156d40b12dd53ff55ac8cf3f", + "02000000000101ab84ff284f162cfbfef241f853b47d4368d171f9e2a1445160cd591c4c7d882b01000000000000000001d0070000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e05004730440220649fe8b20e67e46cbb0d09b4acea87dbec001b39b08dee7bdd0b1f03922a8640022037c462dff79df501cecfdb12ea7f4de91f99230bb544726f6e04527b1f89600401483045022100803159dee7935dba4a1d36a61055ce8fd62caa528573cc221ae288515405a252022029c59e7cffce374fe860100a4a63787e105c3cf5156d40b12dd53ff55ac8cf3f01008576a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a914b43e1b38138a41b37f7cd9a1d274bc63e3a9b5d188ac6868f6010000" }, + + { 2, + "30440220770fc321e97a19f38985f2e7732dd9fe08d16a2efa4bcbc0429400a447faf49102204d40b417f3113e1b0944ae0986f517564ab4acd3d190503faf97a6e420d43352", + "3045022100a437cc2ce77400ecde441b3398fea3c3ad8bdad8132be818227fe3c5b8345989022069d45e7fa0ae551ec37240845e2c561ceb2567eacf3076a6a43a502d05865faa", + "02000000000101ab84ff284f162cfbfef241f853b47d4368d171f9e2a1445160cd591c4c7d882b02000000000000000001d0070000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e05004730440220770fc321e97a19f38985f2e7732dd9fe08d16a2efa4bcbc0429400a447faf49102204d40b417f3113e1b0944ae0986f517564ab4acd3d190503faf97a6e420d4335201483045022100a437cc2ce77400ecde441b3398fea3c3ad8bdad8132be818227fe3c5b8345989022069d45e7fa0ae551ec37240845e2c561ceb2567eacf3076a6a43a502d05865faa012001010101010101010101010101010101010101010101010101010101010101018a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a9144b6b2e5444c2639cc0fb7bcea5afba3f3cdce23988527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f501b175ac686800000000" }, + + { 3, + "304402207bcbf4f60a9829b05d2dbab84ed593e0291836be715dc7db6b72a64caf646af802201e489a5a84f7c5cc130398b841d138d031a5137ac8f4c49c770a4959dc3c1363", + "304402203121d9b9c055f354304b016a36662ee99e1110d9501cb271b087ddb6f382c2c80220549882f3f3b78d9c492de47543cb9a697cecc493174726146536c5954dac7487", + "02000000000101ab84ff284f162cfbfef241f853b47d4368d171f9e2a1445160cd591c4c7d882b03000000000000000001b80b0000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e050047304402207bcbf4f60a9829b05d2dbab84ed593e0291836be715dc7db6b72a64caf646af802201e489a5a84f7c5cc130398b841d138d031a5137ac8f4c49c770a4959dc3c13630147304402203121d9b9c055f354304b016a36662ee99e1110d9501cb271b087ddb6f382c2c80220549882f3f3b78d9c492de47543cb9a697cecc493174726146536c5954dac748701008576a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a9148a486ff2e31d6158bf39e2608864d63fefd09d5b88ac6868f7010000" }, + + { 4, + "3044022076dca5cb81ba7e466e349b7128cdba216d4d01659e29b96025b9524aaf0d1899022060de85697b88b21c749702b7d2cfa7dfeaa1f472c8f1d7d9c23f2bf968464b87", + "3045022100d9080f103cc92bac15ec42464a95f070c7fb6925014e673ee2ea1374d36a7f7502200c65294d22eb20d48564954d5afe04a385551919d8b2ddb4ae2459daaeee1d95", + "02000000000101ab84ff284f162cfbfef241f853b47d4368d171f9e2a1445160cd591c4c7d882b04000000000000000001a00f0000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500473044022076dca5cb81ba7e466e349b7128cdba216d4d01659e29b96025b9524aaf0d1899022060de85697b88b21c749702b7d2cfa7dfeaa1f472c8f1d7d9c23f2bf968464b8701483045022100d9080f103cc92bac15ec42464a95f070c7fb6925014e673ee2ea1374d36a7f7502200c65294d22eb20d48564954d5afe04a385551919d8b2ddb4ae2459daaeee1d95012004040404040404040404040404040404040404040404040404040404040404048a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a91418bc1a114ccf9c052d3d23e28d3b0a9d1227434288527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f801b175ac686800000000" } } ); // commitment tx with seven outputs untrimmed (maximum feerate) @@ -7482,33 +8353,33 @@ mod tests { chan.feerate_per_kw = 647; test_commitment!("3045022100a135f9e8a5ed25f7277446c67956b00ce6f610ead2bdec2c2f686155b7814772022059f1f6e1a8b336a68efcc1af3fe4d422d4827332b5b067501b099c47b7b5b5ee", - "30450221009ec15c687898bb4da8b3a833e5ab8bfc51ec6e9202aaa8e66611edfd4a85ed1102203d7183e45078b9735c93450bc3415d3e5a8c576141a711ec6ddcb4a893926bb7", - "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8007e80300000000000022002052bfef0479d7b293c27e0f1eb294bea154c63a3294ef092c19af51409bce0e2ad007000000000000220020403d394747cae42e98ff01734ad5c08f82ba123d3d9a620abda88989651e2ab5d007000000000000220020748eba944fedc8827f6b06bc44678f93c0f9e6078b35c6331ed31e75f8ce0c2db80b000000000000220020c20b5d1f8584fd90443e7b7b720136174fa4b9333c261d04dbbd012635c0f419a00f0000000000002200208c48d15160397c9731df9bc3b236656efb6665fbfe92b4a6878e88a499f741c4c0c62d0000000000160014cc1b07838e387deacd0e5232e1e8b49f4c29e484e09c6a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e04004830450221009ec15c687898bb4da8b3a833e5ab8bfc51ec6e9202aaa8e66611edfd4a85ed1102203d7183e45078b9735c93450bc3415d3e5a8c576141a711ec6ddcb4a893926bb701483045022100a135f9e8a5ed25f7277446c67956b00ce6f610ead2bdec2c2f686155b7814772022059f1f6e1a8b336a68efcc1af3fe4d422d4827332b5b067501b099c47b7b5b5ee01475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", { - - { 0, - "30450221008437627f9ad84ac67052e2a414a4367b8556fd1f94d8b02590f89f50525cd33502205b9c21ff6e7fc864f2352746ad8ba59182510819acb644e25b8a12fc37bbf24f", - "30440220344b0deb055230d01703e6c7acd45853c4af2328b49b5d8af4f88a060733406602202ea64f2a43d5751edfe75503cbc35a62e3141b5ed032fa03360faf4ca66f670b", - "020000000001012cfb3e4788c206881d38f2996b6cb2109b5935acb527d14bdaa7b908afa9b2fe0000000000000000000122020000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e05004830450221008437627f9ad84ac67052e2a414a4367b8556fd1f94d8b02590f89f50525cd33502205b9c21ff6e7fc864f2352746ad8ba59182510819acb644e25b8a12fc37bbf24f014730440220344b0deb055230d01703e6c7acd45853c4af2328b49b5d8af4f88a060733406602202ea64f2a43d5751edfe75503cbc35a62e3141b5ed032fa03360faf4ca66f670b012000000000000000000000000000000000000000000000000000000000000000008a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a914b8bcb07f6344b42ab04250c86a6e8b75d3fdbbc688527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f401b175ac686800000000" }, - - { 1, - "304402205a67f92bf6845cf2892b48d874ac1daf88a36495cf8a06f93d83180d930a6f75022031da1621d95c3f335cc06a3056cf960199dae600b7cf89088f65fc53cdbef28c", - "30450221009e5e3822b0185c6799a95288c597b671d6cc69ab80f43740f00c6c3d0752bdda02206da947a74bd98f3175324dc56fdba86cc783703a120a6f0297537e60632f4c7f", - "020000000001012cfb3e4788c206881d38f2996b6cb2109b5935acb527d14bdaa7b908afa9b2fe0100000000000000000124060000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e050047304402205a67f92bf6845cf2892b48d874ac1daf88a36495cf8a06f93d83180d930a6f75022031da1621d95c3f335cc06a3056cf960199dae600b7cf89088f65fc53cdbef28c014830450221009e5e3822b0185c6799a95288c597b671d6cc69ab80f43740f00c6c3d0752bdda02206da947a74bd98f3175324dc56fdba86cc783703a120a6f0297537e60632f4c7f01008576a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a914b43e1b38138a41b37f7cd9a1d274bc63e3a9b5d188ac6868f6010000" }, - - { 2, - "30440220437e21766054a3eef7f65690c5bcfa9920babbc5af92b819f772f6ea96df6c7402207173622024bd97328cfb26c6665e25c2f5d67c319443ccdc60c903217005d8c8", - "3045022100fcfc47e36b712624677626cef3dc1d67f6583bd46926a6398fe6b00b0c9a37760220525788257b187fc775c6370d04eadf34d06f3650a63f8df851cee0ecb47a1673", - "020000000001012cfb3e4788c206881d38f2996b6cb2109b5935acb527d14bdaa7b908afa9b2fe020000000000000000010a060000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e05004730440220437e21766054a3eef7f65690c5bcfa9920babbc5af92b819f772f6ea96df6c7402207173622024bd97328cfb26c6665e25c2f5d67c319443ccdc60c903217005d8c801483045022100fcfc47e36b712624677626cef3dc1d67f6583bd46926a6398fe6b00b0c9a37760220525788257b187fc775c6370d04eadf34d06f3650a63f8df851cee0ecb47a1673012001010101010101010101010101010101010101010101010101010101010101018a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a9144b6b2e5444c2639cc0fb7bcea5afba3f3cdce23988527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f501b175ac686800000000" }, - - { 3, - "304402207436e10737e4df499fc051686d3e11a5bb2310e4d1f1e691d287cef66514791202207cb58e71a6b7a42dd001b7e3ae672ea4f71ea3e1cd412b742e9124abb0739c64", - "3045022100e78211b8409afb7255ffe37337da87f38646f1faebbdd61bc1920d69e3ead67a02201a626305adfcd16bfb7e9340928d9b6305464eab4aa4c4a3af6646e9b9f69dee", - "020000000001012cfb3e4788c206881d38f2996b6cb2109b5935acb527d14bdaa7b908afa9b2fe030000000000000000010c0a0000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e050047304402207436e10737e4df499fc051686d3e11a5bb2310e4d1f1e691d287cef66514791202207cb58e71a6b7a42dd001b7e3ae672ea4f71ea3e1cd412b742e9124abb0739c6401483045022100e78211b8409afb7255ffe37337da87f38646f1faebbdd61bc1920d69e3ead67a02201a626305adfcd16bfb7e9340928d9b6305464eab4aa4c4a3af6646e9b9f69dee01008576a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a9148a486ff2e31d6158bf39e2608864d63fefd09d5b88ac6868f7010000" }, - - { 4, - "30450221009acd6a827a76bfee50806178dfe0495cd4e1d9c58279c194c7b01520fe68cb8d022024d439047c368883e570997a7d40f0b430cb5a742f507965e7d3063ae3feccca", - "3044022048762cf546bbfe474f1536365ea7c416e3c0389d60558bc9412cb148fb6ab68202207215d7083b75c96ff9d2b08c59c34e287b66820f530b486a9aa4cdd9c347d5b9", - "020000000001012cfb3e4788c206881d38f2996b6cb2109b5935acb527d14bdaa7b908afa9b2fe04000000000000000001da0d0000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e05004830450221009acd6a827a76bfee50806178dfe0495cd4e1d9c58279c194c7b01520fe68cb8d022024d439047c368883e570997a7d40f0b430cb5a742f507965e7d3063ae3feccca01473044022048762cf546bbfe474f1536365ea7c416e3c0389d60558bc9412cb148fb6ab68202207215d7083b75c96ff9d2b08c59c34e287b66820f530b486a9aa4cdd9c347d5b9012004040404040404040404040404040404040404040404040404040404040404048a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a91418bc1a114ccf9c052d3d23e28d3b0a9d1227434288527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f801b175ac686800000000" } + "30450221009ec15c687898bb4da8b3a833e5ab8bfc51ec6e9202aaa8e66611edfd4a85ed1102203d7183e45078b9735c93450bc3415d3e5a8c576141a711ec6ddcb4a893926bb7", + "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8007e80300000000000022002052bfef0479d7b293c27e0f1eb294bea154c63a3294ef092c19af51409bce0e2ad007000000000000220020403d394747cae42e98ff01734ad5c08f82ba123d3d9a620abda88989651e2ab5d007000000000000220020748eba944fedc8827f6b06bc44678f93c0f9e6078b35c6331ed31e75f8ce0c2db80b000000000000220020c20b5d1f8584fd90443e7b7b720136174fa4b9333c261d04dbbd012635c0f419a00f0000000000002200208c48d15160397c9731df9bc3b236656efb6665fbfe92b4a6878e88a499f741c4c0c62d0000000000160014cc1b07838e387deacd0e5232e1e8b49f4c29e484e09c6a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e04004830450221009ec15c687898bb4da8b3a833e5ab8bfc51ec6e9202aaa8e66611edfd4a85ed1102203d7183e45078b9735c93450bc3415d3e5a8c576141a711ec6ddcb4a893926bb701483045022100a135f9e8a5ed25f7277446c67956b00ce6f610ead2bdec2c2f686155b7814772022059f1f6e1a8b336a68efcc1af3fe4d422d4827332b5b067501b099c47b7b5b5ee01475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", { + + { 0, + "30450221008437627f9ad84ac67052e2a414a4367b8556fd1f94d8b02590f89f50525cd33502205b9c21ff6e7fc864f2352746ad8ba59182510819acb644e25b8a12fc37bbf24f", + "30440220344b0deb055230d01703e6c7acd45853c4af2328b49b5d8af4f88a060733406602202ea64f2a43d5751edfe75503cbc35a62e3141b5ed032fa03360faf4ca66f670b", + "020000000001012cfb3e4788c206881d38f2996b6cb2109b5935acb527d14bdaa7b908afa9b2fe0000000000000000000122020000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e05004830450221008437627f9ad84ac67052e2a414a4367b8556fd1f94d8b02590f89f50525cd33502205b9c21ff6e7fc864f2352746ad8ba59182510819acb644e25b8a12fc37bbf24f014730440220344b0deb055230d01703e6c7acd45853c4af2328b49b5d8af4f88a060733406602202ea64f2a43d5751edfe75503cbc35a62e3141b5ed032fa03360faf4ca66f670b012000000000000000000000000000000000000000000000000000000000000000008a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a914b8bcb07f6344b42ab04250c86a6e8b75d3fdbbc688527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f401b175ac686800000000" }, + + { 1, + "304402205a67f92bf6845cf2892b48d874ac1daf88a36495cf8a06f93d83180d930a6f75022031da1621d95c3f335cc06a3056cf960199dae600b7cf89088f65fc53cdbef28c", + "30450221009e5e3822b0185c6799a95288c597b671d6cc69ab80f43740f00c6c3d0752bdda02206da947a74bd98f3175324dc56fdba86cc783703a120a6f0297537e60632f4c7f", + "020000000001012cfb3e4788c206881d38f2996b6cb2109b5935acb527d14bdaa7b908afa9b2fe0100000000000000000124060000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e050047304402205a67f92bf6845cf2892b48d874ac1daf88a36495cf8a06f93d83180d930a6f75022031da1621d95c3f335cc06a3056cf960199dae600b7cf89088f65fc53cdbef28c014830450221009e5e3822b0185c6799a95288c597b671d6cc69ab80f43740f00c6c3d0752bdda02206da947a74bd98f3175324dc56fdba86cc783703a120a6f0297537e60632f4c7f01008576a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a914b43e1b38138a41b37f7cd9a1d274bc63e3a9b5d188ac6868f6010000" }, + + { 2, + "30440220437e21766054a3eef7f65690c5bcfa9920babbc5af92b819f772f6ea96df6c7402207173622024bd97328cfb26c6665e25c2f5d67c319443ccdc60c903217005d8c8", + "3045022100fcfc47e36b712624677626cef3dc1d67f6583bd46926a6398fe6b00b0c9a37760220525788257b187fc775c6370d04eadf34d06f3650a63f8df851cee0ecb47a1673", + "020000000001012cfb3e4788c206881d38f2996b6cb2109b5935acb527d14bdaa7b908afa9b2fe020000000000000000010a060000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e05004730440220437e21766054a3eef7f65690c5bcfa9920babbc5af92b819f772f6ea96df6c7402207173622024bd97328cfb26c6665e25c2f5d67c319443ccdc60c903217005d8c801483045022100fcfc47e36b712624677626cef3dc1d67f6583bd46926a6398fe6b00b0c9a37760220525788257b187fc775c6370d04eadf34d06f3650a63f8df851cee0ecb47a1673012001010101010101010101010101010101010101010101010101010101010101018a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a9144b6b2e5444c2639cc0fb7bcea5afba3f3cdce23988527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f501b175ac686800000000" }, + + { 3, + "304402207436e10737e4df499fc051686d3e11a5bb2310e4d1f1e691d287cef66514791202207cb58e71a6b7a42dd001b7e3ae672ea4f71ea3e1cd412b742e9124abb0739c64", + "3045022100e78211b8409afb7255ffe37337da87f38646f1faebbdd61bc1920d69e3ead67a02201a626305adfcd16bfb7e9340928d9b6305464eab4aa4c4a3af6646e9b9f69dee", + "020000000001012cfb3e4788c206881d38f2996b6cb2109b5935acb527d14bdaa7b908afa9b2fe030000000000000000010c0a0000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e050047304402207436e10737e4df499fc051686d3e11a5bb2310e4d1f1e691d287cef66514791202207cb58e71a6b7a42dd001b7e3ae672ea4f71ea3e1cd412b742e9124abb0739c6401483045022100e78211b8409afb7255ffe37337da87f38646f1faebbdd61bc1920d69e3ead67a02201a626305adfcd16bfb7e9340928d9b6305464eab4aa4c4a3af6646e9b9f69dee01008576a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a9148a486ff2e31d6158bf39e2608864d63fefd09d5b88ac6868f7010000" }, + + { 4, + "30450221009acd6a827a76bfee50806178dfe0495cd4e1d9c58279c194c7b01520fe68cb8d022024d439047c368883e570997a7d40f0b430cb5a742f507965e7d3063ae3feccca", + "3044022048762cf546bbfe474f1536365ea7c416e3c0389d60558bc9412cb148fb6ab68202207215d7083b75c96ff9d2b08c59c34e287b66820f530b486a9aa4cdd9c347d5b9", + "020000000001012cfb3e4788c206881d38f2996b6cb2109b5935acb527d14bdaa7b908afa9b2fe04000000000000000001da0d0000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e05004830450221009acd6a827a76bfee50806178dfe0495cd4e1d9c58279c194c7b01520fe68cb8d022024d439047c368883e570997a7d40f0b430cb5a742f507965e7d3063ae3feccca01473044022048762cf546bbfe474f1536365ea7c416e3c0389d60558bc9412cb148fb6ab68202207215d7083b75c96ff9d2b08c59c34e287b66820f530b486a9aa4cdd9c347d5b9012004040404040404040404040404040404040404040404040404040404040404048a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a91418bc1a114ccf9c052d3d23e28d3b0a9d1227434288527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f801b175ac686800000000" } } ); // commitment tx with six outputs untrimmed (minimum feerate) @@ -7516,28 +8387,28 @@ mod tests { chan.feerate_per_kw = 648; test_commitment!("304402203948f900a5506b8de36a4d8502f94f21dd84fd9c2314ab427d52feaa7a0a19f2022059b6a37a4adaa2c5419dc8aea63c6e2a2ec4c4bde46207f6dc1fcd22152fc6e5", - "3045022100b15f72908ba3382a34ca5b32519240a22300cc6015b6f9418635fb41f3d01d8802207adb331b9ed1575383dca0f2355e86c173802feecf8298fbea53b9d4610583e9", - "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8006d007000000000000220020403d394747cae42e98ff01734ad5c08f82ba123d3d9a620abda88989651e2ab5d007000000000000220020748eba944fedc8827f6b06bc44678f93c0f9e6078b35c6331ed31e75f8ce0c2db80b000000000000220020c20b5d1f8584fd90443e7b7b720136174fa4b9333c261d04dbbd012635c0f419a00f0000000000002200208c48d15160397c9731df9bc3b236656efb6665fbfe92b4a6878e88a499f741c4c0c62d0000000000160014cc1b07838e387deacd0e5232e1e8b49f4c29e4844e9d6a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0400483045022100b15f72908ba3382a34ca5b32519240a22300cc6015b6f9418635fb41f3d01d8802207adb331b9ed1575383dca0f2355e86c173802feecf8298fbea53b9d4610583e90147304402203948f900a5506b8de36a4d8502f94f21dd84fd9c2314ab427d52feaa7a0a19f2022059b6a37a4adaa2c5419dc8aea63c6e2a2ec4c4bde46207f6dc1fcd22152fc6e501475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", { - - { 0, - "3045022100a031202f3be94678f0e998622ee95ebb6ada8da1e9a5110228b5e04a747351e4022010ca6a21e18314ed53cfaae3b1f51998552a61a468e596368829a50ce40110e0", - "304502210097e1873b57267730154595187a34949d3744f52933070c74757005e61ce2112e02204ecfba2aa42d4f14bdf8bad4206bb97217b702e6c433e0e1b0ce6587e6d46ec6", - "020000000001010f44041fdfba175987cf4e6135ba2a154e3b7fb96483dc0ed5efc0678e5b6bf10000000000000000000123060000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100a031202f3be94678f0e998622ee95ebb6ada8da1e9a5110228b5e04a747351e4022010ca6a21e18314ed53cfaae3b1f51998552a61a468e596368829a50ce40110e00148304502210097e1873b57267730154595187a34949d3744f52933070c74757005e61ce2112e02204ecfba2aa42d4f14bdf8bad4206bb97217b702e6c433e0e1b0ce6587e6d46ec601008576a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a914b43e1b38138a41b37f7cd9a1d274bc63e3a9b5d188ac6868f6010000" }, - - { 1, - "304402202361012a634aee7835c5ecdd6413dcffa8f404b7e77364c792cff984e4ee71e90220715c5e90baa08daa45a7439b1ee4fa4843ed77b19c058240b69406606d384124", - "3044022019de73b00f1d818fb388e83b2c8c31f6bce35ac624e215bc12f88f9dc33edf48022006ff814bb9f700ee6abc3294e146fac3efd4f13f0005236b41c0a946ee00c9ae", - "020000000001010f44041fdfba175987cf4e6135ba2a154e3b7fb96483dc0ed5efc0678e5b6bf10100000000000000000109060000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e050047304402202361012a634aee7835c5ecdd6413dcffa8f404b7e77364c792cff984e4ee71e90220715c5e90baa08daa45a7439b1ee4fa4843ed77b19c058240b69406606d38412401473044022019de73b00f1d818fb388e83b2c8c31f6bce35ac624e215bc12f88f9dc33edf48022006ff814bb9f700ee6abc3294e146fac3efd4f13f0005236b41c0a946ee00c9ae012001010101010101010101010101010101010101010101010101010101010101018a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a9144b6b2e5444c2639cc0fb7bcea5afba3f3cdce23988527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f501b175ac686800000000" }, - - { 2, - "304402207e8e82cd71ed4febeb593732c260456836e97d81896153ecd2b3cf320ca6861702202dd4a30f68f98ced7cc56a36369ac1fdd978248c5ff4ed204fc00cc625532989", - "3045022100bd0be6100c4fd8f102ec220e1b053e4c4e2ecca25615490150007b40d314dc3902201a1e0ea266965b43164d9e6576f58fa6726d42883dd1c3996d2925c2e2260796", - "020000000001010f44041fdfba175987cf4e6135ba2a154e3b7fb96483dc0ed5efc0678e5b6bf1020000000000000000010b0a0000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e050047304402207e8e82cd71ed4febeb593732c260456836e97d81896153ecd2b3cf320ca6861702202dd4a30f68f98ced7cc56a36369ac1fdd978248c5ff4ed204fc00cc62553298901483045022100bd0be6100c4fd8f102ec220e1b053e4c4e2ecca25615490150007b40d314dc3902201a1e0ea266965b43164d9e6576f58fa6726d42883dd1c3996d2925c2e226079601008576a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a9148a486ff2e31d6158bf39e2608864d63fefd09d5b88ac6868f7010000" }, - - { 3, - "3044022024cd52e4198c8ae0e414a86d86b5a65ea7450f2eb4e783096736d93395eca5ce022078f0094745b45be4d4b2b04dd5978c9e66ba49109e5704403e84aaf5f387d6be", - "3045022100bbfb9d0a946d420807c86e985d636cceb16e71c3694ed186316251a00cbd807202207773223f9a337e145f64673825be9b30d07ef1542c82188b264bedcf7cda78c6", - "020000000001010f44041fdfba175987cf4e6135ba2a154e3b7fb96483dc0ed5efc0678e5b6bf103000000000000000001d90d0000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500473044022024cd52e4198c8ae0e414a86d86b5a65ea7450f2eb4e783096736d93395eca5ce022078f0094745b45be4d4b2b04dd5978c9e66ba49109e5704403e84aaf5f387d6be01483045022100bbfb9d0a946d420807c86e985d636cceb16e71c3694ed186316251a00cbd807202207773223f9a337e145f64673825be9b30d07ef1542c82188b264bedcf7cda78c6012004040404040404040404040404040404040404040404040404040404040404048a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a91418bc1a114ccf9c052d3d23e28d3b0a9d1227434288527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f801b175ac686800000000" } + "3045022100b15f72908ba3382a34ca5b32519240a22300cc6015b6f9418635fb41f3d01d8802207adb331b9ed1575383dca0f2355e86c173802feecf8298fbea53b9d4610583e9", + "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8006d007000000000000220020403d394747cae42e98ff01734ad5c08f82ba123d3d9a620abda88989651e2ab5d007000000000000220020748eba944fedc8827f6b06bc44678f93c0f9e6078b35c6331ed31e75f8ce0c2db80b000000000000220020c20b5d1f8584fd90443e7b7b720136174fa4b9333c261d04dbbd012635c0f419a00f0000000000002200208c48d15160397c9731df9bc3b236656efb6665fbfe92b4a6878e88a499f741c4c0c62d0000000000160014cc1b07838e387deacd0e5232e1e8b49f4c29e4844e9d6a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0400483045022100b15f72908ba3382a34ca5b32519240a22300cc6015b6f9418635fb41f3d01d8802207adb331b9ed1575383dca0f2355e86c173802feecf8298fbea53b9d4610583e90147304402203948f900a5506b8de36a4d8502f94f21dd84fd9c2314ab427d52feaa7a0a19f2022059b6a37a4adaa2c5419dc8aea63c6e2a2ec4c4bde46207f6dc1fcd22152fc6e501475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", { + + { 0, + "3045022100a031202f3be94678f0e998622ee95ebb6ada8da1e9a5110228b5e04a747351e4022010ca6a21e18314ed53cfaae3b1f51998552a61a468e596368829a50ce40110e0", + "304502210097e1873b57267730154595187a34949d3744f52933070c74757005e61ce2112e02204ecfba2aa42d4f14bdf8bad4206bb97217b702e6c433e0e1b0ce6587e6d46ec6", + "020000000001010f44041fdfba175987cf4e6135ba2a154e3b7fb96483dc0ed5efc0678e5b6bf10000000000000000000123060000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100a031202f3be94678f0e998622ee95ebb6ada8da1e9a5110228b5e04a747351e4022010ca6a21e18314ed53cfaae3b1f51998552a61a468e596368829a50ce40110e00148304502210097e1873b57267730154595187a34949d3744f52933070c74757005e61ce2112e02204ecfba2aa42d4f14bdf8bad4206bb97217b702e6c433e0e1b0ce6587e6d46ec601008576a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a914b43e1b38138a41b37f7cd9a1d274bc63e3a9b5d188ac6868f6010000" }, + + { 1, + "304402202361012a634aee7835c5ecdd6413dcffa8f404b7e77364c792cff984e4ee71e90220715c5e90baa08daa45a7439b1ee4fa4843ed77b19c058240b69406606d384124", + "3044022019de73b00f1d818fb388e83b2c8c31f6bce35ac624e215bc12f88f9dc33edf48022006ff814bb9f700ee6abc3294e146fac3efd4f13f0005236b41c0a946ee00c9ae", + "020000000001010f44041fdfba175987cf4e6135ba2a154e3b7fb96483dc0ed5efc0678e5b6bf10100000000000000000109060000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e050047304402202361012a634aee7835c5ecdd6413dcffa8f404b7e77364c792cff984e4ee71e90220715c5e90baa08daa45a7439b1ee4fa4843ed77b19c058240b69406606d38412401473044022019de73b00f1d818fb388e83b2c8c31f6bce35ac624e215bc12f88f9dc33edf48022006ff814bb9f700ee6abc3294e146fac3efd4f13f0005236b41c0a946ee00c9ae012001010101010101010101010101010101010101010101010101010101010101018a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a9144b6b2e5444c2639cc0fb7bcea5afba3f3cdce23988527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f501b175ac686800000000" }, + + { 2, + "304402207e8e82cd71ed4febeb593732c260456836e97d81896153ecd2b3cf320ca6861702202dd4a30f68f98ced7cc56a36369ac1fdd978248c5ff4ed204fc00cc625532989", + "3045022100bd0be6100c4fd8f102ec220e1b053e4c4e2ecca25615490150007b40d314dc3902201a1e0ea266965b43164d9e6576f58fa6726d42883dd1c3996d2925c2e2260796", + "020000000001010f44041fdfba175987cf4e6135ba2a154e3b7fb96483dc0ed5efc0678e5b6bf1020000000000000000010b0a0000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e050047304402207e8e82cd71ed4febeb593732c260456836e97d81896153ecd2b3cf320ca6861702202dd4a30f68f98ced7cc56a36369ac1fdd978248c5ff4ed204fc00cc62553298901483045022100bd0be6100c4fd8f102ec220e1b053e4c4e2ecca25615490150007b40d314dc3902201a1e0ea266965b43164d9e6576f58fa6726d42883dd1c3996d2925c2e226079601008576a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a9148a486ff2e31d6158bf39e2608864d63fefd09d5b88ac6868f7010000" }, + + { 3, + "3044022024cd52e4198c8ae0e414a86d86b5a65ea7450f2eb4e783096736d93395eca5ce022078f0094745b45be4d4b2b04dd5978c9e66ba49109e5704403e84aaf5f387d6be", + "3045022100bbfb9d0a946d420807c86e985d636cceb16e71c3694ed186316251a00cbd807202207773223f9a337e145f64673825be9b30d07ef1542c82188b264bedcf7cda78c6", + "020000000001010f44041fdfba175987cf4e6135ba2a154e3b7fb96483dc0ed5efc0678e5b6bf103000000000000000001d90d0000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500473044022024cd52e4198c8ae0e414a86d86b5a65ea7450f2eb4e783096736d93395eca5ce022078f0094745b45be4d4b2b04dd5978c9e66ba49109e5704403e84aaf5f387d6be01483045022100bbfb9d0a946d420807c86e985d636cceb16e71c3694ed186316251a00cbd807202207773223f9a337e145f64673825be9b30d07ef1542c82188b264bedcf7cda78c6012004040404040404040404040404040404040404040404040404040404040404048a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a91418bc1a114ccf9c052d3d23e28d3b0a9d1227434288527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f801b175ac686800000000" } } ); // anchors: commitment tx with six outputs untrimmed (minimum dust limit) @@ -7546,28 +8417,28 @@ mod tests { chan.holder_dust_limit_satoshis = 1001; test_commitment_with_anchors!("3044022025d97466c8049e955a5afce28e322f4b34d2561118e52332fb400f9b908cc0a402205dc6fba3a0d67ee142c428c535580cd1f2ff42e2f89b47e0c8a01847caffc312", - "3045022100d57697c707b6f6d053febf24b98e8989f186eea42e37e9e91663ec2c70bb8f70022079b0715a472118f262f43016a674f59c015d9cafccec885968e76d9d9c5d0051", - "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b80084a010000000000002200202b1b5854183c12d3316565972c4668929d314d81c5dcdbb21cb45fe8a9a8114f4a01000000000000220020e9e86e4823faa62e222ebc858a226636856158f07e69898da3b0d1af0ddb3994d0070000000000002200203e68115ae0b15b8de75b6c6bc9af5ac9f01391544e0870dae443a1e8fe7837ead007000000000000220020fe0598d74fee2205cc3672e6e6647706b4f3099713b4661b62482c3addd04a5eb80b000000000000220020f96d0334feb64a4f40eb272031d07afcb038db56aa57446d60308c9f8ccadef9a00f000000000000220020ce6e751274836ff59622a0d1e07f8831d80bd6730bd48581398bfadd2bb8da9ac0c62d0000000000220020f3394e1e619b0eca1f91be2fb5ab4dfc59ba5b84ebe014ad1d43a564d012994abc996a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0400483045022100d57697c707b6f6d053febf24b98e8989f186eea42e37e9e91663ec2c70bb8f70022079b0715a472118f262f43016a674f59c015d9cafccec885968e76d9d9c5d005101473044022025d97466c8049e955a5afce28e322f4b34d2561118e52332fb400f9b908cc0a402205dc6fba3a0d67ee142c428c535580cd1f2ff42e2f89b47e0c8a01847caffc31201475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", { - - { 0, - "3045022100e04d160a326432659fe9fb127304c1d348dfeaba840081bdc57d8efd902a48d8022008a824e7cf5492b97e4d9e03c06a09f822775a44f6b5b2533a2088904abfc282", - "3045022100b7c49846466b13b190ff739bbe3005c105482fc55539e55b1c561f76b6982b6c02200e5c35808619cf543c8405cff9fedd25f333a4a2f6f6d5e8af8150090c40ef09", - "02000000000101104f394af4c4fad78337f95e3e9f802f4c0d86ab231853af09b285348561320002000000000100000001d0070000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100e04d160a326432659fe9fb127304c1d348dfeaba840081bdc57d8efd902a48d8022008a824e7cf5492b97e4d9e03c06a09f822775a44f6b5b2533a2088904abfc28283483045022100b7c49846466b13b190ff739bbe3005c105482fc55539e55b1c561f76b6982b6c02200e5c35808619cf543c8405cff9fedd25f333a4a2f6f6d5e8af8150090c40ef0901008876a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a914b43e1b38138a41b37f7cd9a1d274bc63e3a9b5d188ac6851b27568f6010000" }, - - { 1, - "3045022100fbdc3c367ce3bf30796025cc590ee1f2ce0e72ae1ac19f5986d6d0a4fc76211f02207e45ae9267e8e820d188569604f71d1abd11bd385d58853dd7dc034cdb3e9a6e", - "3045022100d29330f24db213b262068706099b39c15fa7e070c3fcdf8836c09723fc4d365602203ce57d01e9f28601e461a0b5c4a50119b270bde8b70148d133a6849c70b115ac", - "02000000000101104f394af4c4fad78337f95e3e9f802f4c0d86ab231853af09b285348561320003000000000100000001d0070000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100fbdc3c367ce3bf30796025cc590ee1f2ce0e72ae1ac19f5986d6d0a4fc76211f02207e45ae9267e8e820d188569604f71d1abd11bd385d58853dd7dc034cdb3e9a6e83483045022100d29330f24db213b262068706099b39c15fa7e070c3fcdf8836c09723fc4d365602203ce57d01e9f28601e461a0b5c4a50119b270bde8b70148d133a6849c70b115ac012001010101010101010101010101010101010101010101010101010101010101018d76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a9144b6b2e5444c2639cc0fb7bcea5afba3f3cdce23988527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f501b175ac6851b2756800000000" }, - - { 2, - "3044022066c5ef625cee3ddd2bc7b6bfb354b5834cf1cc6d52dd972fb41b7b225437ae4a022066cb85647df65c6b87a54e416dcdcca778a776c36a9643d2b5dc793c9b29f4c1", - "304402202d4ce515cd9000ec37575972d70b8d24f73909fb7012e8ebd8c2066ef6fe187902202830b53e64ea565fecd0f398100691da6bb2a5cf9bb0d1926f1d71d05828a11e", - "02000000000101104f394af4c4fad78337f95e3e9f802f4c0d86ab231853af09b285348561320004000000000100000001b80b0000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500473044022066c5ef625cee3ddd2bc7b6bfb354b5834cf1cc6d52dd972fb41b7b225437ae4a022066cb85647df65c6b87a54e416dcdcca778a776c36a9643d2b5dc793c9b29f4c18347304402202d4ce515cd9000ec37575972d70b8d24f73909fb7012e8ebd8c2066ef6fe187902202830b53e64ea565fecd0f398100691da6bb2a5cf9bb0d1926f1d71d05828a11e01008876a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a9148a486ff2e31d6158bf39e2608864d63fefd09d5b88ac6851b27568f7010000" }, - - { 3, - "3044022022c7e11595c53ee89a57ca76baf0aed730da035952d6ab3fe6459f5eff3b337a022075e10cc5f5fd724a35ce4087a5d03cd616698626c69814032132b50bb97dc615", - "3045022100b20cd63e0587d1711beaebda4730775c4ac8b8b2ec78fe18a0c44c3f168c25230220079abb7fc4924e2fca5950842e5b9e416735585026914570078c4ef62f286226", - "02000000000101104f394af4c4fad78337f95e3e9f802f4c0d86ab231853af09b285348561320005000000000100000001a00f0000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500473044022022c7e11595c53ee89a57ca76baf0aed730da035952d6ab3fe6459f5eff3b337a022075e10cc5f5fd724a35ce4087a5d03cd616698626c69814032132b50bb97dc61583483045022100b20cd63e0587d1711beaebda4730775c4ac8b8b2ec78fe18a0c44c3f168c25230220079abb7fc4924e2fca5950842e5b9e416735585026914570078c4ef62f286226012004040404040404040404040404040404040404040404040404040404040404048d76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a91418bc1a114ccf9c052d3d23e28d3b0a9d1227434288527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f801b175ac6851b2756800000000" } + "3045022100d57697c707b6f6d053febf24b98e8989f186eea42e37e9e91663ec2c70bb8f70022079b0715a472118f262f43016a674f59c015d9cafccec885968e76d9d9c5d0051", + "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b80084a010000000000002200202b1b5854183c12d3316565972c4668929d314d81c5dcdbb21cb45fe8a9a8114f4a01000000000000220020e9e86e4823faa62e222ebc858a226636856158f07e69898da3b0d1af0ddb3994d0070000000000002200203e68115ae0b15b8de75b6c6bc9af5ac9f01391544e0870dae443a1e8fe7837ead007000000000000220020fe0598d74fee2205cc3672e6e6647706b4f3099713b4661b62482c3addd04a5eb80b000000000000220020f96d0334feb64a4f40eb272031d07afcb038db56aa57446d60308c9f8ccadef9a00f000000000000220020ce6e751274836ff59622a0d1e07f8831d80bd6730bd48581398bfadd2bb8da9ac0c62d0000000000220020f3394e1e619b0eca1f91be2fb5ab4dfc59ba5b84ebe014ad1d43a564d012994abc996a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0400483045022100d57697c707b6f6d053febf24b98e8989f186eea42e37e9e91663ec2c70bb8f70022079b0715a472118f262f43016a674f59c015d9cafccec885968e76d9d9c5d005101473044022025d97466c8049e955a5afce28e322f4b34d2561118e52332fb400f9b908cc0a402205dc6fba3a0d67ee142c428c535580cd1f2ff42e2f89b47e0c8a01847caffc31201475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", { + + { 0, + "3045022100e04d160a326432659fe9fb127304c1d348dfeaba840081bdc57d8efd902a48d8022008a824e7cf5492b97e4d9e03c06a09f822775a44f6b5b2533a2088904abfc282", + "3045022100b7c49846466b13b190ff739bbe3005c105482fc55539e55b1c561f76b6982b6c02200e5c35808619cf543c8405cff9fedd25f333a4a2f6f6d5e8af8150090c40ef09", + "02000000000101104f394af4c4fad78337f95e3e9f802f4c0d86ab231853af09b285348561320002000000000100000001d0070000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100e04d160a326432659fe9fb127304c1d348dfeaba840081bdc57d8efd902a48d8022008a824e7cf5492b97e4d9e03c06a09f822775a44f6b5b2533a2088904abfc28283483045022100b7c49846466b13b190ff739bbe3005c105482fc55539e55b1c561f76b6982b6c02200e5c35808619cf543c8405cff9fedd25f333a4a2f6f6d5e8af8150090c40ef0901008876a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a914b43e1b38138a41b37f7cd9a1d274bc63e3a9b5d188ac6851b27568f6010000" }, + + { 1, + "3045022100fbdc3c367ce3bf30796025cc590ee1f2ce0e72ae1ac19f5986d6d0a4fc76211f02207e45ae9267e8e820d188569604f71d1abd11bd385d58853dd7dc034cdb3e9a6e", + "3045022100d29330f24db213b262068706099b39c15fa7e070c3fcdf8836c09723fc4d365602203ce57d01e9f28601e461a0b5c4a50119b270bde8b70148d133a6849c70b115ac", + "02000000000101104f394af4c4fad78337f95e3e9f802f4c0d86ab231853af09b285348561320003000000000100000001d0070000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100fbdc3c367ce3bf30796025cc590ee1f2ce0e72ae1ac19f5986d6d0a4fc76211f02207e45ae9267e8e820d188569604f71d1abd11bd385d58853dd7dc034cdb3e9a6e83483045022100d29330f24db213b262068706099b39c15fa7e070c3fcdf8836c09723fc4d365602203ce57d01e9f28601e461a0b5c4a50119b270bde8b70148d133a6849c70b115ac012001010101010101010101010101010101010101010101010101010101010101018d76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a9144b6b2e5444c2639cc0fb7bcea5afba3f3cdce23988527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f501b175ac6851b2756800000000" }, + + { 2, + "3044022066c5ef625cee3ddd2bc7b6bfb354b5834cf1cc6d52dd972fb41b7b225437ae4a022066cb85647df65c6b87a54e416dcdcca778a776c36a9643d2b5dc793c9b29f4c1", + "304402202d4ce515cd9000ec37575972d70b8d24f73909fb7012e8ebd8c2066ef6fe187902202830b53e64ea565fecd0f398100691da6bb2a5cf9bb0d1926f1d71d05828a11e", + "02000000000101104f394af4c4fad78337f95e3e9f802f4c0d86ab231853af09b285348561320004000000000100000001b80b0000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500473044022066c5ef625cee3ddd2bc7b6bfb354b5834cf1cc6d52dd972fb41b7b225437ae4a022066cb85647df65c6b87a54e416dcdcca778a776c36a9643d2b5dc793c9b29f4c18347304402202d4ce515cd9000ec37575972d70b8d24f73909fb7012e8ebd8c2066ef6fe187902202830b53e64ea565fecd0f398100691da6bb2a5cf9bb0d1926f1d71d05828a11e01008876a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a9148a486ff2e31d6158bf39e2608864d63fefd09d5b88ac6851b27568f7010000" }, + + { 3, + "3044022022c7e11595c53ee89a57ca76baf0aed730da035952d6ab3fe6459f5eff3b337a022075e10cc5f5fd724a35ce4087a5d03cd616698626c69814032132b50bb97dc615", + "3045022100b20cd63e0587d1711beaebda4730775c4ac8b8b2ec78fe18a0c44c3f168c25230220079abb7fc4924e2fca5950842e5b9e416735585026914570078c4ef62f286226", + "02000000000101104f394af4c4fad78337f95e3e9f802f4c0d86ab231853af09b285348561320005000000000100000001a00f0000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500473044022022c7e11595c53ee89a57ca76baf0aed730da035952d6ab3fe6459f5eff3b337a022075e10cc5f5fd724a35ce4087a5d03cd616698626c69814032132b50bb97dc61583483045022100b20cd63e0587d1711beaebda4730775c4ac8b8b2ec78fe18a0c44c3f168c25230220079abb7fc4924e2fca5950842e5b9e416735585026914570078c4ef62f286226012004040404040404040404040404040404040404040404040404040404040404048d76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a91418bc1a114ccf9c052d3d23e28d3b0a9d1227434288527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f801b175ac6851b2756800000000" } } ); // commitment tx with six outputs untrimmed (maximum feerate) @@ -7576,28 +8447,28 @@ mod tests { chan.holder_dust_limit_satoshis = 546; test_commitment!("304502210090b96a2498ce0c0f2fadbec2aab278fed54c1a7838df793ec4d2c78d96ec096202204fdd439c50f90d483baa7b68feeef4bd33bc277695405447bcd0bfb2ca34d7bc", - "3045022100ad9a9bbbb75d506ca3b716b336ee3cf975dd7834fcf129d7dd188146eb58a8b4022061a759ee417339f7fe2ea1e8deb83abb6a74db31a09b7648a932a639cda23e33", - "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8006d007000000000000220020403d394747cae42e98ff01734ad5c08f82ba123d3d9a620abda88989651e2ab5d007000000000000220020748eba944fedc8827f6b06bc44678f93c0f9e6078b35c6331ed31e75f8ce0c2db80b000000000000220020c20b5d1f8584fd90443e7b7b720136174fa4b9333c261d04dbbd012635c0f419a00f0000000000002200208c48d15160397c9731df9bc3b236656efb6665fbfe92b4a6878e88a499f741c4c0c62d0000000000160014cc1b07838e387deacd0e5232e1e8b49f4c29e48477956a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0400483045022100ad9a9bbbb75d506ca3b716b336ee3cf975dd7834fcf129d7dd188146eb58a8b4022061a759ee417339f7fe2ea1e8deb83abb6a74db31a09b7648a932a639cda23e330148304502210090b96a2498ce0c0f2fadbec2aab278fed54c1a7838df793ec4d2c78d96ec096202204fdd439c50f90d483baa7b68feeef4bd33bc277695405447bcd0bfb2ca34d7bc01475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", { - - { 0, - "3045022100f33513ee38abf1c582876f921f8fddc06acff48e04515532a32d3938de938ffd02203aa308a2c1863b7d6fdf53159a1465bf2e115c13152546cc5d74483ceaa7f699", - "3045022100a637902a5d4c9ba9e7c472a225337d5aac9e2e3f6744f76e237132e7619ba0400220035c60d784a031c0d9f6df66b7eab8726a5c25397399ee4aa960842059eb3f9d", - "02000000000101adbe717a63fb658add30ada1e6e12ed257637581898abe475c11d7bbcd65bd4d0000000000000000000175020000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100f33513ee38abf1c582876f921f8fddc06acff48e04515532a32d3938de938ffd02203aa308a2c1863b7d6fdf53159a1465bf2e115c13152546cc5d74483ceaa7f69901483045022100a637902a5d4c9ba9e7c472a225337d5aac9e2e3f6744f76e237132e7619ba0400220035c60d784a031c0d9f6df66b7eab8726a5c25397399ee4aa960842059eb3f9d01008576a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a914b43e1b38138a41b37f7cd9a1d274bc63e3a9b5d188ac6868f6010000" }, - - { 1, - "3045022100ce07682cf4b90093c22dc2d9ab2a77ad6803526b655ef857221cc96af5c9e0bf02200f501cee22e7a268af40b555d15a8237c9f36ad67ef1841daf9f6a0267b1e6df", - "3045022100e57e46234f8782d3ff7aa593b4f7446fb5316c842e693dc63ee324fd49f6a1c302204a2f7b44c48bd26e1554422afae13153eb94b29d3687b733d18930615fb2db61", - "02000000000101adbe717a63fb658add30ada1e6e12ed257637581898abe475c11d7bbcd65bd4d0100000000000000000122020000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100ce07682cf4b90093c22dc2d9ab2a77ad6803526b655ef857221cc96af5c9e0bf02200f501cee22e7a268af40b555d15a8237c9f36ad67ef1841daf9f6a0267b1e6df01483045022100e57e46234f8782d3ff7aa593b4f7446fb5316c842e693dc63ee324fd49f6a1c302204a2f7b44c48bd26e1554422afae13153eb94b29d3687b733d18930615fb2db61012001010101010101010101010101010101010101010101010101010101010101018a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a9144b6b2e5444c2639cc0fb7bcea5afba3f3cdce23988527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f501b175ac686800000000" }, - - { 2, - "3045022100e3e35492e55f82ec0bc2f317ffd7a486d1f7024330fe9743c3559fc39f32ef0c02203d1d4db651fc388a91d5ad8ecdd8e83673063bc8eefe27cfd8c189090e3a23e0", - "3044022068613fb1b98eb3aec7f44c5b115b12343c2f066c4277c82b5f873dfe68f37f50022028109b4650f3f528ca4bfe9a467aff2e3e43893b61b5159157119d5d95cf1c18", - "02000000000101adbe717a63fb658add30ada1e6e12ed257637581898abe475c11d7bbcd65bd4d020000000000000000015d060000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100e3e35492e55f82ec0bc2f317ffd7a486d1f7024330fe9743c3559fc39f32ef0c02203d1d4db651fc388a91d5ad8ecdd8e83673063bc8eefe27cfd8c189090e3a23e001473044022068613fb1b98eb3aec7f44c5b115b12343c2f066c4277c82b5f873dfe68f37f50022028109b4650f3f528ca4bfe9a467aff2e3e43893b61b5159157119d5d95cf1c1801008576a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a9148a486ff2e31d6158bf39e2608864d63fefd09d5b88ac6868f7010000" }, - - { 3, - "304402207475aeb0212ef9bf5130b60937817ad88c9a87976988ef1f323f026148cc4a850220739fea17ad3257dcad72e509c73eebe86bee30b178467b9fdab213d631b109df", - "3045022100d315522e09e7d53d2a659a79cb67fef56d6c4bddf3f46df6772d0d20a7beb7c8022070bcc17e288607b6a72be0bd83368bb6d53488db266c1cdb4d72214e4f02ac33", - "02000000000101adbe717a63fb658add30ada1e6e12ed257637581898abe475c11d7bbcd65bd4d03000000000000000001f2090000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e050047304402207475aeb0212ef9bf5130b60937817ad88c9a87976988ef1f323f026148cc4a850220739fea17ad3257dcad72e509c73eebe86bee30b178467b9fdab213d631b109df01483045022100d315522e09e7d53d2a659a79cb67fef56d6c4bddf3f46df6772d0d20a7beb7c8022070bcc17e288607b6a72be0bd83368bb6d53488db266c1cdb4d72214e4f02ac33012004040404040404040404040404040404040404040404040404040404040404048a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a91418bc1a114ccf9c052d3d23e28d3b0a9d1227434288527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f801b175ac686800000000" } + "3045022100ad9a9bbbb75d506ca3b716b336ee3cf975dd7834fcf129d7dd188146eb58a8b4022061a759ee417339f7fe2ea1e8deb83abb6a74db31a09b7648a932a639cda23e33", + "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8006d007000000000000220020403d394747cae42e98ff01734ad5c08f82ba123d3d9a620abda88989651e2ab5d007000000000000220020748eba944fedc8827f6b06bc44678f93c0f9e6078b35c6331ed31e75f8ce0c2db80b000000000000220020c20b5d1f8584fd90443e7b7b720136174fa4b9333c261d04dbbd012635c0f419a00f0000000000002200208c48d15160397c9731df9bc3b236656efb6665fbfe92b4a6878e88a499f741c4c0c62d0000000000160014cc1b07838e387deacd0e5232e1e8b49f4c29e48477956a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0400483045022100ad9a9bbbb75d506ca3b716b336ee3cf975dd7834fcf129d7dd188146eb58a8b4022061a759ee417339f7fe2ea1e8deb83abb6a74db31a09b7648a932a639cda23e330148304502210090b96a2498ce0c0f2fadbec2aab278fed54c1a7838df793ec4d2c78d96ec096202204fdd439c50f90d483baa7b68feeef4bd33bc277695405447bcd0bfb2ca34d7bc01475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", { + + { 0, + "3045022100f33513ee38abf1c582876f921f8fddc06acff48e04515532a32d3938de938ffd02203aa308a2c1863b7d6fdf53159a1465bf2e115c13152546cc5d74483ceaa7f699", + "3045022100a637902a5d4c9ba9e7c472a225337d5aac9e2e3f6744f76e237132e7619ba0400220035c60d784a031c0d9f6df66b7eab8726a5c25397399ee4aa960842059eb3f9d", + "02000000000101adbe717a63fb658add30ada1e6e12ed257637581898abe475c11d7bbcd65bd4d0000000000000000000175020000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100f33513ee38abf1c582876f921f8fddc06acff48e04515532a32d3938de938ffd02203aa308a2c1863b7d6fdf53159a1465bf2e115c13152546cc5d74483ceaa7f69901483045022100a637902a5d4c9ba9e7c472a225337d5aac9e2e3f6744f76e237132e7619ba0400220035c60d784a031c0d9f6df66b7eab8726a5c25397399ee4aa960842059eb3f9d01008576a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a914b43e1b38138a41b37f7cd9a1d274bc63e3a9b5d188ac6868f6010000" }, + + { 1, + "3045022100ce07682cf4b90093c22dc2d9ab2a77ad6803526b655ef857221cc96af5c9e0bf02200f501cee22e7a268af40b555d15a8237c9f36ad67ef1841daf9f6a0267b1e6df", + "3045022100e57e46234f8782d3ff7aa593b4f7446fb5316c842e693dc63ee324fd49f6a1c302204a2f7b44c48bd26e1554422afae13153eb94b29d3687b733d18930615fb2db61", + "02000000000101adbe717a63fb658add30ada1e6e12ed257637581898abe475c11d7bbcd65bd4d0100000000000000000122020000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100ce07682cf4b90093c22dc2d9ab2a77ad6803526b655ef857221cc96af5c9e0bf02200f501cee22e7a268af40b555d15a8237c9f36ad67ef1841daf9f6a0267b1e6df01483045022100e57e46234f8782d3ff7aa593b4f7446fb5316c842e693dc63ee324fd49f6a1c302204a2f7b44c48bd26e1554422afae13153eb94b29d3687b733d18930615fb2db61012001010101010101010101010101010101010101010101010101010101010101018a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a9144b6b2e5444c2639cc0fb7bcea5afba3f3cdce23988527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f501b175ac686800000000" }, + + { 2, + "3045022100e3e35492e55f82ec0bc2f317ffd7a486d1f7024330fe9743c3559fc39f32ef0c02203d1d4db651fc388a91d5ad8ecdd8e83673063bc8eefe27cfd8c189090e3a23e0", + "3044022068613fb1b98eb3aec7f44c5b115b12343c2f066c4277c82b5f873dfe68f37f50022028109b4650f3f528ca4bfe9a467aff2e3e43893b61b5159157119d5d95cf1c18", + "02000000000101adbe717a63fb658add30ada1e6e12ed257637581898abe475c11d7bbcd65bd4d020000000000000000015d060000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100e3e35492e55f82ec0bc2f317ffd7a486d1f7024330fe9743c3559fc39f32ef0c02203d1d4db651fc388a91d5ad8ecdd8e83673063bc8eefe27cfd8c189090e3a23e001473044022068613fb1b98eb3aec7f44c5b115b12343c2f066c4277c82b5f873dfe68f37f50022028109b4650f3f528ca4bfe9a467aff2e3e43893b61b5159157119d5d95cf1c1801008576a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a9148a486ff2e31d6158bf39e2608864d63fefd09d5b88ac6868f7010000" }, + + { 3, + "304402207475aeb0212ef9bf5130b60937817ad88c9a87976988ef1f323f026148cc4a850220739fea17ad3257dcad72e509c73eebe86bee30b178467b9fdab213d631b109df", + "3045022100d315522e09e7d53d2a659a79cb67fef56d6c4bddf3f46df6772d0d20a7beb7c8022070bcc17e288607b6a72be0bd83368bb6d53488db266c1cdb4d72214e4f02ac33", + "02000000000101adbe717a63fb658add30ada1e6e12ed257637581898abe475c11d7bbcd65bd4d03000000000000000001f2090000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e050047304402207475aeb0212ef9bf5130b60937817ad88c9a87976988ef1f323f026148cc4a850220739fea17ad3257dcad72e509c73eebe86bee30b178467b9fdab213d631b109df01483045022100d315522e09e7d53d2a659a79cb67fef56d6c4bddf3f46df6772d0d20a7beb7c8022070bcc17e288607b6a72be0bd83368bb6d53488db266c1cdb4d72214e4f02ac33012004040404040404040404040404040404040404040404040404040404040404048a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a91418bc1a114ccf9c052d3d23e28d3b0a9d1227434288527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f801b175ac686800000000" } } ); // commitment tx with five outputs untrimmed (minimum feerate) @@ -7605,23 +8476,23 @@ mod tests { chan.feerate_per_kw = 2070; test_commitment!("304402204ca1ba260dee913d318271d86e10ca0f5883026fb5653155cff600fb40895223022037b145204b7054a40e08bb1fefbd826f827b40838d3e501423bcc57924bcb50c", - "3044022001014419b5ba00e083ac4e0a85f19afc848aacac2d483b4b525d15e2ae5adbfe022015ebddad6ee1e72b47cb09f3e78459da5be01ccccd95dceca0e056a00cc773c1", - "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8005d007000000000000220020403d394747cae42e98ff01734ad5c08f82ba123d3d9a620abda88989651e2ab5b80b000000000000220020c20b5d1f8584fd90443e7b7b720136174fa4b9333c261d04dbbd012635c0f419a00f0000000000002200208c48d15160397c9731df9bc3b236656efb6665fbfe92b4a6878e88a499f741c4c0c62d0000000000160014cc1b07838e387deacd0e5232e1e8b49f4c29e484da966a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0400473044022001014419b5ba00e083ac4e0a85f19afc848aacac2d483b4b525d15e2ae5adbfe022015ebddad6ee1e72b47cb09f3e78459da5be01ccccd95dceca0e056a00cc773c10147304402204ca1ba260dee913d318271d86e10ca0f5883026fb5653155cff600fb40895223022037b145204b7054a40e08bb1fefbd826f827b40838d3e501423bcc57924bcb50c01475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", { - - { 0, - "304402205f6b6d12d8d2529fb24f4445630566cf4abbd0f9330ab6c2bdb94222d6a2a0c502202f556258ae6f05b193749e4c541dfcc13b525a5422f6291f073f15617ba8579b", - "30440220150b11069454da70caf2492ded9e0065c9a57f25ac2a4c52657b1d15b6c6ed85022068a38833b603c8892717206383611bad210f1cbb4b1f87ea29c6c65b9e1cb3e5", - "02000000000101403ad7602b43293497a3a2235a12ecefda4f3a1f1d06e49b1786d945685de1ff0000000000000000000174020000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e050047304402205f6b6d12d8d2529fb24f4445630566cf4abbd0f9330ab6c2bdb94222d6a2a0c502202f556258ae6f05b193749e4c541dfcc13b525a5422f6291f073f15617ba8579b014730440220150b11069454da70caf2492ded9e0065c9a57f25ac2a4c52657b1d15b6c6ed85022068a38833b603c8892717206383611bad210f1cbb4b1f87ea29c6c65b9e1cb3e501008576a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a914b43e1b38138a41b37f7cd9a1d274bc63e3a9b5d188ac6868f6010000" }, - - { 1, - "3045022100f960dfb1c9aee7ce1437efa65b523e399383e8149790e05d8fed27ff6e42fe0002202fe8613e062ffe0b0c518cc4101fba1c6de70f64a5bcc7ae663f2efae43b8546", - "30450221009a6ed18e6873bc3644332a6ee21c152a5b102821865350df7a8c74451a51f9f2022050d801fb4895d7d7fbf452824c0168347f5c0cbe821cf6a97a63af5b8b2563c6", - "02000000000101403ad7602b43293497a3a2235a12ecefda4f3a1f1d06e49b1786d945685de1ff010000000000000000015c060000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100f960dfb1c9aee7ce1437efa65b523e399383e8149790e05d8fed27ff6e42fe0002202fe8613e062ffe0b0c518cc4101fba1c6de70f64a5bcc7ae663f2efae43b8546014830450221009a6ed18e6873bc3644332a6ee21c152a5b102821865350df7a8c74451a51f9f2022050d801fb4895d7d7fbf452824c0168347f5c0cbe821cf6a97a63af5b8b2563c601008576a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a9148a486ff2e31d6158bf39e2608864d63fefd09d5b88ac6868f7010000" }, - - { 2, - "3045022100ae5fc7717ae684bc1fcf9020854e5dbe9842c9e7472879ac06ff95ac2bb10e4e022057728ada4c00083a3e65493fb5d50a232165948a1a0f530ef63185c2c8c56504", - "30440220408ad3009827a8fccf774cb285587686bfb2ed041f89a89453c311ce9c8ee0f902203c7392d9f8306d3a46522a66bd2723a7eb2628cb2d9b34d4c104f1766bf37502", - "02000000000101403ad7602b43293497a3a2235a12ecefda4f3a1f1d06e49b1786d945685de1ff02000000000000000001f1090000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100ae5fc7717ae684bc1fcf9020854e5dbe9842c9e7472879ac06ff95ac2bb10e4e022057728ada4c00083a3e65493fb5d50a232165948a1a0f530ef63185c2c8c56504014730440220408ad3009827a8fccf774cb285587686bfb2ed041f89a89453c311ce9c8ee0f902203c7392d9f8306d3a46522a66bd2723a7eb2628cb2d9b34d4c104f1766bf37502012004040404040404040404040404040404040404040404040404040404040404048a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a91418bc1a114ccf9c052d3d23e28d3b0a9d1227434288527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f801b175ac686800000000" } + "3044022001014419b5ba00e083ac4e0a85f19afc848aacac2d483b4b525d15e2ae5adbfe022015ebddad6ee1e72b47cb09f3e78459da5be01ccccd95dceca0e056a00cc773c1", + "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8005d007000000000000220020403d394747cae42e98ff01734ad5c08f82ba123d3d9a620abda88989651e2ab5b80b000000000000220020c20b5d1f8584fd90443e7b7b720136174fa4b9333c261d04dbbd012635c0f419a00f0000000000002200208c48d15160397c9731df9bc3b236656efb6665fbfe92b4a6878e88a499f741c4c0c62d0000000000160014cc1b07838e387deacd0e5232e1e8b49f4c29e484da966a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0400473044022001014419b5ba00e083ac4e0a85f19afc848aacac2d483b4b525d15e2ae5adbfe022015ebddad6ee1e72b47cb09f3e78459da5be01ccccd95dceca0e056a00cc773c10147304402204ca1ba260dee913d318271d86e10ca0f5883026fb5653155cff600fb40895223022037b145204b7054a40e08bb1fefbd826f827b40838d3e501423bcc57924bcb50c01475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", { + + { 0, + "304402205f6b6d12d8d2529fb24f4445630566cf4abbd0f9330ab6c2bdb94222d6a2a0c502202f556258ae6f05b193749e4c541dfcc13b525a5422f6291f073f15617ba8579b", + "30440220150b11069454da70caf2492ded9e0065c9a57f25ac2a4c52657b1d15b6c6ed85022068a38833b603c8892717206383611bad210f1cbb4b1f87ea29c6c65b9e1cb3e5", + "02000000000101403ad7602b43293497a3a2235a12ecefda4f3a1f1d06e49b1786d945685de1ff0000000000000000000174020000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e050047304402205f6b6d12d8d2529fb24f4445630566cf4abbd0f9330ab6c2bdb94222d6a2a0c502202f556258ae6f05b193749e4c541dfcc13b525a5422f6291f073f15617ba8579b014730440220150b11069454da70caf2492ded9e0065c9a57f25ac2a4c52657b1d15b6c6ed85022068a38833b603c8892717206383611bad210f1cbb4b1f87ea29c6c65b9e1cb3e501008576a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a914b43e1b38138a41b37f7cd9a1d274bc63e3a9b5d188ac6868f6010000" }, + + { 1, + "3045022100f960dfb1c9aee7ce1437efa65b523e399383e8149790e05d8fed27ff6e42fe0002202fe8613e062ffe0b0c518cc4101fba1c6de70f64a5bcc7ae663f2efae43b8546", + "30450221009a6ed18e6873bc3644332a6ee21c152a5b102821865350df7a8c74451a51f9f2022050d801fb4895d7d7fbf452824c0168347f5c0cbe821cf6a97a63af5b8b2563c6", + "02000000000101403ad7602b43293497a3a2235a12ecefda4f3a1f1d06e49b1786d945685de1ff010000000000000000015c060000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100f960dfb1c9aee7ce1437efa65b523e399383e8149790e05d8fed27ff6e42fe0002202fe8613e062ffe0b0c518cc4101fba1c6de70f64a5bcc7ae663f2efae43b8546014830450221009a6ed18e6873bc3644332a6ee21c152a5b102821865350df7a8c74451a51f9f2022050d801fb4895d7d7fbf452824c0168347f5c0cbe821cf6a97a63af5b8b2563c601008576a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a9148a486ff2e31d6158bf39e2608864d63fefd09d5b88ac6868f7010000" }, + + { 2, + "3045022100ae5fc7717ae684bc1fcf9020854e5dbe9842c9e7472879ac06ff95ac2bb10e4e022057728ada4c00083a3e65493fb5d50a232165948a1a0f530ef63185c2c8c56504", + "30440220408ad3009827a8fccf774cb285587686bfb2ed041f89a89453c311ce9c8ee0f902203c7392d9f8306d3a46522a66bd2723a7eb2628cb2d9b34d4c104f1766bf37502", + "02000000000101403ad7602b43293497a3a2235a12ecefda4f3a1f1d06e49b1786d945685de1ff02000000000000000001f1090000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100ae5fc7717ae684bc1fcf9020854e5dbe9842c9e7472879ac06ff95ac2bb10e4e022057728ada4c00083a3e65493fb5d50a232165948a1a0f530ef63185c2c8c56504014730440220408ad3009827a8fccf774cb285587686bfb2ed041f89a89453c311ce9c8ee0f902203c7392d9f8306d3a46522a66bd2723a7eb2628cb2d9b34d4c104f1766bf37502012004040404040404040404040404040404040404040404040404040404040404048a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a91418bc1a114ccf9c052d3d23e28d3b0a9d1227434288527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f801b175ac686800000000" } } ); // commitment tx with five outputs untrimmed (maximum feerate) @@ -7629,23 +8500,23 @@ mod tests { chan.feerate_per_kw = 2194; test_commitment!("304402204bb3d6e279d71d9da414c82de42f1f954267c762b2e2eb8b76bc3be4ea07d4b0022014febc009c5edc8c3fc5d94015de163200f780046f1c293bfed8568f08b70fb3", - "3044022072c2e2b1c899b2242656a537dde2892fa3801be0d6df0a87836c550137acde8302201654aa1974d37a829083c3ba15088689f30b56d6a4f6cb14c7bad0ee3116d398", - "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8005d007000000000000220020403d394747cae42e98ff01734ad5c08f82ba123d3d9a620abda88989651e2ab5b80b000000000000220020c20b5d1f8584fd90443e7b7b720136174fa4b9333c261d04dbbd012635c0f419a00f0000000000002200208c48d15160397c9731df9bc3b236656efb6665fbfe92b4a6878e88a499f741c4c0c62d0000000000160014cc1b07838e387deacd0e5232e1e8b49f4c29e48440966a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0400473044022072c2e2b1c899b2242656a537dde2892fa3801be0d6df0a87836c550137acde8302201654aa1974d37a829083c3ba15088689f30b56d6a4f6cb14c7bad0ee3116d3980147304402204bb3d6e279d71d9da414c82de42f1f954267c762b2e2eb8b76bc3be4ea07d4b0022014febc009c5edc8c3fc5d94015de163200f780046f1c293bfed8568f08b70fb301475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", { - - { 0, - "3045022100939726680351a7856c1bc386d4a1f422c7d29bd7b56afc139570f508474e6c40022023175a799ccf44c017fbaadb924c40b2a12115a5b7d0dfd3228df803a2de8450", - "304502210099c98c2edeeee6ec0fb5f3bea8b79bb016a2717afa9b5072370f34382de281d302206f5e2980a995e045cf90a547f0752a7ee99d48547bc135258fe7bc07e0154301", - "02000000000101153cd825fdb3aa624bfe513e8031d5d08c5e582fb3d1d1fe8faf27d3eed410cd0000000000000000000122020000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100939726680351a7856c1bc386d4a1f422c7d29bd7b56afc139570f508474e6c40022023175a799ccf44c017fbaadb924c40b2a12115a5b7d0dfd3228df803a2de84500148304502210099c98c2edeeee6ec0fb5f3bea8b79bb016a2717afa9b5072370f34382de281d302206f5e2980a995e045cf90a547f0752a7ee99d48547bc135258fe7bc07e015430101008576a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a914b43e1b38138a41b37f7cd9a1d274bc63e3a9b5d188ac6868f6010000" }, - - { 1, - "3044022021bb883bf324553d085ba2e821cad80c28ef8b303dbead8f98e548783c02d1600220638f9ef2a9bba25869afc923f4b5dc38be3bb459f9efa5d869392d5f7779a4a0", - "3045022100fd85bd7697b89c08ec12acc8ba89b23090637d83abd26ca37e01ae93e67c367302202b551fe69386116c47f984aab9c8dfd25d864dcde5d3389cfbef2447a85c4b77", - "02000000000101153cd825fdb3aa624bfe513e8031d5d08c5e582fb3d1d1fe8faf27d3eed410cd010000000000000000010a060000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500473044022021bb883bf324553d085ba2e821cad80c28ef8b303dbead8f98e548783c02d1600220638f9ef2a9bba25869afc923f4b5dc38be3bb459f9efa5d869392d5f7779a4a001483045022100fd85bd7697b89c08ec12acc8ba89b23090637d83abd26ca37e01ae93e67c367302202b551fe69386116c47f984aab9c8dfd25d864dcde5d3389cfbef2447a85c4b7701008576a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a9148a486ff2e31d6158bf39e2608864d63fefd09d5b88ac6868f7010000" }, - - { 2, - "3045022100c9e6f0454aa598b905a35e641a70cc9f67b5f38cc4b00843a041238c4a9f1c4a0220260a2822a62da97e44583e837245995ca2e36781769c52f19e498efbdcca262b", - "30450221008a9f2ea24cd455c2b64c1472a5fa83865b0a5f49a62b661801e884cf2849af8302204d44180e50bf6adfcf1c1e581d75af91aba4e28681ce4a5ee5f3cbf65eca10f3", - "02000000000101153cd825fdb3aa624bfe513e8031d5d08c5e582fb3d1d1fe8faf27d3eed410cd020000000000000000019a090000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100c9e6f0454aa598b905a35e641a70cc9f67b5f38cc4b00843a041238c4a9f1c4a0220260a2822a62da97e44583e837245995ca2e36781769c52f19e498efbdcca262b014830450221008a9f2ea24cd455c2b64c1472a5fa83865b0a5f49a62b661801e884cf2849af8302204d44180e50bf6adfcf1c1e581d75af91aba4e28681ce4a5ee5f3cbf65eca10f3012004040404040404040404040404040404040404040404040404040404040404048a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a91418bc1a114ccf9c052d3d23e28d3b0a9d1227434288527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f801b175ac686800000000" } + "3044022072c2e2b1c899b2242656a537dde2892fa3801be0d6df0a87836c550137acde8302201654aa1974d37a829083c3ba15088689f30b56d6a4f6cb14c7bad0ee3116d398", + "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8005d007000000000000220020403d394747cae42e98ff01734ad5c08f82ba123d3d9a620abda88989651e2ab5b80b000000000000220020c20b5d1f8584fd90443e7b7b720136174fa4b9333c261d04dbbd012635c0f419a00f0000000000002200208c48d15160397c9731df9bc3b236656efb6665fbfe92b4a6878e88a499f741c4c0c62d0000000000160014cc1b07838e387deacd0e5232e1e8b49f4c29e48440966a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0400473044022072c2e2b1c899b2242656a537dde2892fa3801be0d6df0a87836c550137acde8302201654aa1974d37a829083c3ba15088689f30b56d6a4f6cb14c7bad0ee3116d3980147304402204bb3d6e279d71d9da414c82de42f1f954267c762b2e2eb8b76bc3be4ea07d4b0022014febc009c5edc8c3fc5d94015de163200f780046f1c293bfed8568f08b70fb301475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", { + + { 0, + "3045022100939726680351a7856c1bc386d4a1f422c7d29bd7b56afc139570f508474e6c40022023175a799ccf44c017fbaadb924c40b2a12115a5b7d0dfd3228df803a2de8450", + "304502210099c98c2edeeee6ec0fb5f3bea8b79bb016a2717afa9b5072370f34382de281d302206f5e2980a995e045cf90a547f0752a7ee99d48547bc135258fe7bc07e0154301", + "02000000000101153cd825fdb3aa624bfe513e8031d5d08c5e582fb3d1d1fe8faf27d3eed410cd0000000000000000000122020000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100939726680351a7856c1bc386d4a1f422c7d29bd7b56afc139570f508474e6c40022023175a799ccf44c017fbaadb924c40b2a12115a5b7d0dfd3228df803a2de84500148304502210099c98c2edeeee6ec0fb5f3bea8b79bb016a2717afa9b5072370f34382de281d302206f5e2980a995e045cf90a547f0752a7ee99d48547bc135258fe7bc07e015430101008576a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a914b43e1b38138a41b37f7cd9a1d274bc63e3a9b5d188ac6868f6010000" }, + + { 1, + "3044022021bb883bf324553d085ba2e821cad80c28ef8b303dbead8f98e548783c02d1600220638f9ef2a9bba25869afc923f4b5dc38be3bb459f9efa5d869392d5f7779a4a0", + "3045022100fd85bd7697b89c08ec12acc8ba89b23090637d83abd26ca37e01ae93e67c367302202b551fe69386116c47f984aab9c8dfd25d864dcde5d3389cfbef2447a85c4b77", + "02000000000101153cd825fdb3aa624bfe513e8031d5d08c5e582fb3d1d1fe8faf27d3eed410cd010000000000000000010a060000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500473044022021bb883bf324553d085ba2e821cad80c28ef8b303dbead8f98e548783c02d1600220638f9ef2a9bba25869afc923f4b5dc38be3bb459f9efa5d869392d5f7779a4a001483045022100fd85bd7697b89c08ec12acc8ba89b23090637d83abd26ca37e01ae93e67c367302202b551fe69386116c47f984aab9c8dfd25d864dcde5d3389cfbef2447a85c4b7701008576a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a9148a486ff2e31d6158bf39e2608864d63fefd09d5b88ac6868f7010000" }, + + { 2, + "3045022100c9e6f0454aa598b905a35e641a70cc9f67b5f38cc4b00843a041238c4a9f1c4a0220260a2822a62da97e44583e837245995ca2e36781769c52f19e498efbdcca262b", + "30450221008a9f2ea24cd455c2b64c1472a5fa83865b0a5f49a62b661801e884cf2849af8302204d44180e50bf6adfcf1c1e581d75af91aba4e28681ce4a5ee5f3cbf65eca10f3", + "02000000000101153cd825fdb3aa624bfe513e8031d5d08c5e582fb3d1d1fe8faf27d3eed410cd020000000000000000019a090000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100c9e6f0454aa598b905a35e641a70cc9f67b5f38cc4b00843a041238c4a9f1c4a0220260a2822a62da97e44583e837245995ca2e36781769c52f19e498efbdcca262b014830450221008a9f2ea24cd455c2b64c1472a5fa83865b0a5f49a62b661801e884cf2849af8302204d44180e50bf6adfcf1c1e581d75af91aba4e28681ce4a5ee5f3cbf65eca10f3012004040404040404040404040404040404040404040404040404040404040404048a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a91418bc1a114ccf9c052d3d23e28d3b0a9d1227434288527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f801b175ac686800000000" } } ); // commitment tx with four outputs untrimmed (minimum feerate) @@ -7653,18 +8524,18 @@ mod tests { chan.feerate_per_kw = 2195; test_commitment!("304402201a8c1b1f9671cd9e46c7323a104d7047cc48d3ee80d40d4512e0c72b8dc65666022066d7f9a2ce18c9eb22d2739ffcce05721c767f9b607622a31b6ea5793ddce403", - "3044022044d592025b610c0d678f65032e87035cdfe89d1598c522cc32524ae8172417c30220749fef9d5b2ae8cdd91ece442ba8809bc891efedae2291e578475f97715d1767", - "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8004b80b000000000000220020c20b5d1f8584fd90443e7b7b720136174fa4b9333c261d04dbbd012635c0f419a00f0000000000002200208c48d15160397c9731df9bc3b236656efb6665fbfe92b4a6878e88a499f741c4c0c62d0000000000160014cc1b07838e387deacd0e5232e1e8b49f4c29e484b8976a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0400473044022044d592025b610c0d678f65032e87035cdfe89d1598c522cc32524ae8172417c30220749fef9d5b2ae8cdd91ece442ba8809bc891efedae2291e578475f97715d17670147304402201a8c1b1f9671cd9e46c7323a104d7047cc48d3ee80d40d4512e0c72b8dc65666022066d7f9a2ce18c9eb22d2739ffcce05721c767f9b607622a31b6ea5793ddce40301475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", { - - { 0, - "3045022100e57b845066a06ee7c2cbfc29eabffe52daa9bf6f6de760066d04df9f9b250e0002202ffb197f0e6e0a77a75a9aff27014bd3de83b7f748d7efef986abe655e1dd50e", - "3045022100ecc8c6529d0b2316d046f0f0757c1e1c25a636db168ec4f3aa1b9278df685dc0022067ae6b65e936f1337091f7b18a15935b608c5f2cdddb2f892ed0babfdd376d76", - "020000000001018130a10f09b13677ba2885a8bca32860f3a952e5912b829a473639b5a2c07b900000000000000000000109060000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100e57b845066a06ee7c2cbfc29eabffe52daa9bf6f6de760066d04df9f9b250e0002202ffb197f0e6e0a77a75a9aff27014bd3de83b7f748d7efef986abe655e1dd50e01483045022100ecc8c6529d0b2316d046f0f0757c1e1c25a636db168ec4f3aa1b9278df685dc0022067ae6b65e936f1337091f7b18a15935b608c5f2cdddb2f892ed0babfdd376d7601008576a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a9148a486ff2e31d6158bf39e2608864d63fefd09d5b88ac6868f7010000" }, - - { 1, - "3045022100d193b7ecccad8057571620a0b1ffa6c48e9483311723b59cf536043b20bc51550220546d4bd37b3b101ecda14f6c907af46ec391abce1cd9c7ce22b1a62b534f2f2a", - "3044022014d66f11f9cacf923807eba49542076c5fe5cccf252fb08fe98c78ef3ca6ab5402201b290dbe043cc512d9d78de074a5a129b8759bc6a6c546b190d120b690bd6e82", - "020000000001018130a10f09b13677ba2885a8bca32860f3a952e5912b829a473639b5a2c07b900100000000000000000199090000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100d193b7ecccad8057571620a0b1ffa6c48e9483311723b59cf536043b20bc51550220546d4bd37b3b101ecda14f6c907af46ec391abce1cd9c7ce22b1a62b534f2f2a01473044022014d66f11f9cacf923807eba49542076c5fe5cccf252fb08fe98c78ef3ca6ab5402201b290dbe043cc512d9d78de074a5a129b8759bc6a6c546b190d120b690bd6e82012004040404040404040404040404040404040404040404040404040404040404048a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a91418bc1a114ccf9c052d3d23e28d3b0a9d1227434288527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f801b175ac686800000000" } + "3044022044d592025b610c0d678f65032e87035cdfe89d1598c522cc32524ae8172417c30220749fef9d5b2ae8cdd91ece442ba8809bc891efedae2291e578475f97715d1767", + "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8004b80b000000000000220020c20b5d1f8584fd90443e7b7b720136174fa4b9333c261d04dbbd012635c0f419a00f0000000000002200208c48d15160397c9731df9bc3b236656efb6665fbfe92b4a6878e88a499f741c4c0c62d0000000000160014cc1b07838e387deacd0e5232e1e8b49f4c29e484b8976a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0400473044022044d592025b610c0d678f65032e87035cdfe89d1598c522cc32524ae8172417c30220749fef9d5b2ae8cdd91ece442ba8809bc891efedae2291e578475f97715d17670147304402201a8c1b1f9671cd9e46c7323a104d7047cc48d3ee80d40d4512e0c72b8dc65666022066d7f9a2ce18c9eb22d2739ffcce05721c767f9b607622a31b6ea5793ddce40301475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", { + + { 0, + "3045022100e57b845066a06ee7c2cbfc29eabffe52daa9bf6f6de760066d04df9f9b250e0002202ffb197f0e6e0a77a75a9aff27014bd3de83b7f748d7efef986abe655e1dd50e", + "3045022100ecc8c6529d0b2316d046f0f0757c1e1c25a636db168ec4f3aa1b9278df685dc0022067ae6b65e936f1337091f7b18a15935b608c5f2cdddb2f892ed0babfdd376d76", + "020000000001018130a10f09b13677ba2885a8bca32860f3a952e5912b829a473639b5a2c07b900000000000000000000109060000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100e57b845066a06ee7c2cbfc29eabffe52daa9bf6f6de760066d04df9f9b250e0002202ffb197f0e6e0a77a75a9aff27014bd3de83b7f748d7efef986abe655e1dd50e01483045022100ecc8c6529d0b2316d046f0f0757c1e1c25a636db168ec4f3aa1b9278df685dc0022067ae6b65e936f1337091f7b18a15935b608c5f2cdddb2f892ed0babfdd376d7601008576a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a9148a486ff2e31d6158bf39e2608864d63fefd09d5b88ac6868f7010000" }, + + { 1, + "3045022100d193b7ecccad8057571620a0b1ffa6c48e9483311723b59cf536043b20bc51550220546d4bd37b3b101ecda14f6c907af46ec391abce1cd9c7ce22b1a62b534f2f2a", + "3044022014d66f11f9cacf923807eba49542076c5fe5cccf252fb08fe98c78ef3ca6ab5402201b290dbe043cc512d9d78de074a5a129b8759bc6a6c546b190d120b690bd6e82", + "020000000001018130a10f09b13677ba2885a8bca32860f3a952e5912b829a473639b5a2c07b900100000000000000000199090000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100d193b7ecccad8057571620a0b1ffa6c48e9483311723b59cf536043b20bc51550220546d4bd37b3b101ecda14f6c907af46ec391abce1cd9c7ce22b1a62b534f2f2a01473044022014d66f11f9cacf923807eba49542076c5fe5cccf252fb08fe98c78ef3ca6ab5402201b290dbe043cc512d9d78de074a5a129b8759bc6a6c546b190d120b690bd6e82012004040404040404040404040404040404040404040404040404040404040404048a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a91418bc1a114ccf9c052d3d23e28d3b0a9d1227434288527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f801b175ac686800000000" } } ); // anchors: commitment tx with four outputs untrimmed (minimum dust limit) @@ -7673,18 +8544,18 @@ mod tests { chan.holder_dust_limit_satoshis = 2001; test_commitment_with_anchors!("3044022040f63a16148cf35c8d3d41827f5ae7f7c3746885bb64d4d1b895892a83812b3e02202fcf95c2bf02c466163b3fa3ced6a24926fbb4035095a96842ef516e86ba54c0", - "3045022100cd8479cfe1edb1e5a1d487391e0451a469c7171e51e680183f19eb4321f20e9b02204eab7d5a6384b1b08e03baa6e4d9748dfd2b5ab2bae7e39604a0d0055bbffdd5", - "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b80064a010000000000002200202b1b5854183c12d3316565972c4668929d314d81c5dcdbb21cb45fe8a9a8114f4a01000000000000220020e9e86e4823faa62e222ebc858a226636856158f07e69898da3b0d1af0ddb3994b80b000000000000220020f96d0334feb64a4f40eb272031d07afcb038db56aa57446d60308c9f8ccadef9a00f000000000000220020ce6e751274836ff59622a0d1e07f8831d80bd6730bd48581398bfadd2bb8da9ac0c62d0000000000220020f3394e1e619b0eca1f91be2fb5ab4dfc59ba5b84ebe014ad1d43a564d012994ac5916a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0400483045022100cd8479cfe1edb1e5a1d487391e0451a469c7171e51e680183f19eb4321f20e9b02204eab7d5a6384b1b08e03baa6e4d9748dfd2b5ab2bae7e39604a0d0055bbffdd501473044022040f63a16148cf35c8d3d41827f5ae7f7c3746885bb64d4d1b895892a83812b3e02202fcf95c2bf02c466163b3fa3ced6a24926fbb4035095a96842ef516e86ba54c001475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", { - - { 0, - "304402206870514a72ad6e723ff7f1e0370d7a33c1cd2a0b9272674143ebaf6a1d02dee102205bd953c34faf5e7322e9a1c0103581cb090280fda4f1039ee8552668afa90ebb", - "30440220669de9ca7910eff65a7773ebd14a9fc371fe88cde5b8e2a81609d85c87ac939b02201ac29472fa4067322e92d75b624942d60be5050139b20bb363db75be79eb946f", - "02000000000101ac13a7715f80b8e52dda43c6929cade5521bdced3a405da02b443f1ffb1e33cc02000000000100000001b80b0000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e050047304402206870514a72ad6e723ff7f1e0370d7a33c1cd2a0b9272674143ebaf6a1d02dee102205bd953c34faf5e7322e9a1c0103581cb090280fda4f1039ee8552668afa90ebb834730440220669de9ca7910eff65a7773ebd14a9fc371fe88cde5b8e2a81609d85c87ac939b02201ac29472fa4067322e92d75b624942d60be5050139b20bb363db75be79eb946f01008876a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a9148a486ff2e31d6158bf39e2608864d63fefd09d5b88ac6851b27568f7010000" }, - - { 1, - "3045022100949e8dd938da56445b1cdfdebe1b7efea086edd05d89910d205a1e2e033ce47102202cbd68b5262ab144d9ec12653f87dfb0bb6bd05d1f58ae1e523f028eaefd7271", - "3045022100e3104ed8b239f8019e5f0a1a73d7782a94a8c36e7984f476c3a0b3cb0e62e27902207e3d52884600985f8a2098e53a5c30dd6a5e857733acfaa07ab2162421ed2688", - "02000000000101ac13a7715f80b8e52dda43c6929cade5521bdced3a405da02b443f1ffb1e33cc03000000000100000001a00f0000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100949e8dd938da56445b1cdfdebe1b7efea086edd05d89910d205a1e2e033ce47102202cbd68b5262ab144d9ec12653f87dfb0bb6bd05d1f58ae1e523f028eaefd727183483045022100e3104ed8b239f8019e5f0a1a73d7782a94a8c36e7984f476c3a0b3cb0e62e27902207e3d52884600985f8a2098e53a5c30dd6a5e857733acfaa07ab2162421ed2688012004040404040404040404040404040404040404040404040404040404040404048d76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a91418bc1a114ccf9c052d3d23e28d3b0a9d1227434288527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f801b175ac6851b2756800000000" } + "3045022100cd8479cfe1edb1e5a1d487391e0451a469c7171e51e680183f19eb4321f20e9b02204eab7d5a6384b1b08e03baa6e4d9748dfd2b5ab2bae7e39604a0d0055bbffdd5", + "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b80064a010000000000002200202b1b5854183c12d3316565972c4668929d314d81c5dcdbb21cb45fe8a9a8114f4a01000000000000220020e9e86e4823faa62e222ebc858a226636856158f07e69898da3b0d1af0ddb3994b80b000000000000220020f96d0334feb64a4f40eb272031d07afcb038db56aa57446d60308c9f8ccadef9a00f000000000000220020ce6e751274836ff59622a0d1e07f8831d80bd6730bd48581398bfadd2bb8da9ac0c62d0000000000220020f3394e1e619b0eca1f91be2fb5ab4dfc59ba5b84ebe014ad1d43a564d012994ac5916a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0400483045022100cd8479cfe1edb1e5a1d487391e0451a469c7171e51e680183f19eb4321f20e9b02204eab7d5a6384b1b08e03baa6e4d9748dfd2b5ab2bae7e39604a0d0055bbffdd501473044022040f63a16148cf35c8d3d41827f5ae7f7c3746885bb64d4d1b895892a83812b3e02202fcf95c2bf02c466163b3fa3ced6a24926fbb4035095a96842ef516e86ba54c001475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", { + + { 0, + "304402206870514a72ad6e723ff7f1e0370d7a33c1cd2a0b9272674143ebaf6a1d02dee102205bd953c34faf5e7322e9a1c0103581cb090280fda4f1039ee8552668afa90ebb", + "30440220669de9ca7910eff65a7773ebd14a9fc371fe88cde5b8e2a81609d85c87ac939b02201ac29472fa4067322e92d75b624942d60be5050139b20bb363db75be79eb946f", + "02000000000101ac13a7715f80b8e52dda43c6929cade5521bdced3a405da02b443f1ffb1e33cc02000000000100000001b80b0000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e050047304402206870514a72ad6e723ff7f1e0370d7a33c1cd2a0b9272674143ebaf6a1d02dee102205bd953c34faf5e7322e9a1c0103581cb090280fda4f1039ee8552668afa90ebb834730440220669de9ca7910eff65a7773ebd14a9fc371fe88cde5b8e2a81609d85c87ac939b02201ac29472fa4067322e92d75b624942d60be5050139b20bb363db75be79eb946f01008876a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a9148a486ff2e31d6158bf39e2608864d63fefd09d5b88ac6851b27568f7010000" }, + + { 1, + "3045022100949e8dd938da56445b1cdfdebe1b7efea086edd05d89910d205a1e2e033ce47102202cbd68b5262ab144d9ec12653f87dfb0bb6bd05d1f58ae1e523f028eaefd7271", + "3045022100e3104ed8b239f8019e5f0a1a73d7782a94a8c36e7984f476c3a0b3cb0e62e27902207e3d52884600985f8a2098e53a5c30dd6a5e857733acfaa07ab2162421ed2688", + "02000000000101ac13a7715f80b8e52dda43c6929cade5521bdced3a405da02b443f1ffb1e33cc03000000000100000001a00f0000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100949e8dd938da56445b1cdfdebe1b7efea086edd05d89910d205a1e2e033ce47102202cbd68b5262ab144d9ec12653f87dfb0bb6bd05d1f58ae1e523f028eaefd727183483045022100e3104ed8b239f8019e5f0a1a73d7782a94a8c36e7984f476c3a0b3cb0e62e27902207e3d52884600985f8a2098e53a5c30dd6a5e857733acfaa07ab2162421ed2688012004040404040404040404040404040404040404040404040404040404040404048d76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a91418bc1a114ccf9c052d3d23e28d3b0a9d1227434288527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f801b175ac6851b2756800000000" } } ); // commitment tx with four outputs untrimmed (maximum feerate) @@ -7693,18 +8564,18 @@ mod tests { chan.holder_dust_limit_satoshis = 546; test_commitment!("304502210092a587aeb777f869e7ff0d7898ea619ee26a3dacd1f3672b945eea600be431100220077ee9eae3528d15251f2a52b607b189820e57a6ccfac8d1af502b132ee40169", - "3045022100e5efb73c32d32da2d79702299b6317de6fb24a60476e3855926d78484dd1b3c802203557cb66a42c944ef06e00bcc4da35a5bcb2f185aab0f8e403e519e1d66aaf75", - "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8004b80b000000000000220020c20b5d1f8584fd90443e7b7b720136174fa4b9333c261d04dbbd012635c0f419a00f0000000000002200208c48d15160397c9731df9bc3b236656efb6665fbfe92b4a6878e88a499f741c4c0c62d0000000000160014cc1b07838e387deacd0e5232e1e8b49f4c29e4846f916a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0400483045022100e5efb73c32d32da2d79702299b6317de6fb24a60476e3855926d78484dd1b3c802203557cb66a42c944ef06e00bcc4da35a5bcb2f185aab0f8e403e519e1d66aaf750148304502210092a587aeb777f869e7ff0d7898ea619ee26a3dacd1f3672b945eea600be431100220077ee9eae3528d15251f2a52b607b189820e57a6ccfac8d1af502b132ee4016901475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", { - - { 0, - "304402206fa54c11f98c3bae1e93df43fc7affeb05b476bf8060c03e29c377c69bc08e8b0220672701cce50d5c379ff45a5d2cfe48ac44973adb066ac32608e21221d869bb89", - "304402206e36c683ebf2cb16bcef3d5439cf8b53cd97280a365ed8acd7abb85a8ba5f21c02206e8621edfc2a5766cbc96eb67fd501127ff163eb6b85518a39f7d4974aef126f", - "020000000001018db483bff65c70ee71d8282aeec5a880e2e2b39e45772bda5460403095c62e3f0000000000000000000122020000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e050047304402206fa54c11f98c3bae1e93df43fc7affeb05b476bf8060c03e29c377c69bc08e8b0220672701cce50d5c379ff45a5d2cfe48ac44973adb066ac32608e21221d869bb890147304402206e36c683ebf2cb16bcef3d5439cf8b53cd97280a365ed8acd7abb85a8ba5f21c02206e8621edfc2a5766cbc96eb67fd501127ff163eb6b85518a39f7d4974aef126f01008576a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a9148a486ff2e31d6158bf39e2608864d63fefd09d5b88ac6868f7010000" }, - - { 1, - "3044022057649739b0eb74d541ead0dfdb3d4b2c15aa192720031044c3434c67812e5ca902201e5ede42d960ae551707f4a6b34b09393cf4dee2418507daa022e3550dbb5817", - "304402207faad26678c8850e01b4a0696d60841f7305e1832b786110ee9075cb92ed14a30220516ef8ee5dfa80824ea28cbcec0dd95f8b847146257c16960db98507db15ffdc", - "020000000001018db483bff65c70ee71d8282aeec5a880e2e2b39e45772bda5460403095c62e3f0100000000000000000176050000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500473044022057649739b0eb74d541ead0dfdb3d4b2c15aa192720031044c3434c67812e5ca902201e5ede42d960ae551707f4a6b34b09393cf4dee2418507daa022e3550dbb58170147304402207faad26678c8850e01b4a0696d60841f7305e1832b786110ee9075cb92ed14a30220516ef8ee5dfa80824ea28cbcec0dd95f8b847146257c16960db98507db15ffdc012004040404040404040404040404040404040404040404040404040404040404048a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a91418bc1a114ccf9c052d3d23e28d3b0a9d1227434288527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f801b175ac686800000000" } + "3045022100e5efb73c32d32da2d79702299b6317de6fb24a60476e3855926d78484dd1b3c802203557cb66a42c944ef06e00bcc4da35a5bcb2f185aab0f8e403e519e1d66aaf75", + "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8004b80b000000000000220020c20b5d1f8584fd90443e7b7b720136174fa4b9333c261d04dbbd012635c0f419a00f0000000000002200208c48d15160397c9731df9bc3b236656efb6665fbfe92b4a6878e88a499f741c4c0c62d0000000000160014cc1b07838e387deacd0e5232e1e8b49f4c29e4846f916a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0400483045022100e5efb73c32d32da2d79702299b6317de6fb24a60476e3855926d78484dd1b3c802203557cb66a42c944ef06e00bcc4da35a5bcb2f185aab0f8e403e519e1d66aaf750148304502210092a587aeb777f869e7ff0d7898ea619ee26a3dacd1f3672b945eea600be431100220077ee9eae3528d15251f2a52b607b189820e57a6ccfac8d1af502b132ee4016901475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", { + + { 0, + "304402206fa54c11f98c3bae1e93df43fc7affeb05b476bf8060c03e29c377c69bc08e8b0220672701cce50d5c379ff45a5d2cfe48ac44973adb066ac32608e21221d869bb89", + "304402206e36c683ebf2cb16bcef3d5439cf8b53cd97280a365ed8acd7abb85a8ba5f21c02206e8621edfc2a5766cbc96eb67fd501127ff163eb6b85518a39f7d4974aef126f", + "020000000001018db483bff65c70ee71d8282aeec5a880e2e2b39e45772bda5460403095c62e3f0000000000000000000122020000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e050047304402206fa54c11f98c3bae1e93df43fc7affeb05b476bf8060c03e29c377c69bc08e8b0220672701cce50d5c379ff45a5d2cfe48ac44973adb066ac32608e21221d869bb890147304402206e36c683ebf2cb16bcef3d5439cf8b53cd97280a365ed8acd7abb85a8ba5f21c02206e8621edfc2a5766cbc96eb67fd501127ff163eb6b85518a39f7d4974aef126f01008576a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a9148a486ff2e31d6158bf39e2608864d63fefd09d5b88ac6868f7010000" }, + + { 1, + "3044022057649739b0eb74d541ead0dfdb3d4b2c15aa192720031044c3434c67812e5ca902201e5ede42d960ae551707f4a6b34b09393cf4dee2418507daa022e3550dbb5817", + "304402207faad26678c8850e01b4a0696d60841f7305e1832b786110ee9075cb92ed14a30220516ef8ee5dfa80824ea28cbcec0dd95f8b847146257c16960db98507db15ffdc", + "020000000001018db483bff65c70ee71d8282aeec5a880e2e2b39e45772bda5460403095c62e3f0100000000000000000176050000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500473044022057649739b0eb74d541ead0dfdb3d4b2c15aa192720031044c3434c67812e5ca902201e5ede42d960ae551707f4a6b34b09393cf4dee2418507daa022e3550dbb58170147304402207faad26678c8850e01b4a0696d60841f7305e1832b786110ee9075cb92ed14a30220516ef8ee5dfa80824ea28cbcec0dd95f8b847146257c16960db98507db15ffdc012004040404040404040404040404040404040404040404040404040404040404048a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a91418bc1a114ccf9c052d3d23e28d3b0a9d1227434288527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f801b175ac686800000000" } } ); // commitment tx with three outputs untrimmed (minimum feerate) @@ -7712,13 +8583,13 @@ mod tests { chan.feerate_per_kw = 3703; test_commitment!("3045022100b495d239772a237ff2cf354b1b11be152fd852704cb184e7356d13f2fb1e5e430220723db5cdb9cbd6ead7bfd3deb419cf41053a932418cbb22a67b581f40bc1f13e", - "304402201b736d1773a124c745586217a75bed5f66c05716fbe8c7db4fdb3c3069741cdd02205083f39c321c1bcadfc8d97e3c791a66273d936abac0c6a2fde2ed46019508e1", - "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8003a00f0000000000002200208c48d15160397c9731df9bc3b236656efb6665fbfe92b4a6878e88a499f741c4c0c62d0000000000160014cc1b07838e387deacd0e5232e1e8b49f4c29e484eb936a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e040047304402201b736d1773a124c745586217a75bed5f66c05716fbe8c7db4fdb3c3069741cdd02205083f39c321c1bcadfc8d97e3c791a66273d936abac0c6a2fde2ed46019508e101483045022100b495d239772a237ff2cf354b1b11be152fd852704cb184e7356d13f2fb1e5e430220723db5cdb9cbd6ead7bfd3deb419cf41053a932418cbb22a67b581f40bc1f13e01475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", { + "304402201b736d1773a124c745586217a75bed5f66c05716fbe8c7db4fdb3c3069741cdd02205083f39c321c1bcadfc8d97e3c791a66273d936abac0c6a2fde2ed46019508e1", + "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8003a00f0000000000002200208c48d15160397c9731df9bc3b236656efb6665fbfe92b4a6878e88a499f741c4c0c62d0000000000160014cc1b07838e387deacd0e5232e1e8b49f4c29e484eb936a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e040047304402201b736d1773a124c745586217a75bed5f66c05716fbe8c7db4fdb3c3069741cdd02205083f39c321c1bcadfc8d97e3c791a66273d936abac0c6a2fde2ed46019508e101483045022100b495d239772a237ff2cf354b1b11be152fd852704cb184e7356d13f2fb1e5e430220723db5cdb9cbd6ead7bfd3deb419cf41053a932418cbb22a67b581f40bc1f13e01475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", { - { 0, - "3045022100c34c61735f93f2e324cc873c3b248111ccf8f6db15d5969583757010d4ad2b4602207867bb919b2ddd6387873e425345c9b7fd18d1d66aba41f3607bc2896ef3c30a", - "3045022100988c143e2110067117d2321bdd4bd16ca1734c98b29290d129384af0962b634e02206c1b02478878c5f547018b833986578f90c3e9be669fe5788ad0072a55acbb05", - "0200000000010120060e4a29579d429f0f27c17ee5f1ee282f20d706d6f90b63d35946d8f3029a0000000000000000000175050000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100c34c61735f93f2e324cc873c3b248111ccf8f6db15d5969583757010d4ad2b4602207867bb919b2ddd6387873e425345c9b7fd18d1d66aba41f3607bc2896ef3c30a01483045022100988c143e2110067117d2321bdd4bd16ca1734c98b29290d129384af0962b634e02206c1b02478878c5f547018b833986578f90c3e9be669fe5788ad0072a55acbb05012004040404040404040404040404040404040404040404040404040404040404048a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a91418bc1a114ccf9c052d3d23e28d3b0a9d1227434288527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f801b175ac686800000000" } + { 0, + "3045022100c34c61735f93f2e324cc873c3b248111ccf8f6db15d5969583757010d4ad2b4602207867bb919b2ddd6387873e425345c9b7fd18d1d66aba41f3607bc2896ef3c30a", + "3045022100988c143e2110067117d2321bdd4bd16ca1734c98b29290d129384af0962b634e02206c1b02478878c5f547018b833986578f90c3e9be669fe5788ad0072a55acbb05", + "0200000000010120060e4a29579d429f0f27c17ee5f1ee282f20d706d6f90b63d35946d8f3029a0000000000000000000175050000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100c34c61735f93f2e324cc873c3b248111ccf8f6db15d5969583757010d4ad2b4602207867bb919b2ddd6387873e425345c9b7fd18d1d66aba41f3607bc2896ef3c30a01483045022100988c143e2110067117d2321bdd4bd16ca1734c98b29290d129384af0962b634e02206c1b02478878c5f547018b833986578f90c3e9be669fe5788ad0072a55acbb05012004040404040404040404040404040404040404040404040404040404040404048a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a91418bc1a114ccf9c052d3d23e28d3b0a9d1227434288527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f801b175ac686800000000" } } ); // anchors: commitment tx with three outputs untrimmed (minimum dust limit) @@ -7727,13 +8598,13 @@ mod tests { chan.holder_dust_limit_satoshis = 3001; test_commitment_with_anchors!("3045022100ad6c71569856b2d7ff42e838b4abe74a713426b37f22fa667a195a4c88908c6902202b37272b02a42dc6d9f4f82cab3eaf84ac882d9ed762859e1e75455c2c228377", - "3045022100c970799bcb33f43179eb43b3378a0a61991cf2923f69b36ef12548c3df0e6d500220413dc27d2e39ee583093adfcb7799be680141738babb31cc7b0669a777a31f5d", - "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b80054a010000000000002200202b1b5854183c12d3316565972c4668929d314d81c5dcdbb21cb45fe8a9a8114f4a01000000000000220020e9e86e4823faa62e222ebc858a226636856158f07e69898da3b0d1af0ddb3994a00f000000000000220020ce6e751274836ff59622a0d1e07f8831d80bd6730bd48581398bfadd2bb8da9ac0c62d0000000000220020f3394e1e619b0eca1f91be2fb5ab4dfc59ba5b84ebe014ad1d43a564d012994aa28b6a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0400483045022100c970799bcb33f43179eb43b3378a0a61991cf2923f69b36ef12548c3df0e6d500220413dc27d2e39ee583093adfcb7799be680141738babb31cc7b0669a777a31f5d01483045022100ad6c71569856b2d7ff42e838b4abe74a713426b37f22fa667a195a4c88908c6902202b37272b02a42dc6d9f4f82cab3eaf84ac882d9ed762859e1e75455c2c22837701475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", { + "3045022100c970799bcb33f43179eb43b3378a0a61991cf2923f69b36ef12548c3df0e6d500220413dc27d2e39ee583093adfcb7799be680141738babb31cc7b0669a777a31f5d", + "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b80054a010000000000002200202b1b5854183c12d3316565972c4668929d314d81c5dcdbb21cb45fe8a9a8114f4a01000000000000220020e9e86e4823faa62e222ebc858a226636856158f07e69898da3b0d1af0ddb3994a00f000000000000220020ce6e751274836ff59622a0d1e07f8831d80bd6730bd48581398bfadd2bb8da9ac0c62d0000000000220020f3394e1e619b0eca1f91be2fb5ab4dfc59ba5b84ebe014ad1d43a564d012994aa28b6a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0400483045022100c970799bcb33f43179eb43b3378a0a61991cf2923f69b36ef12548c3df0e6d500220413dc27d2e39ee583093adfcb7799be680141738babb31cc7b0669a777a31f5d01483045022100ad6c71569856b2d7ff42e838b4abe74a713426b37f22fa667a195a4c88908c6902202b37272b02a42dc6d9f4f82cab3eaf84ac882d9ed762859e1e75455c2c22837701475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", { - { 0, - "3044022017b558a3cf5f0cb94269e2e927b29ed22bd2416abb8a7ce6de4d1256f359b93602202e9ca2b1a23ea3e69f433c704e327739e219804b8c188b1d52f74fd5a9de954c", - "3045022100af7a8b7c7ff2080c68995254cb66d64d9954edcc5baac3bb4f27ed2d29aaa6120220421c27da7a60574a9263f271e0f3bd34594ec6011095190022b3b54596ea03de", - "02000000000101542562b326c08e3a076d9cfca2be175041366591da334d8d513ff1686fd95a6002000000000100000001a00f0000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500473044022017b558a3cf5f0cb94269e2e927b29ed22bd2416abb8a7ce6de4d1256f359b93602202e9ca2b1a23ea3e69f433c704e327739e219804b8c188b1d52f74fd5a9de954c83483045022100af7a8b7c7ff2080c68995254cb66d64d9954edcc5baac3bb4f27ed2d29aaa6120220421c27da7a60574a9263f271e0f3bd34594ec6011095190022b3b54596ea03de012004040404040404040404040404040404040404040404040404040404040404048d76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a91418bc1a114ccf9c052d3d23e28d3b0a9d1227434288527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f801b175ac6851b2756800000000" } + { 0, + "3044022017b558a3cf5f0cb94269e2e927b29ed22bd2416abb8a7ce6de4d1256f359b93602202e9ca2b1a23ea3e69f433c704e327739e219804b8c188b1d52f74fd5a9de954c", + "3045022100af7a8b7c7ff2080c68995254cb66d64d9954edcc5baac3bb4f27ed2d29aaa6120220421c27da7a60574a9263f271e0f3bd34594ec6011095190022b3b54596ea03de", + "02000000000101542562b326c08e3a076d9cfca2be175041366591da334d8d513ff1686fd95a6002000000000100000001a00f0000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500473044022017b558a3cf5f0cb94269e2e927b29ed22bd2416abb8a7ce6de4d1256f359b93602202e9ca2b1a23ea3e69f433c704e327739e219804b8c188b1d52f74fd5a9de954c83483045022100af7a8b7c7ff2080c68995254cb66d64d9954edcc5baac3bb4f27ed2d29aaa6120220421c27da7a60574a9263f271e0f3bd34594ec6011095190022b3b54596ea03de012004040404040404040404040404040404040404040404040404040404040404048d76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a91418bc1a114ccf9c052d3d23e28d3b0a9d1227434288527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f801b175ac6851b2756800000000" } } ); // commitment tx with three outputs untrimmed (maximum feerate) @@ -7742,13 +8613,13 @@ mod tests { chan.holder_dust_limit_satoshis = 546; test_commitment!("3045022100b4b16d5f8cc9fc4c1aff48831e832a0d8990e133978a66e302c133550954a44d022073573ce127e2200d316f6b612803a5c0c97b8d20e1e44dbe2ac0dd2fb8c95244", - "3045022100d72638bc6308b88bb6d45861aae83e5b9ff6e10986546e13bce769c70036e2620220320be7c6d66d22f30b9fcd52af66531505b1310ca3b848c19285b38d8a1a8c19", - "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8003a00f0000000000002200208c48d15160397c9731df9bc3b236656efb6665fbfe92b4a6878e88a499f741c4c0c62d0000000000160014cc1b07838e387deacd0e5232e1e8b49f4c29e484ae8f6a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0400483045022100d72638bc6308b88bb6d45861aae83e5b9ff6e10986546e13bce769c70036e2620220320be7c6d66d22f30b9fcd52af66531505b1310ca3b848c19285b38d8a1a8c1901483045022100b4b16d5f8cc9fc4c1aff48831e832a0d8990e133978a66e302c133550954a44d022073573ce127e2200d316f6b612803a5c0c97b8d20e1e44dbe2ac0dd2fb8c9524401475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", { + "3045022100d72638bc6308b88bb6d45861aae83e5b9ff6e10986546e13bce769c70036e2620220320be7c6d66d22f30b9fcd52af66531505b1310ca3b848c19285b38d8a1a8c19", + "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8003a00f0000000000002200208c48d15160397c9731df9bc3b236656efb6665fbfe92b4a6878e88a499f741c4c0c62d0000000000160014cc1b07838e387deacd0e5232e1e8b49f4c29e484ae8f6a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0400483045022100d72638bc6308b88bb6d45861aae83e5b9ff6e10986546e13bce769c70036e2620220320be7c6d66d22f30b9fcd52af66531505b1310ca3b848c19285b38d8a1a8c1901483045022100b4b16d5f8cc9fc4c1aff48831e832a0d8990e133978a66e302c133550954a44d022073573ce127e2200d316f6b612803a5c0c97b8d20e1e44dbe2ac0dd2fb8c9524401475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", { - { 0, - "3045022100f43591c156038ba217756006bb3c55f7d113a325cdd7d9303c82115372858d68022016355b5aadf222bc8d12e426c75f4a03423917b2443a103eb2a498a3a2234374", - "30440220585dee80fafa264beac535c3c0bb5838ac348b156fdc982f86adc08dfc9bfd250220130abb82f9f295cc9ef423dcfef772fde2acd85d9df48cc538981d26a10a9c10", - "02000000000101a9172908eace869cc35128c31fc2ab502f72e4dff31aab23e0244c4b04b11ab00000000000000000000122020000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100f43591c156038ba217756006bb3c55f7d113a325cdd7d9303c82115372858d68022016355b5aadf222bc8d12e426c75f4a03423917b2443a103eb2a498a3a2234374014730440220585dee80fafa264beac535c3c0bb5838ac348b156fdc982f86adc08dfc9bfd250220130abb82f9f295cc9ef423dcfef772fde2acd85d9df48cc538981d26a10a9c10012004040404040404040404040404040404040404040404040404040404040404048a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a91418bc1a114ccf9c052d3d23e28d3b0a9d1227434288527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f801b175ac686800000000" } + { 0, + "3045022100f43591c156038ba217756006bb3c55f7d113a325cdd7d9303c82115372858d68022016355b5aadf222bc8d12e426c75f4a03423917b2443a103eb2a498a3a2234374", + "30440220585dee80fafa264beac535c3c0bb5838ac348b156fdc982f86adc08dfc9bfd250220130abb82f9f295cc9ef423dcfef772fde2acd85d9df48cc538981d26a10a9c10", + "02000000000101a9172908eace869cc35128c31fc2ab502f72e4dff31aab23e0244c4b04b11ab00000000000000000000122020000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100f43591c156038ba217756006bb3c55f7d113a325cdd7d9303c82115372858d68022016355b5aadf222bc8d12e426c75f4a03423917b2443a103eb2a498a3a2234374014730440220585dee80fafa264beac535c3c0bb5838ac348b156fdc982f86adc08dfc9bfd250220130abb82f9f295cc9ef423dcfef772fde2acd85d9df48cc538981d26a10a9c10012004040404040404040404040404040404040404040404040404040404040404048a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a91418bc1a114ccf9c052d3d23e28d3b0a9d1227434288527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f801b175ac686800000000" } } ); // commitment tx with two outputs untrimmed (minimum feerate) @@ -7757,8 +8628,8 @@ mod tests { chan.holder_dust_limit_satoshis = 546; test_commitment!("304402203a286936e74870ca1459c700c71202af0381910a6bfab687ef494ef1bc3e02c902202506c362d0e3bee15e802aa729bf378e051644648253513f1c085b264cc2a720", - "30450221008a953551f4d67cb4df3037207fc082ddaf6be84d417b0bd14c80aab66f1b01a402207508796dc75034b2dee876fe01dc05a08b019f3e5d689ac8842ade2f1befccf5", - "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8002c0c62d0000000000160014cc1b07838e387deacd0e5232e1e8b49f4c29e484fa926a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e04004830450221008a953551f4d67cb4df3037207fc082ddaf6be84d417b0bd14c80aab66f1b01a402207508796dc75034b2dee876fe01dc05a08b019f3e5d689ac8842ade2f1befccf50147304402203a286936e74870ca1459c700c71202af0381910a6bfab687ef494ef1bc3e02c902202506c362d0e3bee15e802aa729bf378e051644648253513f1c085b264cc2a72001475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", {}); + "30450221008a953551f4d67cb4df3037207fc082ddaf6be84d417b0bd14c80aab66f1b01a402207508796dc75034b2dee876fe01dc05a08b019f3e5d689ac8842ade2f1befccf5", + "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8002c0c62d0000000000160014cc1b07838e387deacd0e5232e1e8b49f4c29e484fa926a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e04004830450221008a953551f4d67cb4df3037207fc082ddaf6be84d417b0bd14c80aab66f1b01a402207508796dc75034b2dee876fe01dc05a08b019f3e5d689ac8842ade2f1befccf50147304402203a286936e74870ca1459c700c71202af0381910a6bfab687ef494ef1bc3e02c902202506c362d0e3bee15e802aa729bf378e051644648253513f1c085b264cc2a72001475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", {}); // anchors: commitment tx with two outputs untrimmed (minimum dust limit) chan.value_to_self_msat = 6993000000; // 7000000000 - 7000000 @@ -7766,8 +8637,8 @@ mod tests { chan.holder_dust_limit_satoshis = 4001; test_commitment_with_anchors!("3045022100e784a66b1588575801e237d35e510fd92a81ae3a4a2a1b90c031ad803d07b3f3022021bc5f16501f167607d63b681442da193eb0a76b4b7fd25c2ed4f8b28fd35b95", - "30450221009f16ac85d232e4eddb3fcd750a68ebf0b58e3356eaada45d3513ede7e817bf4c02207c2b043b4e5f971261975406cb955219fa56bffe5d834a833694b5abc1ce4cfd", - "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b80044a010000000000002200202b1b5854183c12d3316565972c4668929d314d81c5dcdbb21cb45fe8a9a8114f4a01000000000000220020e9e86e4823faa62e222ebc858a226636856158f07e69898da3b0d1af0ddb3994c0c62d0000000000220020f3394e1e619b0eca1f91be2fb5ab4dfc59ba5b84ebe014ad1d43a564d012994ad0886a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e04004830450221009f16ac85d232e4eddb3fcd750a68ebf0b58e3356eaada45d3513ede7e817bf4c02207c2b043b4e5f971261975406cb955219fa56bffe5d834a833694b5abc1ce4cfd01483045022100e784a66b1588575801e237d35e510fd92a81ae3a4a2a1b90c031ad803d07b3f3022021bc5f16501f167607d63b681442da193eb0a76b4b7fd25c2ed4f8b28fd35b9501475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", {}); + "30450221009f16ac85d232e4eddb3fcd750a68ebf0b58e3356eaada45d3513ede7e817bf4c02207c2b043b4e5f971261975406cb955219fa56bffe5d834a833694b5abc1ce4cfd", + "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b80044a010000000000002200202b1b5854183c12d3316565972c4668929d314d81c5dcdbb21cb45fe8a9a8114f4a01000000000000220020e9e86e4823faa62e222ebc858a226636856158f07e69898da3b0d1af0ddb3994c0c62d0000000000220020f3394e1e619b0eca1f91be2fb5ab4dfc59ba5b84ebe014ad1d43a564d012994ad0886a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e04004830450221009f16ac85d232e4eddb3fcd750a68ebf0b58e3356eaada45d3513ede7e817bf4c02207c2b043b4e5f971261975406cb955219fa56bffe5d834a833694b5abc1ce4cfd01483045022100e784a66b1588575801e237d35e510fd92a81ae3a4a2a1b90c031ad803d07b3f3022021bc5f16501f167607d63b681442da193eb0a76b4b7fd25c2ed4f8b28fd35b9501475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", {}); // commitment tx with two outputs untrimmed (maximum feerate) chan.value_to_self_msat = 6993000000; // 7000000000 - 7000000 @@ -7775,16 +8646,16 @@ mod tests { chan.holder_dust_limit_satoshis = 546; test_commitment!("304402200a8544eba1d216f5c5e530597665fa9bec56943c0f66d98fc3d028df52d84f7002201e45fa5c6bc3a506cc2553e7d1c0043a9811313fc39c954692c0d47cfce2bbd3", - "3045022100e11b638c05c650c2f63a421d36ef8756c5ce82f2184278643520311cdf50aa200220259565fb9c8e4a87ccaf17f27a3b9ca4f20625754a0920d9c6c239d8156a11de", - "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b800222020000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80ec0c62d0000000000160014cc1b07838e387deacd0e5232e1e8b49f4c29e4840400483045022100e11b638c05c650c2f63a421d36ef8756c5ce82f2184278643520311cdf50aa200220259565fb9c8e4a87ccaf17f27a3b9ca4f20625754a0920d9c6c239d8156a11de0147304402200a8544eba1d216f5c5e530597665fa9bec56943c0f66d98fc3d028df52d84f7002201e45fa5c6bc3a506cc2553e7d1c0043a9811313fc39c954692c0d47cfce2bbd301475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", {}); + "3045022100e11b638c05c650c2f63a421d36ef8756c5ce82f2184278643520311cdf50aa200220259565fb9c8e4a87ccaf17f27a3b9ca4f20625754a0920d9c6c239d8156a11de", + "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b800222020000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80ec0c62d0000000000160014cc1b07838e387deacd0e5232e1e8b49f4c29e4840400483045022100e11b638c05c650c2f63a421d36ef8756c5ce82f2184278643520311cdf50aa200220259565fb9c8e4a87ccaf17f27a3b9ca4f20625754a0920d9c6c239d8156a11de0147304402200a8544eba1d216f5c5e530597665fa9bec56943c0f66d98fc3d028df52d84f7002201e45fa5c6bc3a506cc2553e7d1c0043a9811313fc39c954692c0d47cfce2bbd301475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", {}); // commitment tx with one output untrimmed (minimum feerate) chan.value_to_self_msat = 6993000000; // 7000000000 - 7000000 chan.feerate_per_kw = 9651181; test_commitment!("304402202ade0142008309eb376736575ad58d03e5b115499709c6db0b46e36ff394b492022037b63d78d66404d6504d4c4ac13be346f3d1802928a6d3ad95a6a944227161a2", - "304402207e8d51e0c570a5868a78414f4e0cbfaed1106b171b9581542c30718ee4eb95ba02203af84194c97adf98898c9afe2f2ed4a7f8dba05a2dfab28ac9d9c604aa49a379", - "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8001c0c62d0000000000160014cc1b07838e387deacd0e5232e1e8b49f4c29e484040047304402207e8d51e0c570a5868a78414f4e0cbfaed1106b171b9581542c30718ee4eb95ba02203af84194c97adf98898c9afe2f2ed4a7f8dba05a2dfab28ac9d9c604aa49a3790147304402202ade0142008309eb376736575ad58d03e5b115499709c6db0b46e36ff394b492022037b63d78d66404d6504d4c4ac13be346f3d1802928a6d3ad95a6a944227161a201475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", {}); + "304402207e8d51e0c570a5868a78414f4e0cbfaed1106b171b9581542c30718ee4eb95ba02203af84194c97adf98898c9afe2f2ed4a7f8dba05a2dfab28ac9d9c604aa49a379", + "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8001c0c62d0000000000160014cc1b07838e387deacd0e5232e1e8b49f4c29e484040047304402207e8d51e0c570a5868a78414f4e0cbfaed1106b171b9581542c30718ee4eb95ba02203af84194c97adf98898c9afe2f2ed4a7f8dba05a2dfab28ac9d9c604aa49a3790147304402202ade0142008309eb376736575ad58d03e5b115499709c6db0b46e36ff394b492022037b63d78d66404d6504d4c4ac13be346f3d1802928a6d3ad95a6a944227161a201475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", {}); // anchors: commitment tx with one output untrimmed (minimum dust limit) chan.value_to_self_msat = 6993000000; // 7000000000 - 7000000 @@ -7792,8 +8663,8 @@ mod tests { chan.holder_dust_limit_satoshis = 4001; test_commitment_with_anchors!("30450221008fd5dbff02e4b59020d4cd23a3c30d3e287065fda75a0a09b402980adf68ccda022001e0b8b620cd915ddff11f1de32addf23d81d51b90e6841b2cb8dcaf3faa5ecf", - "30450221009ad80792e3038fe6968d12ff23e6888a565c3ddd065037f357445f01675d63f3022018384915e5f1f4ae157e15debf4f49b61c8d9d2b073c7d6f97c4a68caa3ed4c1", - "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b80024a01000000000000220020e9e86e4823faa62e222ebc858a226636856158f07e69898da3b0d1af0ddb3994c0c62d0000000000220020f3394e1e619b0eca1f91be2fb5ab4dfc59ba5b84ebe014ad1d43a564d012994a04004830450221009ad80792e3038fe6968d12ff23e6888a565c3ddd065037f357445f01675d63f3022018384915e5f1f4ae157e15debf4f49b61c8d9d2b073c7d6f97c4a68caa3ed4c1014830450221008fd5dbff02e4b59020d4cd23a3c30d3e287065fda75a0a09b402980adf68ccda022001e0b8b620cd915ddff11f1de32addf23d81d51b90e6841b2cb8dcaf3faa5ecf01475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", {}); + "30450221009ad80792e3038fe6968d12ff23e6888a565c3ddd065037f357445f01675d63f3022018384915e5f1f4ae157e15debf4f49b61c8d9d2b073c7d6f97c4a68caa3ed4c1", + "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b80024a01000000000000220020e9e86e4823faa62e222ebc858a226636856158f07e69898da3b0d1af0ddb3994c0c62d0000000000220020f3394e1e619b0eca1f91be2fb5ab4dfc59ba5b84ebe014ad1d43a564d012994a04004830450221009ad80792e3038fe6968d12ff23e6888a565c3ddd065037f357445f01675d63f3022018384915e5f1f4ae157e15debf4f49b61c8d9d2b073c7d6f97c4a68caa3ed4c1014830450221008fd5dbff02e4b59020d4cd23a3c30d3e287065fda75a0a09b402980adf68ccda022001e0b8b620cd915ddff11f1de32addf23d81d51b90e6841b2cb8dcaf3faa5ecf01475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", {}); // commitment tx with fee greater than funder amount chan.value_to_self_msat = 6993000000; // 7000000000 - 7000000 @@ -7801,8 +8672,8 @@ mod tests { chan.holder_dust_limit_satoshis = 546; test_commitment!("304402202ade0142008309eb376736575ad58d03e5b115499709c6db0b46e36ff394b492022037b63d78d66404d6504d4c4ac13be346f3d1802928a6d3ad95a6a944227161a2", - "304402207e8d51e0c570a5868a78414f4e0cbfaed1106b171b9581542c30718ee4eb95ba02203af84194c97adf98898c9afe2f2ed4a7f8dba05a2dfab28ac9d9c604aa49a379", - "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8001c0c62d0000000000160014cc1b07838e387deacd0e5232e1e8b49f4c29e484040047304402207e8d51e0c570a5868a78414f4e0cbfaed1106b171b9581542c30718ee4eb95ba02203af84194c97adf98898c9afe2f2ed4a7f8dba05a2dfab28ac9d9c604aa49a3790147304402202ade0142008309eb376736575ad58d03e5b115499709c6db0b46e36ff394b492022037b63d78d66404d6504d4c4ac13be346f3d1802928a6d3ad95a6a944227161a201475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", {}); + "304402207e8d51e0c570a5868a78414f4e0cbfaed1106b171b9581542c30718ee4eb95ba02203af84194c97adf98898c9afe2f2ed4a7f8dba05a2dfab28ac9d9c604aa49a379", + "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8001c0c62d0000000000160014cc1b07838e387deacd0e5232e1e8b49f4c29e484040047304402207e8d51e0c570a5868a78414f4e0cbfaed1106b171b9581542c30718ee4eb95ba02203af84194c97adf98898c9afe2f2ed4a7f8dba05a2dfab28ac9d9c604aa49a3790147304402202ade0142008309eb376736575ad58d03e5b115499709c6db0b46e36ff394b492022037b63d78d66404d6504d4c4ac13be346f3d1802928a6d3ad95a6a944227161a201475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", {}); // commitment tx with 3 htlc outputs, 2 offered having the same amount and preimage chan.value_to_self_msat = 7_000_000_000 - 2_000_000; @@ -7846,39 +8717,39 @@ mod tests { }); test_commitment!("30440220048705bec5288d28b3f29344b8d124853b1af423a568664d2c6f02c8ea886525022060f998a461052a2476b912db426ea2a06700953a241135c7957f2e79bc222df9", - "3045022100c4f1d60b6fca9febc8b39de1a31e84c5f7c4b41c97239ef05f4350aa484c6b5e02200c5134ac8b20eb7a29d0dd4a501f6aa8fefb8489171f4cb408bd2a32324ab03f", - "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8005d007000000000000220020748eba944fedc8827f6b06bc44678f93c0f9e6078b35c6331ed31e75f8ce0c2d8813000000000000220020305c12e1a0bc21e283c131cea1c66d68857d28b7b2fce0a6fbc40c164852121b8813000000000000220020305c12e1a0bc21e283c131cea1c66d68857d28b7b2fce0a6fbc40c164852121bc0c62d0000000000160014cc1b07838e387deacd0e5232e1e8b49f4c29e484a79f6a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0400483045022100c4f1d60b6fca9febc8b39de1a31e84c5f7c4b41c97239ef05f4350aa484c6b5e02200c5134ac8b20eb7a29d0dd4a501f6aa8fefb8489171f4cb408bd2a32324ab03f014730440220048705bec5288d28b3f29344b8d124853b1af423a568664d2c6f02c8ea886525022060f998a461052a2476b912db426ea2a06700953a241135c7957f2e79bc222df901475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", { - - { 0, - "304502210081cbb94121761d34c189cd4e6a281feea6f585060ad0ba2632e8d6b3c6bb8a6c02201007981bbd16539d63df2805b5568f1f5688cd2a885d04706f50db9b77ba13c6", - "304502210090ed76aeb21b53236a598968abc66e2024691d07b62f53ddbeca8f93144af9c602205f873af5a0c10e62690e9aba09740550f194a9dc455ba4c1c23f6cde7704674c", - "0200000000010189a326e23addc28323dbadcb4e71c2c17088b6e8fa184103e552f44075dddc34000000000000000000011f070000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e050048304502210081cbb94121761d34c189cd4e6a281feea6f585060ad0ba2632e8d6b3c6bb8a6c02201007981bbd16539d63df2805b5568f1f5688cd2a885d04706f50db9b77ba13c60148304502210090ed76aeb21b53236a598968abc66e2024691d07b62f53ddbeca8f93144af9c602205f873af5a0c10e62690e9aba09740550f194a9dc455ba4c1c23f6cde7704674c012001010101010101010101010101010101010101010101010101010101010101018a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a9144b6b2e5444c2639cc0fb7bcea5afba3f3cdce23988527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f501b175ac686800000000" }, - { 1, - "304402201d0f09d2bf7bc245a4f17980e1e9164290df16c70c6a2ff1592f5030d6108581022061e744a7dc151b36bf0aff7a4f1812ba90b8b03633bb979a270d19858fd960c5", - "30450221009aef000d2e843a4202c1b1a2bf554abc9a7902bf49b2cb0759bc507456b7ebad02204e7c3d193ede2fd2b4cd6b39f51a920e581e35575e357e44d7b699c40ce61d39", - "0200000000010189a326e23addc28323dbadcb4e71c2c17088b6e8fa184103e552f44075dddc3401000000000000000001e1120000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e050047304402201d0f09d2bf7bc245a4f17980e1e9164290df16c70c6a2ff1592f5030d6108581022061e744a7dc151b36bf0aff7a4f1812ba90b8b03633bb979a270d19858fd960c5014830450221009aef000d2e843a4202c1b1a2bf554abc9a7902bf49b2cb0759bc507456b7ebad02204e7c3d193ede2fd2b4cd6b39f51a920e581e35575e357e44d7b699c40ce61d3901008576a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a9142002cc93ebefbb1b73f0af055dcc27a0b504ad7688ac6868f9010000" }, - { 2, - "30440220010bf035d5823596e50dce2076a4d9f942d8d28031c9c428b901a02b6b8140de02203250e8e4a08bc5b4ecdca4d0eedf98223e02e3ac1c0206b3a7ffdb374aa21e5f", - "30440220073de0067b88e425b3018b30366bfeda0ccb703118ccd3d02ead08c0f53511d002203fac50ac0e4cf8a3af0b4b1b12e801650591f748f8ddf1e089c160f10b69e511", - "0200000000010189a326e23addc28323dbadcb4e71c2c17088b6e8fa184103e552f44075dddc3402000000000000000001e1120000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e05004730440220010bf035d5823596e50dce2076a4d9f942d8d28031c9c428b901a02b6b8140de02203250e8e4a08bc5b4ecdca4d0eedf98223e02e3ac1c0206b3a7ffdb374aa21e5f014730440220073de0067b88e425b3018b30366bfeda0ccb703118ccd3d02ead08c0f53511d002203fac50ac0e4cf8a3af0b4b1b12e801650591f748f8ddf1e089c160f10b69e51101008576a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a9142002cc93ebefbb1b73f0af055dcc27a0b504ad7688ac6868fa010000" } + "3045022100c4f1d60b6fca9febc8b39de1a31e84c5f7c4b41c97239ef05f4350aa484c6b5e02200c5134ac8b20eb7a29d0dd4a501f6aa8fefb8489171f4cb408bd2a32324ab03f", + "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8005d007000000000000220020748eba944fedc8827f6b06bc44678f93c0f9e6078b35c6331ed31e75f8ce0c2d8813000000000000220020305c12e1a0bc21e283c131cea1c66d68857d28b7b2fce0a6fbc40c164852121b8813000000000000220020305c12e1a0bc21e283c131cea1c66d68857d28b7b2fce0a6fbc40c164852121bc0c62d0000000000160014cc1b07838e387deacd0e5232e1e8b49f4c29e484a79f6a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0400483045022100c4f1d60b6fca9febc8b39de1a31e84c5f7c4b41c97239ef05f4350aa484c6b5e02200c5134ac8b20eb7a29d0dd4a501f6aa8fefb8489171f4cb408bd2a32324ab03f014730440220048705bec5288d28b3f29344b8d124853b1af423a568664d2c6f02c8ea886525022060f998a461052a2476b912db426ea2a06700953a241135c7957f2e79bc222df901475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", { + + { 0, + "304502210081cbb94121761d34c189cd4e6a281feea6f585060ad0ba2632e8d6b3c6bb8a6c02201007981bbd16539d63df2805b5568f1f5688cd2a885d04706f50db9b77ba13c6", + "304502210090ed76aeb21b53236a598968abc66e2024691d07b62f53ddbeca8f93144af9c602205f873af5a0c10e62690e9aba09740550f194a9dc455ba4c1c23f6cde7704674c", + "0200000000010189a326e23addc28323dbadcb4e71c2c17088b6e8fa184103e552f44075dddc34000000000000000000011f070000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e050048304502210081cbb94121761d34c189cd4e6a281feea6f585060ad0ba2632e8d6b3c6bb8a6c02201007981bbd16539d63df2805b5568f1f5688cd2a885d04706f50db9b77ba13c60148304502210090ed76aeb21b53236a598968abc66e2024691d07b62f53ddbeca8f93144af9c602205f873af5a0c10e62690e9aba09740550f194a9dc455ba4c1c23f6cde7704674c012001010101010101010101010101010101010101010101010101010101010101018a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a9144b6b2e5444c2639cc0fb7bcea5afba3f3cdce23988527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f501b175ac686800000000" }, + { 1, + "304402201d0f09d2bf7bc245a4f17980e1e9164290df16c70c6a2ff1592f5030d6108581022061e744a7dc151b36bf0aff7a4f1812ba90b8b03633bb979a270d19858fd960c5", + "30450221009aef000d2e843a4202c1b1a2bf554abc9a7902bf49b2cb0759bc507456b7ebad02204e7c3d193ede2fd2b4cd6b39f51a920e581e35575e357e44d7b699c40ce61d39", + "0200000000010189a326e23addc28323dbadcb4e71c2c17088b6e8fa184103e552f44075dddc3401000000000000000001e1120000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e050047304402201d0f09d2bf7bc245a4f17980e1e9164290df16c70c6a2ff1592f5030d6108581022061e744a7dc151b36bf0aff7a4f1812ba90b8b03633bb979a270d19858fd960c5014830450221009aef000d2e843a4202c1b1a2bf554abc9a7902bf49b2cb0759bc507456b7ebad02204e7c3d193ede2fd2b4cd6b39f51a920e581e35575e357e44d7b699c40ce61d3901008576a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a9142002cc93ebefbb1b73f0af055dcc27a0b504ad7688ac6868f9010000" }, + { 2, + "30440220010bf035d5823596e50dce2076a4d9f942d8d28031c9c428b901a02b6b8140de02203250e8e4a08bc5b4ecdca4d0eedf98223e02e3ac1c0206b3a7ffdb374aa21e5f", + "30440220073de0067b88e425b3018b30366bfeda0ccb703118ccd3d02ead08c0f53511d002203fac50ac0e4cf8a3af0b4b1b12e801650591f748f8ddf1e089c160f10b69e511", + "0200000000010189a326e23addc28323dbadcb4e71c2c17088b6e8fa184103e552f44075dddc3402000000000000000001e1120000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e05004730440220010bf035d5823596e50dce2076a4d9f942d8d28031c9c428b901a02b6b8140de02203250e8e4a08bc5b4ecdca4d0eedf98223e02e3ac1c0206b3a7ffdb374aa21e5f014730440220073de0067b88e425b3018b30366bfeda0ccb703118ccd3d02ead08c0f53511d002203fac50ac0e4cf8a3af0b4b1b12e801650591f748f8ddf1e089c160f10b69e51101008576a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a9142002cc93ebefbb1b73f0af055dcc27a0b504ad7688ac6868fa010000" } } ); test_commitment_with_anchors!("3045022100c592f6b80d35b4f5d1e3bc9788f51141a0065be6013bad53a1977f7c444651660220278ac06ead9016bfb8dc476f186eabace2b02793b2f308442f5b0d5f24a68948", - "3045022100c37ac4fc8538677631230c4b286f36b6f54c51fb4b34ef0bd0ba219ba47452630220278e09a745454ea380f3694392ed113762c68dd209b48360f547541088be9e45", - "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b80074a010000000000002200202b1b5854183c12d3316565972c4668929d314d81c5dcdbb21cb45fe8a9a8114f4a01000000000000220020e9e86e4823faa62e222ebc858a226636856158f07e69898da3b0d1af0ddb3994d007000000000000220020fe0598d74fee2205cc3672e6e6647706b4f3099713b4661b62482c3addd04a5e881300000000000022002018e40f9072c44350f134bdc887bab4d9bdfc8aa468a25616c80e21757ba5dac7881300000000000022002018e40f9072c44350f134bdc887bab4d9bdfc8aa468a25616c80e21757ba5dac7c0c62d0000000000220020f3394e1e619b0eca1f91be2fb5ab4dfc59ba5b84ebe014ad1d43a564d012994aae9c6a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0400483045022100c37ac4fc8538677631230c4b286f36b6f54c51fb4b34ef0bd0ba219ba47452630220278e09a745454ea380f3694392ed113762c68dd209b48360f547541088be9e4501483045022100c592f6b80d35b4f5d1e3bc9788f51141a0065be6013bad53a1977f7c444651660220278ac06ead9016bfb8dc476f186eabace2b02793b2f308442f5b0d5f24a6894801475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", { - - { 0, - "3045022100de8a0649d54fd2e4fc04502c77df9b65da839bbd01854f818f129338b99564b2022009528dbb12c00e874cb2149b1dccc600c69ea5e4042ebf584984fcb029c2d1ec", - "304402203e7c2622fa3ca29355d37a0ea991bfd7cdb54e6122a1d98d3229d092131f55cd022055263f7f8f32f4cd2f86da63ca106bd7badf0b19ee9833d80cd3b9216eeafd74", - "02000000000101aa443fb63abc1e8c754f98a7b96c27cb02b21d891d1242a16b630dc32c2afe2902000000000100000001d0070000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100de8a0649d54fd2e4fc04502c77df9b65da839bbd01854f818f129338b99564b2022009528dbb12c00e874cb2149b1dccc600c69ea5e4042ebf584984fcb029c2d1ec8347304402203e7c2622fa3ca29355d37a0ea991bfd7cdb54e6122a1d98d3229d092131f55cd022055263f7f8f32f4cd2f86da63ca106bd7badf0b19ee9833d80cd3b9216eeafd74012001010101010101010101010101010101010101010101010101010101010101018d76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a9144b6b2e5444c2639cc0fb7bcea5afba3f3cdce23988527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f501b175ac6851b2756800000000" }, - { 1, - "3045022100de6eee8474376ea316d007b33103b4543a46bdf6fda5cbd5902b28a5bc14584f022002989e7b4f7813b77acbe4babcf96d7ffbbe0bf14cba24672364f8e591479edb", - "3045022100c10688346a9d84647bde7027da07f0d79c6d4129307e4c6c9aea7bdbf25ac3350220269104209793c32c47491698c4e46ebea9c3293a1e4403f9abda39f79698f6b5", - "02000000000101aa443fb63abc1e8c754f98a7b96c27cb02b21d891d1242a16b630dc32c2afe290300000000010000000188130000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100de6eee8474376ea316d007b33103b4543a46bdf6fda5cbd5902b28a5bc14584f022002989e7b4f7813b77acbe4babcf96d7ffbbe0bf14cba24672364f8e591479edb83483045022100c10688346a9d84647bde7027da07f0d79c6d4129307e4c6c9aea7bdbf25ac3350220269104209793c32c47491698c4e46ebea9c3293a1e4403f9abda39f79698f6b501008876a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a9142002cc93ebefbb1b73f0af055dcc27a0b504ad7688ac6851b27568f9010000" }, - { 2, - "3045022100fe87da8124ceecbcabb9d599c5339f40277c7c7406514fafbccbf180c7c09cf40220429c7fb6d0fd3705e931ab1219ab0432af38ae4d676008cc1964fbeb8cd35d2e", - "3044022040ac769a851da31d8e4863e5f94719204f716c82a1ce6d6c52193d9a33b84bce022035df97b078ce80f20dca2109e4c6075af0b50148811452e7290e68b2680fced4", - "02000000000101aa443fb63abc1e8c754f98a7b96c27cb02b21d891d1242a16b630dc32c2afe290400000000010000000188130000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100fe87da8124ceecbcabb9d599c5339f40277c7c7406514fafbccbf180c7c09cf40220429c7fb6d0fd3705e931ab1219ab0432af38ae4d676008cc1964fbeb8cd35d2e83473044022040ac769a851da31d8e4863e5f94719204f716c82a1ce6d6c52193d9a33b84bce022035df97b078ce80f20dca2109e4c6075af0b50148811452e7290e68b2680fced401008876a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a9142002cc93ebefbb1b73f0af055dcc27a0b504ad7688ac6851b27568fa010000" } + "3045022100c37ac4fc8538677631230c4b286f36b6f54c51fb4b34ef0bd0ba219ba47452630220278e09a745454ea380f3694392ed113762c68dd209b48360f547541088be9e45", + "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b80074a010000000000002200202b1b5854183c12d3316565972c4668929d314d81c5dcdbb21cb45fe8a9a8114f4a01000000000000220020e9e86e4823faa62e222ebc858a226636856158f07e69898da3b0d1af0ddb3994d007000000000000220020fe0598d74fee2205cc3672e6e6647706b4f3099713b4661b62482c3addd04a5e881300000000000022002018e40f9072c44350f134bdc887bab4d9bdfc8aa468a25616c80e21757ba5dac7881300000000000022002018e40f9072c44350f134bdc887bab4d9bdfc8aa468a25616c80e21757ba5dac7c0c62d0000000000220020f3394e1e619b0eca1f91be2fb5ab4dfc59ba5b84ebe014ad1d43a564d012994aae9c6a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0400483045022100c37ac4fc8538677631230c4b286f36b6f54c51fb4b34ef0bd0ba219ba47452630220278e09a745454ea380f3694392ed113762c68dd209b48360f547541088be9e4501483045022100c592f6b80d35b4f5d1e3bc9788f51141a0065be6013bad53a1977f7c444651660220278ac06ead9016bfb8dc476f186eabace2b02793b2f308442f5b0d5f24a6894801475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", { + + { 0, + "3045022100de8a0649d54fd2e4fc04502c77df9b65da839bbd01854f818f129338b99564b2022009528dbb12c00e874cb2149b1dccc600c69ea5e4042ebf584984fcb029c2d1ec", + "304402203e7c2622fa3ca29355d37a0ea991bfd7cdb54e6122a1d98d3229d092131f55cd022055263f7f8f32f4cd2f86da63ca106bd7badf0b19ee9833d80cd3b9216eeafd74", + "02000000000101aa443fb63abc1e8c754f98a7b96c27cb02b21d891d1242a16b630dc32c2afe2902000000000100000001d0070000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100de8a0649d54fd2e4fc04502c77df9b65da839bbd01854f818f129338b99564b2022009528dbb12c00e874cb2149b1dccc600c69ea5e4042ebf584984fcb029c2d1ec8347304402203e7c2622fa3ca29355d37a0ea991bfd7cdb54e6122a1d98d3229d092131f55cd022055263f7f8f32f4cd2f86da63ca106bd7badf0b19ee9833d80cd3b9216eeafd74012001010101010101010101010101010101010101010101010101010101010101018d76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a9144b6b2e5444c2639cc0fb7bcea5afba3f3cdce23988527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f501b175ac6851b2756800000000" }, + { 1, + "3045022100de6eee8474376ea316d007b33103b4543a46bdf6fda5cbd5902b28a5bc14584f022002989e7b4f7813b77acbe4babcf96d7ffbbe0bf14cba24672364f8e591479edb", + "3045022100c10688346a9d84647bde7027da07f0d79c6d4129307e4c6c9aea7bdbf25ac3350220269104209793c32c47491698c4e46ebea9c3293a1e4403f9abda39f79698f6b5", + "02000000000101aa443fb63abc1e8c754f98a7b96c27cb02b21d891d1242a16b630dc32c2afe290300000000010000000188130000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100de6eee8474376ea316d007b33103b4543a46bdf6fda5cbd5902b28a5bc14584f022002989e7b4f7813b77acbe4babcf96d7ffbbe0bf14cba24672364f8e591479edb83483045022100c10688346a9d84647bde7027da07f0d79c6d4129307e4c6c9aea7bdbf25ac3350220269104209793c32c47491698c4e46ebea9c3293a1e4403f9abda39f79698f6b501008876a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a9142002cc93ebefbb1b73f0af055dcc27a0b504ad7688ac6851b27568f9010000" }, + { 2, + "3045022100fe87da8124ceecbcabb9d599c5339f40277c7c7406514fafbccbf180c7c09cf40220429c7fb6d0fd3705e931ab1219ab0432af38ae4d676008cc1964fbeb8cd35d2e", + "3044022040ac769a851da31d8e4863e5f94719204f716c82a1ce6d6c52193d9a33b84bce022035df97b078ce80f20dca2109e4c6075af0b50148811452e7290e68b2680fced4", + "02000000000101aa443fb63abc1e8c754f98a7b96c27cb02b21d891d1242a16b630dc32c2afe290400000000010000000188130000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100fe87da8124ceecbcabb9d599c5339f40277c7c7406514fafbccbf180c7c09cf40220429c7fb6d0fd3705e931ab1219ab0432af38ae4d676008cc1964fbeb8cd35d2e83473044022040ac769a851da31d8e4863e5f94719204f716c82a1ce6d6c52193d9a33b84bce022035df97b078ce80f20dca2109e4c6075af0b50148811452e7290e68b2680fced401008876a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a9142002cc93ebefbb1b73f0af055dcc27a0b504ad7688ac6851b27568fa010000" } } ); } @@ -7889,21 +8760,21 @@ mod tests { let mut seed = [0; 32]; seed[0..32].clone_from_slice(&hex::decode("0000000000000000000000000000000000000000000000000000000000000000").unwrap()); assert_eq!(chan_utils::build_commitment_secret(&seed, 281474976710655), - hex::decode("02a40c85b6f28da08dfdbe0926c53fab2de6d28c10301f8f7c4073d5e42e3148").unwrap()[..]); + hex::decode("02a40c85b6f28da08dfdbe0926c53fab2de6d28c10301f8f7c4073d5e42e3148").unwrap()[..]); seed[0..32].clone_from_slice(&hex::decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF").unwrap()); assert_eq!(chan_utils::build_commitment_secret(&seed, 281474976710655), - hex::decode("7cc854b54e3e0dcdb010d7a3fee464a9687be6e8db3be6854c475621e007a5dc").unwrap()[..]); + hex::decode("7cc854b54e3e0dcdb010d7a3fee464a9687be6e8db3be6854c475621e007a5dc").unwrap()[..]); assert_eq!(chan_utils::build_commitment_secret(&seed, 0xaaaaaaaaaaa), - hex::decode("56f4008fb007ca9acf0e15b054d5c9fd12ee06cea347914ddbaed70d1c13a528").unwrap()[..]); + hex::decode("56f4008fb007ca9acf0e15b054d5c9fd12ee06cea347914ddbaed70d1c13a528").unwrap()[..]); assert_eq!(chan_utils::build_commitment_secret(&seed, 0x555555555555), - hex::decode("9015daaeb06dba4ccc05b91b2f73bd54405f2be9f217fbacd3c5ac2e62327d31").unwrap()[..]); + hex::decode("9015daaeb06dba4ccc05b91b2f73bd54405f2be9f217fbacd3c5ac2e62327d31").unwrap()[..]); seed[0..32].clone_from_slice(&hex::decode("0101010101010101010101010101010101010101010101010101010101010101").unwrap()); assert_eq!(chan_utils::build_commitment_secret(&seed, 1), - hex::decode("915c75942a26bb3a433a8ce2cb0427c29ec6c1775cfc78328b57f6ba7bfeaa9c").unwrap()[..]); + hex::decode("915c75942a26bb3a433a8ce2cb0427c29ec6c1775cfc78328b57f6ba7bfeaa9c").unwrap()[..]); } #[test] diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index e3128d15f53..b145c6c371d 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -32,7 +32,7 @@ use bitcoin::hash_types::{BlockHash, Txid}; use bitcoin::secp256k1::{SecretKey,PublicKey}; use bitcoin::secp256k1::Secp256k1; use bitcoin::secp256k1::ecdh::SharedSecret; -use bitcoin::{LockTime, secp256k1, Sequence}; +use bitcoin::{LockTime, secp256k1, Sequence, Script}; use crate::chain; use crate::chain::{Confirm, ChannelMonitorUpdateStatus, Watch, BestBlock}; @@ -49,11 +49,11 @@ use crate::ln::features::InvoiceFeatures; use crate::routing::router::{PaymentParameters, Route, RouteHop, RoutePath, RouteParameters}; use crate::ln::msgs; use crate::ln::onion_utils; -use crate::ln::msgs::{ChannelMessageHandler, DecodeError, LightningError, MAX_VALUE_MSAT}; +use crate::ln::msgs::{ChannelMessageHandler, CommitmentUpdate, DecodeError, LightningError, MAX_VALUE_MSAT}; use crate::ln::wire::Encode; use crate::chain::keysinterface::{Sign, KeysInterface, KeysManager, InMemorySigner, Recipient}; use crate::util::config::{UserConfig, ChannelConfig}; -use crate::util::events::{EventHandler, EventsProvider, MessageSendEvent, MessageSendEventsProvider, ClosureReason, HTLCDestination}; +use crate::util::events::{EventHandler, EventsProvider, MessageSendEvent, MessageSendEventsProvider, ClosureReason, HTLCDestination, Event}; use crate::util::{byte_utils, events}; use crate::util::wakers::{Future, Notifier}; use crate::util::scid_utils::fake_scid; @@ -65,12 +65,16 @@ use crate::io; use crate::prelude::*; use core::{cmp, mem}; use core::cell::RefCell; +use core::fmt::{Debug, Display, Formatter}; use crate::io::Read; use crate::sync::{Arc, Mutex, MutexGuard, RwLock, RwLockReadGuard}; use core::sync::atomic::{AtomicUsize, Ordering}; use core::time::Duration; use core::ops::Deref; +use super::channel::{ShouldRevoke, DidRemoteSendCustomOutputCommitmentSignature}; +use super::msgs::{CommitmentSigned, RevokeAndACK}; + // We hold various information about HTLC relay in the HTLC objects in Channel itself: // // Upon receipt of an HTLC from a peer, we'll give it a PendingHTLCStatus indicating if it should @@ -150,7 +154,7 @@ pub(super) enum HTLCForwardInfo { } /// Tracks the inbound corresponding to an outbound HTLC -#[derive(Clone, Hash, PartialEq, Eq)] +#[derive(Clone, Hash, PartialEq, Eq, Debug)] pub(crate) struct HTLCPreviousHopData { // Note that this may be an outbound SCID alias for the associated channel. short_channel_id: u64, @@ -191,6 +195,37 @@ struct ClaimableHTLC { #[derive(Hash, Copy, Clone, PartialEq, Eq, Debug)] pub struct PaymentId(pub [u8; 32]); +/// An identifier used to uniquely identify a custom output to LDK. +/// (C-not exported) as we just use [u8; 32] directly +#[derive(Hash, Copy, Clone, PartialEq, Eq, Debug)] +pub struct CustomOutputId(pub [u8; 32]); + +/// How to use a custom output as an input in another transaction. +/// TODO(10101): Add sighash for both commitment transaction. +#[derive(Clone, Debug)] +pub struct CustomOutputDetails { + /// Unique identifier for the custom output. + pub id: CustomOutputId, + /// Where the output is located in the local commitment transaction. + pub outpoint_commit_local: OutPoint, + /// Where the output is located in the remote commitment transaction. + pub outpoint_commit_remote: OutPoint, + /// The script to be signed when spending the custom output. + pub script: Script, + /// The shared amount in the custom output. + pub amount: u64, +} + +impl Display for CustomOutputId { + + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + for v in &self.0 { + write!(f, "{:x?}", v)?; + } + Ok(()) + } +} + impl Writeable for PaymentId { fn write(&self, w: &mut W) -> Result<(), io::Error> { self.0.write(w) @@ -203,9 +238,23 @@ impl Readable for PaymentId { Ok(PaymentId(buf)) } } + +impl Writeable for CustomOutputId { + fn write(&self, w: &mut W) -> Result<(), io::Error> { + self.0.write(w) + } +} + +impl Readable for CustomOutputId { + fn read(r: &mut R) -> Result { + let buf: [u8; 32] = Readable::read(r)?; + Ok(CustomOutputId(buf)) + } +} + /// Tracks the inbound corresponding to an outbound HTLC #[allow(clippy::derive_hash_xor_eq)] // Our Hash is faithful to the data, we just don't have SecretKey::hash -#[derive(Clone, PartialEq, Eq)] +#[derive(Clone, PartialEq, Eq, Debug)] pub(crate) enum HTLCSource { PreviousHopData(HTLCPreviousHopData), OutboundRoute { @@ -487,6 +536,16 @@ pub(crate) enum PendingOutboundPayment { }, } +#[derive(Debug)] +struct CustomOutput { + channel_id: [u8;32], + local_amount_msat: u64, + remote_amount_msat: u64, + cltv_expiry: u32, + script: Script, + counterparty_node_id: PublicKey, +} + impl PendingOutboundPayment { fn is_retryable(&self) -> bool { match self { @@ -701,9 +760,9 @@ pub type SimpleRefChannelManager<'a, 'b, 'c, 'd, 'e, M, T, F, L> = ChannelManage // pub struct ChannelManager where M::Target: chain::Watch, - T::Target: BroadcasterInterface, - K::Target: KeysInterface, - F::Target: FeeEstimator, + T::Target: BroadcasterInterface, + K::Target: KeysInterface, + F::Target: FeeEstimator, L::Target: Logger, { default_configuration: UserConfig, @@ -747,6 +806,9 @@ pub struct ChannelManager>, + /// Stores alive custom outputs currently asigned to some channel + custom_outputs: Mutex>, // TODO(10101): Not sure if beta ever adds it to this enum. + /// SCID/SCID Alias -> forward infos. Key of 0 means payments received. /// /// Note that because we may have an SCID Alias as the key we can have two entries per channel, @@ -1231,6 +1293,25 @@ pub enum PaymentSendFailure { }, } +/// An error returned if removing a custom output failed +#[derive(Clone, Debug)] +pub enum RemoveCustomOutputError { + /// Custom output was not found + CustomOutputNotFound, + /// Channel to remove custom output from was not found + ChannelNotFound, + /// Channel already closed + ChannelClosed, + /// Amounts provided do not add up + InvalidAmounts, + /// Channel currently not available + ChannelNotAvailable, + /// Channel is dead + ChannelFailed, + /// Somethingsomething monitor in progress + MonitorInProgress, +} + /// Route hints used in constructing invoices for [phantom node payents]. /// /// [phantom node payments]: crate::chain::keysinterface::PhantomKeysManager @@ -1538,7 +1619,7 @@ macro_rules! handle_chan_restoration_locked { macro_rules! handle_cs { () => { if let Some(update) = $commitment_update { - $channel_state.pending_msg_events.push(events::MessageSendEvent::UpdateHTLCs { + $channel_state.pending_msg_events.push(events::MessageSendEvent::UpdateCommitmentOutputs { node_id: counterparty_node_id, updates: update, }); @@ -1594,10 +1675,10 @@ macro_rules! post_handle_chan_restoration { impl ChannelManager where M::Target: chain::Watch, - T::Target: BroadcasterInterface, - K::Target: KeysInterface, - F::Target: FeeEstimator, - L::Target: Logger, + T::Target: BroadcasterInterface, + K::Target: KeysInterface, + F::Target: FeeEstimator, + L::Target: Logger, { /// Constructs a new ChannelManager to hold several channels and route between them. /// @@ -1632,6 +1713,7 @@ impl ChannelMana outbound_scid_aliases: Mutex::new(HashSet::new()), pending_inbound_payments: Mutex::new(HashMap::new()), pending_outbound_payments: Mutex::new(HashMap::new()), + custom_outputs: Mutex::new(Default::default()), forward_htlcs: Mutex::new(HashMap::new()), id_to_peer: Mutex::new(HashMap::new()), @@ -2528,7 +2610,7 @@ impl ChannelMana } log_debug!(self.logger, "Sending payment along path resulted in a commitment_signed for channel {}", log_bytes!(chan_id)); - channel_state.pending_msg_events.push(events::MessageSendEvent::UpdateHTLCs { + channel_state.pending_msg_events.push(events::MessageSendEvent::UpdateCommitmentOutputs { node_id: path.first().unwrap().pubkey, updates: msgs::CommitmentUpdate { update_add_htlcs: vec![update_add], @@ -2537,6 +2619,8 @@ impl ChannelMana update_fail_malformed_htlcs: Vec::new(), update_fee: None, commitment_signed, + update_add_custom_output: Vec::new(), + update_remove_custom_output: Vec::new() }, }); }, @@ -2676,6 +2760,273 @@ impl ChannelMana } } + /// TODO(10101): Add docs + pub fn add_custom_output( + &self, + short_channel_id: u64, + pk_counterparty: PublicKey, + local_amount_msat: u64, + remote_amount_msat: u64, + cltv_expiry: u32, + script: Script, + ) -> Result { + let mut channel_lock = self.channel_state.lock().unwrap(); + let channel_id = channel_lock + .short_to_chan_info + .get(&short_channel_id) + .map(|(_, id)| id) + .cloned() + .ok_or("No channel available with first hop!".to_owned())?; + + // TODO(10101): Here `send_payment_along_path` checks if the payment is already in + // `pending_outbounds` and exits if it's not marked as "retryable". We might have to do + // something similar for DLCs + + let channel_holder = &mut *channel_lock; + let mut channel = match channel_holder.by_id.entry(channel_id.clone()) { + hash_map::Entry::Occupied(channel) => channel, + hash_map::Entry::Vacant(_) => { + return Err("No channel available with peer".to_owned()); + } + }; + + + if channel.get().get_counterparty_node_id() != pk_counterparty { + return Err("Node ID mismatch".to_owned()); + } + + if !channel.get().is_live() { + return Err("Peer for first hop currently disconnected/pending monitor update!".to_owned()); + } + + let custom_output_id = CustomOutputId(self.keys_manager.get_secure_random_bytes()); + + + let (custom_output_details, update_add) = + match channel.get_mut().add_custom_output_and_build_commits(custom_output_id, + local_amount_msat, + remote_amount_msat, + cltv_expiry, + script.clone(), + &self.logger + ) + { + Ok(res) => res, + Err(e) => { + let (drop, e) = convert_chan_err!(self, e, channel_holder.short_to_chan_info, channel.get_mut(), channel.key()); + if drop { + channel.remove_entry(); + } + match handle_error!(self, Result::<(), _>::Err(e), pk_counterparty) { + Ok(_) => unreachable!(), + Err(e) => { + return Err(format!("Channel unavailable: {}", e.err)); + }, + } + }, + }; + + let channel_id = channel.get().channel_id(); + + // TODO(10101): We have to monitor after we sign the commit transaction later! + // let update_err = self.chain_monitor.update_channel(channel.get().get_funding_txo().unwrap(), monitor_update); + // match (update_err, + // handle_monitor_update_res!(self, update_err, channel_holder, channel, + // RAACommitmentOrder::CommitmentFirst, false, true)) + // { + // (ChannelMonitorUpdateStatus::PermanentFailure, Err(e)) => return Err(format!("{}", e.err.err)), + // (ChannelMonitorUpdateStatus::Completed | ChannelMonitorUpdateStatus::InProgress, res) => { + // // TODO(10101): Add entry to a `pending_custom_outputs` field in `ChannelManager`? + // // let payment = payment_entry.or_insert_with(|| PendingOutboundPayment::Retryable { + // // session_privs: HashSet::new(), + // // pending_amt_msat: 0, + // // pending_fee_msat: Some(0), + // // payment_hash: *payment_hash, + // // payment_secret: *payment_secret, + // // starting_block_height: self.best_block.read().unwrap().height(), + // // total_msat: total_value, + // // }); + // // assert!(payment.insert(session_priv_bytes, path)); + + // if res.is_err() { + // return Err("Monitor update in progress".to_owned()); + // } + // }, + // _ => unreachable!(), + // } + + log_debug!(self.logger, "Adding custom output resulted in a commitment_signed for channel {}", log_bytes!(channel_id)); + + channel_holder.pending_msg_events.push(events::MessageSendEvent::AddCustomOutput { + node_id: pk_counterparty, + msg: update_add, + }); + + self.custom_outputs.lock().unwrap().insert(custom_output_id, CustomOutput { + channel_id, + local_amount_msat, + remote_amount_msat, + script, + cltv_expiry, + counterparty_node_id: channel.get().get_counterparty_node_id(), + }); + + Ok(custom_output_details) + } + + /// TODO(10101): add doc + pub fn continue_remote_add_custom_output( + &self, + custom_output_id: CustomOutputId, + ) -> Result { + let custom_outputs = self.custom_outputs.lock().unwrap(); + let CustomOutput { channel_id, local_amount_msat, remote_amount_msat, cltv_expiry, script, counterparty_node_id } = custom_outputs.get(&custom_output_id).unwrap(); + + let custom_output_details = self.internal_continue_remote_add_custom_output( + counterparty_node_id, + *channel_id, + custom_output_id, + *local_amount_msat, + *remote_amount_msat, + *cltv_expiry, + script.clone() + ).map_err(|e| format!("Failed to continue with add custom output protocol initiated by remote: {:?}", e.err))?; + + Ok(custom_output_details) + } + + /// TODO(10101): add doc + pub fn manual_send_commitment_signed( + &self, + pk_counterparty: PublicKey, + commitment_signed: CommitmentSigned, + revoke_and_ack: RevokeAndACK, + ) -> Result<(), String> { + let mut channel_holder = self.channel_state.lock().unwrap(); + + channel_holder.pending_msg_events.push(events::MessageSendEvent::UpdateCommitmentOutputs { + node_id: pk_counterparty, + updates: CommitmentUpdate { + update_add_htlcs: Vec::new(), + update_fulfill_htlcs: Vec::new(), + update_fail_htlcs: Vec::new(), + update_fail_malformed_htlcs: Vec::new(), + update_fee: None, + commitment_signed, + update_add_custom_output: Vec::new(), + update_remove_custom_output: Vec::new(), + } + }); + + channel_holder.pending_msg_events.push(events::MessageSendEvent::SendRevokeAndACK { + node_id: pk_counterparty, + msg: revoke_and_ack, + }); + + // TODO(10101): Move channel state forward? + + Ok(()) + } + + /// Remove custom output from channel + pub fn remove_custom_output(&self, custom_output_id: CustomOutputId, local_out_amount: u64) -> Result<(), RemoveCustomOutputError> { + let mut channel_lock = self.channel_state.lock().unwrap(); + + let mut custom_outputs = self.custom_outputs.lock().unwrap(); + let custom_output = custom_outputs.get(&custom_output_id).ok_or(RemoveCustomOutputError::CustomOutputNotFound)?; + + let total_amount_msat = custom_output.local_amount_msat + custom_output.remote_amount_msat; + + if local_out_amount > total_amount_msat { + return Err(RemoveCustomOutputError::InvalidAmounts) + } + + let remote_out_amount = total_amount_msat - local_out_amount; + + let channel_id = custom_output.channel_id; + + let channel_holder = &mut *channel_lock; + let mut channel = match channel_holder.by_id.entry(channel_id.clone()) { + hash_map::Entry::Occupied(channel) => channel, + hash_map::Entry::Vacant(_) => { + return Err(RemoveCustomOutputError::ChannelNotFound); + } + }; + + if !channel.get().is_live() { + return Err(RemoveCustomOutputError::ChannelNotAvailable); + } + + + let pk_counterparty = channel.get().get_counterparty_node_id(); + + let (update_remove_custom_output, commitment_signed, monitor_update) = + match channel.get_mut().remove_custom_output_and_commit(custom_output_id, local_out_amount, remote_out_amount, &self.logger) + { + Ok(res) => res, + Err(e) => { + let (drop, e) = convert_chan_err!(self, e, channel_holder.short_to_chan_info, channel.get_mut(), channel.key()); + if drop { + channel.remove_entry(); + } + match handle_error!(self, Result::<(), _>::Err(e), pk_counterparty) { + Ok(_) => unreachable!(), + Err(_) => { + return Err(RemoveCustomOutputError::ChannelNotAvailable); + }, + } + }, + }; + + let update_err = self.chain_monitor.update_channel(channel.get().get_funding_txo().unwrap(), monitor_update); + let channel_id = channel.get().channel_id(); + match (update_err, + handle_monitor_update_res!(self, update_err, channel_holder, channel, + RAACommitmentOrder::CommitmentFirst, false, true)) + { + (ChannelMonitorUpdateStatus::PermanentFailure, Err(_)) => return Err(RemoveCustomOutputError::ChannelFailed), + (ChannelMonitorUpdateStatus::Completed | ChannelMonitorUpdateStatus::InProgress, res) => { + // TODO(10101): Add entry to a `pending_custom_outputs` field in `ChannelManager`? + // let payment = payment_entry.or_insert_with(|| PendingOutboundPayment::Retryable { + // session_privs: HashSet::new(), + // pending_amt_msat: 0, + // pending_fee_msat: Some(0), + // payment_hash: *payment_hash, + // payment_secret: *payment_secret, + // starting_block_height: self.best_block.read().unwrap().height(), + // total_msat: total_value, + // }); + // assert!(payment.insert(session_priv_bytes, path)); + + if res.is_err() { + return Err(RemoveCustomOutputError::MonitorInProgress); + } + }, + _ => unreachable!(), + } + + log_debug!(self.logger, "Removing custom output resulted in a commitment_signed for channel {}", log_bytes!(channel_id)); + + channel_holder.pending_msg_events.push(events::MessageSendEvent::UpdateCommitmentOutputs { + node_id: pk_counterparty, + updates: msgs::CommitmentUpdate { + update_add_htlcs: Vec::new(), + update_fulfill_htlcs: Vec::new(), + update_fail_htlcs: Vec::new(), + update_fail_malformed_htlcs: Vec::new(), + update_fee: None, + commitment_signed, + update_add_custom_output: Vec::new(), + update_remove_custom_output: vec![update_remove_custom_output] + }, + }); + + + custom_outputs.remove(&custom_output_id); + + Ok(()) + } + /// Retries a payment along the given [`Route`]. /// /// Errors returned are a superset of those returned from [`send_payment`], so see @@ -3254,7 +3605,7 @@ impl ChannelMana } log_debug!(self.logger, "Forwarding HTLCs resulted in a commitment update with {} HTLCs added and {} HTLCs failed for channel {}", add_htlc_msgs.len(), fail_htlc_msgs.len(), log_bytes!(chan.get().channel_id())); - channel_state.pending_msg_events.push(events::MessageSendEvent::UpdateHTLCs { + channel_state.pending_msg_events.push(events::MessageSendEvent::UpdateCommitmentOutputs { node_id: chan.get().get_counterparty_node_id(), updates: msgs::CommitmentUpdate { update_add_htlcs: add_htlc_msgs, @@ -3263,6 +3614,8 @@ impl ChannelMana update_fail_malformed_htlcs: Vec::new(), update_fee: None, commitment_signed: commitment_msg, + update_add_custom_output: Vec::new(), + update_remove_custom_output: Vec::new() }, }); } @@ -3521,7 +3874,7 @@ impl ChannelMana Ok(Some((update_fee, commitment_signed, monitor_update))) => { match self.chain_monitor.update_channel(chan.get_funding_txo().unwrap(), monitor_update) { ChannelMonitorUpdateStatus::Completed => { - pending_msg_events.push(events::MessageSendEvent::UpdateHTLCs { + pending_msg_events.push(events::MessageSendEvent::UpdateCommitmentOutputs { node_id: chan.get_counterparty_node_id(), updates: msgs::CommitmentUpdate { update_add_htlcs: Vec::new(), @@ -3530,6 +3883,8 @@ impl ChannelMana update_fail_malformed_htlcs: Vec::new(), update_fee: Some(update_fee), commitment_signed, + update_add_custom_output: Vec::new(), + update_remove_custom_output: Vec::new() }, }); Ok(()) @@ -4143,7 +4498,7 @@ impl ChannelMana if let Some((msg, commitment_signed)) = msgs { log_debug!(self.logger, "Claiming funds for HTLC with preimage {} resulted in a commitment_signed for channel {}", log_bytes!(payment_preimage.0), log_bytes!(chan.get().channel_id())); - channel_state.pending_msg_events.push(events::MessageSendEvent::UpdateHTLCs { + channel_state.pending_msg_events.push(events::MessageSendEvent::UpdateCommitmentOutputs { node_id: chan.get().get_counterparty_node_id(), updates: msgs::CommitmentUpdate { update_add_htlcs: Vec::new(), @@ -4152,6 +4507,8 @@ impl ChannelMana update_fail_malformed_htlcs: Vec::new(), update_fee: None, commitment_signed, + update_add_custom_output: Vec::new(), + update_remove_custom_output: Vec::new() } }); } @@ -4824,6 +5181,75 @@ impl ChannelMana Ok(()) } + fn internal_update_receive_add_custom_output_request(&self, counterparty_node_id: &PublicKey, channel_id: [u8; 32], custom_output_id: CustomOutputId, local_amount_msat: u64, remote_amount_msat: u64, cltv_expiry: u32, script: Script) -> Result<(), MsgHandleErrInternal> { + // Stored to remember once receiver is ready to continue with the protocol + self.custom_outputs.lock().unwrap().insert(custom_output_id, CustomOutput { + channel_id, + local_amount_msat, + remote_amount_msat, + script, + cltv_expiry, + counterparty_node_id: counterparty_node_id.clone() + }); + + self.pending_events.lock().unwrap().push(Event::RemoteSentAddCustomOutputEvent { custom_output_id }); + + Ok(()) + } + + fn internal_continue_remote_add_custom_output(&self, counterparty_node_id: &PublicKey, channel_id: [u8; 32], custom_output_id: CustomOutputId, local_amount_msat: u64, remote_amount_msat: u64, cltv_expiry: u32, script: Script) -> Result { + let mut channel_holder = self.channel_state.lock().unwrap(); + let channel_state = &mut *channel_holder; + + let (custom_output_details, commitment_signed) = match channel_state.by_id.entry(channel_id) { + hash_map::Entry::Occupied(mut channel) => { + if channel.get().get_counterparty_node_id() != *counterparty_node_id { + return Err(MsgHandleErrInternal::send_err_msg_no_close("Got a message for a channel from the wrong node!".to_owned(), channel_id)); + } + let (custom_output_details, commiment_signed, monitor_update) = try_chan_entry!(self, channel.get_mut().continue_remote_add_custom_output_and_commit(channel_id, custom_output_id, local_amount_msat, remote_amount_msat, cltv_expiry, script, &self.logger), channel_state, channel); + + // TODO(10101): Handle update_err properly + let _update_err = self.chain_monitor.update_channel(channel.get().get_funding_txo().unwrap(), monitor_update); + + (custom_output_details, commiment_signed) + }, + hash_map::Entry::Vacant(_) => return Err(MsgHandleErrInternal::send_err_msg_no_close("Failed to find corresponding channel".to_owned(), channel_id)), + }; + + + + channel_state.pending_msg_events.push(MessageSendEvent::UpdateCommitmentOutputs { node_id: *counterparty_node_id, updates: CommitmentUpdate { + update_add_htlcs: vec![], + update_fulfill_htlcs: vec![], + update_fail_htlcs: vec![], + update_fail_malformed_htlcs: vec![], + update_fee: None, + commitment_signed, + update_add_custom_output: vec![], // TODO(10101): Is this okay? + update_remove_custom_output: vec![], + } }); + + Ok(custom_output_details) + } + + + fn internal_update_remove_custom_output(&self, counterparty_node_id: &PublicKey, channel_id: [u8; 32], custom_output_id: CustomOutputId, local_amount_msat: u64, remote_amount_msat: u64) -> Result<(), MsgHandleErrInternal> { + let mut channel_holder = self.channel_state.lock().unwrap(); + let channel_state = &mut *channel_holder; + + match channel_state.by_id.entry(channel_id) { + hash_map::Entry::Occupied(mut channel) => { + if channel.get().get_counterparty_node_id() != *counterparty_node_id { + return Err(MsgHandleErrInternal::send_err_msg_no_close("Got a message for a channel from the wrong node!".to_owned(), channel_id)); + } + try_chan_entry!(self, channel.get_mut().update_remove_custom_output(channel_id, custom_output_id, local_amount_msat, remote_amount_msat, &self.logger), channel_state, channel); + }, + hash_map::Entry::Vacant(_) => return Err(MsgHandleErrInternal::send_err_msg_no_close("Failed to find corresponding channel".to_owned(), channel_id)), + } + + Ok(()) + } + fn internal_update_fulfill_htlc(&self, counterparty_node_id: &PublicKey, msg: &msgs::UpdateFulfillHTLC) -> Result<(), MsgHandleErrInternal> { let mut channel_lock = self.channel_state.lock().unwrap(); let (htlc_source, forwarded_htlc_value) = { @@ -4884,7 +5310,7 @@ impl ChannelMana if chan.get().get_counterparty_node_id() != *counterparty_node_id { return Err(MsgHandleErrInternal::send_err_msg_no_close("Got a message for a channel from the wrong node!".to_owned(), msg.channel_id)); } - let (revoke_and_ack, commitment_signed, monitor_update) = + let (revoke_and_ack, commitment_signed, monitor_update, should_revoke, did_remote_send_custom_output_commitment_sig) = match chan.get_mut().commitment_signed(&msg, &self.logger) { Err((None, e)) => try_chan_entry!(self, Err(e), channel_state, chan), Err((Some(update), e)) => { @@ -4900,23 +5326,40 @@ impl ChannelMana return Err(e); } - channel_state.pending_msg_events.push(events::MessageSendEvent::SendRevokeAndACK { - node_id: counterparty_node_id.clone(), - msg: revoke_and_ack, - }); - if let Some(msg) = commitment_signed { - channel_state.pending_msg_events.push(events::MessageSendEvent::UpdateHTLCs { + + + if let ShouldRevoke::Yes = should_revoke { + + channel_state.pending_msg_events.push(events::MessageSendEvent::SendRevokeAndACK { node_id: counterparty_node_id.clone(), - updates: msgs::CommitmentUpdate { - update_add_htlcs: Vec::new(), - update_fulfill_htlcs: Vec::new(), - update_fail_htlcs: Vec::new(), - update_fail_malformed_htlcs: Vec::new(), - update_fee: None, - commitment_signed: msg, - }, + msg: revoke_and_ack.clone(), }); } + + if let Some(commitment_signed) = commitment_signed { + if let DidRemoteSendCustomOutputCommitmentSignature::Yes = did_remote_send_custom_output_commitment_sig { + let mut pending_events = self.pending_events.lock().unwrap(); + pending_events.push(Event::RemoteSentCustomOutputCommitmentSignature { + public_key_remote: counterparty_node_id.clone(), + commitment_signed, + revoke_and_ack + }); + } else { + channel_state.pending_msg_events.push(events::MessageSendEvent::UpdateCommitmentOutputs { + node_id: counterparty_node_id.clone(), + updates: msgs::CommitmentUpdate { + update_add_htlcs: Vec::new(), + update_fulfill_htlcs: Vec::new(), + update_fail_htlcs: Vec::new(), + update_fail_malformed_htlcs: Vec::new(), + update_fee: None, + commitment_signed, + update_add_custom_output: Vec::new(), + update_remove_custom_output: Vec::new() + }, + }); + } + } Ok(()) }, hash_map::Entry::Vacant(_) => return Err(MsgHandleErrInternal::send_err_msg_no_close("Failed to find corresponding channel".to_owned(), msg.channel_id)) @@ -4940,11 +5383,11 @@ impl ChannelMana }) { hash_map::Entry::Occupied(mut entry) => { entry.get_mut().push(HTLCForwardInfo::AddHTLC { prev_short_channel_id, prev_funding_outpoint, - prev_htlc_id, forward_info }); + prev_htlc_id, forward_info }); }, hash_map::Entry::Vacant(entry) => { entry.insert(vec!(HTLCForwardInfo::AddHTLC { prev_short_channel_id, prev_funding_outpoint, - prev_htlc_id, forward_info })); + prev_htlc_id, forward_info })); } } } @@ -4994,11 +5437,12 @@ impl ChannelMana } else { unreachable!(); } } if let Some(updates) = raa_updates.commitment_update { - channel_state.pending_msg_events.push(events::MessageSendEvent::UpdateHTLCs { + channel_state.pending_msg_events.push(events::MessageSendEvent::UpdateCommitmentOutputs { node_id: counterparty_node_id.clone(), updates, }); } + break Ok((raa_updates.accepted_htlcs, raa_updates.failed_htlcs, raa_updates.finalized_claimed_htlcs, chan.get().get_short_channel_id() @@ -5258,7 +5702,7 @@ impl ChannelMana if let Some((commitment_update, monitor_update)) = commitment_opt { match self.chain_monitor.update_channel(chan.get_funding_txo().unwrap(), monitor_update) { ChannelMonitorUpdateStatus::Completed => { - pending_msg_events.push(events::MessageSendEvent::UpdateHTLCs { + pending_msg_events.push(events::MessageSendEvent::UpdateCommitmentOutputs { node_id: chan.get_counterparty_node_id(), updates: commitment_update, }); @@ -5549,6 +5993,13 @@ impl ChannelMana } } + /// Gets the custom outputs. + pub fn custom_outputs(&self) -> Vec { + let custom_outputs = self.custom_outputs.lock().unwrap(); + + custom_outputs.keys().copied().collect() + } + #[cfg(any(test, fuzzing, feature = "_test_utils"))] pub fn get_and_clear_pending_events(&self) -> Vec { let events = core::cell::RefCell::new(Vec::new()); @@ -5570,9 +6021,9 @@ impl ChannelMana impl MessageSendEventsProvider for ChannelManager where M::Target: chain::Watch, - T::Target: BroadcasterInterface, - K::Target: KeysInterface, - F::Target: FeeEstimator, + T::Target: BroadcasterInterface, + K::Target: KeysInterface, + F::Target: FeeEstimator, L::Target: Logger, { fn get_and_clear_pending_msg_events(&self) -> Vec { @@ -5954,10 +6405,10 @@ where impl ChannelMessageHandler for ChannelManager where M::Target: chain::Watch, - T::Target: BroadcasterInterface, - K::Target: KeysInterface, - F::Target: FeeEstimator, - L::Target: Logger, + T::Target: BroadcasterInterface, + K::Target: KeysInterface, + F::Target: FeeEstimator, + L::Target: Logger, { fn handle_open_channel(&self, counterparty_node_id: &PublicKey, their_features: InitFeatures, msg: &msgs::OpenChannel) { let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier); @@ -5999,6 +6450,28 @@ impl let _ = handle_error!(self, self.internal_update_add_htlc(counterparty_node_id, msg), *counterparty_node_id); } + fn handle_update_add_custom_output(&self, counterparty_node_id: &PublicKey, msg: &msgs::UpdateAddCustomOutput) { + let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier); + + let msgs::UpdateAddCustomOutput { channel_id, custom_output_id, sender_amount_msat, receiver_amount_msat, cltv_expiry, script } = msg.clone(); + + let local_amount_msat = receiver_amount_msat; + let remote_amount_msat = sender_amount_msat; + + let _ = handle_error!(self, self.internal_update_receive_add_custom_output_request(counterparty_node_id, channel_id, custom_output_id, local_amount_msat, remote_amount_msat, cltv_expiry, script), *counterparty_node_id); + } + + fn handle_update_remove_custom_output(&self, counterparty_node_id: &PublicKey, msg: &msgs::UpdateRemoveCustomOutput) { + let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier); + + let msgs::UpdateRemoveCustomOutput { channel_id, custom_output_id, sender_amount_msat, receiver_amount_msat } = *msg; + + let local_amount_msat = receiver_amount_msat; + let remote_amount_msat = sender_amount_msat; + + let _ = handle_error!(self, self.internal_update_remove_custom_output(counterparty_node_id, channel_id, custom_output_id, local_amount_msat, remote_amount_msat), *counterparty_node_id); + } + fn handle_update_fulfill_htlc(&self, counterparty_node_id: &PublicKey, msg: &msgs::UpdateFulfillHTLC) { let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier); let _ = handle_error!(self, self.internal_update_fulfill_htlc(counterparty_node_id, msg), *counterparty_node_id); @@ -6075,13 +6548,14 @@ impl }); pending_msg_events.retain(|msg| { match msg { + &events::MessageSendEvent::AddCustomOutput { ref node_id, .. } => node_id != counterparty_node_id, &events::MessageSendEvent::SendAcceptChannel { ref node_id, .. } => node_id != counterparty_node_id, &events::MessageSendEvent::SendOpenChannel { ref node_id, .. } => node_id != counterparty_node_id, &events::MessageSendEvent::SendFundingCreated { ref node_id, .. } => node_id != counterparty_node_id, &events::MessageSendEvent::SendFundingSigned { ref node_id, .. } => node_id != counterparty_node_id, &events::MessageSendEvent::SendChannelReady { ref node_id, .. } => node_id != counterparty_node_id, &events::MessageSendEvent::SendAnnouncementSignatures { ref node_id, .. } => node_id != counterparty_node_id, - &events::MessageSendEvent::UpdateHTLCs { ref node_id, .. } => node_id != counterparty_node_id, + &events::MessageSendEvent::UpdateCommitmentOutputs { ref node_id, .. } => node_id != counterparty_node_id, &events::MessageSendEvent::SendRevokeAndACK { ref node_id, .. } => node_id != counterparty_node_id, &events::MessageSendEvent::SendClosingSigned { ref node_id, .. } => node_id != counterparty_node_id, &events::MessageSendEvent::SendShutdown { ref node_id, .. } => node_id != counterparty_node_id, @@ -6567,6 +7041,15 @@ impl_writeable_tlv_based!(PendingInboundPayment, { (8, min_value_msat, required), }); +impl_writeable_tlv_based!(CustomOutput, { + (0, channel_id, required), + (2, local_amount_msat, required), + (4, remote_amount_msat, required), + (6, cltv_expiry, required), + (8, script, required), + (10, counterparty_node_id, required), +}); + impl_writeable_tlv_based_enum_upgradable!(PendingOutboundPayment, (0, Legacy) => { (0, session_privs, required), @@ -6592,10 +7075,10 @@ impl_writeable_tlv_based_enum_upgradable!(PendingOutboundPayment, impl Writeable for ChannelManager where M::Target: chain::Watch, - T::Target: BroadcasterInterface, - K::Target: KeysInterface, - F::Target: FeeEstimator, - L::Target: Logger, + T::Target: BroadcasterInterface, + K::Target: KeysInterface, + F::Target: FeeEstimator, + L::Target: Logger, { fn write(&self, writer: &mut W) -> Result<(), io::Error> { let _consistency_lock = self.total_consistency_lock.write().unwrap(); @@ -6661,6 +7144,7 @@ impl Writeable f let pending_inbound_payments = self.pending_inbound_payments.lock().unwrap(); let pending_outbound_payments = self.pending_outbound_payments.lock().unwrap(); + let custom_outputs = self.custom_outputs.lock().unwrap(); let events = self.pending_events.lock().unwrap(); (events.len() as u64).write(writer)?; for event in events.iter() { @@ -6723,6 +7207,13 @@ impl Writeable f _ => {}, } } + + (custom_outputs.len() as u64).write(writer)?; + for (id, custom_output) in custom_outputs.iter() { + id.write(writer)?; + custom_output.write(writer)?; + } + write_tlv_fields!(writer, { (1, pending_outbound_payments_no_retry, required), (3, pending_outbound_payments, required), @@ -6730,6 +7221,8 @@ impl Writeable f (7, self.fake_scid_rand_bytes, required), (9, htlc_purposes, vec_type), (11, self.probing_cookie_secret, required), + // TODO: is this needed? + (13, custom_outputs, required) }); Ok(()) @@ -6770,10 +7263,10 @@ impl Writeable f /// [`ChainMonitor`]: crate::chain::chainmonitor::ChainMonitor pub struct ChannelManagerReadArgs<'a, Signer: 'a + Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> where M::Target: chain::Watch, - T::Target: BroadcasterInterface, - K::Target: KeysInterface, - F::Target: FeeEstimator, - L::Target: Logger, + T::Target: BroadcasterInterface, + K::Target: KeysInterface, + F::Target: FeeEstimator, + L::Target: Logger, { /// The keys provider which will give us relevant keys. Some keys will be loaded during /// deserialization and KeysInterface::read_chan_signer will be used to read per-Channel @@ -6842,10 +7335,10 @@ impl<'a, Signer: 'a + Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> impl<'a, Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ReadableArgs> for (BlockHash, Arc>) where M::Target: chain::Watch, - T::Target: BroadcasterInterface, - K::Target: KeysInterface, - F::Target: FeeEstimator, - L::Target: Logger, + T::Target: BroadcasterInterface, + K::Target: KeysInterface, + F::Target: FeeEstimator, + L::Target: Logger, { fn read(reader: &mut R, args: ChannelManagerReadArgs<'a, Signer, M, T, K, F, L>) -> Result { let (blockhash, chan_manager) = <(BlockHash, ChannelManager)>::read(reader, args)?; @@ -6856,10 +7349,10 @@ impl<'a, Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> impl<'a, Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ReadableArgs> for (BlockHash, ChannelManager) where M::Target: chain::Watch, - T::Target: BroadcasterInterface, - K::Target: KeysInterface, - F::Target: FeeEstimator, - L::Target: Logger, + T::Target: BroadcasterInterface, + K::Target: KeysInterface, + F::Target: FeeEstimator, + L::Target: Logger, { fn read(reader: &mut R, mut args: ChannelManagerReadArgs<'a, Signer, M, T, K, F, L>) -> Result { let _ver = read_ver_prefix!(reader, SERIALIZATION_VERSION); @@ -6876,6 +7369,7 @@ impl<'a, Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> let mut id_to_peer = HashMap::with_capacity(cmp::min(channel_count as usize, 128)); let mut short_to_chan_info = HashMap::with_capacity(cmp::min(channel_count as usize, 128)); let mut channel_closures = Vec::new(); + // TODO: load custom outputs in channel. Right now, when restarting the node, the custom outputs are gone. for _ in 0..channel_count { let mut channel: Channel = Channel::read(reader, (&args.keys_manager, best_block_height))?; let funding_txo = channel.get_funding_txo().ok_or(DecodeError::InvalidValue)?; @@ -7035,6 +7529,15 @@ impl<'a, Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> }; } + let custom_outputs_count: u64 = Readable::read(reader)?; + let mut custom_outputs: HashMap = + HashMap::with_capacity(cmp::min(custom_outputs_count as usize, MAX_ALLOC_SIZE/32)); + for _ in 0..custom_outputs_count { + if custom_outputs.insert(Readable::read(reader)?, Readable::read(reader)?).is_some() { + return Err(DecodeError::InvalidValue) + }; + } + // pending_outbound_payments_no_retry is for compatibility with 0.0.101 clients. let mut pending_outbound_payments_no_retry: Option>> = None; let mut pending_outbound_payments = None; @@ -7243,6 +7746,7 @@ impl<'a, Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> } } + let channel_manager = ChannelManager { genesis_hash, fee_estimator: bounded_fee_estimator, @@ -7261,6 +7765,8 @@ impl<'a, Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> pending_inbound_payments: Mutex::new(pending_inbound_payments), pending_outbound_payments: Mutex::new(pending_outbound_payments.unwrap()), + custom_outputs: Mutex::new(custom_outputs), + forward_htlcs: Mutex::new(forward_htlcs), outbound_scid_aliases: Mutex::new(outbound_scid_aliases), id_to_peer: Mutex::new(id_to_peer), @@ -8017,7 +8523,7 @@ pub mod bench { expect_payment_claimed!(NodeHolder { node: &$node_b }, payment_hash, 10_000); match $node_b.get_and_clear_pending_msg_events().pop().unwrap() { - MessageSendEvent::UpdateHTLCs { node_id, updates } => { +MessageSendEvent::UpdateCommitmentOutputs { node_id, updates } => { assert_eq!(node_id, $node_a.get_our_node_id()); $node_a.handle_update_fulfill_htlc(&$node_b.get_our_node_id(), &updates.update_fulfill_htlcs[0]); $node_a.handle_commitment_signed(&$node_b.get_our_node_id(), &updates.commitment_signed); diff --git a/lightning/src/ln/functional_test_utils.rs b/lightning/src/ln/functional_test_utils.rs index 6e6155f682b..dd6f6e34f26 100644 --- a/lightning/src/ln/functional_test_utils.rs +++ b/lightning/src/ln/functional_test_utils.rs @@ -420,15 +420,16 @@ macro_rules! get_revoke_commit_msgs { { use $crate::util::events::MessageSendEvent; let events = $node.node.get_and_clear_pending_msg_events(); + dbg!(&events); assert_eq!(events.len(), 2); - (match events[0] { + (match dbg!(&events[0]) { MessageSendEvent::SendRevokeAndACK { ref node_id, ref msg } => { assert_eq!(*node_id, $node_id); (*msg).clone() }, _ => panic!("Unexpected event"), - }, match events[1] { - MessageSendEvent::UpdateHTLCs { ref node_id, ref updates } => { + }, match dbg!(&events[1]) { + MessageSendEvent::UpdateCommitmentOutputs { ref node_id, ref updates } => { assert_eq!(*node_id, $node_id); assert!(updates.update_add_htlcs.is_empty()); assert!(updates.update_fulfill_htlcs.is_empty()); @@ -507,7 +508,7 @@ macro_rules! get_htlc_update_msgs { let events = $node.node.get_and_clear_pending_msg_events(); assert_eq!(events.len(), 1); match events[0] { - $crate::util::events::MessageSendEvent::UpdateHTLCs { ref node_id, ref updates } => { +$crate::util::events::MessageSendEvent::UpdateCommitmentOutputs { ref node_id, ref updates } => { assert_eq!(*node_id, $node_id); (*updates).clone() }, @@ -1131,7 +1132,7 @@ impl SendEvent { pub fn from_event(event: MessageSendEvent) -> SendEvent { match event { - MessageSendEvent::UpdateHTLCs { node_id, updates } => SendEvent::from_commitment_update(node_id, updates), + MessageSendEvent::UpdateCommitmentOutputs { node_id, updates } => SendEvent::from_commitment_update(node_id, updates), _ => panic!("Unexpected event type!"), } } @@ -1217,7 +1218,7 @@ macro_rules! commitment_signed_dance { let channel_state = $node_a.node.channel_state.lock().unwrap(); assert_eq!(channel_state.pending_msg_events.len(), 1); - if let MessageSendEvent::UpdateHTLCs { ref node_id, .. } = channel_state.pending_msg_events[0] { +if let MessageSendEvent::UpdateCommitmentOutputs { ref node_id, .. } = channel_state.pending_msg_events[0] { assert_ne!(*node_id, $node_b.node.get_our_node_id()); } else { panic!("Unexpected event"); } } else { @@ -1736,7 +1737,7 @@ pub fn do_claim_payment_along_route<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, macro_rules! msgs_from_ev { ($ev: expr) => { match $ev { - &MessageSendEvent::UpdateHTLCs { ref node_id, updates: msgs::CommitmentUpdate { ref update_add_htlcs, ref update_fulfill_htlcs, ref update_fail_htlcs, ref update_fail_malformed_htlcs, ref update_fee, ref commitment_signed } } => { + &MessageSendEvent::UpdateCommitmentOutputs { ref node_id, updates: msgs::CommitmentUpdate { ref update_add_htlcs, ref update_fulfill_htlcs, ref update_fail_htlcs, ref update_fail_malformed_htlcs, ref update_fee, ref commitment_signed, .. } } => { assert!(update_add_htlcs.is_empty()); assert_eq!(update_fulfill_htlcs.len(), 1); assert!(update_fail_htlcs.is_empty()); @@ -1912,7 +1913,7 @@ pub fn pass_failed_payment_back<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expe assert_eq!(events.len(), expected_paths.len()); for ev in events.iter() { let (update_fail, commitment_signed, node_id) = match ev { - &MessageSendEvent::UpdateHTLCs { ref node_id, updates: msgs::CommitmentUpdate { ref update_add_htlcs, ref update_fulfill_htlcs, ref update_fail_htlcs, ref update_fail_malformed_htlcs, ref update_fee, ref commitment_signed } } => { + &MessageSendEvent::UpdateCommitmentOutputs { ref node_id, updates: msgs::CommitmentUpdate { ref update_add_htlcs, ref update_fulfill_htlcs, ref update_fail_htlcs, ref update_fail_malformed_htlcs, ref update_fee, ref commitment_signed, .. } } => { assert!(update_add_htlcs.is_empty()); assert!(update_fulfill_htlcs.is_empty()); assert_eq!(update_fail_htlcs.len(), 1); @@ -1946,7 +1947,7 @@ pub fn pass_failed_payment_back<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expe if update_next_node { assert_eq!(events.len(), 1); match events[0] { - MessageSendEvent::UpdateHTLCs { ref node_id, updates: msgs::CommitmentUpdate { ref update_add_htlcs, ref update_fulfill_htlcs, ref update_fail_htlcs, ref update_fail_malformed_htlcs, ref update_fee, ref commitment_signed } } => { + MessageSendEvent::UpdateCommitmentOutputs { ref node_id, updates: msgs::CommitmentUpdate { ref update_add_htlcs, ref update_fulfill_htlcs, ref update_fail_htlcs, ref update_fail_malformed_htlcs, ref update_fee, ref commitment_signed, .. } } => { assert!(update_add_htlcs.is_empty()); assert!(update_fulfill_htlcs.is_empty()); assert_eq!(update_fail_htlcs.len(), 1); @@ -2336,7 +2337,7 @@ macro_rules! handle_chan_reestablish_msgs { idx += 1; RAACommitmentOrder::RevokeAndACKFirst }, - &MessageSendEvent::UpdateHTLCs { ref node_id, ref updates } => { +&MessageSendEvent::UpdateCommitmentOutputs { ref node_id, ref updates } => { assert_eq!(*node_id, $dst_node.node.get_our_node_id()); commitment_update = Some(updates.clone()); idx += 1; @@ -2356,7 +2357,7 @@ macro_rules! handle_chan_reestablish_msgs { revoke_and_ack = Some(msg.clone()); idx += 1; }, - &MessageSendEvent::UpdateHTLCs { ref node_id, ref updates } => { +&MessageSendEvent::UpdateCommitmentOutputs { ref node_id, ref updates } => { assert_eq!(*node_id, $dst_node.node.get_our_node_id()); assert!(commitment_update.is_none()); commitment_update = Some(updates.clone()); diff --git a/lightning/src/ln/functional_tests.rs b/lightning/src/ln/functional_tests.rs index 5d7049b79bb..645b5888068 100644 --- a/lightning/src/ln/functional_tests.rs +++ b/lightning/src/ln/functional_tests.rs @@ -23,7 +23,7 @@ use crate::ln::channel::{commitment_tx_base_weight, COMMITMENT_TX_WEIGHT_PER_HTL use crate::ln::channelmanager::{self, ChannelManager, ChannelManagerReadArgs, PaymentId, RAACommitmentOrder, PaymentSendFailure, BREAKDOWN_TIMEOUT, MIN_CLTV_EXPIRY_DELTA, PAYMENT_EXPIRY_BLOCKS}; use crate::ln::channel::{Channel, ChannelError}; use crate::ln::{chan_utils, onion_utils}; -use crate::ln::chan_utils::{OFFERED_HTLC_SCRIPT_WEIGHT, htlc_success_tx_weight, htlc_timeout_tx_weight, HTLCOutputInCommitment}; +use crate::ln::chan_utils::{OFFERED_HTLC_SCRIPT_WEIGHT, htlc_success_tx_weight, htlc_timeout_tx_weight, HTLCOutputInCommitment, CustomOutputInCommitment}; use crate::routing::gossip::{NetworkGraph, NetworkUpdate}; use crate::routing::router::{PaymentParameters, Route, RouteHop, RouteParameters, find_route, get_route}; use crate::ln::features::{ChannelFeatures, NodeFeatures}; @@ -243,7 +243,7 @@ fn test_async_inbound_update_fee() { let events_0 = nodes[0].node.get_and_clear_pending_msg_events(); assert_eq!(events_0.len(), 1); let (update_msg, commitment_signed) = match events_0[0] { // (1) - MessageSendEvent::UpdateHTLCs { updates: msgs::CommitmentUpdate { ref update_fee, ref commitment_signed, .. }, .. } => { + MessageSendEvent::UpdateCommitmentOutputs { updates: msgs::CommitmentUpdate { ref update_fee, ref commitment_signed, .. }, .. } => { (update_fee.as_ref(), commitment_signed) }, _ => panic!("Unexpected event"), @@ -342,7 +342,7 @@ fn test_update_fee_unordered_raa() { let events_0 = nodes[0].node.get_and_clear_pending_msg_events(); assert_eq!(events_0.len(), 1); let update_msg = match events_0[0] { // (1) - MessageSendEvent::UpdateHTLCs { updates: msgs::CommitmentUpdate { ref update_fee, .. }, .. } => { + MessageSendEvent::UpdateCommitmentOutputs { updates: msgs::CommitmentUpdate { ref update_fee, .. }, .. } => { update_fee.as_ref() }, _ => panic!("Unexpected event"), @@ -416,7 +416,7 @@ fn test_multi_flight_update_fee() { let events_0 = nodes[0].node.get_and_clear_pending_msg_events(); assert_eq!(events_0.len(), 1); let (update_msg_1, commitment_signed_1) = match events_0[0] { // (1) - MessageSendEvent::UpdateHTLCs { updates: msgs::CommitmentUpdate { ref update_fee, ref commitment_signed, .. }, .. } => { + MessageSendEvent::UpdateCommitmentOutputs { updates: msgs::CommitmentUpdate { ref update_fee, ref commitment_signed, .. }, .. } => { (update_fee.as_ref().unwrap(), commitment_signed) }, _ => panic!("Unexpected event"), @@ -600,7 +600,7 @@ fn test_update_fee_vanilla() { let events_0 = nodes[0].node.get_and_clear_pending_msg_events(); assert_eq!(events_0.len(), 1); let (update_msg, commitment_signed) = match events_0[0] { - MessageSendEvent::UpdateHTLCs { node_id:_, updates: msgs::CommitmentUpdate { update_add_htlcs:_, update_fulfill_htlcs:_, update_fail_htlcs:_, update_fail_malformed_htlcs:_, ref update_fee, ref commitment_signed } } => { + MessageSendEvent::UpdateCommitmentOutputs { node_id:_, updates: msgs::CommitmentUpdate { update_add_htlcs:_, update_fulfill_htlcs:_, update_fail_htlcs:_, update_fail_malformed_htlcs:_, ref update_fee, ref commitment_signed, .. } } => { (update_fee.as_ref(), commitment_signed) }, _ => panic!("Unexpected event"), @@ -711,6 +711,7 @@ fn test_update_fee_that_funder_cannot_afford() { let local_chan = local_chan_lock.by_id.get(&chan.2).unwrap(); let local_chan_signer = local_chan.get_signer(); let mut htlcs: Vec<(HTLCOutputInCommitment, ())> = vec![]; + let mut custom_outputs: Vec = vec![]; let commitment_tx = CommitmentTransaction::new_with_auxiliary_htlc_data( INITIAL_COMMITMENT_NUMBER - 1, push_sats, @@ -719,6 +720,7 @@ fn test_update_fee_that_funder_cannot_afford() { commit_tx_keys.clone(), non_buffer_feerate + 4, &mut htlcs, + &mut custom_outputs, &local_chan.channel_transaction_parameters.as_counterparty_broadcastable() ); local_chan_signer.sign_counterparty_commitment(&commitment_tx, Vec::new(), &secp_ctx).unwrap() @@ -755,7 +757,7 @@ fn test_update_fee_with_fundee_update_add_htlc() { let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs); let chan = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features()); - // balancing + // balancing node0 to node1 send_payment(&nodes[0], &vec!(&nodes[1])[..], 8000000); { @@ -765,19 +767,34 @@ fn test_update_fee_with_fundee_update_add_htlc() { nodes[0].node.timer_tick_occurred(); check_added_monitors!(nodes[0], 1); + // node0 what to send to node1 let events_0 = nodes[0].node.get_and_clear_pending_msg_events(); assert_eq!(events_0.len(), 1); let (update_msg, commitment_signed) = match events_0[0] { - MessageSendEvent::UpdateHTLCs { node_id:_, updates: msgs::CommitmentUpdate { update_add_htlcs:_, update_fulfill_htlcs:_, update_fail_htlcs:_, update_fail_malformed_htlcs:_, ref update_fee, ref commitment_signed } } => { + MessageSendEvent::UpdateCommitmentOutputs { node_id:_, updates: msgs::CommitmentUpdate { update_add_htlcs:_, update_fulfill_htlcs:_, update_fail_htlcs:_, update_fail_malformed_htlcs:_, ref update_fee, ref commitment_signed, .. } } => { (update_fee.as_ref(), commitment_signed) }, _ => panic!("Unexpected event"), }; nodes[1].node.handle_update_fee(&nodes[0].node.get_our_node_id(), update_msg.unwrap()); + // node0 send commit and HTLC signatures to node1 nodes[1].node.handle_commitment_signed(&nodes[0].node.get_our_node_id(), commitment_signed); let (revoke_msg, commitment_signed) = get_revoke_commit_msgs!(nodes[1], nodes[0].node.get_our_node_id()); check_added_monitors!(nodes[1], 1); + nodes[0].node.handle_revoke_and_ack(&nodes[1].node.get_our_node_id(), &revoke_msg); + assert!(nodes[0].node.get_and_clear_pending_msg_events().is_empty()); + check_added_monitors!(nodes[0], 1); + + nodes[0].node.handle_commitment_signed(&nodes[1].node.get_our_node_id(), &commitment_signed); + let revoke_msg = get_event_msg!(nodes[0], MessageSendEvent::SendRevokeAndACK, nodes[1].node.get_our_node_id()); + // No commitment_signed so get_event_msg's assert(len == 1) passes + check_added_monitors!(nodes[0], 1); + nodes[1].node.handle_revoke_and_ack(&nodes[0].node.get_our_node_id(), &revoke_msg); + check_added_monitors!(nodes[1], 1); + // AwaitingRemoteRevoke ends here + // is channel rebalancing done? + let (route, our_payment_hash, our_payment_preimage, our_payment_secret) = get_route_and_payment_hash!(nodes[1], nodes[0], 800000); // nothing happens since node[1] is in AwaitingRemoteRevoke @@ -787,21 +804,11 @@ fn test_update_fee_with_fundee_update_add_htlc() { assert_eq!(added_monitors.len(), 0); added_monitors.clear(); } - assert!(nodes[0].node.get_and_clear_pending_events().is_empty()); - assert!(nodes[0].node.get_and_clear_pending_msg_events().is_empty()); + // assert!(nodes[0].node.get_and_clear_pending_events().is_empty()); + // assert!(nodes[0].node.get_and_clear_pending_msg_events().is_empty()); // node[1] has nothing to do - nodes[0].node.handle_revoke_and_ack(&nodes[1].node.get_our_node_id(), &revoke_msg); - assert!(nodes[0].node.get_and_clear_pending_msg_events().is_empty()); - check_added_monitors!(nodes[0], 1); - nodes[0].node.handle_commitment_signed(&nodes[1].node.get_our_node_id(), &commitment_signed); - let revoke_msg = get_event_msg!(nodes[0], MessageSendEvent::SendRevokeAndACK, nodes[1].node.get_our_node_id()); - // No commitment_signed so get_event_msg's assert(len == 1) passes - check_added_monitors!(nodes[0], 1); - nodes[1].node.handle_revoke_and_ack(&nodes[0].node.get_our_node_id(), &revoke_msg); - check_added_monitors!(nodes[1], 1); - // AwaitingRemoteRevoke ends here let commitment_update = get_htlc_update_msgs!(nodes[1], nodes[0].node.get_our_node_id()); assert_eq!(commitment_update.update_add_htlcs.len(), 1); @@ -816,7 +823,7 @@ fn test_update_fee_with_fundee_update_add_htlc() { let (revoke, commitment_signed) = get_revoke_commit_msgs!(nodes[0], nodes[1].node.get_our_node_id()); nodes[1].node.handle_revoke_and_ack(&nodes[0].node.get_our_node_id(), &revoke); - check_added_monitors!(nodes[1], 1); + check_added_monitors!(nodes[1], 2); assert!(nodes[1].node.get_and_clear_pending_msg_events().is_empty()); nodes[1].node.handle_commitment_signed(&nodes[0].node.get_our_node_id(), &commitment_signed); @@ -846,6 +853,349 @@ fn test_update_fee_with_fundee_update_add_htlc() { check_closed_event!(nodes[1], 1, ClosureReason::CooperativeClosure); } +#[test] +fn test_add_custom_output() { + let chanmon_cfgs = create_chanmon_cfgs(2); + let node_cfgs = create_node_cfgs(2, &chanmon_cfgs); + let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]); + let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs); + let chan = create_announced_chan_between_nodes( + &nodes, + 0, + 1, + channelmanager::provided_init_features(), + channelmanager::provided_init_features(), + ); + + dbg!("Balancing"); + // balancing node0 to node1 (apparently we can only send 10k satoshi at a time??) + send_payment(&nodes[0], &vec![&nodes[1]][..], 10_000_000); + + dbg!("Balanced"); + + { + let mut feerate_lock = chanmon_cfgs[0].fee_estimator.sat_per_kw.lock().unwrap(); + *feerate_lock += 20; + } + nodes[0].node.timer_tick_occurred(); + check_added_monitors!(nodes[0], 1); + + // node0 what to send to node1 + let events_0 = nodes[0].node.get_and_clear_pending_msg_events(); + assert_eq!(events_0.len(), 1); + let (update_msg, commitment_signed) = match events_0[0] { + MessageSendEvent::UpdateCommitmentOutputs { + node_id: _, + updates: + msgs::CommitmentUpdate { + update_add_htlcs: _, + update_fulfill_htlcs: _, + update_fail_htlcs: _, + update_fail_malformed_htlcs: _, + ref update_fee, + ref commitment_signed, + .. + }, + } => (update_fee.as_ref(), commitment_signed), + _ => panic!("Unexpected event"), + }; + nodes[1] + .node + .handle_update_fee(&nodes[0].node.get_our_node_id(), update_msg.unwrap()); + // node0 send commit and HTLC signatures to node1 + nodes[1] + .node + .handle_commitment_signed(&nodes[0].node.get_our_node_id(), commitment_signed); + let (revoke_msg, commitment_signed) = + get_revoke_commit_msgs!(nodes[1], nodes[0].node.get_our_node_id()); + check_added_monitors!(nodes[1], 1); + + nodes[0] + .node + .handle_revoke_and_ack(&nodes[1].node.get_our_node_id(), &revoke_msg); + assert!(nodes[0].node.get_and_clear_pending_msg_events().is_empty()); + check_added_monitors!(nodes[0], 1); + + nodes[0] + .node + .handle_commitment_signed(&nodes[1].node.get_our_node_id(), &commitment_signed); + let revoke_msg = get_event_msg!( + nodes[0], + MessageSendEvent::SendRevokeAndACK, + nodes[1].node.get_our_node_id() + ); + // No commitment_signed so get_event_msg's assert(len == 1) passes + check_added_monitors!(nodes[0], 1); + nodes[1] + .node + .handle_revoke_and_ack(&nodes[0].node.get_our_node_id(), &revoke_msg); + check_added_monitors!(nodes[1], 1); + // AwaitingRemoteRevoke ends here + + // channel balancing probably done! + + dbg!("Payment"); + let (route, our_payment_hash, our_payment_preimage, our_payment_secret) = + get_route_and_payment_hash!(nodes[1], nodes[0], 800_000); + + dbg!("Got route for payment"); + + // nothing happens since node[1] is in AwaitingRemoteRevoke + nodes[1] + .node + .send_payment(&route, our_payment_hash, &Some(our_payment_secret)) + .unwrap(); + let commitment_update = get_htlc_update_msgs!(nodes[1], nodes[0].node.get_our_node_id()); + + + // assert_eq!(commitment_update.update_add_htlcs.len(), 1); + // assert_eq!(commitment_update.update_fulfill_htlcs.len(), 0); + // assert_eq!(commitment_update.update_fail_htlcs.len(), 0); + // assert_eq!(commitment_update.update_fail_malformed_htlcs.len(), 0); + // assert_eq!(commitment_update.update_fee.is_none(), true); + + nodes[0].node.handle_update_add_htlc( + &nodes[1].node.get_our_node_id(), + &commitment_update.update_add_htlcs[0], + ); + nodes[0].node.handle_commitment_signed( + &nodes[1].node.get_our_node_id(), + &commitment_update.commitment_signed, + ); + check_added_monitors!(nodes[0], 1); + let (revoke, commitment_signed) = + get_revoke_commit_msgs!(nodes[0], nodes[1].node.get_our_node_id()); + + nodes[1] + .node + .handle_revoke_and_ack(&nodes[0].node.get_our_node_id(), &revoke); + check_added_monitors!(nodes[1], 2); + assert!(nodes[1].node.get_and_clear_pending_msg_events().is_empty()); + + nodes[1] + .node + .handle_commitment_signed(&nodes[0].node.get_our_node_id(), &commitment_signed); + check_added_monitors!(nodes[1], 1); + let revoke = get_event_msg!( + nodes[1], + MessageSendEvent::SendRevokeAndACK, + nodes[0].node.get_our_node_id() + ); + // No commitment_signed so get_event_msg's assert(len == 1) passes + + nodes[0] + .node + .handle_revoke_and_ack(&nodes[1].node.get_our_node_id(), &revoke); + check_added_monitors!(nodes[0], 1); + assert!(nodes[0].node.get_and_clear_pending_msg_events().is_empty()); + + expect_pending_htlcs_forwardable!(nodes[0]); + + let events = nodes[0].node.get_and_clear_pending_events(); + assert_eq!(events.len(), 1); + match events[0] { + Event::PaymentReceived { .. } => {} + _ => panic!("Unexpected event"), + }; + + check_added_monitors!(nodes[1], 0); + // HTLC Fun is over, let's start with custom outputs + + dbg!("Hello"); + + // Node1 starts, is the taker. + // Node0 responds, is the maker. + + let taker = &nodes[1]; + let maker = &nodes[0]; + + // 1. node1 calls get_route() + + let amount_node1_msat = 1_000_000; + let amount_node0_msat = 234_000; + + // TODO: This information should be acquired differently i.e using the new APIs in `lightning-invoice` + let route_to_node0 = get_route!( + taker, + // Should we be reusing `PaymentParameters`? We only want to support trivial routing at + // this stage + PaymentParameters::from_node_id(maker.node.get_our_node_id()), + amount_node1_msat + amount_node0_msat, + TEST_FINAL_CLTV + ) + .unwrap(); + + let RouteHop { + pubkey: pk_counterparty, + short_channel_id, + cltv_expiry_delta: cltv_expiry, + .. + } = route_to_node0.paths + .first() + .unwrap() + .first() + .unwrap() + .clone(); + + // 2. node1.add_custom_output() (similar to send_payment()?) + let custom_output_script = Script::new(); + let custom_output_details = taker.node.add_custom_output(short_channel_id, pk_counterparty, amount_node1_msat, amount_node0_msat, cltv_expiry, custom_output_script).unwrap(); + dbg!("Node1 added custom output"); + + // 3. let (update_fee, commitment_signed) = node1.get_msg_events() + let events_1 = taker.node.get_and_clear_pending_msg_events(); + assert_eq!(events_1.len(), 1); + let update_add_custom_output = match events_1.as_slice() { + [MessageSendEvent::AddCustomOutput { msg, .. }] => msg, + _ => panic!("Unexpected event"), + }; + dbg!("Node1 got msg events"); + + maker + .node + .handle_update_add_custom_output(&taker.node.get_our_node_id(), &update_add_custom_output); + dbg!("Node0 handled update_add_custom_output"); + + // maker + // .node + // .handle_commitment_signed(&taker.node.get_our_node_id(), commitment_signed); + // dbg!("Node0 handled commitment signed"); + // check_added_monitors!(maker, 1); + + let node0_local_events = maker.node.get_and_clear_pending_events(); + let custom_output_id = match node0_local_events.as_slice() { + [Event::RemoteSentAddCustomOutputEvent { custom_output_id }] => custom_output_id, + _ => panic!("Unexpected event"), + }; + dbg!("Node0 got custom_output_id from local event"); + + // CETs are exchanged at the application level here. + + let _custom_output_details_node0 = maker.node.continue_remote_add_custom_output(*custom_output_id).unwrap(); + // _custom_output_details_node0 will be used by application to create CETs + check_added_monitors!(maker, 1); + + // 6. let (revoke_and_ack, commitment_signed) = node0.get_msg_events() + let events_0 = maker.node.get_and_clear_pending_msg_events(); + let commitment_signed = match events_0.as_slice() { + [MessageSendEvent::UpdateCommitmentOutputs { updates, .. }] => updates.commitment_signed.clone(), + _ => panic!("Unexpected event"), + }; + dbg!("Node0 about to send commitment signed"); + + // 7. node1.handle_commitment_signed(commitment_signed) + taker.node.handle_commitment_signed(&maker.node.get_our_node_id(), &commitment_signed); + dbg!("Node1 handled commitment signed"); + check_added_monitors!(taker, 1); + + let events_1 = taker.node.get_and_clear_pending_msg_events(); + assert_eq!(events_1.len(), 0); + + let taker_local_events = taker.node.get_and_clear_pending_events(); + let (commitment_signed, revoke_and_ack) = match taker_local_events.as_slice() { + [Event::RemoteSentCustomOutputCommitmentSignature { commitment_signed, revoke_and_ack, .. }] => (commitment_signed, revoke_and_ack), + _ => panic!("Unexpected event"), + }; + dbg!("Taker was told that maker sent commitment signature"); + + taker.node.manual_send_commitment_signed(maker.node.get_our_node_id(), commitment_signed.clone(), revoke_and_ack.clone()).unwrap(); + dbg!("Taker manual commit"); + + let events_taker = taker.node.get_and_clear_pending_msg_events(); + assert_eq!(events_taker.len(), 2); + + let (commitment_signed, revoke_and_ack) = match events_taker.as_slice() { + [MessageSendEvent::UpdateCommitmentOutputs { updates, .. }, + MessageSendEvent::SendRevokeAndACK { msg, .. }] => (updates.commitment_signed.clone(), msg.clone()), + unexpected_events => { + dbg!(unexpected_events); + panic!("Unexpected event") + }, + }; + dbg!("Taker about to send commitment signed and RAA"); + + maker.node.handle_revoke_and_ack(&taker.node.get_our_node_id(), &revoke_and_ack); + check_added_monitors!(maker, 1); + maker.node.handle_commitment_signed(&taker.node.get_our_node_id(), &commitment_signed); + check_added_monitors!(maker, 1); + + dbg!("Maker sent commitment signed and RAA"); + + let revoke_and_ack_maker = get_event_msg!(maker, MessageSendEvent::SendRevokeAndACK, taker.node.get_our_node_id()); + + // 7. taker.handle_revoke_and_ack(revoke_and_ack) + taker.node.handle_revoke_and_ack(&maker.node.get_our_node_id(), &revoke_and_ack_maker); + dbg!("Taker handled revoke and ack"); + + check_added_monitors!(taker, 1); + + assert_eq!(taker.node.get_and_clear_pending_msg_events().len(), 0); + + dbg!("Custom output added"); + + // Let's remove the custom output collaboratively + + let full_amount = amount_node0_msat + amount_node1_msat; + taker.node.remove_custom_output(custom_output_details.id, full_amount / 2).unwrap(); + + dbg!("Taker called `remove_custom_outputs`"); + check_added_monitors!(taker, 1); + + let events_1 = taker.node.get_and_clear_pending_msg_events(); + assert_eq!(events_1.len(), 1); + let (_update_fee, update_remove_custom_output, commitment_signed) = match events_1.as_slice() { + [MessageSendEvent::UpdateCommitmentOutputs { + updates: + msgs::CommitmentUpdate { + ref update_fee, + ref commitment_signed, + ref update_remove_custom_output, + .. + }, + .. + }] => (update_fee.as_ref(), update_remove_custom_output, commitment_signed), + _ => panic!("Unexpected event"), + }; + + dbg!("Taker got msg events to remove custom output"); + + maker + .node + .handle_update_remove_custom_output(&taker.node.get_our_node_id(), &update_remove_custom_output[0]); + + maker + .node + .handle_commitment_signed(&taker.node.get_our_node_id(), commitment_signed); + dbg!("Maker handled commitment after remove signed"); + check_added_monitors!(maker, 1); + + let (revoke, commitment_signed) = get_revoke_commit_msgs!(maker, taker.node.get_our_node_id()); + + taker.node.handle_revoke_and_ack(&maker.node.get_our_node_id(), &revoke); + dbg!("Taker handled revoke and ack for remove"); + check_added_monitors!(taker, 1); + + taker.node.handle_commitment_signed(&maker.node.get_our_node_id(), &commitment_signed); + dbg!("Taker handled commitment signed for remove"); + check_added_monitors!(taker, 1); + + let revoke = get_event_msg!(taker, MessageSendEvent::SendRevokeAndACK, maker.node.get_our_node_id()); + + // 10. node0.handle_revoke_and_ack(revoke_and_ack) + maker.node.handle_revoke_and_ack(&taker.node.get_our_node_id(), &revoke); + check_added_monitors!(maker, 1); + + dbg!("Custom output removed"); + + claim_payment(&taker, &vec!(maker)[..], our_payment_preimage); + + send_payment(taker, &vec!(maker)[..], 800000); + send_payment(maker, &vec!(taker)[..], 800000); + close_channel(maker, taker, &chan.2, chan.3, true); + check_closed_event!(maker, 1, ClosureReason::CooperativeClosure); + check_closed_event!(taker, 1, ClosureReason::CooperativeClosure); +} + #[test] fn test_update_fee() { let chanmon_cfgs = create_chanmon_cfgs(2); @@ -882,7 +1232,7 @@ fn test_update_fee() { let events_0 = nodes[0].node.get_and_clear_pending_msg_events(); assert_eq!(events_0.len(), 1); let (update_msg, commitment_signed) = match events_0[0] { - MessageSendEvent::UpdateHTLCs { node_id:_, updates: msgs::CommitmentUpdate { update_add_htlcs:_, update_fulfill_htlcs:_, update_fail_htlcs:_, update_fail_malformed_htlcs:_, ref update_fee, ref commitment_signed } } => { + MessageSendEvent::UpdateCommitmentOutputs { node_id:_, updates: msgs::CommitmentUpdate { update_add_htlcs:_, update_fulfill_htlcs:_, update_fail_htlcs:_, update_fail_malformed_htlcs:_, ref update_fee, ref commitment_signed, .. } } => { (update_fee.as_ref(), commitment_signed) }, _ => panic!("Unexpected event"), @@ -909,7 +1259,7 @@ fn test_update_fee() { let events_0 = nodes[0].node.get_and_clear_pending_msg_events(); assert_eq!(events_0.len(), 1); let (update_msg, commitment_signed) = match events_0[0] { - MessageSendEvent::UpdateHTLCs { node_id:_, updates: msgs::CommitmentUpdate { update_add_htlcs:_, update_fulfill_htlcs:_, update_fail_htlcs:_, update_fail_malformed_htlcs:_, ref update_fee, ref commitment_signed } } => { + MessageSendEvent::UpdateCommitmentOutputs { node_id:_, updates: msgs::CommitmentUpdate { update_add_htlcs:_, update_fulfill_htlcs:_, update_fail_htlcs:_, update_fail_malformed_htlcs:_, ref update_fee, ref commitment_signed, .. } } => { (update_fee.as_ref(), commitment_signed) }, _ => panic!("Unexpected event"), @@ -1303,7 +1653,7 @@ fn test_duplicate_htlc_different_direction_onchain() { assert_eq!(node_id, nodes[1].node.get_our_node_id()); assert_eq!(msg.data, "Channel closed because commitment or closing transaction was confirmed on chain."); }, - MessageSendEvent::UpdateHTLCs { ref node_id, updates: msgs::CommitmentUpdate { ref update_add_htlcs, ref update_fulfill_htlcs, ref update_fail_htlcs, ref update_fail_malformed_htlcs, .. } } => { + MessageSendEvent::UpdateCommitmentOutputs { ref node_id, updates: msgs::CommitmentUpdate { ref update_add_htlcs, ref update_fulfill_htlcs, ref update_fail_htlcs, ref update_fail_malformed_htlcs, .. } } => { assert!(update_add_htlcs.is_empty()); assert!(update_fail_htlcs.is_empty()); assert_eq!(update_fulfill_htlcs.len(), 1); @@ -1439,6 +1789,7 @@ fn test_fee_spike_violation_fails_htlc() { commit_tx_keys.clone(), feerate_per_kw, &mut vec![(accepted_htlc_info, ())], + &mut vec![], &local_chan.channel_transaction_parameters.as_counterparty_broadcastable() ); local_chan_signer.sign_counterparty_commitment(&commitment_tx, Vec::new(), &secp_ctx).unwrap() @@ -1466,7 +1817,7 @@ fn test_fee_spike_violation_fails_htlc() { assert_eq!(events.len(), 1); // Make sure the HTLC failed in the way we expect. match events[0] { - MessageSendEvent::UpdateHTLCs { updates: msgs::CommitmentUpdate { ref update_fail_htlcs, .. }, .. } => { + MessageSendEvent::UpdateCommitmentOutputs { updates: msgs::CommitmentUpdate { ref update_fail_htlcs, .. }, .. } => { assert_eq!(update_fail_htlcs.len(), 1); update_fail_htlcs[0].clone() }, @@ -2231,7 +2582,7 @@ fn channel_monitor_network_test() { let events = $node.node.get_and_clear_pending_msg_events(); assert_eq!(events.len(), 1); match events[0] { - MessageSendEvent::UpdateHTLCs { ref node_id, updates: msgs::CommitmentUpdate { ref update_add_htlcs, ref update_fail_htlcs, .. } } => { +MessageSendEvent::UpdateCommitmentOutputs { ref node_id, updates: msgs::CommitmentUpdate { ref update_add_htlcs, ref update_fail_htlcs, .. } } => { assert!(update_add_htlcs.is_empty()); assert!(update_fail_htlcs.is_empty()); assert_eq!(*node_id, $prev_node.node.get_our_node_id()); @@ -2764,7 +3115,7 @@ fn test_htlc_on_chain_success() { } match events[2] { - MessageSendEvent::UpdateHTLCs { ref node_id, updates: msgs::CommitmentUpdate { ref update_add_htlcs, ref update_fail_htlcs, ref update_fulfill_htlcs, ref update_fail_malformed_htlcs, .. } } => { + MessageSendEvent::UpdateCommitmentOutputs { ref node_id, updates: msgs::CommitmentUpdate { ref update_add_htlcs, ref update_fail_htlcs, ref update_fulfill_htlcs, ref update_fail_malformed_htlcs, .. } } => { assert!(update_add_htlcs.is_empty()); assert!(update_fail_htlcs.is_empty()); assert_eq!(update_fulfill_htlcs.len(), 1); @@ -2873,9 +3224,9 @@ fn do_test_htlc_on_chain_timeout(connect_style: ConnectStyle) { // timeout the HTLC backward accordingly. So here we test that ChannelManager is // broadcasting the right event to other nodes in payment path. // A ------------------> B ----------------------> C (timeout) - // B's commitment tx C's commitment tx - // \ \ - // B's HTLC timeout tx B's timeout tx + // B's commitment tx C's commitment tx + // \ \ + // B's HTLC timeout tx B's timeout tx let chanmon_cfgs = create_chanmon_cfgs(3); let node_cfgs = create_node_cfgs(3, &chanmon_cfgs); @@ -2906,7 +3257,7 @@ fn do_test_htlc_on_chain_timeout(connect_style: ConnectStyle) { let events = nodes[2].node.get_and_clear_pending_msg_events(); assert_eq!(events.len(), 1); match events[0] { - MessageSendEvent::UpdateHTLCs { ref node_id, updates: msgs::CommitmentUpdate { ref update_add_htlcs, ref update_fulfill_htlcs, ref update_fail_htlcs, ref update_fail_malformed_htlcs, .. } } => { + MessageSendEvent::UpdateCommitmentOutputs { ref node_id, updates: msgs::CommitmentUpdate { ref update_add_htlcs, ref update_fulfill_htlcs, ref update_fail_htlcs, ref update_fail_malformed_htlcs, .. } } => { assert!(update_add_htlcs.is_empty()); assert!(!update_fail_htlcs.is_empty()); assert!(update_fulfill_htlcs.is_empty()); @@ -2977,7 +3328,7 @@ fn do_test_htlc_on_chain_timeout(connect_style: ConnectStyle) { let events = nodes[1].node.get_and_clear_pending_msg_events(); assert_eq!(events.len(), 1); match events[0] { - MessageSendEvent::UpdateHTLCs { ref node_id, updates: msgs::CommitmentUpdate { ref update_add_htlcs, ref update_fail_htlcs, ref update_fulfill_htlcs, ref update_fail_malformed_htlcs, .. } } => { + MessageSendEvent::UpdateCommitmentOutputs { ref node_id, updates: msgs::CommitmentUpdate { ref update_add_htlcs, ref update_fail_htlcs, ref update_fulfill_htlcs, ref update_fail_malformed_htlcs, .. } } => { assert!(update_add_htlcs.is_empty()); assert!(!update_fail_htlcs.is_empty()); assert!(update_fulfill_htlcs.is_empty()); @@ -3045,7 +3396,7 @@ fn test_simple_commitment_revoked_fail_backward() { let events = nodes[1].node.get_and_clear_pending_msg_events(); assert_eq!(events.len(), 1); match events[0] { - MessageSendEvent::UpdateHTLCs { ref node_id, updates: msgs::CommitmentUpdate { ref update_add_htlcs, ref update_fail_htlcs, ref update_fulfill_htlcs, ref update_fail_malformed_htlcs, ref commitment_signed, .. } } => { + MessageSendEvent::UpdateCommitmentOutputs { ref node_id, updates: msgs::CommitmentUpdate { ref update_add_htlcs, ref update_fail_htlcs, ref update_fulfill_htlcs, ref update_fail_malformed_htlcs, ref commitment_signed, .. } } => { assert!(update_add_htlcs.is_empty()); assert_eq!(update_fail_htlcs.len(), 1); assert!(update_fulfill_htlcs.is_empty()); @@ -3228,7 +3579,7 @@ fn do_test_commitment_revoked_fail_backward_exhaustive(deliver_bs_raa: bool, use } if deliver_bs_raa { match events[0] { - MessageSendEvent::UpdateHTLCs { ref node_id, updates: msgs::CommitmentUpdate { ref update_add_htlcs, ref update_fail_htlcs, ref update_fulfill_htlcs, ref update_fail_malformed_htlcs, .. } } => { + MessageSendEvent::UpdateCommitmentOutputs { ref node_id, updates: msgs::CommitmentUpdate { ref update_add_htlcs, ref update_fail_htlcs, ref update_fulfill_htlcs, ref update_fail_malformed_htlcs, .. } } => { assert_eq!(nodes[2].node.get_our_node_id(), *node_id); assert_eq!(update_add_htlcs.len(), 1); assert!(update_fulfill_htlcs.is_empty()); @@ -3239,7 +3590,7 @@ fn do_test_commitment_revoked_fail_backward_exhaustive(deliver_bs_raa: bool, use } } match events[if deliver_bs_raa { 3 } else { 2 }] { - MessageSendEvent::UpdateHTLCs { ref node_id, updates: msgs::CommitmentUpdate { ref update_add_htlcs, ref update_fail_htlcs, ref update_fulfill_htlcs, ref update_fail_malformed_htlcs, ref commitment_signed, .. } } => { + MessageSendEvent::UpdateCommitmentOutputs { ref node_id, updates: msgs::CommitmentUpdate { ref update_add_htlcs, ref update_fail_htlcs, ref update_fulfill_htlcs, ref update_fail_malformed_htlcs, ref commitment_signed, .. } } => { assert!(update_add_htlcs.is_empty()); assert_eq!(update_fail_htlcs.len(), 3); assert!(update_fulfill_htlcs.is_empty()); @@ -3747,7 +4098,7 @@ fn do_test_drop_messages_peer_disconnect(messages_delivered: u8, simulate_broken let events_3 = nodes[1].node.get_and_clear_pending_msg_events(); assert_eq!(events_3.len(), 1); let (update_fulfill_htlc, commitment_signed) = match events_3[0] { - MessageSendEvent::UpdateHTLCs { ref node_id, ref updates } => { + MessageSendEvent::UpdateCommitmentOutputs { ref node_id, ref updates } => { assert_eq!(*node_id, nodes[0].node.get_our_node_id()); assert!(updates.update_add_htlcs.is_empty()); assert!(updates.update_fail_htlcs.is_empty()); @@ -4076,7 +4427,7 @@ fn test_drop_messages_peer_disconnect_dual_htlc() { let events_1 = nodes[0].node.get_and_clear_pending_msg_events(); assert_eq!(events_1.len(), 1); match events_1[0] { - MessageSendEvent::UpdateHTLCs { .. } => {}, + MessageSendEvent::UpdateCommitmentOutputs { .. } => {}, _ => panic!("Unexpected event"), } @@ -4087,7 +4438,7 @@ fn test_drop_messages_peer_disconnect_dual_htlc() { let events_2 = nodes[1].node.get_and_clear_pending_msg_events(); assert_eq!(events_2.len(), 1); match events_2[0] { - MessageSendEvent::UpdateHTLCs { ref node_id, updates: msgs::CommitmentUpdate { ref update_add_htlcs, ref update_fulfill_htlcs, ref update_fail_htlcs, ref update_fail_malformed_htlcs, ref update_fee, ref commitment_signed } } => { + MessageSendEvent::UpdateCommitmentOutputs { ref node_id, updates: msgs::CommitmentUpdate { ref update_add_htlcs, ref update_fulfill_htlcs, ref update_fail_htlcs, ref update_fail_malformed_htlcs, ref update_fee, ref commitment_signed, .. } } => { assert_eq!(*node_id, nodes[0].node.get_our_node_id()); assert!(update_add_htlcs.is_empty()); assert_eq!(update_fulfill_htlcs.len(), 1); @@ -4316,7 +4667,7 @@ fn do_test_holding_cell_htlc_add_timeouts(forwarded_htlc: bool) { let fail_commit = nodes[1].node.get_and_clear_pending_msg_events(); assert_eq!(fail_commit.len(), 1); match fail_commit[0] { - MessageSendEvent::UpdateHTLCs { updates: msgs::CommitmentUpdate { ref update_fail_htlcs, ref commitment_signed, .. }, .. } => { + MessageSendEvent::UpdateCommitmentOutputs { updates: msgs::CommitmentUpdate { ref update_fail_htlcs, ref commitment_signed, .. }, .. } => { nodes[0].node.handle_update_fail_htlc(&nodes[1].node.get_our_node_id(), &update_fail_htlcs[0]); commitment_signed_dance!(nodes[0], nodes[1], commitment_signed, true, true); }, @@ -4879,7 +5230,7 @@ fn test_static_spendable_outputs_preimage_tx() { check_added_monitors!(nodes[1], 1); let events = nodes[1].node.get_and_clear_pending_msg_events(); match events[0] { - MessageSendEvent::UpdateHTLCs { .. } => {}, + MessageSendEvent::UpdateCommitmentOutputs { .. } => {}, _ => panic!("Unexpected event"), } match events[1] { @@ -5232,7 +5583,7 @@ fn test_onchain_to_onchain_claim() { _ => panic!("Unexpected event"), } match msg_events[2] { - MessageSendEvent::UpdateHTLCs { ref node_id, updates: msgs::CommitmentUpdate { ref update_add_htlcs, ref update_fulfill_htlcs, ref update_fail_htlcs, ref update_fail_malformed_htlcs, .. } } => { + MessageSendEvent::UpdateCommitmentOutputs { ref node_id, updates: msgs::CommitmentUpdate { ref update_add_htlcs, ref update_fulfill_htlcs, ref update_fail_htlcs, ref update_fail_malformed_htlcs, .. } } => { assert!(update_add_htlcs.is_empty()); assert!(update_fail_htlcs.is_empty()); assert_eq!(update_fulfill_htlcs.len(), 1); @@ -5344,7 +5695,7 @@ fn test_duplicate_payment_hash_one_failure_one_success() { check_closed_event!(nodes[2], 1, ClosureReason::CommitmentTxConfirmed); let events = nodes[2].node.get_and_clear_pending_msg_events(); match events[0] { - MessageSendEvent::UpdateHTLCs { .. } => {}, + MessageSendEvent::UpdateCommitmentOutputs { .. } => {}, _ => panic!("Unexpected event"), } match events[1] { @@ -5435,7 +5786,7 @@ fn test_dynamic_spendable_outputs_local_htlc_success_tx() { check_closed_event!(nodes[1], 1, ClosureReason::CommitmentTxConfirmed); let events = nodes[1].node.get_and_clear_pending_msg_events(); match events[0] { - MessageSendEvent::UpdateHTLCs { .. } => {}, + MessageSendEvent::UpdateCommitmentOutputs { .. } => {}, _ => panic!("Unexpected event"), } match events[1] { @@ -5657,7 +6008,7 @@ fn do_test_fail_backwards_unrevoked_remote_announce(deliver_last_raa: bool, anno let mut a_done = false; for msg in cs_msgs { match msg { - MessageSendEvent::UpdateHTLCs { ref node_id, ref updates } => { + MessageSendEvent::UpdateCommitmentOutputs { ref node_id, ref updates } => { // Both under-dust HTLCs and the one above-dust HTLC that we had already failed // should be failed-backwards here. let target = if *node_id == nodes[0].node.get_our_node_id() { @@ -5813,7 +6164,7 @@ fn test_dynamic_spendable_outputs_local_htlc_timeout_tx() { assert_eq!(spend_txn[2].input.len(), 2); check_spends!(spend_txn[2], local_txn[0], htlc_timeout); assert!(spend_txn[2].input[0].sequence.0 == BREAKDOWN_TIMEOUT as u32 || - spend_txn[2].input[1].sequence.0 == BREAKDOWN_TIMEOUT as u32); + spend_txn[2].input[1].sequence.0 == BREAKDOWN_TIMEOUT as u32); } #[test] @@ -5896,7 +6247,7 @@ fn test_key_derivation_params() { assert_eq!(spend_txn[2].input.len(), 2); check_spends!(spend_txn[2], local_txn_1[0], htlc_timeout); assert!(spend_txn[2].input[0].sequence.0 == BREAKDOWN_TIMEOUT as u32 || - spend_txn[2].input[1].sequence.0 == BREAKDOWN_TIMEOUT as u32); + spend_txn[2].input[1].sequence.0 == BREAKDOWN_TIMEOUT as u32); } #[test] @@ -6204,7 +6555,7 @@ fn test_fail_holding_cell_htlc_upon_free() { let events = nodes[0].node.get_and_clear_pending_msg_events(); assert_eq!(events.len(), 1); let (update_msg, commitment_signed) = match events[0] { - MessageSendEvent::UpdateHTLCs { updates: msgs::CommitmentUpdate { ref update_fee, ref commitment_signed, .. }, .. } => { + MessageSendEvent::UpdateCommitmentOutputs { updates: msgs::CommitmentUpdate { ref update_fee, ref commitment_signed, .. }, .. } => { (update_fee.as_ref(), commitment_signed) }, _ => panic!("Unexpected event"), @@ -6282,7 +6633,7 @@ fn test_free_and_fail_holding_cell_htlcs() { let events = nodes[0].node.get_and_clear_pending_msg_events(); assert_eq!(events.len(), 1); let (update_msg, commitment_signed) = match events[0] { - MessageSendEvent::UpdateHTLCs { updates: msgs::CommitmentUpdate { ref update_fee, ref commitment_signed, .. }, .. } => { + MessageSendEvent::UpdateCommitmentOutputs { updates: msgs::CommitmentUpdate { ref update_fee, ref commitment_signed, .. }, .. } => { (update_fee.as_ref(), commitment_signed) }, _ => panic!("Unexpected event"), @@ -6408,7 +6759,7 @@ fn test_fail_holding_cell_htlc_upon_free_multihop() { let events = nodes[1].node.get_and_clear_pending_msg_events(); assert_eq!(events.len(), 1); let (update_msg, commitment_signed) = match events[0] { - MessageSendEvent::UpdateHTLCs { updates: msgs::CommitmentUpdate { ref update_fee, ref commitment_signed, .. }, .. } => { + MessageSendEvent::UpdateCommitmentOutputs { updates: msgs::CommitmentUpdate { ref update_fee, ref commitment_signed, .. }, .. } => { (update_fee.as_ref(), commitment_signed) }, _ => panic!("Unexpected event"), @@ -6482,7 +6833,7 @@ fn test_fail_holding_cell_htlc_upon_free_multihop() { let fail_event = nodes[1].node.get_and_clear_pending_msg_events(); assert_eq!(fail_event.len(), 1); let (fail_msg, commitment_signed) = match &fail_event[0] { - &MessageSendEvent::UpdateHTLCs { ref updates, .. } => { + &MessageSendEvent::UpdateCommitmentOutputs { ref updates, .. } => { assert_eq!(updates.update_add_htlcs.len(), 0); assert_eq!(updates.update_fulfill_htlcs.len(), 0); assert_eq!(updates.update_fail_malformed_htlcs.len(), 0); @@ -6613,7 +6964,7 @@ fn test_update_add_htlc_bolt2_sender_exceed_max_htlc_num_and_htlc_id_increment() let mut events = nodes[0].node.get_and_clear_pending_msg_events(); assert_eq!(events.len(), 1); - if let MessageSendEvent::UpdateHTLCs { node_id: _, updates: msgs::CommitmentUpdate{ update_add_htlcs: ref htlcs, .. }, } = events[0] { + if let MessageSendEvent::UpdateCommitmentOutputs { node_id: _, updates: msgs::CommitmentUpdate{ update_add_htlcs: ref htlcs, .. }, } = events[0] { assert_eq!(htlcs[0].htlc_id, i); } else { assert!(false); @@ -6971,7 +7322,7 @@ fn test_update_fulfill_htlc_bolt2_incorrect_htlc_id() { assert_eq!(events.len(), 1); let mut update_fulfill_msg: msgs::UpdateFulfillHTLC = { match events[0] { - MessageSendEvent::UpdateHTLCs { node_id: _ , updates: msgs::CommitmentUpdate { ref update_add_htlcs, ref update_fulfill_htlcs, ref update_fail_htlcs, ref update_fail_malformed_htlcs, ref update_fee, .. } } => { + MessageSendEvent::UpdateCommitmentOutputs { node_id: _ , updates: msgs::CommitmentUpdate { ref update_add_htlcs, ref update_fulfill_htlcs, ref update_fail_htlcs, ref update_fail_malformed_htlcs, ref update_fee, .. } } => { assert!(update_add_htlcs.is_empty()); assert_eq!(update_fulfill_htlcs.len(), 1); assert!(update_fail_htlcs.is_empty()); @@ -7014,7 +7365,7 @@ fn test_update_fulfill_htlc_bolt2_wrong_preimage() { assert_eq!(events.len(), 1); let mut update_fulfill_msg: msgs::UpdateFulfillHTLC = { match events[0] { - MessageSendEvent::UpdateHTLCs { node_id: _ , updates: msgs::CommitmentUpdate { ref update_add_htlcs, ref update_fulfill_htlcs, ref update_fail_htlcs, ref update_fail_malformed_htlcs, ref update_fee, .. } } => { + MessageSendEvent::UpdateCommitmentOutputs { node_id: _ , updates: msgs::CommitmentUpdate { ref update_add_htlcs, ref update_fulfill_htlcs, ref update_fail_htlcs, ref update_fail_malformed_htlcs, ref update_fee, .. } } => { assert!(update_add_htlcs.is_empty()); assert_eq!(update_fulfill_htlcs.len(), 1); assert!(update_fail_htlcs.is_empty()); @@ -7062,7 +7413,7 @@ fn test_update_fulfill_htlc_bolt2_missing_badonion_bit_for_malformed_htlc_messag let mut update_msg: msgs::UpdateFailMalformedHTLC = { match events[0] { - MessageSendEvent::UpdateHTLCs { node_id: _ , updates: msgs::CommitmentUpdate { ref update_add_htlcs, ref update_fulfill_htlcs, ref update_fail_htlcs, ref update_fail_malformed_htlcs, ref update_fee, .. } } => { + MessageSendEvent::UpdateCommitmentOutputs { node_id: _ , updates: msgs::CommitmentUpdate { ref update_add_htlcs, ref update_fulfill_htlcs, ref update_fail_htlcs, ref update_fail_malformed_htlcs, ref update_fee, .. } } => { assert!(update_add_htlcs.is_empty()); assert!(update_fulfill_htlcs.is_empty()); assert!(update_fail_htlcs.is_empty()); @@ -7125,7 +7476,7 @@ fn test_update_fulfill_htlc_bolt2_after_malformed_htlc_message_must_forward_upda assert_eq!(events_3.len(), 1); let update_msg : (msgs::UpdateFailMalformedHTLC, msgs::CommitmentSigned) = { match events_3[0] { - MessageSendEvent::UpdateHTLCs { node_id: _ , updates: msgs::CommitmentUpdate { ref update_add_htlcs, ref update_fulfill_htlcs, ref update_fail_htlcs, ref update_fail_malformed_htlcs, ref update_fee, ref commitment_signed } } => { + MessageSendEvent::UpdateCommitmentOutputs { node_id: _ , updates: msgs::CommitmentUpdate { ref update_add_htlcs, ref update_fulfill_htlcs, ref update_fail_htlcs, ref update_fail_malformed_htlcs, ref update_fee, ref commitment_signed, .. } } => { assert!(update_add_htlcs.is_empty()); assert!(update_fulfill_htlcs.is_empty()); assert!(update_fail_htlcs.is_empty()); @@ -7147,7 +7498,7 @@ fn test_update_fulfill_htlc_bolt2_after_malformed_htlc_message_must_forward_upda //Confirm that handlinge the update_malformed_htlc message produces an update_fail_htlc message to be forwarded back along the route match events_4[0] { - MessageSendEvent::UpdateHTLCs { node_id: _ , updates: msgs::CommitmentUpdate { ref update_add_htlcs, ref update_fulfill_htlcs, ref update_fail_htlcs, ref update_fail_malformed_htlcs, ref update_fee, .. } } => { + MessageSendEvent::UpdateCommitmentOutputs { node_id: _ , updates: msgs::CommitmentUpdate { ref update_add_htlcs, ref update_fulfill_htlcs, ref update_fail_htlcs, ref update_fail_malformed_htlcs, ref update_fee, .. } } => { assert!(update_add_htlcs.is_empty()); assert!(update_fulfill_htlcs.is_empty()); assert_eq!(update_fail_htlcs.len(), 1); @@ -7194,7 +7545,7 @@ fn test_channel_failed_after_message_with_badonion_node_perm_bits_set() { let events_3 = nodes[2].node.get_and_clear_pending_msg_events(); assert_eq!(events_3.len(), 1); match events_3[0] { - MessageSendEvent::UpdateHTLCs { ref updates, .. } => { + MessageSendEvent::UpdateCommitmentOutputs { ref updates, .. } => { let mut update_msg = updates.update_fail_malformed_htlcs[0].clone(); // Set the NODE bit (BADONION and PERM already set in invalid_onion_version error) update_msg.failure_code |= 0x2000; @@ -7213,7 +7564,7 @@ fn test_channel_failed_after_message_with_badonion_node_perm_bits_set() { check_added_monitors!(nodes[1], 1); match events_4[0] { - MessageSendEvent::UpdateHTLCs { ref updates, .. } => { + MessageSendEvent::UpdateCommitmentOutputs { ref updates, .. } => { nodes[0].node.handle_update_fail_htlc(&nodes[1].node.get_our_node_id(), &updates.update_fail_htlcs[0]); commitment_signed_dance!(nodes[0], nodes[1], updates.commitment_signed, false, true); }, @@ -7283,7 +7634,7 @@ fn do_test_failure_delay_dust_htlc_local_commitment(announce_latest: bool) { _ => panic!("Unexpected event"), } match events[1] { - MessageSendEvent::UpdateHTLCs { node_id, .. } => { + MessageSendEvent::UpdateCommitmentOutputs { node_id, .. } => { assert_eq!(node_id, nodes[1].node.get_our_node_id()); }, _ => panic!("Unexpected event"), @@ -7675,7 +8026,7 @@ fn test_check_htlc_underpaying() { let events = nodes[1].node.get_and_clear_pending_msg_events(); assert_eq!(events.len(), 1); let (update_fail_htlc, commitment_signed) = match events[0] { - MessageSendEvent::UpdateHTLCs { node_id: _ , updates: msgs::CommitmentUpdate { ref update_add_htlcs, ref update_fulfill_htlcs, ref update_fail_htlcs, ref update_fail_malformed_htlcs, ref update_fee, ref commitment_signed } } => { + MessageSendEvent::UpdateCommitmentOutputs { node_id: _ , updates: msgs::CommitmentUpdate { ref update_add_htlcs, ref update_fulfill_htlcs, ref update_fail_htlcs, ref update_fail_malformed_htlcs, ref update_fee, ref commitment_signed, .. } } => { assert!(update_add_htlcs.is_empty()); assert!(update_fulfill_htlcs.is_empty()); assert_eq!(update_fail_htlcs.len(), 1); @@ -8800,7 +9151,7 @@ fn test_bad_secret_hash() { // We should fail the payment back let mut events = nodes[1].node.get_and_clear_pending_msg_events(); match events.pop().unwrap() { - MessageSendEvent::UpdateHTLCs { node_id: _, updates: msgs::CommitmentUpdate { update_fail_htlcs, commitment_signed, .. } } => { +MessageSendEvent::UpdateCommitmentOutputs { node_id: _, updates: msgs::CommitmentUpdate { update_fail_htlcs, commitment_signed, .. } } => { nodes[0].node.handle_update_fail_htlc(&nodes[1].node.get_our_node_id(), &update_fail_htlcs[0]); commitment_signed_dance!(nodes[0], nodes[1], commitment_signed, false); }, @@ -8886,7 +9237,7 @@ fn test_update_err_monitor_lockdown() { assert_eq!(updates.update_fulfill_htlcs.len(), 1); nodes[0].node.handle_update_fulfill_htlc(&nodes[1].node.get_our_node_id(), &updates.update_fulfill_htlcs[0]); if let Some(ref mut channel) = nodes[0].node.channel_state.lock().unwrap().by_id.get_mut(&chan_1.2) { - if let Ok((_, _, update)) = channel.commitment_signed(&updates.commitment_signed, &node_cfgs[0].logger) { + if let Ok((_, _, update, _, _)) = channel.commitment_signed(&updates.commitment_signed, &node_cfgs[0].logger) { assert_eq!(watchtower.chain_monitor.update_channel(outpoint, update.clone()), ChannelMonitorUpdateStatus::PermanentFailure); assert_eq!(nodes[0].chain_monitor.update_channel(outpoint, update), ChannelMonitorUpdateStatus::Completed); } else { assert!(false); } @@ -8977,7 +9328,7 @@ fn test_concurrent_monitor_claim() { assert_eq!(updates.update_add_htlcs.len(), 1); nodes[0].node.handle_update_add_htlc(&nodes[1].node.get_our_node_id(), &updates.update_add_htlcs[0]); if let Some(ref mut channel) = nodes[0].node.channel_state.lock().unwrap().by_id.get_mut(&chan_1.2) { - if let Ok((_, _, update)) = channel.commitment_signed(&updates.commitment_signed, &node_cfgs[0].logger) { + if let Ok((_, _, update, _, _)) = channel.commitment_signed(&updates.commitment_signed, &node_cfgs[0].logger) { // Watchtower Alice should already have seen the block and reject the update assert_eq!(watchtower_alice.chain_monitor.update_channel(outpoint, update.clone()), ChannelMonitorUpdateStatus::PermanentFailure); assert_eq!(watchtower_bob.chain_monitor.update_channel(outpoint, update.clone()), ChannelMonitorUpdateStatus::Completed); @@ -9185,7 +9536,7 @@ fn do_test_onchain_htlc_settlement_after_close(broadcast_alice: bool, go_onchain let events = nodes[1].node.get_and_clear_pending_msg_events(); assert_eq!(events.len(), 1); match events[0] { - MessageSendEvent::UpdateHTLCs { ref node_id, .. } => { + MessageSendEvent::UpdateCommitmentOutputs { ref node_id, .. } => { assert_eq!(*node_id, nodes[0].node.get_our_node_id()); }, _ => panic!("Unexpected event"), @@ -9206,7 +9557,7 @@ fn do_test_onchain_htlc_settlement_after_close(broadcast_alice: bool, go_onchain _ => panic!("Unexpected event"), }; let bob_updates = match events[1] { - MessageSendEvent::UpdateHTLCs { ref node_id, ref updates } => { + MessageSendEvent::UpdateCommitmentOutputs { ref node_id, ref updates } => { assert_eq!(*node_id, nodes[2].node.get_our_node_id()); (*updates).clone() }, @@ -10271,7 +10622,7 @@ fn do_test_partial_claim_before_restart(persist_both_monitors: bool) { if let MessageSendEvent::SendChannelUpdate { .. } = ds_msgs[1] {} else { panic!(); } let cs_updates = match ds_msgs[0] { - MessageSendEvent::UpdateHTLCs { ref updates, .. } => { + MessageSendEvent::UpdateCommitmentOutputs { ref updates, .. } => { nodes[2].node.handle_update_fulfill_htlc(&nodes[3].node.get_our_node_id(), &updates.update_fulfill_htlcs[0]); check_added_monitors!(nodes[2], 1); let cs_updates = get_htlc_update_msgs!(nodes[2], nodes[0].node.get_our_node_id()); @@ -10396,7 +10747,7 @@ fn do_test_max_dust_htlc_exposure(dust_outbound_balance: bool, exposure_breach_e let (route, payment_hash, _, payment_secret) = get_route_and_payment_hash!(nodes[0], nodes[1], dust_htlc_on_counterparty_tx_msat); if let Err(_) = nodes[0].node.send_payment(&route, payment_hash, &Some(payment_secret)) { panic!("Unexpected event at dust HTLC {}", i); } } - } else { + } else { // Inbound dust threshold: 2031 sats (`dust_buffer_feerate` * HTLC_TIMEOUT_TX_WEIGHT / 1000 + counteparty's `dust_limit_satoshis`) // Inbound dust balance: 5000 sats for _ in 0..dust_htlc_on_counterparty_tx { diff --git a/lightning/src/ln/msgs.rs b/lightning/src/ln/msgs.rs index 58339339511..6c1e6ea4613 100644 --- a/lightning/src/ln/msgs.rs +++ b/lightning/src/ln/msgs.rs @@ -45,6 +45,7 @@ use crate::util::logger; use crate::util::ser::{BigSize, LengthReadable, Readable, ReadableArgs, Writeable, Writer, FixedLengthReader, HighZeroBytesDroppedBigSize, Hostname}; use crate::ln::{PaymentPreimage, PaymentHash, PaymentSecret}; +use crate::ln::channelmanager::CustomOutputId; /// 21 million * 10^8 * 1000 pub(crate) const MAX_VALUE_MSAT: u64 = 21_000_000_0000_0000_000; @@ -67,7 +68,7 @@ pub enum DecodeError { BadLengthDescriptor, /// Error from std::io Io(/// (C-not exported) as ErrorKind doesn't have a reasonable mapping - io::ErrorKind), + io::ErrorKind), /// The message included zlib-compressed values, which we don't support. UnsupportedCompression, } @@ -306,6 +307,37 @@ pub struct UpdateAddHTLC { pub(crate) onion_routing_packet: OnionPacket, } +/// An update_add_custom_output message to be sent or received from a peer +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct UpdateAddCustomOutput { + /// The channel ID + pub channel_id: [u8; 32], + /// The custom output ID + pub custom_output_id: CustomOutputId, + /// The custom output value provided by the local node, in milli-satoshi. + pub sender_amount_msat: u64, + /// The custom output value provided by the remote node, in milli-satoshi. + pub receiver_amount_msat: u64, + /// The expiry height of the custom output + pub cltv_expiry: u32, + /// The script of the custom output. + pub script: Script, + // pub(crate) onion_routing_packet: OnionPacket, TODO(10101): Determine if needed +} + +/// An update_remove_custom_output message to be sent or received from a peer +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct UpdateRemoveCustomOutput { + /// The channel ID + pub channel_id: [u8; 32], + /// The custom output ID + pub custom_output_id: CustomOutputId, + /// The custom output value given back to the local node, in milli-satoshi. + pub sender_amount_msat: u64, + /// The custom output value given back to the remote node, in milli-satoshi. + pub receiver_amount_msat: u64, +} + /// An onion message to be sent or received from a peer #[derive(Clone, Debug, PartialEq, Eq)] pub struct OnionMessage { @@ -325,6 +357,7 @@ pub struct UpdateFulfillHTLC { pub payment_preimage: PaymentPreimage, } + /// An update_fail_htlc message to be sent or received from a peer #[derive(Clone, Debug, PartialEq, Eq)] pub struct UpdateFailHTLC { @@ -356,6 +389,7 @@ pub struct CommitmentSigned { pub signature: Signature, /// Signatures on the HTLC transactions pub htlc_signatures: Vec, + // TODO(10101): Add dlc_signatures } /// A revoke_and_ack message to be sent or received from a peer @@ -819,6 +853,11 @@ pub struct CommitmentUpdate { pub update_fee: Option, /// Finally, the commitment_signed message which should be sent pub commitment_signed: CommitmentSigned, + + /// TODO(10101): Add docs + pub update_add_custom_output: Vec, + /// A list of custom outputs which need to be removed + pub update_remove_custom_output: Vec } /// Messages could have optional fields to use with extended features @@ -860,6 +899,10 @@ pub trait ChannelMessageHandler : MessageSendEventsProvider { // HTLC handling: /// Handle an incoming update_add_htlc message from the given peer. fn handle_update_add_htlc(&self, their_node_id: &PublicKey, msg: &UpdateAddHTLC); + /// Handle an incoming update_add_custom_output message from the given peer. + fn handle_update_add_custom_output(&self, their_node_id: &PublicKey, msg: &UpdateAddCustomOutput); + /// Handle an incoming update_remove_custom_output message from the given peer. + fn handle_update_remove_custom_output(&self, their_node_id: &PublicKey, msg: &UpdateRemoveCustomOutput); /// Handle an incoming update_fulfill_htlc message from the given peer. fn handle_update_fulfill_htlc(&self, their_node_id: &PublicKey, msg: &UpdateFulfillHTLC); /// Handle an incoming update_fail_htlc message from the given peer. @@ -1371,6 +1414,13 @@ impl_writeable_msg!(UpdateFulfillHTLC, { payment_preimage }, {}); +impl_writeable_msg!(UpdateRemoveCustomOutput, { + channel_id, + custom_output_id, + sender_amount_msat, + receiver_amount_msat +}, {}); + // Note that this is written as a part of ChannelManager objects, and thus cannot change its // serialization format in a way which assumes we know the total serialized length/message end // position. @@ -1958,8 +2008,19 @@ impl_writeable_msg!(GossipTimestampFilter, { timestamp_range, }, {}); + +impl_writeable_msg!(UpdateAddCustomOutput, { + channel_id, + custom_output_id, + sender_amount_msat, + receiver_amount_msat, + cltv_expiry, + script, +}, {}); + #[cfg(test)] mod tests { + use bitcoin::Script; use hex; use crate::ln::{PaymentPreimage, PaymentHash, PaymentSecret}; use crate::ln::features::{ChannelFeatures, ChannelTypeFeatures, InitFeatures, NodeFeatures}; @@ -1980,6 +2041,7 @@ mod tests { use crate::io::{self, Cursor}; use crate::prelude::*; use core::convert::TryFrom; + use crate::ln::channelmanager::CustomOutputId; #[test] fn encoding_channel_reestablish_no_secret() { @@ -2924,4 +2986,34 @@ mod tests { } Ok(encoded_payload) } + + #[test] + fn encoding_update_add_custom_output() { + let update_add_custom_output = msgs::UpdateAddCustomOutput { + channel_id: [2; 32], + sender_amount_msat: 3608586615801332854, + receiver_amount_msat: 3608586615801332854, + cltv_expiry: 821716, + custom_output_id: CustomOutputId([4;32]), + script: Script::new(), + }; + let encoded_value = update_add_custom_output.encode(); + let target_value = hex::decode("0202020202020202020202020202020202020202020202020202020202020202040404040404040404040404040404040404040404040404040404040404040432144668701144763214466870114476000c89d40000").unwrap(); + + assert_eq!(encoded_value, target_value); + } + + #[test] + fn encoding_remove_custom_output() { + let remove_custom_output = msgs::UpdateRemoveCustomOutput { + channel_id: [2; 32], + custom_output_id: CustomOutputId([1; 32]), + sender_amount_msat: 123, + receiver_amount_msat: 456 + }; + let encoded_value = remove_custom_output.encode(); + let target_value = hex::decode("02020202020202020202020202020202020202020202020202020202020202020101010101010101010101010101010101010101010101010101010101010101000000000000007b00000000000001c8").unwrap(); + assert_eq!(encoded_value, target_value); + } + } diff --git a/lightning/src/ln/payment_tests.rs b/lightning/src/ln/payment_tests.rs index c22f4611c34..c238c24e220 100644 --- a/lightning/src/ln/payment_tests.rs +++ b/lightning/src/ln/payment_tests.rs @@ -150,7 +150,7 @@ fn mpp_retry() { // Add the HTLC along the first hop. let fail_path_msgs_1 = events.remove(0); let (update_add, commitment_signed) = match fail_path_msgs_1 { - MessageSendEvent::UpdateHTLCs { node_id: _, updates: msgs::CommitmentUpdate { ref update_add_htlcs, ref update_fulfill_htlcs, ref update_fail_htlcs, ref update_fail_malformed_htlcs, ref update_fee, ref commitment_signed } } => { + MessageSendEvent::UpdateCommitmentOutputs { node_id: _, updates: msgs::CommitmentUpdate { ref update_add_htlcs, ref update_fulfill_htlcs, ref update_fail_htlcs, ref update_fail_malformed_htlcs, ref update_fee, ref commitment_signed, .. } } => { assert_eq!(update_add_htlcs.len(), 1); assert!(update_fail_htlcs.is_empty()); assert!(update_fulfill_htlcs.is_empty()); diff --git a/lightning/src/ln/peer_handler.rs b/lightning/src/ln/peer_handler.rs index 228c2491c47..63be46e5a0b 100644 --- a/lightning/src/ln/peer_handler.rs +++ b/lightning/src/ln/peer_handler.rs @@ -19,12 +19,12 @@ use bitcoin::secp256k1::{self, Secp256k1, SecretKey, PublicKey}; use crate::ln::features::{InitFeatures, NodeFeatures}; use crate::ln::msgs; -use crate::ln::msgs::{ChannelMessageHandler, LightningError, NetAddress, OnionMessageHandler, RoutingMessageHandler}; +use crate::ln::msgs::{ChannelMessageHandler, LightningError, NetAddress, OnionMessageHandler, RoutingMessageHandler, UpdateRemoveCustomOutput}; use crate::ln::channelmanager::{SimpleArcChannelManager, SimpleRefChannelManager}; use crate::util::ser::{MaybeReadableArgs, VecWriter, Writeable, Writer}; use crate::ln::peer_channel_encryptor::{PeerChannelEncryptor,NextNoiseStep}; use crate::ln::wire; -use crate::ln::wire::Encode; +use crate::ln::wire::{Encode, Message}; use crate::onion_message::{CustomOnionMessageContents, CustomOnionMessageHandler, SimpleArcOnionMessenger, SimpleRefOnionMessenger}; use crate::routing::gossip::{NetworkGraph, P2PGossipSync}; use crate::util::atomic_counter::AtomicCounter; @@ -199,6 +199,12 @@ impl ChannelMessageHandler for ErroringMessageHandler { fn handle_update_add_htlc(&self, their_node_id: &PublicKey, msg: &msgs::UpdateAddHTLC) { ErroringMessageHandler::push_error(self, their_node_id, msg.channel_id); } + fn handle_update_add_custom_output(&self, their_node_id: &PublicKey, msg: &msgs::UpdateAddCustomOutput) { + ErroringMessageHandler::push_error(self, their_node_id, msg.channel_id); + } + fn handle_update_remove_custom_output(&self, their_node_id: &PublicKey, msg: &UpdateRemoveCustomOutput) { + ErroringMessageHandler::push_error(self, their_node_id, msg.channel_id); + } fn handle_update_fulfill_htlc(&self, their_node_id: &PublicKey, msg: &msgs::UpdateFulfillHTLC) { ErroringMessageHandler::push_error(self, their_node_id, msg.channel_id); } @@ -247,6 +253,7 @@ impl ChannelMessageHandler for ErroringMessageHandler { features.set_zero_conf_optional(); features } + } impl Deref for ErroringMessageHandler { type Target = ErroringMessageHandler; @@ -668,9 +675,9 @@ fn filter_addresses(ip_address: Option) -> Option { Some(NetAddress::IPv4{addr: [0, _, _, _], port: _}) => None, // For IPv4 range 100.64.0.0 - 100.127.255.255 (100.64/10) Some(NetAddress::IPv4{addr: [100, 64..=127, _, _], port: _}) => None, - // For IPv4 range 127.0.0.0 - 127.255.255.255 (127/8) + // For IPv4 range 127.0.0.0 - 127.255.255.255 (127/8) Some(NetAddress::IPv4{addr: [127, _, _, _], port: _}) => None, - // For IPv4 range 169.254.0.0 - 169.254.255.255 (169.254/16) + // For IPv4 range 169.254.0.0 - 169.254.255.255 (169.254/16) Some(NetAddress::IPv4{addr: [169, 254, _, _], port: _}) => None, // For IPv4 range 172.16.0.0 - 172.31.255.255 (172.16/12) Some(NetAddress::IPv4{addr: [172, 16..=31, _, _], port: _}) => None, @@ -1369,6 +1376,9 @@ impl { self.message_handler.chan_handler.handle_update_add_htlc(&their_node_id, &msg); }, + wire::Message::UpdateAddCustomOutput(msg) => { + self.message_handler.chan_handler.handle_update_add_custom_output(&their_node_id, &msg); + }, wire::Message::UpdateFulfillHTLC(msg) => { self.message_handler.chan_handler.handle_update_fulfill_htlc(&their_node_id, &msg); }, @@ -1445,6 +1455,9 @@ impl { self.custom_message_handler.handle_custom_message(custom, &their_node_id)?; }, + Message::UpdateRemoveCustomOutput(msg) => { + self.message_handler.chan_handler.handle_update_remove_custom_output(&their_node_id, &msg); + } }; Ok(should_forward) } @@ -1603,6 +1616,12 @@ impl { + log_debug!(self.logger, "Handling AddCustomOutput event in peer_handler for node {} for channel {}", + log_pubkey!(node_id), + log_bytes!(msg.channel_id)); + self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg); + }, MessageSendEvent::SendAcceptChannel { ref node_id, ref msg } => { log_debug!(self.logger, "Handling SendAcceptChannel event in peer_handler for node {} for channel {}", log_pubkey!(node_id), @@ -1642,10 +1661,12 @@ impl { - log_debug!(self.logger, "Handling UpdateHTLCs event in peer_handler for node {} with {} adds, {} fulfills, {} fails for channel {}", + MessageSendEvent::UpdateCommitmentOutputs { ref node_id, updates: msgs::CommitmentUpdate { ref update_add_htlcs, ref update_fulfill_htlcs, ref update_fail_htlcs, ref update_fail_malformed_htlcs, ref update_fee, ref commitment_signed, ref update_add_custom_output, ref update_remove_custom_output } } => { + log_debug!(self.logger, "Handling UpdateCommitmentOutputs event in peer_handler for node {} with {} htlc adds, {} custom adds, {} custom removals, {} fulfills, {} fails for channel {}", log_pubkey!(node_id), update_add_htlcs.len(), + update_add_custom_output.len(), + update_remove_custom_output.len(), update_fulfill_htlcs.len(), update_fail_htlcs.len(), log_bytes!(commitment_signed.channel_id)); @@ -1653,6 +1674,12 @@ impl where T: core::fmt::Debug + Type + TestEq { ClosingSigned(msgs::ClosingSigned), OnionMessage(msgs::OnionMessage), UpdateAddHTLC(msgs::UpdateAddHTLC), + UpdateAddCustomOutput(msgs::UpdateAddCustomOutput), UpdateFulfillHTLC(msgs::UpdateFulfillHTLC), + UpdateRemoveCustomOutput(msgs::UpdateRemoveCustomOutput), UpdateFailHTLC(msgs::UpdateFailHTLC), UpdateFailMalformedHTLC(msgs::UpdateFailMalformedHTLC), CommitmentSigned(msgs::CommitmentSigned), @@ -103,6 +105,8 @@ impl Message where T: core::fmt::Debug + Type + TestEq { &Message::ClosingSigned(ref msg) => msg.type_id(), &Message::OnionMessage(ref msg) => msg.type_id(), &Message::UpdateAddHTLC(ref msg) => msg.type_id(), + &Message::UpdateAddCustomOutput(ref msg) => msg.type_id(), + &Message::UpdateRemoveCustomOutput(ref msg) => msg.type_id(), &Message::UpdateFulfillHTLC(ref msg) => msg.type_id(), &Message::UpdateFailHTLC(ref msg) => msg.type_id(), &Message::UpdateFailMalformedHTLC(ref msg) => msg.type_id(), @@ -193,9 +197,15 @@ fn do_read(buffer: &mut R, message_type: u1 msgs::UpdateAddHTLC::TYPE => { Ok(Message::UpdateAddHTLC(Readable::read(buffer)?)) }, + msgs::UpdateAddCustomOutput::TYPE => { + Ok(Message::UpdateAddCustomOutput(Readable::read(buffer)?)) + }, msgs::UpdateFulfillHTLC::TYPE => { Ok(Message::UpdateFulfillHTLC(Readable::read(buffer)?)) }, + msgs::UpdateRemoveCustomOutput::TYPE => { + Ok(Message::UpdateRemoveCustomOutput(Readable::read(buffer)?)) + }, msgs::UpdateFailHTLC::TYPE => { Ok(Message::UpdateFailHTLC(Readable::read(buffer)?)) }, @@ -421,6 +431,14 @@ impl Encode for msgs::GossipTimestampFilter { const TYPE: u16 = 265; } +impl Encode for msgs::UpdateAddCustomOutput { + const TYPE: u16 = 266; +} + +impl Encode for msgs::UpdateRemoveCustomOutput { + const TYPE: u16 = 267; +} + #[cfg(test)] mod tests { use super::*; diff --git a/lightning/src/routing/router.rs b/lightning/src/routing/router.rs index 0d37744db83..a0802297c3e 100644 --- a/lightning/src/routing/router.rs +++ b/lightning/src/routing/router.rs @@ -14,7 +14,7 @@ use bitcoin::secp256k1::PublicKey; -use crate::ln::channelmanager::ChannelDetails; +use crate::ln::channelmanager::{ChannelDetails, CustomOutputId}; use crate::ln::features::{ChannelFeatures, InvoiceFeatures, NodeFeatures}; use crate::ln::msgs::{DecodeError, ErrorAction, LightningError, MAX_VALUE_MSAT}; use crate::routing::gossip::{DirectedChannelInfoWithUpdate, EffectiveCapacity, ReadOnlyNetworkGraph, NetworkGraph, NodeId, RoutingFees}; @@ -78,6 +78,28 @@ pub struct Route { pub payment_params: Option, } +/// Details needed to create a custom output with peer. +pub struct AddCustomOutputRouteDetails { + /// The channel to which the custom output is added. + pub short_channel_id: u64, + /// The node ID of the counterparty in the channel. + pub pk_counterparty: PublicKey, + /// The amount that the local node (we) provide for the custom output. + pub local_amount_msats: u64, + /// The amount that our counterparty (the listener) provides for the custom output. + pub amount_counterparty_msat: u64, + /// The CLTV expiry of the custom output. + pub cltv_expiry: u32 +} + +/// Details needed to remove a custom output with peer. +pub struct RemoveCustomOutputDetails { + /// The id of the custom output which is mean to be removed + pub custom_output_id: CustomOutputId, + /// The amount that the local node (we) provide for the custom output. + pub local_amount_msats: u64, +} + pub(crate) trait RoutePath { /// Gets the fees for a given path, excluding any excess paid to the recipient. fn get_path_fees(&self) -> u64; @@ -1719,7 +1741,7 @@ where L::Target: Logger { for idx in 0..(selected_route.len() - 1) { if idx + 1 >= selected_route.len() { break; } if iter_equal(selected_route[idx ].hops.iter().map(|h| (h.0.candidate.short_channel_id(), h.0.node_id)), - selected_route[idx + 1].hops.iter().map(|h| (h.0.candidate.short_channel_id(), h.0.node_id))) { + selected_route[idx + 1].hops.iter().map(|h| (h.0.candidate.short_channel_id(), h.0.node_id))) { let new_value = selected_route[idx].get_value_msat() + selected_route[idx + 1].get_value_msat(); selected_route[idx].update_value_and_recompute_fees(new_value); selected_route.remove(idx + 1); diff --git a/lightning/src/util/events.rs b/lightning/src/util/events.rs index 37a146c3dac..15084763e5e 100644 --- a/lightning/src/util/events.rs +++ b/lightning/src/util/events.rs @@ -15,18 +15,17 @@ //! few other things. use crate::chain::keysinterface::SpendableOutputDescriptor; -use crate::ln::chan_utils::HTLCOutputInCommitment; -use crate::ln::channelmanager::PaymentId; +use crate::ln::channelmanager::{PaymentId, CustomOutputId}; use crate::ln::channel::FUNDING_CONF_DEADLINE_BLOCKS; use crate::ln::features::ChannelTypeFeatures; -use crate::ln::msgs; +use crate::ln::msgs::{self, CommitmentSigned, RevokeAndACK}; use crate::ln::msgs::DecodeError; use crate::ln::{PaymentPreimage, PaymentHash, PaymentSecret}; use crate::routing::gossip::NetworkUpdate; use crate::util::ser::{BigSize, FixedLengthReader, Writeable, Writer, MaybeReadable, Readable, VecReadWrapper, VecWriteWrapper}; use crate::routing::router::{RouteHop, RouteParameters}; -use bitcoin::{PackedLockTime, Transaction, OutPoint}; +use bitcoin::{PackedLockTime, Transaction}; use bitcoin::blockdata::script::Script; use bitcoin::hashes::Hash; use bitcoin::hashes::sha256::Hash as Sha256; @@ -698,6 +697,27 @@ pub enum Event { /// LDK does not currently generate this event. It is limited to the scope of channels with /// anchor outputs, which will be introduced in a future release. BumpTransaction(BumpTransactionEvent), + /// The remote node sent a request to add a custom output. + /// + /// We expect the library consumer to verify signatures based on the custom output on the + /// application layer, before they continue with the protocol. + RemoteSentAddCustomOutputEvent { + /// Custom output ID. + custom_output_id: CustomOutputId + }, + /// The remote node sent their signature for a commitment transaction which includes at + /// least one custom output. + /// + /// We expect the library consumer to verify signatures based on the custom output, on the + /// application layer before they send their own commitment signature to the remote node. + RemoteSentCustomOutputCommitmentSignature { + /// TODO(10101): add doc + public_key_remote: PublicKey, + /// TODO(10101): add doc + commitment_signed: CommitmentSigned, + /// TODO(10101): add doc + revoke_and_ack: RevokeAndACK, + }, } impl Writeable for Event { @@ -861,6 +881,24 @@ impl Writeable for Event { // Note that, going forward, all new events must only write data inside of // `write_tlv_fields`. Versions 0.0.101+ will ignore odd-numbered events that write // data via `write_tlv_fields`. + &Event::RemoteSentAddCustomOutputEvent { custom_output_id } => { + 29u8.write(writer)?; + write_tlv_fields!(writer, { + (0, custom_output_id, required), + }) + } + &Event::RemoteSentCustomOutputCommitmentSignature { ref public_key_remote, ref commitment_signed, ref revoke_and_ack } => { + let public_key_remote = public_key_remote.clone(); + let commitment_signed = commitment_signed.clone(); + let revoke_and_ack = revoke_and_ack.clone(); + + 31u8.write(writer)?; + write_tlv_fields!(writer, { + (0, public_key_remote, required), + (2, commitment_signed, required), + (4, revoke_and_ack, required), + }) + } } Ok(()) } @@ -1138,6 +1176,38 @@ impl MaybeReadable for Event { }; f() }, + 29u8 => { + let f = || { + let mut custom_output_id = CustomOutputId([0; 32]); + read_tlv_fields!(reader, { + (0, custom_output_id, required) + }); + Ok(Some(Event::RemoteSentAddCustomOutputEvent { custom_output_id })) + }; + f() + } + 31u8 => { + let f = || { + let mut public_key_remote = PublicKey::from_slice(&[0;64]).unwrap(); + let mut commitment_signed = CommitmentSigned { + channel_id: [0; 32], + signature: bitcoin::secp256k1::ecdsa::Signature::from_compact(&[0;64]).unwrap(), + htlc_signatures: Vec::new() + }; + let mut revoke_and_ack = RevokeAndACK { + channel_id: [0; 32], + per_commitment_secret: [0; 32], + next_per_commitment_point: PublicKey::from_slice(&[0;64]).unwrap(), + }; + read_tlv_fields!(reader, { + (0, public_key_remote, required), + (2, commitment_signed, required), + (4, revoke_and_ack, required) + }); + Ok(Some(Event::RemoteSentCustomOutputCommitmentSignature { public_key_remote, commitment_signed, revoke_and_ack })) + }; + f() + } // Versions prior to 0.0.100 did not ignore odd types, instead returning InvalidValue. // Version 0.0.100 failed to properly ignore odd types, possibly resulting in corrupt // reads. @@ -1162,6 +1232,13 @@ impl MaybeReadable for Event { /// These events are handled by PeerManager::process_events if you are using a PeerManager. #[derive(Clone, Debug)] pub enum MessageSendEvent { + /// Used to indicate that we've added a custom output locally. + AddCustomOutput { + /// The node_id of the node which should receive this message + node_id: PublicKey, + /// The message which should be sent. + msg: msgs::UpdateAddCustomOutput, + }, /// Used to indicate that we've accepted a channel open and should send the accept_channel /// message provided to the given peer. SendAcceptChannel { @@ -1206,14 +1283,16 @@ pub enum MessageSendEvent { /// The announcement_signatures message which should be sent. msg: msgs::AnnouncementSignatures, }, - /// Used to indicate that a series of HTLC update messages, as well as a commitment_signed + /// Used to indicate that a series of commitment output update messages, as well as a commitment_signed /// message should be sent to the peer with the given node_id. - UpdateHTLCs { + UpdateCommitmentOutputs { /// The node_id of the node which should receive these message(s) node_id: PublicKey, /// The update messages which should be sent. ALL messages in the struct should be sent! updates: msgs::CommitmentUpdate, }, + /// Used to indicate that a series of custom output update messages, as well as a + /// commitment_signed message should be sent to the peer with the given node_id. /// Used to indicate that a revoke_and_ack message should be sent to the peer with the given node_id. SendRevokeAndACK { /// The node_id of the node which should receive this message diff --git a/lightning/src/util/ser.rs b/lightning/src/util/ser.rs index 1bf30fa9f72..5ee5d9481ce 100644 --- a/lightning/src/util/ser.rs +++ b/lightning/src/util/ser.rs @@ -466,6 +466,7 @@ macro_rules! impl_writeable_primitive { impl_writeable_primitive!(u64, 8); impl_writeable_primitive!(u32, 4); impl_writeable_primitive!(u16, 2); +impl_writeable_primitive!(i64, 8); impl Writeable for u8 { #[inline] diff --git a/lightning/src/util/test_utils.rs b/lightning/src/util/test_utils.rs index 89bf27de280..544a2c538d0 100644 --- a/lightning/src/util/test_utils.rs +++ b/lightning/src/util/test_utils.rs @@ -53,6 +53,7 @@ use crate::chain::keysinterface::{InMemorySigner, Recipient, KeyMaterial}; #[cfg(feature = "std")] use std::time::{SystemTime, UNIX_EPOCH}; use bitcoin::Sequence; +use crate::ln::msgs::UpdateRemoveCustomOutput; pub struct TestVecWriter(pub Vec); impl Writer for TestVecWriter { @@ -323,6 +324,12 @@ impl msgs::ChannelMessageHandler for TestChannelMessageHandler { fn handle_update_add_htlc(&self, _their_node_id: &PublicKey, msg: &msgs::UpdateAddHTLC) { self.received_msg(wire::Message::UpdateAddHTLC(msg.clone())); } + fn handle_update_add_custom_output(&self, _their_node_id: &PublicKey, msg: &msgs::UpdateAddCustomOutput) { + self.received_msg(wire::Message::UpdateAddCustomOutput(msg.clone())); + } + fn handle_update_remove_custom_output(&self, _their_node_id: &PublicKey, msg: &UpdateRemoveCustomOutput) { + self.received_msg(wire::Message::UpdateRemoveCustomOutput(msg.clone())); + } fn handle_update_fulfill_htlc(&self, _their_node_id: &PublicKey, msg: &msgs::UpdateFulfillHTLC) { self.received_msg(wire::Message::UpdateFulfillHTLC(msg.clone())); } diff --git a/lightning/src/util/transaction_utils.rs b/lightning/src/util/transaction_utils.rs index db146028332..6cff12b4cae 100644 --- a/lightning/src/util/transaction_utils.rs +++ b/lightning/src/util/transaction_utils.rs @@ -18,12 +18,14 @@ use crate::prelude::*; use crate::io_extras::sink; use core::cmp::Ordering; -pub fn sort_outputs Ordering>(outputs: &mut Vec<(TxOut, T)>, tie_breaker: C) { +pub fn sort_outputs Ordering, TC: Fn(&C, &C) -> Ordering>(outputs: &mut Vec<(TxOut, H, C)>, htlc_tie_breaker: TH, custom_output_tie_breaker: TC) { outputs.sort_unstable_by(|a, b| { a.0.value.cmp(&b.0.value).then_with(|| { a.0.script_pubkey[..].cmp(&b.0.script_pubkey[..]).then_with(|| { - tie_breaker(&a.1, &b.1) - }) + htlc_tie_breaker(&a.1, &b.1) + }).then_with(|| { + custom_output_tie_breaker(&a.2, &b.2) + }) }) }); } @@ -96,12 +98,12 @@ mod tests { }; let txout2_ = txout2.clone(); - let mut outputs = vec![(txout1, "ignore"), (txout2, "ignore")]; - sort_outputs(&mut outputs, |_, _| { unreachable!(); }); + let mut outputs = vec![(txout1, "ignore", ()), (txout2, "ignore", ())]; + sort_outputs(&mut outputs, |_, _| { unreachable!(); }, |_, _| { unreachable!(); }); assert_eq!( &outputs, - &vec![(txout2_, "ignore"), (txout1_, "ignore")] + &vec![(txout2_, "ignore", ()), (txout1_, "ignore", ())] ); } @@ -119,12 +121,12 @@ mod tests { }; let txout2_ = txout2.clone(); - let mut outputs = vec![(txout1, "ignore"), (txout2, "ignore")]; - sort_outputs(&mut outputs, |_, _| { unreachable!(); }); + let mut outputs = vec![(txout1, "ignore", ()), (txout2, "ignore", ())]; + sort_outputs(&mut outputs, |_, _| { unreachable!(); }, |_, _| { unreachable!(); }); assert_eq!( &outputs, - &vec![(txout2_, "ignore"), (txout1_, "ignore")] + &vec![(txout2_, "ignore", ()), (txout1_, "ignore", ())] ); } @@ -143,10 +145,10 @@ mod tests { }; let txout2_ = txout2.clone(); - let mut outputs = vec![(txout1, "ignore"), (txout2, "ignore")]; - sort_outputs(&mut outputs, |_, _| { unreachable!(); }); + let mut outputs = vec![(txout1, "ignore", ()), (txout2, "ignore", ())]; + sort_outputs(&mut outputs, |_, _| { unreachable!(); }, |_, _| { unreachable!(); }); - assert_eq!(&outputs, &vec![(txout1_, "ignore"), (txout2_, "ignore")]); + assert_eq!(&outputs, &vec![(txout1_, "ignore", ()), (txout2_, "ignore", ())]); } #[test] @@ -160,12 +162,12 @@ mod tests { let txout2 = txout1.clone(); let txout2_ = txout1.clone(); - let mut outputs = vec![(txout1, 420), (txout2, 69)]; - sort_outputs(&mut outputs, |a, b| { a.cmp(b) }); + let mut outputs = vec![(txout1, 420, ()), (txout2, 69, ())]; + sort_outputs(&mut outputs, |a, b| { a.cmp(b) }, |_, _| { unreachable!(); }); assert_eq!( &outputs, - &vec![(txout2_, 69), (txout1_, 420)] + &vec![(txout2_, 69, ()), (txout1_, 420, ())] ); } @@ -179,18 +181,18 @@ mod tests { #[test] fn $name() { let expected_raw: Vec<(u64, &str)> = $value; - let expected: Vec<(TxOut, &str)> = expected_raw.iter() + let expected: Vec<(TxOut, &str, ())> = expected_raw.iter() .map(|txout_raw| TxOut { value: txout_raw.0, script_pubkey: script_from_hex(txout_raw.1) - }).map(|txout| (txout, "ignore")) + }).map(|txout| (txout, "ignore", ())) .collect(); let mut outputs = expected.clone(); outputs.reverse(); // prep it // actually do the work! - sort_outputs(&mut outputs, |_, _| { unreachable!(); }); + sort_outputs(&mut outputs, |_, _| { unreachable!(); }, |_, _| { unreachable!(); }); assert_eq!(outputs, expected); }