Skip to content

Commit c3e488b

Browse files
committed
f Expose methods to remove and list filtered payments
1 parent 6f5a9ce commit c3e488b

File tree

3 files changed

+65
-16
lines changed

3 files changed

+65
-16
lines changed

src/lib.rs

+32-6
Original file line numberDiff line numberDiff line change
@@ -503,11 +503,9 @@ impl Builder {
503503

504504
// Init payment info storage
505505
let payment_store = match io::utils::read_payments(Arc::clone(&kv_store)) {
506-
Ok(payments) => Arc::new(PaymentStore::from_payments(
507-
payments,
508-
Arc::clone(&kv_store),
509-
Arc::clone(&logger),
510-
)),
506+
Ok(payments) => {
507+
Arc::new(PaymentStore::new(payments, Arc::clone(&kv_store), Arc::clone(&logger)))
508+
}
511509
Err(e) => {
512510
log_error!(logger, "Failed to read payment information: {}", e.to_string());
513511
panic!("Failed to read payment information: {}", e.to_string());
@@ -1270,10 +1268,38 @@ impl Node {
12701268
Ok(invoice)
12711269
}
12721270

1273-
/// Query for information about the status of a specific payment.
1271+
/// Retrieve the details of a specific payment with the given hash.
1272+
///
1273+
/// Returns `Some` if the payment was known and `None` otherwise.
12741274
pub fn payment(&self, payment_hash: &PaymentHash) -> Option<PaymentDetails> {
12751275
self.payment_store.get(payment_hash)
12761276
}
1277+
1278+
/// Remove the payment with the given hash from the store.
1279+
///
1280+
/// Returns `true` if the payment was present and `false` otherwise.
1281+
pub fn remove_payment(&self, payment_hash: &PaymentHash) -> Result<bool, Error> {
1282+
self.payment_store.remove(&payment_hash)
1283+
}
1284+
1285+
/// Retrieves all payments that match the given predicate.
1286+
///
1287+
/// For example, you could retrieve all stored outbound payments as follows:
1288+
/// ```
1289+
/// # use ldk_node::{Builder, Config, PaymentDirection};
1290+
/// # use ldk_node::bitcoin::Network;
1291+
/// # let mut config = Config::default();
1292+
/// # config.network = Network::Regtest;
1293+
/// # config.storage_dir_path = "/tmp/ldk_node_test/".to_string();
1294+
/// # let builder = Builder::from_config(config);
1295+
/// # let node = builder.build();
1296+
/// node.list_payments_with_filter(|p| p.direction == PaymentDirection::Outbound);
1297+
/// ```
1298+
pub fn list_payments_with_filter<F: FnMut(&&PaymentDetails) -> bool>(
1299+
&self, f: F,
1300+
) -> Vec<PaymentDetails> {
1301+
self.payment_store.list_filter(f)
1302+
}
12771303
}
12781304

12791305
async fn connect_peer_if_necessary(

src/payment_store.rs

+17-10
Original file line numberDiff line numberDiff line change
@@ -84,12 +84,7 @@ where
8484
K::Target: KVStore,
8585
L::Target: Logger,
8686
{
87-
pub(crate) fn new(kv_store: K, logger: L) -> Self {
88-
let payments = Mutex::new(HashMap::new());
89-
Self { payments, kv_store, logger }
90-
}
91-
92-
pub(crate) fn from_payments(payments: Vec<PaymentDetails>, kv_store: K, logger: L) -> Self {
87+
pub(crate) fn new(payments: Vec<PaymentDetails>, kv_store: K, logger: L) -> Self {
9388
let payments = Mutex::new(HashMap::from_iter(
9489
payments.into_iter().map(|payment| (payment.hash, payment)),
9590
));
@@ -105,7 +100,7 @@ where
105100
Ok(updated)
106101
}
107102

108-
pub(crate) fn remove(&self, hash: &PaymentHash) -> Result<(), Error> {
103+
pub(crate) fn remove(&self, hash: &PaymentHash) -> Result<bool, Error> {
109104
let store_key = hex_utils::to_string(&hash.0);
110105
self.kv_store.remove(PAYMENT_INFO_PERSISTENCE_NAMESPACE, &store_key).map_err(|e| {
111106
log_error!(
@@ -116,8 +111,7 @@ where
116111
e
117112
);
118113
Error::PersistenceFailed
119-
})?;
120-
Ok(())
114+
})
121115
}
122116

123117
pub(crate) fn get(&self, hash: &PaymentHash) -> Option<PaymentDetails> {
@@ -160,6 +154,19 @@ where
160154
Ok(updated)
161155
}
162156

157+
pub(crate) fn list_filter<F: FnMut(&&PaymentDetails) -> bool>(
158+
&self, f: F,
159+
) -> Vec<PaymentDetails> {
160+
self.payments
161+
.lock()
162+
.unwrap()
163+
.iter()
164+
.map(|(_, p)| p)
165+
.filter(f)
166+
.cloned()
167+
.collect::<Vec<PaymentDetails>>()
168+
}
169+
163170
fn write_info_and_commit(
164171
&self, hash: &PaymentHash, payment: &PaymentDetails,
165172
) -> Result<(), Error> {
@@ -209,7 +216,7 @@ mod tests {
209216
fn persistence_guard_persists_on_drop() {
210217
let store = Arc::new(TestStore::new());
211218
let logger = Arc::new(TestLogger::new());
212-
let payment_store = PaymentStore::new(Arc::clone(&store), logger);
219+
let payment_store = PaymentStore::new(Vec::new(), Arc::clone(&store), logger);
213220

214221
let hash = PaymentHash([42u8; 32]);
215222
assert!(!payment_store.contains(&hash));

src/test/functional_tests.rs

+16
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,22 @@ fn channel_full_cycle() {
7878
println!("\nA send_payment");
7979
let payment_hash = node_a.send_payment(invoice.clone()).unwrap();
8080

81+
let outbound_payments_a =
82+
node_a.list_payments_with_filter(|p| p.direction == PaymentDirection::Outbound);
83+
assert_eq!(outbound_payments_a.len(), 1);
84+
85+
let inbound_payments_a =
86+
node_a.list_payments_with_filter(|p| p.direction == PaymentDirection::Inbound);
87+
assert_eq!(inbound_payments_a.len(), 0);
88+
89+
let outbound_payments_b =
90+
node_b.list_payments_with_filter(|p| p.direction == PaymentDirection::Outbound);
91+
assert_eq!(outbound_payments_b.len(), 0);
92+
93+
let inbound_payments_b =
94+
node_b.list_payments_with_filter(|p| p.direction == PaymentDirection::Inbound);
95+
assert_eq!(inbound_payments_b.len(), 1);
96+
8197
expect_event!(node_a, PaymentSuccessful);
8298
expect_event!(node_b, PaymentReceived);
8399
assert_eq!(node_a.payment(&payment_hash).unwrap().status, PaymentStatus::Succeeded);

0 commit comments

Comments
 (0)