mirror of
https://github.com/lightningdevkit/rust-lightning.git
synced 2025-01-19 05:43:55 +01:00
Implement support for accepting V2 channels
This commit is contained in:
parent
f71bbb9643
commit
24ba5848d5
@ -606,6 +606,20 @@ impl_writeable_tlv_based_enum_upgradable!(PaymentFailureReason,
|
|||||||
(10, UnexpectedError) => {},
|
(10, UnexpectedError) => {},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/// Used to indicate the kind of funding for this channel by the channel acceptor (us).
|
||||||
|
///
|
||||||
|
/// Allows the differentiation between a request for a dual-funded and non-dual-funded channel.
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
|
pub enum InboundChannelFunds {
|
||||||
|
/// For a non-dual-funded channel, the `push_msat` value from the channel initiator to us.
|
||||||
|
PushMsat(u64),
|
||||||
|
/// Indicates the open request is for a dual funded channel.
|
||||||
|
///
|
||||||
|
/// Note that these channels do not support starting with initial funds pushed from the counterparty,
|
||||||
|
/// who is the channel opener in this case.
|
||||||
|
DualFunded,
|
||||||
|
}
|
||||||
|
|
||||||
/// An Event which you should probably take some action in response to.
|
/// An Event which you should probably take some action in response to.
|
||||||
///
|
///
|
||||||
/// Note that while Writeable and Readable are implemented for Event, you probably shouldn't use
|
/// Note that while Writeable and Readable are implemented for Event, you probably shouldn't use
|
||||||
@ -1337,9 +1351,10 @@ pub enum Event {
|
|||||||
},
|
},
|
||||||
/// Indicates a request to open a new channel by a peer.
|
/// Indicates a request to open a new channel by a peer.
|
||||||
///
|
///
|
||||||
/// To accept the request, call [`ChannelManager::accept_inbound_channel`]. To reject the request,
|
/// To accept the request (and in the case of a dual-funded channel, not contribute funds),
|
||||||
/// call [`ChannelManager::force_close_without_broadcasting_txn`]. Note that a ['ChannelClosed`]
|
/// call [`ChannelManager::accept_inbound_channel`].
|
||||||
/// event will _not_ be triggered if the channel is rejected.
|
/// To reject the request, call [`ChannelManager::force_close_without_broadcasting_txn`].
|
||||||
|
/// Note that a ['ChannelClosed`] event will _not_ be triggered if the channel is rejected.
|
||||||
///
|
///
|
||||||
/// The event is only triggered when a new open channel request is received and the
|
/// The event is only triggered when a new open channel request is received and the
|
||||||
/// [`UserConfig::manually_accept_inbound_channels`] config flag is set to true.
|
/// [`UserConfig::manually_accept_inbound_channels`] config flag is set to true.
|
||||||
@ -1373,8 +1388,10 @@ pub enum Event {
|
|||||||
counterparty_node_id: PublicKey,
|
counterparty_node_id: PublicKey,
|
||||||
/// The channel value of the requested channel.
|
/// The channel value of the requested channel.
|
||||||
funding_satoshis: u64,
|
funding_satoshis: u64,
|
||||||
/// Our starting balance in the channel if the request is accepted, in milli-satoshi.
|
/// If `channel_negotiation_type` is `InboundChannelFunds::DualFunded`, this indicates that the peer wishes to
|
||||||
push_msat: u64,
|
/// open a dual-funded channel. Otherwise, this field will be `InboundChannelFunds::PushMsats`,
|
||||||
|
/// indicating the `push_msats` value our peer is pushing to us for a non-dual-funded channel.
|
||||||
|
channel_negotiation_type: InboundChannelFunds,
|
||||||
/// The features that this channel will operate with. If you reject the channel, a
|
/// The features that this channel will operate with. If you reject the channel, a
|
||||||
/// well-behaved counterparty may automatically re-attempt the channel with a new set of
|
/// well-behaved counterparty may automatically re-attempt the channel with a new set of
|
||||||
/// feature flags.
|
/// feature flags.
|
||||||
|
@ -9,11 +9,13 @@
|
|||||||
|
|
||||||
use bitcoin::amount::Amount;
|
use bitcoin::amount::Amount;
|
||||||
use bitcoin::constants::ChainHash;
|
use bitcoin::constants::ChainHash;
|
||||||
use bitcoin::script::{Script, ScriptBuf, Builder};
|
use bitcoin::script::{Script, ScriptBuf, Builder, WScriptHash};
|
||||||
use bitcoin::transaction::Transaction;
|
use bitcoin::transaction::{Transaction, TxIn};
|
||||||
use bitcoin::sighash;
|
use bitcoin::sighash;
|
||||||
use bitcoin::sighash::EcdsaSighashType;
|
use bitcoin::sighash::EcdsaSighashType;
|
||||||
use bitcoin::consensus::encode;
|
use bitcoin::consensus::encode;
|
||||||
|
use bitcoin::absolute::LockTime;
|
||||||
|
use bitcoin::Weight;
|
||||||
|
|
||||||
use bitcoin::hashes::Hash;
|
use bitcoin::hashes::Hash;
|
||||||
use bitcoin::hashes::sha256::Hash as Sha256;
|
use bitcoin::hashes::sha256::Hash as Sha256;
|
||||||
@ -28,7 +30,10 @@ use bitcoin::secp256k1;
|
|||||||
use crate::ln::types::ChannelId;
|
use crate::ln::types::ChannelId;
|
||||||
use crate::types::payment::{PaymentPreimage, PaymentHash};
|
use crate::types::payment::{PaymentPreimage, PaymentHash};
|
||||||
use crate::types::features::{ChannelTypeFeatures, InitFeatures};
|
use crate::types::features::{ChannelTypeFeatures, InitFeatures};
|
||||||
use crate::ln::interactivetxs::InteractiveTxConstructor;
|
use crate::ln::interactivetxs::{
|
||||||
|
get_output_weight, HandleTxCompleteResult, InteractiveTxConstructor, InteractiveTxConstructorArgs,
|
||||||
|
InteractiveTxMessageSend, InteractiveTxMessageSendResult, TX_COMMON_FIELDS_WEIGHT,
|
||||||
|
};
|
||||||
use crate::ln::msgs;
|
use crate::ln::msgs;
|
||||||
use crate::ln::msgs::{ClosingSigned, ClosingSignedFeeRange, DecodeError};
|
use crate::ln::msgs::{ClosingSigned, ClosingSignedFeeRange, DecodeError};
|
||||||
use crate::ln::script::{self, ShutdownScript};
|
use crate::ln::script::{self, ShutdownScript};
|
||||||
@ -45,14 +50,14 @@ use crate::ln::chan_utils::{
|
|||||||
use crate::ln::chan_utils;
|
use crate::ln::chan_utils;
|
||||||
use crate::ln::onion_utils::HTLCFailReason;
|
use crate::ln::onion_utils::HTLCFailReason;
|
||||||
use crate::chain::BestBlock;
|
use crate::chain::BestBlock;
|
||||||
use crate::chain::chaininterface::{FeeEstimator, ConfirmationTarget, LowerBoundedFeeEstimator};
|
use crate::chain::chaininterface::{FeeEstimator, ConfirmationTarget, LowerBoundedFeeEstimator, fee_for_weight};
|
||||||
use crate::chain::channelmonitor::{ChannelMonitor, ChannelMonitorUpdate, ChannelMonitorUpdateStep, LATENCY_GRACE_PERIOD_BLOCKS};
|
use crate::chain::channelmonitor::{ChannelMonitor, ChannelMonitorUpdate, ChannelMonitorUpdateStep, LATENCY_GRACE_PERIOD_BLOCKS};
|
||||||
use crate::chain::transaction::{OutPoint, TransactionData};
|
use crate::chain::transaction::{OutPoint, TransactionData};
|
||||||
use crate::sign::ecdsa::EcdsaChannelSigner;
|
use crate::sign::ecdsa::EcdsaChannelSigner;
|
||||||
use crate::sign::{EntropySource, ChannelSigner, SignerProvider, NodeSigner, Recipient};
|
use crate::sign::{EntropySource, ChannelSigner, SignerProvider, NodeSigner, Recipient};
|
||||||
use crate::events::ClosureReason;
|
use crate::events::ClosureReason;
|
||||||
use crate::routing::gossip::NodeId;
|
use crate::routing::gossip::NodeId;
|
||||||
use crate::util::ser::{Readable, ReadableArgs, Writeable, Writer};
|
use crate::util::ser::{Readable, ReadableArgs, TransactionU16LenLimited, Writeable, Writer};
|
||||||
use crate::util::logger::{Logger, Record, WithContext};
|
use crate::util::logger::{Logger, Record, WithContext};
|
||||||
use crate::util::errors::APIError;
|
use crate::util::errors::APIError;
|
||||||
use crate::util::config::{UserConfig, ChannelConfig, LegacyChannelConfig, ChannelHandshakeConfig, ChannelHandshakeLimits, MaxDustHTLCExposure};
|
use crate::util::config::{UserConfig, ChannelConfig, LegacyChannelConfig, ChannelHandshakeConfig, ChannelHandshakeLimits, MaxDustHTLCExposure};
|
||||||
@ -1637,6 +1642,101 @@ impl<SP: Deref> InitialRemoteCommitmentReceiver<SP> for InboundV1Channel<SP> whe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(super) trait InteractivelyFunded<SP: Deref> where SP::Target: SignerProvider {
|
||||||
|
fn context(&self) -> &ChannelContext<SP>;
|
||||||
|
|
||||||
|
fn context_mut(&mut self) -> &mut ChannelContext<SP>;
|
||||||
|
|
||||||
|
fn interactive_tx_constructor_mut(&mut self) -> &mut Option<InteractiveTxConstructor>;
|
||||||
|
|
||||||
|
fn dual_funding_context(&self) -> &DualFundingChannelContext;
|
||||||
|
|
||||||
|
fn tx_add_input(&mut self, msg: &msgs::TxAddInput) -> InteractiveTxMessageSendResult {
|
||||||
|
InteractiveTxMessageSendResult(match self.interactive_tx_constructor_mut() {
|
||||||
|
Some(ref mut tx_constructor) => tx_constructor.handle_tx_add_input(msg).map_err(
|
||||||
|
|reason| reason.into_tx_abort_msg(self.context().channel_id())),
|
||||||
|
None => Err(msgs::TxAbort {
|
||||||
|
channel_id: self.context().channel_id(),
|
||||||
|
data: b"No interactive transaction negotiation in progress".to_vec()
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tx_add_output(&mut self, msg: &msgs::TxAddOutput)-> InteractiveTxMessageSendResult {
|
||||||
|
InteractiveTxMessageSendResult(match self.interactive_tx_constructor_mut() {
|
||||||
|
Some(ref mut tx_constructor) => tx_constructor.handle_tx_add_output(msg).map_err(
|
||||||
|
|reason| reason.into_tx_abort_msg(self.context().channel_id())),
|
||||||
|
None => Err(msgs::TxAbort {
|
||||||
|
channel_id: self.context().channel_id(),
|
||||||
|
data: b"No interactive transaction negotiation in progress".to_vec()
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tx_remove_input(&mut self, msg: &msgs::TxRemoveInput)-> InteractiveTxMessageSendResult {
|
||||||
|
InteractiveTxMessageSendResult(match self.interactive_tx_constructor_mut() {
|
||||||
|
Some(ref mut tx_constructor) => tx_constructor.handle_tx_remove_input(msg).map_err(
|
||||||
|
|reason| reason.into_tx_abort_msg(self.context().channel_id())),
|
||||||
|
None => Err(msgs::TxAbort {
|
||||||
|
channel_id: self.context().channel_id(),
|
||||||
|
data: b"No interactive transaction negotiation in progress".to_vec()
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tx_remove_output(&mut self, msg: &msgs::TxRemoveOutput)-> InteractiveTxMessageSendResult {
|
||||||
|
InteractiveTxMessageSendResult(match self.interactive_tx_constructor_mut() {
|
||||||
|
Some(ref mut tx_constructor) => tx_constructor.handle_tx_remove_output(msg).map_err(
|
||||||
|
|reason| reason.into_tx_abort_msg(self.context().channel_id())),
|
||||||
|
None => Err(msgs::TxAbort {
|
||||||
|
channel_id: self.context().channel_id(),
|
||||||
|
data: b"No interactive transaction negotiation in progress".to_vec()
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tx_complete(&mut self, msg: &msgs::TxComplete) -> HandleTxCompleteResult {
|
||||||
|
HandleTxCompleteResult(match self.interactive_tx_constructor_mut() {
|
||||||
|
Some(ref mut tx_constructor) => tx_constructor.handle_tx_complete(msg).map_err(
|
||||||
|
|reason| reason.into_tx_abort_msg(self.context().channel_id())),
|
||||||
|
None => Err(msgs::TxAbort {
|
||||||
|
channel_id: self.context().channel_id(),
|
||||||
|
data: b"No interactive transaction negotiation in progress".to_vec()
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<SP: Deref> InteractivelyFunded<SP> for OutboundV2Channel<SP> where SP::Target: SignerProvider {
|
||||||
|
fn context(&self) -> &ChannelContext<SP> {
|
||||||
|
&self.context
|
||||||
|
}
|
||||||
|
fn context_mut(&mut self) -> &mut ChannelContext<SP> {
|
||||||
|
&mut self.context
|
||||||
|
}
|
||||||
|
fn dual_funding_context(&self) -> &DualFundingChannelContext {
|
||||||
|
&self.dual_funding_context
|
||||||
|
}
|
||||||
|
fn interactive_tx_constructor_mut(&mut self) -> &mut Option<InteractiveTxConstructor> {
|
||||||
|
&mut self.interactive_tx_constructor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<SP: Deref> InteractivelyFunded<SP> for InboundV2Channel<SP> where SP::Target: SignerProvider {
|
||||||
|
fn context(&self) -> &ChannelContext<SP> {
|
||||||
|
&self.context
|
||||||
|
}
|
||||||
|
fn context_mut(&mut self) -> &mut ChannelContext<SP> {
|
||||||
|
&mut self.context
|
||||||
|
}
|
||||||
|
fn dual_funding_context(&self) -> &DualFundingChannelContext {
|
||||||
|
&self.dual_funding_context
|
||||||
|
}
|
||||||
|
fn interactive_tx_constructor_mut(&mut self) -> &mut Option<InteractiveTxConstructor> {
|
||||||
|
&mut self.interactive_tx_constructor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
|
impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
|
||||||
fn new_for_inbound_channel<'a, ES: Deref, F: Deref, L: Deref>(
|
fn new_for_inbound_channel<'a, ES: Deref, F: Deref, L: Deref>(
|
||||||
fee_estimator: &'a LowerBoundedFeeEstimator<F>,
|
fee_estimator: &'a LowerBoundedFeeEstimator<F>,
|
||||||
@ -3766,6 +3866,16 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
|
|||||||
self.channel_transaction_parameters.channel_type_features = self.channel_type.clone();
|
self.channel_transaction_parameters.channel_type_features = self.channel_type.clone();
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Interactive transaction construction
|
||||||
|
|
||||||
|
pub fn tx_signatures(&self, msg: &msgs::TxSignatures) -> Result<InteractiveTxMessageSend, ChannelError> {
|
||||||
|
todo!();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tx_abort(&self, msg: &msgs::TxAbort) -> Result<InteractiveTxMessageSend, ChannelError> {
|
||||||
|
todo!();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Internal utility functions for channels
|
// Internal utility functions for channels
|
||||||
@ -3823,6 +3933,47 @@ fn get_v2_channel_reserve_satoshis(channel_value_satoshis: u64, dust_limit_satos
|
|||||||
cmp::min(channel_value_satoshis, cmp::max(q, dust_limit_satoshis))
|
cmp::min(channel_value_satoshis, cmp::max(q, dust_limit_satoshis))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(super) fn calculate_our_funding_satoshis(
|
||||||
|
is_initiator: bool, funding_inputs: &[(TxIn, TransactionU16LenLimited)],
|
||||||
|
total_witness_weight: Weight, funding_feerate_sat_per_1000_weight: u32,
|
||||||
|
holder_dust_limit_satoshis: u64,
|
||||||
|
) -> Result<u64, APIError> {
|
||||||
|
let mut total_input_satoshis = 0u64;
|
||||||
|
let mut our_contributed_weight = 0u64;
|
||||||
|
|
||||||
|
for (idx, input) in funding_inputs.iter().enumerate() {
|
||||||
|
if let Some(output) = input.1.as_transaction().output.get(input.0.previous_output.vout as usize) {
|
||||||
|
total_input_satoshis = total_input_satoshis.saturating_add(output.value.to_sat());
|
||||||
|
} else {
|
||||||
|
return Err(APIError::APIMisuseError {
|
||||||
|
err: format!("Transaction with txid {} does not have an output with vout of {} corresponding to TxIn at funding_inputs[{}]",
|
||||||
|
input.1.as_transaction().compute_txid(), input.0.previous_output.vout, idx) });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
our_contributed_weight = our_contributed_weight.saturating_add(total_witness_weight.to_wu());
|
||||||
|
|
||||||
|
// If we are the initiator, we must pay for weight of all common fields in the funding transaction.
|
||||||
|
if is_initiator {
|
||||||
|
our_contributed_weight = our_contributed_weight
|
||||||
|
.saturating_add(TX_COMMON_FIELDS_WEIGHT)
|
||||||
|
// The weight of a P2WSH output to be added later.
|
||||||
|
//
|
||||||
|
// NOTE: The witness script hash given here is irrelevant as it's a fixed size and we just want
|
||||||
|
// to calculate the contributed weight, so we use an all-zero hash.
|
||||||
|
.saturating_add(get_output_weight(&ScriptBuf::new_p2wsh(
|
||||||
|
&WScriptHash::from_raw_hash(Hash::all_zeros())
|
||||||
|
)).to_wu())
|
||||||
|
}
|
||||||
|
|
||||||
|
let funding_satoshis = total_input_satoshis
|
||||||
|
.saturating_sub(fee_for_weight(funding_feerate_sat_per_1000_weight, our_contributed_weight));
|
||||||
|
if funding_satoshis < holder_dust_limit_satoshis {
|
||||||
|
Ok(0)
|
||||||
|
} else {
|
||||||
|
Ok(funding_satoshis)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Context for dual-funded channels.
|
/// Context for dual-funded channels.
|
||||||
pub(super) struct DualFundingChannelContext {
|
pub(super) struct DualFundingChannelContext {
|
||||||
/// The amount in satoshis we will be contributing to the channel.
|
/// The amount in satoshis we will be contributing to the channel.
|
||||||
@ -3831,9 +3982,15 @@ pub(super) struct DualFundingChannelContext {
|
|||||||
pub their_funding_satoshis: u64,
|
pub their_funding_satoshis: u64,
|
||||||
/// The funding transaction locktime suggested by the initiator. If set by us, it is always set
|
/// The funding transaction locktime suggested by the initiator. If set by us, it is always set
|
||||||
/// to the current block height to align incentives against fee-sniping.
|
/// to the current block height to align incentives against fee-sniping.
|
||||||
pub funding_tx_locktime: u32,
|
pub funding_tx_locktime: LockTime,
|
||||||
/// The feerate set by the initiator to be used for the funding transaction.
|
/// The feerate set by the initiator to be used for the funding transaction.
|
||||||
pub funding_feerate_sat_per_1000_weight: u32,
|
pub funding_feerate_sat_per_1000_weight: u32,
|
||||||
|
/// The funding inputs we will be contributing to the channel.
|
||||||
|
///
|
||||||
|
/// Note that the `our_funding_satoshis` field is equal to the total value of `our_funding_inputs`
|
||||||
|
/// minus any fees paid for our contributed weight. This means that change will never be generated
|
||||||
|
/// and the maximum value possible will go towards funding the channel.
|
||||||
|
pub our_funding_inputs: Vec<(TxIn, TransactionU16LenLimited)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Holder designates channel data owned for the benefit of the user client.
|
// Holder designates channel data owned for the benefit of the user client.
|
||||||
@ -8140,7 +8297,7 @@ impl<SP: Deref> InboundV1Channel<SP> where SP::Target: SignerProvider {
|
|||||||
/// should be sent back to the counterparty node.
|
/// should be sent back to the counterparty node.
|
||||||
///
|
///
|
||||||
/// [`msgs::AcceptChannel`]: crate::ln::msgs::AcceptChannel
|
/// [`msgs::AcceptChannel`]: crate::ln::msgs::AcceptChannel
|
||||||
pub fn accept_inbound_channel(&mut self) -> msgs::AcceptChannel {
|
pub fn accept_inbound_channel(&self) -> msgs::AcceptChannel {
|
||||||
if self.context.is_outbound() {
|
if self.context.is_outbound() {
|
||||||
panic!("Tried to send accept_channel for an outbound channel?");
|
panic!("Tried to send accept_channel for an outbound channel?");
|
||||||
}
|
}
|
||||||
@ -8272,8 +8429,9 @@ impl<SP: Deref> OutboundV2Channel<SP> where SP::Target: SignerProvider {
|
|||||||
pub fn new<ES: Deref, F: Deref, L: Deref>(
|
pub fn new<ES: Deref, F: Deref, L: Deref>(
|
||||||
fee_estimator: &LowerBoundedFeeEstimator<F>, entropy_source: &ES, signer_provider: &SP,
|
fee_estimator: &LowerBoundedFeeEstimator<F>, entropy_source: &ES, signer_provider: &SP,
|
||||||
counterparty_node_id: PublicKey, their_features: &InitFeatures, funding_satoshis: u64,
|
counterparty_node_id: PublicKey, their_features: &InitFeatures, funding_satoshis: u64,
|
||||||
user_id: u128, config: &UserConfig, current_chain_height: u32, outbound_scid_alias: u64,
|
funding_inputs: Vec<(TxIn, TransactionU16LenLimited)>, user_id: u128, config: &UserConfig,
|
||||||
funding_confirmation_target: ConfirmationTarget, logger: L,
|
current_chain_height: u32, outbound_scid_alias: u64, funding_confirmation_target: ConfirmationTarget,
|
||||||
|
logger: L,
|
||||||
) -> Result<OutboundV2Channel<SP>, APIError>
|
) -> Result<OutboundV2Channel<SP>, APIError>
|
||||||
where ES::Target: EntropySource,
|
where ES::Target: EntropySource,
|
||||||
F::Target: FeeEstimator,
|
F::Target: FeeEstimator,
|
||||||
@ -8289,7 +8447,11 @@ impl<SP: Deref> OutboundV2Channel<SP> where SP::Target: SignerProvider {
|
|||||||
funding_satoshis, MIN_CHAN_DUST_LIMIT_SATOSHIS);
|
funding_satoshis, MIN_CHAN_DUST_LIMIT_SATOSHIS);
|
||||||
|
|
||||||
let funding_feerate_sat_per_1000_weight = fee_estimator.bounded_sat_per_1000_weight(funding_confirmation_target);
|
let funding_feerate_sat_per_1000_weight = fee_estimator.bounded_sat_per_1000_weight(funding_confirmation_target);
|
||||||
let funding_tx_locktime = current_chain_height;
|
let funding_tx_locktime = LockTime::from_height(current_chain_height)
|
||||||
|
.map_err(|_| APIError::APIMisuseError {
|
||||||
|
err: format!(
|
||||||
|
"Provided current chain height of {} doesn't make sense for a height-based timelock for the funding transaction",
|
||||||
|
current_chain_height) })?;
|
||||||
|
|
||||||
let chan = Self {
|
let chan = Self {
|
||||||
context: ChannelContext::new_for_outbound_channel(
|
context: ChannelContext::new_for_outbound_channel(
|
||||||
@ -8317,6 +8479,7 @@ impl<SP: Deref> OutboundV2Channel<SP> where SP::Target: SignerProvider {
|
|||||||
their_funding_satoshis: 0,
|
their_funding_satoshis: 0,
|
||||||
funding_tx_locktime,
|
funding_tx_locktime,
|
||||||
funding_feerate_sat_per_1000_weight,
|
funding_feerate_sat_per_1000_weight,
|
||||||
|
our_funding_inputs: funding_inputs,
|
||||||
},
|
},
|
||||||
interactive_tx_constructor: None,
|
interactive_tx_constructor: None,
|
||||||
};
|
};
|
||||||
@ -8381,7 +8544,7 @@ impl<SP: Deref> OutboundV2Channel<SP> where SP::Target: SignerProvider {
|
|||||||
},
|
},
|
||||||
funding_feerate_sat_per_1000_weight: self.context.feerate_per_kw,
|
funding_feerate_sat_per_1000_weight: self.context.feerate_per_kw,
|
||||||
second_per_commitment_point,
|
second_per_commitment_point,
|
||||||
locktime: self.dual_funding_context.funding_tx_locktime,
|
locktime: self.dual_funding_context.funding_tx_locktime.to_consensus_u32(),
|
||||||
require_confirmed_inputs: None,
|
require_confirmed_inputs: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -8402,13 +8565,22 @@ impl<SP: Deref> InboundV2Channel<SP> where SP::Target: SignerProvider {
|
|||||||
pub fn new<ES: Deref, F: Deref, L: Deref>(
|
pub fn new<ES: Deref, F: Deref, L: Deref>(
|
||||||
fee_estimator: &LowerBoundedFeeEstimator<F>, entropy_source: &ES, signer_provider: &SP,
|
fee_estimator: &LowerBoundedFeeEstimator<F>, entropy_source: &ES, signer_provider: &SP,
|
||||||
counterparty_node_id: PublicKey, our_supported_features: &ChannelTypeFeatures,
|
counterparty_node_id: PublicKey, our_supported_features: &ChannelTypeFeatures,
|
||||||
their_features: &InitFeatures, msg: &msgs::OpenChannelV2, funding_satoshis: u64, user_id: u128,
|
their_features: &InitFeatures, msg: &msgs::OpenChannelV2,
|
||||||
config: &UserConfig, current_chain_height: u32, logger: &L,
|
funding_inputs: Vec<(TxIn, TransactionU16LenLimited)>, total_witness_weight: Weight,
|
||||||
|
user_id: u128, config: &UserConfig, current_chain_height: u32, logger: &L,
|
||||||
) -> Result<InboundV2Channel<SP>, ChannelError>
|
) -> Result<InboundV2Channel<SP>, ChannelError>
|
||||||
where ES::Target: EntropySource,
|
where ES::Target: EntropySource,
|
||||||
F::Target: FeeEstimator,
|
F::Target: FeeEstimator,
|
||||||
L::Target: Logger,
|
L::Target: Logger,
|
||||||
{
|
{
|
||||||
|
let funding_satoshis = calculate_our_funding_satoshis(
|
||||||
|
false, &funding_inputs, total_witness_weight, msg.funding_feerate_sat_per_1000_weight,
|
||||||
|
msg.common_fields.dust_limit_satoshis
|
||||||
|
).map_err(|_| ChannelError::Close(
|
||||||
|
(
|
||||||
|
"Failed to accept channel".to_string(),
|
||||||
|
ClosureReason::HolderForceClosed { broadcasted_latest_txn: Some(false) },
|
||||||
|
)))?;
|
||||||
let channel_value_satoshis = funding_satoshis.saturating_add(msg.common_fields.funding_satoshis);
|
let channel_value_satoshis = funding_satoshis.saturating_add(msg.common_fields.funding_satoshis);
|
||||||
let counterparty_selected_channel_reserve_satoshis = get_v2_channel_reserve_satoshis(
|
let counterparty_selected_channel_reserve_satoshis = get_v2_channel_reserve_satoshis(
|
||||||
channel_value_satoshis, msg.common_fields.dust_limit_satoshis);
|
channel_value_satoshis, msg.common_fields.dust_limit_satoshis);
|
||||||
@ -8457,26 +8629,43 @@ impl<SP: Deref> InboundV2Channel<SP> where SP::Target: SignerProvider {
|
|||||||
&context.get_counterparty_pubkeys().revocation_basepoint);
|
&context.get_counterparty_pubkeys().revocation_basepoint);
|
||||||
context.channel_id = channel_id;
|
context.channel_id = channel_id;
|
||||||
|
|
||||||
let chan = Self {
|
let dual_funding_context = DualFundingChannelContext {
|
||||||
context,
|
our_funding_satoshis: funding_satoshis,
|
||||||
unfunded_context: UnfundedChannelContext { unfunded_channel_age_ticks: 0 },
|
their_funding_satoshis: msg.common_fields.funding_satoshis,
|
||||||
dual_funding_context: DualFundingChannelContext {
|
funding_tx_locktime: LockTime::from_consensus(msg.locktime),
|
||||||
our_funding_satoshis: funding_satoshis,
|
funding_feerate_sat_per_1000_weight: msg.funding_feerate_sat_per_1000_weight,
|
||||||
their_funding_satoshis: msg.common_fields.funding_satoshis,
|
our_funding_inputs: funding_inputs.clone(),
|
||||||
funding_tx_locktime: msg.locktime,
|
|
||||||
funding_feerate_sat_per_1000_weight: msg.funding_feerate_sat_per_1000_weight,
|
|
||||||
},
|
|
||||||
interactive_tx_constructor: None,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(chan)
|
let interactive_tx_constructor = Some(InteractiveTxConstructor::new(
|
||||||
|
InteractiveTxConstructorArgs {
|
||||||
|
entropy_source,
|
||||||
|
channel_id: context.channel_id,
|
||||||
|
feerate_sat_per_kw: dual_funding_context.funding_feerate_sat_per_1000_weight,
|
||||||
|
funding_tx_locktime: dual_funding_context.funding_tx_locktime,
|
||||||
|
is_initiator: false,
|
||||||
|
inputs_to_contribute: funding_inputs,
|
||||||
|
outputs_to_contribute: Vec::new(),
|
||||||
|
expected_remote_shared_funding_output: Some((context.get_funding_redeemscript(), context.channel_value_satoshis)),
|
||||||
|
}
|
||||||
|
).map_err(|_| ChannelError::Close((
|
||||||
|
"V2 channel rejected due to sender error".into(),
|
||||||
|
ClosureReason::HolderForceClosed { broadcasted_latest_txn: Some(false) }
|
||||||
|
)))?);
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
context,
|
||||||
|
dual_funding_context,
|
||||||
|
interactive_tx_constructor,
|
||||||
|
unfunded_context: UnfundedChannelContext { unfunded_channel_age_ticks: 0 },
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Marks an inbound channel as accepted and generates a [`msgs::AcceptChannelV2`] message which
|
/// Marks an inbound channel as accepted and generates a [`msgs::AcceptChannelV2`] message which
|
||||||
/// should be sent back to the counterparty node.
|
/// should be sent back to the counterparty node.
|
||||||
///
|
///
|
||||||
/// [`msgs::AcceptChannelV2`]: crate::ln::msgs::AcceptChannelV2
|
/// [`msgs::AcceptChannelV2`]: crate::ln::msgs::AcceptChannelV2
|
||||||
pub fn accept_inbound_dual_funded_channel(&mut self) -> msgs::AcceptChannelV2 {
|
pub fn accept_inbound_dual_funded_channel(&self) -> msgs::AcceptChannelV2 {
|
||||||
if self.context.is_outbound() {
|
if self.context.is_outbound() {
|
||||||
debug_assert!(false, "Tried to send accept_channel for an outbound channel?");
|
debug_assert!(false, "Tried to send accept_channel for an outbound channel?");
|
||||||
}
|
}
|
||||||
@ -8493,9 +8682,9 @@ impl<SP: Deref> InboundV2Channel<SP> where SP::Target: SignerProvider {
|
|||||||
self.generate_accept_channel_v2_message()
|
self.generate_accept_channel_v2_message()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This function is used to explicitly generate a [`msgs::AcceptChannel`] message for an
|
/// This function is used to explicitly generate a [`msgs::AcceptChannelV2`] message for an
|
||||||
/// inbound channel. If the intention is to accept an inbound channel, use
|
/// inbound dual-funded channel. If the intention is to accept a V1 established inbound channel,
|
||||||
/// [`InboundV1Channel::accept_inbound_channel`] instead.
|
/// use [`InboundV1Channel::accept_inbound_channel`] instead.
|
||||||
///
|
///
|
||||||
/// [`msgs::AcceptChannelV2`]: crate::ln::msgs::AcceptChannelV2
|
/// [`msgs::AcceptChannelV2`]: crate::ln::msgs::AcceptChannelV2
|
||||||
fn generate_accept_channel_v2_message(&self) -> msgs::AcceptChannelV2 {
|
fn generate_accept_channel_v2_message(&self) -> msgs::AcceptChannelV2 {
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
//! imply it needs to fail HTLCs/payments/channels it manages).
|
//! imply it needs to fail HTLCs/payments/channels it manages).
|
||||||
|
|
||||||
use bitcoin::block::Header;
|
use bitcoin::block::Header;
|
||||||
use bitcoin::transaction::Transaction;
|
use bitcoin::transaction::{Transaction, TxIn};
|
||||||
use bitcoin::constants::ChainHash;
|
use bitcoin::constants::ChainHash;
|
||||||
use bitcoin::key::constants::SECRET_KEY_SIZE;
|
use bitcoin::key::constants::SECRET_KEY_SIZE;
|
||||||
use bitcoin::network::Network;
|
use bitcoin::network::Network;
|
||||||
@ -30,7 +30,7 @@ use bitcoin::hash_types::{BlockHash, Txid};
|
|||||||
|
|
||||||
use bitcoin::secp256k1::{SecretKey,PublicKey};
|
use bitcoin::secp256k1::{SecretKey,PublicKey};
|
||||||
use bitcoin::secp256k1::Secp256k1;
|
use bitcoin::secp256k1::Secp256k1;
|
||||||
use bitcoin::{secp256k1, Sequence};
|
use bitcoin::{secp256k1, Sequence, Weight};
|
||||||
|
|
||||||
use crate::events::FundingInfo;
|
use crate::events::FundingInfo;
|
||||||
use crate::blinded_path::message::{AsyncPaymentsContext, MessageContext, OffersContext};
|
use crate::blinded_path::message::{AsyncPaymentsContext, MessageContext, OffersContext};
|
||||||
@ -42,14 +42,13 @@ use crate::chain::{Confirm, ChannelMonitorUpdateStatus, Watch, BestBlock};
|
|||||||
use crate::chain::chaininterface::{BroadcasterInterface, ConfirmationTarget, FeeEstimator, LowerBoundedFeeEstimator};
|
use crate::chain::chaininterface::{BroadcasterInterface, ConfirmationTarget, FeeEstimator, LowerBoundedFeeEstimator};
|
||||||
use crate::chain::channelmonitor::{Balance, ChannelMonitor, ChannelMonitorUpdate, WithChannelMonitor, ChannelMonitorUpdateStep, HTLC_FAIL_BACK_BUFFER, CLTV_CLAIM_BUFFER, LATENCY_GRACE_PERIOD_BLOCKS, ANTI_REORG_DELAY, MonitorEvent};
|
use crate::chain::channelmonitor::{Balance, ChannelMonitor, ChannelMonitorUpdate, WithChannelMonitor, ChannelMonitorUpdateStep, HTLC_FAIL_BACK_BUFFER, CLTV_CLAIM_BUFFER, LATENCY_GRACE_PERIOD_BLOCKS, ANTI_REORG_DELAY, MonitorEvent};
|
||||||
use crate::chain::transaction::{OutPoint, TransactionData};
|
use crate::chain::transaction::{OutPoint, TransactionData};
|
||||||
use crate::events;
|
use crate::events::{self, Event, EventHandler, EventsProvider, InboundChannelFunds, MessageSendEvent, MessageSendEventsProvider, ClosureReason, HTLCDestination, PaymentFailureReason, ReplayEvent};
|
||||||
use crate::events::{Event, EventHandler, EventsProvider, MessageSendEvent, MessageSendEventsProvider, ClosureReason, HTLCDestination, PaymentFailureReason, ReplayEvent};
|
|
||||||
// Since this struct is returned in `list_channels` methods, expose it here in case users want to
|
// Since this struct is returned in `list_channels` methods, expose it here in case users want to
|
||||||
// construct one themselves.
|
// construct one themselves.
|
||||||
use crate::ln::inbound_payment;
|
use crate::ln::inbound_payment;
|
||||||
use crate::ln::types::ChannelId;
|
use crate::ln::types::ChannelId;
|
||||||
use crate::types::payment::{PaymentHash, PaymentPreimage, PaymentSecret};
|
use crate::types::payment::{PaymentHash, PaymentPreimage, PaymentSecret};
|
||||||
use crate::ln::channel::{self, Channel, ChannelPhase, ChannelError, ChannelUpdateStatus, ShutdownResult, UpdateFulfillCommitFetch, OutboundV1Channel, InboundV1Channel, WithChannelContext};
|
use crate::ln::channel::{self, Channel, ChannelPhase, ChannelError, ChannelUpdateStatus, ShutdownResult, UpdateFulfillCommitFetch, OutboundV1Channel, InboundV1Channel, WithChannelContext, InboundV2Channel, InteractivelyFunded as _};
|
||||||
use crate::ln::channel_state::ChannelDetails;
|
use crate::ln::channel_state::ChannelDetails;
|
||||||
use crate::types::features::{Bolt12InvoiceFeatures, ChannelFeatures, ChannelTypeFeatures, InitFeatures, NodeFeatures};
|
use crate::types::features::{Bolt12InvoiceFeatures, ChannelFeatures, ChannelTypeFeatures, InitFeatures, NodeFeatures};
|
||||||
#[cfg(any(feature = "_test_utils", test))]
|
#[cfg(any(feature = "_test_utils", test))]
|
||||||
@ -85,6 +84,7 @@ use crate::util::wakers::{Future, Notifier};
|
|||||||
use crate::util::scid_utils::fake_scid;
|
use crate::util::scid_utils::fake_scid;
|
||||||
use crate::util::string::UntrustedString;
|
use crate::util::string::UntrustedString;
|
||||||
use crate::util::ser::{BigSize, FixedLengthReader, Readable, ReadableArgs, MaybeReadable, Writeable, Writer, VecWriter};
|
use crate::util::ser::{BigSize, FixedLengthReader, Readable, ReadableArgs, MaybeReadable, Writeable, Writer, VecWriter};
|
||||||
|
use crate::util::ser::TransactionU16LenLimited;
|
||||||
use crate::util::logger::{Level, Logger, WithContext};
|
use crate::util::logger::{Level, Logger, WithContext};
|
||||||
use crate::util::errors::APIError;
|
use crate::util::errors::APIError;
|
||||||
|
|
||||||
@ -1357,11 +1357,22 @@ impl <SP: Deref> PeerState<SP> where SP::Target: SignerProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub(super) enum OpenChannelMessage {
|
||||||
|
V1(msgs::OpenChannel),
|
||||||
|
V2(msgs::OpenChannelV2),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) enum OpenChannelMessageRef<'a> {
|
||||||
|
V1(&'a msgs::OpenChannel),
|
||||||
|
V2(&'a msgs::OpenChannelV2),
|
||||||
|
}
|
||||||
|
|
||||||
/// A not-yet-accepted inbound (from counterparty) channel. Once
|
/// A not-yet-accepted inbound (from counterparty) channel. Once
|
||||||
/// accepted, the parameters will be used to construct a channel.
|
/// accepted, the parameters will be used to construct a channel.
|
||||||
pub(super) struct InboundChannelRequest {
|
pub(super) struct InboundChannelRequest {
|
||||||
/// The original OpenChannel message.
|
/// The original OpenChannel message.
|
||||||
pub open_channel_msg: msgs::OpenChannel,
|
pub open_channel_msg: OpenChannelMessage,
|
||||||
/// The number of ticks remaining before the request expires.
|
/// The number of ticks remaining before the request expires.
|
||||||
pub ticks_remaining: i32,
|
pub ticks_remaining: i32,
|
||||||
}
|
}
|
||||||
@ -7591,7 +7602,7 @@ where
|
|||||||
/// [`Event::OpenChannelRequest`]: events::Event::OpenChannelRequest
|
/// [`Event::OpenChannelRequest`]: events::Event::OpenChannelRequest
|
||||||
/// [`Event::ChannelClosed::user_channel_id`]: events::Event::ChannelClosed::user_channel_id
|
/// [`Event::ChannelClosed::user_channel_id`]: events::Event::ChannelClosed::user_channel_id
|
||||||
pub fn accept_inbound_channel(&self, temporary_channel_id: &ChannelId, counterparty_node_id: &PublicKey, user_channel_id: u128) -> Result<(), APIError> {
|
pub fn accept_inbound_channel(&self, temporary_channel_id: &ChannelId, counterparty_node_id: &PublicKey, user_channel_id: u128) -> Result<(), APIError> {
|
||||||
self.do_accept_inbound_channel(temporary_channel_id, counterparty_node_id, false, user_channel_id)
|
self.do_accept_inbound_channel(temporary_channel_id, counterparty_node_id, false, user_channel_id, vec![], Weight::from_wu(0))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Accepts a request to open a channel after a [`events::Event::OpenChannelRequest`], treating
|
/// Accepts a request to open a channel after a [`events::Event::OpenChannelRequest`], treating
|
||||||
@ -7613,11 +7624,14 @@ where
|
|||||||
/// [`Event::OpenChannelRequest`]: events::Event::OpenChannelRequest
|
/// [`Event::OpenChannelRequest`]: events::Event::OpenChannelRequest
|
||||||
/// [`Event::ChannelClosed::user_channel_id`]: events::Event::ChannelClosed::user_channel_id
|
/// [`Event::ChannelClosed::user_channel_id`]: events::Event::ChannelClosed::user_channel_id
|
||||||
pub fn accept_inbound_channel_from_trusted_peer_0conf(&self, temporary_channel_id: &ChannelId, counterparty_node_id: &PublicKey, user_channel_id: u128) -> Result<(), APIError> {
|
pub fn accept_inbound_channel_from_trusted_peer_0conf(&self, temporary_channel_id: &ChannelId, counterparty_node_id: &PublicKey, user_channel_id: u128) -> Result<(), APIError> {
|
||||||
self.do_accept_inbound_channel(temporary_channel_id, counterparty_node_id, true, user_channel_id)
|
self.do_accept_inbound_channel(temporary_channel_id, counterparty_node_id, true, user_channel_id, vec![], Weight::from_wu(0))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn do_accept_inbound_channel(&self, temporary_channel_id: &ChannelId, counterparty_node_id: &PublicKey, accept_0conf: bool, user_channel_id: u128) -> Result<(), APIError> {
|
fn do_accept_inbound_channel(
|
||||||
|
&self, temporary_channel_id: &ChannelId, counterparty_node_id: &PublicKey, accept_0conf: bool,
|
||||||
|
user_channel_id: u128, funding_inputs: Vec<(TxIn, TransactionU16LenLimited)>,
|
||||||
|
total_witness_weight: Weight,
|
||||||
|
) -> Result<(), APIError> {
|
||||||
let logger = WithContext::from(&self.logger, Some(*counterparty_node_id), Some(*temporary_channel_id), None);
|
let logger = WithContext::from(&self.logger, Some(*counterparty_node_id), Some(*temporary_channel_id), None);
|
||||||
let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
|
let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
|
||||||
|
|
||||||
@ -7642,12 +7656,44 @@ where
|
|||||||
let res = match peer_state.inbound_channel_request_by_id.remove(temporary_channel_id) {
|
let res = match peer_state.inbound_channel_request_by_id.remove(temporary_channel_id) {
|
||||||
Some(unaccepted_channel) => {
|
Some(unaccepted_channel) => {
|
||||||
let best_block_height = self.best_block.read().unwrap().height;
|
let best_block_height = self.best_block.read().unwrap().height;
|
||||||
InboundV1Channel::new(&self.fee_estimator, &self.entropy_source, &self.signer_provider,
|
match unaccepted_channel.open_channel_msg {
|
||||||
counterparty_node_id.clone(), &self.channel_type_features(), &peer_state.latest_features,
|
OpenChannelMessage::V1(open_channel_msg) => {
|
||||||
&unaccepted_channel.open_channel_msg, user_channel_id, &self.default_configuration, best_block_height,
|
InboundV1Channel::new(
|
||||||
&self.logger, accept_0conf).map_err(|err| MsgHandleErrInternal::from_chan_no_close(err, *temporary_channel_id))
|
&self.fee_estimator, &self.entropy_source, &self.signer_provider, *counterparty_node_id,
|
||||||
|
&self.channel_type_features(), &peer_state.latest_features, &open_channel_msg,
|
||||||
|
user_channel_id, &self.default_configuration, best_block_height, &self.logger, accept_0conf
|
||||||
|
).map_err(|err| MsgHandleErrInternal::from_chan_no_close(err, *temporary_channel_id)
|
||||||
|
).map(|channel| {
|
||||||
|
let message_send_event = events::MessageSendEvent::SendAcceptChannel {
|
||||||
|
node_id: *counterparty_node_id,
|
||||||
|
msg: channel.accept_inbound_channel(),
|
||||||
|
};
|
||||||
|
(*temporary_channel_id, ChannelPhase::UnfundedInboundV1(channel), message_send_event)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
OpenChannelMessage::V2(open_channel_msg) => {
|
||||||
|
InboundV2Channel::new(&self.fee_estimator, &self.entropy_source, &self.signer_provider,
|
||||||
|
*counterparty_node_id, &self.channel_type_features(), &peer_state.latest_features,
|
||||||
|
&open_channel_msg, funding_inputs, total_witness_weight, user_channel_id,
|
||||||
|
&self.default_configuration, best_block_height, &self.logger
|
||||||
|
).map_err(|_| MsgHandleErrInternal::from_chan_no_close(
|
||||||
|
ChannelError::Close(
|
||||||
|
(
|
||||||
|
"V2 channel rejected due to sender error".into(),
|
||||||
|
ClosureReason::HolderForceClosed { broadcasted_latest_txn: Some(false) },
|
||||||
|
)
|
||||||
|
), *temporary_channel_id)
|
||||||
|
).map(|channel| {
|
||||||
|
let message_send_event = events::MessageSendEvent::SendAcceptChannelV2 {
|
||||||
|
node_id: channel.context.get_counterparty_node_id(),
|
||||||
|
msg: channel.accept_inbound_dual_funded_channel()
|
||||||
|
};
|
||||||
|
(channel.context.channel_id(), ChannelPhase::UnfundedInboundV2(channel), message_send_event)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
}
|
||||||
},
|
},
|
||||||
_ => {
|
None => {
|
||||||
let err_str = "No such channel awaiting to be accepted.".to_owned();
|
let err_str = "No such channel awaiting to be accepted.".to_owned();
|
||||||
log_error!(logger, "{}", err_str);
|
log_error!(logger, "{}", err_str);
|
||||||
|
|
||||||
@ -7655,10 +7701,14 @@ where
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
match res {
|
// We have to match below instead of map_err on the above as in the map_err closure the borrow checker
|
||||||
|
// would consider peer_state moved even though we would bail out with the `?` operator.
|
||||||
|
let (channel_id, mut channel_phase, message_send_event) = match res {
|
||||||
|
Ok(res) => res,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
mem::drop(peer_state_lock);
|
mem::drop(peer_state_lock);
|
||||||
mem::drop(per_peer_state);
|
mem::drop(per_peer_state);
|
||||||
|
// TODO(dunxen): Find/make less icky way to do this.
|
||||||
match handle_error!(self, Result::<(), MsgHandleErrInternal>::Err(err), *counterparty_node_id) {
|
match handle_error!(self, Result::<(), MsgHandleErrInternal>::Err(err), *counterparty_node_id) {
|
||||||
Ok(_) => unreachable!("`handle_error` only returns Err as we've passed in an Err"),
|
Ok(_) => unreachable!("`handle_error` only returns Err as we've passed in an Err"),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
@ -7666,55 +7716,50 @@ where
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(mut channel) => {
|
};
|
||||||
if accept_0conf {
|
|
||||||
// This should have been correctly configured by the call to InboundV1Channel::new.
|
|
||||||
debug_assert!(channel.context.minimum_depth().unwrap() == 0);
|
|
||||||
} else if channel.context.get_channel_type().requires_zero_conf() {
|
|
||||||
let send_msg_err_event = events::MessageSendEvent::HandleError {
|
|
||||||
node_id: channel.context.get_counterparty_node_id(),
|
|
||||||
action: msgs::ErrorAction::SendErrorMessage{
|
|
||||||
msg: msgs::ErrorMessage { channel_id: temporary_channel_id.clone(), data: "No zero confirmation channels accepted".to_owned(), }
|
|
||||||
}
|
|
||||||
};
|
|
||||||
peer_state.pending_msg_events.push(send_msg_err_event);
|
|
||||||
let err_str = "Please use accept_inbound_channel_from_trusted_peer_0conf to accept channels with zero confirmations.".to_owned();
|
|
||||||
log_error!(logger, "{}", err_str);
|
|
||||||
|
|
||||||
return Err(APIError::APIMisuseError { err: err_str });
|
if accept_0conf {
|
||||||
} else {
|
// This should have been correctly configured by the call to Inbound(V1/V2)Channel::new.
|
||||||
// If this peer already has some channels, a new channel won't increase our number of peers
|
debug_assert!(channel_phase.context().minimum_depth().unwrap() == 0);
|
||||||
// with unfunded channels, so as long as we aren't over the maximum number of unfunded
|
} else if channel_phase.context().get_channel_type().requires_zero_conf() {
|
||||||
// channels per-peer we can accept channels from a peer with existing ones.
|
let send_msg_err_event = events::MessageSendEvent::HandleError {
|
||||||
if is_only_peer_channel && peers_without_funded_channels >= MAX_UNFUNDED_CHANNEL_PEERS {
|
node_id: channel_phase.context().get_counterparty_node_id(),
|
||||||
let send_msg_err_event = events::MessageSendEvent::HandleError {
|
action: msgs::ErrorAction::SendErrorMessage{
|
||||||
node_id: channel.context.get_counterparty_node_id(),
|
msg: msgs::ErrorMessage { channel_id: *temporary_channel_id, data: "No zero confirmation channels accepted".to_owned(), }
|
||||||
action: msgs::ErrorAction::SendErrorMessage{
|
|
||||||
msg: msgs::ErrorMessage { channel_id: temporary_channel_id.clone(), data: "Have too many peers with unfunded channels, not accepting new ones".to_owned(), }
|
|
||||||
}
|
|
||||||
};
|
|
||||||
peer_state.pending_msg_events.push(send_msg_err_event);
|
|
||||||
let err_str = "Too many peers with unfunded channels, refusing to accept new ones".to_owned();
|
|
||||||
log_error!(logger, "{}", err_str);
|
|
||||||
|
|
||||||
return Err(APIError::APIMisuseError { err: err_str });
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
peer_state.pending_msg_events.push(send_msg_err_event);
|
||||||
|
let err_str = "Please use accept_inbound_channel_from_trusted_peer_0conf to accept channels with zero confirmations.".to_owned();
|
||||||
|
log_error!(logger, "{}", err_str);
|
||||||
|
|
||||||
// Now that we know we have a channel, assign an outbound SCID alias.
|
return Err(APIError::APIMisuseError { err: err_str });
|
||||||
let outbound_scid_alias = self.create_and_insert_outbound_scid_alias();
|
} else {
|
||||||
channel.context.set_outbound_scid_alias(outbound_scid_alias);
|
// If this peer already has some channels, a new channel won't increase our number of peers
|
||||||
|
// with unfunded channels, so as long as we aren't over the maximum number of unfunded
|
||||||
|
// channels per-peer we can accept channels from a peer with existing ones.
|
||||||
|
if is_only_peer_channel && peers_without_funded_channels >= MAX_UNFUNDED_CHANNEL_PEERS {
|
||||||
|
let send_msg_err_event = events::MessageSendEvent::HandleError {
|
||||||
|
node_id: channel_phase.context().get_counterparty_node_id(),
|
||||||
|
action: msgs::ErrorAction::SendErrorMessage{
|
||||||
|
msg: msgs::ErrorMessage { channel_id: *temporary_channel_id, data: "Have too many peers with unfunded channels, not accepting new ones".to_owned(), }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
peer_state.pending_msg_events.push(send_msg_err_event);
|
||||||
|
let err_str = "Too many peers with unfunded channels, refusing to accept new ones".to_owned();
|
||||||
|
log_error!(logger, "{}", err_str);
|
||||||
|
|
||||||
peer_state.pending_msg_events.push(events::MessageSendEvent::SendAcceptChannel {
|
return Err(APIError::APIMisuseError { err: err_str });
|
||||||
node_id: channel.context.get_counterparty_node_id(),
|
}
|
||||||
msg: channel.accept_inbound_channel(),
|
|
||||||
});
|
|
||||||
|
|
||||||
peer_state.channel_by_id.insert(temporary_channel_id.clone(), ChannelPhase::UnfundedInboundV1(channel));
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Now that we know we have a channel, assign an outbound SCID alias.
|
||||||
|
let outbound_scid_alias = self.create_and_insert_outbound_scid_alias();
|
||||||
|
channel_phase.context_mut().set_outbound_scid_alias(outbound_scid_alias);
|
||||||
|
|
||||||
|
peer_state.pending_msg_events.push(message_send_event);
|
||||||
|
peer_state.channel_by_id.insert(channel_id, channel_phase);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the number of peers which match the given filter and do not have any funded, outbound,
|
/// Gets the number of peers which match the given filter and do not have any funded, outbound,
|
||||||
@ -7777,17 +7822,24 @@ where
|
|||||||
num_unfunded_channels + peer.inbound_channel_request_by_id.len()
|
num_unfunded_channels + peer.inbound_channel_request_by_id.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn internal_open_channel(&self, counterparty_node_id: &PublicKey, msg: &msgs::OpenChannel) -> Result<(), MsgHandleErrInternal> {
|
fn internal_open_channel(&self, counterparty_node_id: &PublicKey, msg: OpenChannelMessageRef<'_>) -> Result<(), MsgHandleErrInternal> {
|
||||||
|
let common_fields = match msg {
|
||||||
|
OpenChannelMessageRef::V1(msg) => &msg.common_fields,
|
||||||
|
OpenChannelMessageRef::V2(msg) => &msg.common_fields,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Do common open_channel(2) checks
|
||||||
|
|
||||||
// Note that the ChannelManager is NOT re-persisted on disk after this, so any changes are
|
// Note that the ChannelManager is NOT re-persisted on disk after this, so any changes are
|
||||||
// likely to be lost on restart!
|
// likely to be lost on restart!
|
||||||
if msg.common_fields.chain_hash != self.chain_hash {
|
if common_fields.chain_hash != self.chain_hash {
|
||||||
return Err(MsgHandleErrInternal::send_err_msg_no_close("Unknown genesis block hash".to_owned(),
|
return Err(MsgHandleErrInternal::send_err_msg_no_close("Unknown genesis block hash".to_owned(),
|
||||||
msg.common_fields.temporary_channel_id.clone()));
|
common_fields.temporary_channel_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
if !self.default_configuration.accept_inbound_channels {
|
if !self.default_configuration.accept_inbound_channels {
|
||||||
return Err(MsgHandleErrInternal::send_err_msg_no_close("No inbound channels accepted".to_owned(),
|
return Err(MsgHandleErrInternal::send_err_msg_no_close("No inbound channels accepted".to_owned(),
|
||||||
msg.common_fields.temporary_channel_id.clone()));
|
common_fields.temporary_channel_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the number of peers with channels, but without funded ones. We don't care too much
|
// Get the number of peers with channels, but without funded ones. We don't care too much
|
||||||
@ -7802,7 +7854,7 @@ where
|
|||||||
debug_assert!(false);
|
debug_assert!(false);
|
||||||
MsgHandleErrInternal::send_err_msg_no_close(
|
MsgHandleErrInternal::send_err_msg_no_close(
|
||||||
format!("Can't find a peer matching the passed counterparty node_id {}", counterparty_node_id),
|
format!("Can't find a peer matching the passed counterparty node_id {}", counterparty_node_id),
|
||||||
msg.common_fields.temporary_channel_id.clone())
|
common_fields.temporary_channel_id)
|
||||||
})?;
|
})?;
|
||||||
let mut peer_state_lock = peer_state_mutex.lock().unwrap();
|
let mut peer_state_lock = peer_state_mutex.lock().unwrap();
|
||||||
let peer_state = &mut *peer_state_lock;
|
let peer_state = &mut *peer_state_lock;
|
||||||
@ -7816,44 +7868,51 @@ where
|
|||||||
{
|
{
|
||||||
return Err(MsgHandleErrInternal::send_err_msg_no_close(
|
return Err(MsgHandleErrInternal::send_err_msg_no_close(
|
||||||
"Have too many peers with unfunded channels, not accepting new ones".to_owned(),
|
"Have too many peers with unfunded channels, not accepting new ones".to_owned(),
|
||||||
msg.common_fields.temporary_channel_id.clone()));
|
common_fields.temporary_channel_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
let best_block_height = self.best_block.read().unwrap().height;
|
let best_block_height = self.best_block.read().unwrap().height;
|
||||||
if Self::unfunded_channel_count(peer_state, best_block_height) >= MAX_UNFUNDED_CHANS_PER_PEER {
|
if Self::unfunded_channel_count(peer_state, best_block_height) >= MAX_UNFUNDED_CHANS_PER_PEER {
|
||||||
return Err(MsgHandleErrInternal::send_err_msg_no_close(
|
return Err(MsgHandleErrInternal::send_err_msg_no_close(
|
||||||
format!("Refusing more than {} unfunded channels.", MAX_UNFUNDED_CHANS_PER_PEER),
|
format!("Refusing more than {} unfunded channels.", MAX_UNFUNDED_CHANS_PER_PEER),
|
||||||
msg.common_fields.temporary_channel_id.clone()));
|
common_fields.temporary_channel_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
let channel_id = msg.common_fields.temporary_channel_id;
|
let channel_id = common_fields.temporary_channel_id;
|
||||||
let channel_exists = peer_state.has_channel(&channel_id);
|
let channel_exists = peer_state.has_channel(&channel_id);
|
||||||
if channel_exists {
|
if channel_exists {
|
||||||
return Err(MsgHandleErrInternal::send_err_msg_no_close(
|
return Err(MsgHandleErrInternal::send_err_msg_no_close(
|
||||||
"temporary_channel_id collision for the same peer!".to_owned(),
|
"temporary_channel_id collision for the same peer!".to_owned(),
|
||||||
msg.common_fields.temporary_channel_id.clone()));
|
common_fields.temporary_channel_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We can get the channel type at this point already as we'll need it immediately in both the
|
||||||
|
// manual and the automatic acceptance cases.
|
||||||
|
let channel_type = channel::channel_type_from_open_channel(
|
||||||
|
common_fields, &peer_state.latest_features, &self.channel_type_features()
|
||||||
|
).map_err(|e| MsgHandleErrInternal::from_chan_no_close(e, common_fields.temporary_channel_id))?;
|
||||||
|
|
||||||
// If we're doing manual acceptance checks on the channel, then defer creation until we're sure we want to accept.
|
// If we're doing manual acceptance checks on the channel, then defer creation until we're sure we want to accept.
|
||||||
if self.default_configuration.manually_accept_inbound_channels {
|
if self.default_configuration.manually_accept_inbound_channels {
|
||||||
let channel_type = channel::channel_type_from_open_channel(
|
|
||||||
&msg.common_fields, &peer_state.latest_features, &self.channel_type_features()
|
|
||||||
).map_err(|e|
|
|
||||||
MsgHandleErrInternal::from_chan_no_close(e, msg.common_fields.temporary_channel_id)
|
|
||||||
)?;
|
|
||||||
let mut pending_events = self.pending_events.lock().unwrap();
|
let mut pending_events = self.pending_events.lock().unwrap();
|
||||||
let is_announced = (msg.common_fields.channel_flags & 1) == 1;
|
let is_announced = (common_fields.channel_flags & 1) == 1;
|
||||||
pending_events.push_back((events::Event::OpenChannelRequest {
|
pending_events.push_back((events::Event::OpenChannelRequest {
|
||||||
temporary_channel_id: msg.common_fields.temporary_channel_id.clone(),
|
temporary_channel_id: common_fields.temporary_channel_id,
|
||||||
counterparty_node_id: counterparty_node_id.clone(),
|
counterparty_node_id: *counterparty_node_id,
|
||||||
funding_satoshis: msg.common_fields.funding_satoshis,
|
funding_satoshis: common_fields.funding_satoshis,
|
||||||
push_msat: msg.push_msat,
|
channel_negotiation_type: match msg {
|
||||||
|
OpenChannelMessageRef::V1(msg) => InboundChannelFunds::PushMsat(msg.push_msat),
|
||||||
|
OpenChannelMessageRef::V2(_) => InboundChannelFunds::DualFunded,
|
||||||
|
},
|
||||||
channel_type,
|
channel_type,
|
||||||
is_announced,
|
is_announced,
|
||||||
params: msg.common_fields.channel_parameters(),
|
params: common_fields.channel_parameters(),
|
||||||
}, None));
|
}, None));
|
||||||
peer_state.inbound_channel_request_by_id.insert(channel_id, InboundChannelRequest {
|
peer_state.inbound_channel_request_by_id.insert(channel_id, InboundChannelRequest {
|
||||||
open_channel_msg: msg.clone(),
|
open_channel_msg: match msg {
|
||||||
|
OpenChannelMessageRef::V1(msg) => OpenChannelMessage::V1(msg.clone()),
|
||||||
|
OpenChannelMessageRef::V2(msg) => OpenChannelMessage::V2(msg.clone()),
|
||||||
|
},
|
||||||
ticks_remaining: UNACCEPTED_INBOUND_CHANNEL_AGE_LIMIT_TICKS,
|
ticks_remaining: UNACCEPTED_INBOUND_CHANNEL_AGE_LIMIT_TICKS,
|
||||||
});
|
});
|
||||||
return Ok(());
|
return Ok(());
|
||||||
@ -7863,36 +7922,47 @@ where
|
|||||||
let mut random_bytes = [0u8; 16];
|
let mut random_bytes = [0u8; 16];
|
||||||
random_bytes.copy_from_slice(&self.entropy_source.get_secure_random_bytes()[..16]);
|
random_bytes.copy_from_slice(&self.entropy_source.get_secure_random_bytes()[..16]);
|
||||||
let user_channel_id = u128::from_be_bytes(random_bytes);
|
let user_channel_id = u128::from_be_bytes(random_bytes);
|
||||||
let mut channel = match InboundV1Channel::new(&self.fee_estimator, &self.entropy_source, &self.signer_provider,
|
|
||||||
counterparty_node_id.clone(), &self.channel_type_features(), &peer_state.latest_features, msg, user_channel_id,
|
|
||||||
&self.default_configuration, best_block_height, &self.logger, /*is_0conf=*/false)
|
|
||||||
{
|
|
||||||
Err(e) => {
|
|
||||||
return Err(MsgHandleErrInternal::from_chan_no_close(e, msg.common_fields.temporary_channel_id));
|
|
||||||
},
|
|
||||||
Ok(res) => res
|
|
||||||
};
|
|
||||||
|
|
||||||
let channel_type = channel.context.get_channel_type();
|
|
||||||
if channel_type.requires_zero_conf() {
|
if channel_type.requires_zero_conf() {
|
||||||
return Err(MsgHandleErrInternal::send_err_msg_no_close(
|
return Err(MsgHandleErrInternal::send_err_msg_no_close("No zero confirmation channels accepted".to_owned(), common_fields.temporary_channel_id));
|
||||||
"No zero confirmation channels accepted".to_owned(),
|
|
||||||
msg.common_fields.temporary_channel_id.clone()));
|
|
||||||
}
|
}
|
||||||
if channel_type.requires_anchors_zero_fee_htlc_tx() {
|
if channel_type.requires_anchors_zero_fee_htlc_tx() {
|
||||||
return Err(MsgHandleErrInternal::send_err_msg_no_close(
|
return Err(MsgHandleErrInternal::send_err_msg_no_close("No channels with anchor outputs accepted".to_owned(), common_fields.temporary_channel_id));
|
||||||
"No channels with anchor outputs accepted".to_owned(),
|
|
||||||
msg.common_fields.temporary_channel_id.clone()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let outbound_scid_alias = self.create_and_insert_outbound_scid_alias();
|
let (mut channel_phase, message_send_event) = match msg {
|
||||||
channel.context.set_outbound_scid_alias(outbound_scid_alias);
|
OpenChannelMessageRef::V1(msg) => {
|
||||||
|
let channel = InboundV1Channel::new(
|
||||||
|
&self.fee_estimator, &self.entropy_source, &self.signer_provider, *counterparty_node_id,
|
||||||
|
&self.channel_type_features(), &peer_state.latest_features, msg, user_channel_id,
|
||||||
|
&self.default_configuration, best_block_height, &self.logger, /*is_0conf=*/false
|
||||||
|
).map_err(|e| MsgHandleErrInternal::from_chan_no_close(e, msg.common_fields.temporary_channel_id))?;
|
||||||
|
let message_send_event = events::MessageSendEvent::SendAcceptChannel {
|
||||||
|
node_id: *counterparty_node_id,
|
||||||
|
msg: channel.accept_inbound_channel(),
|
||||||
|
};
|
||||||
|
(ChannelPhase::UnfundedInboundV1(channel), message_send_event)
|
||||||
|
},
|
||||||
|
OpenChannelMessageRef::V2(msg) => {
|
||||||
|
let channel = InboundV2Channel::new(&self.fee_estimator, &self.entropy_source,
|
||||||
|
&self.signer_provider, *counterparty_node_id, &self.channel_type_features(),
|
||||||
|
&peer_state.latest_features, msg, vec![], Weight::from_wu(0), user_channel_id,
|
||||||
|
&self.default_configuration, best_block_height, &self.logger
|
||||||
|
).map_err(|e| MsgHandleErrInternal::from_chan_no_close(e, msg.common_fields.temporary_channel_id))?;
|
||||||
|
let message_send_event = events::MessageSendEvent::SendAcceptChannelV2 {
|
||||||
|
node_id: *counterparty_node_id,
|
||||||
|
msg: channel.accept_inbound_dual_funded_channel(),
|
||||||
|
};
|
||||||
|
(ChannelPhase::UnfundedInboundV2(channel), message_send_event)
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let outbound_scid_alias = self.create_and_insert_outbound_scid_alias();
|
||||||
|
channel_phase.context_mut().set_outbound_scid_alias(outbound_scid_alias);
|
||||||
|
|
||||||
|
peer_state.pending_msg_events.push(message_send_event);
|
||||||
|
peer_state.channel_by_id.insert(channel_phase.context().channel_id(), channel_phase);
|
||||||
|
|
||||||
peer_state.pending_msg_events.push(events::MessageSendEvent::SendAcceptChannel {
|
|
||||||
node_id: counterparty_node_id.clone(),
|
|
||||||
msg: channel.accept_inbound_channel(),
|
|
||||||
});
|
|
||||||
peer_state.channel_by_id.insert(channel_id, ChannelPhase::UnfundedInboundV1(channel));
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -7912,7 +7982,7 @@ where
|
|||||||
hash_map::Entry::Occupied(mut phase) => {
|
hash_map::Entry::Occupied(mut phase) => {
|
||||||
match phase.get_mut() {
|
match phase.get_mut() {
|
||||||
ChannelPhase::UnfundedOutboundV1(chan) => {
|
ChannelPhase::UnfundedOutboundV1(chan) => {
|
||||||
try_chan_phase_entry!(self, peer_state, chan.accept_channel(&msg, &self.default_configuration.channel_handshake_limits, &peer_state.latest_features), phase);
|
try_chan_phase_entry!(self, peer_state, chan.accept_channel(msg, &self.default_configuration.channel_handshake_limits, &peer_state.latest_features), phase);
|
||||||
(chan.context.get_value_satoshis(), chan.context.get_funding_redeemscript().to_p2wsh(), chan.context.get_user_id())
|
(chan.context.get_value_satoshis(), chan.context.get_funding_redeemscript().to_p2wsh(), chan.context.get_user_id())
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
@ -8092,6 +8162,145 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn internal_tx_msg<HandleTxMsgFn: Fn(&mut ChannelPhase<SP>) -> Result<MessageSendEvent, &'static str>>(
|
||||||
|
&self, counterparty_node_id: &PublicKey, channel_id: ChannelId, tx_msg_handler: HandleTxMsgFn
|
||||||
|
) -> Result<(), MsgHandleErrInternal> {
|
||||||
|
let per_peer_state = self.per_peer_state.read().unwrap();
|
||||||
|
let peer_state_mutex = per_peer_state.get(counterparty_node_id)
|
||||||
|
.ok_or_else(|| {
|
||||||
|
debug_assert!(false);
|
||||||
|
MsgHandleErrInternal::send_err_msg_no_close(
|
||||||
|
format!("Can't find a peer matching the passed counterparty node_id {}", counterparty_node_id),
|
||||||
|
channel_id)
|
||||||
|
})?;
|
||||||
|
let mut peer_state_lock = peer_state_mutex.lock().unwrap();
|
||||||
|
let peer_state = &mut *peer_state_lock;
|
||||||
|
match peer_state.channel_by_id.entry(channel_id) {
|
||||||
|
hash_map::Entry::Occupied(mut chan_phase_entry) => {
|
||||||
|
let channel_phase = chan_phase_entry.get_mut();
|
||||||
|
let msg_send_event = match tx_msg_handler(channel_phase) {
|
||||||
|
Ok(msg_send_event) => msg_send_event,
|
||||||
|
Err(tx_msg_str) => return Err(MsgHandleErrInternal::from_chan_no_close(ChannelError::Warn(
|
||||||
|
format!("Got a {tx_msg_str} message with no interactive transaction construction expected or in-progress")
|
||||||
|
), channel_id)),
|
||||||
|
};
|
||||||
|
peer_state.pending_msg_events.push(msg_send_event);
|
||||||
|
Ok(())
|
||||||
|
},
|
||||||
|
hash_map::Entry::Vacant(_) => {
|
||||||
|
Err(MsgHandleErrInternal::send_err_msg_no_close(format!(
|
||||||
|
"Got a message for a channel from the wrong node! No such channel for the passed counterparty_node_id {}",
|
||||||
|
counterparty_node_id), channel_id)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn internal_tx_add_input(&self, counterparty_node_id: PublicKey, msg: &msgs::TxAddInput) -> Result<(), MsgHandleErrInternal> {
|
||||||
|
self.internal_tx_msg(&counterparty_node_id, msg.channel_id, |channel_phase: &mut ChannelPhase<SP>| {
|
||||||
|
match channel_phase {
|
||||||
|
ChannelPhase::UnfundedInboundV2(ref mut channel) => {
|
||||||
|
Ok(channel.tx_add_input(msg).into_msg_send_event(counterparty_node_id))
|
||||||
|
},
|
||||||
|
ChannelPhase::UnfundedOutboundV2(ref mut channel) => {
|
||||||
|
Ok(channel.tx_add_input(msg).into_msg_send_event(counterparty_node_id))
|
||||||
|
},
|
||||||
|
_ => Err("tx_add_input"),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn internal_tx_add_output(&self, counterparty_node_id: PublicKey, msg: &msgs::TxAddOutput) -> Result<(), MsgHandleErrInternal> {
|
||||||
|
self.internal_tx_msg(&counterparty_node_id, msg.channel_id, |channel_phase: &mut ChannelPhase<SP>| {
|
||||||
|
match channel_phase {
|
||||||
|
ChannelPhase::UnfundedInboundV2(ref mut channel) => {
|
||||||
|
Ok(channel.tx_add_output(msg).into_msg_send_event(counterparty_node_id))
|
||||||
|
},
|
||||||
|
ChannelPhase::UnfundedOutboundV2(ref mut channel) => {
|
||||||
|
Ok(channel.tx_add_output(msg).into_msg_send_event(counterparty_node_id))
|
||||||
|
},
|
||||||
|
_ => Err("tx_add_output"),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn internal_tx_remove_input(&self, counterparty_node_id: PublicKey, msg: &msgs::TxRemoveInput) -> Result<(), MsgHandleErrInternal> {
|
||||||
|
self.internal_tx_msg(&counterparty_node_id, msg.channel_id, |channel_phase: &mut ChannelPhase<SP>| {
|
||||||
|
match channel_phase {
|
||||||
|
ChannelPhase::UnfundedInboundV2(ref mut channel) => {
|
||||||
|
Ok(channel.tx_remove_input(msg).into_msg_send_event(counterparty_node_id))
|
||||||
|
},
|
||||||
|
ChannelPhase::UnfundedOutboundV2(ref mut channel) => {
|
||||||
|
Ok(channel.tx_remove_input(msg).into_msg_send_event(counterparty_node_id))
|
||||||
|
},
|
||||||
|
_ => Err("tx_remove_input"),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn internal_tx_remove_output(&self, counterparty_node_id: PublicKey, msg: &msgs::TxRemoveOutput) -> Result<(), MsgHandleErrInternal> {
|
||||||
|
self.internal_tx_msg(&counterparty_node_id, msg.channel_id, |channel_phase: &mut ChannelPhase<SP>| {
|
||||||
|
match channel_phase {
|
||||||
|
ChannelPhase::UnfundedInboundV2(ref mut channel) => {
|
||||||
|
Ok(channel.tx_remove_output(msg).into_msg_send_event(counterparty_node_id))
|
||||||
|
},
|
||||||
|
ChannelPhase::UnfundedOutboundV2(ref mut channel) => {
|
||||||
|
Ok(channel.tx_remove_output(msg).into_msg_send_event(counterparty_node_id))
|
||||||
|
},
|
||||||
|
_ => Err("tx_remove_output"),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn internal_tx_complete(&self, counterparty_node_id: PublicKey, msg: &msgs::TxComplete) -> Result<(), MsgHandleErrInternal> {
|
||||||
|
let per_peer_state = self.per_peer_state.read().unwrap();
|
||||||
|
let peer_state_mutex = per_peer_state.get(&counterparty_node_id)
|
||||||
|
.ok_or_else(|| {
|
||||||
|
debug_assert!(false);
|
||||||
|
MsgHandleErrInternal::send_err_msg_no_close(
|
||||||
|
format!("Can't find a peer matching the passed counterparty node_id {}", counterparty_node_id),
|
||||||
|
msg.channel_id)
|
||||||
|
})?;
|
||||||
|
let mut peer_state_lock = peer_state_mutex.lock().unwrap();
|
||||||
|
let peer_state = &mut *peer_state_lock;
|
||||||
|
match peer_state.channel_by_id.entry(msg.channel_id) {
|
||||||
|
hash_map::Entry::Occupied(mut chan_phase_entry) => {
|
||||||
|
let channel_phase = chan_phase_entry.get_mut();
|
||||||
|
let (msg_send_event_opt, tx_opt) = match channel_phase {
|
||||||
|
ChannelPhase::UnfundedInboundV2(channel) => channel.tx_complete(msg).into_msg_send_event_or_tx(counterparty_node_id),
|
||||||
|
ChannelPhase::UnfundedOutboundV2(channel) => channel.tx_complete(msg).into_msg_send_event_or_tx(counterparty_node_id),
|
||||||
|
_ => try_chan_phase_entry!(self, peer_state, Err(ChannelError::Close(
|
||||||
|
(
|
||||||
|
"Got a tx_complete message with no interactive transaction construction expected or in-progress".into(),
|
||||||
|
ClosureReason::HolderForceClosed { broadcasted_latest_txn: Some(false) },
|
||||||
|
))), chan_phase_entry)
|
||||||
|
};
|
||||||
|
if let Some(msg_send_event) = msg_send_event_opt {
|
||||||
|
peer_state.pending_msg_events.push(msg_send_event);
|
||||||
|
}
|
||||||
|
if let Some(tx) = tx_opt {
|
||||||
|
// TODO(dual_funding): Handle this unsigned transaction.
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
},
|
||||||
|
hash_map::Entry::Vacant(_) => {
|
||||||
|
Err(MsgHandleErrInternal::send_err_msg_no_close(format!("Got a message for a channel from the wrong node! No such channel for the passed counterparty_node_id {}", counterparty_node_id), msg.channel_id))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn internal_tx_signatures(&self, counterparty_node_id: &PublicKey, msg: &msgs::TxSignatures) {
|
||||||
|
let _: Result<(), _> = handle_error!(self, Err(MsgHandleErrInternal::send_err_msg_no_close(
|
||||||
|
"Dual-funded channels not supported".to_owned(),
|
||||||
|
msg.channel_id)), *counterparty_node_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn internal_tx_abort(&self, counterparty_node_id: &PublicKey, msg: &msgs::TxAbort) {
|
||||||
|
let _: Result<(), _> = handle_error!(self, Err(MsgHandleErrInternal::send_err_msg_no_close(
|
||||||
|
"Dual-funded channels not supported".to_owned(),
|
||||||
|
msg.channel_id)), *counterparty_node_id);
|
||||||
|
}
|
||||||
|
|
||||||
fn internal_channel_ready(&self, counterparty_node_id: &PublicKey, msg: &msgs::ChannelReady) -> Result<(), MsgHandleErrInternal> {
|
fn internal_channel_ready(&self, counterparty_node_id: &PublicKey, msg: &msgs::ChannelReady) -> Result<(), MsgHandleErrInternal> {
|
||||||
// Note that the ChannelManager is NOT re-persisted on disk after this (unless we error
|
// Note that the ChannelManager is NOT re-persisted on disk after this (unless we error
|
||||||
// closing a channel), so any changes are likely to be lost on restart!
|
// closing a channel), so any changes are likely to be lost on restart!
|
||||||
@ -10838,7 +11047,7 @@ where
|
|||||||
// open_channel message - pre-funded channels are never written so there should be no
|
// open_channel message - pre-funded channels are never written so there should be no
|
||||||
// change to the contents.
|
// change to the contents.
|
||||||
let _persistence_guard = PersistenceNotifierGuard::optionally_notify(self, || {
|
let _persistence_guard = PersistenceNotifierGuard::optionally_notify(self, || {
|
||||||
let res = self.internal_open_channel(&counterparty_node_id, msg);
|
let res = self.internal_open_channel(&counterparty_node_id, OpenChannelMessageRef::V1(msg));
|
||||||
let persist = match &res {
|
let persist = match &res {
|
||||||
Err(e) if e.closes_channel() => {
|
Err(e) if e.closes_channel() => {
|
||||||
debug_assert!(false, "We shouldn't close a new channel");
|
debug_assert!(false, "We shouldn't close a new channel");
|
||||||
@ -10852,9 +11061,21 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn handle_open_channel_v2(&self, counterparty_node_id: PublicKey, msg: &msgs::OpenChannelV2) {
|
fn handle_open_channel_v2(&self, counterparty_node_id: PublicKey, msg: &msgs::OpenChannelV2) {
|
||||||
let _: Result<(), _> = handle_error!(self, Err(MsgHandleErrInternal::send_err_msg_no_close(
|
// Note that we never need to persist the updated ChannelManager for an inbound
|
||||||
"Dual-funded channels not supported".to_owned(),
|
// open_channel message - pre-funded channels are never written so there should be no
|
||||||
msg.common_fields.temporary_channel_id.clone())), counterparty_node_id);
|
// change to the contents.
|
||||||
|
let _persistence_guard = PersistenceNotifierGuard::optionally_notify(self, || {
|
||||||
|
let res = self.internal_open_channel(&counterparty_node_id, OpenChannelMessageRef::V2(msg));
|
||||||
|
let persist = match &res {
|
||||||
|
Err(e) if e.closes_channel() => {
|
||||||
|
debug_assert!(false, "We shouldn't close a new channel");
|
||||||
|
NotifyOption::DoPersist
|
||||||
|
},
|
||||||
|
_ => NotifyOption::SkipPersistHandleEvents,
|
||||||
|
};
|
||||||
|
let _ = handle_error!(self, res, counterparty_node_id);
|
||||||
|
persist
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_accept_channel(&self, counterparty_node_id: PublicKey, msg: &msgs::AcceptChannel) {
|
fn handle_accept_channel(&self, counterparty_node_id: PublicKey, msg: &msgs::AcceptChannel) {
|
||||||
@ -11384,33 +11605,53 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn handle_tx_add_input(&self, counterparty_node_id: PublicKey, msg: &msgs::TxAddInput) {
|
fn handle_tx_add_input(&self, counterparty_node_id: PublicKey, msg: &msgs::TxAddInput) {
|
||||||
let _: Result<(), _> = handle_error!(self, Err(MsgHandleErrInternal::send_err_msg_no_close(
|
// Note that we never need to persist the updated ChannelManager for an inbound
|
||||||
"Dual-funded channels not supported".to_owned(),
|
// tx_add_input message - interactive transaction construction does not need to
|
||||||
msg.channel_id.clone())), counterparty_node_id);
|
// be persisted before any signatures are exchanged.
|
||||||
|
let _persistence_guard = PersistenceNotifierGuard::optionally_notify(self, || {
|
||||||
|
let _ = handle_error!(self, self.internal_tx_add_input(counterparty_node_id, msg), counterparty_node_id);
|
||||||
|
NotifyOption::SkipPersistHandleEvents
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_tx_add_output(&self, counterparty_node_id: PublicKey, msg: &msgs::TxAddOutput) {
|
fn handle_tx_add_output(&self, counterparty_node_id: PublicKey, msg: &msgs::TxAddOutput) {
|
||||||
let _: Result<(), _> = handle_error!(self, Err(MsgHandleErrInternal::send_err_msg_no_close(
|
// Note that we never need to persist the updated ChannelManager for an inbound
|
||||||
"Dual-funded channels not supported".to_owned(),
|
// tx_add_output message - interactive transaction construction does not need to
|
||||||
msg.channel_id.clone())), counterparty_node_id);
|
// be persisted before any signatures are exchanged.
|
||||||
|
let _persistence_guard = PersistenceNotifierGuard::optionally_notify(self, || {
|
||||||
|
let _ = handle_error!(self, self.internal_tx_add_output(counterparty_node_id, msg), counterparty_node_id);
|
||||||
|
NotifyOption::SkipPersistHandleEvents
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_tx_remove_input(&self, counterparty_node_id: PublicKey, msg: &msgs::TxRemoveInput) {
|
fn handle_tx_remove_input(&self, counterparty_node_id: PublicKey, msg: &msgs::TxRemoveInput) {
|
||||||
let _: Result<(), _> = handle_error!(self, Err(MsgHandleErrInternal::send_err_msg_no_close(
|
// Note that we never need to persist the updated ChannelManager for an inbound
|
||||||
"Dual-funded channels not supported".to_owned(),
|
// tx_remove_input message - interactive transaction construction does not need to
|
||||||
msg.channel_id.clone())), counterparty_node_id);
|
// be persisted before any signatures are exchanged.
|
||||||
|
let _persistence_guard = PersistenceNotifierGuard::optionally_notify(self, || {
|
||||||
|
let _ = handle_error!(self, self.internal_tx_remove_input(counterparty_node_id, msg), counterparty_node_id);
|
||||||
|
NotifyOption::SkipPersistHandleEvents
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_tx_remove_output(&self, counterparty_node_id: PublicKey, msg: &msgs::TxRemoveOutput) {
|
fn handle_tx_remove_output(&self, counterparty_node_id: PublicKey, msg: &msgs::TxRemoveOutput) {
|
||||||
let _: Result<(), _> = handle_error!(self, Err(MsgHandleErrInternal::send_err_msg_no_close(
|
// Note that we never need to persist the updated ChannelManager for an inbound
|
||||||
"Dual-funded channels not supported".to_owned(),
|
// tx_remove_output message - interactive transaction construction does not need to
|
||||||
msg.channel_id.clone())), counterparty_node_id);
|
// be persisted before any signatures are exchanged.
|
||||||
|
let _persistence_guard = PersistenceNotifierGuard::optionally_notify(self, || {
|
||||||
|
let _ = handle_error!(self, self.internal_tx_remove_output(counterparty_node_id, msg), counterparty_node_id);
|
||||||
|
NotifyOption::SkipPersistHandleEvents
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_tx_complete(&self, counterparty_node_id: PublicKey, msg: &msgs::TxComplete) {
|
fn handle_tx_complete(&self, counterparty_node_id: PublicKey, msg: &msgs::TxComplete) {
|
||||||
let _: Result<(), _> = handle_error!(self, Err(MsgHandleErrInternal::send_err_msg_no_close(
|
// Note that we never need to persist the updated ChannelManager for an inbound
|
||||||
"Dual-funded channels not supported".to_owned(),
|
// tx_complete message - interactive transaction construction does not need to
|
||||||
msg.channel_id.clone())), counterparty_node_id);
|
// be persisted before any signatures are exchanged.
|
||||||
|
let _persistence_guard = PersistenceNotifierGuard::optionally_notify(self, || {
|
||||||
|
let _ = handle_error!(self, self.internal_tx_complete(counterparty_node_id, msg), counterparty_node_id);
|
||||||
|
NotifyOption::SkipPersistHandleEvents
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_tx_signatures(&self, counterparty_node_id: PublicKey, msg: &msgs::TxSignatures) {
|
fn handle_tx_signatures(&self, counterparty_node_id: PublicKey, msg: &msgs::TxSignatures) {
|
||||||
|
@ -1166,14 +1166,49 @@ where
|
|||||||
serial_id
|
serial_id
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) enum HandleTxCompleteValue {
|
pub(super) enum HandleTxCompleteValue {
|
||||||
SendTxMessage(InteractiveTxMessageSend),
|
SendTxMessage(InteractiveTxMessageSend),
|
||||||
SendTxComplete(InteractiveTxMessageSend, ConstructedTransaction),
|
SendTxComplete(InteractiveTxMessageSend, ConstructedTransaction),
|
||||||
NegotiationComplete(ConstructedTransaction),
|
NegotiationComplete(ConstructedTransaction),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl HandleTxCompleteValue {
|
||||||
|
pub fn into_msg_send_event_or_tx(
|
||||||
|
self, counterparty_node_id: PublicKey,
|
||||||
|
) -> (Option<MessageSendEvent>, Option<ConstructedTransaction>) {
|
||||||
|
match self {
|
||||||
|
HandleTxCompleteValue::SendTxMessage(msg) => {
|
||||||
|
(Some(msg.into_msg_send_event(counterparty_node_id)), None)
|
||||||
|
},
|
||||||
|
HandleTxCompleteValue::SendTxComplete(msg, tx) => {
|
||||||
|
(Some(msg.into_msg_send_event(counterparty_node_id)), Some(tx))
|
||||||
|
},
|
||||||
|
HandleTxCompleteValue::NegotiationComplete(tx) => (None, Some(tx)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(super) struct HandleTxCompleteResult(pub Result<HandleTxCompleteValue, msgs::TxAbort>);
|
pub(super) struct HandleTxCompleteResult(pub Result<HandleTxCompleteValue, msgs::TxAbort>);
|
||||||
|
|
||||||
|
impl HandleTxCompleteResult {
|
||||||
|
pub fn into_msg_send_event_or_tx(
|
||||||
|
self, counterparty_node_id: PublicKey,
|
||||||
|
) -> (Option<MessageSendEvent>, Option<ConstructedTransaction>) {
|
||||||
|
match self.0 {
|
||||||
|
Ok(interactive_tx_msg_send) => {
|
||||||
|
interactive_tx_msg_send.into_msg_send_event_or_tx(counterparty_node_id)
|
||||||
|
},
|
||||||
|
Err(tx_abort_msg) => (
|
||||||
|
Some(MessageSendEvent::SendTxAbort {
|
||||||
|
node_id: counterparty_node_id,
|
||||||
|
msg: tx_abort_msg,
|
||||||
|
}),
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(super) struct InteractiveTxConstructorArgs<'a, ES: Deref>
|
pub(super) struct InteractiveTxConstructorArgs<'a, ES: Deref>
|
||||||
where
|
where
|
||||||
ES::Target: EntropySource,
|
ES::Target: EntropySource,
|
||||||
|
Loading…
Reference in New Issue
Block a user