diff --git a/api/src/client.rs b/api/src/client.rs index 80e8df75d..5a5838be5 100644 --- a/api/src/client.rs +++ b/api/src/client.rs @@ -17,7 +17,7 @@ use hyper; use hyper::client::Response; use hyper::status::{StatusClass, StatusCode}; -use serde::{Serialize, Deserialize}; +use serde::{Deserialize, Serialize}; use serde_json; use rest::Error; @@ -26,12 +26,14 @@ use rest::Error; /// returns a JSON object. Handles request building, JSON deserialization and /// response code checking. pub fn get<'a, T>(url: &'a str) -> Result - where for<'de> T: Deserialize<'de> +where + for<'de> T: Deserialize<'de>, { let client = hyper::Client::new(); let res = check_error(client.get(url).send())?; - serde_json::from_reader(res) - .map_err(|e| Error::Internal(format!("Server returned invalid JSON: {}", e))) + serde_json::from_reader(res).map_err(|e| { + Error::Internal(format!("Server returned invalid JSON: {}", e)) + }) } /// Helper function to easily issue a HTTP POST request with the provided JSON @@ -39,15 +41,18 @@ pub fn get<'a, T>(url: &'a str) -> Result /// building, JSON serialization and deserialization, and response code /// checking. pub fn post<'a, IN, OUT>(url: &'a str, input: &IN) -> Result - where IN: Serialize, - for<'de> OUT: Deserialize<'de> +where + IN: Serialize, + for<'de> OUT: Deserialize<'de>, { - let in_json = serde_json::to_string(input) - .map_err(|e| Error::Internal(format!("Could not serialize data to JSON: {}", e)))?; + let in_json = serde_json::to_string(input).map_err(|e| { + Error::Internal(format!("Could not serialize data to JSON: {}", e)) + })?; let client = hyper::Client::new(); let res = check_error(client.post(url).body(&mut in_json.as_bytes()).send())?; - serde_json::from_reader(res) - .map_err(|e| Error::Internal(format!("Server returned invalid JSON: {}", e))) + serde_json::from_reader(res).map_err(|e| { + Error::Internal(format!("Server returned invalid JSON: {}", e)) + }) } // convert hyper error and check for non success response codes @@ -59,13 +64,11 @@ fn check_error(res: hyper::Result) -> Result { match response.status.class() { StatusClass::Success => Ok(response), StatusClass::ServerError => Err(Error::Internal(format!("Server error."))), - StatusClass::ClientError => { - if response.status == StatusCode::NotFound { - Err(Error::NotFound) - } else { - Err(Error::Argument(format!("Argument error"))) - } - } + StatusClass::ClientError => if response.status == StatusCode::NotFound { + Err(Error::NotFound) + } else { + Err(Error::Argument(format!("Argument error"))) + }, _ => Err(Error::Internal(format!("Unrecognized error."))), } } diff --git a/api/src/endpoints.rs b/api/src/endpoints.rs deleted file mode 100644 index 9a630ef39..000000000 --- a/api/src/endpoints.rs +++ /dev/null @@ -1,127 +0,0 @@ -// Copyright 2016 The Grin Developers -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - - -use std::sync::{Arc, RwLock}; -use std::thread; - -use chain; -use core::core::Transaction; -use core::ser; -use pool; -use handlers::{UtxoHandler, ChainHandler, SumTreeHandler}; -use rest::*; -use types::*; -use util; -use util::LOGGER; - -/// ApiEndpoint implementation for the transaction pool, to check its status -/// and size as well as push new transactions. -#[derive(Clone)] -pub struct PoolApi { - tx_pool: Arc>>, -} - -impl ApiEndpoint for PoolApi -where - T: pool::BlockChain + Clone + Send + Sync + 'static, -{ - type ID = String; - type T = PoolInfo; - type OP_IN = TxWrapper; - type OP_OUT = (); - - fn operations(&self) -> Vec { - vec![Operation::Get, Operation::Custom("push".to_string())] - } - - fn get(&self, _: String) -> ApiResult { - let pool = self.tx_pool.read().unwrap(); - Ok(PoolInfo { - pool_size: pool.pool_size(), - orphans_size: pool.orphans_size(), - total_size: pool.total_size(), - }) - } - - fn operation(&self, _: String, input: TxWrapper) -> ApiResult<()> { - let tx_bin = util::from_hex(input.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(), - ) - })?; - - let source = pool::TxSource { - debug_name: "push-api".to_string(), - identifier: "?.?.?.?".to_string(), - }; - info!( - LOGGER, - "Pushing transaction with {} inputs and {} outputs to pool.", - tx.inputs.len(), - tx.outputs.len() - ); - self.tx_pool - .write() - .unwrap() - .add_to_memory_pool(source, tx) - .map_err(|e| { - Error::Internal(format!("Addition to transaction pool failed: {:?}", e)) - })?; - - Ok(()) - } -} - -/// Dummy wrapper for the hex-encoded serialized transaction. -#[derive(Serialize, Deserialize)] -pub struct TxWrapper { - tx_hex: String, -} - -/// Start all server REST APIs. Just register all of them on a ApiServer -/// instance and runs the corresponding HTTP server. -pub fn start_rest_apis( - addr: String, - chain: Arc, - tx_pool: Arc>>, -) where - T: pool::BlockChain + Clone + Send + Sync + 'static, -{ - - thread::spawn(move || { - let mut apis = ApiServer::new("/v1".to_string()); - apis.register_endpoint("/pool".to_string(), PoolApi {tx_pool: tx_pool}); - - // register a nested router at "/v2" for flexibility - // so we can experiment with raw iron handlers - let utxo_handler = UtxoHandler {chain: chain.clone()}; - let chain_tip_handler = ChainHandler {chain: chain.clone()}; - let sumtree_handler = SumTreeHandler {chain: chain.clone()}; - let router = router!( - chain_tip: get "/chain" => chain_tip_handler, - chain_utxos: get "/chain/utxos" => utxo_handler, - sumtree_roots: get "/sumtrees/*" => sumtree_handler, - ); - apis.register_handler("/v2", router); - - apis.start(&addr[..]).unwrap_or_else(|e| { - error!(LOGGER, "Failed to start API HTTP server: {}.", e); - }); - }); -} diff --git a/api/src/handlers.rs b/api/src/handlers.rs index 5e3187fad..f077c38b2 100644 --- a/api/src/handlers.rs +++ b/api/src/handlers.rs @@ -12,37 +12,45 @@ // See the License for the specific language governing permissions and // limitations under the License. - -use std::sync::Arc; +use std::io::Read; +use std::sync::{Arc, RwLock}; +use std::thread; use iron::prelude::*; use iron::Handler; use iron::status; use urlencoded::UrlEncodedQuery; +use serde::Serialize; use serde_json; use chain; +use core::core::Transaction; +use core::ser; +use pool; use rest::*; -use types::*; use util::secp::pedersen::Commitment; +use types::*; use util; use util::LOGGER; -pub struct UtxoHandler { - pub chain: Arc, +// Supports retrieval of multiple outputs in a single request - +// GET /v1/chain/utxos?id=xxx,yyy,zzz +// GET /v1/chain/utxos?id=xxx&id=yyy&id=zzz +struct UtxoHandler { + chain: Arc, } impl UtxoHandler { fn get_utxo(&self, id: &str) -> 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) + let out = self.chain + .get_unspent(&commit) .map_err(|_| Error::NotFound)?; let header = self.chain @@ -53,11 +61,6 @@ impl UtxoHandler { } } -// -// Supports retrieval of multiple outputs in a single request - -// GET /v2/chain/utxos?id=xxx,yyy,zzz -// GET /v2/chain/utxos?id=xxx&id=yyy&id=zzz -// impl Handler for UtxoHandler { fn handle(&self, req: &mut Request) -> IronResult { let mut commitments: Vec<&str> = vec![]; @@ -72,60 +75,49 @@ impl Handler for UtxoHandler { } let mut utxos: Vec = vec![]; - for commit in commitments { if let Ok(out) = self.get_utxo(commit) { utxos.push(out); } } - - match serde_json::to_string(&utxos) { - Ok(json) => Ok(Response::with((status::Ok, json))), - Err(_) => Ok(Response::with((status::BadRequest, ""))), - } + json_response(&utxos) } } -// Sum tree handler - -pub struct SumTreeHandler { - pub chain: Arc, +// Sum tree handler. Retrieve the roots: +// GET /v1/sumtrees/roots +// +// Last inserted nodes:: +// GET /v1/sumtrees/lastutxos (gets last 10) +// GET /v1/sumtrees/lastutxos?n=5 +// GET /v1/sumtrees/lastrangeproofs +// GET /v1/sumtrees/lastkernels +struct SumTreeHandler { + chain: Arc, } impl SumTreeHandler { - //gets roots + // gets roots fn get_roots(&self) -> SumTrees { SumTrees::from_head(self.chain.clone()) } // gets last n utxos inserted in to the tree - fn get_last_n_utxo(&self, distance:u64) -> Vec { + fn get_last_n_utxo(&self, distance: u64) -> Vec { SumTreeNode::get_last_n_utxo(self.chain.clone(), distance) } // gets last n utxos inserted in to the tree - fn get_last_n_rangeproof(&self, distance:u64) -> Vec { + fn get_last_n_rangeproof(&self, distance: u64) -> Vec { SumTreeNode::get_last_n_rangeproof(self.chain.clone(), distance) } // gets last n utxos inserted in to the tree - fn get_last_n_kernel(&self, distance:u64) -> Vec { + fn get_last_n_kernel(&self, distance: u64) -> Vec { SumTreeNode::get_last_n_kernel(self.chain.clone(), distance) } - } -// -// Retrieve the roots: -// GET /v2/sumtrees/roots -// -// Last inserted nodes:: -// GET /v2/sumtrees/lastutxos (gets last 10) -// GET /v2/sumtrees/lastutxos?n=5 -// GET /v2/sumtrees/lastrangeproofs -// GET /v2/sumtrees/lastkernels -// - impl Handler for SumTreeHandler { fn handle(&self, req: &mut Request) -> IronResult { let url = req.url.clone(); @@ -133,40 +125,29 @@ impl Handler for SumTreeHandler { if *path_elems.last().unwrap() == "" { path_elems.pop(); } - //TODO: probably need to set a reasonable max limit here - let mut last_n=10; + // TODO: probably need to set a reasonable max limit here + let mut last_n = 10; if let Ok(params) = req.get_ref::() { if let Some(nums) = params.get("n") { for num in nums { if let Ok(n) = str::parse(num) { - last_n=n; + last_n = n; } } } } - match *path_elems.last().unwrap(){ - "roots" => match serde_json::to_string_pretty(&self.get_roots()) { - Ok(json) => Ok(Response::with((status::Ok, json))), - Err(_) => Ok(Response::with((status::BadRequest, ""))), - }, - "lastutxos" => match serde_json::to_string_pretty(&self.get_last_n_utxo(last_n)) { - Ok(json) => Ok(Response::with((status::Ok, json))), - Err(_) => Ok(Response::with((status::BadRequest, ""))), - }, - "lastrangeproofs" => match serde_json::to_string_pretty(&self.get_last_n_rangeproof(last_n)) { - Ok(json) => Ok(Response::with((status::Ok, json))), - Err(_) => Ok(Response::with((status::BadRequest, ""))), - }, - "lastkernels" => match serde_json::to_string_pretty(&self.get_last_n_kernel(last_n)) { - Ok(json) => Ok(Response::with((status::Ok, json))), - Err(_) => Ok(Response::with((status::BadRequest, ""))), - },_ => Ok(Response::with((status::BadRequest, ""))) + match *path_elems.last().unwrap() { + "roots" => json_response(&self.get_roots()), + "lastutxos" => json_response(&self.get_last_n_utxo(last_n)), + "lastrangeproofs" => json_response(&self.get_last_n_rangeproof(last_n)), + "lastkernels" => json_response(&self.get_last_n_kernel(last_n)), + _ => Ok(Response::with((status::BadRequest, ""))), } } } -// Chain Handler - +// Chain handler. Get the head details. +// GET /v1/chain pub struct ChainHandler { pub chain: Arc, } @@ -177,16 +158,134 @@ impl ChainHandler { } } -// -// Get the head details -// GET /v2/chain -// - impl Handler for ChainHandler { fn handle(&self, _req: &mut Request) -> IronResult { - match serde_json::to_string_pretty(&self.get_tip()) { - Ok(json) => Ok(Response::with((status::Ok, json))), - Err(_) => Ok(Response::with((status::BadRequest, ""))), - } + json_response(&self.get_tip()) } } + +// Get basic information about the transaction pool. +struct PoolInfoHandler { + tx_pool: Arc>>, +} + +impl Handler for PoolInfoHandler +where + T: pool::BlockChain + Send + Sync + 'static, +{ + fn handle(&self, _req: &mut Request) -> IronResult { + let pool = self.tx_pool.read().unwrap(); + json_response(&PoolInfo { + pool_size: pool.pool_size(), + orphans_size: pool.orphans_size(), + total_size: pool.total_size(), + }) + } +} + +/// Dummy wrapper for the hex-encoded serialized transaction. +#[derive(Serialize, Deserialize)] +struct TxWrapper { + tx_hex: String, +} + +// Push new transactions to our transaction pool, that should broadcast it +// to the network if valid. +struct PoolPushHandler { + tx_pool: Arc>>, +} + +impl Handler for PoolPushHandler +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 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()) + })?; + + let source = pool::TxSource { + debug_name: "push-api".to_string(), + identifier: "?.?.?.?".to_string(), + }; + info!( + LOGGER, + "Pushing transaction with {} inputs and {} outputs to pool.", + tx.inputs.len(), + tx.outputs.len() + ); + self.tx_pool + .write() + .unwrap() + .add_to_memory_pool(source, tx) + .map_err(|e| { + Error::Internal(format!("Addition to transaction pool failed: {:?}", e)) + })?; + + Ok(Response::with(status::Ok)) + } +} + +// Utility to serialize a struct into JSON and produce a sensible IronResult +// out of it. +fn json_response(s: &T) -> IronResult +where + T: Serialize, +{ + match serde_json::to_string_pretty(s) { + Ok(json) => Ok(Response::with((status::Ok, json))), + Err(_) => Ok(Response::with((status::InternalServerError, ""))), + } +} + +/// Start all server HTTP handlers. Register all of them with Iron +/// and runs the corresponding HTTP server. +pub fn start_rest_apis( + addr: String, + chain: Arc, + tx_pool: Arc>>, +) where + T: pool::BlockChain + Send + Sync + 'static, +{ + thread::spawn(move || { + // build handlers and register them under the appropriate endpoint + let utxo_handler = UtxoHandler { + chain: chain.clone(), + }; + let chain_tip_handler = ChainHandler { + chain: chain.clone(), + }; + let sumtree_handler = SumTreeHandler { + chain: chain.clone(), + }; + let pool_info_handler = PoolInfoHandler { + tx_pool: tx_pool.clone(), + }; + let pool_push_handler = PoolPushHandler { + tx_pool: tx_pool.clone(), + }; + + let router = router!( + chain_tip: get "/chain" => chain_tip_handler, + chain_utxos: get "/chain/utxos" => utxo_handler, + sumtree_roots: get "/sumtrees/*" => sumtree_handler, + pool_info: get "/pool" => pool_info_handler, + pool_push: post "/pool/push" => pool_push_handler, + ); + + let mut apis = ApiServer::new("/v1".to_string()); + apis.register_handler(router); + + info!(LOGGER, "Starting HTTP API server at {}.", addr); + apis.start(&addr[..]).unwrap_or_else(|e| { + error!(LOGGER, "Failed to start API HTTP server: {}.", e); + }); + }); +} diff --git a/api/src/lib.rs b/api/src/lib.rs index cf344c6a3..4afd613b9 100644 --- a/api/src/lib.rs +++ b/api/src/lib.rs @@ -12,31 +12,30 @@ // See the License for the specific language governing permissions and // limitations under the License. -extern crate grin_core as core; extern crate grin_chain as chain; +extern crate grin_core as core; extern crate grin_pool as pool; extern crate grin_store as store; extern crate grin_util as util; extern crate hyper; -#[macro_use] -extern crate slog; extern crate iron; -extern crate urlencoded; +extern crate mount; #[macro_use] extern crate router; -extern crate mount; extern crate serde; #[macro_use] extern crate serde_derive; extern crate serde_json; +#[macro_use] +extern crate slog; +extern crate urlencoded; pub mod client; -mod endpoints; mod handlers; mod rest; mod types; -pub use endpoints::start_rest_apis; +pub use handlers::start_rest_apis; pub use types::*; pub use rest::*; diff --git a/api/src/rest.rs b/api/src/rest.rs index 3dda86fc2..0db3c5ce3 100644 --- a/api/src/rest.rs +++ b/api/src/rest.rs @@ -19,26 +19,18 @@ //! register them on a ApiServer. use std::error; -use std::fmt::{self, Display, Debug, Formatter}; -use std::io::Read; +use std::fmt::{self, Display, Formatter}; use std::net::ToSocketAddrs; use std::string::ToString; -use std::str::FromStr; use std::mem; use iron::prelude::*; -use iron::{status, headers, Listening}; -use iron::method::Method; -use iron::modifiers::Header; +use iron::{status, Listening}; use iron::middleware::Handler; use router::Router; use mount::Mount; -use serde::Serialize; -use serde::de::DeserializeOwned; -use serde_json; use store; -use util::LOGGER; /// Errors that can be returned by an ApiEndpoint implementation. #[derive(Debug)] @@ -87,161 +79,6 @@ impl From for Error { } } -#[derive(Debug, Clone)] -#[allow(dead_code)] -pub enum Operation { - Create, - Delete, - Update, - Get, - Custom(String), -} - -impl Operation { - fn to_method(&self) -> Method { - match *self { - Operation::Create => Method::Post, - Operation::Delete => Method::Delete, - Operation::Update => Method::Put, - Operation::Get => Method::Get, - Operation::Custom(_) => Method::Post, - } - } -} - -pub type ApiResult = ::std::result::Result; - -/// Trait to implement to expose a service as a RESTful HTTP endpoint. Each -/// method corresponds to a specific relative URL and HTTP method following -/// basic REST principles: -/// -/// * create: POST / -/// * get: GET /:id -/// * update: PUT /:id -/// * delete: DELETE /:id -/// -/// The methods method defines which operation the endpoint implements, they're -/// all optional by default. It also allows the framework to automatically -/// define the OPTIONS HTTP method. -/// -/// The type accepted by create and update, and returned by get, must implement -/// the serde Serialize and Deserialize traits. The identifier type returned by -/// create and accepted by all other methods must have a string representation. -pub trait ApiEndpoint: Clone + Send + Sync + 'static { - type ID: ToString + FromStr; - type T: Serialize + DeserializeOwned; - type OP_IN: Serialize + DeserializeOwned; - type OP_OUT: Serialize + DeserializeOwned; - - fn operations(&self) -> Vec; - - #[allow(unused_variables)] - fn create(&self, o: Self::T) -> ApiResult { - unimplemented!() - } - - #[allow(unused_variables)] - fn delete(&self, id: Self::ID) -> ApiResult<()> { - unimplemented!() - } - - #[allow(unused_variables)] - fn update(&self, id: Self::ID, o: Self::T) -> ApiResult<()> { - unimplemented!() - } - - #[allow(unused_variables)] - fn get(&self, id: Self::ID) -> ApiResult { - unimplemented!() - } - - #[allow(unused_variables)] - fn operation(&self, op: String, input: Self::OP_IN) -> ApiResult { - unimplemented!() - } -} - -// Wrapper required to define the implementation below, Rust doesn't let us -// define the parametric implementation for trait from another crate. -struct ApiWrapper(E); - -impl Handler for ApiWrapper - where E: ApiEndpoint, - <::ID as FromStr>::Err: Debug + Send + error::Error -{ - fn handle(&self, req: &mut Request) -> IronResult { - match req.method { - Method::Get => { - let res = self.0.get(extract_param(req, "id")?)?; - let res_json = serde_json::to_string(&res) - .map_err(|e| IronError::new(e, status::InternalServerError))?; - Ok(Response::with((status::Ok, res_json))) - } - Method::Put => { - let id = extract_param(req, "id")?; - let t: E::T = serde_json::from_reader(req.body.by_ref()) - .map_err(|e| IronError::new(e, status::BadRequest))?; - self.0.update(id, t)?; - Ok(Response::with(status::NoContent)) - } - Method::Delete => { - let id = extract_param(req, "id")?; - self.0.delete(id)?; - Ok(Response::with(status::NoContent)) - } - Method::Post => { - let t: E::T = serde_json::from_reader(req.body.by_ref()) - .map_err(|e| IronError::new(e, status::BadRequest))?; - let id = self.0.create(t)?; - Ok(Response::with((status::Created, id.to_string()))) - } - _ => Ok(Response::with(status::MethodNotAllowed)), - } - } -} - -struct OpWrapper { - operation: String, - endpoint: E, -} - -impl Handler for OpWrapper - where E: ApiEndpoint -{ - fn handle(&self, req: &mut Request) -> IronResult { - let t: E::OP_IN = serde_json::from_reader(req.body.by_ref()).map_err(|e| { - IronError::new(e, status::BadRequest) - })?; - let res = self.endpoint.operation(self.operation.clone(), t); - match res { - Ok(resp) => { - let res_json = serde_json::to_string(&resp).map_err(|e| { - IronError::new(e, status::InternalServerError) - })?; - Ok(Response::with((status::Ok, res_json))) - } - Err(e) => { - error!(LOGGER, "API operation: {:?}", e); - Err(IronError::from(e)) - } - } - } -} - -fn extract_param(req: &mut Request, param: &'static str) -> IronResult - where ID: ToString + FromStr, - ::Err: Debug + Send + error::Error + 'static -{ - - let id = req.extensions - .get::() - .unwrap() - .find(param) - .unwrap_or(""); - id.parse::() - .map_err(|e| IronError::new(e, status::BadRequest)) -} - /// HTTP server allowing the registration of ApiEndpoint implementations. pub struct ApiServer { root: String, @@ -281,119 +118,7 @@ impl ApiServer { } /// Registers an iron handler (via mount) - pub fn register_handler(&mut self, route: &str, handler: H) -> &mut Mount { - self.mount.mount(route, handler) - } - - /// Register a new API endpoint, providing a relative URL for the new - /// endpoint. - pub fn register_endpoint(&mut self, subpath: String, endpoint: E) - where E: ApiEndpoint, - <::ID as FromStr>::Err: Debug + Send + error::Error - { - assert_eq!(subpath.chars().nth(0).unwrap(), '/'); - - // declare a route for each method actually implemented by the endpoint - let route_postfix = &subpath[1..]; - let root = self.root.clone() + &subpath; - for op in endpoint.operations() { - let route_name = format!("{:?}_{}", op, route_postfix); - - // special case of custom operations - if let Operation::Custom(op_s) = op.clone() { - let wrapper = OpWrapper { - operation: op_s.clone(), - endpoint: endpoint.clone(), - }; - let full_path = format!("{}/{}", root.clone(), op_s.clone()); - self.router - .route(op.to_method(), full_path.clone(), wrapper, route_name); - info!(LOGGER, "route: POST {}", full_path); - } else { - - // regular REST operations - let full_path = match op.clone() { - Operation::Get => root.clone() + "/:id", - Operation::Update => root.clone() + "/:id", - Operation::Delete => root.clone() + "/:id", - Operation::Create => root.clone(), - _ => panic!("unreachable"), - }; - let wrapper = ApiWrapper(endpoint.clone()); - self.router - .route(op.to_method(), full_path.clone(), wrapper, route_name); - info!(LOGGER, "route: {} {}", op.to_method(), full_path); - } - } - - // support for the HTTP Options method by differentiating what's on the - // root resource vs the id resource - let (root_opts, sub_opts) = endpoint - .operations() - .iter() - .fold((vec![], vec![]), |mut acc, op| { - let m = op.to_method(); - if m == Method::Post { - acc.0.push(m); - } else { - acc.1.push(m); - } - acc - }); - self.router.options( - root.clone(), - move |_: &mut Request| { - Ok(Response::with((status::Ok, Header(headers::Allow(root_opts.clone()))))) - }, - "option_".to_string() + route_postfix, - ); - self.router.options( - root.clone() + "/:id", - move |_: &mut Request| { - Ok(Response::with((status::Ok, Header(headers::Allow(sub_opts.clone()))))) - }, - "option_id_".to_string() + route_postfix, - ); - } -} - - -#[cfg(test)] -mod test { - use super::*; - - #[derive(Serialize, Deserialize)] - pub struct Animal { - name: String, - legs: u32, - lethal: bool, - } - - #[derive(Clone)] - pub struct TestApi; - - impl ApiEndpoint for TestApi { - type ID = String; - type T = Animal; - type OP_IN = (); - type OP_OUT = (); - - fn operations(&self) -> Vec { - vec![Operation::Get] - } - - fn get(&self, name: String) -> ApiResult { - Ok(Animal { - name: name, - legs: 4, - lethal: false, - }) - } - } - - #[test] - fn req_chain_json() { - let mut apis = ApiServer::new("/v1".to_string()); - apis.register_endpoint("/animal".to_string(), TestApi); + pub fn register_handler(&mut self, handler: H) -> &mut Mount { + self.mount.mount(&self.root, handler) } } diff --git a/api/src/types.rs b/api/src/types.rs index 1c6051a57..bc61eb523 100644 --- a/api/src/types.rs +++ b/api/src/types.rs @@ -44,7 +44,7 @@ impl Tip { } } -/// Sumtrees +/// Sumtrees #[derive(Serialize, Deserialize, Debug, Clone)] pub struct SumTrees { /// UTXO Root Hash @@ -59,7 +59,7 @@ pub struct SumTrees { impl SumTrees { pub fn from_head(head: Arc) -> SumTrees { - let roots=head.get_sumtree_roots(); + let roots = head.get_sumtree_roots(); SumTrees { utxo_root_hash: util::to_hex(roots.0.hash.to_vec()), utxo_root_sum: util::to_hex(roots.0.sum.commit.0.to_vec()), @@ -80,14 +80,13 @@ pub struct SumTreeNode { } impl SumTreeNode { - - pub fn get_last_n_utxo(chain: Arc, distance:u64) -> Vec { + pub fn get_last_n_utxo(chain: Arc, distance: u64) -> Vec { let mut return_vec = Vec::new(); let last_n = chain.get_last_n_utxo(distance); for elem_output in last_n { let header = chain - .get_block_header_by_output_commit(&elem_output.1.commit) - .map_err(|_| Error::NotFound); + .get_block_header_by_output_commit(&elem_output.1.commit) + .map_err(|_| Error::NotFound); // Need to call further method to check if output is spent let mut output = OutputPrintable::from_output(&elem_output.1, &header.unwrap()); if let Ok(_) = chain.get_unspent(&elem_output.1.commit) { @@ -101,7 +100,7 @@ impl SumTreeNode { return_vec } - pub fn get_last_n_rangeproof(head: Arc, distance:u64) -> Vec { + pub fn get_last_n_rangeproof(head: Arc, distance: u64) -> Vec { let mut return_vec = Vec::new(); let last_n = head.get_last_n_rangeproof(distance); for elem in last_n { @@ -113,7 +112,7 @@ impl SumTreeNode { return_vec } - pub fn get_last_n_kernel(head: Arc, distance:u64) -> Vec { + pub fn get_last_n_kernel(head: Arc, distance: u64) -> Vec { let mut return_vec = Vec::new(); let last_n = head.get_last_n_kernel(distance); for elem in last_n { @@ -149,9 +148,10 @@ pub struct Output { impl Output { pub fn from_output(output: &core::Output, block_header: &core::BlockHeader) -> Output { let (output_type, lock_height) = match output.features { - x if x.contains(core::transaction::COINBASE_OUTPUT) => { - (OutputType::Coinbase, block_header.height + global::coinbase_maturity()) - } + x if x.contains(core::transaction::COINBASE_OUTPUT) => ( + OutputType::Coinbase, + block_header.height + global::coinbase_maturity(), + ), _ => (OutputType::Transaction, 0), }; @@ -165,12 +165,13 @@ impl Output { } } -//As above, except formatted a bit better for human viewing +// As above, except formatted a bit better for human viewing #[derive(Debug, Serialize, Deserialize, Clone)] pub struct OutputPrintable { /// The type of output Coinbase|Transaction pub output_type: OutputType, - /// The homomorphic commitment representing the output's amount (as hex string) + /// The homomorphic commitment representing the output's amount (as hex + /// string) pub commit: String, /// The height of the block creating this output pub height: u64, @@ -185,9 +186,10 @@ pub struct OutputPrintable { impl OutputPrintable { pub fn from_output(output: &core::Output, block_header: &core::BlockHeader) -> OutputPrintable { let (output_type, lock_height) = match output.features { - x if x.contains(core::transaction::COINBASE_OUTPUT) => { - (OutputType::Coinbase, block_header.height + global::coinbase_maturity()) - } + x if x.contains(core::transaction::COINBASE_OUTPUT) => ( + OutputType::Coinbase, + block_header.height + global::coinbase_maturity(), + ), _ => (OutputType::Transaction, 0), }; OutputPrintable { diff --git a/chain/src/chain.rs b/chain/src/chain.rs index a9299be8b..3c660492e 100644 --- a/chain/src/chain.rs +++ b/chain/src/chain.rs @@ -20,8 +20,8 @@ use std::sync::{Arc, Mutex, RwLock}; use util::secp::pedersen::{Commitment, RangeProof}; -use core::core::{SumCommit}; -use core::core::pmmr::{NoSum, HashSum}; +use core::core::SumCommit; +use core::core::pmmr::{HashSum, NoSum}; use core::core::{Block, BlockHeader, Output, TxKernel}; use core::core::target::Difficulty; @@ -119,8 +119,10 @@ impl Chain { /// has been added to the longest chain, None if it's added to an (as of /// now) orphan chain. pub fn process_block(&self, b: Block, opts: Options) -> Result, Error> { - let head = self.store.head().map_err(|e| Error::StoreErr(e, "chain load head".to_owned()))?; - let height = head.height; + let head = self.store + .head() + .map_err(|e| Error::StoreErr(e, "chain load head".to_owned()))?; + let height = head.height; let ctx = self.ctx_from_head(head, opts); let res = pipe::process_block(&b, ctx); @@ -143,13 +145,11 @@ impl Chain { self.check_orphans(); } Ok(None) => {} - Err(Error::Orphan) => { - if b.header.height < height + (MAX_ORPHANS as u64) { - let mut orphans = self.orphans.lock().unwrap(); - orphans.push_front((opts, b)); - orphans.truncate(MAX_ORPHANS); - } - } + Err(Error::Orphan) => if b.header.height < height + (MAX_ORPHANS as u64) { + let mut orphans = self.orphans.lock().unwrap(); + orphans.push_front((opts, b)); + orphans.truncate(MAX_ORPHANS); + }, Err(ref e) => { info!( LOGGER, @@ -171,8 +171,9 @@ impl Chain { bh: &BlockHeader, opts: Options, ) -> Result, Error> { - - let head = self.store.get_header_head().map_err(|e| Error::StoreErr(e, "chain header head".to_owned()))?; + let head = self.store + .get_header_head() + .map_err(|e| Error::StoreErr(e, "chain header head".to_owned()))?; let ctx = self.ctx_from_head(head, opts); pipe::process_block_header(bh, ctx) @@ -199,7 +200,7 @@ impl Chain { /// Pop orphans out of the queue and check if we can now accept them. fn check_orphans(&self) { // first check how many we have to retry, unfort. we can't extend the lock - // in the loop as it needs to be freed before going in process_block + // in the loop as it needs to be freed before going in process_block let orphan_count; { let orphans = self.orphans.lock().unwrap(); @@ -227,9 +228,9 @@ impl Chain { let sumtrees = self.sumtrees.read().unwrap(); let is_unspent = sumtrees.is_unspent(output_ref)?; if is_unspent { - self.store.get_output_by_commit(output_ref).map_err(|e| - Error::StoreErr(e, "chain get unspent".to_owned()) - ) + self.store + .get_output_by_commit(output_ref) + .map_err(|e| Error::StoreErr(e, "chain get unspent".to_owned())) } else { Err(Error::OutputNotFound) } @@ -254,9 +255,13 @@ impl Chain { } /// returs sumtree roots - pub fn get_sumtree_roots(&self) -> (HashSum, + pub fn get_sumtree_roots( + &self, + ) -> ( + HashSum, HashSum>, - HashSum>) { + HashSum>, + ) { let mut sumtrees = self.sumtrees.write().unwrap(); sumtrees.roots() } @@ -264,10 +269,10 @@ impl Chain { /// returns the last n nodes inserted into the utxo sum tree /// returns sum tree hash plus output itself (as the sum is contained /// in the output anyhow) - pub fn get_last_n_utxo(&self, distance: u64) -> Vec<(Hash, Output)>{ + pub fn get_last_n_utxo(&self, distance: u64) -> Vec<(Hash, Output)> { let mut sumtrees = self.sumtrees.write().unwrap(); let mut return_vec = Vec::new(); - let sum_nodes=sumtrees.last_n_utxo(distance); + let sum_nodes = sumtrees.last_n_utxo(distance); for sum_commit in sum_nodes { let output = self.store.get_output_by_commit(&sum_commit.sum.commit); return_vec.push((sum_commit.hash, output.unwrap())); @@ -276,13 +281,13 @@ impl Chain { } /// as above, for rangeproofs - pub fn get_last_n_rangeproof(&self, distance: u64) -> Vec>>{ + pub fn get_last_n_rangeproof(&self, distance: u64) -> Vec>> { let mut sumtrees = self.sumtrees.write().unwrap(); sumtrees.last_n_rangeproof(distance) } /// as above, for kernels - pub fn get_last_n_kernel(&self, distance: u64) -> Vec>>{ + pub fn get_last_n_kernel(&self, distance: u64) -> Vec>> { let mut sumtrees = self.sumtrees.write().unwrap(); sumtrees.last_n_kernel(distance) } @@ -299,24 +304,30 @@ impl Chain { /// Block header for the chain head pub fn head_header(&self) -> Result { - self.store.head_header().map_err(|e| Error::StoreErr(e, "chain head header".to_owned())) + self.store + .head_header() + .map_err(|e| Error::StoreErr(e, "chain head header".to_owned())) } /// Gets a block header by hash pub fn get_block(&self, h: &Hash) -> Result { - self.store.get_block(h).map_err(|e| Error::StoreErr(e, "chain get block".to_owned())) + self.store + .get_block(h) + .map_err(|e| Error::StoreErr(e, "chain get block".to_owned())) } /// Gets a block header by hash pub fn get_block_header(&self, h: &Hash) -> Result { - self.store.get_block_header(h).map_err(|e| Error::StoreErr(e, "chain get header".to_owned())) + self.store + .get_block_header(h) + .map_err(|e| Error::StoreErr(e, "chain get header".to_owned())) } /// Gets the block header at the provided height pub fn get_header_by_height(&self, height: u64) -> Result { - self.store.get_header_by_height(height).map_err(|e| - Error::StoreErr(e, "chain get header by height".to_owned()), - ) + self.store.get_header_by_height(height).map_err(|e| { + Error::StoreErr(e, "chain get header by height".to_owned()) + }) } /// Gets the block header by the provided output commitment @@ -331,7 +342,9 @@ impl Chain { /// Get the tip of the header chain pub fn get_header_head(&self) -> Result { - self.store.get_header_head().map_err(|e |Error::StoreErr(e, "chain get header head".to_owned())) + self.store + .get_header_head() + .map_err(|e| Error::StoreErr(e, "chain get header head".to_owned())) } /// Builds an iterator on blocks starting from the current chain head and diff --git a/chain/src/lib.rs b/chain/src/lib.rs index 876bf16f2..b0ef92860 100644 --- a/chain/src/lib.rs +++ b/chain/src/lib.rs @@ -23,16 +23,16 @@ #[macro_use] extern crate bitflags; extern crate byteorder; -#[macro_use] -extern crate slog; extern crate serde; #[macro_use] extern crate serde_derive; +#[macro_use] +extern crate slog; extern crate time; extern crate grin_core as core; -extern crate grin_util as util; extern crate grin_store; +extern crate grin_util as util; mod chain; pub mod pipe; @@ -43,4 +43,4 @@ pub mod types; // Re-export the base interface pub use chain::Chain; -pub use types::{ChainStore, Tip, ChainAdapter, SYNC, NONE, SKIP_POW, EASY_POW, Options, Error}; +pub use types::{ChainAdapter, ChainStore, Error, Options, Tip, EASY_POW, NONE, SKIP_POW, SYNC}; diff --git a/chain/src/pipe.rs b/chain/src/pipe.rs index e8c16ae99..f24bf6b12 100644 --- a/chain/src/pipe.rs +++ b/chain/src/pipe.rs @@ -21,7 +21,7 @@ use time; use core::consensus; use core::core::hash::{Hash, Hashed}; -use core::core::{BlockHeader, Block}; +use core::core::{Block, BlockHeader}; use core::core::transaction; use types::*; use store; @@ -49,7 +49,7 @@ pub struct BlockContext { /// chain head if updated. pub fn process_block(b: &Block, mut ctx: BlockContext) -> Result, Error> { // TODO should just take a promise for a block with a full header so we don't - // spend resources reading the full block when its header is invalid + // spend resources reading the full block when its header is invalid info!( LOGGER, @@ -68,13 +68,13 @@ pub fn process_block(b: &Block, mut ctx: BlockContext) -> Result, Er let mut sumtrees = local_sumtrees.write().unwrap(); // update head now that we're in the lock - ctx.head = ctx.store.head(). - map_err(|e| Error::StoreErr(e, "pipe reload head".to_owned()))?; + ctx.head = ctx.store + .head() + .map_err(|e| Error::StoreErr(e, "pipe reload head".to_owned()))?; // start a chain extension unit of work dependent on the success of the - // internal validation and saving operations + // internal validation and saving operations sumtree::extending(&mut sumtrees, |mut extension| { - validate_block(b, &mut ctx, &mut extension)?; debug!( LOGGER, @@ -94,7 +94,6 @@ pub fn process_block(b: &Block, mut ctx: BlockContext) -> Result, Er /// Process the block header pub fn process_block_header(bh: &BlockHeader, mut ctx: BlockContext) -> Result, Error> { - info!( LOGGER, "Starting validation pipeline for block header {} at {}.", @@ -120,7 +119,7 @@ fn check_known(bh: Hash, ctx: &mut BlockContext) -> Result<(), Error> { } if let Ok(b) = ctx.store.get_block(&bh) { // there is a window where a block can be saved but the chain head not - // updated yet, we plug that window here by re-accepting the block + // updated yet, we plug that window here by re-accepting the block if b.header.total_difficulty <= ctx.head.total_difficulty { return Err(Error::Unfit("already in store".to_string())); } @@ -147,11 +146,11 @@ fn validate_header(header: &BlockHeader, ctx: &mut BlockContext) -> Result<(), E return Err(Error::InvalidBlockVersion(header.version)); } - if header.timestamp > - time::now_utc() + time::Duration::seconds(12 * (consensus::BLOCK_TIME_SEC as i64)) + if header.timestamp + > time::now_utc() + time::Duration::seconds(12 * (consensus::BLOCK_TIME_SEC as i64)) { // refuse blocks more than 12 blocks intervals in future (as in bitcoin) - // TODO add warning in p2p code if local time is too different from peers + // TODO add warning in p2p code if local time is too different from peers return Err(Error::InvalidBlockTime); } @@ -168,16 +167,16 @@ fn validate_header(header: &BlockHeader, ctx: &mut BlockContext) -> Result<(), E } // first I/O cost, better as late as possible - let prev = try!(ctx.store.get_block_header(&header.previous).map_err(|e| - Error::StoreErr(e, format!("previous block header {}", header.previous)), - )); + let prev = try!(ctx.store.get_block_header(&header.previous,).map_err(|e| { + Error::StoreErr(e, format!("previous block header {}", header.previous)) + },)); if header.height != prev.height + 1 { return Err(Error::InvalidBlockHeight); } if header.timestamp <= prev.timestamp && !global::is_automated_testing_mode() { // prevent time warp attacks and some timestamp manipulations by forcing strict - // time progression (but not in CI mode) + // time progression (but not in CI mode) return Err(Error::InvalidBlockTime); } @@ -189,9 +188,8 @@ fn validate_header(header: &BlockHeader, ctx: &mut BlockContext) -> Result<(), E } let diff_iter = store::DifficultyIter::from(header.previous, ctx.store.clone()); - let difficulty = consensus::next_difficulty(diff_iter).map_err(|e| { - Error::Other(e.to_string()) - })?; + let difficulty = + consensus::next_difficulty(diff_iter).map_err(|e| Error::Other(e.to_string()))?; if header.difficulty < difficulty { return Err(Error::DifficultyTooLow); } @@ -219,9 +217,8 @@ fn validate_block( // standard head extension ext.apply_block(b)?; } else { - // extending a fork, first identify the block where forking occurred - // keeping the hashes of blocks along the fork + // keeping the hashes of blocks along the fork let mut current = b.header.previous; let mut hashes = vec![]; loop { @@ -236,16 +233,12 @@ fn validate_block( } // rewind the sum trees up the forking block, providing the height of the - // forked block and the last commitment we want to rewind to + // forked block and the last commitment we want to rewind to let forked_block = ctx.store.get_block(¤t)?; if forked_block.header.height > 0 { let last_output = &forked_block.outputs[forked_block.outputs.len() - 1]; let last_kernel = &forked_block.kernels[forked_block.kernels.len() - 1]; - ext.rewind( - forked_block.header.height, - last_output, - last_kernel, - )?; + ext.rewind(forked_block.header.height, last_output, last_kernel)?; } // apply all forked blocks, including this new one @@ -257,10 +250,9 @@ fn validate_block( } let (utxo_root, rproof_root, kernel_root) = ext.roots(); - if utxo_root.hash != b.header.utxo_root || rproof_root.hash != b.header.range_proof_root || - kernel_root.hash != b.header.kernel_root + if utxo_root.hash != b.header.utxo_root || rproof_root.hash != b.header.range_proof_root + || kernel_root.hash != b.header.kernel_root { - ext.dump(false); return Err(Error::InvalidRoot); } @@ -269,14 +261,11 @@ fn validate_block( for input in &b.inputs { if let Ok(output) = ctx.store.get_output_by_commit(&input.commitment()) { if output.features.contains(transaction::COINBASE_OUTPUT) { - if let Ok(output_header) = - ctx.store.get_block_header_by_output_commit( - &input.commitment(), - ) + if let Ok(output_header) = ctx.store + .get_block_header_by_output_commit(&input.commitment()) { - // TODO - make sure we are not off-by-1 here vs. the equivalent tansaction - // validation rule + // validation rule if b.header.height <= output_header.height + global::coinbase_maturity() { return Err(Error::ImmatureCoinbase); } @@ -290,12 +279,16 @@ fn validate_block( /// Officially adds the block to our chain. fn add_block(b: &Block, ctx: &mut BlockContext) -> Result<(), Error> { - ctx.store.save_block(b).map_err(|e| Error::StoreErr(e, "pipe save block".to_owned())) + ctx.store + .save_block(b) + .map_err(|e| Error::StoreErr(e, "pipe save block".to_owned())) } /// Officially adds the block header to our header chain. fn add_block_header(bh: &BlockHeader, ctx: &mut BlockContext) -> Result<(), Error> { - ctx.store.save_block_header(bh).map_err(|e| Error::StoreErr(e, "pipe save header".to_owned())) + ctx.store + .save_block_header(bh) + .map_err(|e| Error::StoreErr(e, "pipe save header".to_owned())) } /// Directly updates the head if we've just appended a new block to it or handle @@ -303,23 +296,33 @@ fn add_block_header(bh: &BlockHeader, ctx: &mut BlockContext) -> Result<(), Erro /// work than the head. fn update_head(b: &Block, ctx: &mut BlockContext) -> Result, Error> { // if we made a fork with more work than the head (which should also be true - // when extending the head), update it + // when extending the head), update it let tip = Tip::from_block(&b.header); if tip.total_difficulty > ctx.head.total_difficulty { - // update the block height index - ctx.store.setup_height(&b.header).map_err(|e| Error::StoreErr(e, "pipe setup height".to_owned()))?; + ctx.store + .setup_height(&b.header) + .map_err(|e| Error::StoreErr(e, "pipe setup height".to_owned()))?; - // in sync mode, only update the "body chain", otherwise update both the - // "header chain" and "body chain", updating the header chain in sync resets - // all additional "future" headers we've received - if ctx.opts.intersects(SYNC) { - ctx.store.save_body_head(&tip).map_err(|e| Error::StoreErr(e, "pipe save body".to_owned()))?; - } else { - ctx.store.save_head(&tip).map_err(|e| Error::StoreErr(e, "pipe save head".to_owned()))?; - } + // in sync mode, only update the "body chain", otherwise update both the + // "header chain" and "body chain", updating the header chain in sync resets + // all additional "future" headers we've received + if ctx.opts.intersects(SYNC) { + ctx.store + .save_body_head(&tip) + .map_err(|e| Error::StoreErr(e, "pipe save body".to_owned()))?; + } else { + ctx.store + .save_head(&tip) + .map_err(|e| Error::StoreErr(e, "pipe save head".to_owned()))?; + } ctx.head = tip.clone(); - info!(LOGGER, "Updated head to {} at {}.", b.hash(), b.header.height); + info!( + LOGGER, + "Updated head to {} at {}.", + b.hash(), + b.header.height + ); Ok(Some(tip)) } else { Ok(None) @@ -331,10 +334,12 @@ fn update_head(b: &Block, ctx: &mut BlockContext) -> Result, Error> /// work than the head. fn update_header_head(bh: &BlockHeader, ctx: &mut BlockContext) -> Result, Error> { // if we made a fork with more work than the head (which should also be true - // when extending the head), update it + // when extending the head), update it let tip = Tip::from_block(bh); if tip.total_difficulty > ctx.head.total_difficulty { - ctx.store.save_header_head(&tip).map_err(|e| Error::StoreErr(e, "pipe save header head".to_owned()))?; + ctx.store + .save_header_head(&tip) + .map_err(|e| Error::StoreErr(e, "pipe save header head".to_owned()))?; ctx.head = tip.clone(); info!( diff --git a/chain/src/store.rs b/chain/src/store.rs index abc71fd42..9fd329b4b 100644 --- a/chain/src/store.rs +++ b/chain/src/store.rs @@ -23,7 +23,7 @@ use core::core::hash::{Hash, Hashed}; use core::core::{Block, BlockHeader, Output}; use core::consensus::TargetError; use core::core::target::Difficulty; -use grin_store::{self, Error, to_key, u64_to_key, option_to_not_found}; +use grin_store::{self, option_to_not_found, to_key, Error, u64_to_key}; const STORE_SUBPATH: &'static str = "chain"; @@ -85,9 +85,10 @@ impl ChainStore for ChainKVStore { } fn get_block_header(&self, h: &Hash) -> Result { - option_to_not_found(self.db.get_ser( - &to_key(BLOCK_HEADER_PREFIX, &mut h.to_vec()), - )) + option_to_not_found( + self.db + .get_ser(&to_key(BLOCK_HEADER_PREFIX, &mut h.to_vec())), + ) } fn check_block_exists(&self, h: &Hash) -> Result { @@ -111,16 +112,14 @@ impl ChainStore for ChainKVStore { &to_key( OUTPUT_COMMIT_PREFIX, &mut out.commitment().as_ref().to_vec(), - ) - [..], + )[..], out, )? .put_ser( &to_key( HEADER_BY_OUTPUT_PREFIX, &mut out.commitment().as_ref().to_vec(), - ) - [..], + )[..], &b.hash(), )?; } @@ -128,18 +127,18 @@ impl ChainStore for ChainKVStore { } // lookup the block header hash by output commitment - // lookup the block header based on this hash - // to check the chain is correct compare this block header to - // the block header currently indexed at the relevant block height (tbd if - // actually necessary) - // - // NOTE: This index is not exhaustive. - // This node may not have seen this full block, so may not have populated the - // index. - // Block headers older than some threshold (2 months?) will not necessarily be - // included - // in this index. - // + // lookup the block header based on this hash + // to check the chain is correct compare this block header to + // the block header currently indexed at the relevant block height (tbd if + // actually necessary) + // + // NOTE: This index is not exhaustive. + // This node may not have seen this full block, so may not have populated the + // index. + // Block headers older than some threshold (2 months?) will not necessarily be + // included + // in this index. + // fn get_block_header_by_output_commit(&self, commit: &Commitment) -> Result { let block_hash = self.db.get_ser(&to_key( HEADER_BY_OUTPUT_PREFIX, @@ -172,10 +171,10 @@ impl ChainStore for ChainKVStore { } fn get_output_by_commit(&self, commit: &Commitment) -> Result { - option_to_not_found(self.db.get_ser(&to_key( - OUTPUT_COMMIT_PREFIX, - &mut commit.as_ref().to_vec(), - ))) + option_to_not_found( + self.db + .get_ser(&to_key(OUTPUT_COMMIT_PREFIX, &mut commit.as_ref().to_vec())), + ) } fn save_output_pos(&self, commit: &Commitment, pos: u64) -> Result<(), Error> { @@ -186,10 +185,10 @@ impl ChainStore for ChainKVStore { } fn get_output_pos(&self, commit: &Commitment) -> Result { - option_to_not_found(self.db.get_ser(&to_key( - COMMIT_POS_PREFIX, - &mut commit.as_ref().to_vec(), - ))) + option_to_not_found( + self.db + .get_ser(&to_key(COMMIT_POS_PREFIX, &mut commit.as_ref().to_vec())), + ) } fn save_kernel_pos(&self, excess: &Commitment, pos: u64) -> Result<(), Error> { @@ -200,10 +199,10 @@ impl ChainStore for ChainKVStore { } fn get_kernel_pos(&self, excess: &Commitment) -> Result { - option_to_not_found(self.db.get_ser(&to_key( - KERNEL_POS_PREFIX, - &mut excess.as_ref().to_vec(), - ))) + option_to_not_found( + self.db + .get_ser(&to_key(KERNEL_POS_PREFIX, &mut excess.as_ref().to_vec())), + ) } /// Maintain consistency of the "header_by_height" index by traversing back @@ -213,10 +212,8 @@ impl ChainStore for ChainKVStore { /// that is consistent with its height (everything prior to this will be /// consistent) fn setup_height(&self, bh: &BlockHeader) -> Result<(), Error> { - self.db.put_ser( - &u64_to_key(HEADER_HEIGHT_PREFIX, bh.height), - bh, - )?; + self.db + .put_ser(&u64_to_key(HEADER_HEIGHT_PREFIX, bh.height), bh)?; if bh.height == 0 { return Ok(()); } diff --git a/chain/src/sumtree.rs b/chain/src/sumtree.rs index 6b1700f5e..9071bd77f 100644 --- a/chain/src/sumtree.rs +++ b/chain/src/sumtree.rs @@ -24,7 +24,7 @@ use util::secp; use util::secp::pedersen::{RangeProof, Commitment}; use core::core::{Block, Output, SumCommit, TxKernel}; -use core::core::pmmr::{Summable, NoSum, PMMR, HashSum, Backend}; +use core::core::pmmr::{Backend, HashSum, NoSum, Summable, PMMR}; use grin_store; use grin_store::sumtree::PMMRBackend; use types::ChainStore; @@ -121,7 +121,11 @@ impl SumTrees { /// Get sum tree roots pub fn roots( &mut self, - ) -> (HashSum, HashSum>, HashSum>) { + ) -> ( + HashSum, + HashSum>, + HashSum>, + ) { let output_pmmr = PMMR::at(&mut self.output_pmmr_h.backend, self.output_pmmr_h.last_pos); let rproof_pmmr = PMMR::at(&mut self.rproof_pmmr_h.backend, self.rproof_pmmr_h.last_pos); let kernel_pmmr = PMMR::at(&mut self.kernel_pmmr_h.backend, self.kernel_pmmr_h.last_pos); @@ -140,7 +144,6 @@ pub fn extending<'a, F, T>(trees: &'a mut SumTrees, inner: F) -> Result Result, { - let sizes: (u64, u64, u64); let res: Result; let rollback: bool; @@ -229,7 +232,7 @@ impl<'a> Extension<'a> { let secp = secp::Secp256k1::with_caps(secp::ContextFlag::Commit); // doing inputs first guarantees an input can't spend an output in the - // same block, enforcing block cut-through + // same block, enforcing block cut-through for input in &b.inputs { let pos_res = self.commit_index.get_output_pos(&input.commitment()); if let Ok(pos) = pos_res { @@ -319,7 +322,11 @@ impl<'a> Extension<'a> { /// and kernel sum trees. pub fn roots( &self, - ) -> (HashSum, HashSum>, HashSum>) { + ) -> ( + HashSum, + HashSum>, + HashSum>, + ) { ( self.output_pmmr.root(), self.rproof_pmmr.root(), diff --git a/chain/src/types.rs b/chain/src/types.rs index 4139251c9..00ec3c650 100644 --- a/chain/src/types.rs +++ b/chain/src/types.rs @@ -19,7 +19,7 @@ use std::io; use util::secp::pedersen::Commitment; use grin_store as store; -use core::core::{Block, BlockHeader, block, Output}; +use core::core::{block, Block, BlockHeader, Output}; use core::core::hash::{Hash, Hashed}; use core::core::target::Difficulty; use core::ser; @@ -209,9 +209,10 @@ pub trait ChainStore: Send + Sync { fn get_output_by_commit(&self, commit: &Commitment) -> Result; /// Gets a block_header for the given input commit - fn get_block_header_by_output_commit(&self, - commit: &Commitment) - -> Result; + fn get_block_header_by_output_commit( + &self, + commit: &Commitment, + ) -> Result; /// Saves the position of an output, represented by its commitment, in the /// UTXO MMR. Used as an index for spending and pruning. diff --git a/chain/tests/mine_simple_chain.rs b/chain/tests/mine_simple_chain.rs index f5e5544ae..78af92cde 100644 --- a/chain/tests/mine_simple_chain.rs +++ b/chain/tests/mine_simple_chain.rs @@ -12,13 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -extern crate grin_core as core; -extern crate grin_chain as chain; -extern crate grin_keychain as keychain; extern crate env_logger; -extern crate time; -extern crate rand; +extern crate grin_chain as chain; +extern crate grin_core as core; +extern crate grin_keychain as keychain; extern crate grin_pow as pow; +extern crate rand; +extern crate time; use std::fs; use std::sync::Arc; @@ -34,7 +34,7 @@ use core::global::MiningParameterMode; use keychain::Keychain; -use pow::{types, cuckoo, MiningWorker}; +use pow::{cuckoo, types, MiningWorker}; fn clean_output_dir(dir_name: &str) { let _ = fs::remove_dir_all(dir_name); @@ -180,7 +180,7 @@ fn mine_losing_fork() { let bfork = prepare_block(&b1head, &chain, 3); // add higher difficulty first, prepare its successor, then fork - // with lower diff + // with lower diff chain.process_block(b2, chain::SKIP_POW).unwrap(); assert_eq!(chain.head_header().unwrap().hash(), b2head.hash()); let b3 = prepare_block(&b2head, &chain, 5); @@ -195,13 +195,13 @@ fn mine_losing_fork() { #[test] fn longer_fork() { // to make it easier to compute the sumtree roots in the test, we - // prepare 2 chains, the 2nd will be have the forked blocks we can - // then send back on the 1st + // prepare 2 chains, the 2nd will be have the forked blocks we can + // then send back on the 1st let chain = setup(".grin4"); let chain_fork = setup(".grin5"); // add blocks to both chains, 20 on the main one, only the first 5 - // for the forked chain + // for the forked chain let mut prev = chain.head_header().unwrap(); for n in 0..10 { let b = prepare_block(&prev, &chain, n + 2); diff --git a/chain/tests/test_coinbase_maturity.rs b/chain/tests/test_coinbase_maturity.rs index 525576764..00c8d984c 100644 --- a/chain/tests/test_coinbase_maturity.rs +++ b/chain/tests/test_coinbase_maturity.rs @@ -12,13 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -extern crate grin_core as core; +extern crate env_logger; extern crate grin_chain as chain; +extern crate grin_core as core; extern crate grin_keychain as keychain; extern crate grin_pow as pow; -extern crate env_logger; -extern crate time; extern crate rand; +extern crate time; use std::fs; use std::sync::Arc; @@ -32,7 +32,7 @@ use core::global::MiningParameterMode; use keychain::Keychain; -use pow::{types, cuckoo, MiningWorker}; +use pow::{cuckoo, types, MiningWorker}; fn clean_output_dir(dir_name: &str) { let _ = fs::remove_dir_all(dir_name); @@ -91,9 +91,11 @@ fn test_coinbase_maturity() { ).unwrap(); assert_eq!(block.outputs.len(), 1); - assert!(block.outputs[0].features.contains( - transaction::COINBASE_OUTPUT, - )); + assert!( + block.outputs[0] + .features + .contains(transaction::COINBASE_OUTPUT,) + ); chain.process_block(block, chain::EASY_POW).unwrap(); @@ -109,7 +111,8 @@ fn test_coinbase_maturity() { &keychain, ).unwrap(); - let mut block = core::core::Block::new(&prev, vec![&coinbase_txn], &keychain, &key_id3).unwrap(); + let mut block = + core::core::Block::new(&prev, vec![&coinbase_txn], &keychain, &key_id3).unwrap(); block.header.timestamp = prev.timestamp + time::Duration::seconds(60); let difficulty = consensus::next_difficulty(chain.difficulty_iter()).unwrap(); @@ -130,7 +133,7 @@ fn test_coinbase_maturity() { }; // mine enough blocks to increase the height sufficiently for - // coinbase to reach maturity and be spendable in the next block + // coinbase to reach maturity and be spendable in the next block for _ in 0..3 { let prev = chain.head_header().unwrap(); @@ -156,7 +159,8 @@ fn test_coinbase_maturity() { let prev = chain.head_header().unwrap(); - let mut block = core::core::Block::new(&prev, vec![&coinbase_txn], &keychain, &key_id4).unwrap(); + let mut block = + core::core::Block::new(&prev, vec![&coinbase_txn], &keychain, &key_id4).unwrap(); block.header.timestamp = prev.timestamp + time::Duration::seconds(60); diff --git a/config/src/config.rs b/config/src/config.rs index 13a3becf0..0f4ae3970 100644 --- a/config/src/config.rs +++ b/config/src/config.rs @@ -23,7 +23,7 @@ use toml; use grin::ServerConfig; use pow::types::MinerConfig; use util::LoggingConfig; -use types::{ConfigMembers, GlobalConfig, ConfigError}; +use types::{ConfigError, ConfigMembers, GlobalConfig}; /// The default file name to use when trying to derive /// the config file location @@ -86,7 +86,6 @@ impl GlobalConfig { // Give up Err(ConfigError::FileNotFoundError(String::from(""))) - } /// Takes the path to a config file, or if NONE, tries @@ -98,7 +97,7 @@ impl GlobalConfig { if let Some(fp) = file_path { return_value.config_file_path = Some(PathBuf::from(&fp)); } else { - let _result=return_value.derive_config_location(); + let _result = return_value.derive_config_location(); } // No attempt at a config file, just return defaults @@ -120,8 +119,8 @@ impl GlobalConfig { } // Try to parse the config file if it exists - // explode if it does exist but something's wrong - // with it + // explode if it does exist but something's wrong + // with it return_value.read_config() } @@ -134,7 +133,7 @@ impl GlobalConfig { match decoded { Ok(mut gc) => { // Put the struct back together, because the config - // file was flattened a bit + // file was flattened a bit gc.server.mining_config = gc.mining.clone(); self.using_config_file = true; self.members = Some(gc); diff --git a/config/src/lib.rs b/config/src/lib.rs index 308481522..d5908b82d 100644 --- a/config/src/lib.rs +++ b/config/src/lib.rs @@ -28,11 +28,11 @@ extern crate toml; extern crate grin_grin as grin; extern crate grin_p2p as p2p; -extern crate grin_wallet as wallet; extern crate grin_pow as pow; extern crate grin_util as util; +extern crate grin_wallet as wallet; pub mod config; pub mod types; -pub use types::{GlobalConfig, ConfigMembers, ConfigError}; +pub use types::{ConfigError, ConfigMembers, GlobalConfig}; diff --git a/config/src/types.rs b/config/src/types.rs index 49a02e73b..a4d54e158 100644 --- a/config/src/types.rs +++ b/config/src/types.rs @@ -41,14 +41,12 @@ pub enum ConfigError { impl fmt::Display for ConfigError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { - ConfigError::ParseError(ref file_name, ref message) => { - write!( - f, - "Error parsing configuration file at {} - {}", - file_name, - message - ) - } + ConfigError::ParseError(ref file_name, ref message) => write!( + f, + "Error parsing configuration file at {} - {}", + file_name, + message + ), ConfigError::FileIOError(ref file_name, ref message) => { write!(f, "{} {}", message, file_name) } @@ -102,7 +100,7 @@ pub struct ConfigMembers { pub mining: Option, /// Logging config pub logging: Option, - + //removing wallet from here for now, //as its concerns are separate from the server's, really //given it needs to manage keys. It should probably diff --git a/core/benches/sumtree.rs b/core/benches/sumtree.rs index 5b9e50506..8875b259b 100644 --- a/core/benches/sumtree.rs +++ b/core/benches/sumtree.rs @@ -13,15 +13,15 @@ #![feature(test)] -extern crate test; -extern crate rand; extern crate grin_core as core; +extern crate rand; +extern crate test; use rand::Rng; use test::Bencher; use core::core::sumtree::{self, SumTree, Summable}; -use core::ser::{Writeable, Writer, Error}; +use core::ser::{Error, Writeable, Writer}; #[derive(Copy, Clone, Debug)] struct TestElem([u32; 4]); @@ -29,9 +29,9 @@ impl Summable for TestElem { type Sum = u64; fn sum(&self) -> u64 { // sums are not allowed to overflow, so we use this simple - // non-injective "sum" function that will still be homomorphic - self.0[0] as u64 * 0x1000 + self.0[1] as u64 * 0x100 + self.0[2] as u64 * 0x10 + - self.0[3] as u64 + // non-injective "sum" function that will still be homomorphic + self.0[0] as u64 * 0x1000 + self.0[1] as u64 * 0x100 + self.0[2] as u64 * 0x10 + + self.0[3] as u64 } } @@ -51,7 +51,7 @@ fn bench_small_tree(b: &mut Bencher) { let mut big_tree = SumTree::new(); for i in 0..1000 { // To avoid RNG overflow we generate random elements that are small. - // Though to avoid repeat elements they have to be reasonably big. + // Though to avoid repeat elements they have to be reasonably big. let new_elem; let word1 = rng.gen::() as u32; let word2 = rng.gen::() as u32; diff --git a/core/src/consensus.rs b/core/src/consensus.rs index 56a796b40..d06a6f5f8 100644 --- a/core/src/consensus.rs +++ b/core/src/consensus.rs @@ -28,7 +28,7 @@ use core::target::Difficulty; pub const GRIN_BASE: u64 = 1_000_000_000; /// The block subsidy amount -pub const REWARD: u64 = 50*GRIN_BASE; +pub const REWARD: u64 = 50 * GRIN_BASE; /// Actual block reward for a given total fee amount pub fn reward(fee: u64) -> u64 { @@ -80,8 +80,8 @@ pub const MAX_BLOCK_WEIGHT: usize = 80_000; /// Whether a block exceeds the maximum acceptable weight pub fn exceeds_weight(input_len: usize, output_len: usize, kernel_len: usize) -> bool { - input_len * BLOCK_INPUT_WEIGHT + output_len * BLOCK_OUTPUT_WEIGHT + - kernel_len * BLOCK_KERNEL_WEIGHT > MAX_BLOCK_WEIGHT + input_len * BLOCK_INPUT_WEIGHT + output_len * BLOCK_OUTPUT_WEIGHT + + kernel_len * BLOCK_KERNEL_WEIGHT > MAX_BLOCK_WEIGHT } /// Fork every 250,000 blocks for first 2 years, simple number and just a @@ -150,9 +150,8 @@ pub fn next_difficulty(cursor: T) -> Result where T: IntoIterator>, { - // Block times at the begining and end of the adjustment window, used to - // calculate medians later. + // calculate medians later. let mut window_begin = vec![]; let mut window_end = vec![]; @@ -165,8 +164,8 @@ where let (ts, diff) = head_info?; // Sum each element in the adjustment window. In addition, retain - // timestamps within median windows (at ]start;start-11] and ]end;end-11] - // to later calculate medians. + // timestamps within median windows (at ]start;start-11] and ]end;end-11] + // to later calculate medians. if m < DIFFICULTY_ADJUST_WINDOW { diff_sum = diff_sum + diff; @@ -204,9 +203,7 @@ where ts_damp }; - Ok( - diff_avg * Difficulty::from_num(BLOCK_TIME_WINDOW) / Difficulty::from_num(adj_ts), - ) + Ok(diff_avg * Difficulty::from_num(BLOCK_TIME_WINDOW) / Difficulty::from_num(adj_ts)) } /// Consensus rule that collections of items are sorted lexicographically over the wire. @@ -225,7 +222,7 @@ mod test { use super::*; // Builds an iterator for next difficulty calculation with the provided - // constant time interval, difficulty and total length. + // constant time interval, difficulty and total length. fn repeat(interval: u64, diff: u64, len: u64) -> Vec> { // watch overflow here, length shouldn't be ridiculous anyhow assert!(len < std::usize::MAX as u64); @@ -336,15 +333,15 @@ mod test { } // #[test] - // fn hard_fork_2() { - // assert!(valid_header_version(0, 1)); - // assert!(valid_header_version(10, 1)); - // assert!(valid_header_version(10, 2)); - // assert!(valid_header_version(250_000, 1)); - // assert!(!valid_header_version(250_001, 1)); - // assert!(!valid_header_version(500_000, 1)); - // assert!(valid_header_version(250_001, 2)); - // assert!(valid_header_version(500_000, 2)); - // assert!(!valid_header_version(500_001, 2)); - // } + // fn hard_fork_2() { + // assert!(valid_header_version(0, 1)); + // assert!(valid_header_version(10, 1)); + // assert!(valid_header_version(10, 2)); + // assert!(valid_header_version(250_000, 1)); + // assert!(!valid_header_version(250_001, 1)); + // assert!(!valid_header_version(500_000, 1)); + // assert!(valid_header_version(250_001, 2)); + // assert!(valid_header_version(500_000, 2)); + // assert!(!valid_header_version(500_001, 2)); + // } } diff --git a/core/src/core/block.rs b/core/src/core/block.rs index 2edbac611..568859c32 100644 --- a/core/src/core/block.rs +++ b/core/src/core/block.rs @@ -20,12 +20,12 @@ use util::secp::{self, Secp256k1}; use std::collections::HashSet; use core::Committed; -use core::{Input, Output, SwitchCommitHash, Proof, TxKernel, Transaction, COINBASE_KERNEL, +use core::{Input, Output, Proof, SwitchCommitHash, Transaction, TxKernel, COINBASE_KERNEL, COINBASE_OUTPUT}; -use consensus::{MINIMUM_DIFFICULTY, REWARD, reward, exceeds_weight}; +use consensus::{exceeds_weight, reward, MINIMUM_DIFFICULTY, REWARD}; use core::hash::{Hash, Hashed, ZERO_HASH}; use core::target::Difficulty; -use ser::{self, Readable, Reader, Writeable, Writer, WriteableSorted, read_and_verify_sorted}; +use ser::{self, read_and_verify_sorted, Readable, Reader, Writeable, WriteableSorted, Writer}; use util::LOGGER; use global; use keychain; @@ -282,9 +282,8 @@ impl Block { reward_out: Output, reward_kern: TxKernel, ) -> Result { - // note: the following reads easily but may not be the most efficient due to - // repeated iterations, revisit if a problem + // repeated iterations, revisit if a problem let secp = Secp256k1::with_caps(secp::ContextFlag::Commit); // validate each transaction and gather their kernels @@ -292,8 +291,8 @@ impl Block { kernels.push(reward_kern); // build vectors with all inputs and all outputs, ordering them by hash - // needs to be a fold so we don't end up with a vector of vectors and we - // want to fully own the refs (not just a pointer like flat_map). + // needs to be a fold so we don't end up with a vector of vectors and we + // want to fully own the refs (not just a pointer like flat_map). let inputs = txs.iter().fold(vec![], |mut acc, ref tx| { let mut inputs = tx.inputs.clone(); acc.append(&mut inputs); @@ -317,8 +316,8 @@ impl Block { ..time::now_utc() }, previous: prev.hash(), - total_difficulty: prev.pow.clone().to_difficulty() + - prev.total_difficulty.clone(), + total_difficulty: prev.pow.clone().to_difficulty() + + prev.total_difficulty.clone(), ..Default::default() }, inputs: inputs, @@ -439,7 +438,9 @@ impl Block { } if k.lock_height > self.header.height { - return Err(Error::KernelLockHeight { lock_height: k.lock_height }); + return Err(Error::KernelLockHeight { + lock_height: k.lock_height, + }); } } @@ -465,18 +466,17 @@ impl Block { } // Validate the coinbase outputs generated by miners. Entails 2 main checks: - // - // * That the sum of all coinbase-marked outputs equal the supply. - // * That the sum of blinding factors for all coinbase-marked outputs match - // the coinbase-marked kernels. + // + // * That the sum of all coinbase-marked outputs equal the supply. + // * That the sum of blinding factors for all coinbase-marked outputs match + // the coinbase-marked kernels. fn verify_coinbase(&self, secp: &Secp256k1) -> Result<(), Error> { - let cb_outs = filter_map_vec!(self.outputs, |out| if out.features.contains( - COINBASE_OUTPUT, - ) - { - Some(out.commitment()) - } else { - None + let cb_outs = filter_map_vec!(self.outputs, |out| { + if out.features.contains(COINBASE_OUTPUT) { + Some(out.commitment()) + } else { + None + } }); let cb_kerns = filter_map_vec!(self.kernels, |k| if k.features.contains(COINBASE_KERNEL) { Some(k.excess) @@ -557,14 +557,14 @@ mod test { use util::secp; // utility to create a block without worrying about the key or previous - // header + // header fn new_block(txs: Vec<&Transaction>, keychain: &Keychain) -> Block { let key_id = keychain.derive_key_id(1).unwrap(); Block::new(&BlockHeader::default(), txs, keychain, &key_id).unwrap() } // utility producing a transaction that spends an output with the provided - // value and blinding key + // value and blinding key fn txspend1i1o( v: u64, keychain: &Keychain, @@ -624,7 +624,7 @@ mod test { let b = new_block(vec![&mut btx1, &mut btx2, &mut btx3], &keychain); // block should have been automatically compacted (including reward - // output) and should still be valid + // output) and should still be valid b.validate(&keychain.secp()).unwrap(); assert_eq!(b.inputs.len(), 3); assert_eq!(b.outputs.len(), 3); @@ -632,7 +632,7 @@ mod test { #[test] // builds 2 different blocks with a tx spending another and check if merging - // occurs + // occurs fn mergeable_blocks() { let keychain = Keychain::from_random_seed().unwrap(); let key_id1 = keychain.derive_key_id(1).unwrap(); @@ -685,14 +685,14 @@ mod test { assert_eq!(coinbase_kernels.len(), 1); // the block should be valid here (single coinbase output with corresponding - // txn kernel) + // txn kernel) assert_eq!(b.validate(&keychain.secp()), Ok(())); } #[test] // test that flipping the COINBASE_OUTPUT flag on the output features - // invalidates the block and specifically it causes verify_coinbase to fail - // additionally verifying the merkle_inputs_outputs also fails + // invalidates the block and specifically it causes verify_coinbase to fail + // additionally verifying the merkle_inputs_outputs also fails fn remove_coinbase_output_flag() { let keychain = Keychain::from_random_seed().unwrap(); let mut b = new_block(vec![], &keychain); @@ -714,7 +714,7 @@ mod test { #[test] // test that flipping the COINBASE_KERNEL flag on the kernel features - // invalidates the block and specifically it causes verify_coinbase to fail + // invalidates the block and specifically it causes verify_coinbase to fail fn remove_coinbase_kernel_flag() { let keychain = Keychain::from_random_seed().unwrap(); let mut b = new_block(vec![], &keychain); diff --git a/core/src/core/build.rs b/core/src/core/build.rs index 72847018f..64964011f 100644 --- a/core/src/core/build.rs +++ b/core/src/core/build.rs @@ -27,11 +27,11 @@ use util::secp; -use core::{Transaction, Input, Output, SwitchCommitHash, DEFAULT_OUTPUT}; +use core::{Input, Output, SwitchCommitHash, Transaction, DEFAULT_OUTPUT}; use core::transaction::kernel_sig_msg; use util::LOGGER; use keychain; -use keychain::{Keychain, BlindSum, BlindingFactor, Identifier}; +use keychain::{BlindSum, BlindingFactor, Identifier, Keychain}; /// Context information available to transaction combinators. pub struct Context<'a> { @@ -40,7 +40,8 @@ pub struct Context<'a> { /// Function type returned by the transaction combinators. Transforms a /// (Transaction, BlindSum) pair into another, provided some context. -pub type Append = for<'a> Fn(&'a mut Context, (Transaction, BlindSum)) -> (Transaction, BlindSum); +pub type Append = for<'a> Fn(&'a mut Context, (Transaction, BlindSum)) + -> (Transaction, BlindSum); /// Adds an input with the provided value and blinding key to the transaction /// being built. @@ -132,10 +133,11 @@ pub fn transaction( keychain: &keychain::Keychain, ) -> Result<(Transaction, BlindingFactor), keychain::Error> { let mut ctx = Context { keychain }; - let (mut tx, sum) = elems.iter().fold( - (Transaction::empty(), BlindSum::new()), - |acc, elem| elem(&mut ctx, acc), - ); + let (mut tx, sum) = elems + .iter() + .fold((Transaction::empty(), BlindSum::new()), |acc, elem| { + elem(&mut ctx, acc) + }); let blind_sum = ctx.keychain.blind_sum(&sum)?; let msg = secp::Message::from_slice(&kernel_sig_msg(tx.fee, tx.lock_height))?; let sig = ctx.keychain.sign_with_blinding(&msg, &blind_sum)?; diff --git a/core/src/core/hash.rs b/core/src/core/hash.rs index df6e3c6e7..f758ceb94 100644 --- a/core/src/core/hash.rs +++ b/core/src/core/hash.rs @@ -24,7 +24,7 @@ use std::convert::AsRef; use blake2::blake2b::Blake2b; use consensus::VerifySortOrder; -use ser::{self, Reader, Readable, Writer, Writeable, Error, AsFixedBytes}; +use ser::{self, AsFixedBytes, Error, Readable, Reader, Writeable, Writer}; use util::LOGGER; /// A hash consisting of all zeroes, used as a sentinel. No known preimage. @@ -153,7 +153,9 @@ impl HashWriter { impl Default for HashWriter { fn default() -> HashWriter { - HashWriter { state: Blake2b::new(32) } + HashWriter { + state: Blake2b::new(32), + } } } @@ -173,19 +175,19 @@ pub trait Hashed { /// Obtain the hash of the object fn hash(&self) -> Hash; /// Hash the object together with another writeable object - fn hash_with(&self, other:T) -> Hash; + fn hash_with(&self, other: T) -> Hash; } impl Hashed for W { fn hash(&self) -> Hash { let mut hasher = HashWriter::default(); - ser::Writeable::write(self, &mut hasher).unwrap(); + ser::Writeable::write(self, &mut hasher).unwrap(); let mut ret = [0; 32]; hasher.finalize(&mut ret); Hash(ret) } - fn hash_with(&self, other:T) -> Hash{ + fn hash_with(&self, other: T) -> Hash { let mut hasher = HashWriter::default(); ser::Writeable::write(self, &mut hasher).unwrap(); trace!(LOGGER, "Hashing with additional data"); @@ -202,7 +204,8 @@ impl VerifySortOrder for Vec { .map(|item| item.hash()) .collect::>() .windows(2) - .any(|pair| pair[0] > pair[1]) { + .any(|pair| pair[0] > pair[1]) + { true => Err(ser::Error::BadlySorted), false => Ok(()), } diff --git a/core/src/core/mod.rs b/core/src/core/mod.rs index 5bdc2fdc5..0888738db 100644 --- a/core/src/core/mod.rs +++ b/core/src/core/mod.rs @@ -31,8 +31,8 @@ use util::secp::pedersen::*; pub use self::block::*; pub use self::transaction::*; -use self::hash::{Hashed}; -use ser::{Writeable, Writer, Reader, Readable, Error}; +use self::hash::Hashed; +use ser::{Error, Readable, Reader, Writeable, Writer}; use global; // use keychain; @@ -53,7 +53,7 @@ pub trait Committed { let mut output_commits = map_vec!(self.outputs_committed(), |out| out.commitment()); // add the overage as output commitment if positive, as an input commitment if - // negative + // negative let overage = self.overage(); if overage != 0 { let over_commit = secp.commit_value(overage.abs() as u64).unwrap(); @@ -186,11 +186,11 @@ impl Writeable for Proof { mod test { use super::*; use core::hash::ZERO_HASH; - use core::build::{input, output, with_fee, initial_tx, with_excess, with_lock_height}; + use core::build::{initial_tx, input, output, with_excess, with_fee, with_lock_height}; use core::block::Error::KernelLockHeight; use ser; use keychain; - use keychain::{Keychain, BlindingFactor}; + use keychain::{BlindingFactor, Keychain}; #[test] #[should_panic(expected = "InvalidSecretKey")] @@ -308,11 +308,11 @@ mod test { { // Alice gets 2 of her pre-existing outputs to send 5 coins to Bob, they - // become inputs in the new transaction + // become inputs in the new transaction let (in1, in2) = (input(4, key_id1), input(3, key_id2)); // Alice builds her transaction, with change, which also produces the sum - // of blinding factors before they're obscured. + // of blinding factors before they're obscured. let (tx, sum) = build::transaction(vec![in1, in2, output(1, key_id3), with_fee(2)], &keychain) .unwrap(); @@ -321,8 +321,8 @@ mod test { } // From now on, Bob only has the obscured transaction and the sum of - // blinding factors. He adds his output, finalizes the transaction so it's - // ready for broadcast. + // blinding factors. He adds his output, finalizes the transaction so it's + // ready for broadcast. let (tx_final, _) = build::transaction( vec![ initial_tx(tx_alice), @@ -382,7 +382,7 @@ mod test { let key_id3 = keychain.derive_key_id(3).unwrap(); // first check we can add a timelocked tx where lock height matches current block height - // and that the resulting block is valid + // and that the resulting block is valid let tx1 = build::transaction( vec![ input(5, key_id1.clone()), @@ -421,7 +421,9 @@ mod test { &key_id3.clone(), ).unwrap(); match b.validate(keychain.secp()) { - Err(KernelLockHeight { lock_height: height }) => { + Err(KernelLockHeight { + lock_height: height, + }) => { assert_eq!(height, 2); } _ => panic!("expecting KernelLockHeight error here"), diff --git a/core/src/core/pmmr.rs b/core/src/core/pmmr.rs index 00dae256c..59ac84d56 100644 --- a/core/src/core/pmmr.rs +++ b/core/src/core/pmmr.rs @@ -119,7 +119,7 @@ where T: Summable + Hashed, { /// Create a hash sum from a summable - pub fn from_summable(idx: u64, elmt: &T, hash_with:Option) -> HashSum { + pub fn from_summable(idx: u64, elmt: &T, hash_with: Option) -> HashSum { let hash = match hash_with { Some(h) => elmt.hash_with(h), None => elmt.hash(), @@ -259,7 +259,7 @@ where /// Push a new Summable element in the MMR. Computes new related peaks at /// the same time if applicable. - pub fn push(&mut self, elmt: T, hash_with:Option) -> Result { + pub fn push(&mut self, elmt: T, hash_with: Option) -> Result { let elmt_pos = self.last_pos + 1; let mut current_hashsum = HashSum::from_summable(elmt_pos, &elmt, hash_with); let mut to_append = vec![current_hashsum.clone()]; @@ -267,14 +267,14 @@ where let mut pos = elmt_pos; // we look ahead one position in the MMR, if the expected node has a higher - // height it means we have to build a higher peak by summing with a previous - // sibling. we do it iteratively in case the new peak itself allows the - // creation of another parent. + // height it means we have to build a higher peak by summing with a previous + // sibling. we do it iteratively in case the new peak itself allows the + // creation of another parent. while bintree_postorder_height(pos + 1) > height { let left_sibling = bintree_jump_left_sibling(pos); - let left_hashsum = self.backend.get(left_sibling).expect( - "missing left sibling in tree, should not have been pruned", - ); + let left_hashsum = self.backend + .get(left_sibling) + .expect("missing left sibling in tree, should not have been pruned"); current_hashsum = left_hashsum + current_hashsum; to_append.push(current_hashsum.clone()); @@ -293,8 +293,8 @@ where /// well as the consumer-provided index of when the change occurred. pub fn rewind(&mut self, position: u64, index: u32) -> Result<(), String> { // identify which actual position we should rewind to as the provided - // position is a leaf, which may had some parent that needs to exist - // afterward for the MMR to be valid + // position is a leaf, which may had some parent that needs to exist + // afterward for the MMR to be valid let mut pos = position; while bintree_postorder_height(pos + 1) > 0 { pos += 1; @@ -320,7 +320,7 @@ where } // loop going up the tree, from node to parent, as long as we stay inside - // the tree. + // the tree. let mut to_prune = vec![]; let mut current = position; while current + 1 < self.last_pos { @@ -332,7 +332,7 @@ where to_prune.push(current); // if we have a pruned sibling, we can continue up the tree - // otherwise we're done + // otherwise we're done if let None = self.backend.get(sibling) { current = parent; } else { @@ -353,30 +353,30 @@ where /// Helper function to get the last N nodes inserted, i.e. the last /// n nodes along the bottom of the tree pub fn get_last_n_insertions(&self, n: u64) -> Vec> { - let mut return_vec=Vec::new(); + let mut return_vec = Vec::new(); let mut last_leaf = self.last_pos; - let size=self.unpruned_size(); - //Special case that causes issues in bintree functions, - //just return - if size==1 { + let size = self.unpruned_size(); + // Special case that causes issues in bintree functions, + // just return + if size == 1 { return_vec.push(self.backend.get(last_leaf).unwrap()); return return_vec; } - //if size is even, we're already at the bottom, otherwise - //we need to traverse down to it (reverse post-order direction) + // if size is even, we're already at the bottom, otherwise + // we need to traverse down to it (reverse post-order direction) if size % 2 == 1 { - last_leaf=bintree_rightmost(self.last_pos); + last_leaf = bintree_rightmost(self.last_pos); } for _ in 0..n as u64 { - if last_leaf==0 { + if last_leaf == 0 { break; } if bintree_postorder_height(last_leaf) > 0 { last_leaf = bintree_rightmost(last_leaf); } return_vec.push(self.backend.get(last_leaf).unwrap()); - - last_leaf=bintree_jump_left_sibling(last_leaf); + + last_leaf = bintree_jump_left_sibling(last_leaf); } return_vec } @@ -388,30 +388,30 @@ where } /// Debugging utility to print information about the MMRs. Short version - /// only prints the last 8 nodes. + /// only prints the last 8 nodes. pub fn dump(&self, short: bool) { let sz = self.unpruned_size(); if sz > 600 { return; } - let start = if short && sz > 7 { sz/8 - 1 } else { 0 }; - for n in start..(sz/8+1) { - let mut idx = "".to_owned(); - let mut hashes = "".to_owned(); - for m in (n*8)..(n+1)*8 { - if m >= sz { - break; - } - idx.push_str(&format!("{:>8} ", m + 1)); - let ohs = self.get(m+1); - match ohs { - Some(hs) => hashes.push_str(&format!("{} ", hs.hash)), - None => hashes.push_str(&format!("{:>8} ", "??")), - } - } - debug!(LOGGER, "{}", idx); - debug!(LOGGER, "{}", hashes); - } + let start = if short && sz > 7 { sz / 8 - 1 } else { 0 }; + for n in start..(sz / 8 + 1) { + let mut idx = "".to_owned(); + let mut hashes = "".to_owned(); + for m in (n * 8)..(n + 1) * 8 { + if m >= sz { + break; + } + idx.push_str(&format!("{:>8} ", m + 1)); + let ohs = self.get(m + 1); + match ohs { + Some(hs) => hashes.push_str(&format!("{} ", hs.hash)), + None => hashes.push_str(&format!("{:>8} ", "??")), + } + } + debug!(LOGGER, "{}", idx); + debug!(LOGGER, "{}", hashes); + } } } @@ -503,19 +503,21 @@ pub struct PruneList { impl PruneList { /// Instantiate a new empty prune list pub fn new() -> PruneList { - PruneList { pruned_nodes: vec![] } + PruneList { + pruned_nodes: vec![], + } } /// Computes by how many positions a node at pos should be shifted given the /// number of nodes that have already been pruned before it. pub fn get_shift(&self, pos: u64) -> Option { // get the position where the node at pos would fit in the pruned list, if - // it's already pruned, nothing to skip + // it's already pruned, nothing to skip match self.pruned_pos(pos) { None => None, Some(idx) => { // skip by the number of elements pruned in the preceding subtrees, - // which is the sum of the size of each subtree + // which is the sum of the size of each subtree Some( self.pruned_nodes[0..(idx as usize)] .iter() @@ -557,8 +559,8 @@ impl PruneList { Err(idx) => { if self.pruned_nodes.len() > idx { // the node at pos can't be a child of lower position nodes by MMR - // construction but can be a child of the next node, going up parents - // from pos to make sure it's not the case + // construction but can be a child of the next node, going up parents + // from pos to make sure it's not the case let next_peak_pos = self.pruned_nodes[idx]; let mut cursor = pos; loop { @@ -583,15 +585,14 @@ impl PruneList { /// side of the range, and navigates toward lower siblings toward the right /// of the range. fn peaks(num: u64) -> Vec { - // detecting an invalid mountain range, when siblings exist but no parent - // exists + // exists if bintree_postorder_height(num + 1) > bintree_postorder_height(num) { return vec![]; } // our top peak is always on the leftmost side of the tree and leftmost trees - // have for index a binary values with all 1s (i.e. 11, 111, 1111, etc.) + // have for index a binary values with all 1s (i.e. 11, 111, 1111, etc.) let mut top = 1; while (top - 1) <= num { top = top << 1; @@ -604,7 +605,7 @@ fn peaks(num: u64) -> Vec { let mut peaks = vec![top]; // going down the range, next peaks are right neighbors of the top. if one - // doesn't exist yet, we go down to a smaller peak to the left + // doesn't exist yet, we go down to a smaller peak to the left let mut peak = top; 'outer: loop { peak = bintree_jump_right_sibling(peak); @@ -807,8 +808,8 @@ mod test { #[allow(unused_variables)] fn first_50_mmr_heights() { let first_100_str = "0 0 1 0 0 1 2 0 0 1 0 0 1 2 3 0 0 1 0 0 1 2 0 0 1 0 0 1 2 3 4 \ - 0 0 1 0 0 1 2 0 0 1 0 0 1 2 3 0 0 1 0 0 1 2 0 0 1 0 0 1 2 3 4 5 \ - 0 0 1 0 0 1 2 0 0 1 0 0 1 2 3 0 0 1 0 0 1 2 0 0 1 0 0 1 2 3 4 0 0 1 0 0"; + 0 0 1 0 0 1 2 0 0 1 0 0 1 2 3 0 0 1 0 0 1 2 0 0 1 0 0 1 2 3 4 5 \ + 0 0 1 0 0 1 2 0 0 1 0 0 1 2 3 0 0 1 0 0 1 2 0 0 1 0 0 1 2 3 4 0 0 1 0 0"; let first_100 = first_100_str.split(' ').map(|n| n.parse::().unwrap()); let mut count = 1; for n in first_100 { @@ -844,9 +845,9 @@ mod test { type Sum = u64; fn sum(&self) -> u64 { // sums are not allowed to overflow, so we use this simple - // non-injective "sum" function that will still be homomorphic - self.0[0] as u64 * 0x1000 + self.0[1] as u64 * 0x100 + self.0[2] as u64 * 0x10 + - self.0[3] as u64 + // non-injective "sum" function that will still be homomorphic + self.0[0] as u64 * 0x1000 + self.0[1] as u64 * 0x100 + self.0[2] as u64 * 0x10 + + self.0[3] as u64 } fn sum_len() -> usize { 8 @@ -896,7 +897,8 @@ mod test { // two elements pmmr.push(elems[1], None::).unwrap(); - let sum2 = HashSum::from_summable(1, &elems[0], None::) + HashSum::from_summable(2, &elems[1], None::); + let sum2 = HashSum::from_summable(1, &elems[0], None::) + + HashSum::from_summable(2, &elems[1], None::); assert_eq!(pmmr.root(), sum2); assert_eq!(pmmr.unpruned_size(), 3); @@ -908,8 +910,9 @@ mod test { // four elements pmmr.push(elems[3], None::).unwrap(); - let sum4 = sum2 + - (HashSum::from_summable(4, &elems[2], None::) + HashSum::from_summable(5, &elems[3], None::)); + let sum4 = sum2 + + (HashSum::from_summable(4, &elems[2], None::) + + HashSum::from_summable(5, &elems[3], None::)); assert_eq!(pmmr.root(), sum4); assert_eq!(pmmr.unpruned_size(), 7); @@ -921,8 +924,9 @@ mod test { // six elements pmmr.push(elems[5], None::).unwrap(); - let sum6 = sum4.clone() + - (HashSum::from_summable(8, &elems[4], None::) + HashSum::from_summable(9, &elems[5], None::)); + let sum6 = sum4.clone() + + (HashSum::from_summable(8, &elems[4], None::) + + HashSum::from_summable(9, &elems[5], None::)); assert_eq!(pmmr.root(), sum6.clone()); assert_eq!(pmmr.unpruned_size(), 10); @@ -934,9 +938,11 @@ mod test { // eight elements pmmr.push(elems[7], None::).unwrap(); - let sum8 = sum4 + - ((HashSum::from_summable(8, &elems[4], None::) + HashSum::from_summable(9, &elems[5], None::)) + - (HashSum::from_summable(11, &elems[6], None::) + HashSum::from_summable(12, &elems[7], None::))); + let sum8 = sum4 + + ((HashSum::from_summable(8, &elems[4], None::) + + HashSum::from_summable(9, &elems[5], None::)) + + (HashSum::from_summable(11, &elems[6], None::) + + HashSum::from_summable(12, &elems[7], None::))); assert_eq!(pmmr.root(), sum8); assert_eq!(pmmr.unpruned_size(), 15); @@ -949,7 +955,6 @@ mod test { #[test] fn pmmr_get_last_n_insertions() { - let elems = [ TestElem([0, 0, 0, 1]), TestElem([0, 0, 0, 2]), @@ -964,28 +969,31 @@ mod test { let mut ba = VecBackend::new(); let mut pmmr = PMMR::new(&mut ba); - //test when empty - let res=pmmr.get_last_n_insertions(19); - assert!(res.len()==0); + // test when empty + let res = pmmr.get_last_n_insertions(19); + assert!(res.len() == 0); pmmr.push(elems[0], None::).unwrap(); - let res=pmmr.get_last_n_insertions(19); - assert!(res.len()==1 && res[0].sum==1); + let res = pmmr.get_last_n_insertions(19); + assert!(res.len() == 1 && res[0].sum == 1); pmmr.push(elems[1], None::).unwrap(); let res = pmmr.get_last_n_insertions(12); - assert!(res[0].sum==2 && res[1].sum==1); + assert!(res[0].sum == 2 && res[1].sum == 1); pmmr.push(elems[2], None::).unwrap(); let res = pmmr.get_last_n_insertions(2); - assert!(res[0].sum==3 && res[1].sum==2); + assert!(res[0].sum == 3 && res[1].sum == 2); pmmr.push(elems[3], None::).unwrap(); let res = pmmr.get_last_n_insertions(19); - assert!(res[0].sum==4 && res[1].sum==3 && res[2].sum==2 && res[3].sum==1 && res.len()==4); + assert!( + res[0].sum == 4 && res[1].sum == 3 && res[2].sum == 2 && res[3].sum == 1 + && res.len() == 4 + ); pmmr.push(elems[5], None::).unwrap(); pmmr.push(elems[6], None::).unwrap(); @@ -993,8 +1001,10 @@ mod test { pmmr.push(elems[8], None::).unwrap(); let res = pmmr.get_last_n_insertions(7); - assert!(res[0].sum==9 && res[1].sum==8 && res[2].sum==7 && res[3].sum==6 && res.len()==7); - + assert!( + res[0].sum == 9 && res[1].sum == 8 && res[2].sum == 7 && res[3].sum == 6 + && res.len() == 7 + ); } #[test] diff --git a/core/src/core/target.rs b/core/src/core/target.rs index 8c6b34ac1..4aab75ff4 100644 --- a/core/src/core/target.rs +++ b/core/src/core/target.rs @@ -20,13 +20,13 @@ //! wrapper in case the internal representation needs to change again use std::fmt; -use std::ops::{Add, Mul, Div, Sub}; +use std::ops::{Add, Div, Mul, Sub}; -use serde::{Serialize, Serializer, Deserialize, Deserializer, de}; -use byteorder::{ByteOrder, BigEndian}; +use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; +use byteorder::{BigEndian, ByteOrder}; use core::hash::Hash; -use ser::{self, Reader, Writer, Writeable, Readable}; +use ser::{self, Readable, Reader, Writeable, Writer}; /// The target is the 32-bytes hash block hashes must be lower than. pub const MAX_TARGET: [u8; 8] = [0xf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]; @@ -63,7 +63,9 @@ impl Difficulty { let mut in_vec = h.to_vec(); in_vec.truncate(8); let num = BigEndian::read_u64(&in_vec); - Difficulty { num: max_target / num } + Difficulty { + num: max_target / num, + } } /// Converts the difficulty into a u64 @@ -81,28 +83,36 @@ impl fmt::Display for Difficulty { impl Add for Difficulty { type Output = Difficulty; fn add(self, other: Difficulty) -> Difficulty { - Difficulty { num: self.num + other.num } + Difficulty { + num: self.num + other.num, + } } } impl Sub for Difficulty { type Output = Difficulty; fn sub(self, other: Difficulty) -> Difficulty { - Difficulty { num: self.num - other.num } + Difficulty { + num: self.num - other.num, + } } } impl Mul for Difficulty { type Output = Difficulty; fn mul(self, other: Difficulty) -> Difficulty { - Difficulty { num: self.num * other.num } + Difficulty { + num: self.num * other.num, + } } } impl Div for Difficulty { type Output = Difficulty; fn div(self, other: Difficulty) -> Difficulty { - Difficulty { num: self.num / other.num } + Difficulty { + num: self.num / other.num, + } } } @@ -157,6 +167,8 @@ impl<'de> de::Visitor<'de> for DiffVisitor { &"a value number", )); }; - Ok(Difficulty { num: num_in.unwrap() }) + Ok(Difficulty { + num: num_in.unwrap(), + }) } } diff --git a/core/src/core/transaction.rs b/core/src/core/transaction.rs index dea67b17d..47796b0ee 100644 --- a/core/src/core/transaction.rs +++ b/core/src/core/transaction.rs @@ -14,7 +14,7 @@ //! Transactions -use byteorder::{ByteOrder, BigEndian}; +use byteorder::{BigEndian, ByteOrder}; use blake2::blake2b::blake2b; use util::secp::{self, Secp256k1, Message, Signature}; use util::secp::pedersen::{RangeProof, Commitment}; @@ -23,7 +23,7 @@ use std::ops; use core::Committed; use core::pmmr::Summable; use keychain::{Identifier, Keychain}; -use ser::{self, Reader, Writer, Readable, Writeable, WriteableSorted, read_and_verify_sorted}; +use ser::{self, read_and_verify_sorted, Readable, Reader, Writeable, WriteableSorted, Writer}; use util::LOGGER; /// The size to use for the stored blake2 hash of a switch_commitment @@ -102,9 +102,8 @@ impl Writeable for TxKernel { impl Readable for TxKernel { fn read(reader: &mut Reader) -> Result { - let features = KernelFeatures::from_bits(reader.read_u8()?).ok_or( - ser::Error::CorruptedData, - )?; + let features = + KernelFeatures::from_bits(reader.read_u8()?).ok_or(ser::Error::CorruptedData)?; Ok(TxKernel { features: features, @@ -287,12 +286,12 @@ impl Transaction { let sig = Signature::from_der(secp, &self.excess_sig)?; // pretend the sum is a public key (which it is, being of the form r.G) and - // verify the transaction sig with it - // - // we originally converted the commitment to a key_id here (commitment to zero) - // and then passed the key_id to secp.verify() - // the secp api no longer allows us to do this so we have wrapped the complexity - // of generating a public key from a commitment behind verify_from_commit + // verify the transaction sig with it + // + // we originally converted the commitment to a key_id here (commitment to zero) + // and then passed the key_id to secp.verify() + // the secp api no longer allows us to do this so we have wrapped the complexity + // of generating a public key from a commitment behind verify_from_commit secp.verify_from_commit(&msg, &sig, &rsum)?; let kernel = TxKernel { @@ -456,9 +455,8 @@ impl Writeable for Output { /// an Output from a binary stream. impl Readable for Output { fn read(reader: &mut Reader) -> Result { - let features = OutputFeatures::from_bits(reader.read_u8()?).ok_or( - ser::Error::CorruptedData, - )?; + let features = + OutputFeatures::from_bits(reader.read_u8()?).ok_or(ser::Error::CorruptedData)?; Ok(Output { features: features, @@ -494,13 +492,11 @@ impl Output { /// value from the range proof and the commitment pub fn recover_value(&self, keychain: &Keychain, key_id: &Identifier) -> Option { match keychain.rewind_range_proof(key_id, self.commit, self.proof) { - Ok(proof_info) => { - if proof_info.success { - Some(proof_info.value) - } else { - None - } - } + Ok(proof_info) => if proof_info.success { + Some(proof_info.value) + } else { + None + }, Err(_) => None, } } @@ -554,10 +550,9 @@ impl ops::Add for SumCommit { type Output = SumCommit; fn add(self, other: SumCommit) -> SumCommit { - let sum = match self.secp.commit_sum( - vec![self.commit.clone(), other.commit.clone()], - vec![], - ) { + let sum = match self.secp + .commit_sum(vec![self.commit.clone(), other.commit.clone()], vec![]) + { Ok(s) => s, Err(_) => Commitment::from_vec(vec![1; 33]), }; diff --git a/core/src/global.rs b/core/src/global.rs index 97e6a2b14..44883346b 100644 --- a/core/src/global.rs +++ b/core/src/global.rs @@ -61,8 +61,8 @@ pub enum MiningParameterMode { } lazy_static!{ - /// The mining parameter mode - pub static ref MINING_PARAMETER_MODE: RwLock = + /// The mining parameter mode + pub static ref MINING_PARAMETER_MODE: RwLock = RwLock::new(MiningParameterMode::Production); } diff --git a/core/src/lib.rs b/core/src/lib.rs index b4f1df24a..ebfe187dd 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -25,8 +25,10 @@ extern crate bitflags; extern crate blake2_rfc as blake2; extern crate byteorder; +extern crate grin_keychain as keychain; +extern crate grin_util as util; #[macro_use] -extern crate slog; +extern crate lazy_static; extern crate num_bigint as bigint; extern crate rand; extern crate grin_keychain as keychain; @@ -34,9 +36,9 @@ extern crate grin_util as util; extern crate serde; #[macro_use] extern crate serde_derive; -extern crate time; #[macro_use] -extern crate lazy_static; +extern crate slog; +extern crate time; #[macro_use] pub mod macros; diff --git a/core/src/ser.rs b/core/src/ser.rs index 08147b919..32e4e1c95 100644 --- a/core/src/ser.rs +++ b/core/src/ser.rs @@ -19,9 +19,9 @@ //! To use it simply implement `Writeable` or `Readable` and then use the //! `serialize` or `deserialize` functions on them as appropriate. -use std::{error, fmt, cmp}; -use std::io::{self, Write, Read}; -use byteorder::{ByteOrder, ReadBytesExt, BigEndian}; +use std::{cmp, error, fmt}; +use std::io::{self, Read, Write}; +use byteorder::{BigEndian, ByteOrder, ReadBytesExt}; use keychain::{Identifier, IDENTIFIER_SIZE}; use core::hash::Hashed; use consensus::VerifySortOrder; @@ -199,7 +199,8 @@ pub trait WriteableSorted { /// A consensus rule requires everything is sorted lexicographically to avoid /// leaking any information through specific ordering of items. pub fn read_and_verify_sorted(reader: &mut Reader, count: u64) -> Result, Error> - where T: Readable + Hashed + Writeable +where + T: Readable + Hashed + Writeable, { let result: Vec = try!((0..count).map(|_| T::read(reader)).collect()); result.verify_sort_order()?; @@ -276,9 +277,10 @@ impl<'a> Reader for BinReader<'a> { return Err(Error::TooLargeReadErr); } let mut buf = vec![0; length]; - self.source.read_exact(&mut buf).map(move |_| buf).map_err( - Error::IOErr, - ) + self.source + .read_exact(&mut buf) + .map(move |_| buf) + .map_err(Error::IOErr) } fn expect_u8(&mut self, val: u8) -> Result { @@ -532,7 +534,8 @@ impl AsFixedBytes for [u8; 20] { fn len(&self) -> usize { return 20; } -}impl AsFixedBytes for [u8; 32] { +} +impl AsFixedBytes for [u8; 32] { fn len(&self) -> usize { return 32; } diff --git a/doc/build.md b/doc/build.md index 62fa4d3e2..a50e2c7a6 100644 --- a/doc/build.md +++ b/doc/build.md @@ -105,7 +105,7 @@ Before running your mining server, a wallet server needs to be set up and listen See [wallet](wallet.md) for more info on the various Grin wallet commands and options. -This will create a wallet server listening on the default port 13416 with the password "password". Next, in another terminal window in the 'node1' directory, run a full mining node with the following command: +This will create a wallet server listening on the default port 13415 with the password "password". Next, in another terminal window in the 'node1' directory, run a full mining node with the following command: node1$ grin server -m run diff --git a/grin.toml b/grin.toml index 175189585..7aef20fec 100644 --- a/grin.toml +++ b/grin.toml @@ -111,11 +111,11 @@ attempt_time_per_block = 90 #the wallet reciever to which coinbase rewards will be sent -wallet_receiver_url = "http://127.0.0.1:13416" +wallet_receiver_url = "http://127.0.0.1:13415" #whether to ignore the reward (mostly for testing) -burn_reward = false +burn_reward = true #testing value, optional #slow_down_in_millis = 30 diff --git a/grin/Cargo.toml b/grin/Cargo.toml index 7aa4cbe43..3b3b31e4d 100644 --- a/grin/Cargo.toml +++ b/grin/Cargo.toml @@ -27,6 +27,7 @@ serde_json = "~1.0.2" tokio-core="~0.1.1" tokio-timer="~0.1.0" rand = "^0.3" +router = "~0.5.1" itertools = "~0.6.0" [dev_dependencies] diff --git a/grin/src/adapters.rs b/grin/src/adapters.rs index ac291bcae..062299404 100644 --- a/grin/src/adapters.rs +++ b/grin/src/adapters.rs @@ -21,7 +21,7 @@ use core::core::{self, Output}; use core::core::block::BlockHeader; use core::core::hash::{Hash, Hashed}; use core::core::target::Difficulty; -use p2p::{self, NetAdapter, Server, PeerStore, PeerData, State}; +use p2p::{self, NetAdapter, PeerData, PeerStore, Server, State}; use pool; use util::secp::pedersen::Commitment; use util::OneTime; @@ -180,11 +180,8 @@ impl NetAdapter for NetToChainAdapter { /// Find good peers we know with the provided capability and return their /// addresses. fn find_peer_addrs(&self, capab: p2p::Capabilities) -> Vec { - let peers = self.peer_store.find_peers( - State::Healthy, - capab, - p2p::MAX_PEER_ADDRS as usize, - ); + let peers = self.peer_store + .find_peers(State::Healthy, capab, p2p::MAX_PEER_ADDRS as usize); debug!(LOGGER, "Got {} peer addrs to send.", peers.len()); map_vec!(peers, |p| p.addr) } @@ -244,11 +241,11 @@ impl NetToChainAdapter { pub fn start_sync(&self, sync: sync::Syncer) { let arc_sync = Arc::new(sync); self.syncer.init(arc_sync.clone()); - let _ = thread::Builder::new().name("syncer".to_string()).spawn( - move || { + let _ = thread::Builder::new() + .name("syncer".to_string()) + .spawn(move || { let _ = arc_sync.run(); - }, - ); + }); } pub fn syncing(&self) -> bool { @@ -325,7 +322,9 @@ impl pool::PoolAdapter for PoolToNetAdapter { impl PoolToNetAdapter { /// Create a new pool to net adapter pub fn new() -> PoolToNetAdapter { - PoolToNetAdapter { p2p: OneTime::new() } + PoolToNetAdapter { + p2p: OneTime::new(), + } } /// Setup the p2p server on the adapter @@ -345,7 +344,9 @@ pub struct PoolToChainAdapter { impl PoolToChainAdapter { /// Create a new pool adapter pub fn new() -> PoolToChainAdapter { - PoolToChainAdapter { chain: OneTime::new() } + PoolToChainAdapter { + chain: OneTime::new(), + } } pub fn set_chain(&self, chain_ref: Arc) { @@ -355,13 +356,14 @@ impl PoolToChainAdapter { impl pool::BlockChain for PoolToChainAdapter { fn get_unspent(&self, output_ref: &Commitment) -> Result { - self.chain.borrow().get_unspent(output_ref).map_err( - |e| match e { + self.chain + .borrow() + .get_unspent(output_ref) + .map_err(|e| match e { chain::types::Error::OutputNotFound => pool::PoolError::OutputNotFound, chain::types::Error::OutputSpent => pool::PoolError::OutputSpent, _ => pool::PoolError::GenericPoolError, - }, - ) + }) } fn get_block_header_by_output_commit( @@ -375,8 +377,9 @@ impl pool::BlockChain for PoolToChainAdapter { } fn head_header(&self) -> Result { - self.chain.borrow().head_header().map_err(|_| { - pool::PoolError::GenericPoolError - }) + self.chain + .borrow() + .head_header() + .map_err(|_| pool::PoolError::GenericPoolError) } } diff --git a/grin/src/lib.rs b/grin/src/lib.rs index ae12b57b8..d5c5df06a 100644 --- a/grin/src/lib.rs +++ b/grin/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2016 The Grin Developers +// Copyright 2016-2017 The Grin Developers // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -21,32 +21,32 @@ #![deny(unused_mut)] #![warn(missing_docs)] -#[macro_use] -extern crate slog; extern crate futures; extern crate futures_cpupool as cpupool; extern crate hyper; +extern crate itertools; extern crate rand; extern crate serde; #[macro_use] extern crate serde_derive; extern crate serde_json; +#[macro_use] +extern crate slog; extern crate time; extern crate tokio_core; extern crate tokio_timer; -extern crate itertools; extern crate grin_api as api; extern crate grin_chain as chain; #[macro_use] extern crate grin_core as core; +extern crate grin_keychain as keychain; extern crate grin_p2p as p2p; extern crate grin_pool as pool; +extern crate grin_pow as pow; extern crate grin_store as store; extern crate grin_util as util; -extern crate grin_keychain as keychain; extern crate grin_wallet as wallet; -extern crate grin_pow as pow; mod adapters; mod server; @@ -56,4 +56,4 @@ mod types; mod miner; pub use server::Server; -pub use types::{ServerConfig, Seeding, ServerStats}; +pub use types::{Seeding, ServerConfig, ServerStats}; diff --git a/grin/src/miner.rs b/grin/src/miner.rs index e3aefa792..0e7856060 100644 --- a/grin/src/miner.rs +++ b/grin/src/miner.rs @@ -17,7 +17,7 @@ use rand::{self, Rng}; use std::sync::{Arc, RwLock}; -use std::{thread, str}; +use std::{str, thread}; use std; use time; @@ -97,7 +97,6 @@ impl ser::Writer for HeaderPartWriter { for i in 0..bytes_in.len() { self.pre_nonce.push(bytes_in.as_ref()[i]) } - } else if self.bytes_written != 0 { for i in 0..bytes_in.len() { self.post_nonce.push(bytes_in.as_ref()[i]) @@ -158,7 +157,6 @@ impl Miner { latest_hash: &Hash, attempt_time_per_block: u32, ) -> Option { - debug!( LOGGER, "(Server ID: {}) Mining at Cuckoo{} for at most {} secs at height {} and difficulty {}.", @@ -170,9 +168,9 @@ impl Miner { ); // look for a pow for at most attempt_time_per_block sec on the - // same block (to give a chance to new - // transactions) and as long as the head hasn't changed - // Will change this to something else at some point + // same block (to give a chance to new + // transactions) and as long as the head hasn't changed + // Will change this to something else at some point let deadline = time::get_time().sec + attempt_time_per_block as i64; // how often to output stats @@ -215,7 +213,7 @@ impl Miner { debug!( LOGGER, "Mining: Plugin {} - Device {} ({}): Last Solution time: {}s; \ - Solutions per second: {:.*} - Total Attempts: {}", + Solutions per second: {:.*} - Total Attempts: {}", i, s.device_id, s.device_name, @@ -248,7 +246,6 @@ impl Miner { job_handle.stop_jobs(); sol - } /// The inner part of mining loop for cuckoo miner sync mode @@ -262,8 +259,8 @@ impl Miner { latest_hash: &mut Hash, ) -> Option { // look for a pow for at most attempt_time_per_block sec on the same block (to - // give a chance to new - // transactions) and as long as the head hasn't changed + // give a chance to new + // transactions) and as long as the head hasn't changed let deadline = time::get_time().sec + attempt_time_per_block as i64; let stat_check_interval = 3; let mut next_stat_check = time::get_time().sec + stat_check_interval; @@ -271,7 +268,7 @@ impl Miner { debug!( LOGGER, "(Server ID: {}) Mining at Cuckoo{} for {} secs (will wait for last solution) \ - on block {} at difficulty {}.", + on block {} at difficulty {}.", self.debug_output_id, cuckoo_size, attempt_time_per_block, @@ -291,7 +288,6 @@ impl Miner { let mut sol = None; while head.hash() == *latest_hash && time::get_time().sec < deadline { - let pow_hash = b.hash(); if let Ok(proof) = plugin_miner.mine(&pow_hash[..]) { let proof_diff = proof.clone().to_difficulty(); @@ -324,8 +320,8 @@ impl Miner { iter_count += 1; // Artificial slow down - if self.config.slow_down_in_millis != None && - self.config.slow_down_in_millis.unwrap() > 0 + if self.config.slow_down_in_millis != None + && self.config.slow_down_in_millis.unwrap() > 0 { thread::sleep(std::time::Duration::from_millis( self.config.slow_down_in_millis.unwrap(), @@ -356,7 +352,7 @@ impl Miner { latest_hash: &mut Hash, ) -> Option { // look for a pow for at most 2 sec on the same block (to give a chance to new - // transactions) and as long as the head hasn't changed + // transactions) and as long as the head hasn't changed let deadline = time::get_time().sec + attempt_time_per_block as i64; debug!( @@ -381,7 +377,6 @@ impl Miner { let mut sol = None; while head.hash() == *latest_hash && time::get_time().sec < deadline { - let pow_hash = b.hash(); if let Ok(proof) = miner.mine(&pow_hash[..]) { let proof_diff = proof.clone().to_difficulty(); @@ -396,8 +391,8 @@ impl Miner { iter_count += 1; // Artificial slow down - if self.config.slow_down_in_millis != None && - self.config.slow_down_in_millis.unwrap() > 0 + if self.config.slow_down_in_millis != None + && self.config.slow_down_in_millis.unwrap() > 0 { thread::sleep(std::time::Duration::from_millis( self.config.slow_down_in_millis.unwrap(), @@ -419,7 +414,6 @@ impl Miner { /// Starts the mining loop, building a new block on top of the existing /// chain anytime required and looking for PoW solution. pub fn run_loop(&self, miner_config: MinerConfig, cuckoo_size: u32, proof_size: usize) { - info!( LOGGER, "(Server ID: {}) Starting miner loop.", @@ -443,8 +437,8 @@ impl Miner { } // to prevent the wallet from generating a new HD key derivation for each - // iteration, we keep the returned derivation to provide it back when - // nothing has changed + // iteration, we keep the returned derivation to provide it back when + // nothing has changed let mut key_id = None; loop { @@ -550,9 +544,10 @@ impl Miner { let difficulty = consensus::next_difficulty(diff_iter).unwrap(); // extract current transaction from the pool - let txs_box = self.tx_pool.read().unwrap().prepare_mineable_transactions( - MAX_TX, - ); + let txs_box = self.tx_pool + .read() + .unwrap() + .prepare_mineable_transactions(MAX_TX); let txs: Vec<&Transaction> = txs_box.iter().map(|tx| tx.as_ref()).collect(); // build the coinbase and the block itself @@ -564,7 +559,8 @@ impl Miner { height, }; - // TODO - error handling, things can go wrong with get_coinbase (wallet api down etc.) + // TODO - error handling, things can go wrong with get_coinbase (wallet api + // down etc.) let (output, kernel, block_fees) = self.get_coinbase(block_fees).unwrap(); let mut b = core::Block::with_reward(head, txs, output, kernel).unwrap(); @@ -585,9 +581,9 @@ impl Miner { b.header.nonce = rng.gen(); b.header.difficulty = difficulty; b.header.timestamp = time::at_utc(time::Timespec::new(now_sec, 0)); - self.chain.set_sumtree_roots(&mut b).expect( - "Error setting sum tree roots", - ); + self.chain + .set_sumtree_roots(&mut b) + .expect("Error setting sum tree roots"); (b, block_fees) } @@ -600,8 +596,8 @@ impl Miner { ) -> Result<(core::Output, core::TxKernel, BlockFees), Error> { let keychain = Keychain::from_random_seed().unwrap(); let key_id = keychain.derive_key_id(1).unwrap(); - let (out, kernel) = core::Block::reward_output(&keychain, &key_id, block_fees.fees) - .unwrap(); + let (out, kernel) = + core::Block::reward_output(&keychain, &key_id, block_fees.fees).unwrap(); Ok((out, kernel, block_fees)) } @@ -613,8 +609,9 @@ impl Miner { self.burn_reward(block_fees) } else { let url = format!( - "{}/v2/receive/coinbase", - self.config.wallet_receiver_url.as_str()); + "{}/v1/receive/coinbase", + self.config.wallet_receiver_url.as_str() + ); let res = wallet::client::create_coinbase(&url, &block_fees)?; diff --git a/grin/src/seed.rs b/grin/src/seed.rs index 0860ec3e0..44a9844e5 100644 --- a/grin/src/seed.rs +++ b/grin/src/seed.rs @@ -63,14 +63,13 @@ impl Seeder { seed_list: Box, Error = String>>, ) { // open a channel with a listener that connects every peer address sent below - // max peer count + // max peer count let (tx, rx) = futures::sync::mpsc::unbounded(); h.spawn(self.listen_for_addrs(h.clone(), rx)); // check seeds and start monitoring connections - let seeder = self.connect_to_seeds(tx.clone(), seed_list).join( - self.monitor_peers(tx.clone()), - ); + let seeder = self.connect_to_seeds(tx.clone(), seed_list) + .join(self.monitor_peers(tx.clone())); h.spawn(seeder.map(|_| ()).map_err(|e| { error!(LOGGER, "Seeding or peer monitoring error: {}", e); @@ -86,13 +85,12 @@ impl Seeder { let p2p_server = self.p2p.clone(); // now spawn a new future to regularly check if we need to acquire more peers - // and if so, gets them from db + // and if so, gets them from db let mon_loop = Timer::default() .interval(time::Duration::from_secs(10)) .for_each(move |_| { - // maintenance step first, clean up p2p server peers and mark bans - // if needed + // if needed let disconnected = p2p_server.clean_peers(); for p in disconnected { if p.is_banned() { @@ -135,7 +133,7 @@ impl Seeder { } // Check if we have any pre-existing peer in db. If so, start with those, - // otherwise use the seeds provided. + // otherwise use the seeds provided. fn connect_to_seeds( &self, tx: mpsc::UnboundedSender, @@ -144,7 +142,7 @@ impl Seeder { let peer_store = self.peer_store.clone(); // a thread pool is required so we don't block the event loop with a - // db query + // db query let thread_pool = cpupool::CpuPool::new(1); let seeder = thread_pool .spawn_fn(move || { @@ -231,8 +229,10 @@ pub fn web_seeds(h: reactor::Handle) -> Box, Error }) .and_then(|res| { // collect all chunks and split around whitespace to get a list of SocketAddr - res.body().collect().map_err(|e| e.to_string()).and_then( - |chunks| { + res.body() + .collect() + .map_err(|e| e.to_string()) + .and_then(|chunks| { let res = chunks.iter().fold("".to_string(), |acc, ref chunk| { acc + str::from_utf8(&chunk[..]).unwrap() }); @@ -240,8 +240,7 @@ pub fn web_seeds(h: reactor::Handle) -> Box, Error .map(|s| s.parse().unwrap()) .collect::>(); Ok(addrs) - }, - ) + }) }) }); Box::new(seeds) diff --git a/grin/src/server.rs b/grin/src/server.rs index 3233535ab..a32f842ae 100644 --- a/grin/src/server.rs +++ b/grin/src/server.rs @@ -79,7 +79,6 @@ impl Server { /// Instantiates a new server associated with the provided future reactor. pub fn future(mut config: ServerConfig, evt_handle: &reactor::Handle) -> Result { - let pool_adapter = Arc::new(PoolToChainAdapter::new()); let pool_net_adapter = Arc::new(PoolToNetAdapter::new()); let tx_pool = Arc::new(RwLock::new(pool::TransactionPool::new( diff --git a/grin/src/sync.rs b/grin/src/sync.rs index a1a788145..14b75dd26 100644 --- a/grin/src/sync.rs +++ b/grin/src/sync.rs @@ -23,7 +23,7 @@ const MAX_BODY_DOWNLOADS: usize = 8; use std::ops::{Deref, DerefMut}; use std::sync::{Arc, Mutex}; use std::thread; -use std::time::{Instant, Duration}; +use std::time::{Duration, Instant}; use core::core::hash::{Hash, Hashed}; use chain; @@ -87,7 +87,7 @@ impl Syncer { self.init_download()?; // main syncing loop, requests more headers and bodies periodically as long - // as a peer with higher difficulty exists and we're not fully caught up + // as a peer with higher difficulty exists and we're not fully caught up info!(LOGGER, "Starting sync loop."); loop { let tip = self.chain.get_header_head()?; @@ -139,7 +139,7 @@ impl Syncer { let mut blocks_to_download = self.blocks_to_download.lock().unwrap(); // go back the chain and insert for download all blocks we only have the - // head for + // head for let mut prev_h = header_head.last_block_h; while prev_h != full_head.last_block_h { let header = self.chain.get_block_header(&prev_h)?; @@ -184,7 +184,7 @@ impl Syncer { } // consume hashes from blocks to download, place them in downloading and - // request them from the network + // request them from the network let mut count = 0; while blocks_to_download.len() > 0 && blocks_downloading.len() < MAX_BODY_DOWNLOADS { let h = blocks_to_download.pop().unwrap(); @@ -197,21 +197,21 @@ impl Syncer { }); } debug!( - LOGGER, + LOGGER, "Requested {} full blocks to download, total left: {}. Current list: {:?}.", - count, + count, blocks_to_download.len(), - blocks_downloading.deref(), - ); + blocks_downloading.deref(), + ); } /// We added a block, clean up the downloading structure pub fn block_received(&self, bh: Hash) { // just clean up the downloading list let mut bds = self.blocks_downloading.lock().unwrap(); - bds.iter().position(|ref h| h.hash == bh).map( - |n| bds.remove(n), - ); + bds.iter() + .position(|ref h| h.hash == bh) + .map(|n| bds.remove(n)); } /// Request some block headers from a peer to advance us @@ -257,7 +257,7 @@ impl Syncer { /// us the right block headers. fn get_locator(&self, tip: &chain::Tip) -> Result, Error> { // Prepare the heights we want as the latests height minus increasing powers - // of 2 up to max. + // of 2 up to max. let mut heights = vec![tip.height]; let mut tail = (1..p2p::MAX_LOCATORS) .map(|n| 2u64.pow(n)) @@ -271,7 +271,7 @@ impl Syncer { debug!(LOGGER, "Loc heights: {:?}", heights); // Iteratively travel the header chain back from our head and retain the - // headers at the wanted heights. + // headers at the wanted heights. let mut header = self.chain.get_block_header(&tip.last_block_h)?; let mut locator = vec![]; while heights.len() > 0 { diff --git a/grin/src/types.rs b/grin/src/types.rs index 1c91a7a24..2846a37a7 100644 --- a/grin/src/types.rs +++ b/grin/src/types.rs @@ -119,7 +119,7 @@ impl Default for ServerConfig { fn default() -> ServerConfig { ServerConfig { db_root: ".grin".to_string(), - api_http_addr: "0.0.0.0:13415".to_string(), + api_http_addr: "0.0.0.0:13413".to_string(), capabilities: p2p::FULL_NODE, seeding_type: Seeding::None, seeds: None, diff --git a/grin/tests/framework.rs b/grin/tests/framework/mod.rs similarity index 93% rename from grin/tests/framework.rs rename to grin/tests/framework/mod.rs index 16c6cb0fa..96b135d8f 100644 --- a/grin/tests/framework.rs +++ b/grin/tests/framework/mod.rs @@ -12,21 +12,21 @@ // See the License for the specific language governing permissions and // limitations under the License. -extern crate grin_grin as grin; -extern crate grin_core as core; -extern crate grin_p2p as p2p; -extern crate grin_chain as chain; extern crate grin_api as api; -extern crate grin_wallet as wallet; +extern crate grin_chain as chain; +extern crate grin_core as core; +extern crate grin_grin as grin; extern crate grin_keychain as keychain; +extern crate grin_p2p as p2p; extern crate grin_pow as pow; extern crate grin_util as util; +extern crate grin_wallet as wallet; extern crate blake2_rfc as blake2; extern crate futures; +extern crate futures_cpupool; extern crate tokio_core; extern crate tokio_timer; -extern crate futures_cpupool; use std::thread; use std::time; @@ -42,9 +42,7 @@ use util::secp::Secp256k1; use self::keychain::Keychain; use wallet::WalletConfig; - /// Just removes all results from previous runs - pub fn clean_all_output(test_name_dir: &str) { let target_dir = format!("target/test_servers/{}", test_name_dir); let result = fs::remove_dir_all(target_dir); @@ -116,9 +114,9 @@ impl Default for LocalServerContainerConfig { LocalServerContainerConfig { name: String::from("test_host"), base_addr: String::from("127.0.0.1"), + api_server_port: 13413, p2p_server_port: 13414, - api_server_port: 13415, - wallet_port: 13416, + wallet_port: 13415, seed_addr: String::from(""), is_seeding: false, start_miner: false, @@ -172,15 +170,15 @@ impl LocalServerContainer { let working_dir = format!("target/test_servers/{}", config.name); Ok( (LocalServerContainer { - config: config, - p2p_server_stats: None, - api_server: None, - server_is_running: false, - server_is_mining: false, - wallet_is_running: false, - working_dir: working_dir, - peer_list: Vec::new(), - }), + config: config, + p2p_server_stats: None, + api_server: None, + server_is_running: false, + server_is_mining: false, + wallet_is_running: false, + working_dir: working_dir, + peer_list: Vec::new(), + }), ) } @@ -256,14 +254,12 @@ impl LocalServerContainer { } s.get_server_stats().unwrap() - } /// Starts a wallet daemon to receive and returns the /// listening server url pub fn run_wallet(&mut self, _duration_in_seconds: u64) { - // URL on which to start the wallet listener (i.e. api server) let url = format!("{}:{}", self.config.base_addr, self.config.wallet_port); @@ -287,23 +283,22 @@ impl LocalServerContainer { wallet_config.check_node_api_http_addr = self.config.wallet_validating_node_url.clone(); wallet_config.data_file_dir = self.working_dir.clone(); + let receive_tx_handler = wallet::WalletReceiver { + config: wallet_config.clone(), + keychain: keychain.clone(), + }; + let router = router!( + receive_tx: get "/receive/transaction" => receive_tx_handler, + ); + let mut api_server = api::ApiServer::new("/v1".to_string()); - - api_server.register_endpoint( - "/receive".to_string(), - wallet::WalletReceiver { - keychain: keychain, - config: wallet_config, - }, - ); - + api_server.register_handler(router); api_server.start(url).unwrap_or_else(|e| { println!("Failed to start Grin wallet receiver: {}.", e); }); self.api_server = Some(api_server); self.wallet_is_running = true; - } /// Stops the running wallet server @@ -384,13 +379,13 @@ pub struct LocalServerContainerPool { impl LocalServerContainerPool { pub fn new(config: LocalServerContainerPoolConfig) -> LocalServerContainerPool { (LocalServerContainerPool { - next_api_port: config.base_api_port, - next_p2p_port: config.base_p2p_port, - next_wallet_port: config.base_wallet_port, - config: config, - server_containers: Vec::new(), - is_seeding: false, - }) + next_api_port: config.base_api_port, + next_p2p_port: config.base_p2p_port, + next_wallet_port: config.base_wallet_port, + config: config, + server_containers: Vec::new(), + is_seeding: false, + }) } /// adds a single server on the next available port @@ -400,7 +395,6 @@ impl LocalServerContainerPool { /// pub fn create_server(&mut self, server_config: &mut LocalServerContainerConfig) { - // If we're calling it this way, need to override these server_config.p2p_server_port = self.next_p2p_port; server_config.api_server_port = self.next_api_port; @@ -440,12 +434,10 @@ impl LocalServerContainerPool { // self.server_containers.push(server_arc); // Create a future that runs the server for however many seconds - // collect them all and run them in the run_all_servers + // collect them all and run them in the run_all_servers let _run_time = self.config.run_length_in_seconds; self.server_containers.push(server_container); - - } /// adds n servers, ready to run @@ -463,7 +455,6 @@ impl LocalServerContainerPool { /// pub fn run_all_servers(self) -> Vec { - let run_length = self.config.run_length_in_seconds; let mut handles = vec![]; @@ -477,18 +468,17 @@ impl LocalServerContainerPool { let handle = thread::spawn(move || { if is_seeding && !s.config.is_seeding { // there's a seed and we're not it, so hang around longer and give the seed - // a chance to start + // a chance to start thread::sleep(time::Duration::from_millis(2000)); } let server_ref = s.run_server(run_length); return_container_ref.lock().unwrap().push(server_ref); }); // Not a big fan of sleeping hack here, but there appears to be a - // concurrency issue when creating files in rocksdb that causes - // failure if we don't pause a bit before starting the next server + // concurrency issue when creating files in rocksdb that causes + // failure if we don't pause a bit before starting the next server thread::sleep(time::Duration::from_millis(500)); handles.push(handle); - } for handle in handles { @@ -508,7 +498,6 @@ impl LocalServerContainerPool { pub fn connect_all_peers(&mut self) { /// just pull out all currently active servers, build a list, /// and feed into all servers - let mut server_addresses: Vec = Vec::new(); for s in &self.server_containers { let server_address = format!("{}:{}", s.config.base_addr, s.config.p2p_server_port); diff --git a/grin/tests/simulnet.rs b/grin/tests/simulnet.rs index 0971f115b..d328e3b39 100644 --- a/grin/tests/simulnet.rs +++ b/grin/tests/simulnet.rs @@ -12,14 +12,17 @@ // See the License for the specific language governing permissions and // limitations under the License. -extern crate grin_grin as grin; -extern crate grin_core as core; -extern crate grin_p2p as p2p; -extern crate grin_chain as chain; +#[macro_use] +extern crate router; + extern crate grin_api as api; -extern crate grin_wallet as wallet; +extern crate grin_chain as chain; +extern crate grin_core as core; +extern crate grin_grin as grin; +extern crate grin_p2p as p2p; extern crate grin_pow as pow; extern crate grin_util as util; +extern crate grin_wallet as wallet; extern crate futures; extern crate tokio_core; @@ -31,7 +34,7 @@ use std::thread; use std::time; use std::default::Default; -use futures::{Future, Poll, Async}; +use futures::{Async, Future, Poll}; use futures::task::current; use tokio_core::reactor; use tokio_timer::Timer; @@ -41,8 +44,8 @@ use core::global; use core::global::{MiningParameterMode, MINING_PARAMETER_MODE}; use wallet::WalletConfig; -use framework::{LocalServerContainer, LocalServerContainerConfig, LocalServerContainerPoolConfig, - LocalServerContainerPool}; +use framework::{LocalServerContainer, LocalServerContainerConfig, LocalServerContainerPool, + LocalServerContainerPoolConfig}; /// Testing the frameworks by starting a fresh server, creating a genesis /// Block and mining into a wallet for a bit @@ -71,7 +74,6 @@ fn basic_genesis_mine() { pool.create_server(&mut server_config); pool.run_all_servers(); - } /// Creates 5 servers, first being a seed and check that through peer address @@ -175,10 +177,8 @@ fn simulate_parallel_mining() { let _ = pool.run_all_servers(); // Check mining difficulty here?, though I'd think it's more valuable - // to simply output it. Can at least see the evolution of the difficulty target - // in the debug log output for now - - + // to simply output it. Can at least see the evolution of the difficulty target + // in the debug log output for now } // TODO: Convert these tests to newer framework format @@ -186,6 +186,7 @@ fn simulate_parallel_mining() { /// gets propagated to all. #[test] fn a_simulate_block_propagation() { + util::init_test_logger(); global::set_mining_mode(MiningParameterMode::AutomatedTesting); let test_name_dir = "grin-prop"; @@ -243,7 +244,7 @@ fn a_simulate_block_propagation() { let original_height = servers[0].head().height; // monitor for a change of head on a different server and check whether - // chain height has changed + // chain height has changed evtlp.run(change(&servers[4]).and_then(|tip| { assert!(tip.height == original_height + 1); Ok(()) diff --git a/keychain/src/extkey.rs b/keychain/src/extkey.rs index d13e6bc26..78c3235f6 100644 --- a/keychain/src/extkey.rs +++ b/keychain/src/extkey.rs @@ -17,7 +17,7 @@ use std::cmp::min; use serde::{de, ser}; -use byteorder::{ByteOrder, BigEndian}; +use byteorder::{BigEndian, ByteOrder}; use blake2::blake2b::blake2b; use util::secp; use util::secp::Secp256k1; @@ -253,11 +253,11 @@ impl ExtendedKey { let derived = blake2b(64, &self.chaincode[..], &seed[..]); - let mut secret_key = SecretKey::from_slice(&secp, &derived.as_bytes()[0..32]) + let mut secret_key = + SecretKey::from_slice(&secp, &derived.as_bytes()[0..32]).expect("Error deriving key"); + secret_key + .add_assign(secp, &self.key) .expect("Error deriving key"); - secret_key.add_assign(secp, &self.key).expect( - "Error deriving key", - ); // TODO check if key != 0 ? let mut chain_code: [u8; 32] = [0; 32]; @@ -312,13 +312,10 @@ mod test { let s = Secp256k1::new(); let seed = from_hex("000102030405060708090a0b0c0d0e0f"); let extk = ExtendedKey::from_seed(&s, &seed.as_slice()).unwrap(); - let sec = from_hex( - "c3f5ae520f474b390a637de4669c84d0ed9bbc21742577fac930834d3c3083dd", - ); + let sec = from_hex("c3f5ae520f474b390a637de4669c84d0ed9bbc21742577fac930834d3c3083dd"); let secret_key = SecretKey::from_slice(&s, sec.as_slice()).unwrap(); - let chaincode = from_hex( - "e7298e68452b0c6d54837670896e1aee76b118075150d90d4ee416ece106ae72", - ); + let chaincode = + from_hex("e7298e68452b0c6d54837670896e1aee76b118075150d90d4ee416ece106ae72"); let identifier = from_hex("83e59c48297b78b34b73"); let depth = 0; let n_child = 0; @@ -343,13 +340,10 @@ mod test { let seed = from_hex("000102030405060708090a0b0c0d0e0f"); let extk = ExtendedKey::from_seed(&s, &seed.as_slice()).unwrap(); let derived = extk.derive(&s, 0).unwrap(); - let sec = from_hex( - "d75f70beb2bd3b56f9b064087934bdedee98e4b5aae6280c58b4eff38847888f", - ); + let sec = from_hex("d75f70beb2bd3b56f9b064087934bdedee98e4b5aae6280c58b4eff38847888f"); let secret_key = SecretKey::from_slice(&s, sec.as_slice()).unwrap(); - let chaincode = from_hex( - "243cb881e1549e714db31d23af45540b13ad07941f64a786bbf3313b4de1df52", - ); + let chaincode = + from_hex("243cb881e1549e714db31d23af45540b13ad07941f64a786bbf3313b4de1df52"); let root_key_id = from_hex("83e59c48297b78b34b73"); let identifier = from_hex("0185adb4d8b730099c93"); let depth = 1; diff --git a/keychain/src/keychain.rs b/keychain/src/keychain.rs index 275f25999..fc9fd0d86 100644 --- a/keychain/src/keychain.rs +++ b/keychain/src/keychain.rs @@ -20,7 +20,7 @@ use util::secp::{Message, Secp256k1, Signature}; use util::secp::key::SecretKey; use util::secp::pedersen::{Commitment, ProofMessage, ProofInfo, RangeProof}; use blake2; -use blind::{BlindingFactor, BlindSum}; +use blind::{BlindSum, BlindingFactor}; use extkey::{self, Identifier}; @@ -56,7 +56,7 @@ impl Keychain { } // For tests and burn only, associate a key identifier with a known secret key. - // + // pub fn burn_enabled(keychain: &Keychain, burn_key_id: &Identifier) -> Keychain { let mut key_overrides = HashMap::new(); key_overrides.insert( @@ -210,7 +210,7 @@ mod test { let msg = secp::Message::from_slice(&msg_bytes[..]).unwrap(); // now create a zero commitment using the key on the keychain associated with - // the key_id + // the key_id let commit = keychain.commit(0, &key_id).unwrap(); // now check we can use our key to verify a signature from this zero commitment @@ -232,7 +232,7 @@ mod test { assert_eq!(proof_info.value, 5); // now check the recovered message is "empty" (but not truncated) i.e. all - // zeroes + // zeroes assert_eq!( proof_info.message, secp::pedersen::ProofMessage::from_bytes(&[0; secp::constants::PROOF_MSG_SIZE]) diff --git a/keychain/src/lib.rs b/keychain/src/lib.rs index b3bd8a6ec..950014129 100644 --- a/keychain/src/lib.rs +++ b/keychain/src/lib.rs @@ -16,10 +16,10 @@ extern crate blake2_rfc as blake2; extern crate byteorder; +extern crate grin_util as util; extern crate rand; extern crate grin_util as util; extern crate serde; -#[macro_use] extern crate serde_derive; extern crate serde_json; @@ -27,6 +27,6 @@ mod blind; mod extkey; pub use blind::{BlindSum, BlindingFactor}; -pub use extkey::{Identifier, ExtendedKey, IDENTIFIER_SIZE}; +pub use extkey::{ExtendedKey, Identifier, IDENTIFIER_SIZE}; pub mod keychain; pub use keychain::{Error, Keychain}; diff --git a/p2p/src/conn.rs b/p2p/src/conn.rs index 584086350..687224cf9 100644 --- a/p2p/src/conn.rs +++ b/p2p/src/conn.rs @@ -17,13 +17,13 @@ use std::iter; use std::ops::Deref; -use std::sync::{Mutex, Arc}; -use std::time::{Instant, Duration}; +use std::sync::{Arc, Mutex}; +use std::time::{Duration, Instant}; use futures; -use futures::{Stream, Future}; +use futures::{Future, Stream}; use futures::stream; -use futures::sync::mpsc::{Sender, UnboundedSender, UnboundedReceiver}; +use futures::sync::mpsc::{Sender, UnboundedReceiver, UnboundedSender}; use tokio_core::net::TcpStream; use tokio_io::{AsyncRead, AsyncWrite}; use tokio_io::io::{read_exact, write_all}; @@ -54,7 +54,7 @@ pub trait Handler: Sync + Send { impl Handler for F where F: Fn(UnboundedSender>, MsgHeader, Vec) - -> Result, ser::Error>, + -> Result, ser::Error>, F: Sync + Send, { fn handle( @@ -99,7 +99,6 @@ impl Connection { where F: Handler + 'static, { - let (reader, writer) = conn.split(); // Set Max Read to 12 Mb/s @@ -112,9 +111,9 @@ impl Connection { // same for closing the connection let (close_tx, close_rx) = futures::sync::mpsc::channel(1); - let close_conn = close_rx.for_each(|_| Ok(())).map_err( - |_| Error::ConnectionClose, - ); + let close_conn = close_rx + .for_each(|_| Ok(())) + .map_err(|_| Error::ConnectionClose); let me = Connection { outbound_chan: tx.clone(), @@ -128,7 +127,7 @@ impl Connection { let read_msg = me.read_msg(tx, reader, handler).map(|_| ()); // setting the writing future, getting messages from our system and sending - // them out + // them out let write_msg = me.write_msg(rx, writer).map(|_| ()); // select between our different futures and return them @@ -152,7 +151,6 @@ impl Connection { where W: AsyncWrite + 'static, { - let sent_bytes = self.sent_bytes.clone(); let send_data = rx .map_err(|_| Error::ConnectionClose) @@ -181,9 +179,8 @@ impl Connection { F: Handler + 'static, R: AsyncRead + 'static, { - // infinite iterator stream so we repeat the message reading logic until the - // peer is stopped + // peer is stopped let iter = stream::iter_ok(iter::repeat(()).map(Ok::<(), Error>)); // setup the reading future, getting messages from the peer and processing them @@ -229,7 +226,6 @@ impl Connection { /// Utility function to send any Writeable. Handles adding the header and /// serialization. pub fn send_msg(&self, t: Type, body: &W) -> Result<(), Error> { - let mut body_data = vec![]; try!(ser::serialize(&mut body_data, body)); let mut data = vec![]; @@ -239,9 +235,9 @@ impl Connection { )); data.append(&mut body_data); - self.outbound_chan.unbounded_send(data).map_err(|_| { - Error::ConnectionClose - }) + self.outbound_chan + .unbounded_send(data) + .map_err(|_| Error::ConnectionClose) } /// Bytes sent and received by this peer to the remote peer. @@ -269,11 +265,10 @@ impl TimeoutConnection { where F: Handler + 'static, { - let expects = Arc::new(Mutex::new(vec![])); // Decorates the handler to remove the "subscription" from the expected - // responses. We got our replies, so no timeout should occur. + // responses. We got our replies, so no timeout should occur. let exp = expects.clone(); let (conn, fut) = Connection::listen(conn, move |sender, header: MsgHeader, data| { let msg_type = header.msg_type; diff --git a/p2p/src/handshake.rs b/p2p/src/handshake.rs index e674cda79..1829c8a50 100644 --- a/p2p/src/handshake.rs +++ b/p2p/src/handshake.rs @@ -44,7 +44,9 @@ unsafe impl Send for Handshake {} impl Handshake { /// Creates a new handshake handler pub fn new() -> Handshake { - Handshake { nonces: Arc::new(RwLock::new(VecDeque::with_capacity(NONCES_CAP))) } + Handshake { + nonces: Arc::new(RwLock::new(VecDeque::with_capacity(NONCES_CAP))), + } } /// Handles connecting to a new remote peer, starting the version handshake. diff --git a/p2p/src/lib.rs b/p2p/src/lib.rs index f3014ba3e..e67a8b0bd 100644 --- a/p2p/src/lib.rs +++ b/p2p/src/lib.rs @@ -22,25 +22,25 @@ #[macro_use] extern crate bitflags; +extern crate bytes; #[macro_use] extern crate enum_primitive; +extern crate futures; #[macro_use] extern crate grin_core as core; extern crate grin_store; extern crate grin_util as util; -#[macro_use] -extern crate slog; -extern crate futures; -extern crate tokio_core; -extern crate tokio_io; -extern crate bytes; -extern crate tokio_timer; +extern crate num; extern crate rand; extern crate serde; #[macro_use] extern crate serde_derive; +#[macro_use] +extern crate slog; extern crate time; -extern crate num; +extern crate tokio_core; +extern crate tokio_io; +extern crate tokio_timer; mod conn; pub mod handshake; @@ -52,8 +52,8 @@ mod server; mod store; mod types; -pub use server::{Server, DummyAdapter}; +pub use server::{DummyAdapter, Server}; pub use peer::Peer; -pub use types::{P2PConfig, NetAdapter, MAX_LOCATORS, MAX_BLOCK_HEADERS, MAX_PEER_ADDRS, - Capabilities, UNKNOWN, FULL_NODE, FULL_HIST, PeerInfo, Error}; -pub use store::{PeerStore, PeerData, State}; +pub use types::{Capabilities, Error, NetAdapter, P2PConfig, PeerInfo, FULL_HIST, FULL_NODE, + MAX_BLOCK_HEADERS, MAX_LOCATORS, MAX_PEER_ADDRS, UNKNOWN}; +pub use store::{PeerData, PeerStore, State}; diff --git a/p2p/src/msg.rs b/p2p/src/msg.rs index 2641650e0..4a39a5d2c 100644 --- a/p2p/src/msg.rs +++ b/p2p/src/msg.rs @@ -14,10 +14,10 @@ //! Message types that transit over the network and related serialization code. -use std::net::{SocketAddr, SocketAddrV4, SocketAddrV6, Ipv4Addr, Ipv6Addr}; +use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; use num::FromPrimitive; -use futures::future::{Future, ok}; +use futures::future::{ok, Future}; use tokio_core::net::TcpStream; use tokio_io::io::{read_exact, write_all}; @@ -25,7 +25,7 @@ use core::consensus::MAX_MSG_LEN; use core::core::BlockHeader; use core::core::hash::Hash; use core::core::target::Difficulty; -use core::ser::{self, Writeable, Readable, Writer, Reader}; +use core::ser::{self, Readable, Reader, Writeable, Writer}; use types::*; @@ -51,18 +51,18 @@ pub enum ErrCodes { enum_from_primitive! { #[derive(Debug, Clone, Copy, PartialEq)] pub enum Type { - Error, - Hand, - Shake, - Ping, - Pong, - GetPeerAddrs, - PeerAddrs, - GetHeaders, - Headers, - GetBlock, - Block, - Transaction, + Error, + Hand, + Shake, + Ping, + Pong, + GetPeerAddrs, + PeerAddrs, + GetHeaders, + Headers, + GetBlock, + Block, + Transaction, } } @@ -79,7 +79,7 @@ where let header = try!(ser::deserialize::(&mut &buf[..])); if header.msg_len > MAX_MSG_LEN { // TODO add additional restrictions on a per-message-type basis to avoid 20MB - // pings + // pings return Err(Error::Serialization(ser::Error::TooLargeReadErr)); } Ok((reader, header)) @@ -170,13 +170,11 @@ impl Readable for MsgHeader { try!(reader.expect_u8(MAGIC[1])); let (t, len) = ser_multiread!(reader, read_u8, read_u64); match Type::from_u8(t) { - Some(ty) => { - Ok(MsgHeader { - magic: MAGIC, - msg_type: ty, - msg_len: len, - }) - } + Some(ty) => Ok(MsgHeader { + magic: MAGIC, + msg_type: ty, + msg_len: len, + }), None => Err(ser::Error::CorruptedData), } } @@ -226,9 +224,7 @@ impl Readable for Hand { let receiver_addr = try!(SockAddr::read(reader)); let ua = try!(reader.read_vec()); let user_agent = try!(String::from_utf8(ua).map_err(|_| ser::Error::CorruptedData)); - let capabilities = try!(Capabilities::from_bits(capab).ok_or( - ser::Error::CorruptedData, - )); + let capabilities = try!(Capabilities::from_bits(capab).ok_or(ser::Error::CorruptedData,)); Ok(Hand { version: version, capabilities: capabilities, @@ -275,9 +271,7 @@ impl Readable for Shake { let total_diff = try!(Difficulty::read(reader)); let ua = try!(reader.read_vec()); let user_agent = try!(String::from_utf8(ua).map_err(|_| ser::Error::CorruptedData)); - let capabilities = try!(Capabilities::from_bits(capab).ok_or( - ser::Error::CorruptedData, - )); + let capabilities = try!(Capabilities::from_bits(capab).ok_or(ser::Error::CorruptedData,)); Ok(Shake { version: version, capabilities: capabilities, @@ -302,10 +296,10 @@ impl Writeable for GetPeerAddrs { impl Readable for GetPeerAddrs { fn read(reader: &mut Reader) -> Result { let capab = try!(reader.read_u32()); - let capabilities = try!(Capabilities::from_bits(capab).ok_or( - ser::Error::CorruptedData, - )); - Ok(GetPeerAddrs { capabilities: capabilities }) + let capabilities = try!(Capabilities::from_bits(capab).ok_or(ser::Error::CorruptedData,)); + Ok(GetPeerAddrs { + capabilities: capabilities, + }) } } @@ -361,9 +355,7 @@ impl Writeable for PeerError { impl Readable for PeerError { fn read(reader: &mut Reader) -> Result { let (code, msg) = ser_multiread!(reader, read_u32, read_vec); - let message = try!(String::from_utf8(msg).map_err( - |_| ser::Error::CorruptedData, - )); + let message = try!(String::from_utf8(msg).map_err(|_| ser::Error::CorruptedData,)); Ok(PeerError { code: code, message: message, @@ -413,16 +405,7 @@ impl Readable for SockAddr { let ip = try_map_vec!([0..8], |_| reader.read_u16()); let port = try!(reader.read_u16()); Ok(SockAddr(SocketAddr::V6(SocketAddrV6::new( - Ipv6Addr::new( - ip[0], - ip[1], - ip[2], - ip[3], - ip[4], - ip[5], - ip[6], - ip[7], - ), + Ipv6Addr::new(ip[0], ip[1], ip[2], ip[3], ip[4], ip[5], ip[6], ip[7]), port, 0, 0, diff --git a/p2p/src/peer.rs b/p2p/src/peer.rs index 813adba78..9b4815d37 100644 --- a/p2p/src/peer.rs +++ b/p2p/src/peer.rs @@ -13,7 +13,7 @@ // limitations under the License. use std::net::SocketAddr; -use std::sync::{RwLock, Arc}; +use std::sync::{Arc, RwLock}; use futures::Future; use tokio_core::net::TcpStream; @@ -80,20 +80,16 @@ impl Peer { hs: &Handshake, na: Arc, ) -> Box> { - let hs_peer = hs.handshake(capab, total_difficulty, conn).and_then( - |(conn, - proto, - info)| { + let hs_peer = hs.handshake(capab, total_difficulty, conn) + .and_then(|(conn, proto, info)| { Ok((conn, Peer::new(info, Box::new(proto), na))) - }, - ); + }); Box::new(hs_peer) } /// Main peer loop listening for messages and forwarding to the rest of the /// system. pub fn run(&self, conn: TcpStream) -> Box> { - let addr = self.info.addr; let state = self.state.clone(); let adapter = Arc::new(self.tracking_adapter.clone()); @@ -204,7 +200,7 @@ impl TrackingAdapter { fn has(&self, hash: Hash) -> bool { let known = self.known.read().unwrap(); // may become too slow, an ordered set (by timestamp for eviction) may - // end up being a better choice + // end up being a better choice known.contains(&hash) } diff --git a/p2p/src/protocol.rs b/p2p/src/protocol.rs index 39777bec8..da56a7a27 100644 --- a/p2p/src/protocol.rs +++ b/p2p/src/protocol.rs @@ -34,7 +34,9 @@ pub struct ProtocolV1 { impl ProtocolV1 { pub fn new() -> ProtocolV1 { - ProtocolV1 { conn: OneTime::new() } + ProtocolV1 { + conn: OneTime::new(), + } } } @@ -45,7 +47,6 @@ impl Protocol for ProtocolV1 { conn: TcpStream, adapter: Arc, ) -> Box> { - let (conn, listener) = TimeoutConnection::listen(conn, move |sender, header, data| { let adapt = adapter.as_ref(); handle_payload(adapt, sender, header, data) @@ -94,7 +95,9 @@ impl Protocol for ProtocolV1 { self.send_request( Type::GetPeerAddrs, Type::PeerAddrs, - &GetPeerAddrs { capabilities: capab }, + &GetPeerAddrs { + capabilities: capab, + }, None, ) } diff --git a/p2p/src/server.rs b/p2p/src/server.rs index 0aab932ab..1667a50d1 100644 --- a/p2p/src/server.rs +++ b/p2p/src/server.rs @@ -174,7 +174,7 @@ impl Server { let total_diff = adapter.clone().total_difficulty(); // connect to the peer and add it to the server map, wiring it a timeout for - // the handhake + // the handhake let connect = Peer::connect( socket, capab, @@ -330,12 +330,11 @@ fn with_timeout( h: &reactor::Handle, ) -> Box> { let timeout = reactor::Timeout::new(Duration::new(5, 0), h).unwrap(); - let timed = fut.select(timeout.map(Err).from_err()).then( - |res| match res { + let timed = fut.select(timeout.map(Err).from_err()) + .then(|res| match res { Ok((Ok(inner), _timeout)) => Ok(inner), Ok((_, _accept)) => Err(Error::Timeout), Err((e, _other)) => Err(e), - }, - ); + }); Box::new(timed) } diff --git a/p2p/src/store.rs b/p2p/src/store.rs index 754aa0497..bc7f64722 100644 --- a/p2p/src/store.rs +++ b/p2p/src/store.rs @@ -17,8 +17,8 @@ use std::net::SocketAddr; use num::FromPrimitive; -use core::ser::{self, Readable, Writeable, Reader, Writer}; -use grin_store::{self, Error, to_key, option_to_not_found}; +use core::ser::{self, Readable, Reader, Writeable, Writer}; +use grin_store::{self, option_to_not_found, to_key, Error}; use msg::SockAddr; use types::Capabilities; @@ -30,9 +30,9 @@ const PEER_PREFIX: u8 = 'p' as u8; enum_from_primitive! { #[derive(Debug, Clone, Copy, PartialEq)] pub enum State { - Healthy, - Banned, - Defunct, + Healthy, + Banned, + Defunct, } } @@ -68,18 +68,14 @@ impl Readable for PeerData { let addr = SockAddr::read(reader)?; let (capab, ua, fl) = ser_multiread!(reader, read_u32, read_vec, read_u8); let user_agent = String::from_utf8(ua).map_err(|_| ser::Error::CorruptedData)?; - let capabilities = Capabilities::from_bits(capab).ok_or( - ser::Error::CorruptedData, - )?; + let capabilities = Capabilities::from_bits(capab).ok_or(ser::Error::CorruptedData)?; match State::from_u8(fl) { - Some(flags) => { - Ok(PeerData { - addr: addr.0, - capabilities: capabilities, - user_agent: user_agent, - flags: flags, - }) - } + Some(flags) => Ok(PeerData { + addr: addr.0, + capabilities: capabilities, + user_agent: user_agent, + flags: flags, + }), None => Err(ser::Error::CorruptedData), } } @@ -109,22 +105,18 @@ impl PeerStore { } pub fn exists_peer(&self, peer_addr: SocketAddr) -> Result { - self.db.exists( - &to_key(PEER_PREFIX, &mut format!("{}", peer_addr).into_bytes())[..], - ) + self.db + .exists(&to_key(PEER_PREFIX, &mut format!("{}", peer_addr).into_bytes())[..]) } pub fn delete_peer(&self, peer_addr: SocketAddr) -> Result<(), Error> { - self.db.delete( - &to_key(PEER_PREFIX, &mut format!("{}", peer_addr).into_bytes())[..], - ) + self.db + .delete(&to_key(PEER_PREFIX, &mut format!("{}", peer_addr).into_bytes())[..]) } pub fn find_peers(&self, state: State, cap: Capabilities, count: usize) -> Vec { - let peers_iter = self.db.iter::(&to_key( - PEER_PREFIX, - &mut "".to_string().into_bytes(), - )); + let peers_iter = self.db + .iter::(&to_key(PEER_PREFIX, &mut "".to_string().into_bytes())); let mut peers = Vec::with_capacity(count); for p in peers_iter { if p.flags == state && p.capabilities.contains(cap) { diff --git a/p2p/src/types.rs b/p2p/src/types.rs index 4c1a07c6c..7c7942088 100644 --- a/p2p/src/types.rs +++ b/p2p/src/types.rs @@ -14,7 +14,7 @@ use std::convert::From; use std::io; -use std::net::{SocketAddr, IpAddr}; +use std::net::{IpAddr, SocketAddr}; use std::sync::Arc; use futures::Future; @@ -85,17 +85,17 @@ bitflags! { /// Options for what type of interaction a peer supports #[derive(Serialize, Deserialize)] pub flags Capabilities: u32 { - /// We don't know (yet) what the peer can do. - const UNKNOWN = 0b00000000, - /// Full archival node, has the whole history without any pruning. - const FULL_HIST = 0b00000001, - /// Can provide block headers and the UTXO set for some recent-enough - /// height. - const UTXO_HIST = 0b00000010, - /// Can provide a list of healthy peers - const PEER_LIST = 0b00000100, + /// We don't know (yet) what the peer can do. + const UNKNOWN = 0b00000000, + /// Full archival node, has the whole history without any pruning. + const FULL_HIST = 0b00000001, + /// Can provide block headers and the UTXO set for some recent-enough + /// height. + const UTXO_HIST = 0b00000010, + /// Can provide a list of healthy peers + const PEER_LIST = 0b00000100, - const FULL_NODE = FULL_HIST.bits | UTXO_HIST.bits | PEER_LIST.bits, + const FULL_NODE = FULL_HIST.bits | UTXO_HIST.bits | PEER_LIST.bits, } } diff --git a/p2p/tests/peer_handshake.rs b/p2p/tests/peer_handshake.rs index f9b715a2d..3c59dc0df 100644 --- a/p2p/tests/peer_handshake.rs +++ b/p2p/tests/peer_handshake.rs @@ -12,9 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. +extern crate futures; extern crate grin_core as core; extern crate grin_p2p as p2p; -extern crate futures; extern crate tokio_core; use std::net::SocketAddr; @@ -32,7 +32,6 @@ use p2p::Peer; // followed by a ping/pong exchange to make sure the connection is live. #[test] fn peer_handshake() { - let mut evtlp = Core::new().unwrap(); let handle = evtlp.handle(); let p2p_conf = p2p::P2PConfig::default(); @@ -89,5 +88,4 @@ fn peer_handshake() { ); evtlp.run(run_server).unwrap(); - } diff --git a/pool/src/blockchain.rs b/pool/src/blockchain.rs index 500f1ead7..b56a8a0db 100644 --- a/pool/src/blockchain.rs +++ b/pool/src/blockchain.rs @@ -49,7 +49,9 @@ pub struct DummyUtxoSet { #[allow(dead_code)] impl DummyUtxoSet { pub fn empty() -> DummyUtxoSet { - DummyUtxoSet { outputs: HashMap::new() } + DummyUtxoSet { + outputs: HashMap::new(), + } } pub fn root(&self) -> hash::Hash { hash::ZERO_HASH @@ -62,7 +64,9 @@ impl DummyUtxoSet { for output in &b.outputs { new_hashmap.insert(output.commitment(), output.clone()); } - DummyUtxoSet { outputs: new_hashmap } + DummyUtxoSet { + outputs: new_hashmap, + } } pub fn with_block(&mut self, b: &block::Block) { for input in &b.inputs { @@ -73,14 +77,18 @@ impl DummyUtxoSet { } } pub fn rewind(&self, _: &block::Block) -> DummyUtxoSet { - DummyUtxoSet { outputs: HashMap::new() } + DummyUtxoSet { + outputs: HashMap::new(), + } } pub fn get_output(&self, output_ref: &Commitment) -> Option<&transaction::Output> { self.outputs.get(output_ref) } fn clone(&self) -> DummyUtxoSet { - DummyUtxoSet { outputs: self.outputs.clone() } + DummyUtxoSet { + outputs: self.outputs.clone(), + } } // only for testing: add an output to the map @@ -108,8 +116,12 @@ pub struct DummyChainImpl { impl DummyChainImpl { pub fn new() -> DummyChainImpl { DummyChainImpl { - utxo: RwLock::new(DummyUtxoSet { outputs: HashMap::new() }), - block_headers: RwLock::new(DummyBlockHeaderIndex { block_headers: HashMap::new() }), + utxo: RwLock::new(DummyUtxoSet { + outputs: HashMap::new(), + }), + block_headers: RwLock::new(DummyBlockHeaderIndex { + block_headers: HashMap::new(), + }), head_header: RwLock::new(vec![]), } } @@ -131,7 +143,8 @@ impl BlockChain for DummyChainImpl { match self.block_headers .read() .unwrap() - .get_block_header_by_output_commit(*commit) { + .get_block_header_by_output_commit(*commit) + { Ok(h) => Ok(h.clone()), Err(e) => Err(e), } @@ -159,10 +172,10 @@ impl DummyChain for DummyChainImpl { commitment: Commitment, block_header: &block::BlockHeader, ) { - self.block_headers.write().unwrap().insert( - commitment, - block_header.clone(), - ); + self.block_headers + .write() + .unwrap() + .insert(commitment, block_header.clone()); } fn store_head_header(&self, block_header: &block::BlockHeader) { let mut h = self.head_header.write().unwrap(); diff --git a/pool/src/graph.rs b/pool/src/graph.rs index 420da1b10..913c2964b 100644 --- a/pool/src/graph.rs +++ b/pool/src/graph.rs @@ -165,35 +165,36 @@ impl DirectedGraph { /// Remove a vertex by its hash pub fn remove_vertex(&mut self, tx_hash: core::hash::Hash) -> Option { - match self.roots.iter().position( - |x| x.transaction_hash == tx_hash, - ) { + match self.roots + .iter() + .position(|x| x.transaction_hash == tx_hash) + { Some(i) => Some(self.roots.swap_remove(i)), - None => { - match self.vertices.iter().position( - |x| x.transaction_hash == tx_hash, - ) { - Some(i) => Some(self.vertices.swap_remove(i)), - None => None, - } - } + None => match self.vertices + .iter() + .position(|x| x.transaction_hash == tx_hash) + { + Some(i) => Some(self.vertices.swap_remove(i)), + None => None, + }, } } /// Promote any non-root vertices to roots based on current edges. - /// For a given tx, if there are no edges with that tx as destination then it is a root. + /// For a given tx, if there are no edges with that tx as destination then + /// it is a root. pub fn update_roots(&mut self) { let mut new_vertices: Vec = vec![]; // first find the set of all destinations from the edges in the graph - // a root is a vertex that is not a destination of any edge + // a root is a vertex that is not a destination of any edge let destinations = self.edges .values() .filter_map(|edge| edge.destination) .collect::>(); // now iterate over the current non-root vertices - // and check if it is now a root based on the set of edge destinations + // and check if it is now a root based on the set of edge destinations for x in &self.vertices { if destinations.contains(&x.transaction_hash) { new_vertices.push(x.clone()); @@ -272,7 +273,7 @@ impl DirectedGraph { .map(|x| x.transaction_hash) .collect::>(); hashes.extend(&non_root_hashes); - return hashes + return hashes; } } @@ -313,7 +314,9 @@ mod tests { features: core::transaction::DEFAULT_OUTPUT, commit: output_commit, switch_commit_hash: switch_commit_hash, - proof: keychain.range_proof(100, &key_id1, output_commit, msg).unwrap(), + proof: keychain + .range_proof(100, &key_id1, output_commit, msg) + .unwrap(), }, ]; let test_transaction = core::transaction::Transaction::new(inputs, outputs, 5, 0); diff --git a/pool/src/lib.rs b/pool/src/lib.rs index e9071a7cf..2b2c51d1c 100644 --- a/pool/src/lib.rs +++ b/pool/src/lib.rs @@ -26,15 +26,15 @@ mod types; mod blockchain; mod pool; -extern crate time; -extern crate rand; -extern crate serde; -#[macro_use] -extern crate serde_derive; extern crate blake2_rfc as blake2; extern crate grin_core as core; extern crate grin_keychain as keychain; extern crate grin_util as util; +extern crate rand; +extern crate serde; +#[macro_use] +extern crate serde_derive; +extern crate time; pub use pool::TransactionPool; -pub use types::{BlockChain, PoolAdapter, TxSource, PoolError, PoolConfig}; +pub use types::{BlockChain, PoolAdapter, PoolConfig, PoolError, TxSource}; diff --git a/pool/src/pool.rs b/pool/src/pool.rs index 4579c815c..9d8086b8e 100644 --- a/pool/src/pool.rs +++ b/pool/src/pool.rs @@ -71,12 +71,14 @@ where /// be accounted for separately, if relevant. pub fn search_for_best_output(&self, output_commitment: &Commitment) -> Parent { // The current best unspent set is: - // Pool unspent + (blockchain unspent - pool->blockchain spent) - // Pool unspents are unconditional so we check those first + // Pool unspent + (blockchain unspent - pool->blockchain spent) + // Pool unspents are unconditional so we check those first self.pool .get_available_output(output_commitment) .map(|x| { - Parent::PoolTransaction { tx_ref: x.source_hash().unwrap() } + Parent::PoolTransaction { + tx_ref: x.source_hash().unwrap(), + } }) .or(self.search_blockchain_unspents(output_commitment)) .or(self.search_pool_spents(output_commitment)) @@ -84,25 +86,31 @@ where } // search_blockchain_unspents searches the current view of the blockchain - // unspent set, represented by blockchain unspents - pool spents, for an - // output designated by output_commitment. + // unspent set, represented by blockchain unspents - pool spents, for an + // output designated by output_commitment. fn search_blockchain_unspents(&self, output_commitment: &Commitment) -> Option { - self.blockchain.get_unspent(output_commitment).ok().map( - |output| match self.pool.get_blockchain_spent(output_commitment) { - Some(x) => Parent::AlreadySpent { other_tx: x.destination_hash().unwrap() }, - None => Parent::BlockTransaction { output }, - }, - ) + self.blockchain + .get_unspent(output_commitment) + .ok() + .map(|output| { + match self.pool.get_blockchain_spent(output_commitment) { + Some(x) => Parent::AlreadySpent { + other_tx: x.destination_hash().unwrap(), + }, + None => Parent::BlockTransaction { output }, + } + }) } // search_pool_spents is the second half of pool input detection, after the - // available_outputs have been checked. This returns either a - // Parent::AlreadySpent or None. + // available_outputs have been checked. This returns either a + // Parent::AlreadySpent or None. fn search_pool_spents(&self, output_commitment: &Commitment) -> Option { self.pool.get_internal_spent(output_commitment).map(|x| { - Parent::AlreadySpent { other_tx: x.destination_hash().unwrap() } + Parent::AlreadySpent { + other_tx: x.destination_hash().unwrap(), + } }) - } /// Get the number of transactions in the pool @@ -131,7 +139,6 @@ where _: TxSource, tx: transaction::Transaction, ) -> Result<(), PoolError> { - // Do we have the capacity to accept this transaction? if let Err(e) = self.is_acceptable(&tx) { return Err(e); @@ -142,14 +149,14 @@ where tx.validate(&secp).map_err(|_e| PoolError::Invalid)?; // The first check involves ensuring that an identical transaction is - // not already in the pool's transaction set. - // A non-authoritative similar check should be performed under the - // pool's read lock before we get to this point, which would catch the - // majority of duplicate cases. The race condition is caught here. - // TODO: When the transaction identifier is finalized, the assumptions - // here may change depending on the exact coverage of the identifier. - // The current tx.hash() method, for example, does not cover changes - // to fees or other elements of the signature preimage. + // not already in the pool's transaction set. + // A non-authoritative similar check should be performed under the + // pool's read lock before we get to this point, which would catch the + // majority of duplicate cases. The race condition is caught here. + // TODO: When the transaction identifier is finalized, the assumptions + // here may change depending on the exact coverage of the identifier. + // The current tx.hash() method, for example, does not cover changes + // to fees or other elements of the signature preimage. let tx_hash = graph::transaction_identifier(&tx); if self.transactions.contains_key(&tx_hash) { return Err(PoolError::AlreadyInPool); @@ -163,7 +170,7 @@ where } // The next issue is to identify all unspent outputs that - // this transaction will consume and make sure they exist in the set. + // this transaction will consume and make sure they exist in the set. let mut pool_refs: Vec = Vec::new(); let mut orphan_refs: Vec = Vec::new(); let mut blockchain_refs: Vec = Vec::new(); @@ -172,9 +179,9 @@ where let base = graph::Edge::new(None, Some(tx_hash), input.commitment()); // Note that search_for_best_output does not examine orphans, by - // design. If an incoming transaction consumes pool outputs already - // spent by the orphans set, this does not preclude its inclusion - // into the pool. + // design. If an incoming transaction consumes pool outputs already + // spent by the orphans set, this does not preclude its inclusion + // into the pool. match self.search_for_best_output(&input.commitment()) { Parent::PoolTransaction { tx_ref: x } => pool_refs.push(base.with_source(Some(x))), Parent::BlockTransaction { output } => { @@ -207,24 +214,24 @@ where let is_orphan = orphan_refs.len() > 0; // Next we examine the outputs this transaction creates and ensure - // that they do not already exist. - // I believe its worth preventing duplicate outputs from being - // accepted, even though it is possible for them to be mined - // with strict ordering. In the future, if desirable, this could - // be node policy config or more intelligent. + // that they do not already exist. + // I believe its worth preventing duplicate outputs from being + // accepted, even though it is possible for them to be mined + // with strict ordering. In the future, if desirable, this could + // be node policy config or more intelligent. for output in &tx.outputs { self.check_duplicate_outputs(output, is_orphan)? } // Assertion: we have exactly as many resolved spending references as - // inputs to the transaction. + // inputs to the transaction. assert_eq!( tx.inputs.len(), blockchain_refs.len() + pool_refs.len() + orphan_refs.len() ); // At this point we know if we're spending all known unspents and not - // creating any duplicate unspents. + // creating any duplicate unspents. let pool_entry = graph::PoolEntry::new(&tx); let new_unspents = tx.outputs .iter() @@ -233,33 +240,28 @@ where if !is_orphan { // In the non-orphan (pool) case, we've ensured that every input - // maps one-to-one with an unspent (available) output, and each - // output is unique. No further checks are necessary. - self.pool.add_pool_transaction( - pool_entry, - blockchain_refs, - pool_refs, - new_unspents, - ); + // maps one-to-one with an unspent (available) output, and each + // output is unique. No further checks are necessary. + self.pool + .add_pool_transaction(pool_entry, blockchain_refs, pool_refs, new_unspents); self.reconcile_orphans().unwrap(); self.adapter.tx_accepted(&tx); self.transactions.insert(tx_hash, Box::new(tx)); Ok(()) - } else { // At this point, we're pretty sure the transaction is an orphan, - // but we have to explicitly check for double spends against the - // orphans set; we do not check this as part of the connectivity - // checking above. - // First, any references resolved to the pool need to be compared - // against active orphan pool_connections. - // Note that pool_connections here also does double duty to - // account for blockchain connections. + // but we have to explicitly check for double spends against the + // orphans set; we do not check this as part of the connectivity + // checking above. + // First, any references resolved to the pool need to be compared + // against active orphan pool_connections. + // Note that pool_connections here also does double duty to + // account for blockchain connections. for pool_ref in pool_refs.iter().chain(blockchain_refs.iter()) { - match self.orphans.get_external_spent_output( - &pool_ref.output_commitment(), - ) { + match self.orphans + .get_external_spent_output(&pool_ref.output_commitment()) + { // Should the below err be subtyped to orphans somehow? Some(x) => { return Err(PoolError::DoubleSpend { @@ -272,9 +274,9 @@ where } // Next, we have to consider the possibility of double spends - // within the orphans set. - // We also have to distinguish now between missing and internal - // references. + // within the orphans set. + // We also have to distinguish now between missing and internal + // references. let missing_refs = self.resolve_orphan_refs(tx_hash, &mut orphan_refs)?; // We have passed all failure modes. @@ -289,7 +291,6 @@ where Err(PoolError::OrphanTransaction) } - } /// Check the output for a conflict with an existing output. @@ -303,8 +304,8 @@ where is_orphan: bool, ) -> Result<(), PoolError> { // Checking against current blockchain unspent outputs - // We want outputs even if they're spent by pool txs, so we ignore - // consumed_blockchain_outputs + // We want outputs even if they're spent by pool txs, so we ignore + // consumed_blockchain_outputs if self.blockchain.get_unspent(&output.commitment()).is_ok() { return Err(PoolError::DuplicateOutput { other_tx: None, @@ -328,7 +329,7 @@ where // If the transaction might go into orphans, perform the same - // checks as above but against the orphan set instead. + // checks as above but against the orphan set instead. if is_orphan { // Checking against orphan outputs match self.orphans.find_output(&output.commitment()) { @@ -342,7 +343,7 @@ where None => {} }; // No need to check pool connections since those are covered - // by pool unspents and blockchain connections. + // by pool unspents and blockchain connections. } Ok(()) } @@ -380,9 +381,9 @@ where } None => { // The reference does not resolve to anything. - // Make sure this missing_output has not already - // been claimed, then add this entry to - // missing_refs + // Make sure this missing_output has not already + // been claimed, then add this entry to + // missing_refs match self.orphans.get_unknown_output(&orphan_commitment) { Some(x) => { return Err(PoolError::DoubleSpend { @@ -430,34 +431,34 @@ where block: &block::Block, ) -> Result>, PoolError> { // If this pool has been kept in sync correctly, serializing all - // updates, then the inputs must consume only members of the blockchain - // utxo set. - // If the block has been resolved properly and reduced fully to its - // canonical form, no inputs may consume outputs generated by previous - // transactions in the block; they would be cut-through. TODO: If this - // is not consensus enforced, then logic must be added here to account - // for that. - // Based on this, we operate under the following algorithm: - // For each block input, we examine the pool transaction, if any, that - // consumes the same blockchain output. - // If one exists, we mark the transaction and then examine its - // children. Recursively, we mark each child until a child is - // fully satisfied by outputs in the updated utxo view (after - // reconciliation of the block), or there are no more children. - // - // Additionally, to protect our invariant dictating no duplicate - // outputs, each output generated by the new utxo set is checked - // against outputs generated by the pool and the corresponding - // transactions are also marked. - // - // After marking concludes, sweeping begins. In order, the marked - // transactions are removed, the vertexes corresponding to the - // transactions are removed, all the marked transactions' outputs are - // removed, and all remaining non-blockchain inputs are returned to the - // unspent_outputs set. - // - // After the pool has been successfully processed, an orphans - // reconciliation job is triggered. + // updates, then the inputs must consume only members of the blockchain + // utxo set. + // If the block has been resolved properly and reduced fully to its + // canonical form, no inputs may consume outputs generated by previous + // transactions in the block; they would be cut-through. TODO: If this + // is not consensus enforced, then logic must be added here to account + // for that. + // Based on this, we operate under the following algorithm: + // For each block input, we examine the pool transaction, if any, that + // consumes the same blockchain output. + // If one exists, we mark the transaction and then examine its + // children. Recursively, we mark each child until a child is + // fully satisfied by outputs in the updated utxo view (after + // reconciliation of the block), or there are no more children. + // + // Additionally, to protect our invariant dictating no duplicate + // outputs, each output generated by the new utxo set is checked + // against outputs generated by the pool and the corresponding + // transactions are also marked. + // + // After marking concludes, sweeping begins. In order, the marked + // transactions are removed, the vertexes corresponding to the + // transactions are removed, all the marked transactions' outputs are + // removed, and all remaining non-blockchain inputs are returned to the + // unspent_outputs set. + // + // After the pool has been successfully processed, an orphans + // reconciliation job is triggered. let mut marked_transactions: HashSet = HashSet::new(); { @@ -469,20 +470,21 @@ where .filter_map(|x| x.destination_hash()) .collect(); - // find all outputs that conflict - potential for duplicates so use a HashSet here + // find all outputs that conflict - potential for duplicates so use a HashSet + // here let conflicting_outputs: HashSet = block .outputs .iter() .filter_map(|x: &transaction::Output| { - self.pool.get_internal_spent_output(&x.commitment()).or( - self.pool.get_available_output(&x.commitment()), - ) + self.pool + .get_internal_spent_output(&x.commitment()) + .or(self.pool.get_available_output(&x.commitment())) }) .filter_map(|x| x.source_hash()) .collect(); // now iterate over all conflicting hashes from both txs and outputs - // we can just use the union of the two sets here to remove duplicates + // we can just use the union of the two sets here to remove duplicates for &txh in conflicting_txs.union(&conflicting_outputs) { self.mark_transaction(txh, &mut marked_transactions); } @@ -504,11 +506,7 @@ where /// /// Marked transactions are added to the mutable marked_txs HashMap which /// is supplied by the calling function. - fn mark_transaction( - &self, - conflicting_tx: hash::Hash, - marked_txs: &mut HashSet, - ) { + fn mark_transaction(&self, conflicting_tx: hash::Hash, marked_txs: &mut HashSet) { // we can stop recursively visiting txs if we have already seen this one if marked_txs.contains(&conflicting_tx) { return; @@ -520,11 +518,9 @@ where for output in &tx_ref.unwrap().outputs { match self.pool.get_internal_spent_output(&output.commitment()) { - Some(x) => { - if self.blockchain.get_unspent(&x.output_commitment()).is_err() { - self.mark_transaction(x.destination_hash().unwrap(), marked_txs); - } - } + Some(x) => if self.blockchain.get_unspent(&x.output_commitment()).is_err() { + self.mark_transaction(x.destination_hash().unwrap(), marked_txs); + }, None => {} }; } @@ -544,22 +540,19 @@ where &mut self, marked_transactions: HashSet, ) -> Vec> { - let mut removed_txs = Vec::new(); for tx_hash in &marked_transactions { let removed_tx = self.transactions.remove(&tx_hash).unwrap(); - self.pool.remove_pool_transaction( - &removed_tx, - &marked_transactions, - ); + self.pool + .remove_pool_transaction(&removed_tx, &marked_transactions); removed_txs.push(removed_tx); } // final step is to update the pool to reflect the new set of roots - // a tx that was non-root may now be root based on the txs removed + // a tx that was non-root may now be root based on the txs removed self.pool.update_roots(); removed_txs @@ -592,9 +585,9 @@ where } // for a basic transaction (1 input, 2 outputs) - - // (-1 * 1) + (4 * 2) + 1 = 8 - // 8 * 10 = 80 - // + // (-1 * 1) + (4 * 2) + 1 = 8 + // 8 * 10 = 80 + // if self.config.accept_fee_base > 0 { let mut tx_weight = -1 * (tx.inputs.len() as i32) + (4 * tx.outputs.len() as i32) + 1; if tx_weight < 1 { @@ -660,7 +653,7 @@ mod tests { dummy_chain.update_utxo_set(new_utxo); // To mirror how this construction is intended to be used, the pool - // is placed inside a RwLock. + // is placed inside a RwLock. let pool = RwLock::new(test_setup(&Arc::new(dummy_chain))); // Take the write lock and add a pool entry @@ -683,11 +676,10 @@ mod tests { child_result.err().unwrap() ); } - } // Now take the read lock and use a few exposed methods to check - // consistency + // consistency { let read_pool = pool.read().unwrap(); assert_eq!(read_pool.total_size(), 2); @@ -721,7 +713,7 @@ mod tests { assert_eq!(write_pool.total_size(), 0); // First expected failure: duplicate output - let duplicate_tx = test_transaction(vec![5,6], vec![7]); + let duplicate_tx = test_transaction(vec![5, 6], vec![7]); match write_pool.add_to_memory_pool(test_source(), duplicate_tx) { Ok(_) => panic!("Got OK from add_to_memory_pool when dup was expected"), @@ -731,23 +723,22 @@ mod tests { other_tx, in_chain, output, - } => { - if other_tx.is_some() || !in_chain || - output != test_output(7).commitment() - { - panic!("Unexpected parameter in DuplicateOutput: {:?}", x); - } - } - _ => { - panic!("Unexpected error when adding duplicate output transaction: {:?}", x) - } + } => if other_tx.is_some() || !in_chain + || output != test_output(7).commitment() + { + panic!("Unexpected parameter in DuplicateOutput: {:?}", x); + }, + _ => panic!( + "Unexpected error when adding duplicate output transaction: {:?}", + x + ), }; } }; // To test DoubleSpend and AlreadyInPool conditions, we need to add - // a valid transaction. - let valid_transaction = test_transaction(vec![5,6], vec![9]); + // a valid transaction. + let valid_transaction = test_transaction(vec![5, 6], vec![9]); match write_pool.add_to_memory_pool(test_source(), valid_transaction) { Ok(_) => {} @@ -755,7 +746,7 @@ mod tests { }; // Now, test a DoubleSpend by consuming the same blockchain unspent - // as valid_transaction: + // as valid_transaction: let double_spend_transaction = test_transaction(vec![6], vec![2]); match write_pool.add_to_memory_pool(test_source(), double_spend_transaction) { @@ -765,19 +756,18 @@ mod tests { PoolError::DoubleSpend { other_tx: _, spent_output, - } => { - if spent_output != test_output(6).commitment() { - panic!("Unexpected parameter in DoubleSpend: {:?}", x); - } - } - _ => { - panic!("Unexpected error when adding double spend transaction: {:?}", x) - } + } => if spent_output != test_output(6).commitment() { + panic!("Unexpected parameter in DoubleSpend: {:?}", x); + }, + _ => panic!( + "Unexpected error when adding double spend transaction: {:?}", + x + ), }; } }; - let already_in_pool = test_transaction(vec![5,6], vec![9]); + let already_in_pool = test_transaction(vec![5, 6], vec![9]); match write_pool.add_to_memory_pool(test_source(), already_in_pool) { Ok(_) => panic!("Expected error when adding already in pool, got Ok"), @@ -792,10 +782,12 @@ mod tests { assert_eq!(write_pool.total_size(), 1); // now attempt to add a timelocked tx to the pool - // should fail as invalid based on current height + // should fail as invalid based on current height let timelocked_tx_1 = timelocked_transaction(vec![9], vec![5], 10); match write_pool.add_to_memory_pool(test_source(), timelocked_tx_1) { - Err(PoolError::ImmatureTransaction { lock_height: height }) => { + Err(PoolError::ImmatureTransaction { + lock_height: height, + }) => { assert_eq!(height, 10); } Err(e) => panic!("expected ImmatureTransaction error here - {:?}", e), @@ -821,10 +813,8 @@ mod tests { height: 1, ..block::BlockHeader::default() }; - chain_ref.store_header_by_output_commitment( - coinbase_output.commitment(), - &coinbase_header, - ); + chain_ref + .store_header_by_output_commitment(coinbase_output.commitment(), &coinbase_header); let head_header = block::BlockHeader { height: 2, @@ -836,9 +826,9 @@ mod tests { let result = write_pool.add_to_memory_pool(test_source(), txn); match result { Err(PoolError::ImmatureCoinbase { - header: _, - output: out, - }) => { + header: _, + output: out, + }) => { assert_eq!(out, coinbase_output.commitment()); } _ => panic!("expected ImmatureCoinbase error here"), @@ -854,9 +844,9 @@ mod tests { let result = write_pool.add_to_memory_pool(test_source(), txn); match result { Err(PoolError::ImmatureCoinbase { - header: _, - output: out, - }) => { + header: _, + output: out, + }) => { assert_eq!(out, coinbase_output.commitment()); } _ => panic!("expected ImmatureCoinbase error here"), @@ -893,16 +883,15 @@ mod tests { dummy_chain.store_head_header(&head_header); // single UTXO - let new_utxo = DummyUtxoSet::empty() - .with_output(test_output(100)); + let new_utxo = DummyUtxoSet::empty().with_output(test_output(100)); dummy_chain.update_utxo_set(new_utxo); let chain_ref = Arc::new(dummy_chain); let pool = RwLock::new(test_setup(&chain_ref)); // now create two txs - // tx1 spends the UTXO - // tx2 spends output from tx1 + // tx1 spends the UTXO + // tx2 spends output from tx1 let tx1 = test_transaction(vec![100], vec![90]); let tx2 = test_transaction(vec![90], vec![80]); @@ -911,7 +900,7 @@ mod tests { assert_eq!(write_pool.total_size(), 0); // now add both txs to the pool (tx2 spends tx1 with zero confirmations) - // both should be accepted if tx1 added before tx2 + // both should be accepted if tx1 added before tx2 write_pool.add_to_memory_pool(test_source(), tx1).unwrap(); write_pool.add_to_memory_pool(test_source(), tx2).unwrap(); @@ -925,7 +914,7 @@ mod tests { txs = mineable_txs.drain(..).map(|x| *x).collect(); // confirm we can preparing both txs for mining here - // one root tx in the pool, and one non-root vertex in the pool + // one root tx in the pool, and one non-root vertex in the pool assert_eq!(txs.len(), 2); } @@ -944,7 +933,7 @@ mod tests { chain_ref.apply_block(&block); // now reconcile the block - // we should evict both txs here + // we should evict both txs here { let mut write_pool = pool.write().unwrap(); let evicted_transactions = write_pool.reconcile_block(&block).unwrap(); @@ -952,7 +941,7 @@ mod tests { } // check the pool is consistent after reconciling the block - // we should have zero txs in the pool (neither roots nor non-roots) + // we should have zero txs in the pool (neither roots nor non-roots) { let read_pool = pool.write().unwrap(); assert_eq!(read_pool.pool.len_vertices(), 0); @@ -983,44 +972,44 @@ mod tests { let pool = RwLock::new(test_setup(&chain_ref)); // Preparation: We will introduce a three root pool transactions. - // 1. A transaction that should be invalidated because it is exactly - // contained in the block. - // 2. A transaction that should be invalidated because the input is - // consumed in the block, although it is not exactly consumed. - // 3. A transaction that should remain after block reconciliation. + // 1. A transaction that should be invalidated because it is exactly + // contained in the block. + // 2. A transaction that should be invalidated because the input is + // consumed in the block, although it is not exactly consumed. + // 3. A transaction that should remain after block reconciliation. let block_transaction = test_transaction(vec![10], vec![8]); - let conflict_transaction = test_transaction(vec![20], vec![12,6]); - let valid_transaction = test_transaction(vec![30], vec![13,15]); + let conflict_transaction = test_transaction(vec![20], vec![12, 6]); + let valid_transaction = test_transaction(vec![30], vec![13, 15]); // We will also introduce a few children: - // 4. A transaction that descends from transaction 1, that is in - // turn exactly contained in the block. - let block_child = test_transaction(vec![8], vec![5,1]); + // 4. A transaction that descends from transaction 1, that is in + // turn exactly contained in the block. + let block_child = test_transaction(vec![8], vec![5, 1]); // 5. A transaction that descends from transaction 4, that is not - // contained in the block at all and should be valid after - // reconciliation. + // contained in the block at all and should be valid after + // reconciliation. let pool_child = test_transaction(vec![5], vec![3]); // 6. A transaction that descends from transaction 2 that does not - // conflict with anything in the block in any way, but should be - // invalidated (orphaned). + // conflict with anything in the block in any way, but should be + // invalidated (orphaned). let conflict_child = test_transaction(vec![12], vec![2]); // 7. A transaction that descends from transaction 2 that should be - // valid due to its inputs being satisfied by the block. + // valid due to its inputs being satisfied by the block. let conflict_valid_child = test_transaction(vec![6], vec![4]); // 8. A transaction that descends from transaction 3 that should be - // invalidated due to an output conflict. + // invalidated due to an output conflict. let valid_child_conflict = test_transaction(vec![13], vec![9]); // 9. A transaction that descends from transaction 3 that should remain - // valid after reconciliation. + // valid after reconciliation. let valid_child_valid = test_transaction(vec![15], vec![11]); // 10. A transaction that descends from both transaction 6 and - // transaction 9 - let mixed_child = test_transaction(vec![2,11], vec![7]); + // transaction 9 + let mixed_child = test_transaction(vec![2, 11], vec![7]); // Add transactions. - // Note: There are some ordering constraints that must be followed here - // until orphans is 100% implemented. Once the orphans process has - // stabilized, we can mix these up to exercise that path a bit. + // Note: There are some ordering constraints that must be followed here + // until orphans is 100% implemented. Once the orphans process has + // stabilized, we can mix these up to exercise that path a bit. let mut txs_to_add = vec![ block_transaction, conflict_transaction, @@ -1037,7 +1026,7 @@ mod tests { let expected_pool_size = txs_to_add.len(); // First we add the above transactions to the pool; all should be - // accepted. + // accepted. { let mut write_pool = pool.write().unwrap(); assert_eq!(write_pool.total_size(), 0); @@ -1049,15 +1038,15 @@ mod tests { assert_eq!(write_pool.total_size(), expected_pool_size); } // Now we prepare the block that will cause the above condition. - // First, the transactions we want in the block: - // - Copy of 1 + // First, the transactions we want in the block: + // - Copy of 1 let block_tx_1 = test_transaction(vec![10], vec![8]); // - Conflict w/ 2, satisfies 7 let block_tx_2 = test_transaction(vec![20], vec![6]); // - Copy of 4 - let block_tx_3 = test_transaction(vec![8], vec![5,1]); + let block_tx_3 = test_transaction(vec![8], vec![5, 1]); // - Output conflict w/ 8 - let block_tx_4 = test_transaction(vec![40], vec![9,1]); + let block_tx_4 = test_transaction(vec![40], vec![9, 1]); let block_transactions = vec![&block_tx_1, &block_tx_2, &block_tx_3, &block_tx_4]; let keychain = Keychain::from_random_seed().unwrap(); @@ -1083,7 +1072,7 @@ mod tests { assert_eq!(evicted_transactions.unwrap().len(), 6); // TODO: Txids are not yet deterministic. When they are, we should - // check the specific transactions that were evicted. + // check the specific transactions that were evicted. } @@ -1147,11 +1136,31 @@ mod tests { let mut write_pool = pool.write().unwrap(); assert_eq!(write_pool.total_size(), 0); - assert!(write_pool.add_to_memory_pool(test_source(), root_tx_1).is_ok()); - assert!(write_pool.add_to_memory_pool(test_source(), root_tx_2).is_ok()); - assert!(write_pool.add_to_memory_pool(test_source(), root_tx_3).is_ok()); - assert!(write_pool.add_to_memory_pool(test_source(), child_tx_1).is_ok()); - assert!(write_pool.add_to_memory_pool(test_source(), child_tx_2).is_ok()); + assert!( + write_pool + .add_to_memory_pool(test_source(), root_tx_1) + .is_ok() + ); + assert!( + write_pool + .add_to_memory_pool(test_source(), root_tx_2) + .is_ok() + ); + assert!( + write_pool + .add_to_memory_pool(test_source(), root_tx_3) + .is_ok() + ); + assert!( + write_pool + .add_to_memory_pool(test_source(), child_tx_1) + .is_ok() + ); + assert!( + write_pool + .add_to_memory_pool(test_source(), child_tx_2) + .is_ok() + ); assert_eq!(write_pool.total_size(), 5); } @@ -1164,8 +1173,8 @@ mod tests { txs = read_pool.prepare_mineable_transactions(3); assert_eq!(txs.len(), 3); // TODO: This is ugly, either make block::new take owned - // txs instead of mut refs, or change - // prepare_mineable_transactions to return mut refs + // txs instead of mut refs, or change + // prepare_mineable_transactions to return mut refs let block_txs: Vec = txs.drain(..).map(|x| *x).collect(); let tx_refs = block_txs.iter().collect(); @@ -1199,7 +1208,7 @@ mod tests { pool: Pool::empty(), orphans: Orphans::empty(), blockchain: dummy_chain.clone(), - adapter: Arc::new(NoopAdapter{}), + adapter: Arc::new(NoopAdapter {}), } } @@ -1217,8 +1226,8 @@ mod tests { ) -> transaction::Transaction { let keychain = keychain_for_tests(); - let fees: i64 = input_values.iter().sum::() as i64 - - output_values.iter().sum::() as i64; + let fees: i64 = + input_values.iter().sum::() as i64 - output_values.iter().sum::() as i64; assert!(fees >= 0); let mut tx_elements = Vec::new(); @@ -1245,8 +1254,8 @@ mod tests { ) -> transaction::Transaction { let keychain = keychain_for_tests(); - let fees: i64 = input_values.iter().sum::() as i64 - - output_values.iter().sum::() as i64; + let fees: i64 = + input_values.iter().sum::() as i64 - output_values.iter().sum::() as i64; assert!(fees >= 0); let mut tx_elements = Vec::new(); diff --git a/pool/src/types.rs b/pool/src/types.rs index 8d9308094..19460aa2c 100644 --- a/pool/src/types.rs +++ b/pool/src/types.rs @@ -34,11 +34,11 @@ pub struct PoolConfig { /// Base fee for a transaction to be accepted by the pool. The transaction /// weight is computed from its number of inputs, outputs and kernels and /// multipled by the base fee to compare to the actual transaction fee. - #[serde="default_accept_fee_base"] + #[serde = "default_accept_fee_base"] pub accept_fee_base: u64, /// Maximum capacity of the pool in number of transactions - #[serde="default_max_pool_size"] + #[serde = "default_max_pool_size"] pub max_pool_size: usize, } @@ -51,8 +51,12 @@ impl Default for PoolConfig { } } -fn default_accept_fee_base() -> u64 { 10 } -fn default_max_pool_size() -> usize { 50_000 } +fn default_accept_fee_base() -> u64 { + 10 +} +fn default_max_pool_size() -> usize { + 50_000 +} /// Placeholder: the data representing where we heard about a tx from. /// @@ -240,7 +244,6 @@ impl Pool { pool_refs: Vec, mut new_unspents: Vec, ) { - // Removing consumed available_outputs for new_edge in &pool_refs { // All of these should correspond to an existing unspent @@ -253,23 +256,18 @@ impl Pool { // Accounting for consumed blockchain outputs for new_blockchain_edge in blockchain_refs.drain(..) { - self.consumed_blockchain_outputs.insert( - new_blockchain_edge - .output_commitment(), - new_blockchain_edge, - ); + self.consumed_blockchain_outputs + .insert(new_blockchain_edge.output_commitment(), new_blockchain_edge); } // Adding the transaction to the vertices list along with internal - // pool edges + // pool edges self.graph.add_entry(pool_entry, pool_refs); // Adding the new unspents to the unspent map for unspent_output in new_unspents.drain(..) { - self.available_outputs.insert( - unspent_output.output_commitment(), - unspent_output, - ); + self.available_outputs + .insert(unspent_output.output_commitment(), unspent_output); } } @@ -282,19 +280,14 @@ impl Pool { tx: &transaction::Transaction, marked_txs: &HashSet, ) { - self.graph.remove_vertex(graph::transaction_identifier(tx)); for input in tx.inputs.iter().map(|x| x.commitment()) { match self.graph.remove_edge_by_commitment(&input) { - Some(x) => { - if !marked_txs.contains(&x.source_hash().unwrap()) { - self.available_outputs.insert( - x.output_commitment(), - x.with_destination(None), - ); - } - } + Some(x) => if !marked_txs.contains(&x.source_hash().unwrap()) { + self.available_outputs + .insert(x.output_commitment(), x.with_destination(None)); + }, None => { self.consumed_blockchain_outputs.remove(&input); } @@ -303,15 +296,10 @@ impl Pool { for output in tx.outputs.iter().map(|x| x.commitment()) { match self.graph.remove_edge_by_commitment(&output) { - Some(x) => { - if !marked_txs.contains(&x.destination_hash().unwrap()) { - - self.consumed_blockchain_outputs.insert( - x.output_commitment(), - x.with_source(None), - ); - } - } + Some(x) => if !marked_txs.contains(&x.destination_hash().unwrap()) { + self.consumed_blockchain_outputs + .insert(x.output_commitment(), x.with_source(None)); + }, None => { self.available_outputs.remove(&output); } @@ -413,14 +401,11 @@ impl Orphans { is_missing: HashMap, mut new_unspents: Vec, ) { - // Removing consumed available_outputs for (i, new_edge) in orphan_refs.drain(..).enumerate() { if is_missing.contains_key(&i) { - self.missing_outputs.insert( - new_edge.output_commitment(), - new_edge, - ); + self.missing_outputs + .insert(new_edge.output_commitment(), new_edge); } else { assert!( self.available_outputs @@ -433,27 +418,21 @@ impl Orphans { // Accounting for consumed blockchain and pool outputs for external_edge in pool_refs.drain(..) { - self.pool_connections.insert( - external_edge.output_commitment(), - external_edge, - ); + self.pool_connections + .insert(external_edge.output_commitment(), external_edge); } // if missing_refs is the same length as orphan_refs, we have - // no orphan-orphan links for this transaction and it is a - // root transaction of the orphans set - self.graph.add_vertex_only( - orphan_entry, - is_missing.len() == orphan_refs.len(), - ); + // no orphan-orphan links for this transaction and it is a + // root transaction of the orphans set + self.graph + .add_vertex_only(orphan_entry, is_missing.len() == orphan_refs.len()); // Adding the new unspents to the unspent map for unspent_output in new_unspents.drain(..) { - self.available_outputs.insert( - unspent_output.output_commitment(), - unspent_output, - ); + self.available_outputs + .insert(unspent_output.output_commitment(), unspent_output); } } } diff --git a/pow/src/cuckoo.rs b/pow/src/cuckoo.rs index dd8cb173a..cd7859d2e 100644 --- a/pow/src/cuckoo.rs +++ b/pow/src/cuckoo.rs @@ -313,9 +313,9 @@ impl Miner { /// Utility to transform a 8 bytes of a byte array into a u64. fn u8_to_u64(p: &[u8], i: usize) -> u64 { - (p[i] as u64) | (p[i + 1] as u64) << 8 | (p[i + 2] as u64) << 16 | - (p[i + 3] as u64) << 24 | (p[i + 4] as u64) << 32 | (p[i + 5] as u64) << 40 | - (p[i + 6] as u64) << 48 | (p[i + 7] as u64) << 56 + (p[i] as u64) | (p[i + 1] as u64) << 8 | (p[i + 2] as u64) << 16 | (p[i + 3] as u64) << 24 + | (p[i + 4] as u64) << 32 | (p[i + 5] as u64) << 40 | (p[i + 6] as u64) << 48 + | (p[i + 7] as u64) << 56 } #[cfg(test)] @@ -324,32 +324,183 @@ mod test { use core::core::Proof; - static V1: [u32; 42] = [0x1fe9, 0x2050, 0x4581, 0x6322, 0x65ab, 0xb3c1, 0xc1a4, 0xe257, - 0x106ae, 0x17b11, 0x202d4, 0x2705d, 0x2deb2, 0x2f80e, 0x32298, - 0x34782, 0x35c5a, 0x37458, 0x38f28, 0x406b2, 0x40e34, 0x40fc6, - 0x42220, 0x42d13, 0x46c0f, 0x4fd47, 0x55ad2, 0x598f7, 0x5aa8f, - 0x62aa3, 0x65725, 0x65dcb, 0x671c7, 0x6eb20, 0x752fe, 0x7594f, - 0x79b9c, 0x7f775, 0x81635, 0x8401c, 0x844e5, 0x89fa8]; - static V2: [u32; 42] = [0x2a37, 0x7557, 0xa3c3, 0xfce6, 0x1248e, 0x15837, 0x1827f, 0x18a93, - 0x1a7dd, 0x1b56b, 0x1ceb4, 0x1f962, 0x1fe2a, 0x29cb9, 0x2f30e, - 0x2f771, 0x336bf, 0x34355, 0x391d7, 0x39495, 0x3be0c, 0x463be, - 0x4d0c2, 0x4eead, 0x50214, 0x520de, 0x52a86, 0x53818, 0x53b3b, - 0x54c0b, 0x572fa, 0x5d79c, 0x5e3c2, 0x6769e, 0x6a0fe, 0x6d835, - 0x6fc7c, 0x70f03, 0x79d4a, 0x7b03e, 0x81e09, 0x9bd44]; - static V3: [u32; 42] = [0x8158, 0x9f18, 0xc4ba, 0x108c7, 0x11caa, 0x13b82, 0x1618f, 0x1c83b, - 0x1ec89, 0x24354, 0x28864, 0x2a0fb, 0x2ce50, 0x2e8fa, 0x32b36, - 0x343e6, 0x34dc9, 0x36881, 0x3ffca, 0x40f79, 0x42721, 0x43b8c, - 0x44b9d, 0x47ed3, 0x4cd34, 0x5278a, 0x5ab64, 0x5b4d4, 0x5d842, - 0x5fa33, 0x6464e, 0x676ee, 0x685d6, 0x69df0, 0x6a5fd, 0x6bda3, - 0x72544, 0x77974, 0x7908c, 0x80e67, 0x81ef4, 0x8d882]; + static V1: [u32; 42] = [ + 0x1fe9, + 0x2050, + 0x4581, + 0x6322, + 0x65ab, + 0xb3c1, + 0xc1a4, + 0xe257, + 0x106ae, + 0x17b11, + 0x202d4, + 0x2705d, + 0x2deb2, + 0x2f80e, + 0x32298, + 0x34782, + 0x35c5a, + 0x37458, + 0x38f28, + 0x406b2, + 0x40e34, + 0x40fc6, + 0x42220, + 0x42d13, + 0x46c0f, + 0x4fd47, + 0x55ad2, + 0x598f7, + 0x5aa8f, + 0x62aa3, + 0x65725, + 0x65dcb, + 0x671c7, + 0x6eb20, + 0x752fe, + 0x7594f, + 0x79b9c, + 0x7f775, + 0x81635, + 0x8401c, + 0x844e5, + 0x89fa8, + ]; + static V2: [u32; 42] = [ + 0x2a37, + 0x7557, + 0xa3c3, + 0xfce6, + 0x1248e, + 0x15837, + 0x1827f, + 0x18a93, + 0x1a7dd, + 0x1b56b, + 0x1ceb4, + 0x1f962, + 0x1fe2a, + 0x29cb9, + 0x2f30e, + 0x2f771, + 0x336bf, + 0x34355, + 0x391d7, + 0x39495, + 0x3be0c, + 0x463be, + 0x4d0c2, + 0x4eead, + 0x50214, + 0x520de, + 0x52a86, + 0x53818, + 0x53b3b, + 0x54c0b, + 0x572fa, + 0x5d79c, + 0x5e3c2, + 0x6769e, + 0x6a0fe, + 0x6d835, + 0x6fc7c, + 0x70f03, + 0x79d4a, + 0x7b03e, + 0x81e09, + 0x9bd44, + ]; + static V3: [u32; 42] = [ + 0x8158, + 0x9f18, + 0xc4ba, + 0x108c7, + 0x11caa, + 0x13b82, + 0x1618f, + 0x1c83b, + 0x1ec89, + 0x24354, + 0x28864, + 0x2a0fb, + 0x2ce50, + 0x2e8fa, + 0x32b36, + 0x343e6, + 0x34dc9, + 0x36881, + 0x3ffca, + 0x40f79, + 0x42721, + 0x43b8c, + 0x44b9d, + 0x47ed3, + 0x4cd34, + 0x5278a, + 0x5ab64, + 0x5b4d4, + 0x5d842, + 0x5fa33, + 0x6464e, + 0x676ee, + 0x685d6, + 0x69df0, + 0x6a5fd, + 0x6bda3, + 0x72544, + 0x77974, + 0x7908c, + 0x80e67, + 0x81ef4, + 0x8d882, + ]; // cuckoo28 at 50% edges of letter 'u' - static V4: [u32; 42] = [0x1CBBFD, 0x2C5452, 0x520338, 0x6740C5, 0x8C6997, 0xC77150, 0xFD4972, - 0x1060FA7, 0x11BFEA0, 0x1343E8D, 0x14CE02A, 0x1533515, 0x1715E61, - 0x1996D9B, 0x1CB296B, 0x1FCA180, 0x209A367, 0x20AD02E, 0x23CD2E4, - 0x2A3B360, 0x2DD1C0C, 0x333A200, 0x33D77BC, 0x3620C78, 0x3DD7FB8, - 0x3FBFA49, 0x41BDED2, 0x4A86FD9, 0x570DE24, 0x57CAB86, 0x594B886, - 0x5C74C94, 0x5DE7572, 0x60ADD6F, 0x635918B, 0x6C9E120, 0x6EFA583, - 0x7394ACA, 0x7556A23, 0x77F70AA, 0x7CF750A, 0x7F60790]; + static V4: [u32; 42] = [ + 0x1CBBFD, + 0x2C5452, + 0x520338, + 0x6740C5, + 0x8C6997, + 0xC77150, + 0xFD4972, + 0x1060FA7, + 0x11BFEA0, + 0x1343E8D, + 0x14CE02A, + 0x1533515, + 0x1715E61, + 0x1996D9B, + 0x1CB296B, + 0x1FCA180, + 0x209A367, + 0x20AD02E, + 0x23CD2E4, + 0x2A3B360, + 0x2DD1C0C, + 0x333A200, + 0x33D77BC, + 0x3620C78, + 0x3DD7FB8, + 0x3FBFA49, + 0x41BDED2, + 0x4A86FD9, + 0x570DE24, + 0x57CAB86, + 0x594B886, + 0x5C74C94, + 0x5DE7572, + 0x60ADD6F, + 0x635918B, + 0x6C9E120, + 0x6EFA583, + 0x7394ACA, + 0x7556A23, + 0x77F70AA, + 0x7CF750A, + 0x7F60790, + ]; /// Find a 42-cycle on Cuckoo20 at 75% easiness and verifiy against a few /// known cycle proofs @@ -384,13 +535,15 @@ mod test { fn validate_fail() { // edge checks assert!(!Cuckoo::new(&[49], 20).verify(Proof::new(vec![0; 42]), 75)); - assert!(!Cuckoo::new(&[49], 20).verify(Proof::new(vec![0xffff; 42]), 75)); + assert!(!Cuckoo::new(&[49], 20) + .verify(Proof::new(vec![0xffff; 42]), 75)); // wrong data for proof - assert!(!Cuckoo::new(&[50], 20).verify(Proof::new(V1.to_vec().clone()), 75)); + assert!(!Cuckoo::new(&[50], 20) + .verify(Proof::new(V1.to_vec().clone()), 75)); let mut test_header = [0; 32]; test_header[0] = 24; - assert!(!Cuckoo::new(&test_header, 20).verify(Proof::new(V4.to_vec().clone()), 50)); - + assert!(!Cuckoo::new(&test_header, 20) + .verify(Proof::new(V4.to_vec().clone()), 50)); } #[test] diff --git a/pow/src/lib.rs b/pow/src/lib.rs index d052b007b..eca662238 100644 --- a/pow/src/lib.rs +++ b/pow/src/lib.rs @@ -29,15 +29,15 @@ #![warn(missing_docs)] extern crate blake2_rfc as blake2; -extern crate rand; -extern crate time; #[macro_use] extern crate lazy_static; -#[macro_use] -extern crate slog; +extern crate rand; extern crate serde; #[macro_use] extern crate serde_derive; +#[macro_use] +extern crate slog; +extern crate time; extern crate grin_core as core; extern crate grin_util as util; @@ -63,7 +63,9 @@ use cuckoo::{Cuckoo, Error}; pub trait MiningWorker { /// This only sets parameters and does initialisation work now - fn new(ease: u32, sizeshift: u32, proof_size: usize) -> Self where Self: Sized; + fn new(ease: u32, sizeshift: u32, proof_size: usize) -> Self + where + Self: Sized; /// Actually perform a mining attempt on the given input and /// return a proof if found @@ -74,7 +76,7 @@ pub trait MiningWorker { /// satisfies the requirements of the header. pub fn verify_size(bh: &BlockHeader, cuckoo_sz: u32) -> bool { // make sure the pow hash shows a difficulty at least as large as the target - // difficulty + // difficulty if bh.difficulty > bh.pow.clone().to_difficulty() { return false; } @@ -83,10 +85,11 @@ pub fn verify_size(bh: &BlockHeader, cuckoo_sz: u32) -> bool { /// Uses the much easier Cuckoo20 (mostly for /// tests). -pub fn pow20(miner: &mut T, - bh: &mut BlockHeader, - diff: Difficulty) - -> Result<(), Error> { +pub fn pow20( + miner: &mut T, + bh: &mut BlockHeader, + diff: Difficulty, +) -> Result<(), Error> { pow_size(miner, bh, diff, 20) } @@ -104,16 +107,13 @@ pub fn mine_genesis_block(miner_config: Option) -> Option = match miner_config { - Some(c) => { - if c.use_cuckoo_miner { - let mut p = plugin::PluginMiner::new(consensus::EASINESS, sz, proof_size); - p.init(c.clone()); - Box::new(p) - - } else { - Box::new(cuckoo::Miner::new(consensus::EASINESS, sz, proof_size)) - } - } + Some(c) => if c.use_cuckoo_miner { + let mut p = plugin::PluginMiner::new(consensus::EASINESS, sz, proof_size); + p.init(c.clone()); + Box::new(p) + } else { + Box::new(cuckoo::Miner::new(consensus::EASINESS, sz, proof_size)) + }, None => Box::new(cuckoo::Miner::new(consensus::EASINESS, sz, proof_size)), }; pow_size(&mut *miner, &mut gen.header, diff, sz as u32).unwrap(); @@ -124,11 +124,12 @@ pub fn mine_genesis_block(miner_config: Option) -> Option(miner: &mut T, - bh: &mut BlockHeader, - diff: Difficulty, - _: u32) - -> Result<(), Error> { +pub fn pow_size( + miner: &mut T, + bh: &mut BlockHeader, + diff: Difficulty, + _: u32, +) -> Result<(), Error> { let start_nonce = bh.nonce; // if we're in production mode, try the pre-mined solution first @@ -143,11 +144,11 @@ pub fn pow_size(miner: &mut T, // try to find a cuckoo cycle on that header hash loop { // can be trivially optimized by avoiding re-serialization every time but this - // is not meant as a fast miner implementation + // is not meant as a fast miner implementation let pow_hash = bh.hash(); // if we found a cycle (not guaranteed) and the proof hash is higher that the - // diff, we're all good + // diff, we're all good if let Ok(proof) = miner.mine(&pow_hash[..]) { if proof.clone().to_difficulty() >= diff { @@ -160,7 +161,7 @@ pub fn pow_size(miner: &mut T, bh.nonce += 1; // and if we're back where we started, update the time (changes the hash as - // well) + // well) if bh.nonce == start_nonce { bh.timestamp = time::at_utc(time::Timespec { sec: 0, nsec: 0 }); } diff --git a/pow/src/plugin.rs b/pow/src/plugin.rs index 8ad8dc7db..21729f5b5 100644 --- a/pow/src/plugin.rs +++ b/pow/src/plugin.rs @@ -30,8 +30,8 @@ use util::LOGGER; use std::sync::Mutex; -use cuckoo_miner::{CuckooMiner, CuckooPluginManager, CuckooMinerConfig, CuckooMinerSolution, - CuckooMinerDeviceStats, CuckooMinerError}; +use cuckoo_miner::{CuckooMiner, CuckooMinerConfig, CuckooMinerDeviceStats, CuckooMinerError, + CuckooMinerSolution, CuckooPluginManager}; // For now, we're just going to keep a static reference around to the loaded // config @@ -41,7 +41,7 @@ use cuckoo_miner::{CuckooMiner, CuckooPluginManager, CuckooMinerConfig, CuckooMi // testing threads don't try to load/unload the library while another thread is // using it. lazy_static!{ - static ref LOADED_CONFIG: Mutex>> = Mutex::new(None); + static ref LOADED_CONFIG: Mutex>> = Mutex::new(None); } /// plugin miner @@ -84,9 +84,9 @@ impl PluginMiner { } // First, load and query the plugins in the given directory - // These should all be stored in 'plugins' at the moment relative - // to the executable path, though they should appear somewhere else - // when packaging is more//thought out + // These should all be stored in 'plugins' at the moment relative + // to the executable path, though they should appear somewhere else + // when packaging is more//thought out let mut loaded_config_ref = LOADED_CONFIG.lock().unwrap(); @@ -117,7 +117,7 @@ impl PluginMiner { let mut index = 0; for f in plugin_vec_filters { // So this is built dynamically based on the plugin implementation - // type and the consensus sizeshift + // type and the consensus sizeshift let filter = format!("{}_{}", f, sz); let caps = plugin_manager.get_available_plugins(&filter).unwrap(); @@ -141,7 +141,7 @@ impl PluginMiner { index += 1; } // Store this config now, because we just want one instance - // of the plugin lib per invocation now + // of the plugin lib per invocation now *loaded_config_ref = Some(cuckoo_configs.clone()); // this will load the associated plugin @@ -158,7 +158,6 @@ impl PluginMiner { /// Get the miner pub fn get_consumable(&mut self) -> CuckooMiner { - // this will load the associated plugin let result = CuckooMiner::new(self.config.clone()); if let Err(e) = result { diff --git a/pow/src/types.rs b/pow/src/types.rs index fe7ac9796..7bdd831d9 100644 --- a/pow/src/types.rs +++ b/pow/src/types.rs @@ -77,7 +77,7 @@ impl Default for MinerConfig { cuckoo_miner_async_mode: None, cuckoo_miner_plugin_dir: None, cuckoo_miner_plugin_config: None, - wallet_receiver_url: "http://localhost:13416".to_string(), + wallet_receiver_url: "http://localhost:13415".to_string(), burn_reward: false, slow_down_in_millis: Some(0), attempt_time_per_block: 2, diff --git a/src/bin/grin.rs b/src/bin/grin.rs index 1c13effde..54aea075e 100644 --- a/src/bin/grin.rs +++ b/src/bin/grin.rs @@ -14,34 +14,34 @@ //! Main for building the binary of a Grin peer-to-peer node. -#[macro_use] -extern crate slog; +extern crate blake2_rfc as blake2; extern crate clap; extern crate daemonize; extern crate serde; extern crate serde_json; -extern crate blake2_rfc as blake2; +#[macro_use] +extern crate slog; extern crate grin_api as api; -extern crate grin_grin as grin; -extern crate grin_wallet as wallet; -extern crate grin_keychain as keychain; extern crate grin_config as config; extern crate grin_core as core; +extern crate grin_grin as grin; +extern crate grin_keychain as keychain; extern crate grin_util as util; +extern crate grin_wallet as wallet; use std::thread; use std::io::Read; use std::fs::File; use std::time::Duration; -use clap::{Arg, App, SubCommand, ArgMatches}; +use clap::{App, Arg, ArgMatches, SubCommand}; use daemonize::Daemonize; use config::GlobalConfig; use wallet::WalletConfig; use core::global; -use util::{LoggingConfig, LOGGER, init_logger}; +use util::{init_logger, LoggingConfig, LOGGER}; fn start_from_config_file(mut global_config: GlobalConfig) { info!( @@ -68,16 +68,15 @@ fn start_from_config_file(mut global_config: GlobalConfig) { } fn main() { - // First, load a global config object, - // then modify that object with any switches - // found so that the switches override the - // global config file + // then modify that object with any switches + // found so that the switches override the + // global config file // This will return a global config object, - // which will either contain defaults for all // of the config structures or a - // configuration - // read from a config file + // which will either contain defaults for all // of the config structures or a + // configuration + // read from a config file let mut global_config = GlobalConfig::new(None).unwrap_or_else(|e| { panic!("Error parsing config file: {}", e); @@ -241,14 +240,12 @@ fn main() { } // client commands and options - ("client", Some(client_args)) => { - match client_args.subcommand() { - ("status", _) => { - println!("status info..."); - } - _ => panic!("Unknown client command, use 'grin help client' for details"), + ("client", Some(client_args)) => match client_args.subcommand() { + ("status", _) => { + println!("status info..."); } - } + _ => panic!("Unknown client command, use 'grin help client' for details"), + }, // client commands and options ("wallet", Some(wallet_args)) => { @@ -263,7 +260,7 @@ fn main() { start_from_config_file(global_config); } else { // won't attempt to just start with defaults, - // and will reject + // and will reject println!("Unknown command, and no configuration file was found."); println!("Use 'grin help' for a list of all commands."); } @@ -352,48 +349,44 @@ fn wallet_command(wallet_args: &ArgMatches) { } // Derive the keychain based on seed from seed file and specified passphrase. - // Generate the initial wallet seed if we are running "wallet init". + // Generate the initial wallet seed if we are running "wallet init". if let ("init", Some(_)) = wallet_args.subcommand() { - wallet::WalletSeed::init_file(&wallet_config) - .expect("Failed to init wallet seed file."); + wallet::WalletSeed::init_file(&wallet_config).expect("Failed to init wallet seed file."); // we are done here with creating the wallet, so just return return; } - let wallet_seed = wallet::WalletSeed::from_file(&wallet_config) - .expect("Failed to read wallet seed file."); + let wallet_seed = + wallet::WalletSeed::from_file(&wallet_config).expect("Failed to read wallet seed file."); let passphrase = wallet_args .value_of("pass") .expect("Failed to read passphrase."); - let keychain = wallet_seed.derive_keychain(&passphrase) + let keychain = wallet_seed + .derive_keychain(&passphrase) .expect("Failed to derive keychain from seed file and passphrase."); match wallet_args.subcommand() { - ("receive", Some(receive_args)) => { - if let Some(f) = receive_args.value_of("input") { - let mut file = File::open(f).expect("Unable to open transaction file."); - let mut contents = String::new(); - file.read_to_string(&mut contents).expect( - "Unable to read transaction file.", - ); - wallet::receive_json_tx(&wallet_config, &keychain, contents.as_str()).unwrap(); - } else { - wallet::server::start_rest_apis(wallet_config, keychain); - } - } + ("receive", Some(receive_args)) => if let Some(f) = receive_args.value_of("input") { + let mut file = File::open(f).expect("Unable to open transaction file."); + let mut contents = String::new(); + file.read_to_string(&mut contents) + .expect("Unable to read transaction file."); + wallet::receive_json_tx(&wallet_config, &keychain, contents.as_str()).unwrap(); + } else { + wallet::server::start_rest_apis(wallet_config, keychain); + }, ("send", Some(send_args)) => { let amount = send_args .value_of("amount") .expect("Amount to send required") .parse() .expect("Could not parse amount as a whole number."); - let minimum_confirmations: u64 = - send_args - .value_of("minimum_confirmations") - .unwrap_or("1") - .parse() - .expect("Could not parse minimum_confirmations as a whole number."); + let minimum_confirmations: u64 = send_args + .value_of("minimum_confirmations") + .unwrap_or("1") + .parse() + .expect("Could not parse minimum_confirmations as a whole number."); let mut dest = "stdout"; if let Some(d) = send_args.value_of("dest") { dest = d; @@ -412,12 +405,11 @@ fn wallet_command(wallet_args: &ArgMatches) { .expect("Amount to burn required") .parse() .expect("Could not parse amount as a whole number."); - let minimum_confirmations: u64 = - send_args - .value_of("minimum_confirmations") - .unwrap_or("1") - .parse() - .expect("Could not parse minimum_confirmations as a whole number."); + let minimum_confirmations: u64 = send_args + .value_of("minimum_confirmations") + .unwrap_or("1") + .parse() + .expect("Could not parse minimum_confirmations as a whole number."); wallet::issue_burn_tx(&wallet_config, &keychain, amount, minimum_confirmations) .unwrap(); } diff --git a/store/src/lib.rs b/store/src/lib.rs index 09eb30190..a3abdce49 100644 --- a/store/src/lib.rs +++ b/store/src/lib.rs @@ -21,14 +21,14 @@ #![warn(missing_docs)] extern crate byteorder; +extern crate env_logger; extern crate grin_core as core; extern crate grin_util as util; extern crate libc; -#[macro_use] -extern crate slog; -extern crate env_logger; extern crate memmap; extern crate rocksdb; +#[macro_use] +extern crate slog; pub mod sumtree; @@ -39,8 +39,8 @@ use std::iter::Iterator; use std::marker::PhantomData; use std::sync::RwLock; -use byteorder::{WriteBytesExt, BigEndian}; -use rocksdb::{DB, WriteBatch, DBCompactionStyle, DBIterator, IteratorMode, Direction}; +use byteorder::{BigEndian, WriteBytesExt}; +use rocksdb::{DBCompactionStyle, DBIterator, Direction, IteratorMode, WriteBatch, DB}; use core::ser; @@ -89,7 +89,9 @@ impl Store { opts.set_max_open_files(256); opts.set_use_fsync(false); let db = try!(DB::open(&opts, &path)); - Ok(Store { rdb: RwLock::new(db) }) + Ok(Store { + rdb: RwLock::new(db), + }) } /// Writes a single key/value pair to the db @@ -125,10 +127,11 @@ impl Store { /// Gets a `Readable` value from the db, provided its key, allowing to /// extract only partial data. The underlying Readable size must align /// accordingly. Encapsulates serialization. - pub fn get_ser_limited(&self, - key: &[u8], - len: usize) - -> Result, Error> { + pub fn get_ser_limited( + &self, + key: &[u8], + len: usize, + ) -> Result, Error> { let data = try!(self.get(key)); match data { Some(val) => { @@ -213,14 +216,16 @@ impl<'a> Batch<'a> { /// An iterator thad produces Readable instances back. Wraps the lower level /// DBIterator and deserializes the returned values. pub struct SerIterator - where T: ser::Readable +where + T: ser::Readable, { iter: DBIterator, _marker: PhantomData, } impl Iterator for SerIterator - where T: ser::Readable +where + T: ser::Readable, { type Item = T; diff --git a/store/src/sumtree.rs b/store/src/sumtree.rs index 1effc77ca..2420c8085 100644 --- a/store/src/sumtree.rs +++ b/store/src/sumtree.rs @@ -17,17 +17,17 @@ use memmap; use std::cmp; use std::fs::{self, File, OpenOptions}; -use std::io::{self, Write, BufReader, BufRead, ErrorKind}; +use std::io::{self, BufRead, BufReader, ErrorKind, Write}; use std::os::unix::io::AsRawFd; use std::path::Path; use std::io::Read; #[cfg(any(target_os = "linux"))] -use libc::{off64_t, ftruncate64}; +use libc::{ftruncate64, off64_t}; #[cfg(not(any(target_os = "linux", target_os = "android")))] -use libc::{off_t as off64_t, ftruncate as ftruncate64}; +use libc::{ftruncate as ftruncate64, off_t as off64_t}; -use core::core::pmmr::{self, Summable, Backend, HashSum, VecBackend}; +use core::core::pmmr::{self, Backend, HashSum, Summable, VecBackend}; use core::ser; use util::LOGGER; @@ -116,7 +116,7 @@ impl AppendOnlyFile { } as u64; // write the buffer, except if we prune offsets in the current span, - // in which case we skip + // in which case we skip let mut buf_start = 0; while prune_offs[prune_pos] >= read && prune_offs[prune_pos] < read + len { let prune_at = prune_offs[prune_pos] as usize; @@ -282,10 +282,8 @@ where /// Append the provided HashSums to the backend storage. #[allow(unused_variables)] fn append(&mut self, position: u64, data: Vec>) -> Result<(), String> { - self.buffer.append( - position - (self.buffer_index as u64), - data.clone(), - )?; + self.buffer + .append(position - (self.buffer_index as u64), data.clone())?; Ok(()) } @@ -330,9 +328,9 @@ where fn rewind(&mut self, position: u64, index: u32) -> Result<(), String> { assert!(self.buffer.len() == 0, "Rewind on non empty buffer."); - self.remove_log.truncate(index).map_err(|e| { - format!("Could not truncate remove log: {}", e) - })?; + self.remove_log + .truncate(index) + .map_err(|e| format!("Could not truncate remove log: {}", e))?; self.rewind = Some((position, index, self.buffer_index)); self.buffer_index = position as usize; Ok(()) @@ -343,8 +341,7 @@ where if self.buffer.used_size() > 0 { for position in &positions { let pos_sz = *position as usize; - if pos_sz > self.buffer_index && - pos_sz - 1 < self.buffer_index + self.buffer.len() + if pos_sz > self.buffer_index && pos_sz - 1 < self.buffer_index + self.buffer.len() { self.buffer.remove(vec![*position], index).unwrap(); } @@ -375,7 +372,9 @@ where remove_log: rm_log, buffer: VecBackend::new(), buffer_index: (sz as usize) / record_len, - pruned_nodes: pmmr::PruneList { pruned_nodes: prune_list }, + pruned_nodes: pmmr::PruneList { + pruned_nodes: prune_list, + }, rewind: None, }) } @@ -403,10 +402,7 @@ where if let Err(e) = self.hashsum_file.append(&ser::ser_vec(&hs).unwrap()[..]) { return Err(io::Error::new( io::ErrorKind::Interrupted, - format!( - "Could not write to log storage, disk full? {:?}", - e - ), + format!("Could not write to log storage, disk full? {:?}", e), )); } } @@ -442,28 +438,28 @@ where /// TODO whatever is calling this should also clean up the commit to /// position index in db pub fn check_compact(&mut self, max_len: usize) -> io::Result<()> { - if !(max_len > 0 && self.remove_log.len() > max_len || - max_len == 0 && self.remove_log.len() > RM_LOG_MAX_NODES) + if !(max_len > 0 && self.remove_log.len() > max_len + || max_len == 0 && self.remove_log.len() > RM_LOG_MAX_NODES) { return Ok(()); } // 0. validate none of the nodes in the rm log are in the prune list (to - // avoid accidental double compaction) + // avoid accidental double compaction) for pos in &self.remove_log.removed[..] { if let None = self.pruned_nodes.pruned_pos(pos.0) { // TODO we likely can recover from this by directly jumping to 3 error!( LOGGER, "The remove log contains nodes that are already in the pruned \ - list, a previous compaction likely failed." + list, a previous compaction likely failed." ); return Ok(()); } } // 1. save hashsum file to a compact copy, skipping data that's in the - // remove list + // remove list let tmp_prune_file = format!("{}/{}.prune", self.data_dir, PMMR_DATA_FILE); let record_len = (32 + T::sum_len()) as u64; let to_rm = self.remove_log @@ -474,11 +470,8 @@ where (pos - 1 - shift.unwrap()) * record_len }) .collect(); - self.hashsum_file.save_prune( - tmp_prune_file.clone(), - to_rm, - record_len, - )?; + self.hashsum_file + .save_prune(tmp_prune_file.clone(), to_rm, record_len)?; // 2. update the prune list and save it in place for &(rm_pos, _) in &self.remove_log.removed[..] { @@ -510,7 +503,6 @@ fn read_ordered_vec(path: String) -> io::Result> where T: ser::Readable + cmp::Ord, { - let file_path = Path::new(&path); let mut ovec = Vec::with_capacity(1000); if file_path.exists() { @@ -524,20 +516,15 @@ where } let elmts_res: Result, ser::Error> = ser::deserialize(&mut &buf[..]); match elmts_res { - Ok(elmts) => { - for elmt in elmts { - if let Err(idx) = ovec.binary_search(&elmt) { - ovec.insert(idx, elmt); - } + Ok(elmts) => for elmt in elmts { + if let Err(idx) = ovec.binary_search(&elmt) { + ovec.insert(idx, elmt); } - } + }, Err(_) => { return Err(io::Error::new( io::ErrorKind::InvalidData, - format!( - "Corrupted storage, could not read file at {}", - path - ), + format!("Corrupted storage, could not read file at {}", path), )); } } @@ -553,7 +540,6 @@ fn write_vec(path: String, v: &Vec) -> io::Result<()> where T: ser::Writeable, { - let mut file_path = File::create(&path)?; ser::serialize(&mut file_path, v).map_err(|_| { io::Error::new( diff --git a/store/tests/sumtree.rs b/store/tests/sumtree.rs index e865a70f4..310ec02d8 100644 --- a/store/tests/sumtree.rs +++ b/store/tests/sumtree.rs @@ -20,7 +20,7 @@ extern crate time; use std::fs; use core::ser::*; -use core::core::pmmr::{PMMR, Summable, HashSum, Backend}; +use core::core::pmmr::{Backend, HashSum, Summable, PMMR}; use core::core::hash::Hashed; #[test] @@ -48,11 +48,16 @@ fn sumtree_append() { }) ); - let sum2 = HashSum::from_summable(1, &elems[0], None::) + HashSum::from_summable(2, &elems[1], None::); - let sum4 = sum2 + (HashSum::from_summable(4, &elems[2], None::) + HashSum::from_summable(5, &elems[3], None::)); - let sum8 = sum4 + - ((HashSum::from_summable(8, &elems[4], None::) + HashSum::from_summable(9, &elems[5], None::)) + - (HashSum::from_summable(11, &elems[6], None::) + HashSum::from_summable(12, &elems[7], None::))); + let sum2 = HashSum::from_summable(1, &elems[0], None::) + + HashSum::from_summable(2, &elems[1], None::); + let sum4 = sum2 + + (HashSum::from_summable(4, &elems[2], None::) + + HashSum::from_summable(5, &elems[3], None::)); + let sum8 = sum4 + + ((HashSum::from_summable(8, &elems[4], None::) + + HashSum::from_summable(9, &elems[5], None::)) + + (HashSum::from_summable(11, &elems[6], None::) + + HashSum::from_summable(12, &elems[7], None::))); let sum9 = sum8 + HashSum::from_summable(16, &elems[8], None::); { @@ -177,7 +182,7 @@ fn sumtree_rewind() { } backend.check_compact(1).unwrap(); backend.sync().unwrap(); - + // rewind and check the roots still match { let mut pmmr = PMMR::at(&mut backend, mmr_size); @@ -223,7 +228,6 @@ fn setup() -> (String, Vec) { } fn load(pos: u64, elems: &[TestElem], backend: &mut store::sumtree::PMMRBackend) -> u64 { - let mut pmmr = PMMR::at(backend, pos); for elem in elems { pmmr.push(elem.clone(), None::).unwrap(); @@ -237,9 +241,9 @@ impl Summable for TestElem { type Sum = u64; fn sum(&self) -> u64 { // sums are not allowed to overflow, so we use this simple - // non-injective "sum" function that will still be homomorphic - self.0[0] as u64 * 0x1000 + self.0[1] as u64 * 0x100 + self.0[2] as u64 * 0x10 + - self.0[3] as u64 + // non-injective "sum" function that will still be homomorphic + self.0[0] as u64 * 0x1000 + self.0[1] as u64 * 0x100 + self.0[2] as u64 * 0x10 + + self.0[3] as u64 } fn sum_len() -> usize { 8 diff --git a/util/src/lib.rs b/util/src/lib.rs index 3dcdb1663..5931a6c3b 100644 --- a/util/src/lib.rs +++ b/util/src/lib.rs @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Logging, as well as various low-level utilities that factor Rust +//! Logging, as well as various low-level utilities that factor Rust //! patterns that are frequent within the grin codebase. #![deny(non_upper_case_globals)] @@ -23,8 +23,8 @@ #[macro_use] extern crate slog; -extern crate slog_term; extern crate slog_async; +extern crate slog_term; #[macro_use] extern crate lazy_static; @@ -39,13 +39,13 @@ pub use secp_ as secp; // Logging related pub mod logger; -pub use logger::{LOGGER, init_logger, init_test_logger}; +pub use logger::{init_logger, init_test_logger, LOGGER}; pub mod types; pub use types::LoggingConfig; // other utils -use std::cell::{RefCell, Ref}; +use std::cell::{Ref, RefCell}; #[allow(unused_imports)] use std::ops::Deref; @@ -68,7 +68,9 @@ unsafe impl Send for OneTime {} impl OneTime { /// Builds a new uninitialized OneTime. pub fn new() -> OneTime { - OneTime { inner: RefCell::new(None) } + OneTime { + inner: RefCell::new(None), + } } /// Initializes the OneTime, should only be called once after construction. diff --git a/util/src/logger.rs b/util/src/logger.rs index 424f5790d..fa91aea74 100644 --- a/util/src/logger.rs +++ b/util/src/logger.rs @@ -15,7 +15,7 @@ use std::fs::OpenOptions; use std::sync::Mutex; use std::ops::Deref; -use slog::{Logger, Drain, Level, LevelFilter, Duplicate, Discard}; +use slog::{Discard, Drain, Duplicate, Level, LevelFilter, Logger}; use slog_term; use slog_async; @@ -53,7 +53,7 @@ lazy_static! { if !config.log_to_stdout || !was_init { terminal_drain = slog_async::Async::new(Discard{}).build().fuse(); } - + let mut file_drain_final = slog_async::Async::new(Discard{}).build().fuse(); if config.log_to_file && was_init { @@ -93,12 +93,11 @@ pub fn init_logger(config: Option) { /// Initializes the logger for unit and integration tests pub fn init_test_logger() { - let mut was_init_ref = WAS_INIT.lock().unwrap(); + let mut was_init_ref = WAS_INIT.lock().unwrap(); if *was_init_ref.deref() { return; } - let mut config_ref = LOGGING_CONFIG.lock().unwrap(); - *config_ref = LoggingConfig::default(); - *was_init_ref = true; + let mut config_ref = LOGGING_CONFIG.lock().unwrap(); + *config_ref = LoggingConfig::default(); + *was_init_ref = true; } - diff --git a/wallet/src/checker.rs b/wallet/src/checker.rs index b17a131e9..eac4253c5 100644 --- a/wallet/src/checker.rs +++ b/wallet/src/checker.rs @@ -34,37 +34,34 @@ fn refresh_output(out: &mut OutputData, api_out: &api::Output) { match out.status { OutputStatus::Unconfirmed => { out.status = OutputStatus::Unspent; - }, + } _ => (), } } -// Transitions a local wallet output (based on it not being in the node utxo set) - +// Transitions a local wallet output (based on it not being in the node utxo +// set) - // Unspent -> Spent // Locked -> Spent fn mark_spent_output(out: &mut OutputData) { match out.status { - OutputStatus::Unspent | OutputStatus::Locked => { - out.status = OutputStatus::Spent - }, + OutputStatus::Unspent | OutputStatus::Locked => out.status = OutputStatus::Spent, _ => (), } } /// Builds a single api query to retrieve the latest output data from the node. /// So we can refresh the local wallet outputs. -pub fn refresh_outputs( - config: &WalletConfig, - keychain: &Keychain, -) -> Result<(), Error> { +pub fn refresh_outputs(config: &WalletConfig, keychain: &Keychain) -> Result<(), Error> { debug!(LOGGER, "Refreshing wallet outputs"); let mut wallet_outputs: HashMap = HashMap::new(); let mut commits: Vec = vec![]; // build a local map of wallet outputs by commits - // and a list of outputs we wantot query the node for + // and a list of outputs we wantot query the node for let _ = WalletData::read_wallet(&config.data_file_dir, |wallet_data| { - for out in wallet_data.outputs + for out in wallet_data + .outputs .values() .filter(|out| out.root_key_id == keychain.root_key_id()) .filter(|out| out.status != OutputStatus::Spent) @@ -77,7 +74,7 @@ pub fn refresh_outputs( }); // build the necessary query params - - // ?id=xxx&id=yyy&id=zzz + // ?id=xxx&id=yyy&id=zzz let query_params: Vec = commits .iter() .map(|commit| { @@ -88,7 +85,7 @@ pub fn refresh_outputs( let query_string = query_params.join("&"); let url = format!( - "{}/v2/chain/utxos?{}", + "{}/v1/chain/utxos?{}", config.check_node_api_http_addr, query_string, ); @@ -96,32 +93,28 @@ pub fn refresh_outputs( // build a map of api outputs by commit so we can look them up efficiently let mut api_outputs: HashMap = HashMap::new(); match api::client::get::>(url.as_str()) { - Ok(outputs) => { - for out in outputs { - api_outputs.insert(out.commit, out); - } + Ok(outputs) => for out in outputs { + api_outputs.insert(out.commit, out); }, - Err(_) => {}, + Err(_) => {} }; // now for each commit, find the output in the wallet and - // the corresponding api output (if it exists) - // and refresh it in-place in the wallet. - // Note: minimizing the time we spend holding the wallet lock. - WalletData::with_wallet(&config.data_file_dir, |wallet_data| { - for commit in commits { - let id = wallet_outputs.get(&commit).unwrap(); - if let Entry::Occupied(mut output) = wallet_data.outputs.entry(id.to_hex()) { - match api_outputs.get(&commit) { - Some(api_output) => refresh_output(&mut output.get_mut(), api_output), - None => mark_spent_output(&mut output.get_mut()), - }; - } + // the corresponding api output (if it exists) + // and refresh it in-place in the wallet. + // Note: minimizing the time we spend holding the wallet lock. + WalletData::with_wallet(&config.data_file_dir, |wallet_data| for commit in commits { + let id = wallet_outputs.get(&commit).unwrap(); + if let Entry::Occupied(mut output) = wallet_data.outputs.entry(id.to_hex()) { + match api_outputs.get(&commit) { + Some(api_output) => refresh_output(&mut output.get_mut(), api_output), + None => mark_spent_output(&mut output.get_mut()), + }; } }) } pub fn get_tip_from_node(config: &WalletConfig) -> Result { - let url = format!("{}/v2/chain", config.check_node_api_http_addr); + let url = format!("{}/v1/chain", config.check_node_api_http_addr); api::client::get::(url.as_str()).map_err(|e| Error::Node(e)) } diff --git a/wallet/src/client.rs b/wallet/src/client.rs index e0c92db78..d32e25f18 100644 --- a/wallet/src/client.rs +++ b/wallet/src/client.rs @@ -33,7 +33,10 @@ pub fn create_coinbase(url: &str, block_fees: &BlockFees) -> Result Result(f: F) -> Result - where F: (FnMut() -> Result) +where + F: FnMut() -> Result, { let mut core = reactor::Core::new()?; - let retry_strategy = FibonacciBackoff::from_millis(100) - .max_delay(time::Duration::from_secs(10)); + let retry_strategy = + FibonacciBackoff::from_millis(100).max_delay(time::Duration::from_secs(10)); let retry_future = Retry::spawn(core.handle(), retry_strategy, f); let res = core.run(retry_future).unwrap(); Ok(res) @@ -63,8 +67,8 @@ fn single_create_coinbase(url: &str, block_fees: &BlockFees) -> Result Result { - let (out, kern, block_fees) = receive_coinbase( - &self.config, - &self.keychain, - block_fees, - ).map_err(|e| { - api::Error::Internal(format!("Error building coinbase: {:?}", e)) - })?; + let (out, kern, block_fees) = receive_coinbase(&self.config, &self.keychain, block_fees) + .map_err(|e| { + api::Error::Internal(format!("Error building coinbase: {:?}", e)) + })?; let out_bin = ser::ser_vec(&out).map_err(|e| { api::Error::Internal(format!("Error serializing output: {:?}", e)) @@ -50,13 +47,9 @@ impl CoinbaseHandler { })?; let key_id_bin = match block_fees.key_id { - Some(key_id) => { - ser::ser_vec(&key_id).map_err(|e| { - api::Error::Internal( - format!("Error serializing kernel: {:?}", e), - ) - })? - } + Some(key_id) => ser::ser_vec(&key_id).map_err(|e| { + api::Error::Internal(format!("Error serializing kernel: {:?}", e)) + })?, None => vec![], }; @@ -68,7 +61,8 @@ impl CoinbaseHandler { } } -// TODO - error handling - what to return if we fail to get the wallet lock for some reason... +// TODO - error handling - what to return if we fail to get the wallet lock for +// some reason... impl Handler for CoinbaseHandler { fn handle(&self, req: &mut Request) -> IronResult { let struct_body = req.get::>(); diff --git a/wallet/src/info.rs b/wallet/src/info.rs index 78a914956..c4a9e05c8 100644 --- a/wallet/src/info.rs +++ b/wallet/src/info.rs @@ -22,17 +22,14 @@ pub fn show_info(config: &WalletConfig, keychain: &Keychain) { // just read the wallet here, no need for a write lock let _ = WalletData::read_wallet(&config.data_file_dir, |wallet_data| { - // get the current height via the api - // if we cannot get the current height use the max height known to the wallet + // if we cannot get the current height use the max height known to the wallet let current_height = match checker::get_tip_from_node(config) { Ok(tip) => tip.height, - Err(_) => { - match wallet_data.outputs.values().map(|out| out.height).max() { - Some(height) => height, - None => 0, - } - } + Err(_) => match wallet_data.outputs.values().map(|out| out.height).max() { + Some(height) => height, + None => 0, + }, }; println!("Outputs - "); diff --git a/wallet/src/lib.rs b/wallet/src/lib.rs index 6a9a1e2e4..05f74f4ce 100644 --- a/wallet/src/lib.rs +++ b/wallet/src/lib.rs @@ -14,24 +14,24 @@ //! Library module for the main wallet functionalities provided by Grin. -extern crate byteorder; extern crate blake2_rfc as blake2; -#[macro_use] -extern crate slog; +extern crate byteorder; extern crate rand; extern crate serde; #[macro_use] extern crate serde_derive; extern crate serde_json; +#[macro_use] +extern crate slog; extern crate bodyparser; extern crate futures; -extern crate tokio_core; -extern crate tokio_retry; extern crate hyper; extern crate iron; #[macro_use] extern crate router; +extern crate tokio_core; +extern crate tokio_retry; extern crate grin_api as api; extern crate grin_core as core; @@ -48,6 +48,6 @@ pub mod client; pub mod server; pub use info::show_info; -pub use receiver::{WalletReceiver, receive_json_tx}; -pub use sender::{issue_send_tx, issue_burn_tx}; +pub use receiver::{receive_json_tx, WalletReceiver}; +pub use sender::{issue_burn_tx, issue_send_tx}; pub use types::{BlockFees, CbData, Error, WalletConfig, WalletReceiveRequest, WalletSeed}; diff --git a/wallet/src/receiver.rs b/wallet/src/receiver.rs index bb6a33de0..9600c99da 100644 --- a/wallet/src/receiver.rs +++ b/wallet/src/receiver.rs @@ -15,45 +15,18 @@ //! Provides the JSON/HTTP API for wallets to receive payments. Because //! receiving money in MimbleWimble requires an interactive exchange, a //! wallet server that's running at all time is required in many cases. -//! -//! The API looks like this: -//! -//! POST /v1/wallet/receive -//! > { -//! > "amount": 10, -//! > "blind_sum": "a12b7f...", -//! > "tx": "f083de...", -//! > } -//! -//! < { -//! < "tx": "f083de...", -//! < "status": "ok" -//! < } -//! -//! POST /v1/wallet/finalize -//! > { -//! > "tx": "f083de...", -//! > } -//! -//! POST /v1/wallet/receive_coinbase -//! > { -//! > "amount": 1, -//! > } -//! -//! < { -//! < "output": "8a90bc...", -//! < "kernel": "f083de...", -//! < } -//! -//! Note that while at this point the finalize call is completely unecessary, a -//! double-exchange will be required as soon as we support Schnorr signatures. -//! So we may as well have it in place already. + +use std::io::Read; use core::consensus::reward; -use core::core::{Block, Transaction, TxKernel, Output, build}; +use core::core::{build, Block, Output, Transaction, TxKernel}; use core::ser; -use api::{self, ApiEndpoint, Operation, ApiResult}; +use api; +use iron::prelude::*; +use iron::Handler; +use iron::status; use keychain::{BlindingFactor, Identifier, Keychain}; +use serde_json; use types::*; use util; use util::LOGGER; @@ -77,8 +50,8 @@ pub fn receive_json_tx( let tx_hex = util::to_hex(ser::ser_vec(&final_tx).unwrap()); let url = format!("{}/v1/pool/push", config.check_node_api_http_addr.as_str()); - let _: () = api::client::post(url.as_str(), &TxWrapper { tx_hex: tx_hex }) - .map_err(|e| Error::Node(e))?; + let _: () = + api::client::post(url.as_str(), &TxWrapper { tx_hex: tx_hex }).map_err(|e| Error::Node(e))?; Ok(()) } @@ -90,46 +63,27 @@ pub struct WalletReceiver { pub config: WalletConfig, } -impl ApiEndpoint for WalletReceiver { - type ID = String; - type T = String; - type OP_IN = WalletReceiveRequest; - type OP_OUT = CbData; +impl Handler for WalletReceiver { + fn handle(&self, req: &mut Request) -> IronResult { + let receive: WalletReceiveRequest = serde_json::from_reader(req.body.by_ref()) + .map_err(|e| IronError::new(e, status::BadRequest))?; - fn operations(&self) -> Vec { - vec![Operation::Custom("receive_json_tx".to_string())] - } + match receive { + WalletReceiveRequest::PartialTransaction(partial_tx_str) => { + debug!(LOGGER, "Receive with transaction {}", &partial_tx_str,); + receive_json_tx(&self.config, &self.keychain, &partial_tx_str) + .map_err(|e| { + api::Error::Internal( + format!("Error processing partial transaction: {:?}", e), + ) + }) + .unwrap(); - fn operation(&self, op: String, input: WalletReceiveRequest) -> ApiResult { - match op.as_str() { - "receive_json_tx" => { - match input { - WalletReceiveRequest::PartialTransaction(partial_tx_str) => { - debug!( - LOGGER, - "Operation {} with transaction {}", - op, - &partial_tx_str, - ); - receive_json_tx(&self.config, &self.keychain, &partial_tx_str) - .map_err(|e| { - api::Error::Internal( - format!("Error processing partial transaction: {:?}", e), - ) - }) - .unwrap(); - - // TODO: Return emptiness for now, should be a proper enum return type - Ok(CbData { - output: String::from(""), - kernel: String::from(""), - key_id: String::from(""), - }) - } - _ => Err(api::Error::Argument(format!("Incorrect request data: {}", op))), - } + Ok(Response::with(status::Ok)) } - _ => Err(api::Error::Argument(format!("Unknown operation: {}", op))), + _ => Ok(Response::with( + (status::BadRequest, format!("Incorrect request data.")), + )), } } } @@ -168,7 +122,7 @@ fn next_available_key( pub fn receive_coinbase( config: &WalletConfig, keychain: &Keychain, - block_fees: &BlockFees + block_fees: &BlockFees, ) -> Result<(Output, TxKernel, BlockFees), Error> { let root_key_id = keychain.root_key_id(); let key_id = block_fees.key_id(); @@ -208,11 +162,7 @@ pub fn receive_coinbase( debug!(LOGGER, "block_fees updated - {:?}", block_fees); - let (out, kern) = Block::reward_output( - &keychain, - &key_id, - block_fees.fees, - )?; + let (out, kern) = Block::reward_output(&keychain, &key_id, block_fees.fees)?; Ok((out, kern, block_fees)) } @@ -229,8 +179,8 @@ fn receive_transaction( let (key_id, derivation) = next_available_key(config, keychain)?; // double check the fee amount included in the partial tx - // we don't necessarily want to just trust the sender - // we could just overwrite the fee here (but we won't) due to the ecdsa sig + // we don't necessarily want to just trust the sender + // we could just overwrite the fee here (but we won't) due to the ecdsa sig let fee = tx_fee(partial.inputs.len(), partial.outputs.len() + 1, None); if fee != partial.fee { return Err(Error::FeeDispute { @@ -241,14 +191,18 @@ fn receive_transaction( let out_amount = amount - fee; - let (tx_final, _) = build::transaction(vec![ - build::initial_tx(partial), - build::with_excess(blinding), - build::output(out_amount, key_id.clone()), + let (tx_final, _) = build::transaction( + vec![ + build::initial_tx(partial), + build::with_excess(blinding), + build::output(out_amount, key_id.clone()), // build::with_fee(fee_amount), - ], keychain)?; + ], + keychain, + )?; - // make sure the resulting transaction is valid (could have been lied to on excess). + // make sure the resulting transaction is valid (could have been lied to on + // excess). tx_final.validate(&keychain.secp())?; // operate within a lock on wallet data diff --git a/wallet/src/sender.rs b/wallet/src/sender.rs index ba9b6345a..f73b1f6a8 100644 --- a/wallet/src/sender.rs +++ b/wallet/src/sender.rs @@ -14,9 +14,9 @@ use api; use checker; -use core::core::{Transaction, build}; +use core::core::{build, Transaction}; use core::ser; -use keychain::{BlindingFactor, Keychain, Identifier}; +use keychain::{BlindingFactor, Identifier, Keychain}; use receiver::TxWrapper; use types::*; use util::LOGGER; @@ -55,7 +55,7 @@ pub fn issue_send_tx( if dest == "stdout" { println!("{}", json_tx); } else if &dest[..4] == "http" { - let url = format!("{}/v1/receive/receive_json_tx", &dest); + let url = format!("{}/v1/receive/transaction", &dest); debug!(LOGGER, "Posting partial transaction to {}", url); let request = WalletReceiveRequest::PartialTransaction(json_tx); let _: CbData = api::client::post(url.as_str(), &request).expect(&format!( @@ -90,7 +90,7 @@ fn build_send_tx( let mut parts = inputs_and_change(&coins, config, keychain, key_id, amount)?; // This is more proof of concept than anything but here we set lock_height - // on tx being sent (based on current chain height via api). + // on tx being sent (based on current chain height via api). parts.push(build::with_lock_height(lock_height)); let (tx, blind) = build::transaction(parts, &keychain)?; @@ -130,8 +130,8 @@ pub fn issue_burn_tx( let tx_hex = util::to_hex(ser::ser_vec(&tx_burn).unwrap()); let url = format!("{}/v1/pool/push", config.check_node_api_http_addr.as_str()); - let _: () = api::client::post(url.as_str(), &TxWrapper { tx_hex: tx_hex }) - .map_err(|e| Error::Node(e))?; + let _: () = + api::client::post(url.as_str(), &TxWrapper { tx_hex: tx_hex }).map_err(|e| Error::Node(e))?; Ok(()) } @@ -165,15 +165,15 @@ fn inputs_and_change( } // sender is responsible for setting the fee on the partial tx - // recipient should double check the fee calculation and not blindly trust the - // sender + // recipient should double check the fee calculation and not blindly trust the + // sender let fee = tx_fee(coins.len(), 2, None); parts.push(build::with_fee(fee)); // if we are spending 10,000 coins to send 1,000 then our change will be 9,000 - // the fee will come out of the amount itself - // if the fee is 80 then the recipient will only receive 920 - // but our change will still be 9,000 + // the fee will come out of the amount itself + // if the fee is 80 then the recipient will only receive 920 + // but our change will still be 9,000 let change = total - amount; // build inputs using the appropriate derived key_ids @@ -200,7 +200,8 @@ fn inputs_and_change( is_coinbase: false, }); - // now lock the ouputs we're spending so we avoid accidental double spend attempt + // now lock the ouputs we're spending so we avoid accidental double spend + // attempt for coin in coins { wallet_data.lock_output(coin); } @@ -216,7 +217,7 @@ mod test { #[test] // demonstrate that input.commitment == referenced output.commitment - // based on the public key and amount begin spent + // based on the public key and amount begin spent fn output_commitment_equals_input_commitment_on_spend() { let keychain = Keychain::from_random_seed().unwrap(); let key_id1 = keychain.derive_key_id(1).unwrap(); diff --git a/wallet/src/server.rs b/wallet/src/server.rs index 8ae3fc457..7ff92ba23 100644 --- a/wallet/src/server.rs +++ b/wallet/src/server.rs @@ -27,28 +27,22 @@ pub fn start_rest_apis(wallet_config: WalletConfig, keychain: Keychain) { wallet_config.api_http_addr ); - let mut apis = ApiServer::new("/v1".to_string()); - - apis.register_endpoint( - "/receive".to_string(), - WalletReceiver { - config: wallet_config.clone(), - keychain: keychain.clone(), - }, - ); - + let receive_tx_handler = WalletReceiver { + config: wallet_config.clone(), + keychain: keychain.clone(), + }; let coinbase_handler = CoinbaseHandler { config: wallet_config.clone(), keychain: keychain.clone(), }; - // let tx_handler = TxHandler{}; let router = router!( + receive_tx: get "/receive/transaction" => receive_tx_handler, receive_coinbase: post "/receive/coinbase" => coinbase_handler, - // receive_tx: post "/receive/tx" => tx_handler, - ); - apis.register_handler("/v2", router); + ); + let mut apis = ApiServer::new("/v1".to_string()); + apis.register_handler(router); apis.start(wallet_config.api_http_addr).unwrap_or_else(|e| { error!(LOGGER, "Failed to start Grin wallet receiver: {}.", e); }); diff --git a/wallet/src/types.rs b/wallet/src/types.rs index b9c3c6ee7..57f5b1311 100644 --- a/wallet/src/types.rs +++ b/wallet/src/types.rs @@ -14,7 +14,7 @@ use blake2; use rand::{thread_rng, Rng}; -use std::{fmt, num, error}; +use std::{error, fmt, num}; use std::convert::From; use std::fs::{self, File, OpenOptions}; use std::io::{self, Read, Write}; @@ -32,7 +32,7 @@ use tokio_retry::strategy::FibonacciBackoff; use api; -use core::core::{Transaction, transaction}; +use core::core::{transaction, Transaction}; use core::ser; use keychain; use util; @@ -62,7 +62,7 @@ pub fn tx_fee(input_len: usize, output_len: usize, base_fee: Option) -> u64 #[derive(Debug)] pub enum Error { NotEnoughFunds(u64), - FeeDispute{sender_fee: u64, recipient_fee: u64}, + FeeDispute { sender_fee: u64, recipient_fee: u64 }, Keychain(keychain::Error), Transaction(transaction::Error), Secp(secp::Error), @@ -166,7 +166,7 @@ impl Default for WalletConfig { fn default() -> WalletConfig { WalletConfig { enable_wallet: false, - api_http_addr: "0.0.0.0:13416".to_string(), + api_http_addr: "0.0.0.0:13415".to_string(), check_node_api_http_addr: "http://127.0.0.1:13413".to_string(), data_file_dir: ".".to_string(), } @@ -226,8 +226,10 @@ impl OutputData { } /// How many confirmations has this output received? - /// If height == 0 then we are either Unconfirmed or the output was cut-through - /// so we do not actually know how many confirmations this output had (and never will). + /// If height == 0 then we are either Unconfirmed or the output was + /// cut-through + /// so we do not actually know how many confirmations this output had (and + /// never will). pub fn num_confirmations(&self, current_height: u64) -> u64 { if self.status == OutputStatus::Unconfirmed { 0 @@ -239,21 +241,16 @@ impl OutputData { } /// Check if output is eligible for spending based on state and height. - pub fn eligible_to_spend( - &self, - current_height: u64, - minimum_confirmations: u64 - ) -> bool { - if [ - OutputStatus::Spent, - OutputStatus::Locked, - ].contains(&self.status) { + pub fn eligible_to_spend(&self, current_height: u64, minimum_confirmations: u64) -> bool { + if [OutputStatus::Spent, OutputStatus::Locked].contains(&self.status) { return false; } else if self.status == OutputStatus::Unconfirmed && self.is_coinbase { return false; } else if self.lock_height > current_height { return false; - } else if self.status == OutputStatus::Unspent && self.height + minimum_confirmations <= current_height { + } else if self.status == OutputStatus::Unspent + && self.height + minimum_confirmations <= current_height + { return true; } else if self.status == OutputStatus::Unconfirmed && minimum_confirmations == 0 { return true; @@ -306,11 +303,7 @@ impl WalletSeed { SEED_FILE, ); - debug!( - LOGGER, - "Generating wallet seed file at: {}", - seed_file_path, - ); + debug!(LOGGER, "Generating wallet seed file at: {}", seed_file_path,); if Path::new(seed_file_path).exists() { panic!("wallet seed file already exists"); @@ -333,11 +326,7 @@ impl WalletSeed { SEED_FILE, ); - debug!( - LOGGER, - "Using wallet seed file at: {}", - seed_file_path, - ); + debug!(LOGGER, "Using wallet seed file at: {}", seed_file_path,); if Path::new(seed_file_path).exists() { let mut file = File::open(seed_file_path)?; @@ -369,10 +358,11 @@ pub struct WalletData { } impl WalletData { - - /// Allows for reading wallet data (without needing to acquire the write lock). + /// Allows for reading wallet data (without needing to acquire the write + /// lock). pub fn read_wallet(data_file_dir: &str, f: F) -> Result - where F: FnOnce(&WalletData) -> T + where + F: FnOnce(&WalletData) -> T, { // open the wallet readonly and do what needs to be done with it let data_file_path = &format!("{}{}{}", data_file_dir, MAIN_SEPARATOR, DAT_FILE); @@ -388,7 +378,8 @@ impl WalletData { /// across operating systems, this just creates a lock file with a "should /// not exist" option. pub fn with_wallet(data_file_dir: &str, f: F) -> Result - where F: FnOnce(&mut WalletData) -> T + where + F: FnOnce(&mut WalletData) -> T, { // create directory if it doesn't exist fs::create_dir_all(data_file_dir).unwrap_or_else(|why| { @@ -415,7 +406,7 @@ impl WalletData { let retry_result = core.run(retry_future); match retry_result { - Ok(_) => {}, + Ok(_) => {} Err(_) => { error!( LOGGER, @@ -448,31 +439,33 @@ impl WalletData { WalletData::read(data_file_path) } else { // just create a new instance, it will get written afterward - Ok(WalletData { outputs: HashMap::new() }) + Ok(WalletData { + outputs: HashMap::new(), + }) } } /// Read the wallet data from disk. fn read(data_file_path: &str) -> Result { - let data_file = - File::open(data_file_path) - .map_err(|e| Error::WalletData(format!("Could not open {}: {}", data_file_path, e)))?; - serde_json::from_reader(data_file) - .map_err(|e| Error::WalletData(format!("Error reading {}: {}", data_file_path, e))) + let data_file = File::open(data_file_path).map_err(|e| { + Error::WalletData(format!("Could not open {}: {}", data_file_path, e)) + })?; + serde_json::from_reader(data_file).map_err(|e| { + Error::WalletData(format!("Error reading {}: {}", data_file_path, e)) + }) } /// Write the wallet data to disk. fn write(&self, data_file_path: &str) -> Result<(), Error> { - let mut data_file = - File::create(data_file_path) - .map_err(|e| { - Error::WalletData(format!("Could not create {}: {}", data_file_path, e)) - })?; - let res_json = serde_json::to_vec_pretty(self) - .map_err(|e| Error::WalletData(format!("Error serializing wallet data: {}", e)))?; - data_file - .write_all(res_json.as_slice()) - .map_err(|e| Error::WalletData(format!("Error writing {}: {}", data_file_path, e))) + let mut data_file = File::create(data_file_path).map_err(|e| { + Error::WalletData(format!("Could not create {}: {}", data_file_path, e)) + })?; + let res_json = serde_json::to_vec_pretty(self).map_err(|e| { + Error::WalletData(format!("Error serializing wallet data: {}", e)) + })?; + data_file.write_all(res_json.as_slice()).map_err(|e| { + Error::WalletData(format!("Error writing {}: {}", data_file_path, e)) + }) } /// Append a new output data to the wallet data. @@ -503,7 +496,6 @@ impl WalletData { current_height: u64, minimum_confirmations: u64, ) -> Vec { - self.outputs .values() .filter(|out| { @@ -537,10 +529,11 @@ struct JSONPartialTx { /// Encodes the information for a partial transaction (not yet completed by the /// receiver) into JSON. -pub fn partial_tx_to_json(receive_amount: u64, - blind_sum: keychain::BlindingFactor, - tx: Transaction) - -> String { +pub fn partial_tx_to_json( + receive_amount: u64, + blind_sum: keychain::BlindingFactor, + tx: Transaction, +) -> String { let partial_tx = JSONPartialTx { amount: receive_amount, blind_sum: util::to_hex(blind_sum.secret_key().as_ref().to_vec()), @@ -551,22 +544,22 @@ pub fn partial_tx_to_json(receive_amount: u64, /// Reads a partial transaction encoded as JSON into the amount, sum of blinding /// factors and the transaction itself. -pub fn partial_tx_from_json(keychain: &keychain::Keychain, - json_str: &str) - -> Result<(u64, keychain::BlindingFactor, Transaction), Error> { +pub fn partial_tx_from_json( + keychain: &keychain::Keychain, + json_str: &str, +) -> Result<(u64, keychain::BlindingFactor, Transaction), Error> { let partial_tx: JSONPartialTx = serde_json::from_str(json_str)?; let blind_bin = util::from_hex(partial_tx.blind_sum)?; // TODO - turn some data into a blinding factor here somehow - // let blinding = SecretKey::from_slice(&secp, &blind_bin[..])?; + // let blinding = SecretKey::from_slice(&secp, &blind_bin[..])?; let blinding = keychain::BlindingFactor::from_slice(keychain.secp(), &blind_bin[..])?; let tx_bin = util::from_hex(partial_tx.tx)?; - let tx = ser::deserialize(&mut &tx_bin[..]) - .map_err(|_| { - Error::Format("Could not deserialize transaction, invalid format.".to_string()) - })?; + let tx = ser::deserialize(&mut &tx_bin[..]).map_err(|_| { + Error::Format("Could not deserialize transaction, invalid format.".to_string()) + })?; Ok((partial_tx.amount, blinding, tx)) }