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