use super::utils::w;
use crate::chain;
use crate::rest::*;
use crate::router::{Handler, ResponseFuture};
use crate::types::*;
use crate::util;
use crate::util::secp::pedersen::Commitment;
use crate::web::*;
use failure::ResultExt;
use hyper::{Body, Request, StatusCode};
use std::sync::Weak;
pub struct TxHashSetHandler {
pub chain: Weak<chain::Chain>,
}
impl TxHashSetHandler {
fn get_roots(&self) -> Result<TxHashSet, Error> {
let chain = w(&self.chain)?;
let res = TxHashSet::from_head(&chain).context(ErrorKind::Internal(
"failed to read roots from txhashset".to_owned(),
))?;
Ok(res)
}
fn get_last_n_output(&self, distance: u64) -> Result<Vec<TxHashSetNode>, Error> {
let chain = w(&self.chain)?;
Ok(TxHashSetNode::get_last_n_output(&chain, distance))
}
fn get_last_n_rangeproof(&self, distance: u64) -> Result<Vec<TxHashSetNode>, Error> {
let chain = w(&self.chain)?;
Ok(TxHashSetNode::get_last_n_rangeproof(&chain, distance))
}
fn get_last_n_kernel(&self, distance: u64) -> Result<Vec<TxHashSetNode>, Error> {
let chain = w(&self.chain)?;
Ok(TxHashSetNode::get_last_n_kernel(&chain, distance))
}
fn outputs(
&self,
start_index: u64,
end_index: Option<u64>,
mut max: u64,
) -> Result<OutputListing, Error> {
if max > 10_000 {
max = 10_000;
}
let chain = w(&self.chain)?;
let outputs = chain
.unspent_outputs_by_pmmr_index(start_index, max, end_index)
.context(ErrorKind::NotFound)?;
let out = OutputListing {
last_retrieved_index: outputs.0,
highest_index: outputs.1,
outputs: outputs
.2
.iter()
.map(|x| OutputPrintable::from_output(x, &chain, None, true, true))
.collect::<Result<Vec<_>, _>>()
.context(ErrorKind::Internal("chain error".to_owned()))?,
};
Ok(out)
}
pub fn block_height_range_to_pmmr_indices(
&self,
start_block_height: u64,
end_block_height: Option<u64>,
) -> Result<OutputListing, Error> {
let chain = w(&self.chain)?;
let range = chain
.block_height_range_to_pmmr_indices(start_block_height, end_block_height)
.context(ErrorKind::NotFound)?;
let out = OutputListing {
last_retrieved_index: range.0,
highest_index: range.1,
outputs: vec![],
};
Ok(out)
}
fn get_merkle_proof_for_output(&self, id: &str) -> Result<OutputPrintable, Error> {
let c = util::from_hex(id)
.map_err(|_| ErrorKind::Argument(format!("Not a valid commitment: {}", id)))?;
let commit = Commitment::from_vec(c);
let chain = w(&self.chain)?;
let output_pos = chain.get_output_pos(&commit).context(ErrorKind::NotFound)?;
let merkle_proof = chain::Chain::get_merkle_proof_for_pos(&chain, commit)
.map_err(|_| ErrorKind::NotFound)?;
Ok(OutputPrintable {
output_type: OutputType::Coinbase,
commit: Commitment::from_vec(vec![]),
spent: false,
proof: None,
proof_hash: "".to_string(),
block_height: None,
merkle_proof: Some(merkle_proof),
mmr_index: output_pos,
})
}
}
impl Handler for TxHashSetHandler {
fn get(&self, req: Request<Body>) -> ResponseFuture {
let params = QueryParams::from(req.uri().query());
let last_n = parse_param_no_err!(params, "n", 10);
let start_index = parse_param_no_err!(params, "start_index", 1);
let end_index = match parse_param_no_err!(params, "end_index", 0) {
0 => None,
i => Some(i),
};
let max = parse_param_no_err!(params, "max", 100);
let id = parse_param_no_err!(params, "id", "".to_owned());
let start_height = parse_param_no_err!(params, "start_height", 1);
let end_height = match parse_param_no_err!(params, "end_height", 0) {
0 => None,
h => Some(h),
};
match right_path_element!(req) {
"roots" => result_to_response(self.get_roots()),
"lastoutputs" => result_to_response(self.get_last_n_output(last_n)),
"lastrangeproofs" => result_to_response(self.get_last_n_rangeproof(last_n)),
"lastkernels" => result_to_response(self.get_last_n_kernel(last_n)),
"outputs" => result_to_response(self.outputs(start_index, end_index, max)),
"heightstopmmr" => result_to_response(
self.block_height_range_to_pmmr_indices(start_height, end_height),
),
"merkleproof" => result_to_response(self.get_merkle_proof_for_output(&id)),
_ => response(StatusCode::BAD_REQUEST, ""),
}
}
}