From 7addf838aefc217ceb80fbc4bdda584190f851de Mon Sep 17 00:00:00 2001 From: lalanza808 Date: Sun, 29 Mar 2020 01:46:09 -0700 Subject: [PATCH] adding first wave of code --- Cargo.toml | 17 +++++++++ README.md | 12 ++++++ src/data_types.rs | 97 +++++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 60 +++++++++++++++++++++++++++++ 4 files changed, 186 insertions(+) create mode 100644 Cargo.toml create mode 100644 README.md create mode 100644 src/data_types.rs create mode 100644 src/main.rs diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..62126b8 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "monero-blockchain-explorer" +version = "0.1.0" +authors = ["lalanza808 "] +edition = "2018" +description = "" + +# https://doc.rust-lang.org/cargo/reference/manifest.html + + +[dependencies] +rocket = "0.4.4" +rocket_contrib = "0.4.4" +serde = "1.0" +serde_json = "1.0" +serde_derive = "1.0" +reqwest = { version = "0.10.4", features = ["blocking", "json"] } diff --git a/README.md b/README.md new file mode 100644 index 0000000..65955da --- /dev/null +++ b/README.md @@ -0,0 +1,12 @@ +# Monero Block Explorer + +Building a very simple HTTP service to help learn Rust and get more familiar with the ecosystem. + +## Running + +``` +git clone https://github.com/lalanza808/monero-blockchain-explorer +cd monero-blockchain-explorer +rustup override set nightly +cargo run +``` diff --git a/src/data_types.rs b/src/data_types.rs new file mode 100644 index 0000000..94c93e7 --- /dev/null +++ b/src/data_types.rs @@ -0,0 +1,97 @@ +#[derive(Serialize, Deserialize)] +pub struct RPCPayload { + pub jsonrpc: String, + pub id: String, + pub method: String +} + +impl Default for RPCPayload { + fn default() -> RPCPayload { + RPCPayload { + jsonrpc: "2.0".to_string(), + id: "0".to_string(), + method: "get_info".to_string() + } + } +} + +#[derive(Serialize, Deserialize)] +pub struct GetInfo { + pub jsonrpc: String, + pub id: String, + pub result: GetInfoResult +} + +#[derive(Serialize, Deserialize)] +pub struct GetInfoResult { + pub alt_blocks_count: u32, + pub block_size_limit: u32, + pub block_size_median: u32, + pub block_weight_limit: u32, + pub block_weight_median: u64, + pub bootstrap_daemon_address: String, + pub credits: u32, + pub cumulative_difficulty: u64, + pub cumulative_difficulty_top64: u32, + pub database_size: u64, + pub difficulty: u64, + pub difficulty_top64: u32, + pub free_space: u64, + pub grey_peerlist_size: u32, + pub height: u32, + pub height_without_bootstrap: u32, + pub incoming_connections_count: u32, + pub mainnet: bool, + pub nettype: String, + pub offline: bool, + pub outgoing_connections_count: u32, + pub rpc_connections_count: u32, + pub stagenet: bool, + pub start_time: u32, + pub status: String, + pub target: u32, + pub target_height: u32, + pub testnet: bool, + pub top_block_hash: String, + pub top_hash: String, + pub tx_count: u32, + pub tx_pool_size: u32, + pub untrusted: bool, + pub update_available: bool, + pub version: String, + pub was_bootstrap_ever_used: bool, + pub white_peerlist_size: u32, + pub wide_cumulative_difficulty: String, + pub wide_difficulty: String +} + +#[derive(Serialize, Deserialize)] +pub struct BlockByHeaderHash { + pub id: String, + pub jsonrpc: String, + pub result: BlockByHeaderHashResult +} + +#[derive(Serialize, Deserialize)] +pub struct BlockByHeaderHashResult { + pub status: String, + pub untrusted: bool, + pub block_header: BlockHeader +} + +#[derive(Serialize, Deserialize)] +pub struct BlockHeader { + pub block_size: u32, + pub depth: u32, + pub difficulty: u64, + pub hash: String, + pub height: u32, + pub major_version: u8, + pub minor_version: u8, + pub nonce: u32, + pub num_txes: u32, + pub orphan_status: bool, + pub prev_hash: String, + pub reward: u64, + pub timestamp: u64 +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..b1fb673 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,60 @@ +#![feature(proc_macro_hygiene, decl_macro)] +#[macro_use] extern crate rocket; +#[macro_use] extern crate rocket_contrib; +#[macro_use] extern crate serde_derive; +extern crate reqwest; +mod data_types; +use rocket_contrib::json::{Json, JsonValue}; +use std::env; +use data_types::*; + + + +fn issue_rpc(method: &str) -> reqwest::blocking::RequestBuilder { + let uri = env::var("DAEMON_URI").unwrap(); + let http_client = reqwest::blocking::Client::new(); + let post_data = RPCPayload { + method: method.to_string(), + ..Default::default() + }; + return http_client.post(&uri).json(&post_data); +} + +#[catch(404)] +fn not_found() -> JsonValue { + json!({ + "status": "error", + "reason": "Resource was not found." + }) +} + +#[get("/transaction/")] +fn get_transaction(hash: String) -> Json { + let res: BlockByHeaderHash = issue_rpc(&"get_block_header_by_hash") + .send() + .unwrap().json().unwrap(); + Json(res.result.block_header) +} + +#[get("/info")] +fn get_daemon_info() -> Json { + let res: GetInfo = issue_rpc(&"get_info") + .send() + .unwrap().json().unwrap(); + Json(res.result) +} + +fn main() { + let env_url = env::var("DAEMON_URI"); + match env_url { + Ok(_) => { + rocket::ignite() + .mount("/", routes![ + get_daemon_info, get_transaction + ]) + .register(catchers![not_found]) + .launch(); + }, + Err(_) => panic!("Environment variable `DAEMON_URI` not provided.") + } +}