Skip to content

Commit

Permalink
Merge pull request #104 from zoedberg/persist_payments
Browse files Browse the repository at this point in the history
persist payments info to disk
  • Loading branch information
TheBlueMatt authored Jul 25, 2023
2 parents 6621d79 + bd7121e commit 139e065
Show file tree
Hide file tree
Showing 3 changed files with 163 additions and 80 deletions.
123 changes: 64 additions & 59 deletions src/cli.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::disk;
use crate::disk::{self, INBOUND_PAYMENTS_FNAME, OUTBOUND_PAYMENTS_FNAME};
use crate::hex_utils;
use crate::{
ChannelManager, HTLCStatus, MillisatAmount, NetworkGraph, OnionMessenger, PaymentInfo,
Expand All @@ -16,17 +16,18 @@ use lightning::onion_message::{CustomOnionMessageContents, Destination, OnionMes
use lightning::routing::gossip::NodeId;
use lightning::routing::router::{PaymentParameters, RouteParameters};
use lightning::util::config::{ChannelHandshakeConfig, ChannelHandshakeLimits, UserConfig};
use lightning::util::persist::KVStorePersister;
use lightning::util::ser::{Writeable, Writer};
use lightning_invoice::payment::pay_invoice;
use lightning_invoice::{utils, Currency, Invoice};
use lightning_persister::FilesystemPersister;
use std::env;
use std::io;
use std::io::Write;
use std::net::{SocketAddr, ToSocketAddrs};
use std::ops::Deref;
use std::path::Path;
use std::str::FromStr;
use std::sync::Arc;
use std::sync::{Arc, Mutex};
use std::time::Duration;

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

send_payment(&*channel_manager, &invoice, outbound_payments.clone());
send_payment(
&channel_manager,
&invoice,
&mut outbound_payments.lock().unwrap(),
persister.clone(),
);
}
"keysend" => {
let dest_pubkey = match words.next() {
Expand Down Expand Up @@ -188,11 +194,12 @@ pub(crate) async fn poll_for_user_input(
}
};
keysend(
&*channel_manager,
&channel_manager,
dest_pubkey,
amt_msat,
&*keys_manager,
outbound_payments.clone(),
&mut outbound_payments.lock().unwrap(),
persister.clone(),
);
}
"getinvoice" => {
Expand Down Expand Up @@ -220,15 +227,17 @@ pub(crate) async fn poll_for_user_input(
continue;
}

let mut inbound_payments = inbound_payments.lock().unwrap();
get_invoice(
amt_msat.unwrap(),
Arc::clone(&inbound_payments),
&*channel_manager,
&mut inbound_payments,
&channel_manager,
Arc::clone(&keys_manager),
network,
expiry_secs.unwrap(),
Arc::clone(&logger),
);
persister.persist(INBOUND_PAYMENTS_FNAME, &*inbound_payments).unwrap();
}
"connectpeer" => {
let peer_pubkey_and_ip_addr = words.next();
Expand Down Expand Up @@ -278,9 +287,10 @@ pub(crate) async fn poll_for_user_input(
}
}
"listchannels" => list_channels(&channel_manager, &network_graph),
"listpayments" => {
list_payments(inbound_payments.clone(), outbound_payments.clone())
}
"listpayments" => list_payments(
&inbound_payments.lock().unwrap(),
&outbound_payments.lock().unwrap(),
),
"closechannel" => {
let channel_id_str = words.next();
if channel_id_str.is_none() {
Expand Down Expand Up @@ -527,11 +537,9 @@ fn list_channels(channel_manager: &Arc<ChannelManager>, network_graph: &Arc<Netw
println!("]");
}

fn list_payments(inbound_payments: PaymentInfoStorage, outbound_payments: PaymentInfoStorage) {
let inbound = inbound_payments.lock().unwrap();
let outbound = outbound_payments.lock().unwrap();
fn list_payments(inbound_payments: &PaymentInfoStorage, outbound_payments: &PaymentInfoStorage) {
print!("[");
for (payment_hash, payment_info) in inbound.deref() {
for (payment_hash, payment_info) in &inbound_payments.payments {
println!("");
println!("\t{{");
println!("\t\tamount_millisatoshis: {},", payment_info.amt_msat);
Expand All @@ -549,7 +557,7 @@ fn list_payments(inbound_payments: PaymentInfoStorage, outbound_payments: Paymen
println!("\t}},");
}

for (payment_hash, payment_info) in outbound.deref() {
for (payment_hash, payment_info) in &outbound_payments.payments {
println!("");
println!("\t{{");
println!("\t\tamount_millisatoshis: {},", payment_info.amt_msat);
Expand Down Expand Up @@ -658,41 +666,40 @@ fn open_channel(
}

fn send_payment(
channel_manager: &ChannelManager, invoice: &Invoice, payment_storage: PaymentInfoStorage,
channel_manager: &ChannelManager, invoice: &Invoice,
outbound_payments: &mut PaymentInfoStorage, persister: Arc<FilesystemPersister>,
) {
let status =
match pay_invoice(invoice, Retry::Timeout(Duration::from_secs(10)), channel_manager) {
Ok(_payment_id) => {
let payee_pubkey = invoice.recover_payee_pub_key();
let amt_msat = invoice.amount_milli_satoshis().unwrap();
println!("EVENT: initiated sending {} msats to {}", amt_msat, payee_pubkey);
print!("> ");
HTLCStatus::Pending
}
Err(e) => {
println!("ERROR: failed to send payment: {:?}", e);
print!("> ");
HTLCStatus::Failed
}
};
let payment_hash = PaymentHash(invoice.payment_hash().clone().into_inner());
let payment_secret = Some(invoice.payment_secret().clone());

let mut payments = payment_storage.lock().unwrap();
payments.insert(
let payment_hash = PaymentHash((*invoice.payment_hash()).into_inner());
let payment_secret = Some(*invoice.payment_secret());
outbound_payments.payments.insert(
payment_hash,
PaymentInfo {
preimage: None,
secret: payment_secret,
status,
status: HTLCStatus::Pending,
amt_msat: MillisatAmount(invoice.amount_milli_satoshis()),
},
);
persister.persist(OUTBOUND_PAYMENTS_FNAME, &*outbound_payments).unwrap();
match pay_invoice(invoice, Retry::Timeout(Duration::from_secs(10)), channel_manager) {
Ok(_payment_id) => {
let payee_pubkey = invoice.recover_payee_pub_key();
let amt_msat = invoice.amount_milli_satoshis().unwrap();
println!("EVENT: initiated sending {} msats to {}", amt_msat, payee_pubkey);
print!("> ");
}
Err(e) => {
println!("ERROR: failed to send payment: {:?}", e);
print!("> ");
outbound_payments.payments.get_mut(&payment_hash).unwrap().status = HTLCStatus::Failed;
persister.persist(OUTBOUND_PAYMENTS_FNAME, &*outbound_payments).unwrap();
}
};
}

fn keysend<E: EntropySource>(
channel_manager: &ChannelManager, payee_pubkey: PublicKey, amt_msat: u64, entropy_source: &E,
payment_storage: PaymentInfoStorage,
outbound_payments: &mut PaymentInfoStorage, persister: Arc<FilesystemPersister>,
) {
let payment_preimage = PaymentPreimage(entropy_source.get_secure_random_bytes());
let payment_hash = PaymentHash(Sha256::hash(&payment_preimage.0[..]).into_inner());
Expand All @@ -701,7 +708,17 @@ fn keysend<E: EntropySource>(
payment_params: PaymentParameters::for_keysend(payee_pubkey, 40),
final_value_msat: amt_msat,
};
let status = match channel_manager.send_spontaneous_payment_with_retry(
outbound_payments.payments.insert(
payment_hash,
PaymentInfo {
preimage: None,
secret: None,
status: HTLCStatus::Pending,
amt_msat: MillisatAmount(Some(amt_msat)),
},
);
persister.persist(OUTBOUND_PAYMENTS_FNAME, &*outbound_payments).unwrap();
match channel_manager.send_spontaneous_payment_with_retry(
Some(payment_preimage),
RecipientOnionFields::spontaneous_empty(),
PaymentId(payment_hash.0),
Expand All @@ -711,33 +728,21 @@ fn keysend<E: EntropySource>(
Ok(_payment_hash) => {
println!("EVENT: initiated sending {} msats to {}", amt_msat, payee_pubkey);
print!("> ");
HTLCStatus::Pending
}
Err(e) => {
println!("ERROR: failed to send payment: {:?}", e);
print!("> ");
HTLCStatus::Failed
outbound_payments.payments.get_mut(&payment_hash).unwrap().status = HTLCStatus::Failed;
persister.persist(OUTBOUND_PAYMENTS_FNAME, &*outbound_payments).unwrap();
}
};

let mut payments = payment_storage.lock().unwrap();
payments.insert(
payment_hash,
PaymentInfo {
preimage: None,
secret: None,
status,
amt_msat: MillisatAmount(Some(amt_msat)),
},
);
}

fn get_invoice(
amt_msat: u64, payment_storage: PaymentInfoStorage, channel_manager: &ChannelManager,
amt_msat: u64, inbound_payments: &mut PaymentInfoStorage, channel_manager: &ChannelManager,
keys_manager: Arc<KeysManager>, network: Network, expiry_secs: u32,
logger: Arc<disk::FilesystemLogger>,
) {
let mut payments = payment_storage.lock().unwrap();
let currency = match network {
Network::Bitcoin => Currency::Bitcoin,
Network::Testnet => Currency::BitcoinTestnet,
Expand Down Expand Up @@ -765,7 +770,7 @@ fn get_invoice(
};

let payment_hash = PaymentHash(invoice.payment_hash().clone().into_inner());
payments.insert(
inbound_payments.payments.insert(
payment_hash,
PaymentInfo {
preimage: None,
Expand Down
16 changes: 14 additions & 2 deletions src/disk.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use crate::{cli, NetworkGraph};
use crate::{cli, NetworkGraph, PaymentInfoStorage};
use bitcoin::secp256k1::PublicKey;
use bitcoin::Network;
use chrono::Utc;
use lightning::routing::scoring::{ProbabilisticScorer, ProbabilisticScoringParameters};
use lightning::util::logger::{Logger, Record};
use lightning::util::ser::{ReadableArgs, Writer};
use lightning::util::ser::{Readable, ReadableArgs, Writer};
use std::collections::HashMap;
use std::fs;
use std::fs::File;
Expand All @@ -13,6 +13,9 @@ use std::net::SocketAddr;
use std::path::Path;
use std::sync::Arc;

pub(crate) const INBOUND_PAYMENTS_FNAME: &str = "inbound_payments";
pub(crate) const OUTBOUND_PAYMENTS_FNAME: &str = "outbound_payments";

pub(crate) struct FilesystemLogger {
data_dir: String,
}
Expand Down Expand Up @@ -83,6 +86,15 @@ pub(crate) fn read_network(
NetworkGraph::new(network, logger)
}

pub(crate) fn read_payment_info(path: &Path) -> PaymentInfoStorage {
if let Ok(file) = File::open(path) {
if let Ok(info) = PaymentInfoStorage::read(&mut BufReader::new(file)) {
return info;
}
}
PaymentInfoStorage { payments: HashMap::new() }
}

pub(crate) fn read_scorer(
path: &Path, graph: Arc<NetworkGraph>, logger: Arc<FilesystemLogger>,
) -> ProbabilisticScorer<Arc<NetworkGraph>, Arc<FilesystemLogger>> {
Expand Down
Loading

0 comments on commit 139e065

Please sign in to comment.