From 9ceebf3b9e548e33eeadcd7a2b448b549a228188 Mon Sep 17 00:00:00 2001 From: aglkm <39521015+aglkm@users.noreply.github.com> Date: Sun, 19 May 2024 17:20:48 +0300 Subject: [PATCH 01/10] Bump version --- Cargo.lock | 2 +- Cargo.toml | 2 +- templates/base.html.tera | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b3c3156..979161b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -730,7 +730,7 @@ dependencies = [ [[package]] name = "grin-explorer" -version = "0.1.2" +version = "0.1.3" dependencies = [ "chrono", "colored", diff --git a/Cargo.toml b/Cargo.toml index 3a21405..96efd10 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "grin-explorer" -version = "0.1.2" +version = "0.1.3" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/templates/base.html.tera b/templates/base.html.tera index 8c1c0f0..701ee1d 100644 --- a/templates/base.html.tera +++ b/templates/base.html.tera @@ -212,7 +212,7 @@
From 33426c1a5eaeffce0cfec317b697f3265bc522b8 Mon Sep 17 00:00:00 2001 From: aglkm <39521015+aglkm@users.noreply.github.com> Date: Sun, 19 May 2024 17:37:54 +0300 Subject: [PATCH 02/10] Hardening search input --- src/main.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/main.rs b/src/main.rs index feb0e9a..a907f89 100644 --- a/src/main.rs +++ b/src/main.rs @@ -138,11 +138,12 @@ async fn kernel(kernel: &str) -> Either { // Handling search request. #[post("/search", data="")] fn search(input: &str) -> Either { - // Trim 'search=' from the request data - let input = &input[7..].to_lowercase(); - - //Check if input is valid - if input.is_empty() == false { + //Check input length + if input.len() > "search=".len() { + // Trim 'search=' from the request data + let input = &input[7..].to_lowercase(); + + // Check for valid chars if input.chars().all(|x| (x >= 'a' && x <= 'f') || (x >= '0' && x <= '9')) == true { // Block number From 38ee6500eb361c80c81fcb5b83ccf154f4aa12bc Mon Sep 17 00:00:00 2001 From: aglkm <39521015+aglkm@users.noreply.github.com> Date: Sun, 19 May 2024 20:04:13 +0300 Subject: [PATCH 03/10] Introduced coingecko api switch, preparations for testnet explorer --- Explorer.toml | 16 +- src/data.rs | 5 + src/main.rs | 15 +- src/requests.rs | 94 +++++----- templates/index.html.tera | 348 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 435 insertions(+), 43 deletions(-) diff --git a/Explorer.toml b/Explorer.toml index 95a7c76..cd1dd2d 100644 --- a/Explorer.toml +++ b/Explorer.toml @@ -16,6 +16,20 @@ api_secret_path = "~/.grin/main/.api_secret" # Foreign API secret path. foreign_api_secret_path = "~/.grin/main/.foreign_api_secret" -# Path to Grin directory +# Path to Grin directory. grin_dir = "~/.grin" +# CoinGecko API on/off switch. +coingecko_api = "on" + + +# Testnet config +# ip = "127.0.0.1" +# port = "13413" +# proto = "http" +# user = "grin" +# api_secret_path = "~/.grin/test/.api_secret" +# foreign_api_secret_path = "~/.grin/test/.foreign_api_secret" +# grin_dir = "~/.grin" +# coingecko_api = "off" + diff --git a/src/data.rs b/src/data.rs index a8a462c..caca842 100644 --- a/src/data.rs +++ b/src/data.rs @@ -35,6 +35,8 @@ pub struct Dashboard { // mempool pub txns: String, pub stem: String, + // coingecko api + pub cg_api: String, } impl Dashboard { @@ -64,6 +66,7 @@ impl Dashboard { breakeven_cost: String::new(), txns: String::new(), stem: String::new(), + cg_api: String::new(), } } } @@ -141,6 +144,7 @@ pub struct ExplorerConfig { pub grin_dir: String, pub api_secret: String, pub foreign_api_secret: String, + pub coingecko_api: String, } impl ExplorerConfig { @@ -155,6 +159,7 @@ impl ExplorerConfig { grin_dir: String::new(), api_secret: String::new(), foreign_api_secret: String::new(), + coingecko_api: String::new(), } } } diff --git a/src/main.rs b/src/main.rs index a907f89..fa93a9d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -25,9 +25,10 @@ fn index(dashboard: &State
+{# We have different UI to display if CoinGecko API is disabled by user #}
+
+{% if cg_api == "on" %}
+{# CoinGecko API is enabled #}
+
@@ -456,6 +461,349 @@
+{% else %}
+{# CoinGecko API is disabled #}
+
+
+
+
+
+ MARKET
+
+
+ Yearly Inflation Rate %
+
+
+
+ Coin Supply
+
+
+
+ Soft Total Supply
+
+
+
+
+
+
+
+
+
+ MINING
+
+
+ Hashrate KG/s
+
+
+
+ Difficulty
+
+
+
+ Block Reward ツ 60
+
+
+
+
+
+
+
+
+
+ BLOCKCHAIN
+
+
+ Size
+
+
+
+ Block Height
+
+
+
+ Time Since Last Block
+
+
+
+
+
+ TRANSACTIONS & FEES
+
+
+ 1H Period
+
+
+
+ 24H Period
+
+
+
+
+
+
+
+
+
+ MEMPOOL
+
+
+ Transactions
+
+
+
+ Stem
+
+
+
+
+
+ CONNECTIONS
+
+
+ Inbound
+
+
+
+ Outbound
+
+
+
+
+
+ NODE
+
+
+ Version {{ node_ver }}
+
+
+
+ Protocol {{ proto_ver }}
+
+
+
+ Sync Status
+
+
+
+
+
+
+
+
+
+
+
+ MARKET
+
+
+ Yearly Inflation Rate %
+
+
+
+ Coin Supply
+
+
+
+ Soft Total Supply
+
+
+
+
+
+
+
+
+
+
+
+ BLOCKCHAIN
+
+
+
+ Size
+
+
+
+ Block Height
+
+
+
+ Time Since Last Block
+
+
+
+
+
+ MINING
+
+
+ Hashrate KG/s
+
+
+
+ Difficulty
+
+
+
+ Block Reward ツ 60
+
+
+
+
+
+ TRANSACTIONS & FEES
+
+
+ 1H Period
+
+
+
+ 24H Period
+
+
+
+
+
+
+
+
+ MEMPOOL
+
+
+ Transactions
+
+
+
+ Stem
+
+
+
+
+
+ CONNECTIONS
+
+
+ Inbound
+
+
+
+ Outbound
+
+
+
+
+
+ NODE
+
+
+ Version {{ node_ver }}
+
+
+
+ Protocol {{ proto_ver }}
+
+
+
+ Sync Status
+
+
+
+
+
+
+
+
+
+
+
+
+
+{% endif %}
+
{% endblock content%}
From 04fde44594b22b25a7b169f39476321953905a5e Mon Sep 17 00:00:00 2001
From: aglkm <39521015+aglkm@users.noreply.github.com>
Date: Mon, 20 May 2024 02:33:19 +0300
Subject: [PATCH 04/10] More preparations for testnet explorer
---
Rocket.toml | 4 ++++
src/main.rs | 2 +-
src/requests.rs | 6 +++---
templates/error.html.tera | 6 +-----
4 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/Rocket.toml b/Rocket.toml
index 97e9661..6077f33 100644
--- a/Rocket.toml
+++ b/Rocket.toml
@@ -2,3 +2,7 @@
address = "127.0.0.1"
log_level = "critical"
+# Uncomment and change default port number (8000) if another instance of the explorer is needed to run.
+# E.g. Mainnet (8000) and Testnet (8001) instances.
+# port = 8000
+
diff --git a/src/main.rs b/src/main.rs
index fa93a9d..c7227db 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -155,7 +155,7 @@ fn search(input: &str) -> Either {
} else if input.len() == 64 {
return Either::Right(Redirect::to(uri!(block_header_by_hash(input))));
- // Kernel hash
+ // Kernel
} else if input.len() == 66 {
return Either::Right(Redirect::to(uri!(kernel(input))));
}
diff --git a/src/requests.rs b/src/requests.rs
index d3ac911..f1b4839 100644
--- a/src/requests.rs
+++ b/src/requests.rs
@@ -93,6 +93,9 @@ pub async fn get_status(dashboard: Arc
+
+
+
+
+
+
+
+
+>) -> Result<(), Error> {
data.proto_ver = resp["result"]["Ok"]["protocol_version"].to_string();
}
+ // Also set cg_api value
+ data.cg_api = CONFIG.coingecko_api.clone();
+
Ok(())
}
@@ -153,9 +156,6 @@ pub async fn get_market(dashboard: Arc>) -> Result<(), Error> {
let mut data = dashboard.lock().unwrap();
- // Save the setting into Dashboard structure for later use
- data.cg_api = CONFIG.coingecko_api.clone();
-
if data.height.is_empty() == false {
// Calculating coin supply
// Adding +1 as block index starts with 0
diff --git a/templates/error.html.tera b/templates/error.html.tera
index 15c7ec0..88b82f8 100644
--- a/templates/error.html.tera
+++ b/templates/error.html.tera
@@ -7,11 +7,7 @@
No results found.
- Explorer supports requests by block number, block hash or kernel.
- Examples:
- Block number - 2765726
- Block hash - 0000fc4d93e5717579b955ab840165d96603f009804a228be22da76f6f906a3c
- Kernel - 084caeb931b7e8cb73d6419ea74ea157a3cef19f6e9307108a8a808df58437a4ef
+ Explorer supports requests by block number, block hash or kernel.
From 50173f92215c8699541c35d735c9c0f573a52dac Mon Sep 17 00:00:00 2001
From: aglkm <39521015+aglkm@users.noreply.github.com>
Date: Mon, 20 May 2024 16:37:24 +0300
Subject: [PATCH 05/10] Generalize returned Error
---
Cargo.lock | 7 +++++++
Cargo.toml | 1 +
src/requests.rs | 39 ++++++++++++++++++++-------------------
src/worker.rs | 3 +--
4 files changed, 29 insertions(+), 21 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
index 979161b..911b7e4 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -41,6 +41,12 @@ dependencies = [
"libc",
]
+[[package]]
+name = "anyhow"
+version = "1.0.86"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da"
+
[[package]]
name = "arrayvec"
version = "0.7.4"
@@ -732,6 +738,7 @@ dependencies = [
name = "grin-explorer"
version = "0.1.3"
dependencies = [
+ "anyhow",
"chrono",
"colored",
"config",
diff --git a/Cargo.toml b/Cargo.toml
index 96efd10..164b703 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -19,6 +19,7 @@ config = "0.14.0"
lazy_static = "1.4.0"
shellexpand = "3.1.0"
either = "1.11.0"
+anyhow = "1.0.86"
[dependencies.reqwest]
version = "0.11.23"
diff --git a/src/requests.rs b/src/requests.rs
index f1b4839..4fe3375 100644
--- a/src/requests.rs
+++ b/src/requests.rs
@@ -53,7 +53,7 @@ lazy_static! {
// RPC requests to grin node.
-async fn call(method: &str, params: &str, rpc_type: &str) -> Result {
+async fn call(method: &str, params: &str, rpc_type: &str) -> Result {
let rpc_url;
let secret;
@@ -74,14 +74,14 @@ async fn call(method: &str, params: &str, rpc_type: &str) -> Result>) -> Result<(), Error> {
+pub async fn get_status(dashboard: Arc>) -> Result<(), anyhow::Error> {
let resp = call("get_status", "[]", "owner").await?;
let mut data = dashboard.lock().unwrap();
@@ -101,7 +101,7 @@ pub async fn get_status(dashboard: Arc>) -> Result<(), Error> {
// Collecting: txns, stem.
-pub async fn get_mempool(dashboard: Arc>) -> Result<(), Error> {
+pub async fn get_mempool(dashboard: Arc>) -> Result<(), anyhow::Error> {
let resp1 = call("get_pool_size", "[]", "foreign").await?;
let resp2 = call("get_stempool_size", "[]", "foreign").await?;
@@ -117,7 +117,8 @@ pub async fn get_mempool(dashboard: Arc>) -> Result<(), Error>
// Collecting: inbound, outbound.
-pub async fn get_connected_peers(dashboard: Arc>) -> Result<(), Error> {
+pub async fn get_connected_peers(dashboard: Arc>)
+ -> Result<(), anyhow::Error> {
let resp = call("get_connected_peers", "[]", "owner").await?;
let mut data = dashboard.lock().unwrap();
@@ -216,7 +217,7 @@ pub fn get_disk_usage(dashboard: Arc>) -> Result<(), Error> {
// Collecting: hashrate, difficulty, production cost, breakeven cost.
-pub async fn get_mining_stats(dashboard: Arc>) -> Result<(), Error> {
+pub async fn get_mining_stats(dashboard: Arc>) -> Result<(), anyhow::Error> {
let difficulty_window = 1440;
let height = get_current_height(dashboard.clone());
@@ -265,7 +266,7 @@ pub async fn get_mining_stats(dashboard: Arc>) -> Result<(), Er
// Collecting block data for recent blocks (block_list page).
pub async fn get_block_list_data(height: &String, block: &mut Block)
- -> Result<(), Error> {
+ -> Result<(), anyhow::Error> {
// Max block weight is 40000
// One unit of weight is 32 bytes
let kernel_weight = 3.0;
@@ -273,11 +274,11 @@ pub async fn get_block_list_data(height: &String, block: &mut Block)
let output_weight = 21.0;
if height.is_empty() == false {
- let params = &format!("[{}, null, null]", height)[..];
- let resp = call("get_block", params, "foreign").await.unwrap();
+ let params = &format!("[{}, null, null]", height)[..];
+ let resp = call("get_block", params, "foreign").await?;
if resp["result"]["Ok"].is_null() == false {
- block.height = resp["result"]["Ok"]["header"]["height"].to_string();
+ block.height = resp["result"]["Ok"]["header"]["height"].to_string();
let dt: DateTime = resp["result"]["Ok"]["header"]["timestamp"]
.as_str().unwrap().to_string().parse().unwrap();
@@ -324,7 +325,7 @@ pub async fn get_block_list_data(height: &String, block: &mut Block)
// Collecting block data.
pub async fn get_block_data(height: &str, block: &mut Block)
- -> Result<(), Error> {
+ -> Result<(), anyhow::Error> {
// Max block weight is 40000
// One unit of weight is 32 bytes
let kernel_weight = 3.0;
@@ -380,10 +381,10 @@ pub async fn get_block_data(height: &str, block: &mut Block)
// Get block height by hash.
pub async fn get_block_header(hash: &str, height: &mut String)
- -> Result<(), Error> {
+ -> Result<(), anyhow::Error> {
let params = &format!("[null, \"{}\", null]", hash)[..];
- let resp = call("get_header", params, "foreign").await.unwrap();
+ let resp = call("get_header", params, "foreign").await?;
if resp["result"]["Ok"].is_null() == false {
*height = resp["result"]["Ok"]["height"].to_string();
@@ -395,10 +396,10 @@ pub async fn get_block_header(hash: &str, height: &mut String)
// Get kernel.
pub async fn get_kernel(kernel: &str, height: &mut String)
- -> Result<(), Error> {
+ -> Result<(), anyhow::Error> {
let params = &format!("[\"{}\", null, null]", kernel)[..];
- let resp = call("get_kernel", params, "foreign").await.unwrap();
+ let resp = call("get_kernel", params, "foreign").await?;
if resp["result"]["Ok"].is_null() == false {
*height = resp["result"]["Ok"]["height"].to_string();
@@ -410,11 +411,11 @@ pub async fn get_kernel(kernel: &str, height: &mut String)
// Collecting block kernels for transactions stats.
pub async fn get_block_kernels(height: &String, blocks: &mut Vec)
- -> Result<(), Error> {
+ -> Result<(), anyhow::Error> {
if height.is_empty() == false {
let params = &format!("[{}, {}, 720, false]", height.parse::().unwrap() - 720,
height)[..];
- let resp = call("get_blocks", params, "foreign").await.unwrap();
+ let resp = call("get_blocks", params, "foreign").await?;
for resp_block in resp["result"]["Ok"]["blocks"].as_array().unwrap() {
let mut block = Block::new();
@@ -528,11 +529,11 @@ pub async fn get_recent_blocks(dashboard: Arc>,
// Collecting a specified list of blocks.
pub async fn get_block_list_by_height(height: &str, blocks: &mut Vec,
- latest_height: &mut u64) -> Result<(), Error> {
+ latest_height: &mut u64) -> Result<(), anyhow::Error> {
let mut i = 0;
let height = height.to_string();
- let resp = call("get_status", "[]", "owner").await.unwrap();
+ let resp = call("get_status", "[]", "owner").await?;
if resp != Value::Null {
*latest_height = resp["result"]["Ok"]["tip"]["height"].to_string().parse::().unwrap();
diff --git a/src/worker.rs b/src/worker.rs
index b75343f..4a4f17e 100644
--- a/src/worker.rs
+++ b/src/worker.rs
@@ -1,5 +1,4 @@
use std::sync::{Arc, Mutex};
-use reqwest::Error;
use crate::data::Dashboard;
use crate::data::Block;
@@ -10,7 +9,7 @@ use crate::requests;
// Tokio Runtime Worker.
// Collecting all the data.
pub async fn run(dash: Arc>, blocks: Arc>>,
- txns: Arc>) -> Result<(), Error> {
+ txns: Arc>) -> Result<(), anyhow::Error> {
let _ = requests::get_status(dash.clone()).await?;
let _ = requests::get_mempool(dash.clone()).await?;
let _ = requests::get_connected_peers(dash.clone()).await?;
From fca10e1a2c0d2ee8e6b3318f739f2e09090d0297 Mon Sep 17 00:00:00 2001
From: aglkm <39521015+aglkm@users.noreply.github.com>
Date: Mon, 20 May 2024 19:02:12 +0300
Subject: [PATCH 06/10] Adjust hashrate metrics for testnet
---
src/main.rs | 2 +-
src/requests.rs | 12 ++++++++++--
2 files changed, 11 insertions(+), 3 deletions(-)
diff --git a/src/main.rs b/src/main.rs
index c7227db..46159a8 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -314,7 +314,7 @@ fn disk_usage(dashboard: &State>>) -> String {
fn network_hashrate(dashboard: &State>>) -> String {
let data = dashboard.lock().unwrap();
- format!("{} KG/s", data.hashrate)
+ data.hashrate.clone()
}
diff --git a/src/requests.rs b/src/requests.rs
index 4fe3375..b885fa8 100644
--- a/src/requests.rs
+++ b/src/requests.rs
@@ -240,8 +240,16 @@ pub async fn get_mining_stats(dashboard: Arc>) -> Result<(), an
// https://forum.grin.mw/t/on-dual-pow-graph-rates-gps-and-difficulty/2144/52
// https://forum.grin.mw/t/difference-c31-and-c32-c33/7018/7
- let hashrate = (net_diff as f64) * 42.0 / 60.0 / 16384.0;
- data.hashrate = format!("{:.2}", hashrate / 1000.0);
+ let hashrate = (net_diff as f64) * 42.0 / 60.0 / 16384.0;
+
+ // KG/s
+ if hashrate > 1000.0 {
+ data.hashrate = format!("{:.2} KG/s", hashrate / 1000.0);
+ // G/s
+ } else {
+ data.hashrate = format!("{:.2} G/s", hashrate);
+ }
+
data.difficulty = net_diff.to_string();
if CONFIG.coingecko_api == "on" {
From b9b0045448abd192c3e8e6e91fe9797f19d83c6f Mon Sep 17 00:00:00 2001
From: aglkm <39521015+aglkm@users.noreply.github.com>
Date: Thu, 23 May 2024 17:41:03 +0300
Subject: [PATCH 07/10] API support
---
src/main.rs | 62 ++++++++++++++++++++++++++++++++++++++++++++++++-
src/requests.rs | 2 +-
2 files changed, 62 insertions(+), 2 deletions(-)
diff --git a/src/main.rs b/src/main.rs
index 46159a8..4682bb8 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -9,6 +9,7 @@ use colored::Colorize;
use rocket::tokio;
use rocket::response::Redirect;
use either::Either;
+use serde_json::Value;
mod worker;
mod requests;
@@ -168,6 +169,64 @@ fn search(input: &str) -> Either {
}
+// Owner API.
+#[post("/api/v2/owner", data="")]
+async fn api_owner(data: &str) -> String {
+ let result = serde_json::from_str(data);
+
+ let v: Value = match result {
+ Ok(value) => value,
+ Err(_err) => return "{\"error\":\"bad syntax\"}".to_string(),
+ };
+
+ let method = match v["method"].as_str() {
+ Some(value) => value,
+ _ => return "{\"error\":\"bad syntax\"}".to_string(),
+ };
+
+ // Whitelisted methods: get_connected_peer, get_peers, get_status.
+ if method == "get_connected_peers" || method == "get_peers" || method == "get_status" {
+ let resp = requests::call(method, v["params"].to_string().as_str(), "owner").await;
+
+ let result = match resp {
+ Ok(value) => value,
+ Err(_err) => return "{\"error\":\"rpc call failed\"}".to_string(),
+ };
+
+ return result.to_string();
+ }
+
+ "{\"error\":\"not allowed\"}".to_string()
+}
+
+
+// Foreign API.
+// All methods are whitelisted.
+#[post("/api/v2/foreign", data="")]
+async fn api_foreign(data: &str) -> String {
+ let result = serde_json::from_str(data);
+
+ let v: Value = match result {
+ Ok(value) => value,
+ Err(_err) => return "{\"error\":\"bad syntax\"}".to_string(),
+ };
+
+ let method = match v["method"].as_str() {
+ Some(value) => value,
+ _ => return "{\"error\":\"bad syntax\"}".to_string(),
+ };
+
+ let resp = requests::call(method, v["params"].to_string().as_str(), "foreign").await;
+
+ let result = match resp {
+ Ok(value) => value,
+ Err(_err) => return "{\"error\":\"rpc call failed\"}".to_string(),
+ };
+
+ result.to_string()
+}
+
+
// Start of HTMX routes.
#[get("/rpc/peers/inbound")]
fn peers_inbound(dashboard: &State>>) -> String {
@@ -560,7 +619,8 @@ async fn main() {
block_time, block_txns, block_inputs, block_outputs, block_fees,
block_weight, block_details_by_height, block_header_by_hash,
soft_supply, production_cost, reward_ratio, breakeven_cost,
- last_block_age, block_list_by_height, block_list_index, search, kernel])
+ last_block_age, block_list_by_height, block_list_index, search, kernel,
+ api_owner, api_foreign])
.mount("/static", FileServer::from("static"))
.attach(Template::fairing())
.launch()
diff --git a/src/requests.rs b/src/requests.rs
index b885fa8..dbcfef4 100644
--- a/src/requests.rs
+++ b/src/requests.rs
@@ -53,7 +53,7 @@ lazy_static! {
// RPC requests to grin node.
-async fn call(method: &str, params: &str, rpc_type: &str) -> Result {
+pub async fn call(method: &str, params: &str, rpc_type: &str) -> Result {
let rpc_url;
let secret;
From 3aecc6d557959931b2ea287220cd2dd0494f8228 Mon Sep 17 00:00:00 2001
From: aglkm <39521015+aglkm@users.noreply.github.com>
Date: Thu, 23 May 2024 18:32:05 +0300
Subject: [PATCH 08/10] Shorten api url
---
src/main.rs | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/src/main.rs b/src/main.rs
index 4682bb8..4298fd2 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -170,7 +170,7 @@ fn search(input: &str) -> Either {
// Owner API.
-#[post("/api/v2/owner", data="")]
+#[post("/v2/owner", data="")]
async fn api_owner(data: &str) -> String {
let result = serde_json::from_str(data);
@@ -184,6 +184,7 @@ async fn api_owner(data: &str) -> String {
_ => return "{\"error\":\"bad syntax\"}".to_string(),
};
+ println!("{}", method);
// Whitelisted methods: get_connected_peer, get_peers, get_status.
if method == "get_connected_peers" || method == "get_peers" || method == "get_status" {
let resp = requests::call(method, v["params"].to_string().as_str(), "owner").await;
@@ -202,7 +203,7 @@ async fn api_owner(data: &str) -> String {
// Foreign API.
// All methods are whitelisted.
-#[post("/api/v2/foreign", data="")]
+#[post("/v2/foreign", data="")]
async fn api_foreign(data: &str) -> String {
let result = serde_json::from_str(data);
@@ -216,6 +217,7 @@ async fn api_foreign(data: &str) -> String {
_ => return "{\"error\":\"bad syntax\"}".to_string(),
};
+ println!("{}", method);
let resp = requests::call(method, v["params"].to_string().as_str(), "foreign").await;
let result = match resp {
From 7aadd85e19f36a1aaffaa2d1c31c19ed064bd325 Mon Sep 17 00:00:00 2001
From: aglkm <39521015+aglkm@users.noreply.github.com>
Date: Thu, 23 May 2024 18:43:38 +0300
Subject: [PATCH 09/10] Remove debug prints
---
src/main.rs | 2 --
1 file changed, 2 deletions(-)
diff --git a/src/main.rs b/src/main.rs
index 4298fd2..26207b6 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -184,7 +184,6 @@ async fn api_owner(data: &str) -> String {
_ => return "{\"error\":\"bad syntax\"}".to_string(),
};
- println!("{}", method);
// Whitelisted methods: get_connected_peer, get_peers, get_status.
if method == "get_connected_peers" || method == "get_peers" || method == "get_status" {
let resp = requests::call(method, v["params"].to_string().as_str(), "owner").await;
@@ -217,7 +216,6 @@ async fn api_foreign(data: &str) -> String {
_ => return "{\"error\":\"bad syntax\"}".to_string(),
};
- println!("{}", method);
let resp = requests::call(method, v["params"].to_string().as_str(), "foreign").await;
let result = match resp {
From 2aaebee5f46b255fde2fdef16cce5eb69077ade2 Mon Sep 17 00:00:00 2001
From: aglkm <39521015+aglkm@users.noreply.github.com>
Date: Fri, 24 May 2024 15:14:16 +0300
Subject: [PATCH 10/10] Added kernel page, respect id field in api
---
src/data.rs | 23 +++++++++++++++++
src/main.rs | 30 ++++++++++++----------
src/requests.rs | 47 +++++++++++++++++++++-------------
templates/base.html.tera | 4 +--
templates/kernel.html.tera | 52 ++++++++++++++++++++++++++++++++++++++
5 files changed, 124 insertions(+), 32 deletions(-)
create mode 100644 templates/kernel.html.tera
diff --git a/src/data.rs b/src/data.rs
index caca842..d529320 100644
--- a/src/data.rs
+++ b/src/data.rs
@@ -111,6 +111,29 @@ impl Block {
}
+// Kernel data
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct Kernel {
+ pub height: String,
+ pub excess: String,
+ pub ker_type: String,
+ pub fee: String,
+ pub raw_data: String,
+}
+
+impl Kernel {
+ pub fn new() -> Kernel {
+ Kernel {
+ height: String::new(),
+ excess: String::new(),
+ ker_type: String::new(),
+ fee: String::new(),
+ raw_data: String::new(),
+ }
+ }
+}
+
+
// Transactions data
#[derive(Debug)]
pub struct Transactions {
diff --git a/src/main.rs b/src/main.rs
index 26207b6..3584b85 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -18,6 +18,7 @@ mod data;
use crate::data::Dashboard;
use crate::data::Block;
use crate::data::Transactions;
+use crate::data::Kernel;
// Rendering main (Dashboard) page.
@@ -119,21 +120,22 @@ async fn block_header_by_hash(hash: &str) -> Either {
// Rendering page for a specified kernel.
-#[get("/kernel/")]
-async fn kernel(kernel: &str) -> Either {
- let mut height = String::new();
+#[get("/kernel/")]
+async fn kernel(excess: &str) -> Template {
+ let mut kernel = Kernel::new();
- let _ = requests::get_kernel(&kernel, &mut height).await;
+ let _ = requests::get_kernel(&excess, &mut kernel).await;
- if kernel.is_empty() == false {
- if height.is_empty() == false {
- return Either::Right(Redirect::to(uri!(block_details_by_height(height.as_str()))));
- }
+ if kernel.height.is_empty() == false {
+ return Template::render("kernel", context! {
+ route: "kernel",
+ kernel,
+ })
}
- return Either::Left(Template::render("error", context! {
+ return Template::render("error", context! {
route: "error",
- }))
+ })
}
@@ -183,10 +185,10 @@ async fn api_owner(data: &str) -> String {
Some(value) => value,
_ => return "{\"error\":\"bad syntax\"}".to_string(),
};
-
+
// Whitelisted methods: get_connected_peer, get_peers, get_status.
if method == "get_connected_peers" || method == "get_peers" || method == "get_status" {
- let resp = requests::call(method, v["params"].to_string().as_str(), "owner").await;
+ let resp = requests::call(method, v["params"].to_string().as_str(), v["id"].to_string().as_str(), "owner").await;
let result = match resp {
Ok(value) => value,
@@ -216,7 +218,9 @@ async fn api_foreign(data: &str) -> String {
_ => return "{\"error\":\"bad syntax\"}".to_string(),
};
- let resp = requests::call(method, v["params"].to_string().as_str(), "foreign").await;
+ println!("{}", method);
+ println!("{}", data);
+ let resp = requests::call(method, v["params"].to_string().as_str(), v["id"].to_string().as_str(), "foreign").await;
let result = match resp {
Ok(value) => value,
diff --git a/src/requests.rs b/src/requests.rs
index dbcfef4..0fc6020 100644
--- a/src/requests.rs
+++ b/src/requests.rs
@@ -16,6 +16,7 @@ use crate::data::Dashboard;
use crate::data::Block;
use crate::data::Transactions;
use crate::data::ExplorerConfig;
+use crate::Kernel;
// Static explorer config structure
@@ -53,7 +54,7 @@ lazy_static! {
// RPC requests to grin node.
-pub async fn call(method: &str, params: &str, rpc_type: &str) -> Result {
+pub async fn call(method: &str, params: &str, id: &str, rpc_type: &str) -> Result {
let rpc_url;
let secret;
@@ -68,7 +69,7 @@ pub async fn call(method: &str, params: &str, rpc_type: &str) -> Result Result>) -> Result<(), anyhow::Error> {
- let resp = call("get_status", "[]", "owner").await?;
+ let resp = call("get_status", "[]", "1", "owner").await?;
let mut data = dashboard.lock().unwrap();
@@ -102,8 +103,8 @@ pub async fn get_status(dashboard: Arc>) -> Result<(), anyhow::
// Collecting: txns, stem.
pub async fn get_mempool(dashboard: Arc>) -> Result<(), anyhow::Error> {
- let resp1 = call("get_pool_size", "[]", "foreign").await?;
- let resp2 = call("get_stempool_size", "[]", "foreign").await?;
+ let resp1 = call("get_pool_size", "[]", "1", "foreign").await?;
+ let resp2 = call("get_stempool_size", "[]", "1", "foreign").await?;
let mut data = dashboard.lock().unwrap();
@@ -119,7 +120,7 @@ pub async fn get_mempool(dashboard: Arc>) -> Result<(), anyhow:
// Collecting: inbound, outbound.
pub async fn get_connected_peers(dashboard: Arc>)
-> Result<(), anyhow::Error> {
- let resp = call("get_connected_peers", "[]", "owner").await?;
+ let resp = call("get_connected_peers", "[]", "1", "owner").await?;
let mut data = dashboard.lock().unwrap();
@@ -225,8 +226,8 @@ pub async fn get_mining_stats(dashboard: Arc>) -> Result<(), an
let params1 = &format!("[{}, null, null]", height)[..];
let params2 = &format!("[{}, null, null]", height.parse::().unwrap()
- difficulty_window)[..];
- let resp1 = call("get_block", params1, "foreign").await?;
- let resp2 = call("get_block", params2, "foreign").await?;
+ let resp1 = call("get_block", params1, "1", "foreign").await?;
+ let resp2 = call("get_block", params2, "1", "foreign").await?;
let mut data = dashboard.lock().unwrap();
@@ -283,7 +284,7 @@ pub async fn get_block_list_data(height: &String, block: &mut Block)
if height.is_empty() == false {
let params = &format!("[{}, null, null]", height)[..];
- let resp = call("get_block", params, "foreign").await?;
+ let resp = call("get_block", params, "1", "foreign").await?;
if resp["result"]["Ok"].is_null() == false {
block.height = resp["result"]["Ok"]["header"]["height"].to_string();
@@ -343,7 +344,7 @@ pub async fn get_block_data(height: &str, block: &mut Block)
if height.is_empty() == false {
let params = &format!("[{}, null, null]", height)[..];
- let resp = call("get_block", params, "foreign").await?;
+ let resp = call("get_block", params, "1", "foreign").await?;
if resp["result"]["Ok"].is_null() == false {
block.hash = resp["result"]["Ok"]["header"]["hash"].as_str().unwrap().to_string();
@@ -392,7 +393,7 @@ pub async fn get_block_header(hash: &str, height: &mut String)
-> Result<(), anyhow::Error> {
let params = &format!("[null, \"{}\", null]", hash)[..];
- let resp = call("get_header", params, "foreign").await?;
+ let resp = call("get_header", params, "1", "foreign").await?;
if resp["result"]["Ok"].is_null() == false {
*height = resp["result"]["Ok"]["height"].to_string();
@@ -403,14 +404,26 @@ pub async fn get_block_header(hash: &str, height: &mut String)
// Get kernel.
-pub async fn get_kernel(kernel: &str, height: &mut String)
+pub async fn get_kernel(excess: &str, kernel: &mut Kernel)
-> Result<(), anyhow::Error> {
- let params = &format!("[\"{}\", null, null]", kernel)[..];
+ let params = &format!("[\"{}\", null, null]", excess)[..];
- let resp = call("get_kernel", params, "foreign").await?;
+ let resp = call("get_kernel", params, "1", "foreign").await?;
if resp["result"]["Ok"].is_null() == false {
- *height = resp["result"]["Ok"]["height"].to_string();
+ kernel.height = resp["result"]["Ok"]["height"].to_string();
+ kernel.excess = resp["result"]["Ok"]["tx_kernel"]["excess"].as_str().unwrap().to_string();
+ if resp["result"]["Ok"]["tx_kernel"]["features"]["Plain"].is_null() == false {
+ kernel.ker_type = "Plain".to_string();
+ kernel.fee = format!("ツ {}",
+ resp["result"]["Ok"]["tx_kernel"]["features"]["Plain"]["fee"]
+ .to_string().parse::().unwrap() / 1000000000.0);
+ } else {
+ kernel.ker_type = resp["result"]["Ok"]["tx_kernel"]["features"].as_str().unwrap().to_string();
+ kernel.fee = "ツ 0".to_string();
+ }
+
+ kernel.raw_data = serde_json::to_string_pretty(&resp).unwrap()
}
Ok(())
@@ -423,7 +436,7 @@ pub async fn get_block_kernels(height: &String, blocks: &mut Vec)
if height.is_empty() == false {
let params = &format!("[{}, {}, 720, false]", height.parse::().unwrap() - 720,
height)[..];
- let resp = call("get_blocks", params, "foreign").await?;
+ let resp = call("get_blocks", params, "1", "foreign").await?;
for resp_block in resp["result"]["Ok"]["blocks"].as_array().unwrap() {
let mut block = Block::new();
@@ -541,7 +554,7 @@ pub async fn get_block_list_by_height(height: &str, blocks: &mut Vec,
let mut i = 0;
let height = height.to_string();
- let resp = call("get_status", "[]", "owner").await?;
+ let resp = call("get_status", "[]", "1", "owner").await?;
if resp != Value::Null {
*latest_height = resp["result"]["Ok"]["tip"]["height"].to_string().parse::().unwrap();
diff --git a/templates/base.html.tera b/templates/base.html.tera
index 701ee1d..c9d1e2a 100644
--- a/templates/base.html.tera
+++ b/templates/base.html.tera
@@ -1,5 +1,5 @@
-
+
Grin Blockchain Explorer
@@ -78,7 +78,7 @@
{% block content %}{% endblock content %}
-