extending templates, fixing search/routes/structs

master
lalanza808 5 years ago
parent 58c93f8cba
commit 917ba7baa2

@ -1,4 +1,4 @@
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Debug)]
pub struct RPCPayload { pub struct RPCPayload {
pub jsonrpc: String, pub jsonrpc: String,
pub id: String, pub id: String,
@ -17,7 +17,7 @@ impl Default for RPCPayload {
} }
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Debug)]
pub struct RPCParams { pub struct RPCParams {
pub hash: Option<String>, pub hash: Option<String>,
pub txs_hashes: Option<Vec<String>>, pub txs_hashes: Option<Vec<String>>,
@ -84,21 +84,21 @@ pub struct GetInfoResult {
pub wide_difficulty: String pub wide_difficulty: String
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Debug)]
pub struct BlockByHeaderHash { pub struct BlockByHeaderHash {
pub id: String, pub id: String,
pub jsonrpc: String, pub jsonrpc: String,
pub result: BlockByHeaderHashResult pub result: BlockByHeaderHashResult
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Debug)]
pub struct BlockByHeaderHashResult { pub struct BlockByHeaderHashResult {
pub status: String, pub status: String,
pub untrusted: bool, pub untrusted: bool,
pub block_header: BlockHeader pub block_header: BlockHeader
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Debug)]
pub struct BlockHeader { pub struct BlockHeader {
pub block_size: u32, pub block_size: u32,
pub depth: u32, pub depth: u32,
@ -116,12 +116,12 @@ pub struct BlockHeader {
pub timestamp: i64 pub timestamp: i64
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Debug)]
pub struct GetTransactions { pub struct GetTransactions {
pub txs: Vec<GetTransactionsTxs> pub txs: Vec<GetTransactionsTxs>
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Debug)]
pub struct GetTransactionsTxs { pub struct GetTransactionsTxs {
pub block_height: u32, pub block_height: u32,
pub block_timestamp: i64, pub block_timestamp: i64,
@ -130,16 +130,15 @@ pub struct GetTransactionsTxs {
pub output_indices: Vec<u32>, pub output_indices: Vec<u32>,
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Debug)]
pub struct GetBlock { pub struct GetBlock {
pub id: String, pub id: String,
pub jsonrpc: String, pub jsonrpc: String,
pub result: GetBlockResult pub result: GetBlockResult
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Debug)]
pub struct GetBlockResult { pub struct GetBlockResult {
pub blob: String,
pub block_header: BlockHeader, pub block_header: BlockHeader,
pub credits: u8, pub credits: u8,
pub miner_tx_hash: String, pub miner_tx_hash: String,

@ -4,12 +4,14 @@
#[macro_use] extern crate serde_derive; #[macro_use] extern crate serde_derive;
extern crate reqwest; extern crate reqwest;
mod data_types; mod data_types;
use rocket::http::RawStr; use rocket::http::RawStr;
use rocket::response::Redirect; use rocket::response::Redirect;
use rocket_contrib::json::{Json, JsonValue}; use rocket_contrib::json::{Json, JsonValue};
use rocket_contrib::templates::Template; use rocket_contrib::templates::Template;
use rocket_contrib::serve::StaticFiles; use rocket_contrib::serve::StaticFiles;
use reqwest::blocking::{RequestBuilder, Client}; use reqwest::blocking::{RequestBuilder, Client};
use reqwest::Error;
use std::env; use std::env;
use data_types::*; use data_types::*;
@ -38,30 +40,29 @@ fn issue_raw_rpc(method: &str, params: JsonValue) -> RequestBuilder {
} }
#[get("/block/hash/<block_hash>")] #[get("/block/hash/<block_hash>")]
fn get_block_header_by_block_hash(block_hash: String) -> Json<BlockHeader> { fn get_block_by_hash(block_hash: String) -> Json<GetBlockResult> {
let params = RPCParams { let params = RPCParams {
hash: Some(block_hash), hash: Some(block_hash),
..Default::default() ..Default::default()
}; };
let res: BlockByHeaderHash = issue_rpc(&"get_block_header_by_hash", Some(params)) let res: GetBlock = issue_rpc(&"get_block", Some(params))
.send().unwrap().json().unwrap(); .send().unwrap().json().unwrap();
Json(res.result.block_header) Json(res.result)
} }
#[get("/block/height/<block_height>")] #[get("/block/height/<block_height>")]
fn get_block_by_height(block_height: String) -> String { fn get_block_by_height(block_height: String) -> Json<GetBlockResult> {
let params = RPCParams { let params = RPCParams {
height: Some(block_height), height: Some(block_height),
..Default::default() ..Default::default()
}; };
let res: GetBlock = issue_rpc(&"get_block", Some(params)) let res: GetBlock = issue_rpc(&"get_block", Some(params))
.send().unwrap().json().unwrap(); .send().unwrap().json().unwrap();
// Json(res.result.block_header) Json(res.result)
serde_json::to_string(&res).unwrap()
} }
#[get("/transaction/<tx_hash>")] #[get("/transaction/<tx_hash>")]
fn get_block_header_by_transaction_hash(tx_hash: String) -> Json<GetTransactions> { fn get_transaction_by_hash(tx_hash: String) -> Json<GetTransactions> {
let params: JsonValue = json!({"txs_hashes": [&tx_hash]}); let params: JsonValue = json!({"txs_hashes": [&tx_hash]});
let res: GetTransactions = issue_raw_rpc(&"get_transactions", params) let res: GetTransactions = issue_raw_rpc(&"get_transactions", params)
.send().unwrap().json().unwrap(); .send().unwrap().json().unwrap();
@ -70,68 +71,53 @@ fn get_block_header_by_transaction_hash(tx_hash: String) -> Json<GetTransactions
#[get("/search?<value>")] #[get("/search?<value>")]
fn search(value: &RawStr) -> Redirect { fn search(value: &RawStr) -> Redirect {
// This search implementation is not ideal but it works.
// We basically check the length of the search value and
// attempt to redirect to the appropriate route.
let sl: usize = value.len(); let sl: usize = value.len();
let first_byte = value.get(0..1).unwrap(); println!("{}", sl);
println!("Search value: {}", value);
println!("First byte: {}", first_byte);
if sl < 10 { if sl < 10 {
// Less than 10 characters is probably a block height. If it can
// be parsed as valid u32 then redirect to `get_block_by_height`,
// otherwise redirect to the error response.
match value.parse::<u32>() { match value.parse::<u32>() {
Ok(v) => { Ok(_) => return Redirect::found(uri!(get_block_by_height: value.as_str())),
println!("Found: {}", v); Err(_) => return Redirect::found(uri!(error))
// "this looks like a block height"
return Redirect::found(uri!(get_block_by_height: value.as_str()));
},
Err(e) => {
println!("Error: {}", e);
// "this is an invalid search query"
return Redirect::found(uri!(index));
} }
} else if sl == 64 {
// Equal to 64 characters is probably a hash; block or tx.
// For this we attempt to query for a block with
// given hash. If we don't receive a valid/expected
// response then we attempt to query for a transaction hash.
// If neither works then redirect to error response.
let block_hash_params = RPCParams {
hash: Some(value.to_string()),
..Default::default()
};
let check_valid_block_hash: Result<GetBlock, Error> = issue_rpc(
&"get_block", Some(block_hash_params)
).send().unwrap().json();
match check_valid_block_hash {
Ok(_) => return Redirect::found(uri!(get_block_by_hash: value.as_str())),
Err(_) => {
let tx_hash_params: JsonValue = json!({"txs_hashes": [&value.as_str()]});
let check_valid_tx_hash: Result<GetTransactions, Error> = issue_raw_rpc(
&"get_transactions", tx_hash_params
).send().unwrap().json();
match check_valid_tx_hash {
Ok(_) => return Redirect::found(uri!(get_transaction_by_hash: value.as_str())),
Err(_) => return Redirect::found(uri!(error))
} }
} else if sl < 95 {
// "this looks like a tx or block hash"
return Redirect::found(uri!(index));
} else if sl == 95 {
match first_byte {
"9" => {
println!("This looks like a testnet address");
return Redirect::found(uri!(index));
},
"A" => {
println!("This looks like a testnet subaddress");
return Redirect::found(uri!(index));
},
"5" => {
println!("This looks like a stagenet address");
return Redirect::found(uri!(index));
},
"7" => {
println!("This looks like a stagenet subaddress");
return Redirect::found(uri!(index));
},
"4" => {
println!("This looks like a mainnet address");
return Redirect::found(uri!(index));
},
"8" => {
println!("This looks like a mainnet subaddress");
return Redirect::found(uri!(index));
},
_ => {
println!("Not sure what this is");
return Redirect::found(uri!(index));
} }
} }
} else if sl == 105 {
// "this looks like an integrated address"
return Redirect::found(uri!(index));
} else { } else {
// "no idea what this is" // Anything else hasn't been implemented yet
return Redirect::found(uri!(index)); // so redirect to error response.
return Redirect::found(uri!(error));
}; };
// println!("No if stmt matched");
// return Redirect::found(uri!(index));
} }
#[get("/")] #[get("/")]
@ -141,6 +127,14 @@ fn index() -> Template {
Template::render("index", &res.result) Template::render("index", &res.result)
} }
#[get("/error", )]
fn error() -> JsonValue {
json!({
"status": "error",
"reason": "There was an error while searching the provided values."
})
}
#[catch(404)] #[catch(404)]
fn not_found() -> JsonValue { fn not_found() -> JsonValue {
json!({ json!({
@ -158,8 +152,9 @@ fn main() {
index, index,
search, search,
get_block_by_height, get_block_by_height,
get_block_header_by_block_hash, get_block_by_hash,
get_block_header_by_transaction_hash, get_transaction_by_hash,
error
]) ])
.mount("/static", StaticFiles::from("./static")) .mount("/static", StaticFiles::from("./static"))
.register(catchers![not_found]) .register(catchers![not_found])

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Monero Block Explorer</title>
<link rel="stylesheet" href="/static/css/main.css"/>
<link rel="stylesheet" href="/static/css/normalize.css"/>
</head>
<body>
<div class="container">
{% block content %}
{% endblock content %}
</div>
</body>
</html>

@ -1,37 +1,31 @@
<!DOCTYPE html> {% extends "base" %}
<html>
<head> {% block content %}
<meta charset="UTF-8"> <div class="title">
<title>Monero Block Explorer</title>
<link rel="stylesheet" href="/static/css/main.css"/>
<link rel="stylesheet" href="/static/css/normalize.css"/>
</head>
<body>
<div class="title">
<h1>Monero Block Explorer</h1> <h1>Monero Block Explorer</h1>
</div> </div>
<div class="search"> <div class="search">
<h2>Search</h2> <h2>Search</h2>
<form action="/search" method="get"> <form action="/search" method="get">
<input type="text" name="value" placeholder="Enter a transaction hash, block hash, or block height."> <input type="text" name="value" placeholder="Enter a transaction hash, block hash, or block height.">
<input type="submit" value="Search"> <input type="submit" value="Search">
</form> </form>
</div> </div>
<div class="server-info"> <div class="server-info">
<h2>Server Info</h2> <h2>Server Info</h2>
</div> </div>
<div class="network-stats"> <div class="network-stats">
<h2>Network Stats</h2> <h2>Network Stats</h2>
</div> </div>
<div class="tx-pool"> <div class="tx-pool">
<h2>Transaction Pool</h2> <h2>Transaction Pool</h2>
</div> </div>
<div class=""> <div class="">
<h2>Top Block</h2> <h2>Top Block</h2>
</div> </div>
<div class=""> <div class="">
<h2>Previous Block</h2> <h2>Previous Block</h2>
</div> </div>
<h1>get_info</h1> <h1>get_info</h1>
<p>alt_blocks_count: {{ alt_blocks_count }}</p> <p>alt_blocks_count: {{ alt_blocks_count }}</p>
@ -74,5 +68,4 @@
<p>wide_cumulative_difficulty: {{ wide_cumulative_difficulty }}</p> <p>wide_cumulative_difficulty: {{ wide_cumulative_difficulty }}</p>
<p>wide_difficulty: {{ wide_difficulty }}</p> <p>wide_difficulty: {{ wide_difficulty }}</p>
</body> {% endblock content %}
</html>

Loading…
Cancel
Save