Skip to content

Commit 139e065

Browse files
authored
Merge pull request #104 from zoedberg/persist_payments
persist payments info to disk
2 parents 6621d79 + bd7121e commit 139e065

File tree

3 files changed

+163
-80
lines changed

3 files changed

+163
-80
lines changed

src/cli.rs

Lines changed: 64 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::disk;
1+
use crate::disk::{self, INBOUND_PAYMENTS_FNAME, OUTBOUND_PAYMENTS_FNAME};
22
use crate::hex_utils;
33
use crate::{
44
ChannelManager, HTLCStatus, MillisatAmount, NetworkGraph, OnionMessenger, PaymentInfo,
@@ -16,17 +16,18 @@ use lightning::onion_message::{CustomOnionMessageContents, Destination, OnionMes
1616
use lightning::routing::gossip::NodeId;
1717
use lightning::routing::router::{PaymentParameters, RouteParameters};
1818
use lightning::util::config::{ChannelHandshakeConfig, ChannelHandshakeLimits, UserConfig};
19+
use lightning::util::persist::KVStorePersister;
1920
use lightning::util::ser::{Writeable, Writer};
2021
use lightning_invoice::payment::pay_invoice;
2122
use lightning_invoice::{utils, Currency, Invoice};
23+
use lightning_persister::FilesystemPersister;
2224
use std::env;
2325
use std::io;
2426
use std::io::Write;
2527
use std::net::{SocketAddr, ToSocketAddrs};
26-
use std::ops::Deref;
2728
use std::path::Path;
2829
use std::str::FromStr;
29-
use std::sync::Arc;
30+
use std::sync::{Arc, Mutex};
3031
use std::time::Duration;
3132

3233
pub(crate) struct LdkUserInfo {
@@ -61,9 +62,9 @@ impl Writeable for UserOnionMessageContents {
6162
pub(crate) async fn poll_for_user_input(
6263
peer_manager: Arc<PeerManager>, channel_manager: Arc<ChannelManager>,
6364
keys_manager: Arc<KeysManager>, network_graph: Arc<NetworkGraph>,
64-
onion_messenger: Arc<OnionMessenger>, inbound_payments: PaymentInfoStorage,
65-
outbound_payments: PaymentInfoStorage, ldk_data_dir: String, network: Network,
66-
logger: Arc<disk::FilesystemLogger>,
65+
onion_messenger: Arc<OnionMessenger>, inbound_payments: Arc<Mutex<PaymentInfoStorage>>,
66+
outbound_payments: Arc<Mutex<PaymentInfoStorage>>, ldk_data_dir: String, network: Network,
67+
logger: Arc<disk::FilesystemLogger>, persister: Arc<FilesystemPersister>,
6768
) {
6869
println!(
6970
"LDK startup successful. Enter \"help\" to view available commands. Press Ctrl-D to quit."
@@ -157,7 +158,12 @@ pub(crate) async fn poll_for_user_input(
157158
}
158159
};
159160

160-
send_payment(&*channel_manager, &invoice, outbound_payments.clone());
161+
send_payment(
162+
&channel_manager,
163+
&invoice,
164+
&mut outbound_payments.lock().unwrap(),
165+
persister.clone(),
166+
);
161167
}
162168
"keysend" => {
163169
let dest_pubkey = match words.next() {
@@ -188,11 +194,12 @@ pub(crate) async fn poll_for_user_input(
188194
}
189195
};
190196
keysend(
191-
&*channel_manager,
197+
&channel_manager,
192198
dest_pubkey,
193199
amt_msat,
194200
&*keys_manager,
195-
outbound_payments.clone(),
201+
&mut outbound_payments.lock().unwrap(),
202+
persister.clone(),
196203
);
197204
}
198205
"getinvoice" => {
@@ -220,15 +227,17 @@ pub(crate) async fn poll_for_user_input(
220227
continue;
221228
}
222229

230+
let mut inbound_payments = inbound_payments.lock().unwrap();
223231
get_invoice(
224232
amt_msat.unwrap(),
225-
Arc::clone(&inbound_payments),
226-
&*channel_manager,
233+
&mut inbound_payments,
234+
&channel_manager,
227235
Arc::clone(&keys_manager),
228236
network,
229237
expiry_secs.unwrap(),
230238
Arc::clone(&logger),
231239
);
240+
persister.persist(INBOUND_PAYMENTS_FNAME, &*inbound_payments).unwrap();
232241
}
233242
"connectpeer" => {
234243
let peer_pubkey_and_ip_addr = words.next();
@@ -278,9 +287,10 @@ pub(crate) async fn poll_for_user_input(
278287
}
279288
}
280289
"listchannels" => list_channels(&channel_manager, &network_graph),
281-
"listpayments" => {
282-
list_payments(inbound_payments.clone(), outbound_payments.clone())
283-
}
290+
"listpayments" => list_payments(
291+
&inbound_payments.lock().unwrap(),
292+
&outbound_payments.lock().unwrap(),
293+
),
284294
"closechannel" => {
285295
let channel_id_str = words.next();
286296
if channel_id_str.is_none() {
@@ -527,11 +537,9 @@ fn list_channels(channel_manager: &Arc<ChannelManager>, network_graph: &Arc<Netw
527537
println!("]");
528538
}
529539

530-
fn list_payments(inbound_payments: PaymentInfoStorage, outbound_payments: PaymentInfoStorage) {
531-
let inbound = inbound_payments.lock().unwrap();
532-
let outbound = outbound_payments.lock().unwrap();
540+
fn list_payments(inbound_payments: &PaymentInfoStorage, outbound_payments: &PaymentInfoStorage) {
533541
print!("[");
534-
for (payment_hash, payment_info) in inbound.deref() {
542+
for (payment_hash, payment_info) in &inbound_payments.payments {
535543
println!("");
536544
println!("\t{{");
537545
println!("\t\tamount_millisatoshis: {},", payment_info.amt_msat);
@@ -549,7 +557,7 @@ fn list_payments(inbound_payments: PaymentInfoStorage, outbound_payments: Paymen
549557
println!("\t}},");
550558
}
551559

552-
for (payment_hash, payment_info) in outbound.deref() {
560+
for (payment_hash, payment_info) in &outbound_payments.payments {
553561
println!("");
554562
println!("\t{{");
555563
println!("\t\tamount_millisatoshis: {},", payment_info.amt_msat);
@@ -658,41 +666,40 @@ fn open_channel(
658666
}
659667

660668
fn send_payment(
661-
channel_manager: &ChannelManager, invoice: &Invoice, payment_storage: PaymentInfoStorage,
669+
channel_manager: &ChannelManager, invoice: &Invoice,
670+
outbound_payments: &mut PaymentInfoStorage, persister: Arc<FilesystemPersister>,
662671
) {
663-
let status =
664-
match pay_invoice(invoice, Retry::Timeout(Duration::from_secs(10)), channel_manager) {
665-
Ok(_payment_id) => {
666-
let payee_pubkey = invoice.recover_payee_pub_key();
667-
let amt_msat = invoice.amount_milli_satoshis().unwrap();
668-
println!("EVENT: initiated sending {} msats to {}", amt_msat, payee_pubkey);
669-
print!("> ");
670-
HTLCStatus::Pending
671-
}
672-
Err(e) => {
673-
println!("ERROR: failed to send payment: {:?}", e);
674-
print!("> ");
675-
HTLCStatus::Failed
676-
}
677-
};
678-
let payment_hash = PaymentHash(invoice.payment_hash().clone().into_inner());
679-
let payment_secret = Some(invoice.payment_secret().clone());
680-
681-
let mut payments = payment_storage.lock().unwrap();
682-
payments.insert(
672+
let payment_hash = PaymentHash((*invoice.payment_hash()).into_inner());
673+
let payment_secret = Some(*invoice.payment_secret());
674+
outbound_payments.payments.insert(
683675
payment_hash,
684676
PaymentInfo {
685677
preimage: None,
686678
secret: payment_secret,
687-
status,
679+
status: HTLCStatus::Pending,
688680
amt_msat: MillisatAmount(invoice.amount_milli_satoshis()),
689681
},
690682
);
683+
persister.persist(OUTBOUND_PAYMENTS_FNAME, &*outbound_payments).unwrap();
684+
match pay_invoice(invoice, Retry::Timeout(Duration::from_secs(10)), channel_manager) {
685+
Ok(_payment_id) => {
686+
let payee_pubkey = invoice.recover_payee_pub_key();
687+
let amt_msat = invoice.amount_milli_satoshis().unwrap();
688+
println!("EVENT: initiated sending {} msats to {}", amt_msat, payee_pubkey);
689+
print!("> ");
690+
}
691+
Err(e) => {
692+
println!("ERROR: failed to send payment: {:?}", e);
693+
print!("> ");
694+
outbound_payments.payments.get_mut(&payment_hash).unwrap().status = HTLCStatus::Failed;
695+
persister.persist(OUTBOUND_PAYMENTS_FNAME, &*outbound_payments).unwrap();
696+
}
697+
};
691698
}
692699

693700
fn keysend<E: EntropySource>(
694701
channel_manager: &ChannelManager, payee_pubkey: PublicKey, amt_msat: u64, entropy_source: &E,
695-
payment_storage: PaymentInfoStorage,
702+
outbound_payments: &mut PaymentInfoStorage, persister: Arc<FilesystemPersister>,
696703
) {
697704
let payment_preimage = PaymentPreimage(entropy_source.get_secure_random_bytes());
698705
let payment_hash = PaymentHash(Sha256::hash(&payment_preimage.0[..]).into_inner());
@@ -701,7 +708,17 @@ fn keysend<E: EntropySource>(
701708
payment_params: PaymentParameters::for_keysend(payee_pubkey, 40),
702709
final_value_msat: amt_msat,
703710
};
704-
let status = match channel_manager.send_spontaneous_payment_with_retry(
711+
outbound_payments.payments.insert(
712+
payment_hash,
713+
PaymentInfo {
714+
preimage: None,
715+
secret: None,
716+
status: HTLCStatus::Pending,
717+
amt_msat: MillisatAmount(Some(amt_msat)),
718+
},
719+
);
720+
persister.persist(OUTBOUND_PAYMENTS_FNAME, &*outbound_payments).unwrap();
721+
match channel_manager.send_spontaneous_payment_with_retry(
705722
Some(payment_preimage),
706723
RecipientOnionFields::spontaneous_empty(),
707724
PaymentId(payment_hash.0),
@@ -711,33 +728,21 @@ fn keysend<E: EntropySource>(
711728
Ok(_payment_hash) => {
712729
println!("EVENT: initiated sending {} msats to {}", amt_msat, payee_pubkey);
713730
print!("> ");
714-
HTLCStatus::Pending
715731
}
716732
Err(e) => {
717733
println!("ERROR: failed to send payment: {:?}", e);
718734
print!("> ");
719-
HTLCStatus::Failed
735+
outbound_payments.payments.get_mut(&payment_hash).unwrap().status = HTLCStatus::Failed;
736+
persister.persist(OUTBOUND_PAYMENTS_FNAME, &*outbound_payments).unwrap();
720737
}
721738
};
722-
723-
let mut payments = payment_storage.lock().unwrap();
724-
payments.insert(
725-
payment_hash,
726-
PaymentInfo {
727-
preimage: None,
728-
secret: None,
729-
status,
730-
amt_msat: MillisatAmount(Some(amt_msat)),
731-
},
732-
);
733739
}
734740

735741
fn get_invoice(
736-
amt_msat: u64, payment_storage: PaymentInfoStorage, channel_manager: &ChannelManager,
742+
amt_msat: u64, inbound_payments: &mut PaymentInfoStorage, channel_manager: &ChannelManager,
737743
keys_manager: Arc<KeysManager>, network: Network, expiry_secs: u32,
738744
logger: Arc<disk::FilesystemLogger>,
739745
) {
740-
let mut payments = payment_storage.lock().unwrap();
741746
let currency = match network {
742747
Network::Bitcoin => Currency::Bitcoin,
743748
Network::Testnet => Currency::BitcoinTestnet,
@@ -765,7 +770,7 @@ fn get_invoice(
765770
};
766771

767772
let payment_hash = PaymentHash(invoice.payment_hash().clone().into_inner());
768-
payments.insert(
773+
inbound_payments.payments.insert(
769774
payment_hash,
770775
PaymentInfo {
771776
preimage: None,

src/disk.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
use crate::{cli, NetworkGraph};
1+
use crate::{cli, NetworkGraph, PaymentInfoStorage};
22
use bitcoin::secp256k1::PublicKey;
33
use bitcoin::Network;
44
use chrono::Utc;
55
use lightning::routing::scoring::{ProbabilisticScorer, ProbabilisticScoringParameters};
66
use lightning::util::logger::{Logger, Record};
7-
use lightning::util::ser::{ReadableArgs, Writer};
7+
use lightning::util::ser::{Readable, ReadableArgs, Writer};
88
use std::collections::HashMap;
99
use std::fs;
1010
use std::fs::File;
@@ -13,6 +13,9 @@ use std::net::SocketAddr;
1313
use std::path::Path;
1414
use std::sync::Arc;
1515

16+
pub(crate) const INBOUND_PAYMENTS_FNAME: &str = "inbound_payments";
17+
pub(crate) const OUTBOUND_PAYMENTS_FNAME: &str = "outbound_payments";
18+
1619
pub(crate) struct FilesystemLogger {
1720
data_dir: String,
1821
}
@@ -83,6 +86,15 @@ pub(crate) fn read_network(
8386
NetworkGraph::new(network, logger)
8487
}
8588

89+
pub(crate) fn read_payment_info(path: &Path) -> PaymentInfoStorage {
90+
if let Ok(file) = File::open(path) {
91+
if let Ok(info) = PaymentInfoStorage::read(&mut BufReader::new(file)) {
92+
return info;
93+
}
94+
}
95+
PaymentInfoStorage { payments: HashMap::new() }
96+
}
97+
8698
pub(crate) fn read_scorer(
8799
path: &Path, graph: Arc<NetworkGraph>, logger: Arc<FilesystemLogger>,
88100
) -> ProbabilisticScorer<Arc<NetworkGraph>, Arc<FilesystemLogger>> {

0 commit comments

Comments
 (0)