Merge pull request #9233 from filecoin-project/feat/lotus-info-cmd

feat: cli: lotus info cmd
This commit is contained in:
Łukasz Magiera 2022-09-05 09:47:42 +02:00 committed by GitHub
commit 783fc6a20d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 248 additions and 0 deletions

View File

@ -69,6 +69,7 @@ var CommonCommands = []*cli.Command{
var Commands = []*cli.Command{ var Commands = []*cli.Command{
WithCategory("basic", sendCmd), WithCategory("basic", sendCmd),
WithCategory("basic", walletCmd), WithCategory("basic", walletCmd),
WithCategory("basic", infoCmd),
WithCategory("basic", clientCmd), WithCategory("basic", clientCmd),
WithCategory("basic", multisigCmd), WithCategory("basic", multisigCmd),
WithCategory("basic", filplusCmd), WithCategory("basic", filplusCmd),

230
cli/info.go Normal file
View File

@ -0,0 +1,230 @@
package cli
import (
"context"
"fmt"
"math"
"os"
"sort"
"strings"
"text/tabwriter"
"time"
"github.com/dustin/go-humanize"
"github.com/fatih/color"
"github.com/urfave/cli/v2"
"github.com/filecoin-project/go-fil-markets/storagemarket"
"github.com/filecoin-project/go-state-types/big"
"github.com/filecoin-project/lotus/api/v1api"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/types"
)
var infoCmd = &cli.Command{
Name: "info",
Usage: "Print node info",
Action: infoCmdAct,
}
func infoCmdAct(cctx *cli.Context) error {
fullapi, acloser, err := GetFullNodeAPIV1(cctx)
if err != nil {
return err
}
defer acloser()
ctx := ReqContext(cctx)
network, err := fullapi.StateGetNetworkParams(ctx)
if err != nil {
return err
}
fmt.Printf("Network: %s\n", network.NetworkName)
fmt.Print("Chain: ")
err = SyncBasefeeCheck(ctx, fullapi)
if err != nil {
return err
}
status, err := fullapi.NodeStatus(ctx, true)
if err != nil {
return err
}
fmt.Printf(" [epoch %s]\n", color.MagentaString(("%d"), status.SyncStatus.Epoch))
fmt.Printf("Peers to: [publish messages %d] [publish blocks %d]\n", status.PeerStatus.PeersToPublishMsgs, status.PeerStatus.PeersToPublishBlocks)
//Chain health calculated as percentage: amount of blocks in last finality / very healthy amount of blocks in a finality (900 epochs * 5 blocks per tipset)
health := (100 * (900 * status.ChainStatus.BlocksPerTipsetLastFinality) / (900 * 5))
switch {
case health > 85:
fmt.Printf("Chain health: %.f%% [%s]\n", health, color.GreenString("healthy"))
case health < 85:
fmt.Printf("Chain health: %.f%% [%s]\n", health, color.RedString("unhealthy"))
}
fmt.Println()
addr, err := fullapi.WalletDefaultAddress(ctx)
if err == nil {
fmt.Printf("Default address: \n")
balance, err := fullapi.WalletBalance(ctx, addr)
if err != nil {
return err
}
fmt.Printf(" %s [%s]\n", addr.String(), types.FIL(balance).Short())
} else {
fmt.Printf("Default address: address not set\n")
}
fmt.Println()
addrs, err := fullapi.WalletList(ctx)
if err != nil {
return err
}
totalBalance := big.Zero()
for _, addr := range addrs {
totbal, err := fullapi.WalletBalance(ctx, addr)
if err != nil {
return err
}
totalBalance = big.Add(totalBalance, totbal)
}
switch {
case len(addrs) <= 1:
fmt.Printf("Wallet: %v address\n", len(addrs))
case len(addrs) > 1:
fmt.Printf("Wallet: %v addresses\n", len(addrs))
}
fmt.Printf(" Total balance: %s\n", types.FIL(totalBalance).Short())
mbLockedSum := big.Zero()
mbAvailableSum := big.Zero()
for _, addr := range addrs {
mbal, err := fullapi.StateMarketBalance(ctx, addr, types.EmptyTSK)
if err != nil {
if strings.Contains(err.Error(), "actor not found") {
continue
} else {
return err
}
}
mbLockedSum = big.Add(mbLockedSum, mbal.Locked)
mbAvailableSum = big.Add(mbAvailableSum, mbal.Escrow)
}
fmt.Printf(" Market locked: %s\n", types.FIL(mbLockedSum).Short())
fmt.Printf(" Market available: %s\n", types.FIL(mbAvailableSum).Short())
fmt.Println()
chs, err := fullapi.PaychList(ctx)
if err != nil {
return err
}
switch {
case len(chs) <= 1:
fmt.Printf("Payment Channels: %v channel\n", len(chs))
case len(chs) > 1:
fmt.Printf("Payment Channels: %v channels\n", len(chs))
}
fmt.Println()
localDeals, err := fullapi.ClientListDeals(ctx)
if err != nil {
return err
}
var totalSize uint64
byState := map[storagemarket.StorageDealStatus][]uint64{}
for _, deal := range localDeals {
totalSize += deal.Size
byState[deal.State] = append(byState[deal.State], deal.Size)
}
fmt.Printf("Deals: %d, %s\n", len(localDeals), types.SizeStr(types.NewInt(totalSize)))
type stateStat struct {
state storagemarket.StorageDealStatus
count int
bytes uint64
}
stateStats := make([]stateStat, 0, len(byState))
for state, deals := range byState {
if state == storagemarket.StorageDealActive {
state = math.MaxUint64 // for sort
}
st := stateStat{
state: state,
count: len(deals),
}
for _, b := range deals {
st.bytes += b
}
stateStats = append(stateStats, st)
}
sort.Slice(stateStats, func(i, j int) bool {
return int64(stateStats[i].state) < int64(stateStats[j].state)
})
for _, st := range stateStats {
if st.state == math.MaxUint64 {
st.state = storagemarket.StorageDealActive
}
fmt.Printf(" %s: %d deals, %s\n", storagemarket.DealStates[st.state], st.count, types.SizeStr(types.NewInt(st.bytes)))
}
fmt.Println()
tw := tabwriter.NewWriter(os.Stdout, 6, 6, 2, ' ', 0)
s, err := fullapi.NetBandwidthStats(ctx)
if err != nil {
return err
}
fmt.Printf("Bandwidth:\n")
fmt.Fprintf(tw, "\tTotalIn\tTotalOut\tRateIn\tRateOut\n")
fmt.Fprintf(tw, "\t%s\t%s\t%s/s\t%s/s\n", humanize.Bytes(uint64(s.TotalIn)), humanize.Bytes(uint64(s.TotalOut)), humanize.Bytes(uint64(s.RateIn)), humanize.Bytes(uint64(s.RateOut)))
return tw.Flush()
}
func SyncBasefeeCheck(ctx context.Context, fullapi v1api.FullNode) error {
head, err := fullapi.ChainHead(ctx)
if err != nil {
return err
}
switch {
case time.Now().Unix()-int64(head.MinTimestamp()) < int64(build.BlockDelaySecs*3/2): // within 1.5 epochs
fmt.Printf("[%s]", color.GreenString("sync ok"))
case time.Now().Unix()-int64(head.MinTimestamp()) < int64(build.BlockDelaySecs*5): // within 5 epochs
fmt.Printf("[%s]", color.YellowString("sync slow (%s behind)", time.Now().Sub(time.Unix(int64(head.MinTimestamp()), 0)).Truncate(time.Second)))
default:
fmt.Printf("[%s]", color.RedString("sync behind! (%s behind)", time.Now().Sub(time.Unix(int64(head.MinTimestamp()), 0)).Truncate(time.Second)))
}
basefee := head.MinTicketBlock().ParentBaseFee
gasCol := []color.Attribute{color.FgBlue}
switch {
case basefee.GreaterThan(big.NewInt(7000_000_000)): // 7 nFIL
gasCol = []color.Attribute{color.BgRed, color.FgBlack}
case basefee.GreaterThan(big.NewInt(3000_000_000)): // 3 nFIL
gasCol = []color.Attribute{color.FgRed}
case basefee.GreaterThan(big.NewInt(750_000_000)): // 750 uFIL
gasCol = []color.Attribute{color.FgYellow}
case basefee.GreaterThan(big.NewInt(100_000_000)): // 100 uFIL
gasCol = []color.Attribute{color.FgGreen}
}
fmt.Printf(" [basefee %s]", color.New(gasCol...).Sprint(types.FIL(basefee).Short()))
return nil
}

View File

@ -18,6 +18,7 @@ COMMANDS:
BASIC: BASIC:
send Send funds between accounts send Send funds between accounts
wallet Manage wallet wallet Manage wallet
info Print node info
client Make deals, store data, retrieve data client Make deals, store data, retrieve data
msig Interact with a multisig wallet msig Interact with a multisig wallet
filplus Interact with the verified registry actor used by Filplus filplus Interact with the verified registry actor used by Filplus
@ -398,6 +399,22 @@ OPTIONS:
``` ```
## lotus info
```
NAME:
lotus info - Print node info
USAGE:
lotus info [command options] [arguments...]
CATEGORY:
BASIC
OPTIONS:
--help, -h show help (default: false)
```
## lotus client ## lotus client
``` ```
NAME: NAME: