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 < 95 { } else if sl == 64 {
// "this looks like a tx or block hash" // Equal to 64 characters is probably a hash; block or tx.
return Redirect::found(uri!(index)); // For this we attempt to query for a block with
} else if sl == 95 { // given hash. If we don't receive a valid/expected
match first_byte { // response then we attempt to query for a transaction hash.
"9" => { // If neither works then redirect to error response.
println!("This looks like a testnet address"); let block_hash_params = RPCParams {
return Redirect::found(uri!(index)); hash: Some(value.to_string()),
}, ..Default::default()
"A" => { };
println!("This looks like a testnet subaddress"); let check_valid_block_hash: Result<GetBlock, Error> = issue_rpc(
return Redirect::found(uri!(index)); &"get_block", Some(block_hash_params)
}, ).send().unwrap().json();
"5" => {
println!("This looks like a stagenet address"); match check_valid_block_hash {
return Redirect::found(uri!(index)); Ok(_) => return Redirect::found(uri!(get_block_by_hash: value.as_str())),
}, Err(_) => {
"7" => { let tx_hash_params: JsonValue = json!({"txs_hashes": [&value.as_str()]});
println!("This looks like a stagenet subaddress"); let check_valid_tx_hash: Result<GetTransactions, Error> = issue_raw_rpc(
return Redirect::found(uri!(index)); &"get_transactions", tx_hash_params
}, ).send().unwrap().json();
"4" => {
println!("This looks like a mainnet address"); match check_valid_tx_hash {
return Redirect::found(uri!(index)); Ok(_) => return Redirect::found(uri!(get_transaction_by_hash: value.as_str())),
}, Err(_) => return Redirect::found(uri!(error))
"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,78 +1,71 @@
<!DOCTYPE html> {% extends "base" %}
<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="title">
<h1>Monero Block Explorer</h1>
</div>
<div class="search">
<h2>Search</h2>
<form action="/search" method="get">
<input type="text" name="value" placeholder="Enter a transaction hash, block hash, or block height.">
<input type="submit" value="Search">
</form>
</div>
<div class="server-info">
<h2>Server Info</h2>
</div>
<div class="network-stats">
<h2>Network Stats</h2>
</div>
<div class="tx-pool">
<h2>Transaction Pool</h2>
</div>
<div class="">
<h2>Top Block</h2>
</div>
<div class="">
<h2>Previous Block</h2>
</div>
<h1>get_info</h1> {% block content %}
<p>alt_blocks_count: {{ alt_blocks_count }}</p> <div class="title">
<p>block_size_limit: {{ block_size_limit }}</p> <h1>Monero Block Explorer</h1>
<p>block_size_median: {{ block_size_median }}</p> </div>
<p>block_weight_limit: {{ block_weight_limit }}</p> <div class="search">
<p>block_weight_median: {{ block_weight_median }}</p> <h2>Search</h2>
<p>bootstrap_daemon_address: {{ bootstrap_daemon_address }}</p> <form action="/search" method="get">
<p>credits: {{ credits }}</p> <input type="text" name="value" placeholder="Enter a transaction hash, block hash, or block height.">
<p>cumulative_difficulty: {{ cumulative_difficulty }}</p> <input type="submit" value="Search">
<p>cumulative_difficulty_top64: {{ cumulative_difficulty_top64 }}</p> </form>
<p>database_size: {{ database_size }}</p> </div>
<p>difficulty: {{ difficulty }}</p> <div class="server-info">
<p>difficulty_top64: {{ difficulty_top64 }}</p> <h2>Server Info</h2>
<p>free_space: {{ free_space }}</p> </div>
<p>grey_peerlist_size: {{ grey_peerlist_size }}</p> <div class="network-stats">
<p>height: {{ height }}</p> <h2>Network Stats</h2>
<p>height_without_bootstrap: {{ height_without_bootstrap }}</p> </div>
<p>incoming_connections_count: {{ incoming_connections_count }}</p> <div class="tx-pool">
<p>mainnet: {{ mainnet }}</p> <h2>Transaction Pool</h2>
<p>nettype: {{ nettype }}</p> </div>
<p>offline: {{ offline }}</p> <div class="">
<p>outgoing_connections_count: {{ outgoing_connections_count }}</p> <h2>Top Block</h2>
<p>rpc_connections_count: {{ rpc_connections_count }}</p> </div>
<p>stagenet: {{ stagenet }}</p> <div class="">
<p>start_time: {{ start_time }}</p> <h2>Previous Block</h2>
<p>status: {{ status }}</p> </div>
<p>target: {{ target }}</p>
<p>target_height: {{ target_height }}</p>
<p>testnet: {{ testnet }}</p>
<p>top_block_hash: {{ top_block_hash }}</p>
<p>top_hash: {{ top_hash }}</p>
<p>tx_count: {{ tx_count }}</p>
<p>tx_pool_size: {{ tx_pool_size }}</p>
<p>untrusted: {{ untrusted }}</p>
<p>update_available: {{ update_available }}</p>
<p>version: {{ version }}</p>
<p>was_bootstrap_ever_used: {{ was_bootstrap_ever_used }}</p>
<p>white_peerlist_size: {{ white_peerlist_size }}</p>
<p>wide_cumulative_difficulty: {{ wide_cumulative_difficulty }}</p>
<p>wide_difficulty: {{ wide_difficulty }}</p>
</body> <h1>get_info</h1>
</html> <p>alt_blocks_count: {{ alt_blocks_count }}</p>
<p>block_size_limit: {{ block_size_limit }}</p>
<p>block_size_median: {{ block_size_median }}</p>
<p>block_weight_limit: {{ block_weight_limit }}</p>
<p>block_weight_median: {{ block_weight_median }}</p>
<p>bootstrap_daemon_address: {{ bootstrap_daemon_address }}</p>
<p>credits: {{ credits }}</p>
<p>cumulative_difficulty: {{ cumulative_difficulty }}</p>
<p>cumulative_difficulty_top64: {{ cumulative_difficulty_top64 }}</p>
<p>database_size: {{ database_size }}</p>
<p>difficulty: {{ difficulty }}</p>
<p>difficulty_top64: {{ difficulty_top64 }}</p>
<p>free_space: {{ free_space }}</p>
<p>grey_peerlist_size: {{ grey_peerlist_size }}</p>
<p>height: {{ height }}</p>
<p>height_without_bootstrap: {{ height_without_bootstrap }}</p>
<p>incoming_connections_count: {{ incoming_connections_count }}</p>
<p>mainnet: {{ mainnet }}</p>
<p>nettype: {{ nettype }}</p>
<p>offline: {{ offline }}</p>
<p>outgoing_connections_count: {{ outgoing_connections_count }}</p>
<p>rpc_connections_count: {{ rpc_connections_count }}</p>
<p>stagenet: {{ stagenet }}</p>
<p>start_time: {{ start_time }}</p>
<p>status: {{ status }}</p>
<p>target: {{ target }}</p>
<p>target_height: {{ target_height }}</p>
<p>testnet: {{ testnet }}</p>
<p>top_block_hash: {{ top_block_hash }}</p>
<p>top_hash: {{ top_hash }}</p>
<p>tx_count: {{ tx_count }}</p>
<p>tx_pool_size: {{ tx_pool_size }}</p>
<p>untrusted: {{ untrusted }}</p>
<p>update_available: {{ update_available }}</p>
<p>version: {{ version }}</p>
<p>was_bootstrap_ever_used: {{ was_bootstrap_ever_used }}</p>
<p>white_peerlist_size: {{ white_peerlist_size }}</p>
<p>wide_cumulative_difficulty: {{ wide_cumulative_difficulty }}</p>
<p>wide_difficulty: {{ wide_difficulty }}</p>
{% endblock content %}

Loading…
Cancel
Save