use bitcoin::network::constants::Network;
use bitcoin::secp256k1::key::PublicKey;
use lightning::chain;
-use lightning::chain::keysinterface::KeysManager;
+use lightning::chain::keysinterface::{KeysInterface, KeysManager};
use lightning::ln::features::InvoiceFeatures;
use lightning::ln::msgs::NetAddress;
use lightning::ln::{PaymentHash, PaymentSecret};
use lightning::routing::network_graph::NetGraphMsgHandler;
use lightning::routing::router;
use lightning::routing::router::RouteHint;
+use lightning::routing::scorer::Scorer;
use lightning::util::config::{ChannelConfig, ChannelHandshakeLimits, UserConfig};
use lightning_invoice::{utils, Currency, Invoice};
use std::env;
let mut ldk_peer_port_set = true;
let ldk_peer_listening_port: u16 = match env::args().skip(3).next().map(|p| p.parse()) {
Some(Ok(p)) => p,
- Some(Err(e)) => panic!("{}", e),
+ Some(Err(_)) => {
+ ldk_peer_port_set = false;
+ 9735
+ }
None => {
ldk_peer_port_set = false;
9735
let network: Network = match env::args().skip(arg_idx).next().as_ref().map(String::as_str) {
Some("testnet") => Network::Testnet,
Some("regtest") => Network::Regtest,
- Some(_) => panic!("Unsupported network provided. Options are: `regtest`, `testnet`"),
+ Some(net) => {
+ panic!("Unsupported network provided. Options are: `regtest`, `testnet`. Got {}", net);
+ }
None => Network::Testnet,
};
let payee_pubkey = invoice.recover_payee_pub_key();
let final_cltv = invoice.min_final_cltv_expiry() as u32;
let payment_hash = PaymentHash(invoice.payment_hash().clone().into_inner());
- let payment_secret = invoice.payment_secret().cloned();
+ let payment_secret = Some(invoice.payment_secret().clone());
let invoice_features = invoice.features().cloned();
send_payment(
logger.clone(),
);
}
+ "keysend" => {
+ let dest_pubkey = match words.next() {
+ Some(dest) => match hex_utils::to_compressed_pubkey(dest) {
+ Some(pk) => pk,
+ None => {
+ println!("ERROR: couldn't parse destination pubkey");
+ print!("> ");
+ io::stdout().flush().unwrap();
+ continue;
+ }
+ },
+ None => {
+ println!("ERROR: keysend requires a destination pubkey: `keysend <dest_pubkey> <amt_msat>`");
+ print!("> ");
+ io::stdout().flush().unwrap();
+ continue;
+ }
+ };
+ let amt_msat_str = match words.next() {
+ Some(amt) => amt,
+ None => {
+ println!("ERROR: keysend requires an amount in millisatoshis: `keysend <dest_pubkey> <amt_msat>`");
+
+ print!("> ");
+ io::stdout().flush().unwrap();
+ continue;
+ }
+ };
+ let amt_msat: u64 = match amt_msat_str.parse() {
+ Ok(amt) => amt,
+ Err(e) => {
+ println!("ERROR: couldn't parse amount_msat: {}", e);
+ print!("> ");
+ io::stdout().flush().unwrap();
+ continue;
+ }
+ };
+ keysend(
+ dest_pubkey,
+ amt_msat,
+ router.clone(),
+ channel_manager.clone(),
+ outbound_payments.clone(),
+ logger.clone(),
+ );
+ }
"getinvoice" => {
let amt_str = words.next();
if amt_str.is_none() {
}
"nodeinfo" => node_info(channel_manager.clone(), peer_manager.clone()),
"listpeers" => list_peers(peer_manager.clone()),
+ "signmessage" => {
+ const MSG_STARTPOS: usize = "signmsg".len() + 1;
+ if line.as_bytes().len() <= MSG_STARTPOS {
+ println!("ERROR: signmsg requires a message");
+ print!("> ");
+ io::stdout().flush().unwrap();
+ continue;
+ }
+ println!(
+ "{:?}",
+ lightning::util::message_signing::sign(
+ &line.as_bytes()[MSG_STARTPOS..],
+ &keys_manager.get_node_secret()
+ )
+ );
+ print!("> ");
+ io::stdout().flush().unwrap();
+ }
_ => println!("Unknown command. See `\"help\" for available commands."),
}
}
println!("forceclosechannel <channel_id>");
println!("nodeinfo");
println!("listpeers");
+ println!("signmessage <message>");
}
fn node_info(channel_manager: Arc<ChannelManager>, peer_manager: Arc<PeerManager>) {
}
println!("\t\tis_confirmed_onchain: {},", chan_info.is_funding_locked);
println!("\t\tchannel_value_satoshis: {},", chan_info.channel_value_satoshis);
+ println!(
+ "\t\tlocal_balance_msat: {},",
+ chan_info.outbound_capacity_msat
+ + chan_info.unspendable_punishment_reserve.unwrap_or(0) * 1000
+ );
if chan_info.is_usable {
println!("\t\tavailable_balance_for_send_msat: {},", chan_info.outbound_capacity_msat);
println!("\t\tavailable_balance_for_recv_msat: {},", chan_info.inbound_capacity_msat);
channel_manager: Arc<ChannelManager>, payment_storage: PaymentInfoStorage,
logger: Arc<FilesystemLogger>,
) {
- let network_graph = router.network_graph.read().unwrap();
+ let network_graph = &router.network_graph;
let first_hops = channel_manager.list_usable_channels();
let payer_pubkey = channel_manager.get_our_node_id();
amt_msat,
final_cltv,
logger,
+ &Scorer::default(),
);
if let Err(e) = route {
println!("ERROR: failed to find route: {}", e.err);
}
let status = match channel_manager.send_payment(&route.unwrap(), payment_hash, &payment_secret)
{
- Ok(()) => {
+ Ok(_payment_id) => {
println!("EVENT: initiated sending {} msats to {}", amt_msat, payee);
HTLCStatus::Pending
}
);
}
+fn keysend(
+ payee: PublicKey, amt_msat: u64,
+ router: Arc<NetGraphMsgHandler<Arc<dyn chain::Access + Send + Sync>, Arc<FilesystemLogger>>>,
+ channel_manager: Arc<ChannelManager>, payment_storage: PaymentInfoStorage,
+ logger: Arc<FilesystemLogger>,
+) {
+ let network_graph = &router.network_graph;
+ let first_hops = channel_manager.list_usable_channels();
+ let payer_pubkey = channel_manager.get_our_node_id();
+
+ let route = match router::get_keysend_route(
+ &payer_pubkey,
+ &network_graph,
+ &payee,
+ Some(&first_hops.iter().collect::<Vec<_>>()),
+ &vec![],
+ amt_msat,
+ 40,
+ logger,
+ &Scorer::default(),
+ ) {
+ Ok(r) => r,
+ Err(e) => {
+ println!("ERROR: failed to find route: {}", e.err);
+ return;
+ }
+ };
+
+ let mut payments = payment_storage.lock().unwrap();
+ let payment_hash = channel_manager.send_spontaneous_payment(&route, None).unwrap().0;
+ payments.insert(
+ payment_hash,
+ PaymentInfo {
+ preimage: None,
+ secret: None,
+ status: HTLCStatus::Pending,
+ amt_msat: MillisatAmount(Some(amt_msat)),
+ },
+ );
+}
+
fn get_invoice(
amt_msat: u64, payment_storage: PaymentInfoStorage, channel_manager: Arc<ChannelManager>,
keys_manager: Arc<KeysManager>, network: Network,
payment_hash,
PaymentInfo {
preimage: None,
- secret: invoice.payment_secret().cloned(),
+ secret: Some(invoice.payment_secret().clone()),
status: HTLCStatus::Pending,
amt_msat: MillisatAmount(Some(amt_msat)),
},