From 814722fdfb5ef5229d8e1812be197c1e71529228 Mon Sep 17 00:00:00 2001 From: aglkm <39521015+aglkm@users.noreply.github.com> Date: Tue, 4 Jun 2024 16:33:50 +0300 Subject: [PATCH] search over unspent outputs --- src/data.rs | 23 +++++++++++++++++ src/main.rs | 47 ++++++++++++++++++++++++++++++---- src/requests.rs | 38 +++++++++++++++++++++++++++- templates/output.html.tera | 52 ++++++++++++++++++++++++++++++++++++++ templates/search.html.tera | 2 +- 5 files changed, 155 insertions(+), 7 deletions(-) create mode 100644 templates/output.html.tera diff --git a/src/data.rs b/src/data.rs index 5622eea..a22439c 100644 --- a/src/data.rs +++ b/src/data.rs @@ -133,6 +133,29 @@ impl Kernel { } +// Output data +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Output { + pub height: String, + pub commit: String, + pub out_type: String, + pub status: String, + pub raw_data: String, +} + +impl Output { + pub fn new() -> Output { + Output { + height: String::new(), + commit: String::new(), + out_type: String::new(), + status: String::new(), + raw_data: String::new(), + } + } +} + + // Transactions data #[derive(Debug)] pub struct Transactions { diff --git a/src/main.rs b/src/main.rs index e44474c..905ab14 100644 --- a/src/main.rs +++ b/src/main.rs @@ -19,6 +19,7 @@ use crate::data::Dashboard; use crate::data::Block; use crate::data::Transactions; use crate::data::Kernel; +use crate::data::Output; use crate::requests::CONFIG; @@ -149,11 +150,33 @@ async fn kernel(excess: &str) -> Template { } +// Rendering page for a specified output. +#[get("/output/")] +async fn output(commit: &str) -> Template { + let mut output = Output::new(); + + let _ = requests::get_output(&commit, &mut output).await; + + if output.commit.is_empty() == false { + return Template::render("output", context! { + route: "output", + cg_api: CONFIG.coingecko_api.clone(), + output, + }) + } + + return Template::render("error", context! { + route: "error", + cg_api: CONFIG.coingecko_api.clone(), + }) +} + + // Handling search request. // Using Option<&str> to match '/search' query without input params. // https://github.com/rwf2/Rocket/issues/608 #[get("/search?")] -fn search(input: Option<&str>) -> Either { +pub async fn search(input: Option<&str>) -> Either { // Unwrap Option and forward to Search page if no parameters let input = match input { Some(value) => value, @@ -174,9 +197,23 @@ fn search(input: Option<&str>) -> Either { } else if input.len() == 64 { return Either::Right(Redirect::to(uri!(block_header_by_hash(input)))); - // Kernel + // Kernel or Output } else if input.len() == 66 { - return Either::Right(Redirect::to(uri!(kernel(input)))); + // First search for Kernel + let mut kernel = Kernel::new(); + + let _ = requests::get_kernel(&input, &mut kernel).await; + + if kernel.excess.is_empty() == false { + return Either::Left(Template::render("kernel", context! { + route: "kernel", + cg_api: CONFIG.coingecko_api.clone(), + kernel, + })); + } else { + // If Kernel not found, then search for Output + return Either::Right(Redirect::to(uri!(output(input)))); + } } } @@ -188,6 +225,7 @@ fn search(input: Option<&str>) -> Either { // Owner API. +// Whitelisted methods: get_connected_peers, get_peers, get_status. #[post("/v2/owner", data="")] async fn api_owner(data: &str) -> String { if CONFIG.public_api == "enabled" { @@ -203,7 +241,6 @@ async fn api_owner(data: &str) -> String { _ => 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(), v["id"].to_string().as_str(), "owner").await; @@ -646,7 +683,7 @@ async fn main() { 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, - api_owner, api_foreign]) + output, api_owner, api_foreign]) .mount("/static", FileServer::from("static")) .attach(Template::fairing()) .launch() diff --git a/src/requests.rs b/src/requests.rs index bf64796..4baa48f 100644 --- a/src/requests.rs +++ b/src/requests.rs @@ -16,7 +16,8 @@ use crate::data::Dashboard; use crate::data::Block; use crate::data::Transactions; use crate::data::ExplorerConfig; -use crate::Kernel; +use crate::data::Kernel; +use crate::data::Output; // Static explorer config structure @@ -447,6 +448,41 @@ pub async fn get_kernel(excess: &str, kernel: &mut Kernel) -> Result<(), anyhow: } +// Get output. +pub async fn get_output(commit: &str, output: &mut Output) -> Result<(), anyhow::Error> { + // First check whether output is broadcasted but not confirmed yet (in mempool) + let mut resp = call("get_unconfirmed_transactions", "[]", "1", "foreign").await?; + + if resp["result"]["Ok"].is_null() == false { + for tx in resp["result"]["Ok"].as_array().unwrap() { + for out in tx["tx"]["body"]["outputs"].as_array().unwrap() { + if out["commit"].as_str().unwrap() == commit { + // Only Plain outputs in the mempool + output.out_type = "Plain".to_string(); + output.commit = out["commit"].as_str().unwrap().to_string(); + output.status = "Unconfirmed".to_string(); + // Found it, no need to continue + return Ok(()); + } + } + } + } + + let params = &format!("[[\"{}\"], null, null, true, true]", commit)[..]; + + resp = call("get_outputs", params, "1", "foreign").await?; + + if resp["result"]["Ok"][0].is_null() == false { + output.height = resp["result"]["Ok"][0]["block_height"].to_string(); + output.commit = resp["result"]["Ok"][0]["commit"].as_str().unwrap().to_string(); + output.out_type = resp["result"]["Ok"][0]["output_type"].as_str().unwrap().to_string(); + output.raw_data = serde_json::to_string_pretty(&resp).unwrap() + } + + Ok(()) +} + + // Collecting block kernels for transactions stats. pub async fn get_block_kernels(height: &String, blocks: &mut Vec) -> Result<(), anyhow::Error> { diff --git a/templates/output.html.tera b/templates/output.html.tera new file mode 100644 index 0000000..2ef9414 --- /dev/null +++ b/templates/output.html.tera @@ -0,0 +1,52 @@ +{% extends "base" %} + +{% block content %} + + + +
+
+
+
OUTPUT
+ {% if output.status == "Unconfirmed" %} + UNCONFIRMED + {% endif %} +
+
+
+
Commitment 
+
{{ output.commit }}
+
+ {% if output.status != "Unconfirmed" %} +
+
+
Block Height 
+ +
+ {% endif %} +
+
+
Type 
+
{{ output.out_type }}
+
+
+
+ + {% if output.status != "Unconfirmed" %} +
+
+
RAW DATA
+
+
{{ output.raw_data }}
+
+
+ {% endif %} + +
+ +{% endblock %} + diff --git a/templates/search.html.tera b/templates/search.html.tera index 9ca1716..dbda3b0 100644 --- a/templates/search.html.tera +++ b/templates/search.html.tera @@ -4,7 +4,7 @@ -
+