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