Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update main.rs to improve Properties tab #154

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
192 changes: 157 additions & 35 deletions manager/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,11 @@ pub struct ChainInfo {

#[derive(Clone, Debug, serde::Deserialize)]
pub struct NetworkInfo {
#[allow(dead_code)]
connections: usize,
#[allow(dead_code)]
connections_in: usize,
#[allow(dead_code)]
connections_out: usize,
}

Expand Down Expand Up @@ -112,6 +115,50 @@ pub struct Stat {

fn sidecar(config: &Mapping, addr: &str) -> Result<(), Box<dyn Error>> {
let mut stats = LinearMap::new();
// Node uptime with years included
let uptime_info = std::process::Command::new("bitcoin-cli")
.arg("-conf=/root/.bitcoin/bitcoin.conf")
.arg("uptime")
.output()?;

if uptime_info.status.success() {
let uptime_seconds = String::from_utf8_lossy(&uptime_info.stdout)
.trim()
.parse::<u64>()
.unwrap_or(0);

let years = uptime_seconds / 31_536_000;
let days = (uptime_seconds % 31_536_000) / 86400;
let hours = (uptime_seconds % 86400) / 3600;
let minutes = (uptime_seconds % 3600) / 60;

let uptime_formatted = if years > 0 {
format!("{} years, {} days, {} hours, {} minutes", years, days, hours, minutes)
} else if days > 0 {
format!("{} days, {} hours, {} minutes", days, hours, minutes)
} else if hours > 0 {
format!("{} hours, {} minutes", hours, minutes)
} else {
format!("{} minutes", minutes)
};

stats.insert(
Cow::from("Node Uptime"),
Stat {
value_type: "string",
value: uptime_formatted,
description: Some(Cow::from("Total time the Bitcoin node has been running")),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This description is a bit misleading as it might leave a user thinking their node has only been running for a short time in total.

Maybe a description like "Total time Bitcoin has been running since it was last started"?

copyable: false,
qr: false,
masked: false,
},
);
} else {
eprintln!(
"Error retrieving uptime info: {}",
std::str::from_utf8(&uptime_info.stderr).unwrap_or("UNKNOWN ERROR")
);
}
if let (Some(user), Some(pass)) = (
config
.get(&Value::String("rpc".to_owned()))
Expand Down Expand Up @@ -168,51 +215,132 @@ fn sidecar(config: &Mapping, addr: &str) -> Result<(), Box<dyn Error>> {
},
);
}
let info_res = std::process::Command::new("bitcoin-cli")

// Calculate total supply and progress to the next halving
let blockchain_info = std::process::Command::new("bitcoin-cli")
.arg("-conf=/root/.bitcoin/bitcoin.conf")
.arg("getblockchaininfo")
.output()?;
if info_res.status.success() {
let info: ChainInfo = serde_json::from_slice(&info_res.stdout)?;

if blockchain_info.status.success() {
let blockchain_data: serde_json::Value = serde_json::from_slice(&blockchain_info.stdout)?;
let current_height = blockchain_data["blocks"].as_u64().unwrap_or(0);

// Calculate total supply based on height and halving intervals
let halving_interval = 210_000;
let mut subsidy = 50.0; // Initial subsidy in BTC
let mut total_supply = 0.0;
let mut remaining_height = current_height;

while remaining_height > 0 {
let blocks_in_this_epoch = remaining_height.min(halving_interval);
total_supply += blocks_in_this_epoch as f64 * subsidy;
remaining_height = remaining_height.saturating_sub(halving_interval);
subsidy /= 2.0;
}

Comment on lines +225 to +241
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given the imprecision of this calculation of issuance compared to gettxoutsetinfo (even if it is small as a percentage) I don't think it makes sense to include this metric in Properties.

stats.insert(
Cow::from("Block Height"),
Cow::from("Total Bitcoin Supply"),
Stat {
value_type: "string",
value: format!("{}", info.headers),
description: Some(Cow::from("The current block height for the network")),
value: format!("{:.8} BTC", total_supply),
description: Some(Cow::from("Current total supply of Bitcoin based on issuance schedule")),
copyable: false,
qr: false,
masked: false,
},
);

// Progress to Next Halving calculation
let last_halving_block = (current_height / halving_interval) * halving_interval;
let blocks_since_last_halving = current_height - last_halving_block;
let progress_to_next_halving = (blocks_since_last_halving as f64 / halving_interval as f64) * 100.0;

stats.insert(
Cow::from("Synced Block Height"),
Cow::from("Progress to Next Halving"),
Stat {
value_type: "string",
value: format!("{}", info.blocks),
description: Some(Cow::from("The number of blocks the node has verified")),
value: format!("{:.2}%", progress_to_next_halving),
description: Some(Cow::from("Percentage of blocks completed until the next Bitcoin halving")),
copyable: false,
qr: false,
masked: false,
},
);
}

// New section to fetch and display a simplified mempool summary
let mempool_info = std::process::Command::new("bitcoin-cli")
.arg("-conf=/root/.bitcoin/bitcoin.conf")
.arg("getmempoolinfo")
.output()?;

if mempool_info.status.success() {
let mempool_data: serde_json::Value = serde_json::from_slice(&mempool_info.stdout)?;

let max_mempool = mempool_data["maxmempool"].as_u64().unwrap_or(0) as f64 / 1024_f64.powf(2.0); // Convert to MB
let mempool_usage = mempool_data["usage"].as_u64().unwrap_or(0) as f64 / 1024_f64.powf(2.0); // Convert to MB
let mempool_percent = if max_mempool > 0.0 {
(mempool_usage / max_mempool) * 100.0
} else {
0.0
};
let tx_count = mempool_data["size"].as_u64().unwrap_or(0); // Number of transactions

// Insert the simplified mempool summary
stats.insert(
Cow::from("Mempool Summary"),
Stat {
value_type: "string",
value: format!(
"{:.2}/{:.2} MB ({:.2}%), {} Transactions",
mempool_usage, max_mempool, mempool_percent, tx_count
),
description: Some(Cow::from("Summary of current mempool usage and transaction count")),
copyable: false,
qr: false,
masked: false,
},
);
} else {
eprintln!(
"Error retrieving mempool info: {}",
std::str::from_utf8(&mempool_info.stderr).unwrap_or("UNKNOWN ERROR")
);
}
Comment on lines +273 to +310
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if it makes sense to include this information in Properties when users can get this and more detailed information about their mempool in a better format by using mempool-startos.

mempool


// Existing code for blockchain and network info retrieval continues here...
let info_res = std::process::Command::new("bitcoin-cli")
.arg("-conf=/root/.bitcoin/bitcoin.conf")
.arg("getblockchaininfo")
.output()?;
if info_res.status.success() {
let info: ChainInfo = serde_json::from_slice(&info_res.stdout)?;
// Consolidated block height and sync progress information
// Extract values for current synced blocks, total headers, and sync progress percentage
let current_blocks = info.blocks;
let total_headers = info.headers;
let sync_progress = if current_blocks < total_headers {
100.0 * info.verificationprogress
} else {
100.0
};

// Insert the simplified blockchain sync summary
stats.insert(
Cow::from("Sync Progress"),
Cow::from("Blockchain Sync Summary"),
Stat {
value_type: "string",
value: if info.blocks < info.headers {
format!("{:.2}%", 100.0 * info.verificationprogress)
} else {
"100%".to_owned()
},
description: Some(Cow::from(
"The percentage of the blockchain that has been verified",
)),
value: format!(
"{}/{} ({:.2}%)",
current_blocks, total_headers, sync_progress
),
Comment on lines +334 to +337
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a great improvement to make the Properties more concise. Nicely done. However I would add some spacing here for better readability.

Suggested change
value: format!(
"{}/{} ({:.2}%)",
current_blocks, total_headers, sync_progress
),
value: format!(
"{} / {} ({:.2}%)",
current_blocks, total_headers, sync_progress
),

description: Some(Cow::from("Current synced block height out of total headers and sync progress")),
copyable: false,
qr: false,
masked: false,
},
);
);
for (sf_name, sf_data) in info.softforks {
let sf_name_pretty = sf_name.to_title_case();
let status_desc = Some(Cow::from(format!(
Expand Down Expand Up @@ -417,8 +545,9 @@ fn sidecar(config: &Mapping, addr: &str) -> Result<(), Box<dyn Error>> {
)?;
Ok(())
}


fn inner_main(reindex: bool, reindex_chainstate: bool) -> Result<(), Box<dyn Error>> {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This parameter is needed for the Reindex Chainstate action. Is there a reason this parameter and all its subsequent uses are being removed?

fn inner_main(reindex: bool) -> Result<(), Box<dyn Error>> {
while !Path::new("/root/.bitcoin/start9/config.yaml").exists() {
std::thread::sleep(std::time::Duration::from_secs(1));
}
Expand All @@ -431,7 +560,6 @@ fn inner_main(reindex: bool, reindex_chainstate: bool) -> Result<(), Box<dyn Err
format!("-onion={}:9050", var("EMBASSY_IP")?),
format!("-externalip={}", peer_addr),
"-datadir=/root/.bitcoin".to_owned(),
"-deprecatedrpc=warnings".to_owned(),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is the "deprecatedrpc=warnings" arg being removed here?

While Bitcoin 28 has not yet shipped for bitcoind-startos, this arg is currently required for some dependencies like LND until LND 18.4 is released (currently on rc1).

"-conf=/root/.bitcoin/bitcoin.conf".to_owned(),
];
if config
Expand All @@ -456,18 +584,6 @@ fn inner_main(reindex: bool, reindex_chainstate: bool) -> Result<(), Box<dyn Err
}
if reindex {
btc_args.push("-reindex".to_owned());
match fs::remove_file("/root/.bitcoin/requires.reindex") {
Ok(()) => (),
Err(e) if e.kind() == std::io::ErrorKind::NotFound => (),
a => a?,
}
} else if reindex_chainstate {
btc_args.push("-reindex-chainstate".to_owned());
match fs::remove_file("/root/.bitcoin/requires.reindex_chainstate") {
Ok(()) => (),
Err(e) if e.kind() == std::io::ErrorKind::NotFound => (),
a => a?,
}
}

std::io::copy(
Expand All @@ -482,6 +598,13 @@ fn inner_main(reindex: bool, reindex_chainstate: bool) -> Result<(), Box<dyn Err
let mut child = std::process::Command::new("bitcoind")
.args(btc_args)
.spawn()?;
if reindex {
match fs::remove_file("/root/.bitcoin/requires.reindex") {
Ok(()) => (),
Err(e) if e.kind() == std::io::ErrorKind::NotFound => (),
a => a?,
}
}
Comment on lines +601 to +607
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why create a new conditional block here to delete the requires.reindex file when there is already a conditional block above used to add the "-reindex" arg?

let raw_child = child.id();
*CHILD_PID.lock().unwrap() = Some(raw_child);
let pruned = {
Expand Down Expand Up @@ -539,7 +662,6 @@ fn inner_main(reindex: bool, reindex_chainstate: bool) -> Result<(), Box<dyn Err
fn main() -> Result<(), Box<dyn Error>> {
env_logger::Builder::from_env(Env::default().default_filter_or("warn")).init();
let reindex = Path::new("/root/.bitcoin/requires.reindex").exists();
let reindex_chainstate = Path::new("/root/.bitcoin/requires.reindex_chainstate").exists();
ctrlc::set_handler(move || {
if let Some(raw_child) = *CHILD_PID.lock().unwrap() {
use nix::{
Expand All @@ -551,7 +673,7 @@ fn main() -> Result<(), Box<dyn Error>> {
std::process::exit(143)
}
})?;
inner_main(reindex, reindex_chainstate)
inner_main(reindex)
}

fn human_readable_timestamp(unix_time: u64) -> String {
Expand Down