Skip to content

Commit 9dd71eb

Browse files
committed
chore: improve onchain events
1 parent 7de3bce commit 9dd71eb

File tree

9 files changed

+527
-328
lines changed

9 files changed

+527
-328
lines changed

bindings/ldk_node.udl

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -387,11 +387,26 @@ enum VssHeaderProviderError {
387387
"InternalError",
388388
};
389389

390-
[Enum]
391-
interface TransactionContext {
392-
ChannelFunding(ChannelId channel_id, UserChannelId user_channel_id, PublicKey counterparty_node_id);
393-
ChannelClosure(ChannelId channel_id, UserChannelId user_channel_id, PublicKey? counterparty_node_id);
394-
RegularWallet();
390+
dictionary TxInput {
391+
string txid;
392+
u32 vout;
393+
string scriptsig;
394+
sequence<string> witness;
395+
u32 sequence;
396+
};
397+
398+
dictionary TxOutput {
399+
string scriptpubkey;
400+
string? scriptpubkey_type;
401+
string? scriptpubkey_address;
402+
i64 value;
403+
u32 n;
404+
};
405+
406+
dictionary TransactionDetails {
407+
i64 amount_sats;
408+
sequence<TxInput> inputs;
409+
sequence<TxOutput> outputs;
395410
};
396411

397412
enum SyncType {
@@ -411,9 +426,10 @@ interface Event {
411426
ChannelPending(ChannelId channel_id, UserChannelId user_channel_id, ChannelId former_temporary_channel_id, PublicKey counterparty_node_id, OutPoint funding_txo);
412427
ChannelReady(ChannelId channel_id, UserChannelId user_channel_id, PublicKey? counterparty_node_id);
413428
ChannelClosed(ChannelId channel_id, UserChannelId user_channel_id, PublicKey? counterparty_node_id, ClosureReason? reason);
414-
OnchainTransactionConfirmed(Txid txid, BlockHash block_hash, u32 block_height, u64 confirmation_time, TransactionContext context);
415-
OnchainTransactionUnconfirmed(Txid txid);
416-
OnchainTransactionReceived(Txid txid, i64 amount_sats, TransactionContext context);
429+
OnchainTransactionConfirmed(Txid txid, BlockHash block_hash, u32 block_height, u64 confirmation_time, TransactionDetails details);
430+
OnchainTransactionReceived(Txid txid, TransactionDetails details);
431+
OnchainTransactionReplaced(Txid txid);
432+
OnchainTransactionReorged(Txid txid);
417433
SyncProgress(SyncType sync_type, u8 progress_percent, u32 current_block_height, u32 target_block_height);
418434
SyncCompleted(SyncType sync_type, u32 synced_block_height);
419435
BalanceChanged(u64 old_spendable_onchain_balance_sats, u64 new_spendable_onchain_balance_sats, u64 old_total_onchain_balance_sats, u64 new_total_onchain_balance_sats, u64 old_total_lightning_balance_sats, u64 new_total_lightning_balance_sats);

src/chain/mod.rs

Lines changed: 65 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@ use crate::logger::{log_bytes, log_error, log_info, log_trace, LdkLogger, Logger
2727
use crate::types::{Broadcaster, ChainMonitor, ChannelManager, DynStore, Sweeper, Wallet};
2828
use crate::{Error, NodeMetrics};
2929

30-
use lightning::chain::chaininterface::{BroadcasterInterface, ConfirmationTarget as LdkConfirmationTarget};
30+
use lightning::chain::chaininterface::{
31+
BroadcasterInterface, ConfirmationTarget as LdkConfirmationTarget,
32+
};
3133
use lightning::chain::{Confirm, Filter, Listen, WatchedOutput};
3234
use lightning::util::ser::Writeable;
3335

@@ -48,8 +50,8 @@ use esplora_client::AsyncClient as EsploraAsyncClient;
4850

4951
use bitcoin::{FeeRate, Network, Script, ScriptBuf, Txid};
5052

51-
use crate::event::{Event, EventQueue, SyncType};
5253
use crate::check_and_emit_balance_update;
54+
use crate::event::{Event, EventQueue, SyncType};
5355

5456
use std::collections::HashMap;
5557
use std::ops::Deref;
@@ -237,61 +239,29 @@ pub(crate) enum ChainSource {
237239
},
238240
}
239241

240-
use crate::event::TransactionContext;
241-
use crate::types::UserChannelId;
242-
use lightning::ln::types::ChannelId;
243-
244-
/// Determine transaction context by checking against known channel funding outpoints.
245-
///
246-
/// This function attempts to identify whether a transaction is related to channel operations
247-
/// by checking against the channel manager and channel monitor data.
248-
fn determine_transaction_context(
249-
txid: &bitcoin::Txid,
250-
channel_manager: Option<&Arc<ChannelManager>>,
251-
chain_monitor: Option<&Arc<ChainMonitor>>,
252-
) -> TransactionContext {
253-
// Check if this transaction is a known channel funding transaction
254-
if let Some(cm) = channel_manager {
255-
// Check all channels for matching funding txids
256-
for channel_details in cm.list_channels() {
257-
if let Some(funding_txo) = channel_details.funding_txo {
258-
if funding_txo.txid == *txid {
259-
// This is a channel funding transaction
260-
return TransactionContext::ChannelFunding {
261-
channel_id: channel_details.channel_id,
262-
user_channel_id: UserChannelId(channel_details.user_channel_id),
263-
counterparty_node_id: channel_details.counterparty.node_id,
264-
};
265-
}
266-
}
267-
}
242+
use crate::event::TransactionDetails;
268243

269-
// Check recently closed channels - they might not be in the active list anymore
270-
// but could still have pending transactions
271-
for _channel_details in cm.list_recent_payments() {
272-
// TODO: Once we have access to closed channel data, we can check those as well
273-
// For now, we'll need to rely on the channel monitor
274-
}
275-
}
276-
277-
// Check channel monitors for channel closure transactions
278-
if let Some(_monitor) = chain_monitor {
279-
// The chain monitor can help identify channel closures
280-
// TODO: Implement channel closure detection through monitor data
281-
// This would require iterating through monitored channels and checking
282-
// their closing transactions
283-
}
244+
/// Get transaction details including inputs and outputs.
245+
fn get_transaction_details<B: Deref, E: Deref, L: Deref>(
246+
txid: &bitcoin::Txid, wallet: &crate::wallet::Wallet<B, E, L>,
247+
_channel_manager: Option<&Arc<ChannelManager>>,
248+
) -> Option<TransactionDetails>
249+
where
250+
B::Target: lightning::chain::chaininterface::BroadcasterInterface,
251+
E::Target: crate::fee_estimator::FeeEstimator,
252+
L::Target: crate::logger::LdkLogger,
253+
{
254+
// Get transaction details from wallet
255+
let (amount_sats, inputs, outputs) = wallet.get_tx_details(txid)?;
284256

285-
// Default to regular wallet transaction if we can't identify it as channel-related
286-
// Applications can still cross-reference with ChannelPending/ChannelClosed events
287-
TransactionContext::RegularWallet
257+
Some(TransactionDetails { amount_sats, inputs, outputs })
288258
}
289259

290260
/// Process BDK wallet events and emit corresponding ldk-node events via the event queue.
291261
fn process_wallet_events<B: Deref, E: Deref, L: Deref, L2: Deref>(
292262
wallet_events: Vec<BdkWalletEvent>, wallet: &crate::wallet::Wallet<B, E, L>,
293263
event_queue: &EventQueue<L2>, logger: &Arc<Logger>,
294-
channel_manager: Option<&Arc<ChannelManager>>, chain_monitor: Option<&Arc<ChainMonitor>>,
264+
channel_manager: Option<&Arc<ChannelManager>>, _chain_monitor: Option<&Arc<ChainMonitor>>,
295265
) -> Result<(), Error>
296266
where
297267
B::Target: BroadcasterInterface,
@@ -302,22 +272,29 @@ where
302272
for wallet_event in wallet_events {
303273
match wallet_event {
304274
BdkWalletEvent::TxConfirmed { txid, block_time, .. } => {
275+
let details = get_transaction_details(&txid, wallet, channel_manager)
276+
.unwrap_or_else(|| {
277+
log_error!(logger, "Transaction {} not found in wallet", txid);
278+
TransactionDetails {
279+
amount_sats: 0,
280+
inputs: Vec::new(),
281+
outputs: Vec::new(),
282+
}
283+
});
284+
305285
log_info!(
306286
logger,
307287
"Onchain transaction {} confirmed at height {}",
308288
txid,
309289
block_time.block_id.height
310290
);
311291

312-
// Determine the transaction context by checking channel data
313-
let context = determine_transaction_context(&txid, channel_manager, chain_monitor);
314-
315292
let event = Event::OnchainTransactionConfirmed {
316293
txid,
317294
block_hash: block_time.block_id.hash,
318295
block_height: block_time.block_id.height,
319296
confirmation_time: block_time.confirmation_time,
320-
context,
297+
details,
321298
};
322299
event_queue.add_event(event).map_err(|e| {
323300
log_error!(logger, "Failed to push onchain event to queue: {}", e);
@@ -328,31 +305,37 @@ where
328305
match old_block_time {
329306
Some(_) => {
330307
// Transaction was previously confirmed but is now unconfirmed (reorg)
331-
log_info!(logger, "Onchain transaction {} became unconfirmed (reorg)", txid);
332-
let event = Event::OnchainTransactionUnconfirmed { txid };
308+
log_info!(
309+
logger,
310+
"Onchain transaction {} became unconfirmed (reorg)",
311+
txid
312+
);
313+
let event = Event::OnchainTransactionReorged { txid };
333314
event_queue.add_event(event).map_err(|e| {
334315
log_error!(logger, "Failed to push onchain event to queue: {}", e);
335316
e
336317
})?;
337318
},
338319
None => {
339320
// New unconfirmed transaction detected in mempool
340-
// Get transaction details from wallet to calculate the amount
341-
let amount_sats = wallet.get_tx_net_amount(&txid).unwrap_or_else(|| {
342-
// Shouldn't happen, but handle gracefully
343-
log_error!(logger, "Transaction {} not found in wallet", txid);
344-
0
345-
});
321+
let details = get_transaction_details(&txid, wallet, channel_manager)
322+
.unwrap_or_else(|| {
323+
log_error!(logger, "Transaction {} not found in wallet", txid);
324+
TransactionDetails {
325+
amount_sats: 0,
326+
inputs: Vec::new(),
327+
outputs: Vec::new(),
328+
}
329+
});
346330

347331
log_info!(
348332
logger,
349333
"New unconfirmed transaction {} detected in mempool (amount: {} sats)",
350334
txid,
351-
amount_sats
335+
details.amount_sats
352336
);
353337

354-
let context = determine_transaction_context(&txid, channel_manager, chain_monitor);
355-
let event = Event::OnchainTransactionReceived { txid, amount_sats, context };
338+
let event = Event::OnchainTransactionReceived { txid, details };
356339
event_queue.add_event(event).map_err(|e| {
357340
log_error!(logger, "Failed to push onchain event to queue: {}", e);
358341
e
@@ -373,8 +356,7 @@ where
373356
},
374357
BdkWalletEvent::TxReplaced { txid, .. } => {
375358
log_info!(logger, "Onchain transaction {} was replaced", txid);
376-
// Treat a replacement as an unconfirm event
377-
let event = Event::OnchainTransactionUnconfirmed { txid };
359+
let event = Event::OnchainTransactionReplaced { txid };
378360
event_queue.add_event(event).map_err(|e| {
379361
log_error!(logger, "Failed to push onchain event to queue: {}", e);
380362
e
@@ -1053,15 +1035,24 @@ impl ChainSource {
10531035
(channel_manager, chain_monitor, config)
10541036
{
10551037
// Compute current balances
1056-
let cur_anchor_reserve_sats = crate::total_anchor_channels_reserve_sats(cm, cfg);
1057-
let (total_onchain_balance_sats, spendable_onchain_balance_sats) =
1058-
onchain_wallet.get_balances(cur_anchor_reserve_sats).unwrap_or((0, 0));
1038+
let cur_anchor_reserve_sats =
1039+
crate::total_anchor_channels_reserve_sats(cm, cfg);
1040+
let (
1041+
total_onchain_balance_sats,
1042+
spendable_onchain_balance_sats,
1043+
) = onchain_wallet
1044+
.get_balances(cur_anchor_reserve_sats)
1045+
.unwrap_or((0, 0));
10591046

10601047
let mut total_lightning_balance_sats = 0;
1061-
for (funding_txo, _channel_id) in chain_mon.list_monitors() {
1062-
if let Ok(monitor) = chain_mon.get_monitor(funding_txo) {
1063-
for ldk_balance in monitor.get_claimable_balances() {
1064-
total_lightning_balance_sats += ldk_balance.claimable_amount_satoshis();
1048+
for (funding_txo, _channel_id) in chain_mon.list_monitors()
1049+
{
1050+
if let Ok(monitor) = chain_mon.get_monitor(funding_txo)
1051+
{
1052+
for ldk_balance in monitor.get_claimable_balances()
1053+
{
1054+
total_lightning_balance_sats +=
1055+
ldk_balance.claimable_amount_satoshis();
10651056
}
10661057
}
10671058
}
@@ -1071,7 +1062,7 @@ impl ChainSource {
10711062
spendable_onchain_balance_sats,
10721063
total_anchor_channels_reserve_sats: std::cmp::min(
10731064
cur_anchor_reserve_sats,
1074-
total_onchain_balance_sats
1065+
total_onchain_balance_sats,
10751066
),
10761067
total_lightning_balance_sats,
10771068
lightning_balances: Vec::new(), // We don't need full details for change detection
@@ -1909,4 +1900,3 @@ fn periodically_archive_fully_resolved_monitors(
19091900
}
19101901
Ok(())
19111902
}
1912-

0 commit comments

Comments
 (0)