1 use crate::disk::{self, INBOUND_PAYMENTS_FNAME, OUTBOUND_PAYMENTS_FNAME};
4 ChannelManager, HTLCStatus, MillisatAmount, NetworkGraph, OnionMessenger, PaymentInfo,
5 PaymentInfoStorage, PeerManager,
7 use bitcoin::hashes::sha256::Hash as Sha256;
8 use bitcoin::hashes::Hash;
9 use bitcoin::network::constants::Network;
10 use bitcoin::secp256k1::PublicKey;
11 use lightning::ln::channelmanager::{PaymentId, RecipientOnionFields, Retry};
12 use lightning::ln::msgs::NetAddress;
13 use lightning::ln::{PaymentHash, PaymentPreimage};
14 use lightning::onion_message::OnionMessagePath;
15 use lightning::onion_message::{CustomOnionMessageContents, Destination, OnionMessageContents};
16 use lightning::routing::gossip::NodeId;
17 use lightning::routing::router::{PaymentParameters, RouteParameters};
18 use lightning::sign::{EntropySource, KeysManager};
19 use lightning::util::config::{ChannelHandshakeConfig, ChannelHandshakeLimits, UserConfig};
20 use lightning::util::persist::KVStorePersister;
21 use lightning::util::ser::{Writeable, Writer};
22 use lightning_invoice::payment::pay_invoice;
23 use lightning_invoice::{utils, Bolt11Invoice, Currency};
24 use lightning_persister::FilesystemPersister;
28 use std::net::{SocketAddr, ToSocketAddrs};
30 use std::str::FromStr;
31 use std::sync::{Arc, Mutex};
32 use std::time::Duration;
34 pub(crate) struct LdkUserInfo {
35 pub(crate) bitcoind_rpc_username: String,
36 pub(crate) bitcoind_rpc_password: String,
37 pub(crate) bitcoind_rpc_port: u16,
38 pub(crate) bitcoind_rpc_host: String,
39 pub(crate) ldk_storage_dir_path: String,
40 pub(crate) ldk_peer_listening_port: u16,
41 pub(crate) ldk_announced_listen_addr: Vec<NetAddress>,
42 pub(crate) ldk_announced_node_name: [u8; 32],
43 pub(crate) network: Network,
46 struct UserOnionMessageContents {
51 impl CustomOnionMessageContents for UserOnionMessageContents {
52 fn tlv_type(&self) -> u64 {
57 impl Writeable for UserOnionMessageContents {
58 fn write<W: Writer>(&self, w: &mut W) -> Result<(), std::io::Error> {
59 w.write_all(&self.data)
63 pub(crate) async fn poll_for_user_input(
64 peer_manager: Arc<PeerManager>, channel_manager: Arc<ChannelManager>,
65 keys_manager: Arc<KeysManager>, network_graph: Arc<NetworkGraph>,
66 onion_messenger: Arc<OnionMessenger>, inbound_payments: Arc<Mutex<PaymentInfoStorage>>,
67 outbound_payments: Arc<Mutex<PaymentInfoStorage>>, ldk_data_dir: String, network: Network,
68 logger: Arc<disk::FilesystemLogger>, persister: Arc<FilesystemPersister>,
71 "LDK startup successful. Enter \"help\" to view available commands. Press Ctrl-D to quit."
73 println!("LDK logs are available at <your-supplied-ldk-data-dir-path>/.ldk/logs");
74 println!("Local Node ID is {}.", channel_manager.get_our_node_id());
77 io::stdout().flush().unwrap(); // Without flushing, the `>` doesn't print
78 let mut line = String::new();
79 if let Err(e) = io::stdin().read_line(&mut line) {
80 break println!("ERROR: {}", e);
84 // We hit EOF / Ctrl-D
88 let mut words = line.split_whitespace();
89 if let Some(word) = words.next() {
93 let peer_pubkey_and_ip_addr = words.next();
94 let channel_value_sat = words.next();
95 if peer_pubkey_and_ip_addr.is_none() || channel_value_sat.is_none() {
96 println!("ERROR: openchannel has 2 required arguments: `openchannel pubkey@host:port channel_amt_satoshis` [--public]");
99 let peer_pubkey_and_ip_addr = peer_pubkey_and_ip_addr.unwrap();
100 let (pubkey, peer_addr) =
101 match parse_peer_info(peer_pubkey_and_ip_addr.to_string()) {
104 println!("{:?}", e.into_inner().unwrap());
109 let chan_amt_sat: Result<u64, _> = channel_value_sat.unwrap().parse();
110 if chan_amt_sat.is_err() {
111 println!("ERROR: channel amount must be a number");
115 if connect_peer_if_necessary(pubkey, peer_addr, peer_manager.clone())
122 let announce_channel = match words.next() {
123 Some("--public") | Some("--public=true") => true,
124 Some("--public=false") => false,
126 println!("ERROR: invalid `--public` command format. Valid formats: `--public`, `--public=true` `--public=false`");
134 chan_amt_sat.unwrap(),
136 channel_manager.clone(),
140 let peer_data_path = format!("{}/channel_peer_data", ldk_data_dir.clone());
141 let _ = disk::persist_channel_peer(
142 Path::new(&peer_data_path),
143 peer_pubkey_and_ip_addr,
148 let invoice_str = words.next();
149 if invoice_str.is_none() {
150 println!("ERROR: sendpayment requires an invoice: `sendpayment <invoice>`");
154 let invoice = match Bolt11Invoice::from_str(invoice_str.unwrap()) {
157 println!("ERROR: invalid invoice: {:?}", e);
165 &mut outbound_payments.lock().unwrap(),
170 let dest_pubkey = match words.next() {
171 Some(dest) => match hex_utils::to_compressed_pubkey(dest) {
174 println!("ERROR: couldn't parse destination pubkey");
179 println!("ERROR: keysend requires a destination pubkey: `keysend <dest_pubkey> <amt_msat>`");
183 let amt_msat_str = match words.next() {
186 println!("ERROR: keysend requires an amount in millisatoshis: `keysend <dest_pubkey> <amt_msat>`");
190 let amt_msat: u64 = match amt_msat_str.parse() {
193 println!("ERROR: couldn't parse amount_msat: {}", e);
202 &mut outbound_payments.lock().unwrap(),
207 let amt_str = words.next();
208 if amt_str.is_none() {
209 println!("ERROR: getinvoice requires an amount in millisatoshis");
213 let amt_msat: Result<u64, _> = amt_str.unwrap().parse();
214 if amt_msat.is_err() {
215 println!("ERROR: getinvoice provided payment amount was not a number");
219 let expiry_secs_str = words.next();
220 if expiry_secs_str.is_none() {
221 println!("ERROR: getinvoice requires an expiry in seconds");
225 let expiry_secs: Result<u32, _> = expiry_secs_str.unwrap().parse();
226 if expiry_secs.is_err() {
227 println!("ERROR: getinvoice provided expiry was not a number");
231 let mut inbound_payments = inbound_payments.lock().unwrap();
234 &mut inbound_payments,
236 Arc::clone(&keys_manager),
238 expiry_secs.unwrap(),
241 persister.persist(INBOUND_PAYMENTS_FNAME, &*inbound_payments).unwrap();
244 let peer_pubkey_and_ip_addr = words.next();
245 if peer_pubkey_and_ip_addr.is_none() {
246 println!("ERROR: connectpeer requires peer connection info: `connectpeer pubkey@host:port`");
249 let (pubkey, peer_addr) =
250 match parse_peer_info(peer_pubkey_and_ip_addr.unwrap().to_string()) {
253 println!("{:?}", e.into_inner().unwrap());
257 if connect_peer_if_necessary(pubkey, peer_addr, peer_manager.clone())
261 println!("SUCCESS: connected to peer {}", pubkey);
264 "disconnectpeer" => {
265 let peer_pubkey = words.next();
266 if peer_pubkey.is_none() {
267 println!("ERROR: disconnectpeer requires peer public key: `disconnectpeer <peer_pubkey>`");
272 match bitcoin::secp256k1::PublicKey::from_str(peer_pubkey.unwrap()) {
273 Ok(pubkey) => pubkey,
275 println!("ERROR: {}", e.to_string());
280 if do_disconnect_peer(
282 peer_manager.clone(),
283 channel_manager.clone(),
287 println!("SUCCESS: disconnected from peer {}", peer_pubkey);
290 "listchannels" => list_channels(&channel_manager, &network_graph),
291 "listpayments" => list_payments(
292 &inbound_payments.lock().unwrap(),
293 &outbound_payments.lock().unwrap(),
296 let channel_id_str = words.next();
297 if channel_id_str.is_none() {
298 println!("ERROR: closechannel requires a channel ID: `closechannel <channel_id> <peer_pubkey>`");
301 let channel_id_vec = hex_utils::to_vec(channel_id_str.unwrap());
302 if channel_id_vec.is_none() || channel_id_vec.as_ref().unwrap().len() != 32 {
303 println!("ERROR: couldn't parse channel_id");
306 let mut channel_id = [0; 32];
307 channel_id.copy_from_slice(&channel_id_vec.unwrap());
309 let peer_pubkey_str = words.next();
310 if peer_pubkey_str.is_none() {
311 println!("ERROR: closechannel requires a peer pubkey: `closechannel <channel_id> <peer_pubkey>`");
314 let peer_pubkey_vec = match hex_utils::to_vec(peer_pubkey_str.unwrap()) {
315 Some(peer_pubkey_vec) => peer_pubkey_vec,
317 println!("ERROR: couldn't parse peer_pubkey");
321 let peer_pubkey = match PublicKey::from_slice(&peer_pubkey_vec) {
322 Ok(peer_pubkey) => peer_pubkey,
324 println!("ERROR: couldn't parse peer_pubkey");
329 close_channel(channel_id, peer_pubkey, channel_manager.clone());
331 "forceclosechannel" => {
332 let channel_id_str = words.next();
333 if channel_id_str.is_none() {
334 println!("ERROR: forceclosechannel requires a channel ID: `forceclosechannel <channel_id> <peer_pubkey>`");
337 let channel_id_vec = hex_utils::to_vec(channel_id_str.unwrap());
338 if channel_id_vec.is_none() || channel_id_vec.as_ref().unwrap().len() != 32 {
339 println!("ERROR: couldn't parse channel_id");
342 let mut channel_id = [0; 32];
343 channel_id.copy_from_slice(&channel_id_vec.unwrap());
345 let peer_pubkey_str = words.next();
346 if peer_pubkey_str.is_none() {
347 println!("ERROR: forceclosechannel requires a peer pubkey: `forceclosechannel <channel_id> <peer_pubkey>`");
350 let peer_pubkey_vec = match hex_utils::to_vec(peer_pubkey_str.unwrap()) {
351 Some(peer_pubkey_vec) => peer_pubkey_vec,
353 println!("ERROR: couldn't parse peer_pubkey");
357 let peer_pubkey = match PublicKey::from_slice(&peer_pubkey_vec) {
358 Ok(peer_pubkey) => peer_pubkey,
360 println!("ERROR: couldn't parse peer_pubkey");
365 force_close_channel(channel_id, peer_pubkey, channel_manager.clone());
367 "nodeinfo" => node_info(&channel_manager, &peer_manager),
368 "listpeers" => list_peers(peer_manager.clone()),
370 const MSG_STARTPOS: usize = "signmessage".len() + 1;
371 if line.as_bytes().len() <= MSG_STARTPOS {
372 println!("ERROR: signmsg requires a message");
377 lightning::util::message_signing::sign(
378 &line.as_bytes()[MSG_STARTPOS..],
379 &keys_manager.get_node_secret_key()
383 "sendonionmessage" => {
384 let path_pks_str = words.next();
385 if path_pks_str.is_none() {
387 "ERROR: sendonionmessage requires at least one node id for the path"
391 let mut intermediate_nodes = Vec::new();
392 let mut errored = false;
393 for pk_str in path_pks_str.unwrap().split(",") {
394 let node_pubkey_vec = match hex_utils::to_vec(pk_str) {
395 Some(peer_pubkey_vec) => peer_pubkey_vec,
397 println!("ERROR: couldn't parse peer_pubkey");
402 let node_pubkey = match PublicKey::from_slice(&node_pubkey_vec) {
403 Ok(peer_pubkey) => peer_pubkey,
405 println!("ERROR: couldn't parse peer_pubkey");
410 intermediate_nodes.push(node_pubkey);
415 let tlv_type = match words.next().map(|ty_str| ty_str.parse()) {
416 Some(Ok(ty)) if ty >= 64 => ty,
418 println!("Need an integral message type above 64");
422 let data = match words.next().map(|s| hex_utils::to_vec(s)) {
423 Some(Some(data)) => data,
425 println!("Need a hex data string");
429 let destination = Destination::Node(intermediate_nodes.pop().unwrap());
430 let message_path = OnionMessagePath { intermediate_nodes, destination };
431 match onion_messenger.send_onion_message(
433 OnionMessageContents::Custom(UserOnionMessageContents { tlv_type, data }),
436 Ok(()) => println!("SUCCESS: forwarded onion message to first hop"),
437 Err(e) => println!("ERROR: failed to send onion message: {:?}", e),
440 "quit" | "exit" => break,
441 _ => println!("Unknown command. See `\"help\" for available commands."),
448 let package_version = env!("CARGO_PKG_VERSION");
449 let package_name = env!("CARGO_PKG_NAME");
450 println!("\nVERSION:");
451 println!(" {} v{}", package_name, package_version);
452 println!("\nUSAGE:");
453 println!(" Command [arguments]");
454 println!("\nCOMMANDS:");
455 println!(" help\tShows a list of commands.");
456 println!(" quit\tClose the application.");
457 println!("\n Channels:");
458 println!(" openchannel pubkey@host:port <amt_satoshis> [--public]");
459 println!(" closechannel <channel_id> <peer_pubkey>");
460 println!(" forceclosechannel <channel_id> <peer_pubkey>");
461 println!(" listchannels");
462 println!("\n Peers:");
463 println!(" connectpeer pubkey@host:port");
464 println!(" disconnectpeer <peer_pubkey>");
465 println!(" listpeers");
466 println!("\n Payments:");
467 println!(" sendpayment <invoice>");
468 println!(" keysend <dest_pubkey> <amt_msats>");
469 println!(" listpayments");
470 println!("\n Invoices:");
471 println!(" getinvoice <amt_msats> <expiry_secs>");
472 println!("\n Other:");
473 println!(" signmessage <message>");
475 " sendonionmessage <node_id_1,node_id_2,..,destination_node_id> <type> <hex_bytes>"
477 println!(" nodeinfo");
480 fn node_info(channel_manager: &Arc<ChannelManager>, peer_manager: &Arc<PeerManager>) {
482 println!("\t\t node_pubkey: {}", channel_manager.get_our_node_id());
483 let chans = channel_manager.list_channels();
484 println!("\t\t num_channels: {}", chans.len());
485 println!("\t\t num_usable_channels: {}", chans.iter().filter(|c| c.is_usable).count());
486 let local_balance_msat = chans.iter().map(|c| c.balance_msat).sum::<u64>();
487 println!("\t\t local_balance_msat: {}", local_balance_msat);
488 println!("\t\t num_peers: {}", peer_manager.get_peer_node_ids().len());
492 fn list_peers(peer_manager: Arc<PeerManager>) {
494 for (pubkey, _) in peer_manager.get_peer_node_ids() {
495 println!("\t\t pubkey: {}", pubkey);
500 fn list_channels(channel_manager: &Arc<ChannelManager>, network_graph: &Arc<NetworkGraph>) {
502 for chan_info in channel_manager.list_channels() {
505 println!("\t\tchannel_id: {},", hex_utils::hex_str(&chan_info.channel_id[..]));
506 if let Some(funding_txo) = chan_info.funding_txo {
507 println!("\t\tfunding_txid: {},", funding_txo.txid);
511 "\t\tpeer_pubkey: {},",
512 hex_utils::hex_str(&chan_info.counterparty.node_id.serialize())
514 if let Some(node_info) = network_graph
517 .get(&NodeId::from_pubkey(&chan_info.counterparty.node_id))
519 if let Some(announcement) = &node_info.announcement_info {
520 println!("\t\tpeer_alias: {}", announcement.alias);
524 if let Some(id) = chan_info.short_channel_id {
525 println!("\t\tshort_channel_id: {},", id);
527 println!("\t\tis_channel_ready: {},", chan_info.is_channel_ready);
528 println!("\t\tchannel_value_satoshis: {},", chan_info.channel_value_satoshis);
529 println!("\t\tlocal_balance_msat: {},", chan_info.balance_msat);
530 if chan_info.is_usable {
531 println!("\t\tavailable_balance_for_send_msat: {},", chan_info.outbound_capacity_msat);
532 println!("\t\tavailable_balance_for_recv_msat: {},", chan_info.inbound_capacity_msat);
534 println!("\t\tchannel_can_send_payments: {},", chan_info.is_usable);
535 println!("\t\tpublic: {},", chan_info.is_public);
541 fn list_payments(inbound_payments: &PaymentInfoStorage, outbound_payments: &PaymentInfoStorage) {
543 for (payment_hash, payment_info) in &inbound_payments.payments {
546 println!("\t\tamount_millisatoshis: {},", payment_info.amt_msat);
547 println!("\t\tpayment_hash: {},", hex_utils::hex_str(&payment_hash.0));
548 println!("\t\thtlc_direction: inbound,");
550 "\t\thtlc_status: {},",
551 match payment_info.status {
552 HTLCStatus::Pending => "pending",
553 HTLCStatus::Succeeded => "succeeded",
554 HTLCStatus::Failed => "failed",
561 for (payment_hash, payment_info) in &outbound_payments.payments {
564 println!("\t\tamount_millisatoshis: {},", payment_info.amt_msat);
565 println!("\t\tpayment_hash: {},", hex_utils::hex_str(&payment_hash.0));
566 println!("\t\thtlc_direction: outbound,");
568 "\t\thtlc_status: {},",
569 match payment_info.status {
570 HTLCStatus::Pending => "pending",
571 HTLCStatus::Succeeded => "succeeded",
572 HTLCStatus::Failed => "failed",
581 pub(crate) async fn connect_peer_if_necessary(
582 pubkey: PublicKey, peer_addr: SocketAddr, peer_manager: Arc<PeerManager>,
583 ) -> Result<(), ()> {
584 for (node_pubkey, _) in peer_manager.get_peer_node_ids() {
585 if node_pubkey == pubkey {
589 let res = do_connect_peer(pubkey, peer_addr, peer_manager).await;
591 println!("ERROR: failed to connect to peer");
596 pub(crate) async fn do_connect_peer(
597 pubkey: PublicKey, peer_addr: SocketAddr, peer_manager: Arc<PeerManager>,
598 ) -> Result<(), ()> {
599 match lightning_net_tokio::connect_outbound(Arc::clone(&peer_manager), pubkey, peer_addr).await
601 Some(connection_closed_future) => {
602 let mut connection_closed_future = Box::pin(connection_closed_future);
605 _ = &mut connection_closed_future => return Err(()),
606 _ = tokio::time::sleep(Duration::from_millis(10)) => {},
608 if peer_manager.get_peer_node_ids().iter().find(|(id, _)| *id == pubkey).is_some() {
617 fn do_disconnect_peer(
618 pubkey: bitcoin::secp256k1::PublicKey, peer_manager: Arc<PeerManager>,
619 channel_manager: Arc<ChannelManager>,
620 ) -> Result<(), ()> {
621 //check for open channels with peer
622 for channel in channel_manager.list_channels() {
623 if channel.counterparty.node_id == pubkey {
624 println!("Error: Node has an active channel with this peer, close any channels first");
629 //check the pubkey matches a valid connected peer
630 let peers = peer_manager.get_peer_node_ids();
631 if !peers.iter().any(|(pk, _)| &pubkey == pk) {
632 println!("Error: Could not find peer {}", pubkey);
636 peer_manager.disconnect_by_node_id(pubkey);
641 peer_pubkey: PublicKey, channel_amt_sat: u64, announced_channel: bool,
642 channel_manager: Arc<ChannelManager>,
643 ) -> Result<(), ()> {
644 let config = UserConfig {
645 channel_handshake_limits: ChannelHandshakeLimits {
646 // lnd's max to_self_delay is 2016, so we want to be compatible.
647 their_to_self_delay: 2016,
650 channel_handshake_config: ChannelHandshakeConfig {
657 match channel_manager.create_channel(peer_pubkey, channel_amt_sat, 0, 0, Some(config)) {
659 println!("EVENT: initiated channel with peer {}. ", peer_pubkey);
663 println!("ERROR: failed to open channel: {:?}", e);
670 channel_manager: &ChannelManager, invoice: &Bolt11Invoice,
671 outbound_payments: &mut PaymentInfoStorage, persister: Arc<FilesystemPersister>,
673 let payment_hash = PaymentHash((*invoice.payment_hash()).into_inner());
674 let payment_secret = Some(*invoice.payment_secret());
675 outbound_payments.payments.insert(
679 secret: payment_secret,
680 status: HTLCStatus::Pending,
681 amt_msat: MillisatAmount(invoice.amount_milli_satoshis()),
684 persister.persist(OUTBOUND_PAYMENTS_FNAME, &*outbound_payments).unwrap();
685 match pay_invoice(invoice, Retry::Timeout(Duration::from_secs(10)), channel_manager) {
687 let payee_pubkey = invoice.recover_payee_pub_key();
688 let amt_msat = invoice.amount_milli_satoshis().unwrap();
689 println!("EVENT: initiated sending {} msats to {}", amt_msat, payee_pubkey);
693 println!("ERROR: failed to send payment: {:?}", e);
695 outbound_payments.payments.get_mut(&payment_hash).unwrap().status = HTLCStatus::Failed;
696 persister.persist(OUTBOUND_PAYMENTS_FNAME, &*outbound_payments).unwrap();
701 fn keysend<E: EntropySource>(
702 channel_manager: &ChannelManager, payee_pubkey: PublicKey, amt_msat: u64, entropy_source: &E,
703 outbound_payments: &mut PaymentInfoStorage, persister: Arc<FilesystemPersister>,
705 let payment_preimage = PaymentPreimage(entropy_source.get_secure_random_bytes());
706 let payment_hash = PaymentHash(Sha256::hash(&payment_preimage.0[..]).into_inner());
708 let route_params = RouteParameters {
709 payment_params: PaymentParameters::for_keysend(payee_pubkey, 40, false),
710 final_value_msat: amt_msat,
712 outbound_payments.payments.insert(
717 status: HTLCStatus::Pending,
718 amt_msat: MillisatAmount(Some(amt_msat)),
721 persister.persist(OUTBOUND_PAYMENTS_FNAME, &*outbound_payments).unwrap();
722 match channel_manager.send_spontaneous_payment_with_retry(
723 Some(payment_preimage),
724 RecipientOnionFields::spontaneous_empty(),
725 PaymentId(payment_hash.0),
727 Retry::Timeout(Duration::from_secs(10)),
729 Ok(_payment_hash) => {
730 println!("EVENT: initiated sending {} msats to {}", amt_msat, payee_pubkey);
734 println!("ERROR: failed to send payment: {:?}", e);
736 outbound_payments.payments.get_mut(&payment_hash).unwrap().status = HTLCStatus::Failed;
737 persister.persist(OUTBOUND_PAYMENTS_FNAME, &*outbound_payments).unwrap();
743 amt_msat: u64, inbound_payments: &mut PaymentInfoStorage, channel_manager: &ChannelManager,
744 keys_manager: Arc<KeysManager>, network: Network, expiry_secs: u32,
745 logger: Arc<disk::FilesystemLogger>,
747 let currency = match network {
748 Network::Bitcoin => Currency::Bitcoin,
749 Network::Testnet => Currency::BitcoinTestnet,
750 Network::Regtest => Currency::Regtest,
751 Network::Signet => Currency::Signet,
753 let invoice = match utils::create_invoice_from_channelmanager(
759 "ldk-tutorial-node".to_string(),
764 println!("SUCCESS: generated invoice: {}", inv);
768 println!("ERROR: failed to create invoice: {:?}", e);
773 let payment_hash = PaymentHash(invoice.payment_hash().clone().into_inner());
774 inbound_payments.payments.insert(
778 secret: Some(invoice.payment_secret().clone()),
779 status: HTLCStatus::Pending,
780 amt_msat: MillisatAmount(Some(amt_msat)),
786 channel_id: [u8; 32], counterparty_node_id: PublicKey, channel_manager: Arc<ChannelManager>,
788 match channel_manager.close_channel(&channel_id, &counterparty_node_id) {
789 Ok(()) => println!("EVENT: initiating channel close"),
790 Err(e) => println!("ERROR: failed to close channel: {:?}", e),
794 fn force_close_channel(
795 channel_id: [u8; 32], counterparty_node_id: PublicKey, channel_manager: Arc<ChannelManager>,
797 match channel_manager.force_close_broadcasting_latest_txn(&channel_id, &counterparty_node_id) {
798 Ok(()) => println!("EVENT: initiating channel force-close"),
799 Err(e) => println!("ERROR: failed to force-close channel: {:?}", e),
803 pub(crate) fn parse_peer_info(
804 peer_pubkey_and_ip_addr: String,
805 ) -> Result<(PublicKey, SocketAddr), std::io::Error> {
806 let mut pubkey_and_addr = peer_pubkey_and_ip_addr.split("@");
807 let pubkey = pubkey_and_addr.next();
808 let peer_addr_str = pubkey_and_addr.next();
809 if peer_addr_str.is_none() {
810 return Err(std::io::Error::new(
811 std::io::ErrorKind::Other,
812 "ERROR: incorrectly formatted peer info. Should be formatted as: `pubkey@host:port`",
816 let peer_addr = peer_addr_str.unwrap().to_socket_addrs().map(|mut r| r.next());
817 if peer_addr.is_err() || peer_addr.as_ref().unwrap().is_none() {
818 return Err(std::io::Error::new(
819 std::io::ErrorKind::Other,
820 "ERROR: couldn't parse pubkey@host:port into a socket address",
824 let pubkey = hex_utils::to_compressed_pubkey(pubkey.unwrap());
825 if pubkey.is_none() {
826 return Err(std::io::Error::new(
827 std::io::ErrorKind::Other,
828 "ERROR: unable to parse given pubkey for node",
832 Ok((pubkey.unwrap(), peer_addr.unwrap().unwrap()))