persist payments info to disk
[ldk-sample] / src / cli.rs
1 use crate::disk::{self, INBOUND_PAYMENTS_FNAME, OUTBOUND_PAYMENTS_FNAME};
2 use crate::hex_utils;
3 use crate::{
4         ChannelManager, HTLCStatus, MillisatAmount, NetworkGraph, OnionMessenger, PaymentInfo,
5         PaymentInfoStorage, PeerManager,
6 };
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::chain::keysinterface::{EntropySource, KeysManager};
12 use lightning::ln::channelmanager::{PaymentId, RecipientOnionFields, Retry};
13 use lightning::ln::msgs::NetAddress;
14 use lightning::ln::{PaymentHash, PaymentPreimage};
15 use lightning::onion_message::{CustomOnionMessageContents, Destination, OnionMessageContents};
16 use lightning::routing::gossip::NodeId;
17 use lightning::routing::router::{PaymentParameters, RouteParameters};
18 use lightning::util::config::{ChannelHandshakeConfig, ChannelHandshakeLimits, UserConfig};
19 use lightning::util::persist::KVStorePersister;
20 use lightning::util::ser::{Writeable, Writer};
21 use lightning_invoice::payment::pay_invoice;
22 use lightning_invoice::{utils, Currency, Invoice};
23 use lightning_persister::FilesystemPersister;
24 use std::env;
25 use std::io;
26 use std::io::Write;
27 use std::net::{SocketAddr, ToSocketAddrs};
28 use std::path::Path;
29 use std::str::FromStr;
30 use std::sync::{Arc, Mutex};
31 use std::time::Duration;
32
33 pub(crate) struct LdkUserInfo {
34         pub(crate) bitcoind_rpc_username: String,
35         pub(crate) bitcoind_rpc_password: String,
36         pub(crate) bitcoind_rpc_port: u16,
37         pub(crate) bitcoind_rpc_host: String,
38         pub(crate) ldk_storage_dir_path: String,
39         pub(crate) ldk_peer_listening_port: u16,
40         pub(crate) ldk_announced_listen_addr: Vec<NetAddress>,
41         pub(crate) ldk_announced_node_name: [u8; 32],
42         pub(crate) network: Network,
43 }
44
45 struct UserOnionMessageContents {
46         tlv_type: u64,
47         data: Vec<u8>,
48 }
49
50 impl CustomOnionMessageContents for UserOnionMessageContents {
51         fn tlv_type(&self) -> u64 {
52                 self.tlv_type
53         }
54 }
55
56 impl Writeable for UserOnionMessageContents {
57         fn write<W: Writer>(&self, w: &mut W) -> Result<(), std::io::Error> {
58                 w.write_all(&self.data)
59         }
60 }
61
62 pub(crate) async fn poll_for_user_input(
63         peer_manager: Arc<PeerManager>, channel_manager: Arc<ChannelManager>,
64         keys_manager: Arc<KeysManager>, network_graph: Arc<NetworkGraph>,
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>,
68 ) {
69         println!(
70                 "LDK startup successful. Enter \"help\" to view available commands. Press Ctrl-D to quit."
71         );
72         println!("LDK logs are available at <your-supplied-ldk-data-dir-path>/.ldk/logs");
73         println!("Local Node ID is {}.", channel_manager.get_our_node_id());
74         loop {
75                 print!("> ");
76                 io::stdout().flush().unwrap(); // Without flushing, the `>` doesn't print
77                 let mut line = String::new();
78                 if let Err(e) = io::stdin().read_line(&mut line) {
79                         break println!("ERROR: {}", e);
80                 }
81
82                 if line.len() == 0 {
83                         // We hit EOF / Ctrl-D
84                         break;
85                 }
86
87                 let mut words = line.split_whitespace();
88                 if let Some(word) = words.next() {
89                         match word {
90                                 "help" => help(),
91                                 "openchannel" => {
92                                         let peer_pubkey_and_ip_addr = words.next();
93                                         let channel_value_sat = words.next();
94                                         if peer_pubkey_and_ip_addr.is_none() || channel_value_sat.is_none() {
95                                                 println!("ERROR: openchannel has 2 required arguments: `openchannel pubkey@host:port channel_amt_satoshis` [--public]");
96                                                 continue;
97                                         }
98                                         let peer_pubkey_and_ip_addr = peer_pubkey_and_ip_addr.unwrap();
99                                         let (pubkey, peer_addr) =
100                                                 match parse_peer_info(peer_pubkey_and_ip_addr.to_string()) {
101                                                         Ok(info) => info,
102                                                         Err(e) => {
103                                                                 println!("{:?}", e.into_inner().unwrap());
104                                                                 continue;
105                                                         }
106                                                 };
107
108                                         let chan_amt_sat: Result<u64, _> = channel_value_sat.unwrap().parse();
109                                         if chan_amt_sat.is_err() {
110                                                 println!("ERROR: channel amount must be a number");
111                                                 continue;
112                                         }
113
114                                         if connect_peer_if_necessary(pubkey, peer_addr, peer_manager.clone())
115                                                 .await
116                                                 .is_err()
117                                         {
118                                                 continue;
119                                         };
120
121                                         let announce_channel = match words.next() {
122                                                 Some("--public") | Some("--public=true") => true,
123                                                 Some("--public=false") => false,
124                                                 Some(_) => {
125                                                         println!("ERROR: invalid `--public` command format. Valid formats: `--public`, `--public=true` `--public=false`");
126                                                         continue;
127                                                 }
128                                                 None => false,
129                                         };
130
131                                         if open_channel(
132                                                 pubkey,
133                                                 chan_amt_sat.unwrap(),
134                                                 announce_channel,
135                                                 channel_manager.clone(),
136                                         )
137                                         .is_ok()
138                                         {
139                                                 let peer_data_path = format!("{}/channel_peer_data", ldk_data_dir.clone());
140                                                 let _ = disk::persist_channel_peer(
141                                                         Path::new(&peer_data_path),
142                                                         peer_pubkey_and_ip_addr,
143                                                 );
144                                         }
145                                 }
146                                 "sendpayment" => {
147                                         let invoice_str = words.next();
148                                         if invoice_str.is_none() {
149                                                 println!("ERROR: sendpayment requires an invoice: `sendpayment <invoice>`");
150                                                 continue;
151                                         }
152
153                                         let invoice = match Invoice::from_str(invoice_str.unwrap()) {
154                                                 Ok(inv) => inv,
155                                                 Err(e) => {
156                                                         println!("ERROR: invalid invoice: {:?}", e);
157                                                         continue;
158                                                 }
159                                         };
160
161                                         send_payment(
162                                                 &channel_manager,
163                                                 &invoice,
164                                                 &mut outbound_payments.lock().unwrap(),
165                                                 persister.clone(),
166                                         );
167                                 }
168                                 "keysend" => {
169                                         let dest_pubkey = match words.next() {
170                                                 Some(dest) => match hex_utils::to_compressed_pubkey(dest) {
171                                                         Some(pk) => pk,
172                                                         None => {
173                                                                 println!("ERROR: couldn't parse destination pubkey");
174                                                                 continue;
175                                                         }
176                                                 },
177                                                 None => {
178                                                         println!("ERROR: keysend requires a destination pubkey: `keysend <dest_pubkey> <amt_msat>`");
179                                                         continue;
180                                                 }
181                                         };
182                                         let amt_msat_str = match words.next() {
183                                                 Some(amt) => amt,
184                                                 None => {
185                                                         println!("ERROR: keysend requires an amount in millisatoshis: `keysend <dest_pubkey> <amt_msat>`");
186                                                         continue;
187                                                 }
188                                         };
189                                         let amt_msat: u64 = match amt_msat_str.parse() {
190                                                 Ok(amt) => amt,
191                                                 Err(e) => {
192                                                         println!("ERROR: couldn't parse amount_msat: {}", e);
193                                                         continue;
194                                                 }
195                                         };
196                                         keysend(
197                                                 &channel_manager,
198                                                 dest_pubkey,
199                                                 amt_msat,
200                                                 &*keys_manager,
201                                                 &mut outbound_payments.lock().unwrap(),
202                                                 persister.clone(),
203                                         );
204                                 }
205                                 "getinvoice" => {
206                                         let amt_str = words.next();
207                                         if amt_str.is_none() {
208                                                 println!("ERROR: getinvoice requires an amount in millisatoshis");
209                                                 continue;
210                                         }
211
212                                         let amt_msat: Result<u64, _> = amt_str.unwrap().parse();
213                                         if amt_msat.is_err() {
214                                                 println!("ERROR: getinvoice provided payment amount was not a number");
215                                                 continue;
216                                         }
217
218                                         let expiry_secs_str = words.next();
219                                         if expiry_secs_str.is_none() {
220                                                 println!("ERROR: getinvoice requires an expiry in seconds");
221                                                 continue;
222                                         }
223
224                                         let expiry_secs: Result<u32, _> = expiry_secs_str.unwrap().parse();
225                                         if expiry_secs.is_err() {
226                                                 println!("ERROR: getinvoice provided expiry was not a number");
227                                                 continue;
228                                         }
229
230                                         let mut inbound_payments = inbound_payments.lock().unwrap();
231                                         get_invoice(
232                                                 amt_msat.unwrap(),
233                                                 &mut inbound_payments,
234                                                 &channel_manager,
235                                                 Arc::clone(&keys_manager),
236                                                 network,
237                                                 expiry_secs.unwrap(),
238                                                 Arc::clone(&logger),
239                                         );
240                                         persister.persist(INBOUND_PAYMENTS_FNAME, &*inbound_payments).unwrap();
241                                 }
242                                 "connectpeer" => {
243                                         let peer_pubkey_and_ip_addr = words.next();
244                                         if peer_pubkey_and_ip_addr.is_none() {
245                                                 println!("ERROR: connectpeer requires peer connection info: `connectpeer pubkey@host:port`");
246                                                 continue;
247                                         }
248                                         let (pubkey, peer_addr) =
249                                                 match parse_peer_info(peer_pubkey_and_ip_addr.unwrap().to_string()) {
250                                                         Ok(info) => info,
251                                                         Err(e) => {
252                                                                 println!("{:?}", e.into_inner().unwrap());
253                                                                 continue;
254                                                         }
255                                                 };
256                                         if connect_peer_if_necessary(pubkey, peer_addr, peer_manager.clone())
257                                                 .await
258                                                 .is_ok()
259                                         {
260                                                 println!("SUCCESS: connected to peer {}", pubkey);
261                                         }
262                                 }
263                                 "disconnectpeer" => {
264                                         let peer_pubkey = words.next();
265                                         if peer_pubkey.is_none() {
266                                                 println!("ERROR: disconnectpeer requires peer public key: `disconnectpeer <peer_pubkey>`");
267                                                 continue;
268                                         }
269
270                                         let peer_pubkey =
271                                                 match bitcoin::secp256k1::PublicKey::from_str(peer_pubkey.unwrap()) {
272                                                         Ok(pubkey) => pubkey,
273                                                         Err(e) => {
274                                                                 println!("ERROR: {}", e.to_string());
275                                                                 continue;
276                                                         }
277                                                 };
278
279                                         if do_disconnect_peer(
280                                                 peer_pubkey,
281                                                 peer_manager.clone(),
282                                                 channel_manager.clone(),
283                                         )
284                                         .is_ok()
285                                         {
286                                                 println!("SUCCESS: disconnected from peer {}", peer_pubkey);
287                                         }
288                                 }
289                                 "listchannels" => list_channels(&channel_manager, &network_graph),
290                                 "listpayments" => list_payments(
291                                         &inbound_payments.lock().unwrap(),
292                                         &outbound_payments.lock().unwrap(),
293                                 ),
294                                 "closechannel" => {
295                                         let channel_id_str = words.next();
296                                         if channel_id_str.is_none() {
297                                                 println!("ERROR: closechannel requires a channel ID: `closechannel <channel_id> <peer_pubkey>`");
298                                                 continue;
299                                         }
300                                         let channel_id_vec = hex_utils::to_vec(channel_id_str.unwrap());
301                                         if channel_id_vec.is_none() || channel_id_vec.as_ref().unwrap().len() != 32 {
302                                                 println!("ERROR: couldn't parse channel_id");
303                                                 continue;
304                                         }
305                                         let mut channel_id = [0; 32];
306                                         channel_id.copy_from_slice(&channel_id_vec.unwrap());
307
308                                         let peer_pubkey_str = words.next();
309                                         if peer_pubkey_str.is_none() {
310                                                 println!("ERROR: closechannel requires a peer pubkey: `closechannel <channel_id> <peer_pubkey>`");
311                                                 continue;
312                                         }
313                                         let peer_pubkey_vec = match hex_utils::to_vec(peer_pubkey_str.unwrap()) {
314                                                 Some(peer_pubkey_vec) => peer_pubkey_vec,
315                                                 None => {
316                                                         println!("ERROR: couldn't parse peer_pubkey");
317                                                         continue;
318                                                 }
319                                         };
320                                         let peer_pubkey = match PublicKey::from_slice(&peer_pubkey_vec) {
321                                                 Ok(peer_pubkey) => peer_pubkey,
322                                                 Err(_) => {
323                                                         println!("ERROR: couldn't parse peer_pubkey");
324                                                         continue;
325                                                 }
326                                         };
327
328                                         close_channel(channel_id, peer_pubkey, channel_manager.clone());
329                                 }
330                                 "forceclosechannel" => {
331                                         let channel_id_str = words.next();
332                                         if channel_id_str.is_none() {
333                                                 println!("ERROR: forceclosechannel requires a channel ID: `forceclosechannel <channel_id> <peer_pubkey>`");
334                                                 continue;
335                                         }
336                                         let channel_id_vec = hex_utils::to_vec(channel_id_str.unwrap());
337                                         if channel_id_vec.is_none() || channel_id_vec.as_ref().unwrap().len() != 32 {
338                                                 println!("ERROR: couldn't parse channel_id");
339                                                 continue;
340                                         }
341                                         let mut channel_id = [0; 32];
342                                         channel_id.copy_from_slice(&channel_id_vec.unwrap());
343
344                                         let peer_pubkey_str = words.next();
345                                         if peer_pubkey_str.is_none() {
346                                                 println!("ERROR: forceclosechannel requires a peer pubkey: `forceclosechannel <channel_id> <peer_pubkey>`");
347                                                 continue;
348                                         }
349                                         let peer_pubkey_vec = match hex_utils::to_vec(peer_pubkey_str.unwrap()) {
350                                                 Some(peer_pubkey_vec) => peer_pubkey_vec,
351                                                 None => {
352                                                         println!("ERROR: couldn't parse peer_pubkey");
353                                                         continue;
354                                                 }
355                                         };
356                                         let peer_pubkey = match PublicKey::from_slice(&peer_pubkey_vec) {
357                                                 Ok(peer_pubkey) => peer_pubkey,
358                                                 Err(_) => {
359                                                         println!("ERROR: couldn't parse peer_pubkey");
360                                                         continue;
361                                                 }
362                                         };
363
364                                         force_close_channel(channel_id, peer_pubkey, channel_manager.clone());
365                                 }
366                                 "nodeinfo" => node_info(&channel_manager, &peer_manager),
367                                 "listpeers" => list_peers(peer_manager.clone()),
368                                 "signmessage" => {
369                                         const MSG_STARTPOS: usize = "signmessage".len() + 1;
370                                         if line.as_bytes().len() <= MSG_STARTPOS {
371                                                 println!("ERROR: signmsg requires a message");
372                                                 continue;
373                                         }
374                                         println!(
375                                                 "{:?}",
376                                                 lightning::util::message_signing::sign(
377                                                         &line.as_bytes()[MSG_STARTPOS..],
378                                                         &keys_manager.get_node_secret_key()
379                                                 )
380                                         );
381                                 }
382                                 "sendonionmessage" => {
383                                         let path_pks_str = words.next();
384                                         if path_pks_str.is_none() {
385                                                 println!(
386                                                         "ERROR: sendonionmessage requires at least one node id for the path"
387                                                 );
388                                                 continue;
389                                         }
390                                         let mut node_pks = Vec::new();
391                                         let mut errored = false;
392                                         for pk_str in path_pks_str.unwrap().split(",") {
393                                                 let node_pubkey_vec = match hex_utils::to_vec(pk_str) {
394                                                         Some(peer_pubkey_vec) => peer_pubkey_vec,
395                                                         None => {
396                                                                 println!("ERROR: couldn't parse peer_pubkey");
397                                                                 errored = true;
398                                                                 break;
399                                                         }
400                                                 };
401                                                 let node_pubkey = match PublicKey::from_slice(&node_pubkey_vec) {
402                                                         Ok(peer_pubkey) => peer_pubkey,
403                                                         Err(_) => {
404                                                                 println!("ERROR: couldn't parse peer_pubkey");
405                                                                 errored = true;
406                                                                 break;
407                                                         }
408                                                 };
409                                                 node_pks.push(node_pubkey);
410                                         }
411                                         if errored {
412                                                 continue;
413                                         }
414                                         let tlv_type = match words.next().map(|ty_str| ty_str.parse()) {
415                                                 Some(Ok(ty)) if ty >= 64 => ty,
416                                                 _ => {
417                                                         println!("Need an integral message type above 64");
418                                                         continue;
419                                                 }
420                                         };
421                                         let data = match words.next().map(|s| hex_utils::to_vec(s)) {
422                                                 Some(Some(data)) => data,
423                                                 _ => {
424                                                         println!("Need a hex data string");
425                                                         continue;
426                                                 }
427                                         };
428                                         let destination_pk = node_pks.pop().unwrap();
429                                         match onion_messenger.send_onion_message(
430                                                 &node_pks,
431                                                 Destination::Node(destination_pk),
432                                                 OnionMessageContents::Custom(UserOnionMessageContents { tlv_type, data }),
433                                                 None,
434                                         ) {
435                                                 Ok(()) => println!("SUCCESS: forwarded onion message to first hop"),
436                                                 Err(e) => println!("ERROR: failed to send onion message: {:?}", e),
437                                         }
438                                 }
439                                 "quit" | "exit" => break,
440                                 _ => println!("Unknown command. See `\"help\" for available commands."),
441                         }
442                 }
443         }
444 }
445
446 fn help() {
447         let package_version = env!("CARGO_PKG_VERSION");
448         let package_name = env!("CARGO_PKG_NAME");
449         println!("\nVERSION:");
450         println!("  {} v{}", package_name, package_version);
451         println!("\nUSAGE:");
452         println!("  Command [arguments]");
453         println!("\nCOMMANDS:");
454         println!("  help\tShows a list of commands.");
455         println!("  quit\tClose the application.");
456         println!("\n  Channels:");
457         println!("      openchannel pubkey@host:port <amt_satoshis> [--public]");
458         println!("      closechannel <channel_id> <peer_pubkey>");
459         println!("      forceclosechannel <channel_id> <peer_pubkey>");
460         println!("      listchannels");
461         println!("\n  Peers:");
462         println!("      connectpeer pubkey@host:port");
463         println!("      disconnectpeer <peer_pubkey>");
464         println!("      listpeers");
465         println!("\n  Payments:");
466         println!("      sendpayment <invoice>");
467         println!("      keysend <dest_pubkey> <amt_msats>");
468         println!("      listpayments");
469         println!("\n  Invoices:");
470         println!("      getinvoice <amt_msats> <expiry_secs>");
471         println!("\n  Other:");
472         println!("      signmessage <message>");
473         println!(
474                 "      sendonionmessage <node_id_1,node_id_2,..,destination_node_id> <type> <hex_bytes>"
475         );
476         println!("      nodeinfo");
477 }
478
479 fn node_info(channel_manager: &Arc<ChannelManager>, peer_manager: &Arc<PeerManager>) {
480         println!("\t{{");
481         println!("\t\t node_pubkey: {}", channel_manager.get_our_node_id());
482         let chans = channel_manager.list_channels();
483         println!("\t\t num_channels: {}", chans.len());
484         println!("\t\t num_usable_channels: {}", chans.iter().filter(|c| c.is_usable).count());
485         let local_balance_msat = chans.iter().map(|c| c.balance_msat).sum::<u64>();
486         println!("\t\t local_balance_msat: {}", local_balance_msat);
487         println!("\t\t num_peers: {}", peer_manager.get_peer_node_ids().len());
488         println!("\t}},");
489 }
490
491 fn list_peers(peer_manager: Arc<PeerManager>) {
492         println!("\t{{");
493         for (pubkey, _) in peer_manager.get_peer_node_ids() {
494                 println!("\t\t pubkey: {}", pubkey);
495         }
496         println!("\t}},");
497 }
498
499 fn list_channels(channel_manager: &Arc<ChannelManager>, network_graph: &Arc<NetworkGraph>) {
500         print!("[");
501         for chan_info in channel_manager.list_channels() {
502                 println!("");
503                 println!("\t{{");
504                 println!("\t\tchannel_id: {},", hex_utils::hex_str(&chan_info.channel_id[..]));
505                 if let Some(funding_txo) = chan_info.funding_txo {
506                         println!("\t\tfunding_txid: {},", funding_txo.txid);
507                 }
508
509                 println!(
510                         "\t\tpeer_pubkey: {},",
511                         hex_utils::hex_str(&chan_info.counterparty.node_id.serialize())
512                 );
513                 if let Some(node_info) = network_graph
514                         .read_only()
515                         .nodes()
516                         .get(&NodeId::from_pubkey(&chan_info.counterparty.node_id))
517                 {
518                         if let Some(announcement) = &node_info.announcement_info {
519                                 println!("\t\tpeer_alias: {}", announcement.alias);
520                         }
521                 }
522
523                 if let Some(id) = chan_info.short_channel_id {
524                         println!("\t\tshort_channel_id: {},", id);
525                 }
526                 println!("\t\tis_channel_ready: {},", chan_info.is_channel_ready);
527                 println!("\t\tchannel_value_satoshis: {},", chan_info.channel_value_satoshis);
528                 println!("\t\tlocal_balance_msat: {},", chan_info.balance_msat);
529                 if chan_info.is_usable {
530                         println!("\t\tavailable_balance_for_send_msat: {},", chan_info.outbound_capacity_msat);
531                         println!("\t\tavailable_balance_for_recv_msat: {},", chan_info.inbound_capacity_msat);
532                 }
533                 println!("\t\tchannel_can_send_payments: {},", chan_info.is_usable);
534                 println!("\t\tpublic: {},", chan_info.is_public);
535                 println!("\t}},");
536         }
537         println!("]");
538 }
539
540 fn list_payments(inbound_payments: &PaymentInfoStorage, outbound_payments: &PaymentInfoStorage) {
541         print!("[");
542         for (payment_hash, payment_info) in &inbound_payments.payments {
543                 println!("");
544                 println!("\t{{");
545                 println!("\t\tamount_millisatoshis: {},", payment_info.amt_msat);
546                 println!("\t\tpayment_hash: {},", hex_utils::hex_str(&payment_hash.0));
547                 println!("\t\thtlc_direction: inbound,");
548                 println!(
549                         "\t\thtlc_status: {},",
550                         match payment_info.status {
551                                 HTLCStatus::Pending => "pending",
552                                 HTLCStatus::Succeeded => "succeeded",
553                                 HTLCStatus::Failed => "failed",
554                         }
555                 );
556
557                 println!("\t}},");
558         }
559
560         for (payment_hash, payment_info) in &outbound_payments.payments {
561                 println!("");
562                 println!("\t{{");
563                 println!("\t\tamount_millisatoshis: {},", payment_info.amt_msat);
564                 println!("\t\tpayment_hash: {},", hex_utils::hex_str(&payment_hash.0));
565                 println!("\t\thtlc_direction: outbound,");
566                 println!(
567                         "\t\thtlc_status: {},",
568                         match payment_info.status {
569                                 HTLCStatus::Pending => "pending",
570                                 HTLCStatus::Succeeded => "succeeded",
571                                 HTLCStatus::Failed => "failed",
572                         }
573                 );
574
575                 println!("\t}},");
576         }
577         println!("]");
578 }
579
580 pub(crate) async fn connect_peer_if_necessary(
581         pubkey: PublicKey, peer_addr: SocketAddr, peer_manager: Arc<PeerManager>,
582 ) -> Result<(), ()> {
583         for (node_pubkey, _) in peer_manager.get_peer_node_ids() {
584                 if node_pubkey == pubkey {
585                         return Ok(());
586                 }
587         }
588         let res = do_connect_peer(pubkey, peer_addr, peer_manager).await;
589         if res.is_err() {
590                 println!("ERROR: failed to connect to peer");
591         }
592         res
593 }
594
595 pub(crate) async fn do_connect_peer(
596         pubkey: PublicKey, peer_addr: SocketAddr, peer_manager: Arc<PeerManager>,
597 ) -> Result<(), ()> {
598         match lightning_net_tokio::connect_outbound(Arc::clone(&peer_manager), pubkey, peer_addr).await
599         {
600                 Some(connection_closed_future) => {
601                         let mut connection_closed_future = Box::pin(connection_closed_future);
602                         loop {
603                                 tokio::select! {
604                                         _ = &mut connection_closed_future => return Err(()),
605                                         _ = tokio::time::sleep(Duration::from_millis(10)) => {},
606                                 };
607                                 if peer_manager.get_peer_node_ids().iter().find(|(id, _)| *id == pubkey).is_some() {
608                                         return Ok(());
609                                 }
610                         }
611                 }
612                 None => Err(()),
613         }
614 }
615
616 fn do_disconnect_peer(
617         pubkey: bitcoin::secp256k1::PublicKey, peer_manager: Arc<PeerManager>,
618         channel_manager: Arc<ChannelManager>,
619 ) -> Result<(), ()> {
620         //check for open channels with peer
621         for channel in channel_manager.list_channels() {
622                 if channel.counterparty.node_id == pubkey {
623                         println!("Error: Node has an active channel with this peer, close any channels first");
624                         return Err(());
625                 }
626         }
627
628         //check the pubkey matches a valid connected peer
629         let peers = peer_manager.get_peer_node_ids();
630         if !peers.iter().any(|(pk, _)| &pubkey == pk) {
631                 println!("Error: Could not find peer {}", pubkey);
632                 return Err(());
633         }
634
635         peer_manager.disconnect_by_node_id(pubkey);
636         Ok(())
637 }
638
639 fn open_channel(
640         peer_pubkey: PublicKey, channel_amt_sat: u64, announced_channel: bool,
641         channel_manager: Arc<ChannelManager>,
642 ) -> Result<(), ()> {
643         let config = UserConfig {
644                 channel_handshake_limits: ChannelHandshakeLimits {
645                         // lnd's max to_self_delay is 2016, so we want to be compatible.
646                         their_to_self_delay: 2016,
647                         ..Default::default()
648                 },
649                 channel_handshake_config: ChannelHandshakeConfig {
650                         announced_channel,
651                         ..Default::default()
652                 },
653                 ..Default::default()
654         };
655
656         match channel_manager.create_channel(peer_pubkey, channel_amt_sat, 0, 0, Some(config)) {
657                 Ok(_) => {
658                         println!("EVENT: initiated channel with peer {}. ", peer_pubkey);
659                         return Ok(());
660                 }
661                 Err(e) => {
662                         println!("ERROR: failed to open channel: {:?}", e);
663                         return Err(());
664                 }
665         }
666 }
667
668 fn send_payment(
669         channel_manager: &ChannelManager, invoice: &Invoice,
670         outbound_payments: &mut PaymentInfoStorage, persister: Arc<FilesystemPersister>,
671 ) {
672         let payment_hash = PaymentHash((*invoice.payment_hash()).into_inner());
673         let payment_secret = Some(*invoice.payment_secret());
674         outbound_payments.payments.insert(
675                 payment_hash,
676                 PaymentInfo {
677                         preimage: None,
678                         secret: payment_secret,
679                         status: HTLCStatus::Pending,
680                         amt_msat: MillisatAmount(invoice.amount_milli_satoshis()),
681                 },
682         );
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         };
698 }
699
700 fn keysend<E: EntropySource>(
701         channel_manager: &ChannelManager, payee_pubkey: PublicKey, amt_msat: u64, entropy_source: &E,
702         outbound_payments: &mut PaymentInfoStorage, persister: Arc<FilesystemPersister>,
703 ) {
704         let payment_preimage = PaymentPreimage(entropy_source.get_secure_random_bytes());
705         let payment_hash = PaymentHash(Sha256::hash(&payment_preimage.0[..]).into_inner());
706
707         let route_params = RouteParameters {
708                 payment_params: PaymentParameters::for_keysend(payee_pubkey, 40),
709                 final_value_msat: amt_msat,
710         };
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(
722                 Some(payment_preimage),
723                 RecipientOnionFields::spontaneous_empty(),
724                 PaymentId(payment_hash.0),
725                 route_params,
726                 Retry::Timeout(Duration::from_secs(10)),
727         ) {
728                 Ok(_payment_hash) => {
729                         println!("EVENT: initiated sending {} msats to {}", amt_msat, payee_pubkey);
730                         print!("> ");
731                 }
732                 Err(e) => {
733                         println!("ERROR: failed to send payment: {:?}", e);
734                         print!("> ");
735                         outbound_payments.payments.get_mut(&payment_hash).unwrap().status = HTLCStatus::Failed;
736                         persister.persist(OUTBOUND_PAYMENTS_FNAME, &*outbound_payments).unwrap();
737                 }
738         };
739 }
740
741 fn get_invoice(
742         amt_msat: u64, inbound_payments: &mut PaymentInfoStorage, channel_manager: &ChannelManager,
743         keys_manager: Arc<KeysManager>, network: Network, expiry_secs: u32,
744         logger: Arc<disk::FilesystemLogger>,
745 ) {
746         let currency = match network {
747                 Network::Bitcoin => Currency::Bitcoin,
748                 Network::Testnet => Currency::BitcoinTestnet,
749                 Network::Regtest => Currency::Regtest,
750                 Network::Signet => Currency::Signet,
751         };
752         let invoice = match utils::create_invoice_from_channelmanager(
753                 channel_manager,
754                 keys_manager,
755                 logger,
756                 currency,
757                 Some(amt_msat),
758                 "ldk-tutorial-node".to_string(),
759                 expiry_secs,
760                 None,
761         ) {
762                 Ok(inv) => {
763                         println!("SUCCESS: generated invoice: {}", inv);
764                         inv
765                 }
766                 Err(e) => {
767                         println!("ERROR: failed to create invoice: {:?}", e);
768                         return;
769                 }
770         };
771
772         let payment_hash = PaymentHash(invoice.payment_hash().clone().into_inner());
773         inbound_payments.payments.insert(
774                 payment_hash,
775                 PaymentInfo {
776                         preimage: None,
777                         secret: Some(invoice.payment_secret().clone()),
778                         status: HTLCStatus::Pending,
779                         amt_msat: MillisatAmount(Some(amt_msat)),
780                 },
781         );
782 }
783
784 fn close_channel(
785         channel_id: [u8; 32], counterparty_node_id: PublicKey, channel_manager: Arc<ChannelManager>,
786 ) {
787         match channel_manager.close_channel(&channel_id, &counterparty_node_id) {
788                 Ok(()) => println!("EVENT: initiating channel close"),
789                 Err(e) => println!("ERROR: failed to close channel: {:?}", e),
790         }
791 }
792
793 fn force_close_channel(
794         channel_id: [u8; 32], counterparty_node_id: PublicKey, channel_manager: Arc<ChannelManager>,
795 ) {
796         match channel_manager.force_close_broadcasting_latest_txn(&channel_id, &counterparty_node_id) {
797                 Ok(()) => println!("EVENT: initiating channel force-close"),
798                 Err(e) => println!("ERROR: failed to force-close channel: {:?}", e),
799         }
800 }
801
802 pub(crate) fn parse_peer_info(
803         peer_pubkey_and_ip_addr: String,
804 ) -> Result<(PublicKey, SocketAddr), std::io::Error> {
805         let mut pubkey_and_addr = peer_pubkey_and_ip_addr.split("@");
806         let pubkey = pubkey_and_addr.next();
807         let peer_addr_str = pubkey_and_addr.next();
808         if peer_addr_str.is_none() {
809                 return Err(std::io::Error::new(
810                         std::io::ErrorKind::Other,
811                         "ERROR: incorrectly formatted peer info. Should be formatted as: `pubkey@host:port`",
812                 ));
813         }
814
815         let peer_addr = peer_addr_str.unwrap().to_socket_addrs().map(|mut r| r.next());
816         if peer_addr.is_err() || peer_addr.as_ref().unwrap().is_none() {
817                 return Err(std::io::Error::new(
818                         std::io::ErrorKind::Other,
819                         "ERROR: couldn't parse pubkey@host:port into a socket address",
820                 ));
821         }
822
823         let pubkey = hex_utils::to_compressed_pubkey(pubkey.unwrap());
824         if pubkey.is_none() {
825                 return Err(std::io::Error::new(
826                         std::io::ErrorKind::Other,
827                         "ERROR: unable to parse given pubkey for node",
828                 ));
829         }
830
831         Ok((pubkey.unwrap(), peer_addr.unwrap().unwrap()))
832 }