+ Err(e) => {println!("ERROR: failed to connect to peer: {:?}", e);
+ return Err(())
+ }
+ }
+ Ok(())
+}
+
+fn open_channel(peer_pubkey: PublicKey, channel_amt_sat: u64, channel_manager: Arc<ChannelManager>)
+ -> Result<(), ()> {
+ let mut config = UserConfig::default();
+ // lnd's max to_self_delay is 2016, so we want to be compatible.
+ config.peer_channel_config_limits.their_to_self_delay = 2016;
+ match channel_manager.create_channel(peer_pubkey, channel_amt_sat, 0, 0, None) {
+ Ok(_) => {
+ println!("EVENT: initiated channel with peer {}. ", peer_pubkey);
+ return Ok(())
+ },
+ Err(e) => {
+ println!("ERROR: failed to open channel: {:?}", e);
+ return Err(())
+ }
+ }
+}
+
+fn send_payment(payee: PublicKey, amt_msat: u64, final_cltv: u32, payment_hash: PaymentHash,
+ payment_secret: Option<PaymentSecret>, payee_features:
+ Option<InvoiceFeatures>, router: Arc<NetGraphMsgHandler<Arc<dyn
+ chain::Access>, Arc<FilesystemLogger>>>, channel_manager:
+ Arc<ChannelManager>, payment_storage: PaymentInfoStorage, logger:
+ Arc<FilesystemLogger>) {
+ let network_graph = router.network_graph.read().unwrap();
+ let first_hops = channel_manager.list_usable_channels();
+ let payer_pubkey = channel_manager.get_our_node_id();
+
+ let route = router::get_route(&payer_pubkey, &network_graph, &payee, payee_features,
+ Some(&first_hops.iter().collect::<Vec<_>>()), &vec![], amt_msat,
+ final_cltv, logger);
+ if let Err(e) = route {
+ println!("ERROR: failed to find route: {}", e.err);
+ return
+ }
+ let status = match channel_manager.send_payment(&route.unwrap(), payment_hash, &payment_secret) {
+ Ok(()) => {
+ println!("EVENT: initiated sending {} msats to {}", amt_msat, payee);
+ HTLCStatus::Pending
+ },
+ Err(e) => {
+ println!("ERROR: failed to send payment: {:?}", e);
+ HTLCStatus::Failed
+ }
+ };
+ let mut payments = payment_storage.lock().unwrap();
+ payments.insert(payment_hash, (None, HTLCDirection::Outbound, status));
+}
+
+fn get_invoice(amt_sat: u64, payment_storage: PaymentInfoStorage, our_node_privkey: SecretKey,
+ channel_manager: Arc<ChannelManager>, router: Arc<NetGraphMsgHandler<Arc<dyn
+ chain::Access>, Arc<FilesystemLogger>>>) {
+ let mut payments = payment_storage.lock().unwrap();
+ let secp_ctx = Secp256k1::new();
+
+ let mut preimage = [0; 32];
+ rand::thread_rng().fill_bytes(&mut preimage);
+ let payment_hash = Sha256Hash::hash(&preimage);
+
+
+ let our_node_pubkey = channel_manager.get_our_node_id();
+ let invoice = lightning_invoice::InvoiceBuilder::new(match NETWORK {
+ Network::Bitcoin => lightning_invoice::Currency::Bitcoin,
+ Network::Testnet => lightning_invoice::Currency::BitcoinTestnet,
+ Network::Regtest => lightning_invoice::Currency::Regtest,
+ Network::Signet => panic!("Signet invoices not supported")
+ }).payment_hash(payment_hash).description("rust-lightning-bitcoinrpc invoice".to_string())
+ .amount_pico_btc(amt_sat * 10)
+ .current_timestamp()
+ .payee_pub_key(our_node_pubkey);
+
+ // Add route hints to the invoice.
+ // let our_channels = channel_manager.list_usable_channels();
+ // let network_graph = router.network_graph.read().unwrap();
+ // let network_channels = network_graph.get_channels();
+ // for channel in our_channels {
+ // let short_channel_id_opt = channel.short_channel_id;
+ // if short_channel_id_opt.is_none() {
+ // continue
+ // }
+
+ // let short_channel_id = short_channel_id_opt.unwrap();
+ // let channel_routing_info_opt = network_channels.get(&short_channel_id);
+ // if channel_routing_info_opt.is_none() {
+ // continue
+ // }
+
+ // let channel_routing_info = channel_routing_info_opt.unwrap();
+ // let mut counterparty = channel_routing_info.node_two;
+ // let mut counterparty_chan_fees_opt = channel_routing_info.one_to_two.as_ref();
+ // if channel_routing_info.node_two != our_node_pubkey { // e.g. if our counterparty is node_one
+ // counterparty = channel_routing_info.node_one;
+ // counterparty_chan_fees_opt = channel_routing_info.two_to_one.as_ref();
+ // }
+ // if counterparty_chan_fees_opt.is_none() {
+ // continue
+ // }
+
+ // let counterparty_chan_fees = counterparty_chan_fees_opt.unwrap();
+ // invoice = invoice.route(vec![
+ // lightning_invoice::RouteHop {
+ // short_channel_id: short_channel_id.to_be_bytes(),
+ // cltv_expiry_delta: counterparty_chan_fees.cltv_expiry_delta,
+ // fee_base_msat: counterparty_chan_fees.fees.base_msat,
+ // fee_proportional_millionths: counterparty_chan_fees.fees.proportional_millionths,
+ // pubkey: counterparty,
+ // }
+ // ]);
+ // }
+
+ // Sign the invoice.
+ let invoice = invoice.build_signed(|msg_hash| {
+ secp_ctx.sign_recoverable(msg_hash, &our_node_privkey)
+ });
+
+ match invoice {
+ Ok(invoice) => println!("SUCCESS: generated invoice: {}", invoice),
+ Err(e) => println!("ERROR: failed to create invoice: {:?}", e),
+ }
+
+ payments.insert(PaymentHash(payment_hash.into_inner()), (Some(PaymentPreimage(preimage)),
+ HTLCDirection::Inbound,
+ HTLCStatus::Pending));
+}
+
+fn close_channel(channel_id: [u8; 32], channel_manager: Arc<ChannelManager>) {
+ match channel_manager.close_channel(&channel_id) {
+ Ok(()) => println!("EVENT: initiating channel close"),
+ Err(e) => println!("ERROR: failed to close channel: {:?}", e)
+ }
+}
+
+fn force_close_channel(channel_id: [u8; 32], channel_manager: Arc<ChannelManager>) {
+ match channel_manager.force_close_channel(&channel_id) {
+ Ok(()) => println!("EVENT: initiating channel force-close"),
+ Err(e) => println!("ERROR: failed to force-close channel: {:?}", e)
+ }
+}
+
+pub(crate) fn parse_peer_info(peer_pubkey_and_ip_addr: String) -> Result<(PublicKey, SocketAddr), std::io::Error> {
+ let mut pubkey_and_addr = peer_pubkey_and_ip_addr.split("@");
+ let pubkey = pubkey_and_addr.next();
+ let peer_addr_str = pubkey_and_addr.next();
+ if peer_addr_str.is_none() || peer_addr_str.is_none() {
+ return Err(std::io::Error::new(std::io::ErrorKind::Other, "ERROR: incorrectly formatted peer
+ info. Should be formatted as: `pubkey@host:port`"));
+ }
+
+ let peer_addr: Result<SocketAddr, _> = peer_addr_str.unwrap().parse();
+ if peer_addr.is_err() {
+ return Err(std::io::Error::new(std::io::ErrorKind::Other, "ERROR: couldn't parse pubkey@host:port into a socket address"));