From: valentinewallace Date: Thu, 5 Jan 2023 17:14:43 +0000 (-0500) Subject: Merge pull request #85 from ch1ru/main X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=commitdiff_plain;h=90ff6896459523d237ab2a8401dfddf9e99ae34e;hp=-c;p=ldk-sample Merge pull request #85 from ch1ru/main Add `disconnectpeer` subcommand --- 90ff6896459523d237ab2a8401dfddf9e99ae34e diff --combined src/cli.rs index da6d97f,64ee04d..030109e --- a/src/cli.rs +++ b/src/cli.rs @@@ -21,7 -21,7 +21,7 @@@ use lightning_invoice::{utils, Currency use std::env; use std::io; use std::io::Write; -use std::net::{IpAddr, SocketAddr, ToSocketAddrs}; +use std::net::{SocketAddr, ToSocketAddrs}; use std::ops::Deref; use std::path::Path; use std::str::FromStr; @@@ -40,6 -40,107 +40,6 @@@ pub(crate) struct LdkUserInfo pub(crate) network: Network, } -pub(crate) fn parse_startup_args() -> Result { - if env::args().len() < 3 { - println!("ldk-tutorial-node requires 3 arguments: `cargo run :@: ldk_storage_directory_path [] [bitcoin-network] [announced-node-name announced-listen-addr*]`"); - return Err(()); - } - let bitcoind_rpc_info = env::args().skip(1).next().unwrap(); - let bitcoind_rpc_info_parts: Vec<&str> = bitcoind_rpc_info.rsplitn(2, "@").collect(); - if bitcoind_rpc_info_parts.len() != 2 { - println!("ERROR: bad bitcoind RPC URL provided"); - return Err(()); - } - let rpc_user_and_password: Vec<&str> = bitcoind_rpc_info_parts[1].split(":").collect(); - if rpc_user_and_password.len() != 2 { - println!("ERROR: bad bitcoind RPC username/password combo provided"); - return Err(()); - } - let bitcoind_rpc_username = rpc_user_and_password[0].to_string(); - let bitcoind_rpc_password = rpc_user_and_password[1].to_string(); - let bitcoind_rpc_path: Vec<&str> = bitcoind_rpc_info_parts[0].split(":").collect(); - if bitcoind_rpc_path.len() != 2 { - println!("ERROR: bad bitcoind RPC path provided"); - return Err(()); - } - let bitcoind_rpc_host = bitcoind_rpc_path[0].to_string(); - let bitcoind_rpc_port = bitcoind_rpc_path[1].parse::().unwrap(); - - let ldk_storage_dir_path = env::args().skip(2).next().unwrap(); - - let mut ldk_peer_port_set = true; - let ldk_peer_listening_port: u16 = match env::args().skip(3).next().map(|p| p.parse()) { - Some(Ok(p)) => p, - Some(Err(_)) => { - ldk_peer_port_set = false; - 9735 - } - None => { - ldk_peer_port_set = false; - 9735 - } - }; - - let mut arg_idx = match ldk_peer_port_set { - true => 4, - false => 3, - }; - let network: Network = match env::args().skip(arg_idx).next().as_ref().map(String::as_str) { - Some("testnet") => Network::Testnet, - Some("regtest") => Network::Regtest, - Some("signet") => Network::Signet, - Some(net) => { - panic!("Unsupported network provided. Options are: `regtest`, `testnet`, and `signet`. Got {}", net); - } - None => Network::Testnet, - }; - - 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, - bitcoind_rpc_host, - bitcoind_rpc_port, - ldk_storage_dir_path, - ldk_peer_listening_port, - ldk_announced_listen_addr, - ldk_announced_node_name, - network, - }) -} - struct UserOnionMessageContents { tlv_type: u64, data: Vec, @@@ -256,6 -357,32 +256,32 @@@ pub(crate) async fn poll_for_user_input println!("SUCCESS: connected to peer {}", pubkey); } } + "disconnectpeer" => { + let peer_pubkey = words.next(); + if peer_pubkey.is_none() { + println!("ERROR: disconnectpeer requires peer public key: `disconnectpeer `"); + continue; + } + + let peer_pubkey = + match bitcoin::secp256k1::PublicKey::from_str(peer_pubkey.unwrap()) { + Ok(pubkey) => pubkey, + Err(e) => { + println!("ERROR: {}", e.to_string()); + continue; + } + }; + + if do_disconnect_peer( + peer_pubkey, + peer_manager.clone(), + channel_manager.clone(), + ) + .is_ok() + { + println!("SUCCESS: disconnected from peer {}", peer_pubkey); + } + } "listchannels" => list_channels(&channel_manager, &network_graph), "listpayments" => { list_payments(inbound_payments.clone(), outbound_payments.clone()) @@@ -429,6 -556,7 +455,7 @@@ fn help() println!(" listchannels"); println!("\n Peers:"); println!(" connectpeer pubkey@host:port"); + println!(" disconnectpeer "); println!(" listpeers"); println!("\n Payments:"); println!(" sendpayment "); @@@ -587,6 -715,29 +614,29 @@@ pub(crate) async fn do_connect_peer } } + fn do_disconnect_peer( + pubkey: bitcoin::secp256k1::PublicKey, peer_manager: Arc, + channel_manager: Arc, + ) -> Result<(), ()> { + //check for open channels with peer + for channel in channel_manager.list_channels() { + if channel.counterparty.node_id == pubkey { + println!("Error: Node has an active channel with this peer, close any channels first"); + return Err(()); + } + } + + //check the pubkey matches a valid connected peer + let peers = peer_manager.get_peer_node_ids(); + if !peers.contains(&pubkey) { + println!("Error: Could not find peer {}", pubkey); + return Err(()); + } + + peer_manager.disconnect_by_node_id(pubkey, false); + Ok(()) + } + fn open_channel( peer_pubkey: PublicKey, channel_amt_sat: u64, announced_channel: bool, channel_manager: Arc,