Skip to content

Commit ea2ffd3

Browse files
committed
Track paid fees in PaymentDetails
Since we split-out the paid fees anways, we optionally start tracking them in `PaymentDetails` for all payment types.
1 parent a38b180 commit ea2ffd3

File tree

9 files changed

+100
-19
lines changed

9 files changed

+100
-19
lines changed

bindings/ldk_node.udl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,7 @@ dictionary PaymentDetails {
412412
PaymentId id;
413413
PaymentKind kind;
414414
u64? amount_msat;
415+
u64? fee_paid_msat;
415416
PaymentDirection direction;
416417
PaymentStatus status;
417418
u64 latest_update_timestamp;

src/event.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -725,6 +725,7 @@ where
725725
payment_id,
726726
kind,
727727
Some(amount_msat),
728+
None,
728729
PaymentDirection::Inbound,
729730
PaymentStatus::Pending,
730731
);
@@ -765,6 +766,7 @@ where
765766
payment_id,
766767
kind,
767768
Some(amount_msat),
769+
None,
768770
PaymentDirection::Inbound,
769771
PaymentStatus::Pending,
770772
);
@@ -931,6 +933,7 @@ where
931933
let update = PaymentDetailsUpdate {
932934
hash: Some(Some(payment_hash)),
933935
preimage: Some(Some(payment_preimage)),
936+
fee_paid_msat: Some(fee_paid_msat),
934937
status: Some(PaymentStatus::Succeeded),
935938
..PaymentDetailsUpdate::new(payment_id)
936939
};

src/payment/bolt11.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ impl Bolt11Payment {
160160
payment_id,
161161
kind,
162162
invoice.amount_milli_satoshis(),
163+
None,
163164
PaymentDirection::Outbound,
164165
PaymentStatus::Pending,
165166
);
@@ -182,6 +183,7 @@ impl Bolt11Payment {
182183
payment_id,
183184
kind,
184185
invoice.amount_milli_satoshis(),
186+
None,
185187
PaymentDirection::Outbound,
186188
PaymentStatus::Failed,
187189
);
@@ -293,6 +295,7 @@ impl Bolt11Payment {
293295
payment_id,
294296
kind,
295297
Some(amount_msat),
298+
None,
296299
PaymentDirection::Outbound,
297300
PaymentStatus::Pending,
298301
);
@@ -315,6 +318,7 @@ impl Bolt11Payment {
315318
payment_id,
316319
kind,
317320
Some(amount_msat),
321+
None,
318322
PaymentDirection::Outbound,
319323
PaymentStatus::Failed,
320324
);
@@ -531,6 +535,7 @@ impl Bolt11Payment {
531535
id,
532536
kind,
533537
amount_msat,
538+
None,
534539
PaymentDirection::Inbound,
535540
PaymentStatus::Pending,
536541
);
@@ -666,6 +671,7 @@ impl Bolt11Payment {
666671
id,
667672
kind,
668673
amount_msat,
674+
None,
669675
PaymentDirection::Inbound,
670676
PaymentStatus::Pending,
671677
);

src/payment/bolt12.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ impl Bolt12Payment {
113113
payment_id,
114114
kind,
115115
Some(offer_amount_msat),
116+
None,
116117
PaymentDirection::Outbound,
117118
PaymentStatus::Pending,
118119
);
@@ -137,6 +138,7 @@ impl Bolt12Payment {
137138
payment_id,
138139
kind,
139140
Some(offer_amount_msat),
141+
None,
140142
PaymentDirection::Outbound,
141143
PaymentStatus::Failed,
142144
);
@@ -217,6 +219,7 @@ impl Bolt12Payment {
217219
payment_id,
218220
kind,
219221
Some(amount_msat),
222+
None,
220223
PaymentDirection::Outbound,
221224
PaymentStatus::Pending,
222225
);
@@ -241,6 +244,7 @@ impl Bolt12Payment {
241244
payment_id,
242245
kind,
243246
Some(amount_msat),
247+
None,
244248
PaymentDirection::Outbound,
245249
PaymentStatus::Failed,
246250
);
@@ -338,6 +342,7 @@ impl Bolt12Payment {
338342
payment_id,
339343
kind,
340344
Some(refund.amount_msats()),
345+
None,
341346
PaymentDirection::Inbound,
342347
PaymentStatus::Pending,
343348
);
@@ -402,6 +407,7 @@ impl Bolt12Payment {
402407
payment_id,
403408
kind,
404409
Some(amount_msat),
410+
None,
405411
PaymentDirection::Outbound,
406412
PaymentStatus::Pending,
407413
);

src/payment/spontaneous.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ impl SpontaneousPayment {
140140
payment_id,
141141
kind,
142142
Some(amount_msat),
143+
None,
143144
PaymentDirection::Outbound,
144145
PaymentStatus::Pending,
145146
);
@@ -161,6 +162,7 @@ impl SpontaneousPayment {
161162
payment_id,
162163
kind,
163164
Some(amount_msat),
165+
None,
164166
PaymentDirection::Outbound,
165167
PaymentStatus::Failed,
166168
);

src/payment/store.rs

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,13 @@ pub struct PaymentDetails {
4242
pub kind: PaymentKind,
4343
/// The amount transferred.
4444
pub amount_msat: Option<u64>,
45+
/// The fees that were paid for this payment.
46+
///
47+
/// For Lightning payments, this will only be updated for outbound payments once they
48+
/// succeeded.
49+
///
50+
/// Will be `None` for Lightning payments made with LDK Node v0.4.x and earlier.
51+
pub fee_paid_msat: Option<u64>,
4552
/// The direction of the payment.
4653
pub direction: PaymentDirection,
4754
/// The status of the payment.
@@ -52,14 +59,14 @@ pub struct PaymentDetails {
5259

5360
impl PaymentDetails {
5461
pub(crate) fn new(
55-
id: PaymentId, kind: PaymentKind, amount_msat: Option<u64>, direction: PaymentDirection,
56-
status: PaymentStatus,
62+
id: PaymentId, kind: PaymentKind, amount_msat: Option<u64>, fee_paid_msat: Option<u64>,
63+
direction: PaymentDirection, status: PaymentStatus,
5764
) -> Self {
5865
let latest_update_timestamp = SystemTime::now()
5966
.duration_since(UNIX_EPOCH)
6067
.unwrap_or(Duration::from_secs(0))
6168
.as_secs();
62-
Self { id, kind, amount_msat, direction, status, latest_update_timestamp }
69+
Self { id, kind, amount_msat, fee_paid_msat, direction, status, latest_update_timestamp }
6370
}
6471

6572
pub(crate) fn update(&mut self, update: &PaymentDetailsUpdate) -> bool {
@@ -154,6 +161,10 @@ impl PaymentDetails {
154161
update_if_necessary!(self.amount_msat, amount_opt);
155162
}
156163

164+
if let Some(fee_paid_msat_opt) = update.fee_paid_msat {
165+
update_if_necessary!(self.fee_paid_msat, fee_paid_msat_opt);
166+
}
167+
157168
if let Some(status) = update.status {
158169
update_if_necessary!(self.status, status);
159170
}
@@ -192,6 +203,7 @@ impl Writeable for PaymentDetails {
192203
(4, None::<Option<PaymentSecret>>, required),
193204
(5, self.latest_update_timestamp, required),
194205
(6, self.amount_msat, required),
206+
(7, self.fee_paid_msat, option),
195207
(8, self.direction, required),
196208
(10, self.status, required)
197209
});
@@ -213,6 +225,7 @@ impl Readable for PaymentDetails {
213225
(4, secret, required),
214226
(5, latest_update_timestamp, (default_value, unix_time_secs)),
215227
(6, amount_msat, required),
228+
(7, fee_paid_msat, option),
216229
(8, direction, required),
217230
(10, status, required)
218231
});
@@ -253,7 +266,15 @@ impl Readable for PaymentDetails {
253266
}
254267
};
255268

256-
Ok(PaymentDetails { id, kind, amount_msat, direction, status, latest_update_timestamp })
269+
Ok(PaymentDetails {
270+
id,
271+
kind,
272+
amount_msat,
273+
fee_paid_msat,
274+
direction,
275+
status,
276+
latest_update_timestamp,
277+
})
257278
}
258279
}
259280

@@ -479,6 +500,7 @@ pub(crate) struct PaymentDetailsUpdate {
479500
pub preimage: Option<Option<PaymentPreimage>>,
480501
pub secret: Option<Option<PaymentSecret>>,
481502
pub amount_msat: Option<Option<u64>>,
503+
pub fee_paid_msat: Option<Option<u64>>,
482504
pub direction: Option<PaymentDirection>,
483505
pub status: Option<PaymentStatus>,
484506
pub confirmation_status: Option<ConfirmationStatus>,
@@ -492,6 +514,7 @@ impl PaymentDetailsUpdate {
492514
preimage: None,
493515
secret: None,
494516
amount_msat: None,
517+
fee_paid_msat: None,
495518
direction: None,
496519
status: None,
497520
confirmation_status: None,
@@ -521,6 +544,7 @@ impl From<&PaymentDetails> for PaymentDetailsUpdate {
521544
preimage: Some(preimage),
522545
secret: Some(secret),
523546
amount_msat: Some(value.amount_msat),
547+
fee_paid_msat: Some(value.fee_paid_msat),
524548
direction: Some(value.direction),
525549
status: Some(value.status),
526550
confirmation_status,
@@ -708,8 +732,14 @@ mod tests {
708732
.is_err());
709733

710734
let kind = PaymentKind::Bolt11 { hash, preimage: None, secret: None };
711-
let payment =
712-
PaymentDetails::new(id, kind, None, PaymentDirection::Inbound, PaymentStatus::Pending);
735+
let payment = PaymentDetails::new(
736+
id,
737+
kind,
738+
None,
739+
None,
740+
PaymentDirection::Inbound,
741+
PaymentStatus::Pending,
742+
);
713743

714744
assert_eq!(Ok(false), payment_store.insert(payment.clone()));
715745
assert!(payment_store.get(&id).is_some());

src/wallet/mod.rs

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@ use bitcoin::{
4949

5050
use std::ops::Deref;
5151
use std::sync::{Arc, Mutex};
52-
use std::time::{Duration, SystemTime, UNIX_EPOCH};
5352

5453
pub(crate) enum OnchainSendAmount {
5554
ExactRetainingReserve { amount_sats: u64, cur_anchor_reserve_sats: u64 },
@@ -146,11 +145,6 @@ where
146145
fn update_payment_store<'a>(
147146
&self, locked_wallet: &'a mut PersistedWallet<KVStoreWalletPersister>,
148147
) -> Result<(), Error> {
149-
let latest_update_timestamp = SystemTime::now()
150-
.duration_since(UNIX_EPOCH)
151-
.unwrap_or(Duration::from_secs(0))
152-
.as_secs();
153-
154148
for wtx in locked_wallet.transactions() {
155149
let id = PaymentId(wtx.tx_node.txid.to_byte_array());
156150
let txid = wtx.tx_node.txid;
@@ -205,14 +199,16 @@ where
205199
(direction, amount_msat)
206200
};
207201

208-
let payment = PaymentDetails {
202+
let fee_paid_msat = Some(fee.to_sat() * 1000);
203+
204+
let payment = PaymentDetails::new(
209205
id,
210206
kind,
211207
amount_msat,
208+
fee_paid_msat,
212209
direction,
213-
status: payment_status,
214-
latest_update_timestamp,
215-
};
210+
payment_status,
211+
);
216212

217213
self.payment_store.insert_or_update(&payment)?;
218214
}

tests/common/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,8 @@ macro_rules! expect_payment_successful_event {
148148
if let Some(fee_msat) = $fee_paid_msat {
149149
assert_eq!(fee_paid_msat, fee_msat);
150150
}
151+
let payment = $node.payment(&$payment_id.unwrap()).unwrap();
152+
assert_eq!(payment.fee_paid_msat, fee_paid_msat);
151153
assert_eq!(payment_id, $payment_id);
152154
$node.event_handled();
153155
},

tests/integration_tests_rust.rs

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ use lightning::util::persist::KVStore;
2626

2727
use bitcoincore_rpc::RpcApi;
2828

29+
use bitcoin::hashes::Hash;
2930
use bitcoin::Amount;
3031
use lightning_invoice::{Bolt11InvoiceDescription, Description};
3132

@@ -281,7 +282,7 @@ fn start_stop_reinit() {
281282
}
282283

283284
#[test]
284-
fn onchain_spend_receive() {
285+
fn onchain_send_receive() {
285286
let (bitcoind, electrsd) = setup_bitcoind_and_electrsd();
286287
let chain_source = TestChainSource::Esplora(&electrsd);
287288
let (node_a, node_b) = setup_two_nodes(&chain_source, false, true, false);
@@ -352,12 +353,24 @@ fn onchain_spend_receive() {
352353
node_a.onchain_payment().send_to_address(&addr_b, expected_node_a_balance + 1, None)
353354
);
354355

355-
let amount_to_send_sats = 1000;
356+
let amount_to_send_sats = 54321;
356357
let txid =
357358
node_b.onchain_payment().send_to_address(&addr_a, amount_to_send_sats, None).unwrap();
358-
generate_blocks_and_wait(&bitcoind.client, &electrsd.client, 6);
359359
wait_for_tx(&electrsd.client, txid);
360+
node_a.sync_wallets().unwrap();
361+
node_b.sync_wallets().unwrap();
360362

363+
let payment_id = PaymentId(txid.to_byte_array());
364+
let payment_a = node_a.payment(&payment_id).unwrap();
365+
assert_eq!(payment_a.status, PaymentStatus::Pending);
366+
assert!(payment_a.fee_paid_msat > Some(0));
367+
let payment_b = node_b.payment(&payment_id).unwrap();
368+
assert_eq!(payment_b.status, PaymentStatus::Pending);
369+
assert!(payment_b.fee_paid_msat > Some(0));
370+
assert_eq!(payment_a.amount_msat, payment_b.amount_msat);
371+
assert_eq!(payment_a.fee_paid_msat, payment_b.fee_paid_msat);
372+
373+
generate_blocks_and_wait(&bitcoind.client, &electrsd.client, 6);
361374
node_a.sync_wallets().unwrap();
362375
node_b.sync_wallets().unwrap();
363376

@@ -375,6 +388,28 @@ fn onchain_spend_receive() {
375388
node_b.list_payments_with_filter(|p| matches!(p.kind, PaymentKind::Onchain { .. }));
376389
assert_eq!(node_b_payments.len(), 3);
377390

391+
let payment_a = node_a.payment(&payment_id).unwrap();
392+
assert_eq!(payment_a.amount_msat, Some(amount_to_send_sats * 1000));
393+
assert!(payment_a.fee_paid_msat > Some(0));
394+
match payment_a.kind {
395+
PaymentKind::Onchain { txid: _txid, status } => {
396+
assert_eq!(_txid, txid);
397+
assert!(matches!(status, ConfirmationStatus::Confirmed { .. }));
398+
},
399+
_ => panic!("Unexpected payment kind"),
400+
}
401+
402+
let payment_b = node_a.payment(&payment_id).unwrap();
403+
assert_eq!(payment_b.amount_msat, Some(amount_to_send_sats * 1000));
404+
assert!(payment_b.fee_paid_msat > Some(0));
405+
match payment_b.kind {
406+
PaymentKind::Onchain { txid: _txid, status } => {
407+
assert_eq!(_txid, txid);
408+
assert!(matches!(status, ConfirmationStatus::Confirmed { .. }));
409+
},
410+
_ => panic!("Unexpected payment kind"),
411+
}
412+
378413
let addr_b = node_b.onchain_payment().new_address().unwrap();
379414
let txid = node_a.onchain_payment().send_all_to_address(&addr_b, true, None).unwrap();
380415
generate_blocks_and_wait(&bitcoind.client, &electrsd.client, 6);

0 commit comments

Comments
 (0)