From c8383dac93d0a7018c5bfc23cd7047f57ffd4801 Mon Sep 17 00:00:00 2001 From: Quentin Le Sceller Date: Wed, 3 Jan 2018 22:25:14 -0500 Subject: [PATCH] Add POST peers/a.b.c.d/unban in REST API (#571) Add unban peer in rest API and clean TODO --- api/src/handlers.rs | 100 ++++++++++++++++++++++---------------------- p2p/src/peers.rs | 16 +++++++ 2 files changed, 67 insertions(+), 49 deletions(-) diff --git a/api/src/handlers.rs b/api/src/handlers.rs index 9d8f6395..cd3fb8fd 100644 --- a/api/src/handlers.rs +++ b/api/src/handlers.rs @@ -37,15 +37,13 @@ use types::*; use util; use util::LOGGER; - // RESTful index of available api endpoints // GET /v1/ struct IndexHandler { list: Vec, } -impl IndexHandler { -} +impl IndexHandler {} impl Handler for IndexHandler { fn handle(&self, _req: &mut Request) -> IronResult { @@ -64,12 +62,13 @@ struct UtxoHandler { impl UtxoHandler { fn get_utxo(&self, id: &str, include_rp: bool, include_switch: bool) -> Result { debug!(LOGGER, "getting utxo: {}", id); - let c = util::from_hex(String::from(id)).map_err(|_| { - Error::Argument(format!("Not a valid commitment: {}", id)) - })?; + let c = util::from_hex(String::from(id)) + .map_err(|_| Error::Argument(format!("Not a valid commitment: {}", id)))?; let commit = Commitment::from_vec(c); - let out = self.chain.get_unspent(&commit).map_err(|_| Error::NotFound)?; + let out = self.chain + .get_unspent(&commit) + .map_err(|_| Error::NotFound)?; let header = self.chain .get_block_header_by_output_commit(&commit) @@ -120,8 +119,12 @@ impl UtxoHandler { let outputs = block .outputs .iter() - .filter(|c|self.chain.is_unspent(&c.commit, &c.switch_commit_hash).unwrap()) - .map(|k|OutputSwitch::from_output(k, &header)) + .filter(|c| { + self.chain + .is_unspent(&c.commit, &c.switch_commit_hash) + .unwrap() + }) + .map(|k| OutputSwitch::from_output(k, &header)) .collect(); BlockOutputs { header: BlockHeaderInfo::from_header(&header), @@ -259,7 +262,7 @@ impl Handler for PeersConnectedHandler { /// Peer operations /// POST /v1/peers/10.12.12.13/ban -/// TODO POST /v1/peers/10.12.12.13/unban +/// POST /v1/peers/10.12.12.13/unban pub struct PeerPostHandler { pub peers: p2p::Peers, } @@ -272,24 +275,26 @@ impl Handler for PeerPostHandler { path_elems.pop(); } match *path_elems.last().unwrap() { - "ban" => { - path_elems.pop(); - if let Ok(addr) = path_elems.last().unwrap().parse() { - self.peers.ban_peer(&addr); - Ok(Response::with((status::Ok, ""))) - } else { - Ok(Response::with((status::BadRequest, ""))) - } - } - "unban" => { - // TODO - Ok(Response::with((status::BadRequest, ""))) - } - _ => { - // TODO peer details - Ok(Response::with((status::BadRequest, ""))) - } - } + "ban" => { + path_elems.pop(); + if let Ok(addr) = path_elems.last().unwrap().parse() { + self.peers.ban_peer(&addr); + Ok(Response::with((status::Ok, ""))) + } else { + Ok(Response::with((status::BadRequest, ""))) + } + } + "unban" => { + path_elems.pop(); + if let Ok(addr) = path_elems.last().unwrap().parse() { + self.peers.unban_peer(&addr); + Ok(Response::with((status::Ok, ""))) + } else { + Ok(Response::with((status::BadRequest, ""))) + } + } + _ => Ok(Response::with((status::BadRequest, ""))), + } } } @@ -343,7 +348,10 @@ pub struct BlockHandler { impl BlockHandler { fn get_block(&self, h: &Hash) -> Result { - let block = self.chain.clone().get_block(h).map_err(|_| Error::NotFound)?; + let block = self.chain + .clone() + .get_block(h) + .map_err(|_| Error::NotFound)?; Ok(BlockPrintable::from_block(&block)) } @@ -359,8 +367,7 @@ impl BlockHandler { static ref RE: Regex = Regex::new(r"[0-9a-fA-F]{64}").unwrap(); } if !RE.is_match(&input) { - return Err(Error::Argument( - String::from("Not a valid hash or height."))) + return Err(Error::Argument(String::from("Not a valid hash or height."))); } let vec = util::from_hex(input).unwrap(); Ok(Hash::from_vec(vec)) @@ -417,18 +424,14 @@ where T: pool::BlockChain + Send + Sync + 'static, { fn handle(&self, req: &mut Request) -> IronResult { - let wrapper: TxWrapper = serde_json::from_reader(req.body.by_ref()).map_err(|e| { - IronError::new(e, status::BadRequest) - })?; + let wrapper: TxWrapper = serde_json::from_reader(req.body.by_ref()) + .map_err(|e| IronError::new(e, status::BadRequest))?; - let tx_bin = util::from_hex(wrapper.tx_hex).map_err(|_| { - Error::Argument(format!("Invalid hex in transaction wrapper.")) - })?; + let tx_bin = util::from_hex(wrapper.tx_hex) + .map_err(|_| Error::Argument(format!("Invalid hex in transaction wrapper.")))?; let tx: Transaction = ser::deserialize(&mut &tx_bin[..]).map_err(|_| { - Error::Argument( - "Could not deserialize transaction, invalid format.".to_string(), - ) + Error::Argument("Could not deserialize transaction, invalid format.".to_string()) })?; let source = pool::TxSource { @@ -445,9 +448,7 @@ where .write() .unwrap() .add_to_memory_pool(source, tx) - .map_err(|e| { - Error::Internal(format!("Addition to transaction pool failed: {:?}", e)) - })?; + .map_err(|e| Error::Internal(format!("Addition to transaction pool failed: {:?}", e)))?; Ok(Response::with(status::Ok)) } @@ -485,9 +486,9 @@ pub fn start_rest_apis( ) where T: pool::BlockChain + Send + Sync + 'static, { -let _ = thread::Builder::new() - .name("apis".to_string()) - .spawn(move || { + let _ = thread::Builder::new() + .name("apis".to_string()) + .spawn(move || { // build handlers and register them under the appropriate endpoint let utxo_handler = UtxoHandler { chain: chain.clone(), @@ -520,7 +521,7 @@ let _ = thread::Builder::new() peers: peers.clone(), }; - let route_list = vec!( + let route_list = vec![ "get blocks".to_string(), "get chain".to_string(), "get chain/utxos".to_string(), @@ -531,10 +532,11 @@ let _ = thread::Builder::new() "get pool".to_string(), "post pool/push".to_string(), "post peers/a.b.c.d:p/ban".to_string(), + "post peers/a.b.c.d:p/unban".to_string(), "get peers/all".to_string(), "get peers/connected".to_string(), "get peers/a.b.c.d".to_string(), - ); + ]; // We allow manually banning, like this: // curl -v -X POST http://127.0.0.1:13413/v1/peers/88.99.251.87:13414/ban let index_handler = IndexHandler { list: route_list }; @@ -559,5 +561,5 @@ let _ = thread::Builder::new() apis.start(&addr[..]).unwrap_or_else(|e| { error!(LOGGER, "Failed to start API HTTP server: {}.", e); }); - }); + }); } diff --git a/p2p/src/peers.rs b/p2p/src/peers.rs index 55b94769..f064dfcc 100644 --- a/p2p/src/peers.rs +++ b/p2p/src/peers.rs @@ -194,6 +194,22 @@ impl Peers { } } + /// Unbans a peer, checks if it exists and banned then unban + pub fn unban_peer(&self, peer_addr: &SocketAddr) { + match self.get_peer(peer_addr.clone()) { + Ok(_) => { + if self.is_banned(peer_addr.clone()) { + if let Err(e) = self.update_state(peer_addr.clone(), State::Healthy) { + error!(LOGGER, "Couldn't unban {}: {:?}", peer_addr, e) + } + } else { + error!(LOGGER, "Couldn't unban {}: peer is not banned", peer_addr) + } + }, + Err(e) => error!(LOGGER, "Couldn't unban {}: {:?}", peer_addr, e) + }; + } + /// Broadcasts the provided block to PEER_PREFERRED_COUNT of our peers. /// We may be connected to PEER_MAX_COUNT peers so we only /// want to broadcast to a random subset of peers.