mirror of
https://github.com/transatoshi-mw/grin-explorer.git
synced 2025-10-21 13:33:41 +00:00
enhanced logging and external connection
This commit is contained in:
91
Cargo.lock
generated
91
Cargo.lock
generated
@@ -41,6 +41,55 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstream"
|
||||||
|
version = "0.6.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b"
|
||||||
|
dependencies = [
|
||||||
|
"anstyle",
|
||||||
|
"anstyle-parse",
|
||||||
|
"anstyle-query",
|
||||||
|
"anstyle-wincon",
|
||||||
|
"colorchoice",
|
||||||
|
"is_terminal_polyfill",
|
||||||
|
"utf8parse",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle"
|
||||||
|
version = "1.0.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle-parse"
|
||||||
|
version = "0.2.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4"
|
||||||
|
dependencies = [
|
||||||
|
"utf8parse",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle-query"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391"
|
||||||
|
dependencies = [
|
||||||
|
"windows-sys 0.52.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle-wincon"
|
||||||
|
version = "3.0.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19"
|
||||||
|
dependencies = [
|
||||||
|
"anstyle",
|
||||||
|
"windows-sys 0.52.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anyhow"
|
name = "anyhow"
|
||||||
version = "1.0.86"
|
version = "1.0.86"
|
||||||
@@ -234,6 +283,12 @@ dependencies = [
|
|||||||
"phf_codegen",
|
"phf_codegen",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "colorchoice"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "colored"
|
name = "colored"
|
||||||
version = "2.1.0"
|
version = "2.1.0"
|
||||||
@@ -482,6 +537,29 @@ dependencies = [
|
|||||||
"cfg-if",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "env_filter"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a009aa4810eb158359dda09d0c87378e4bbb89b5a801f016885a4707ba24f7ea"
|
||||||
|
dependencies = [
|
||||||
|
"log",
|
||||||
|
"regex",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "env_logger"
|
||||||
|
version = "0.11.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "38b35839ba51819680ba087cd351788c9a3c476841207e0b8cee0b04722343b9"
|
||||||
|
dependencies = [
|
||||||
|
"anstream",
|
||||||
|
"anstyle",
|
||||||
|
"env_filter",
|
||||||
|
"humantime",
|
||||||
|
"log",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "equivalent"
|
name = "equivalent"
|
||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
@@ -743,6 +821,7 @@ dependencies = [
|
|||||||
"colored",
|
"colored",
|
||||||
"config",
|
"config",
|
||||||
"either",
|
"either",
|
||||||
|
"env_logger",
|
||||||
"fs_extra",
|
"fs_extra",
|
||||||
"futures",
|
"futures",
|
||||||
"humantime",
|
"humantime",
|
||||||
@@ -982,6 +1061,12 @@ dependencies = [
|
|||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "is_terminal_polyfill"
|
||||||
|
version = "1.70.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itoa"
|
name = "itoa"
|
||||||
version = "1.0.11"
|
version = "1.0.11"
|
||||||
@@ -2540,6 +2625,12 @@ dependencies = [
|
|||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "utf8parse"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "valuable"
|
name = "valuable"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
@@ -20,6 +20,7 @@ lazy_static = "1.4.0"
|
|||||||
shellexpand = "3.1.0"
|
shellexpand = "3.1.0"
|
||||||
either = "1.11.0"
|
either = "1.11.0"
|
||||||
anyhow = "1.0.86"
|
anyhow = "1.0.86"
|
||||||
|
env_logger = "0.11.3"
|
||||||
|
|
||||||
[dependencies.reqwest]
|
[dependencies.reqwest]
|
||||||
version = "0.11.23"
|
version = "0.11.23"
|
||||||
|
@@ -7,13 +7,13 @@ port = "3413"
|
|||||||
# Node protocol. Either HTTP or HTTPS.
|
# Node protocol. Either HTTP or HTTPS.
|
||||||
proto = "http"
|
proto = "http"
|
||||||
|
|
||||||
# API username.
|
# API username. Comment out if user is not required.
|
||||||
user = "grin"
|
user = "grin"
|
||||||
|
|
||||||
# API secret path.
|
# API secret path. Comment out if secret is not required.
|
||||||
api_secret_path = "~/.grin/main/.api_secret"
|
api_secret_path = "~/.grin/main/.api_secret"
|
||||||
|
|
||||||
# Foreign API secret path.
|
# Foreign API secret path. Comment out if secret is not required.
|
||||||
foreign_api_secret_path = "~/.grin/main/.foreign_api_secret"
|
foreign_api_secret_path = "~/.grin/main/.foreign_api_secret"
|
||||||
|
|
||||||
# Path to Grin directory.
|
# Path to Grin directory.
|
||||||
@@ -26,6 +26,21 @@ coingecko_api = "enabled"
|
|||||||
public_api = "enabled"
|
public_api = "enabled"
|
||||||
|
|
||||||
|
|
||||||
|
# Grinnode config
|
||||||
|
# ip = "grinnode.live"
|
||||||
|
# port = "3413"
|
||||||
|
# proto = "https"
|
||||||
|
# coingecko_api = "enabled"
|
||||||
|
# public_api = "enabled"
|
||||||
|
|
||||||
|
|
||||||
|
# Grincoin config
|
||||||
|
# ip = "grincoin.org"
|
||||||
|
# proto = "https"
|
||||||
|
# coingecko_api = "enabled"
|
||||||
|
# public_api = "enabled"
|
||||||
|
|
||||||
|
|
||||||
# Testnet config
|
# Testnet config
|
||||||
# ip = "127.0.0.1"
|
# ip = "127.0.0.1"
|
||||||
# port = "13413"
|
# port = "13413"
|
||||||
|
@@ -22,15 +22,14 @@ Grin is the very first, simple and fair MimbleWimble blockchain implementation.
|
|||||||
cd grin-explorer
|
cd grin-explorer
|
||||||
cargo build --release
|
cargo build --release
|
||||||
```
|
```
|
||||||
4. Run executable: `./target/release/grin-explorer`
|
4. Run executable: `RUST_LOG=rocket=warn,grin_explorer ./target/release/grin-explorer`
|
||||||
|
|
||||||
You will see the following output:
|
You will see the following output:
|
||||||
|
|
||||||
```
|
```
|
||||||
[ INFO ] Starting up Explorer.
|
[2024-06-19T13:12:34Z INFO grin_explorer] starting up.
|
||||||
[ INFO ] Starting up Rocket engine.
|
[2024-06-19T13:12:34Z WARN rocket::launch] 🚀 Rocket has launched from http://127.0.0.1:8000
|
||||||
🚀 Rocket has launched from http://127.0.0.1:8000
|
[2024-06-19T13:12:34Z INFO grin_explorer] ready.
|
||||||
[ OK ] Explorer Ready.
|
|
||||||
```
|
```
|
||||||
|
|
||||||
5. Open explorer in your browser: http://127.0.0.1:8000
|
5. Open explorer in your browser: http://127.0.0.1:8000
|
||||||
|
@@ -1,6 +1,5 @@
|
|||||||
[default]
|
[default]
|
||||||
address = "127.0.0.1"
|
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.
|
# 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.
|
# E.g. Mainnet (8000) and Testnet (8001) instances.
|
||||||
|
17
src/main.rs
17
src/main.rs
@@ -5,7 +5,6 @@ use rocket::fs::FileServer;
|
|||||||
use rocket::State;
|
use rocket::State;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use colored::Colorize;
|
|
||||||
use rocket::tokio;
|
use rocket::tokio;
|
||||||
use rocket::response::Redirect;
|
use rocket::response::Redirect;
|
||||||
use either::Either;
|
use either::Either;
|
||||||
@@ -396,7 +395,11 @@ fn last_block_age(blocks: &State<Arc<Mutex<Vec<Block>>>>) -> String {
|
|||||||
fn disk_usage(dashboard: &State<Arc<Mutex<Dashboard>>>) -> String {
|
fn disk_usage(dashboard: &State<Arc<Mutex<Dashboard>>>) -> String {
|
||||||
let data = dashboard.lock().unwrap();
|
let data = dashboard.lock().unwrap();
|
||||||
|
|
||||||
format!("{} GB", data.disk_usage)
|
if data.disk_usage.is_empty() == false {
|
||||||
|
return format!("{} GB", data.disk_usage);
|
||||||
|
} else {
|
||||||
|
return format!("<i class=\"bi bi-x-lg\"></i>");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -602,7 +605,9 @@ fn block_list_index(dashboard: &State<Arc<Mutex<Dashboard>>>) -> String {
|
|||||||
// Main
|
// Main
|
||||||
#[rocket::main]
|
#[rocket::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
println!("{} Starting up Explorer.", "[ INFO ]".cyan());
|
env_logger::init();
|
||||||
|
|
||||||
|
info!("starting up.");
|
||||||
|
|
||||||
let dash = Arc::new(Mutex::new(Dashboard::new()));
|
let dash = Arc::new(Mutex::new(Dashboard::new()));
|
||||||
let dash_clone = dash.clone();
|
let dash_clone = dash.clone();
|
||||||
@@ -622,12 +627,12 @@ async fn main() {
|
|||||||
Ok(_v) => {
|
Ok(_v) => {
|
||||||
if ready == false {
|
if ready == false {
|
||||||
ready = true;
|
ready = true;
|
||||||
println!("{} Explorer Ready.", "[ OK ]".green());
|
info!("ready.");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
ready = false;
|
ready = false;
|
||||||
println!("{} {}.", "[ ERROR ]".red(), e);
|
error!("{}", e);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -635,8 +640,6 @@ async fn main() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
println!("{} Starting up Rocket engine.", "[ INFO ]".cyan());
|
|
||||||
|
|
||||||
// Starting Rocket engine.
|
// Starting Rocket engine.
|
||||||
let _ = rocket::build()
|
let _ = rocket::build()
|
||||||
.manage(dash)
|
.manage(dash)
|
||||||
|
@@ -43,11 +43,17 @@ lazy_static! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg.api_secret = fs::read_to_string(format!("{}",
|
if cfg.api_secret_path.is_empty() == false {
|
||||||
shellexpand::tilde(&cfg.api_secret_path))).unwrap();
|
cfg.api_secret = fs::read_to_string(format!("{}", shellexpand::tilde(&cfg.api_secret_path))).unwrap();
|
||||||
cfg.foreign_api_secret = fs::read_to_string(format!("{}",
|
}
|
||||||
shellexpand::tilde(&cfg.foreign_api_secret_path))).unwrap();
|
|
||||||
cfg.grin_dir = format!("{}", shellexpand::tilde(&cfg.grin_dir));
|
if cfg.foreign_api_secret_path.is_empty() == false {
|
||||||
|
cfg.foreign_api_secret = fs::read_to_string(format!("{}", shellexpand::tilde(&cfg.foreign_api_secret_path))).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
if cfg.grin_dir.is_empty() == false {
|
||||||
|
cfg.grin_dir = format!("{}", shellexpand::tilde(&cfg.grin_dir));
|
||||||
|
}
|
||||||
|
|
||||||
cfg
|
cfg
|
||||||
};
|
};
|
||||||
@@ -59,13 +65,16 @@ pub async fn call(method: &str, params: &str, id: &str, rpc_type: &str) -> Resul
|
|||||||
let rpc_url;
|
let rpc_url;
|
||||||
let secret;
|
let secret;
|
||||||
|
|
||||||
if rpc_type == "owner" {
|
if CONFIG.port.is_empty() == false {
|
||||||
rpc_url = format!("{}://{}:{}/v2/owner", CONFIG.proto, CONFIG.ip, CONFIG.port);
|
rpc_url = format!("{}://{}:{}/v2/{}", CONFIG.proto, CONFIG.ip, CONFIG.port, rpc_type);
|
||||||
secret = CONFIG.api_secret.clone();
|
} else {
|
||||||
|
rpc_url = format!("{}://{}/v2/{}", CONFIG.proto, CONFIG.ip, rpc_type);
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
rpc_url = format!("{}://{}:{}/v2/foreign", CONFIG.proto, CONFIG.ip, CONFIG.port);
|
if rpc_type == "owner" {
|
||||||
secret = CONFIG.foreign_api_secret.clone();
|
secret = CONFIG.api_secret.clone();
|
||||||
|
} else {
|
||||||
|
secret = CONFIG.foreign_api_secret.clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
let client = reqwest::Client::new();
|
let client = reqwest::Client::new();
|
||||||
@@ -76,6 +85,11 @@ pub async fn call(method: &str, params: &str, id: &str, rpc_type: &str) -> Resul
|
|||||||
.send()
|
.send()
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
match result.error_for_status_ref() {
|
||||||
|
Ok(_res) => (),
|
||||||
|
Err(err) => { error!("rpc failed, status code: {:?}", err.status().unwrap()); },
|
||||||
|
}
|
||||||
|
|
||||||
let val: Value = serde_json::from_str(&result.text().await.unwrap())?;
|
let val: Value = serde_json::from_str(&result.text().await.unwrap())?;
|
||||||
|
|
||||||
Ok(val)
|
Ok(val)
|
||||||
@@ -173,7 +187,7 @@ pub async fn get_market(dashboard: Arc<Mutex<Dashboard>>) -> Result<(), Error> {
|
|||||||
if CONFIG.coingecko_api == "enabled" && val != Value::Null {
|
if CONFIG.coingecko_api == "enabled" && val != Value::Null {
|
||||||
// Check if CoingGecko API returned error
|
// Check if CoingGecko API returned error
|
||||||
if let Some(status) = val.get("status") {
|
if let Some(status) = val.get("status") {
|
||||||
println!("{} {}.", "[ WARNING ]".yellow(), status["error_message"].as_str().unwrap().to_string());
|
warn!("{}", status["error_message"].as_str().unwrap().to_string());
|
||||||
} else {
|
} else {
|
||||||
data.price_usd = format!("{:.3}", val["grin"]["usd"].to_string().parse::<f64>().unwrap());
|
data.price_usd = format!("{:.3}", val["grin"]["usd"].to_string().parse::<f64>().unwrap());
|
||||||
data.price_btc = format!("{:.8}", val["grin"]["btc"].to_string().parse::<f64>().unwrap());
|
data.price_btc = format!("{:.8}", val["grin"]["btc"].to_string().parse::<f64>().unwrap());
|
||||||
@@ -205,7 +219,13 @@ pub fn get_disk_usage(dashboard: Arc<Mutex<Dashboard>>) -> Result<(), Error> {
|
|||||||
|
|
||||||
match get_size(chain_dir.clone()) {
|
match get_size(chain_dir.clone()) {
|
||||||
Ok(chain_size) => data.disk_usage = format!("{:.2}", (chain_size as f64) / 1000.0 / 1000.0 / 1000.0),
|
Ok(chain_size) => data.disk_usage = format!("{:.2}", (chain_size as f64) / 1000.0 / 1000.0 / 1000.0),
|
||||||
Err(e) => println!("{} {}: \"{}\".", "[ ERROR ]".red(), e, chain_dir),
|
Err(e) => {
|
||||||
|
if CONFIG.ip == "127.0.0.1" || CONFIG.ip == "0.0.0.0" {
|
||||||
|
error!("{}: \"{}\"", e, chain_dir);
|
||||||
|
} else {
|
||||||
|
// Ignore error for external node connection
|
||||||
|
}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -237,7 +257,7 @@ pub async fn get_mining_stats(dashboard: Arc<Mutex<Dashboard>>) -> Result<(), an
|
|||||||
// https://forum.grin.mw/t/difference-c31-and-c32-c33/7018/7
|
// https://forum.grin.mw/t/difference-c31-and-c32-c33/7018/7
|
||||||
let hashrate = (net_diff as f64) * 42.0 / 60.0 / 16384.0;
|
let hashrate = (net_diff as f64) * 42.0 / 60.0 / 16384.0;
|
||||||
|
|
||||||
// KG/s
|
// kG/s
|
||||||
if hashrate > 1000.0 {
|
if hashrate > 1000.0 {
|
||||||
data.hashrate = format!("{:.2} kG/s", hashrate / 1000.0);
|
data.hashrate = format!("{:.2} kG/s", hashrate / 1000.0);
|
||||||
// G/s
|
// G/s
|
||||||
@@ -255,10 +275,12 @@ pub async fn get_mining_stats(dashboard: Arc<Mutex<Dashboard>>) -> Result<(), an
|
|||||||
// Assuming $0.07 per kW/h
|
// Assuming $0.07 per kW/h
|
||||||
data.production_cost = format!("{:.3}", 120.0 / 1000.0 * 0.07 * (1.0 / coins_per_hour));
|
data.production_cost = format!("{:.3}", 120.0 / 1000.0 * 0.07 * (1.0 / coins_per_hour));
|
||||||
|
|
||||||
data.reward_ratio = format!("{:.2}", data.price_usd.parse::<f64>().unwrap()
|
if data.price_usd.is_empty() == false {
|
||||||
|
data.reward_ratio = format!("{:.2}", data.price_usd.parse::<f64>().unwrap()
|
||||||
/ data.production_cost.parse::<f64>().unwrap());
|
/ data.production_cost.parse::<f64>().unwrap());
|
||||||
data.breakeven_cost = format!("{:.2}", data.price_usd.parse::<f64>().unwrap()
|
data.breakeven_cost = format!("{:.2}", data.price_usd.parse::<f64>().unwrap()
|
||||||
/ (120.0 / 1000.0 * (1.0 / coins_per_hour)));
|
/ (120.0 / 1000.0 * (1.0 / coins_per_hour)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user