mirror of
https://github.com/transatoshi-mw/grin-explorer.git
synced 2025-10-21 21:43:40 +00:00
Added kernel page, respect id field in api
This commit is contained in:
23
src/data.rs
23
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
|
// Transactions data
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Transactions {
|
pub struct Transactions {
|
||||||
|
30
src/main.rs
30
src/main.rs
@@ -18,6 +18,7 @@ mod data;
|
|||||||
use crate::data::Dashboard;
|
use crate::data::Dashboard;
|
||||||
use crate::data::Block;
|
use crate::data::Block;
|
||||||
use crate::data::Transactions;
|
use crate::data::Transactions;
|
||||||
|
use crate::data::Kernel;
|
||||||
|
|
||||||
|
|
||||||
// Rendering main (Dashboard) page.
|
// Rendering main (Dashboard) page.
|
||||||
@@ -119,21 +120,22 @@ async fn block_header_by_hash(hash: &str) -> Either<Template, Redirect> {
|
|||||||
|
|
||||||
|
|
||||||
// Rendering page for a specified kernel.
|
// Rendering page for a specified kernel.
|
||||||
#[get("/kernel/<kernel>")]
|
#[get("/kernel/<excess>")]
|
||||||
async fn kernel(kernel: &str) -> Either<Template, Redirect> {
|
async fn kernel(excess: &str) -> Template {
|
||||||
let mut height = String::new();
|
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 kernel.height.is_empty() == false {
|
||||||
if height.is_empty() == false {
|
return Template::render("kernel", context! {
|
||||||
return Either::Right(Redirect::to(uri!(block_details_by_height(height.as_str()))));
|
route: "kernel",
|
||||||
}
|
kernel,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return Either::Left(Template::render("error", context! {
|
return Template::render("error", context! {
|
||||||
route: "error",
|
route: "error",
|
||||||
}))
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -183,10 +185,10 @@ async fn api_owner(data: &str) -> String {
|
|||||||
Some(value) => value,
|
Some(value) => value,
|
||||||
_ => return "{\"error\":\"bad syntax\"}".to_string(),
|
_ => return "{\"error\":\"bad syntax\"}".to_string(),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Whitelisted methods: get_connected_peer, get_peers, get_status.
|
// Whitelisted methods: get_connected_peer, get_peers, get_status.
|
||||||
if method == "get_connected_peers" || method == "get_peers" || method == "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 {
|
let result = match resp {
|
||||||
Ok(value) => value,
|
Ok(value) => value,
|
||||||
@@ -216,7 +218,9 @@ async fn api_foreign(data: &str) -> String {
|
|||||||
_ => return "{\"error\":\"bad syntax\"}".to_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 {
|
let result = match resp {
|
||||||
Ok(value) => value,
|
Ok(value) => value,
|
||||||
|
@@ -16,6 +16,7 @@ use crate::data::Dashboard;
|
|||||||
use crate::data::Block;
|
use crate::data::Block;
|
||||||
use crate::data::Transactions;
|
use crate::data::Transactions;
|
||||||
use crate::data::ExplorerConfig;
|
use crate::data::ExplorerConfig;
|
||||||
|
use crate::Kernel;
|
||||||
|
|
||||||
|
|
||||||
// Static explorer config structure
|
// Static explorer config structure
|
||||||
@@ -53,7 +54,7 @@ lazy_static! {
|
|||||||
|
|
||||||
|
|
||||||
// RPC requests to grin node.
|
// RPC requests to grin node.
|
||||||
pub async fn call(method: &str, params: &str, rpc_type: &str) -> Result<Value, anyhow::Error> {
|
pub async fn call(method: &str, params: &str, id: &str, rpc_type: &str) -> Result<Value, anyhow::Error> {
|
||||||
let rpc_url;
|
let rpc_url;
|
||||||
let secret;
|
let secret;
|
||||||
|
|
||||||
@@ -68,7 +69,7 @@ pub async fn call(method: &str, params: &str, rpc_type: &str) -> Result<Value, a
|
|||||||
|
|
||||||
let client = reqwest::Client::new();
|
let client = reqwest::Client::new();
|
||||||
let result = client.post(rpc_url)
|
let result = client.post(rpc_url)
|
||||||
.body(format!("{{\"method\": \"{}\", \"params\": {}, \"id\":1}}", method, params))
|
.body(format!("{{\"method\": \"{}\", \"params\": {}, \"id\": {}}}", method, params, id))
|
||||||
.basic_auth(CONFIG.user.clone(), Some(secret))
|
.basic_auth(CONFIG.user.clone(), Some(secret))
|
||||||
.header("content-type", "plain/text")
|
.header("content-type", "plain/text")
|
||||||
.send()
|
.send()
|
||||||
@@ -82,7 +83,7 @@ pub async fn call(method: &str, params: &str, rpc_type: &str) -> Result<Value, a
|
|||||||
|
|
||||||
// Collecting: height, sync, node_ver, proto_ver.
|
// Collecting: height, sync, node_ver, proto_ver.
|
||||||
pub async fn get_status(dashboard: Arc<Mutex<Dashboard>>) -> Result<(), anyhow::Error> {
|
pub async fn get_status(dashboard: Arc<Mutex<Dashboard>>) -> Result<(), anyhow::Error> {
|
||||||
let resp = call("get_status", "[]", "owner").await?;
|
let resp = call("get_status", "[]", "1", "owner").await?;
|
||||||
|
|
||||||
let mut data = dashboard.lock().unwrap();
|
let mut data = dashboard.lock().unwrap();
|
||||||
|
|
||||||
@@ -102,8 +103,8 @@ pub async fn get_status(dashboard: Arc<Mutex<Dashboard>>) -> Result<(), anyhow::
|
|||||||
|
|
||||||
// Collecting: txns, stem.
|
// Collecting: txns, stem.
|
||||||
pub async fn get_mempool(dashboard: Arc<Mutex<Dashboard>>) -> Result<(), anyhow::Error> {
|
pub async fn get_mempool(dashboard: Arc<Mutex<Dashboard>>) -> Result<(), anyhow::Error> {
|
||||||
let resp1 = call("get_pool_size", "[]", "foreign").await?;
|
let resp1 = call("get_pool_size", "[]", "1", "foreign").await?;
|
||||||
let resp2 = call("get_stempool_size", "[]", "foreign").await?;
|
let resp2 = call("get_stempool_size", "[]", "1", "foreign").await?;
|
||||||
|
|
||||||
let mut data = dashboard.lock().unwrap();
|
let mut data = dashboard.lock().unwrap();
|
||||||
|
|
||||||
@@ -119,7 +120,7 @@ pub async fn get_mempool(dashboard: Arc<Mutex<Dashboard>>) -> Result<(), anyhow:
|
|||||||
// Collecting: inbound, outbound.
|
// Collecting: inbound, outbound.
|
||||||
pub async fn get_connected_peers(dashboard: Arc<Mutex<Dashboard>>)
|
pub async fn get_connected_peers(dashboard: Arc<Mutex<Dashboard>>)
|
||||||
-> Result<(), anyhow::Error> {
|
-> 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();
|
let mut data = dashboard.lock().unwrap();
|
||||||
|
|
||||||
@@ -225,8 +226,8 @@ pub async fn get_mining_stats(dashboard: Arc<Mutex<Dashboard>>) -> Result<(), an
|
|||||||
let params1 = &format!("[{}, null, null]", height)[..];
|
let params1 = &format!("[{}, null, null]", height)[..];
|
||||||
let params2 = &format!("[{}, null, null]", height.parse::<u64>().unwrap()
|
let params2 = &format!("[{}, null, null]", height.parse::<u64>().unwrap()
|
||||||
- difficulty_window)[..];
|
- difficulty_window)[..];
|
||||||
let resp1 = call("get_block", params1, "foreign").await?;
|
let resp1 = call("get_block", params1, "1", "foreign").await?;
|
||||||
let resp2 = call("get_block", params2, "foreign").await?;
|
let resp2 = call("get_block", params2, "1", "foreign").await?;
|
||||||
|
|
||||||
let mut data = dashboard.lock().unwrap();
|
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 {
|
if height.is_empty() == false {
|
||||||
let params = &format!("[{}, null, null]", height)[..];
|
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 {
|
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();
|
||||||
@@ -343,7 +344,7 @@ pub async fn get_block_data(height: &str, block: &mut Block)
|
|||||||
if height.is_empty() == false {
|
if height.is_empty() == false {
|
||||||
let params = &format!("[{}, null, null]", height)[..];
|
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 {
|
if resp["result"]["Ok"].is_null() == false {
|
||||||
block.hash = resp["result"]["Ok"]["header"]["hash"].as_str().unwrap().to_string();
|
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> {
|
-> Result<(), anyhow::Error> {
|
||||||
let params = &format!("[null, \"{}\", null]", hash)[..];
|
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 {
|
if resp["result"]["Ok"].is_null() == false {
|
||||||
*height = resp["result"]["Ok"]["height"].to_string();
|
*height = resp["result"]["Ok"]["height"].to_string();
|
||||||
@@ -403,14 +404,26 @@ pub async fn get_block_header(hash: &str, height: &mut String)
|
|||||||
|
|
||||||
|
|
||||||
// Get kernel.
|
// 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> {
|
-> 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 {
|
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::<f64>().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(())
|
Ok(())
|
||||||
@@ -423,7 +436,7 @@ pub async fn get_block_kernels(height: &String, blocks: &mut Vec<Block>)
|
|||||||
if height.is_empty() == false {
|
if height.is_empty() == false {
|
||||||
let params = &format!("[{}, {}, 720, false]", height.parse::<u64>().unwrap() - 720,
|
let params = &format!("[{}, {}, 720, false]", height.parse::<u64>().unwrap() - 720,
|
||||||
height)[..];
|
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() {
|
for resp_block in resp["result"]["Ok"]["blocks"].as_array().unwrap() {
|
||||||
let mut block = Block::new();
|
let mut block = Block::new();
|
||||||
@@ -541,7 +554,7 @@ pub async fn get_block_list_by_height(height: &str, blocks: &mut Vec<Block>,
|
|||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
let height = height.to_string();
|
let height = height.to_string();
|
||||||
|
|
||||||
let resp = call("get_status", "[]", "owner").await?;
|
let resp = call("get_status", "[]", "1", "owner").await?;
|
||||||
|
|
||||||
if resp != Value::Null {
|
if resp != Value::Null {
|
||||||
*latest_height = resp["result"]["Ok"]["tip"]["height"].to_string().parse::<u64>().unwrap();
|
*latest_height = resp["result"]["Ok"]["tip"]["height"].to_string().parse::<u64>().unwrap();
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html>
|
<html lang="en" class="h-100">
|
||||||
<head>
|
<head>
|
||||||
<title>Grin Blockchain Explorer</title>
|
<title>Grin Blockchain Explorer</title>
|
||||||
<meta property="og:site_name" content="Grincoin.org (GRIN) Blockchain Explorer" />
|
<meta property="og:site_name" content="Grincoin.org (GRIN) Blockchain Explorer" />
|
||||||
@@ -78,7 +78,7 @@
|
|||||||
{% block content %}{% endblock content %}
|
{% block content %}{% endblock content %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<footer class="shadow">
|
<footer class="shadow mt-auto">
|
||||||
<code>
|
<code>
|
||||||
<br>
|
<br>
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
|
52
templates/kernel.html.tera
Normal file
52
templates/kernel.html.tera
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
{% extends "base" %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<code>
|
||||||
|
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="darkorange-text"><i class="bi bi-card-text"></i> KERNEL</div>
|
||||||
|
<br>
|
||||||
|
<div class="d-flex justify-content-between">
|
||||||
|
<div class="value-text">Excess </div>
|
||||||
|
<div class="value-text text-break text-end">{{ kernel.excess }}</div>
|
||||||
|
</div>
|
||||||
|
<br>
|
||||||
|
<div class="d-flex justify-content-between">
|
||||||
|
<div class="value-text">Block Height </div>
|
||||||
|
<div class="value-text text-end">
|
||||||
|
<a class="text-decoration-none" href="/block/{{ kernel.height }}">
|
||||||
|
{{ kernel.height }} <i class="bi bi-box-arrow-up-right"></i>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<br>
|
||||||
|
<div class="d-flex justify-content-between">
|
||||||
|
<div class="value-text">Type </div>
|
||||||
|
<div class="value-text text-end">{{ kernel.ker_type }}</div>
|
||||||
|
</div>
|
||||||
|
<br>
|
||||||
|
<div class="d-flex justify-content-between">
|
||||||
|
<div class="value-text">Fee </div>
|
||||||
|
<div class="value-text text-end">{{ kernel.fee }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-body" align="left">
|
||||||
|
<div class="darkorange-text"><i class="bi bi-layout-text-sidebar-reverse"></i> RAW DATA</div>
|
||||||
|
<br>
|
||||||
|
<div class="value-text">{{ kernel.raw_data }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
</code>
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
|
|
Reference in New Issue
Block a user