Skip to content

Commit

Permalink
Expose bump transaction and channel close events
Browse files Browse the repository at this point in the history
  • Loading branch information
jjyr committed Nov 25, 2024
1 parent 414a731 commit 8d8b4db
Show file tree
Hide file tree
Showing 6 changed files with 101 additions and 45 deletions.
39 changes: 36 additions & 3 deletions mutiny-core/src/event.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::ldkstorage::{MutinyNodePersister, PhantomChannelManager};
use crate::logging::MutinyLogger;
use crate::lsp::{AnyLsp, Lsp};
use crate::messagehandler::{CommonLnEvent, CommonLnEventCallback};
use crate::node::BumpTxEventHandler;
use crate::nodemanager::ChannelClosure;
use crate::onchain::OnChainWallet;
Expand All @@ -13,7 +14,7 @@ use bitcoin::absolute::LockTime;
use bitcoin::secp256k1::PublicKey;
use bitcoin::secp256k1::Secp256k1;
use core::fmt;
use lightning::events::{BumpTransactionEvent, Event, PaymentPurpose, ReplayEvent};
use lightning::events::{BumpTransactionEvent, ClosureReason, Event, PaymentPurpose, ReplayEvent};
use lightning::sign::SpendableOutputDescriptor;
use lightning::{
log_debug, log_error, log_info, log_warn, util::errors::APIError, util::logger::Logger,
Expand Down Expand Up @@ -100,6 +101,7 @@ pub struct EventHandler<S: MutinyStorage> {
lsp_client: Option<AnyLsp<S>>,
logger: Arc<MutinyLogger>,
do_not_bump_channel_closed_tx: bool,
ln_event_callback: Option<CommonLnEventCallback>,
}

impl<S: MutinyStorage> EventHandler<S> {
Expand All @@ -114,6 +116,7 @@ impl<S: MutinyStorage> EventHandler<S> {
lsp_client: Option<AnyLsp<S>>,
logger: Arc<MutinyLogger>,
do_not_bump_channel_closed_tx: bool,
ln_event_callback: Option<CommonLnEventCallback>,
) -> Self {
Self {
channel_manager,
Expand All @@ -125,6 +128,7 @@ impl<S: MutinyStorage> EventHandler<S> {
bump_tx_event_handler,
logger,
do_not_bump_channel_closed_tx,
ln_event_callback,
}
}

Expand Down Expand Up @@ -589,6 +593,23 @@ impl<S: MutinyStorage> EventHandler<S> {
reason
);

// We guess this is a force close if the reason isn't belongs to a cooperative reason
let maybe_force_closed = !matches!(
reason,
ClosureReason::LegacyCooperativeClosure
| ClosureReason::LocallyInitiatedCooperativeClosure
| ClosureReason::CounterpartyCoopClosedUnfundedChannel
| ClosureReason::CounterpartyInitiatedCooperativeClosure
);

let event = CommonLnEvent::ChannelClosed {
channel_id: format!("{channel_id}"),
reason: format!("{reason}"),
channel_funding_txo: channel_funding_txo.map(|txo| format!("{txo}")),
counterparty_node_id: node_id.map(|node_id| format!("{node_id:x}")),
maybe_force_closed,
};

let closure = ChannelClosure::new(
user_channel_id,
channel_id,
Expand All @@ -602,6 +623,10 @@ impl<S: MutinyStorage> EventHandler<S> {
{
log_error!(self.logger, "Failed to persist channel closure: {e}");
}

if let Some(cb) = self.ln_event_callback.as_ref() {
cb.trigger(event);
}
}
Event::DiscardFunding { .. } => {
// A "real" node should probably "lock" the UTXOs spent in funding transactions until
Expand Down Expand Up @@ -649,12 +674,13 @@ impl<S: MutinyStorage> EventHandler<S> {
commitment_tx,
..
} => {
let txid = format!("{:x}", commitment_tx.compute_txid());
let hex_tx = bitcoin::consensus::encode::serialize_hex(commitment_tx);
log_debug!(
self.logger,
"EVENT: BumpTransaction channel_id {} tx_id {:x}\nhex_tx {}",
"EVENT: BumpTransaction channel_id {} tx_id {}\nhex_tx {}",
channel_id,
commitment_tx.compute_txid(),
txid,
hex_tx
);
if self.do_not_bump_channel_closed_tx {
Expand All @@ -663,6 +689,13 @@ impl<S: MutinyStorage> EventHandler<S> {
log_debug!(self.logger, "Bump channel close transaction");
self.bump_tx_event_handler.handle_event(&event);
}
if let Some(cb) = self.ln_event_callback.as_ref() {
cb.trigger(CommonLnEvent::BumpChannelCloseTransaction {
channel_id: format!("{channel_id}"),
txid,
hex_tx,
});
}
}
_ => {
log_debug!(self.logger, "EVENT: BumpTransaction: {event:?}");
Expand Down
14 changes: 7 additions & 7 deletions mutiny-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ use lightning::{log_debug, log_error, log_info, log_trace, log_warn};
pub use lightning_invoice;
use lightning_invoice::{Bolt11Invoice, Bolt11InvoiceDescription};

use messagehandler::PeerEventCallback;
use messagehandler::CommonLnEventCallback;
use serde::{Deserialize, Serialize};
use utils::{spawn_with_handle, StopHandle};

Expand Down Expand Up @@ -669,7 +669,7 @@ pub struct MutinyWalletBuilder<S: MutinyStorage> {
network: Option<Network>,
blind_auth_url: Option<String>,
hermes_url: Option<String>,
peer_event_callback: Option<PeerEventCallback>,
ln_event_callback: Option<CommonLnEventCallback>,
subscription_url: Option<String>,
do_not_connect_peers: bool,
do_not_bump_channel_close_tx: bool,
Expand All @@ -689,7 +689,7 @@ impl<S: MutinyStorage> MutinyWalletBuilder<S> {
subscription_url: None,
blind_auth_url: None,
hermes_url: None,
peer_event_callback: None,
ln_event_callback: None,
do_not_connect_peers: false,
do_not_bump_channel_close_tx: false,
skip_device_lock: false,
Expand Down Expand Up @@ -732,8 +732,8 @@ impl<S: MutinyStorage> MutinyWalletBuilder<S> {
self.hermes_url = Some(hermes_url);
}

pub fn with_peer_event_callback(&mut self, cb: PeerEventCallback) {
self.peer_event_callback = Some(cb);
pub fn with_ln_event_callback(&mut self, cb: CommonLnEventCallback) {
self.ln_event_callback = Some(cb);
}

pub fn do_not_connect_peers(&mut self) {
Expand Down Expand Up @@ -835,8 +835,8 @@ impl<S: MutinyStorage> MutinyWalletBuilder<S> {
.with_config(config.clone());
nm_builder.with_logger(logger.clone());
nm_builder.with_esplora(esplora.clone());
if let Some(cb) = self.peer_event_callback.clone() {
nm_builder.with_peer_event_callback(cb);
if let Some(cb) = self.ln_event_callback.clone() {
nm_builder.with_ln_event_callback(cb);
}
let node_manager = Arc::new(nm_builder.build().await?);

Expand Down
42 changes: 32 additions & 10 deletions mutiny-core/src/messagehandler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,25 +14,47 @@ use crate::storage::MutinyStorage;

#[derive(Serialize, Deserialize)]
#[serde(tag = "type")]
pub enum PeerConnectionEvent {
pub enum CommonLnEvent {
// On Peer Connect
OnConnect {
their_node_id: String,
inbound: bool,
remote_network_address: Option<String>,
},
// On Peer Disconnect
OnDisconnect {
their_node_id: String,
},
BumpChannelCloseTransaction {
channel_id: String,
txid: String,
hex_tx: String,
},
ChannelClosed {
channel_id: String,
reason: String,
counterparty_node_id: Option<String>,
channel_funding_txo: Option<String>,
// This field may return true on a cooperate close event,
// this must only be used to report debugging information.
maybe_force_closed: bool,
},
}

#[derive(Clone)]
pub struct PeerEventCallback {
pub callback: Arc<dyn Fn(PeerConnectionEvent) + Send + Sync>,
pub struct CommonLnEventCallback {
pub callback: Arc<dyn Fn(CommonLnEvent) + Send + Sync>,
}

impl CommonLnEventCallback {
pub fn trigger(&self, event: CommonLnEvent) {
(self.callback)(event);
}
}

pub struct MutinyMessageHandler<S: MutinyStorage> {
pub liquidity: Option<Arc<LiquidityManager<S>>>,
pub peer_event_callback: Option<PeerEventCallback>,
pub ln_event_callback: Option<CommonLnEventCallback>,
}

pub enum MutinyMessage<S: MutinyStorage> {
Expand Down Expand Up @@ -100,26 +122,26 @@ impl<S: MutinyStorage> CustomMessageHandler for MutinyMessageHandler<S> {
msg: &lightning::ln::msgs::Init,
inbound: bool,
) -> Result<(), ()> {
if let Some(cb) = self.peer_event_callback.clone() {
let event = PeerConnectionEvent::OnConnect {
if let Some(cb) = self.ln_event_callback.clone() {
let event = CommonLnEvent::OnConnect {
their_node_id: their_node_id.to_string(),
inbound,
remote_network_address: msg
.remote_network_address
.as_ref()
.map(|addr| format!("{}", addr)),
};
(cb.callback)(event);
cb.trigger(event);
}
Ok(())
}

fn peer_disconnected(&self, their_node_id: &PublicKey) {
if let Some(cb) = self.peer_event_callback.clone() {
let event = PeerConnectionEvent::OnDisconnect {
if let Some(cb) = self.ln_event_callback.clone() {
let event = CommonLnEvent::OnDisconnect {
their_node_id: their_node_id.to_string(),
};
(cb.callback)(event);
cb.trigger(event);
}
}
}
Expand Down
13 changes: 7 additions & 6 deletions mutiny-core/src/node.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::lsp::LspConfig;
use crate::messagehandler::PeerEventCallback;
use crate::messagehandler::CommonLnEventCallback;
use crate::nodemanager::ChannelClosure;
use crate::peermanager::{LspMessageRouter, PeerManager};
use crate::storage::MutinyStorage;
Expand Down Expand Up @@ -198,7 +198,7 @@ pub struct NodeBuilder<S: MutinyStorage> {
fee_estimator: Option<Arc<MutinyFeeEstimator<S>>>,
wallet: Option<Arc<OnChainWallet<S>>>,
esplora: Option<Arc<AsyncClient>>,
peer_event_callback: Option<PeerEventCallback>,
ln_event_callback: Option<CommonLnEventCallback>,
#[cfg(target_arch = "wasm32")]
websocket_proxy_addr: Option<String>,
network: Option<Network>,
Expand All @@ -225,7 +225,7 @@ impl<S: MutinyStorage> NodeBuilder<S> {
wallet: None,
esplora: None,
has_done_initial_sync: None,
peer_event_callback: None,
ln_event_callback: None,
#[cfg(target_arch = "wasm32")]
websocket_proxy_addr: None,
lsp_config: None,
Expand Down Expand Up @@ -310,8 +310,8 @@ impl<S: MutinyStorage> NodeBuilder<S> {
self.lsp_config = Some(lsp_config);
}

pub fn with_peer_event_callback(&mut self, callback: PeerEventCallback) {
self.peer_event_callback = Some(callback);
pub fn with_ln_event_callback(&mut self, callback: CommonLnEventCallback) {
self.ln_event_callback = Some(callback);
}

pub fn with_logger(&mut self, logger: Arc<MutinyLogger>) {
Expand Down Expand Up @@ -580,7 +580,7 @@ impl<S: MutinyStorage> NodeBuilder<S> {
onion_message_handler: onion_message_handler.clone(),
custom_message_handler: Arc::new(MutinyMessageHandler {
liquidity: liquidity.clone(),
peer_event_callback: self.peer_event_callback.clone(),
ln_event_callback: self.ln_event_callback.clone(),
}),
};
log_trace!(logger, "finished creating peer manager");
Expand Down Expand Up @@ -611,6 +611,7 @@ impl<S: MutinyStorage> NodeBuilder<S> {
lsp_client.clone(),
logger.clone(),
self.do_not_bump_channel_close_tx,
self.ln_event_callback.clone(),
);
log_trace!(logger, "finished creating event handler");

Expand Down
22 changes: 11 additions & 11 deletions mutiny-core/src/nodemanager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use crate::labels::LabelStorage;
use crate::ldkstorage::CHANNEL_CLOSURE_PREFIX;
use crate::logging::LOGGING_KEY;
use crate::lsp::voltage;
use crate::messagehandler::PeerEventCallback;
use crate::messagehandler::CommonLnEventCallback;
use crate::peermanager::PeerManager;
use crate::utils::sleep;
use crate::MutinyInvoice;
Expand Down Expand Up @@ -252,7 +252,7 @@ pub struct NodeManagerBuilder<S: MutinyStorage> {
config: Option<MutinyWalletConfig>,
stop: Option<Arc<AtomicBool>>,
logger: Option<Arc<MutinyLogger>>,
peer_event_callback: Option<PeerEventCallback>,
ln_event_callback: Option<CommonLnEventCallback>,
}

impl<S: MutinyStorage> NodeManagerBuilder<S> {
Expand All @@ -264,7 +264,7 @@ impl<S: MutinyStorage> NodeManagerBuilder<S> {
config: None,
stop: None,
logger: None,
peer_event_callback: None,
ln_event_callback: None,
}
}

Expand All @@ -281,8 +281,8 @@ impl<S: MutinyStorage> NodeManagerBuilder<S> {
self.esplora = Some(esplora);
}

pub fn with_peer_event_callback(&mut self, cb: PeerEventCallback) {
self.peer_event_callback = Some(cb);
pub fn with_ln_event_callback(&mut self, cb: CommonLnEventCallback) {
self.ln_event_callback = Some(cb);
}

pub fn with_logger(&mut self, logger: Arc<MutinyLogger>) {
Expand Down Expand Up @@ -424,8 +424,8 @@ impl<S: MutinyStorage> NodeManagerBuilder<S> {
if let Some(l) = lsp_config.clone() {
node_builder.with_lsp_config(l);
}
if let Some(cb) = self.peer_event_callback.clone() {
node_builder.with_peer_event_callback(cb);
if let Some(cb) = self.ln_event_callback.clone() {
node_builder.with_ln_event_callback(cb);
}
if c.do_not_connect_peers {
node_builder.do_not_connect_peers();
Expand Down Expand Up @@ -500,7 +500,7 @@ impl<S: MutinyStorage> NodeManagerBuilder<S> {
websocket_proxy_addr,
user_rgs_url: c.user_rgs_url,
esplora,
peer_event_callback: self.peer_event_callback,
ln_event_callback: self.ln_event_callback,
lsp_config,
logger,
do_not_connect_peers: c.do_not_connect_peers,
Expand Down Expand Up @@ -528,7 +528,7 @@ pub struct NodeManager<S: MutinyStorage> {
websocket_proxy_addr: String,
user_rgs_url: Option<String>,
esplora: Arc<AsyncClient>,
peer_event_callback: Option<PeerEventCallback>,
ln_event_callback: Option<CommonLnEventCallback>,
pub(crate) wallet: Arc<OnChainWallet<S>>,
gossip_sync: Arc<RapidGossipSync>,
scorer: Arc<utils::Mutex<HubPreferentialScorer>>,
Expand Down Expand Up @@ -1977,8 +1977,8 @@ pub(crate) async fn create_new_node_from_node_manager<S: MutinyStorage>(
if let Some(l) = node_manager.lsp_config.clone() {
node_builder.with_lsp_config(l);
}
if let Some(cb) = node_manager.peer_event_callback.clone() {
node_builder.with_peer_event_callback(cb);
if let Some(cb) = node_manager.ln_event_callback.clone() {
node_builder.with_ln_event_callback(cb);
}
if node_manager.do_not_connect_peers {
node_builder.do_not_connect_peers();
Expand Down
Loading

0 comments on commit 8d8b4db

Please sign in to comment.