pub(crate) bitcoind_rpc_host: String,
pub(crate) ldk_storage_dir_path: String,
pub(crate) ldk_peer_listening_port: u16,
- pub(crate) ldk_announced_listen_addr: Option<NetAddress>,
+ pub(crate) ldk_announced_listen_addr: Vec<NetAddress>,
pub(crate) ldk_announced_node_name: [u8; 32],
pub(crate) network: Network,
}
pub(crate) fn parse_startup_args() -> Result<LdkUserInfo, ()> {
if env::args().len() < 3 {
- println!("ldk-tutorial-node requires 3 arguments: `cargo run <bitcoind-rpc-username>:<bitcoind-rpc-password>@<bitcoind-rpc-host>:<bitcoind-rpc-port> ldk_storage_directory_path [<ldk-incoming-peer-listening-port>] [bitcoin-network] [announced-listen-addr announced-node-name]`");
+ println!("ldk-tutorial-node requires 3 arguments: `cargo run <bitcoind-rpc-username>:<bitcoind-rpc-password>@<bitcoind-rpc-host>:<bitcoind-rpc-port> ldk_storage_directory_path [<ldk-incoming-peer-listening-port>] [bitcoin-network] [announced-node-name announced-listen-addr*]`");
return Err(());
}
let bitcoind_rpc_info = env::args().skip(1).next().unwrap();
}
};
- let arg_idx = match ldk_peer_port_set {
+ let mut arg_idx = match ldk_peer_port_set {
true => 4,
false => 3,
};
None => Network::Testnet,
};
- let ldk_announced_listen_addr = match env::args().skip(arg_idx + 1).next().as_ref() {
- Some(s) => match IpAddr::from_str(s) {
- Ok(IpAddr::V4(a)) => {
- Some(NetAddress::IPv4 { addr: a.octets(), port: ldk_peer_listening_port })
- }
- Ok(IpAddr::V6(a)) => {
- Some(NetAddress::IPv6 { addr: a.octets(), port: ldk_peer_listening_port })
- }
- Err(_) => panic!("Failed to parse announced-listen-addr into an IP address"),
- },
- None => None,
- };
-
- let ldk_announced_node_name = match env::args().skip(arg_idx + 2).next().as_ref() {
+ let ldk_announced_node_name = match env::args().skip(arg_idx + 1).next().as_ref() {
Some(s) => {
if s.len() > 32 {
panic!("Node Alias can not be longer than 32 bytes");
}
+ arg_idx += 1;
let mut bytes = [0; 32];
bytes[..s.len()].copy_from_slice(s.as_bytes());
bytes
None => [0; 32],
};
+ let mut ldk_announced_listen_addr = Vec::new();
+ loop {
+ match env::args().skip(arg_idx + 1).next().as_ref() {
+ Some(s) => match IpAddr::from_str(s) {
+ Ok(IpAddr::V4(a)) => {
+ ldk_announced_listen_addr
+ .push(NetAddress::IPv4 { addr: a.octets(), port: ldk_peer_listening_port });
+ arg_idx += 1;
+ }
+ Ok(IpAddr::V6(a)) => {
+ ldk_announced_listen_addr
+ .push(NetAddress::IPv6 { addr: a.octets(), port: ldk_peer_listening_port });
+ arg_idx += 1;
+ }
+ Err(_) => panic!("Failed to parse announced-listen-addr into an IP address"),
+ },
+ None => break,
+ }
+ }
+
Ok(LdkUserInfo {
bitcoind_rpc_username,
bitcoind_rpc_password,
logger.clone(),
);
}
+ "keysend" => {
+ let dest_pubkey = match words.next() {
+ Some(dest) => match hex_utils::to_compressed_pubkey(dest) {
+ Some(pk) => pk,
+ None => {
+ println!("ERROR: couldn't parse destination pubkey");
+ print!("> ");
+ io::stdout().flush().unwrap();
+ continue;
+ }
+ },
+ None => {
+ println!("ERROR: keysend requires a destination pubkey: `keysend <dest_pubkey> <amt_msat>`");
+ print!("> ");
+ io::stdout().flush().unwrap();
+ continue;
+ }
+ };
+ let amt_msat_str = match words.next() {
+ Some(amt) => amt,
+ None => {
+ println!("ERROR: keysend requires an amount in millisatoshis: `keysend <dest_pubkey> <amt_msat>`");
+
+ print!("> ");
+ io::stdout().flush().unwrap();
+ continue;
+ }
+ };
+ let amt_msat: u64 = match amt_msat_str.parse() {
+ Ok(amt) => amt,
+ Err(e) => {
+ println!("ERROR: couldn't parse amount_msat: {}", e);
+ print!("> ");
+ io::stdout().flush().unwrap();
+ continue;
+ }
+ };
+ keysend(
+ dest_pubkey,
+ amt_msat,
+ router.clone(),
+ channel_manager.clone(),
+ outbound_payments.clone(),
+ logger.clone(),
+ );
+ }
"getinvoice" => {
let amt_str = words.next();
if amt_str.is_none() {
}
println!(
"\t\tpeer_pubkey: {},",
- hex_utils::hex_str(&chan_info.remote_network_id.serialize())
+ hex_utils::hex_str(&chan_info.counterparty.node_id.serialize())
);
if let Some(id) = chan_info.short_channel_id {
println!("\t\tshort_channel_id: {},", id);
}
match lightning_net_tokio::connect_outbound(Arc::clone(&peer_manager), pubkey, peer_addr).await
{
- Some(conn_closed_fut) => {
- let mut closed_fut_box = Box::pin(conn_closed_fut);
- let mut peer_connected = false;
- while !peer_connected {
- match futures::poll!(&mut closed_fut_box) {
+ Some(connection_closed_future) => {
+ let mut connection_closed_future = Box::pin(connection_closed_future);
+ loop {
+ match futures::poll!(&mut connection_closed_future) {
std::task::Poll::Ready(_) => {
println!("ERROR: Peer disconnected before we finished the handshake");
return Err(());
}
std::task::Poll::Pending => {}
}
- for node_pubkey in peer_manager.get_peer_node_ids() {
- if node_pubkey == pubkey {
- peer_connected = true;
- }
- }
// Avoid blocking the tokio context by sleeping a bit
- tokio::time::sleep(Duration::from_millis(10)).await;
+ match peer_manager.get_peer_node_ids().iter().find(|id| **id == pubkey) {
+ Some(_) => break,
+ None => tokio::time::sleep(Duration::from_millis(10)).await,
+ }
}
}
None => {
);
}
+fn keysend(
+ payee: PublicKey, amt_msat: u64,
+ router: Arc<NetGraphMsgHandler<Arc<dyn chain::Access + Send + Sync>, 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 = match router::get_keysend_route(
+ &payer_pubkey,
+ &network_graph,
+ &payee,
+ Some(&first_hops.iter().collect::<Vec<_>>()),
+ &vec![],
+ amt_msat,
+ 40,
+ logger,
+ ) {
+ Ok(r) => r,
+ Err(e) => {
+ println!("ERROR: failed to find route: {}", e.err);
+ return;
+ }
+ };
+
+ let mut payments = payment_storage.lock().unwrap();
+ let payment_hash = channel_manager.send_spontaneous_payment(&route, None).unwrap();
+ payments.insert(
+ payment_hash,
+ PaymentInfo {
+ preimage: None,
+ secret: None,
+ status: HTLCStatus::Pending,
+ amt_msat: MillisatAmount(Some(amt_msat)),
+ },
+ );
+}
+
fn get_invoice(
amt_msat: u64, payment_storage: PaymentInfoStorage, channel_manager: Arc<ChannelManager>,
keys_manager: Arc<KeysManager>, network: Network,
payment_hash,
PaymentInfo {
preimage: None,
- // We can't add payment secrets to invoices until we support features in invoices.
- // Otherwise lnd errors with "destination hop doesn't understand payment addresses"
- // (for context, lnd calls payment secrets "payment addresses").
secret: invoice.payment_secret().cloned(),
status: HTLCStatus::Pending,
amt_msat: MillisatAmount(Some(amt_msat)),