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

Initial support for forest-cli info #2578

Merged
merged 182 commits into from
Jun 16, 2023
Merged

Conversation

creativcoder
Copy link
Contributor

@creativcoder creativcoder commented Feb 21, 2023

Summary of changes

Changes introduced in this pull request:

Add a new info subcommand to forest-cli with the following information:

  • Network
  • Uptime
  • Chain status information
  • Chain health

This is ported from https://github.com/filecoin-project/lotus/blob/master/cli/info.go"

forest-cli info output:

Network: calibnet
Uptime: 0h 3m 210s (Started at: 2023-05-11 09:52:09.007870302 +00:00)
Chain: [sync: Ok! (9s behind)] [basefee: 100 atto FIL] [epoch: 549085]
Chain health: 71.58%


Default wallet address: -

Reference issue to close (if applicable)

Closes #2442

Other information and links

Change checklist

  • I have performed a self-review of my own code,
  • I have made corresponding changes to the documentation,
  • I have added tests that prove my fix is effective or that my feature works (if possible),
  • I have made sure the CHANGELOG is up-to-date. All user-facing changes should be reflected in this document.

@creativcoder creativcoder force-pushed the creativcoder/forest-info branch 3 times, most recently from 09de7e8 to fb0506c Compare February 24, 2023 15:05
@creativcoder creativcoder marked this pull request as ready for review February 24, 2023 15:51
@creativcoder creativcoder force-pushed the creativcoder/forest-info branch 3 times, most recently from 70375df to c8d9dac Compare March 1, 2023 15:44
@lemmih
Copy link
Contributor

lemmih commented Mar 1, 2023

@creativcoder Have you finished the change checklist?

@lemmih
Copy link
Contributor

lemmih commented Mar 13, 2023

@creativcoder Could you show an example of the output?

@creativcoder
Copy link
Contributor Author

@lemmih So far we have the following:

➜  forest2 git:(creativcoder/forest-info) ✗ ./target/release/forest-cli --chain calibnet info show
Network: calibnet
Uptime: 10h 27m 53s
Chain: [sync: Behind! (55959663 behind)] [basefee: 0.0000000000000001 pFIL] [epoch: 382117]
Chain health: 60%

Default wallet address: t1ac6ndwj6nghqbmtbovvnwcqo577p6ox2pt52q2y

node/rpc-api/src/lib.rs Outdated Show resolved Hide resolved
node/rpc-api/src/lib.rs Outdated Show resolved Hide resolved
node/rpc/src/sync_api.rs Outdated Show resolved Hide resolved
@lemmih
Copy link
Contributor

lemmih commented Mar 14, 2023

@lemmih So far we have the following:

➜  forest2 git:(creativcoder/forest-info) ✗ ./target/release/forest-cli --chain calibnet info show
Network: calibnet
Uptime: 10h 27m 53s
Chain: [sync: Behind! (55959663 behind)] [basefee: 0.0000000000000001 pFIL] [epoch: 382117]
Chain health: 60%

Default wallet address: t1ac6ndwj6nghqbmtbovvnwcqo577p6ox2pt52q2y

This should be in the PR description.

@lemmih
Copy link
Contributor

lemmih commented Mar 14, 2023

And concepts such as chain health need to be documented.

@LesnyRumcajs
Copy link
Member

0.0000000000000001 pFIL I think I lack Maths PhD to decode that on the fly. Could we use attoFIL?

@creativcoder creativcoder force-pushed the creativcoder/forest-info branch 2 times, most recently from 65a25e3 to b4cb1a3 Compare March 15, 2023 12:49
@creativcoder creativcoder requested a review from lemmih June 13, 2023 10:48
cur_duration: Duration,
blocks_per_tipset_last_finality: f64,
head: TipsetJson,
) -> anyhow::Result<NodeStatusInfo> {
Copy link
Contributor

Choose a reason for hiding this comment

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

This function can no longer fail.

Comment on lines 168 to 190
if self.use_color {
writeln!(&mut output, "Network: {}", self.network())?;
writeln!(&mut output, "Uptime: {}", self.uptime(now))?;
writeln!(&mut output, "Chain: {}", self.chain_status())?;
writeln!(&mut output, "Chain health: {}", self.health())?;
writeln!(
&mut output,
"Default wallet address: {} {}",
self.wallet_address(),
self.wallet_balance()
)?;
} else {
writeln!(&mut output, "Network: {}", self.network().clear())?;
writeln!(&mut output, "Uptime: {}", self.uptime(now).clear())?;
writeln!(&mut output, "Chain: {}", self.chain_status().clear())?;
writeln!(&mut output, "Chain health: {}", self.health().clear())?;
writeln!(
&mut output,
"Default wallet address: {} {}",
self.wallet_address().clear(),
self.wallet_balance().clear()
)?;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Refactor this to avoid duplicate code.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

let blocks_per_tipset_last_finality =
node_status.chain_status.blocks_per_tipset_last_finality;

let mut node_status_info = NodeStatusInfo::new(
Copy link
Contributor

Choose a reason for hiding this comment

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

This doesn't need to be mut if you refactor it slightly.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

refactored to remove use_color field

lemmih
lemmih previously requested changes Jun 13, 2023
let balance_token_amount = TokenAmount::from_atto(bal.parse::<BigInt>()?);
Ok(format!("{:.4}", balance_token_amount.pretty()))
} else {
Err(anyhow::anyhow!("error parsing balance"))
Copy link
Contributor

Choose a reason for hiding this comment

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

This looks off to me. It returns a parsing error if there's no default wallet.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Reworded error msg

forest/cli/src/cli/info_cmd.rs Outdated Show resolved Hide resolved
@creativcoder creativcoder requested a review from lemmih June 14, 2023 11:55
@lemmih lemmih dismissed their stale review June 15, 2023 13:37

dismissing to allow others to review this PR

Copy link
Contributor

@aatifsyed aatifsyed left a comment

Choose a reason for hiding this comment

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

nits

Comment on lines 154 to 160
output.push(network);
output.push(uptime);
output.push(chain);
output.push(chain_health);
output.push(wallet_info);

output
Copy link
Contributor

Choose a reason for hiding this comment

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

Just construct a vec with vec![..] here.
It's surprising to return Vec<String> - could you add a comment explaining why?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

was needed for color strings fmt, but not needed atm. Changed it to a String

Comment on lines 211 to 218
fn balance(balance: &Option<String>) -> anyhow::Result<String> {
if let Some(bal) = balance {
let balance_token_amount = TokenAmount::from_atto(bal.parse::<BigInt>()?);
Ok(format!("{:.4}", balance_token_amount.pretty()))
} else {
Err(anyhow::anyhow!("could not find balance"))
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

It's very odd to have a function take in a single &Option<T> - just make the inner function, and call one of the Option combinators on the outer option

Copy link
Contributor

Choose a reason for hiding this comment

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

https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=8131fccabf844bba1255f586298b2ac7

Of course, in this example, the mapped function is trivial and should be inlined.

Comment on lines 134 to 149
let wallet_info = {
let wallet_address = self
.default_wallet_address
.clone()
.unwrap_or("address not set".to_string());

let wallet_balance = match balance(&self.default_wallet_address_balance) {
Ok(bal) => format!("[balance: {}]", bal),
Err(e) => e.to_string(),
};

format!(
"Default wallet address: {} [{}]",
wallet_address, wallet_balance
)
};
Copy link
Contributor

@aatifsyed aatifsyed Jun 15, 2023

Choose a reason for hiding this comment

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

Consider rewriting this as follows:

Suggested change
let wallet_info = {
let wallet_address = self
.default_wallet_address
.clone()
.unwrap_or("address not set".to_string());
let wallet_balance = match balance(&self.default_wallet_address_balance) {
Ok(bal) => format!("[balance: {}]", bal),
Err(e) => e.to_string(),
};
format!(
"Default wallet address: {} [{}]",
wallet_address, wallet_balance
)
};
let wallet_info = match (
&self.default_wallet_address,
&self.default_wallet_address_balance,
) {
(None, None) => String::from("<no default wallet address>"),
(Some(address), Some(balance)) => {
let attos = balance
.parse::<BigInt>()
.expect("RPC returned an invalid string for balance");
let token_amount = TokenAmount::from_atto(attos);
format!(
"Default wallet address: {address} [{:.4}]",
token_amount.pretty()
)
}
(None, Some(_)) | (Some(_), None) => {
unreachable!("If there's a default address, we should have the balance")
}
};

Note a couple of things here:

  • writing exhaustively and defensively has shown us that there's some bugs in our logic somewhere
    • we should either have all the default wallet info, or none of it
    • we should always have a valid wallet string

Okay, so now we look for the causes of those bugs:

  1. The new function should be fallible, we shouldn't have error strings in our format function. It should error if we've got an address but no balance (and vice versa). It should be fine for the caller to unwrap that
  2. Our RPC API is weakly typed. If it ever returns an invalid wallet string, something as gone wrong. We should panic there, as it's a software bug. Else, we should carry one with strong types. That means the RPC API should return TokenAmount, not a String. This is one of the main benefits of using a type system

The "principles" at play here are

  • making illegal states unrepresentable
  • fail fast
  • "defensive programming"

Copy link
Contributor

Choose a reason for hiding this comment

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

So we shouldn't really have strings anywhere in our NodeStatusInfo - consider actual types

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not going to hold up the PR on this, because you'll be doing follow on work, and this has been open a while anyway

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Noted. Thanks for the detailed review. We did decide to refactor RPC APIs to return strongly typed values, that'll be part of the follow-up PR and also accordingly the wallet fmt code.

.contains(&expected_status_fmt));
}

// FIXME: enable/debug this failing when color output is supported.
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd greatly prefer it if this uncommented code was removed before merging.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

removed the commented test

@creativcoder creativcoder enabled auto-merge (squash) June 16, 2023 08:15
@creativcoder creativcoder merged commit 105dbe5 into main Jun 16, 2023
19 checks passed
@creativcoder creativcoder deleted the creativcoder/forest-info branch June 16, 2023 08:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Implement forest-cli info command.
7 participants