pub mod bump_transaction;
pub use bump_transaction::BumpTransactionEvent;
use crate::sign::SpendableOutputDescriptor;
use crate::ln::channelmanager::{InterceptId, PaymentId, RecipientOnionFields};
use crate::ln::channel::FUNDING_CONF_DEADLINE_BLOCKS;
use crate::ln::features::ChannelTypeFeatures;
use crate::ln::msgs;
use crate::ln::{ChannelId, PaymentPreimage, PaymentHash, PaymentSecret};
use crate::chain::transaction;
use crate::routing::gossip::NetworkUpdate;
use crate::util::errors::APIError;
use crate::util::ser::{BigSize, FixedLengthReader, Writeable, Writer, MaybeReadable, Readable, RequiredWrapper, UpgradableRequired, WithoutLength};
use crate::util::string::UntrustedString;
use crate::routing::router::{BlindedTail, Path, RouteHop, RouteParameters};
use bitcoin::{Transaction, OutPoint};
use bitcoin::blockdata::locktime::absolute::LockTime;
use bitcoin::blockdata::script::ScriptBuf;
use bitcoin::hashes::Hash;
use bitcoin::hashes::sha256::Hash as Sha256;
use bitcoin::secp256k1::PublicKey;
use crate::io;
use crate::prelude::*;
use core::time::Duration;
use core::ops::Deref;
use crate::sync::Arc;
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum PaymentPurpose {
InvoicePayment {
payment_preimage: Option<PaymentPreimage>,
payment_secret: PaymentSecret,
},
SpontaneousPayment(PaymentPreimage),
}
impl PaymentPurpose {
pub fn preimage(&self) -> Option<PaymentPreimage> {
match self {
PaymentPurpose::InvoicePayment { payment_preimage, .. } => *payment_preimage,
PaymentPurpose::SpontaneousPayment(preimage) => Some(*preimage),
}
}
}
impl_writeable_tlv_based_enum!(PaymentPurpose,
(0, InvoicePayment) => {
(0, payment_preimage, option),
(2, payment_secret, required),
};
(2, SpontaneousPayment)
);
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ClaimedHTLC {
pub channel_id: ChannelId,
pub user_channel_id: u128,
pub cltv_expiry: u32,
pub value_msat: u64,
pub counterparty_skimmed_fee_msat: u64,
}
impl_writeable_tlv_based!(ClaimedHTLC, {
(0, channel_id, required),
(1, counterparty_skimmed_fee_msat, (default_value, 0u64)),
(2, user_channel_id, required),
(4, cltv_expiry, required),
(6, value_msat, required),
});
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum PathFailure {
InitialSend {
err: APIError,
},
OnPath {
network_update: Option<NetworkUpdate>,
},
}
impl_writeable_tlv_based_enum_upgradable!(PathFailure,
(0, OnPath) => {
(0, network_update, upgradable_option),
},
(2, InitialSend) => {
(0, err, upgradable_required),
},
);
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum ClosureReason {
CounterpartyForceClosed {
peer_msg: UntrustedString,
},
HolderForceClosed,
CooperativeClosure,
CommitmentTxConfirmed,
FundingTimedOut,
ProcessingError {
err: String,
},
DisconnectedPeer,
OutdatedChannelManager,
CounterpartyCoopClosedUnfundedChannel,
FundingBatchClosure,
}
impl core::fmt::Display for ClosureReason {
fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
f.write_str("Channel closed because ")?;
match self {
ClosureReason::CounterpartyForceClosed { peer_msg } => {
f.write_fmt(format_args!("counterparty force-closed with message: {}", peer_msg))
},
ClosureReason::HolderForceClosed => f.write_str("user manually force-closed the channel"),
ClosureReason::CooperativeClosure => f.write_str("the channel was cooperatively closed"),
ClosureReason::CommitmentTxConfirmed => f.write_str("commitment or closing transaction was confirmed on chain."),
ClosureReason::FundingTimedOut => write!(f, "funding transaction failed to confirm within {} blocks", FUNDING_CONF_DEADLINE_BLOCKS),
ClosureReason::ProcessingError { err } => {
f.write_str("of an exception: ")?;
f.write_str(&err)
},
ClosureReason::DisconnectedPeer => f.write_str("the peer disconnected prior to the channel being funded"),
ClosureReason::OutdatedChannelManager => f.write_str("the ChannelManager read from disk was stale compared to ChannelMonitor(s)"),
ClosureReason::CounterpartyCoopClosedUnfundedChannel => f.write_str("the peer requested the unfunded channel be closed"),
ClosureReason::FundingBatchClosure => f.write_str("another channel in the same funding batch closed"),
}
}
}
impl_writeable_tlv_based_enum_upgradable!(ClosureReason,
(0, CounterpartyForceClosed) => { (1, peer_msg, required) },
(1, FundingTimedOut) => {},
(2, HolderForceClosed) => {},
(6, CommitmentTxConfirmed) => {},
(4, CooperativeClosure) => {},
(8, ProcessingError) => { (1, err, required) },
(10, DisconnectedPeer) => {},
(12, OutdatedChannelManager) => {},
(13, CounterpartyCoopClosedUnfundedChannel) => {},
(15, FundingBatchClosure) => {}
);
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum HTLCDestination {
NextHopChannel {
node_id: Option<PublicKey>,
channel_id: ChannelId,
},
UnknownNextHop {
requested_forward_scid: u64,
},
InvalidForward {
requested_forward_scid: u64
},
FailedPayment {
payment_hash: PaymentHash
},
}
impl_writeable_tlv_based_enum_upgradable!(HTLCDestination,
(0, NextHopChannel) => {
(0, node_id, required),
(2, channel_id, required),
},
(1, InvalidForward) => {
(0, requested_forward_scid, required),
},
(2, UnknownNextHop) => {
(0, requested_forward_scid, required),
},
(4, FailedPayment) => {
(0, payment_hash, required),
},
);
enum InterceptNextHop {
FakeScid {
requested_next_hop_scid: u64,
},
}
impl_writeable_tlv_based_enum!(InterceptNextHop,
(0, FakeScid) => {
(0, requested_next_hop_scid, required),
};
);
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum PaymentFailureReason {
RecipientRejected,
UserAbandoned,
RetriesExhausted,
PaymentExpired,
RouteNotFound,
UnexpectedError,
}
impl_writeable_tlv_based_enum!(PaymentFailureReason,
(0, RecipientRejected) => {},
(2, UserAbandoned) => {},
(4, RetriesExhausted) => {},
(6, PaymentExpired) => {},
(8, RouteNotFound) => {},
(10, UnexpectedError) => {}, ;
);
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Event {
FundingGenerationReady {
temporary_channel_id: ChannelId,
counterparty_node_id: PublicKey,
channel_value_satoshis: u64,
output_script: ScriptBuf,
user_channel_id: u128,
},
PaymentClaimable {
receiver_node_id: Option<PublicKey>,
payment_hash: PaymentHash,
onion_fields: Option<RecipientOnionFields>,
amount_msat: u64,
counterparty_skimmed_fee_msat: u64,
purpose: PaymentPurpose,
via_channel_id: Option<ChannelId>,
via_user_channel_id: Option<u128>,
claim_deadline: Option<u32>,
},
PaymentClaimed {
receiver_node_id: Option<PublicKey>,
payment_hash: PaymentHash,
amount_msat: u64,
purpose: PaymentPurpose,
htlcs: Vec<ClaimedHTLC>,
sender_intended_total_msat: Option<u64>,
},
ConnectionNeeded {
node_id: PublicKey,
addresses: Vec<msgs::SocketAddress>,
},
InvoiceRequestFailed {
payment_id: PaymentId,
},
PaymentSent {
payment_id: Option<PaymentId>,
payment_preimage: PaymentPreimage,
payment_hash: PaymentHash,
fee_paid_msat: Option<u64>,
},
PaymentFailed {
payment_id: PaymentId,
payment_hash: PaymentHash,
reason: Option<PaymentFailureReason>,
},
PaymentPathSuccessful {
payment_id: PaymentId,
payment_hash: Option<PaymentHash>,
path: Path,
},
PaymentPathFailed {
payment_id: Option<PaymentId>,
payment_hash: PaymentHash,
payment_failed_permanently: bool,
failure: PathFailure,
path: Path,
short_channel_id: Option<u64>,
#[cfg(test)]
error_code: Option<u16>,
#[cfg(test)]
error_data: Option<Vec<u8>>,
},
ProbeSuccessful {
payment_id: PaymentId,
payment_hash: PaymentHash,
path: Path,
},
ProbeFailed {
payment_id: PaymentId,
payment_hash: PaymentHash,
path: Path,
short_channel_id: Option<u64>,
},
PendingHTLCsForwardable {
time_forwardable: Duration,
},
HTLCIntercepted {
intercept_id: InterceptId,
requested_next_hop_scid: u64,
payment_hash: PaymentHash,
inbound_amount_msat: u64,
expected_outbound_amount_msat: u64,
},
SpendableOutputs {
outputs: Vec<SpendableOutputDescriptor>,
channel_id: Option<ChannelId>,
},
PaymentForwarded {
prev_channel_id: Option<ChannelId>,
next_channel_id: Option<ChannelId>,
fee_earned_msat: Option<u64>,
claim_from_onchain_tx: bool,
outbound_amount_forwarded_msat: Option<u64>,
},
ChannelPending {
channel_id: ChannelId,
user_channel_id: u128,
former_temporary_channel_id: Option<ChannelId>,
counterparty_node_id: PublicKey,
funding_txo: OutPoint,
},
ChannelReady {
channel_id: ChannelId,
user_channel_id: u128,
counterparty_node_id: PublicKey,
channel_type: ChannelTypeFeatures,
},
ChannelClosed {
channel_id: ChannelId,
user_channel_id: u128,
reason: ClosureReason,
counterparty_node_id: Option<PublicKey>,
channel_capacity_sats: Option<u64>,
channel_funding_txo: Option<transaction::OutPoint>,
},
DiscardFunding {
channel_id: ChannelId,
transaction: Transaction
},
OpenChannelRequest {
temporary_channel_id: ChannelId,
counterparty_node_id: PublicKey,
funding_satoshis: u64,
push_msat: u64,
channel_type: ChannelTypeFeatures,
},
HTLCHandlingFailed {
prev_channel_id: ChannelId,
failed_next_destination: HTLCDestination,
},
BumpTransaction(BumpTransactionEvent),
}
impl Writeable for Event {
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
match self {
&Event::FundingGenerationReady { .. } => {
0u8.write(writer)?;
},
&Event::PaymentClaimable { ref payment_hash, ref amount_msat, counterparty_skimmed_fee_msat,
ref purpose, ref receiver_node_id, ref via_channel_id, ref via_user_channel_id,
ref claim_deadline, ref onion_fields
} => {
1u8.write(writer)?;
let mut payment_secret = None;
let payment_preimage;
match &purpose {
PaymentPurpose::InvoicePayment { payment_preimage: preimage, payment_secret: secret } => {
payment_secret = Some(secret);
payment_preimage = *preimage;
},
PaymentPurpose::SpontaneousPayment(preimage) => {
payment_preimage = Some(*preimage);
}
}
let skimmed_fee_opt = if counterparty_skimmed_fee_msat == 0 { None }
else { Some(counterparty_skimmed_fee_msat) };
write_tlv_fields!(writer, {
(0, payment_hash, required),
(1, receiver_node_id, option),
(2, payment_secret, option),
(3, via_channel_id, option),
(4, amount_msat, required),
(5, via_user_channel_id, option),
(7, claim_deadline, option),
(8, payment_preimage, option),
(9, onion_fields, option),
(10, skimmed_fee_opt, option),
});
},
&Event::PaymentSent { ref payment_id, ref payment_preimage, ref payment_hash, ref fee_paid_msat } => {
2u8.write(writer)?;
write_tlv_fields!(writer, {
(0, payment_preimage, required),
(1, payment_hash, required),
(3, payment_id, option),
(5, fee_paid_msat, option),
});
},
&Event::PaymentPathFailed {
ref payment_id, ref payment_hash, ref payment_failed_permanently, ref failure,
ref path, ref short_channel_id,
#[cfg(test)]
ref error_code,
#[cfg(test)]
ref error_data,
} => {
3u8.write(writer)?;
#[cfg(test)]
error_code.write(writer)?;
#[cfg(test)]
error_data.write(writer)?;
write_tlv_fields!(writer, {
(0, payment_hash, required),
(1, None::<NetworkUpdate>, option), (2, payment_failed_permanently, required),
(3, false, required), (4, path.blinded_tail, option),
(5, path.hops, required_vec),
(7, short_channel_id, option),
(9, None::<RouteParameters>, option), (11, payment_id, option),
(13, failure, required),
});
},
&Event::PendingHTLCsForwardable { time_forwardable: _ } => {
4u8.write(writer)?;
},
&Event::SpendableOutputs { ref outputs, channel_id } => {
5u8.write(writer)?;
write_tlv_fields!(writer, {
(0, WithoutLength(outputs), required),
(1, channel_id, option),
});
},
&Event::HTLCIntercepted { requested_next_hop_scid, payment_hash, inbound_amount_msat, expected_outbound_amount_msat, intercept_id } => {
6u8.write(writer)?;
let intercept_scid = InterceptNextHop::FakeScid { requested_next_hop_scid };
write_tlv_fields!(writer, {
(0, intercept_id, required),
(2, intercept_scid, required),
(4, payment_hash, required),
(6, inbound_amount_msat, required),
(8, expected_outbound_amount_msat, required),
});
}
&Event::PaymentForwarded {
fee_earned_msat, prev_channel_id, claim_from_onchain_tx,
next_channel_id, outbound_amount_forwarded_msat
} => {
7u8.write(writer)?;
write_tlv_fields!(writer, {
(0, fee_earned_msat, option),
(1, prev_channel_id, option),
(2, claim_from_onchain_tx, required),
(3, next_channel_id, option),
(5, outbound_amount_forwarded_msat, option),
});
},
&Event::ChannelClosed { ref channel_id, ref user_channel_id, ref reason,
ref counterparty_node_id, ref channel_capacity_sats, ref channel_funding_txo
} => {
9u8.write(writer)?;
let user_channel_id_low = *user_channel_id as u64;
let user_channel_id_high = (*user_channel_id >> 64) as u64;
write_tlv_fields!(writer, {
(0, channel_id, required),
(1, user_channel_id_low, required),
(2, reason, required),
(3, user_channel_id_high, required),
(5, counterparty_node_id, option),
(7, channel_capacity_sats, option),
(9, channel_funding_txo, option),
});
},
&Event::DiscardFunding { ref channel_id, ref transaction } => {
11u8.write(writer)?;
write_tlv_fields!(writer, {
(0, channel_id, required),
(2, transaction, required)
})
},
&Event::PaymentPathSuccessful { ref payment_id, ref payment_hash, ref path } => {
13u8.write(writer)?;
write_tlv_fields!(writer, {
(0, payment_id, required),
(2, payment_hash, option),
(4, path.hops, required_vec),
(6, path.blinded_tail, option),
})
},
&Event::PaymentFailed { ref payment_id, ref payment_hash, ref reason } => {
15u8.write(writer)?;
write_tlv_fields!(writer, {
(0, payment_id, required),
(1, reason, option),
(2, payment_hash, required),
})
},
&Event::OpenChannelRequest { .. } => {
17u8.write(writer)?;
},
&Event::PaymentClaimed { ref payment_hash, ref amount_msat, ref purpose, ref receiver_node_id, ref htlcs, ref sender_intended_total_msat } => {
19u8.write(writer)?;
write_tlv_fields!(writer, {
(0, payment_hash, required),
(1, receiver_node_id, option),
(2, purpose, required),
(4, amount_msat, required),
(5, *htlcs, optional_vec),
(7, sender_intended_total_msat, option),
});
},
&Event::ProbeSuccessful { ref payment_id, ref payment_hash, ref path } => {
21u8.write(writer)?;
write_tlv_fields!(writer, {
(0, payment_id, required),
(2, payment_hash, required),
(4, path.hops, required_vec),
(6, path.blinded_tail, option),
})
},
&Event::ProbeFailed { ref payment_id, ref payment_hash, ref path, ref short_channel_id } => {
23u8.write(writer)?;
write_tlv_fields!(writer, {
(0, payment_id, required),
(2, payment_hash, required),
(4, path.hops, required_vec),
(6, short_channel_id, option),
(8, path.blinded_tail, option),
})
},
&Event::HTLCHandlingFailed { ref prev_channel_id, ref failed_next_destination } => {
25u8.write(writer)?;
write_tlv_fields!(writer, {
(0, prev_channel_id, required),
(2, failed_next_destination, required),
})
},
&Event::BumpTransaction(ref event)=> {
27u8.write(writer)?;
match event {
BumpTransactionEvent::ChannelClose { .. } => {}
BumpTransactionEvent::HTLCResolution { .. } => {}
}
write_tlv_fields!(writer, {}); }
&Event::ChannelReady { ref channel_id, ref user_channel_id, ref counterparty_node_id, ref channel_type } => {
29u8.write(writer)?;
write_tlv_fields!(writer, {
(0, channel_id, required),
(2, user_channel_id, required),
(4, counterparty_node_id, required),
(6, channel_type, required),
});
},
&Event::ChannelPending { ref channel_id, ref user_channel_id, ref former_temporary_channel_id, ref counterparty_node_id, ref funding_txo } => {
31u8.write(writer)?;
write_tlv_fields!(writer, {
(0, channel_id, required),
(2, user_channel_id, required),
(4, former_temporary_channel_id, required),
(6, counterparty_node_id, required),
(8, funding_txo, required),
});
},
&Event::InvoiceRequestFailed { ref payment_id } => {
33u8.write(writer)?;
write_tlv_fields!(writer, {
(0, payment_id, required),
})
},
&Event::ConnectionNeeded { .. } => {
35u8.write(writer)?;
},
}
Ok(())
}
}
impl MaybeReadable for Event {
fn read<R: io::Read>(reader: &mut R) -> Result<Option<Self>, msgs::DecodeError> {
match Readable::read(reader)? {
0u8 => Ok(None),
1u8 => {
let f = || {
let mut payment_hash = PaymentHash([0; 32]);
let mut payment_preimage = None;
let mut payment_secret = None;
let mut amount_msat = 0;
let mut counterparty_skimmed_fee_msat_opt = None;
let mut receiver_node_id = None;
let mut _user_payment_id = None::<u64>; let mut via_channel_id = None;
let mut claim_deadline = None;
let mut via_user_channel_id = None;
let mut onion_fields = None;
read_tlv_fields!(reader, {
(0, payment_hash, required),
(1, receiver_node_id, option),
(2, payment_secret, option),
(3, via_channel_id, option),
(4, amount_msat, required),
(5, via_user_channel_id, option),
(6, _user_payment_id, option),
(7, claim_deadline, option),
(8, payment_preimage, option),
(9, onion_fields, option),
(10, counterparty_skimmed_fee_msat_opt, option),
});
let purpose = match payment_secret {
Some(secret) => PaymentPurpose::InvoicePayment {
payment_preimage,
payment_secret: secret
},
None if payment_preimage.is_some() => PaymentPurpose::SpontaneousPayment(payment_preimage.unwrap()),
None => return Err(msgs::DecodeError::InvalidValue),
};
Ok(Some(Event::PaymentClaimable {
receiver_node_id,
payment_hash,
amount_msat,
counterparty_skimmed_fee_msat: counterparty_skimmed_fee_msat_opt.unwrap_or(0),
purpose,
via_channel_id,
via_user_channel_id,
claim_deadline,
onion_fields,
}))
};
f()
},
2u8 => {
let f = || {
let mut payment_preimage = PaymentPreimage([0; 32]);
let mut payment_hash = None;
let mut payment_id = None;
let mut fee_paid_msat = None;
read_tlv_fields!(reader, {
(0, payment_preimage, required),
(1, payment_hash, option),
(3, payment_id, option),
(5, fee_paid_msat, option),
});
if payment_hash.is_none() {
payment_hash = Some(PaymentHash(Sha256::hash(&payment_preimage.0[..]).to_byte_array()));
}
Ok(Some(Event::PaymentSent {
payment_id,
payment_preimage,
payment_hash: payment_hash.unwrap(),
fee_paid_msat,
}))
};
f()
},
3u8 => {
let f = || {
#[cfg(test)]
let error_code = Readable::read(reader)?;
#[cfg(test)]
let error_data = Readable::read(reader)?;
let mut payment_hash = PaymentHash([0; 32]);
let mut payment_failed_permanently = false;
let mut network_update = None;
let mut blinded_tail: Option<BlindedTail> = None;
let mut path: Option<Vec<RouteHop>> = Some(vec![]);
let mut short_channel_id = None;
let mut payment_id = None;
let mut failure_opt = None;
read_tlv_fields!(reader, {
(0, payment_hash, required),
(1, network_update, upgradable_option),
(2, payment_failed_permanently, required),
(4, blinded_tail, option),
(5, path, optional_vec),
(7, short_channel_id, option),
(11, payment_id, option),
(13, failure_opt, upgradable_option),
});
let failure = failure_opt.unwrap_or_else(|| PathFailure::OnPath { network_update });
Ok(Some(Event::PaymentPathFailed {
payment_id,
payment_hash,
payment_failed_permanently,
failure,
path: Path { hops: path.unwrap(), blinded_tail },
short_channel_id,
#[cfg(test)]
error_code,
#[cfg(test)]
error_data,
}))
};
f()
},
4u8 => Ok(None),
5u8 => {
let f = || {
let mut outputs = WithoutLength(Vec::new());
let mut channel_id: Option<ChannelId> = None;
read_tlv_fields!(reader, {
(0, outputs, required),
(1, channel_id, option),
});
Ok(Some(Event::SpendableOutputs { outputs: outputs.0, channel_id }))
};
f()
},
6u8 => {
let mut payment_hash = PaymentHash([0; 32]);
let mut intercept_id = InterceptId([0; 32]);
let mut requested_next_hop_scid = InterceptNextHop::FakeScid { requested_next_hop_scid: 0 };
let mut inbound_amount_msat = 0;
let mut expected_outbound_amount_msat = 0;
read_tlv_fields!(reader, {
(0, intercept_id, required),
(2, requested_next_hop_scid, required),
(4, payment_hash, required),
(6, inbound_amount_msat, required),
(8, expected_outbound_amount_msat, required),
});
let next_scid = match requested_next_hop_scid {
InterceptNextHop::FakeScid { requested_next_hop_scid: scid } => scid
};
Ok(Some(Event::HTLCIntercepted {
payment_hash,
requested_next_hop_scid: next_scid,
inbound_amount_msat,
expected_outbound_amount_msat,
intercept_id,
}))
},
7u8 => {
let f = || {
let mut fee_earned_msat = None;
let mut prev_channel_id = None;
let mut claim_from_onchain_tx = false;
let mut next_channel_id = None;
let mut outbound_amount_forwarded_msat = None;
read_tlv_fields!(reader, {
(0, fee_earned_msat, option),
(1, prev_channel_id, option),
(2, claim_from_onchain_tx, required),
(3, next_channel_id, option),
(5, outbound_amount_forwarded_msat, option),
});
Ok(Some(Event::PaymentForwarded {
fee_earned_msat, prev_channel_id, claim_from_onchain_tx, next_channel_id,
outbound_amount_forwarded_msat
}))
};
f()
},
9u8 => {
let f = || {
let mut channel_id = ChannelId::new_zero();
let mut reason = UpgradableRequired(None);
let mut user_channel_id_low_opt: Option<u64> = None;
let mut user_channel_id_high_opt: Option<u64> = None;
let mut counterparty_node_id = None;
let mut channel_capacity_sats = None;
let mut channel_funding_txo = None;
read_tlv_fields!(reader, {
(0, channel_id, required),
(1, user_channel_id_low_opt, option),
(2, reason, upgradable_required),
(3, user_channel_id_high_opt, option),
(5, counterparty_node_id, option),
(7, channel_capacity_sats, option),
(9, channel_funding_txo, option),
});
let user_channel_id = (user_channel_id_low_opt.unwrap_or(0) as u128) +
((user_channel_id_high_opt.unwrap_or(0) as u128) << 64);
Ok(Some(Event::ChannelClosed { channel_id, user_channel_id, reason: _init_tlv_based_struct_field!(reason, upgradable_required),
counterparty_node_id, channel_capacity_sats, channel_funding_txo }))
};
f()
},
11u8 => {
let f = || {
let mut channel_id = ChannelId::new_zero();
let mut transaction = Transaction{ version: 2, lock_time: LockTime::ZERO, input: Vec::new(), output: Vec::new() };
read_tlv_fields!(reader, {
(0, channel_id, required),
(2, transaction, required),
});
Ok(Some(Event::DiscardFunding { channel_id, transaction } ))
};
f()
},
13u8 => {
let f = || {
_init_and_read_len_prefixed_tlv_fields!(reader, {
(0, payment_id, required),
(2, payment_hash, option),
(4, path, required_vec),
(6, blinded_tail, option),
});
Ok(Some(Event::PaymentPathSuccessful {
payment_id: payment_id.0.unwrap(),
payment_hash,
path: Path { hops: path, blinded_tail },
}))
};
f()
},
15u8 => {
let f = || {
let mut payment_hash = PaymentHash([0; 32]);
let mut payment_id = PaymentId([0; 32]);
let mut reason = None;
read_tlv_fields!(reader, {
(0, payment_id, required),
(1, reason, upgradable_option),
(2, payment_hash, required),
});
Ok(Some(Event::PaymentFailed {
payment_id,
payment_hash,
reason,
}))
};
f()
},
17u8 => {
Ok(None)
},
19u8 => {
let f = || {
let mut payment_hash = PaymentHash([0; 32]);
let mut purpose = UpgradableRequired(None);
let mut amount_msat = 0;
let mut receiver_node_id = None;
let mut htlcs: Option<Vec<ClaimedHTLC>> = Some(vec![]);
let mut sender_intended_total_msat: Option<u64> = None;
read_tlv_fields!(reader, {
(0, payment_hash, required),
(1, receiver_node_id, option),
(2, purpose, upgradable_required),
(4, amount_msat, required),
(5, htlcs, optional_vec),
(7, sender_intended_total_msat, option),
});
Ok(Some(Event::PaymentClaimed {
receiver_node_id,
payment_hash,
purpose: _init_tlv_based_struct_field!(purpose, upgradable_required),
amount_msat,
htlcs: htlcs.unwrap_or(vec![]),
sender_intended_total_msat,
}))
};
f()
},
21u8 => {
let f = || {
_init_and_read_len_prefixed_tlv_fields!(reader, {
(0, payment_id, required),
(2, payment_hash, required),
(4, path, required_vec),
(6, blinded_tail, option),
});
Ok(Some(Event::ProbeSuccessful {
payment_id: payment_id.0.unwrap(),
payment_hash: payment_hash.0.unwrap(),
path: Path { hops: path, blinded_tail },
}))
};
f()
},
23u8 => {
let f = || {
_init_and_read_len_prefixed_tlv_fields!(reader, {
(0, payment_id, required),
(2, payment_hash, required),
(4, path, required_vec),
(6, short_channel_id, option),
(8, blinded_tail, option),
});
Ok(Some(Event::ProbeFailed {
payment_id: payment_id.0.unwrap(),
payment_hash: payment_hash.0.unwrap(),
path: Path { hops: path, blinded_tail },
short_channel_id,
}))
};
f()
},
25u8 => {
let f = || {
let mut prev_channel_id = ChannelId::new_zero();
let mut failed_next_destination_opt = UpgradableRequired(None);
read_tlv_fields!(reader, {
(0, prev_channel_id, required),
(2, failed_next_destination_opt, upgradable_required),
});
Ok(Some(Event::HTLCHandlingFailed {
prev_channel_id,
failed_next_destination: _init_tlv_based_struct_field!(failed_next_destination_opt, upgradable_required),
}))
};
f()
},
27u8 => Ok(None),
29u8 => {
let f = || {
let mut channel_id = ChannelId::new_zero();
let mut user_channel_id: u128 = 0;
let mut counterparty_node_id = RequiredWrapper(None);
let mut channel_type = RequiredWrapper(None);
read_tlv_fields!(reader, {
(0, channel_id, required),
(2, user_channel_id, required),
(4, counterparty_node_id, required),
(6, channel_type, required),
});
Ok(Some(Event::ChannelReady {
channel_id,
user_channel_id,
counterparty_node_id: counterparty_node_id.0.unwrap(),
channel_type: channel_type.0.unwrap()
}))
};
f()
},
31u8 => {
let f = || {
let mut channel_id = ChannelId::new_zero();
let mut user_channel_id: u128 = 0;
let mut former_temporary_channel_id = None;
let mut counterparty_node_id = RequiredWrapper(None);
let mut funding_txo = RequiredWrapper(None);
read_tlv_fields!(reader, {
(0, channel_id, required),
(2, user_channel_id, required),
(4, former_temporary_channel_id, required),
(6, counterparty_node_id, required),
(8, funding_txo, required),
});
Ok(Some(Event::ChannelPending {
channel_id,
user_channel_id,
former_temporary_channel_id,
counterparty_node_id: counterparty_node_id.0.unwrap(),
funding_txo: funding_txo.0.unwrap()
}))
};
f()
},
33u8 => {
let f = || {
_init_and_read_len_prefixed_tlv_fields!(reader, {
(0, payment_id, required),
});
Ok(Some(Event::InvoiceRequestFailed {
payment_id: payment_id.0.unwrap(),
}))
};
f()
},
35u8 => Ok(None),
x if x % 2 == 1 => {
let tlv_len: BigSize = Readable::read(reader)?;
FixedLengthReader::new(reader, tlv_len.0)
.eat_remaining().map_err(|_| msgs::DecodeError::ShortRead)?;
Ok(None)
},
_ => Err(msgs::DecodeError::InvalidValue)
}
}
}
#[derive(Clone, Debug)]
#[cfg_attr(test, derive(PartialEq))]
pub enum MessageSendEvent {
SendAcceptChannel {
node_id: PublicKey,
msg: msgs::AcceptChannel,
},
SendAcceptChannelV2 {
node_id: PublicKey,
msg: msgs::AcceptChannelV2,
},
SendOpenChannel {
node_id: PublicKey,
msg: msgs::OpenChannel,
},
SendOpenChannelV2 {
node_id: PublicKey,
msg: msgs::OpenChannelV2,
},
SendFundingCreated {
node_id: PublicKey,
msg: msgs::FundingCreated,
},
SendFundingSigned {
node_id: PublicKey,
msg: msgs::FundingSigned,
},
SendStfu {
node_id: PublicKey,
msg: msgs::Stfu,
},
SendSplice {
node_id: PublicKey,
msg: msgs::Splice,
},
SendSpliceAck {
node_id: PublicKey,
msg: msgs::SpliceAck,
},
SendSpliceLocked {
node_id: PublicKey,
msg: msgs::SpliceLocked,
},
SendTxAddInput {
node_id: PublicKey,
msg: msgs::TxAddInput,
},
SendTxAddOutput {
node_id: PublicKey,
msg: msgs::TxAddOutput,
},
SendTxRemoveInput {
node_id: PublicKey,
msg: msgs::TxRemoveInput,
},
SendTxRemoveOutput {
node_id: PublicKey,
msg: msgs::TxRemoveOutput,
},
SendTxComplete {
node_id: PublicKey,
msg: msgs::TxComplete,
},
SendTxSignatures {
node_id: PublicKey,
msg: msgs::TxSignatures,
},
SendTxInitRbf {
node_id: PublicKey,
msg: msgs::TxInitRbf,
},
SendTxAckRbf {
node_id: PublicKey,
msg: msgs::TxAckRbf,
},
SendTxAbort {
node_id: PublicKey,
msg: msgs::TxAbort,
},
SendChannelReady {
node_id: PublicKey,
msg: msgs::ChannelReady,
},
SendAnnouncementSignatures {
node_id: PublicKey,
msg: msgs::AnnouncementSignatures,
},
UpdateHTLCs {
node_id: PublicKey,
updates: msgs::CommitmentUpdate,
},
SendRevokeAndACK {
node_id: PublicKey,
msg: msgs::RevokeAndACK,
},
SendClosingSigned {
node_id: PublicKey,
msg: msgs::ClosingSigned,
},
SendShutdown {
node_id: PublicKey,
msg: msgs::Shutdown,
},
SendChannelReestablish {
node_id: PublicKey,
msg: msgs::ChannelReestablish,
},
SendChannelAnnouncement {
node_id: PublicKey,
msg: msgs::ChannelAnnouncement,
update_msg: msgs::ChannelUpdate,
},
BroadcastChannelAnnouncement {
msg: msgs::ChannelAnnouncement,
update_msg: Option<msgs::ChannelUpdate>,
},
BroadcastChannelUpdate {
msg: msgs::ChannelUpdate,
},
BroadcastNodeAnnouncement {
msg: msgs::NodeAnnouncement,
},
SendChannelUpdate {
node_id: PublicKey,
msg: msgs::ChannelUpdate,
},
HandleError {
node_id: PublicKey,
action: msgs::ErrorAction
},
SendChannelRangeQuery {
node_id: PublicKey,
msg: msgs::QueryChannelRange,
},
SendShortIdsQuery {
node_id: PublicKey,
msg: msgs::QueryShortChannelIds,
},
SendReplyChannelRange {
node_id: PublicKey,
msg: msgs::ReplyChannelRange,
},
SendGossipTimestampFilter {
node_id: PublicKey,
msg: msgs::GossipTimestampFilter,
},
}
pub trait MessageSendEventsProvider {
fn get_and_clear_pending_msg_events(&self) -> Vec<MessageSendEvent>;
}
pub trait EventsProvider {
fn process_pending_events<H: Deref>(&self, handler: H) where H::Target: EventHandler;
}
pub trait EventHandler {
fn handle_event(&self, event: Event);
}
impl<F> EventHandler for F where F: Fn(Event) {
fn handle_event(&self, event: Event) {
self(event)
}
}
impl<T: EventHandler> EventHandler for Arc<T> {
fn handle_event(&self, event: Event) {
self.deref().handle_event(event)
}
}