feat: SPTool (#11788)

* sptool: Initial structure

* sptool: Port lotus-miner actor withdraw

* sptool: Make cli docsgen happy

* actors are done

* info

* proving

* sptool the rest

* fixed gitignore

* lints

* oops

* 2

* terminate

* fixes

* sptool: improve sectors list

---------

Co-authored-by: Łukasz Magiera <magik6k@gmail.com>
This commit is contained in:
Andrew Jackson (Ajax)
2024-04-01 10:30:35 -05:00
committed by GitHub
co-authored by Łukasz Magiera
parent 8062f200bd
commit b95e95f4d6
44 changed files with 4765 additions and 3383 deletions
+30
View File
@@ -0,0 +1,30 @@
package clicommands
import (
"github.com/urfave/cli/v2"
lcli "github.com/filecoin-project/lotus/cli"
)
var Commands = []*cli.Command{
lcli.WithCategory("basic", lcli.SendCmd),
lcli.WithCategory("basic", lcli.WalletCmd),
lcli.WithCategory("basic", lcli.InfoCmd),
lcli.WithCategory("basic", lcli.ClientCmd),
lcli.WithCategory("basic", lcli.MultisigCmd),
lcli.WithCategory("basic", lcli.FilplusCmd),
lcli.WithCategory("basic", lcli.PaychCmd),
lcli.WithCategory("developer", lcli.AuthCmd),
lcli.WithCategory("developer", lcli.MpoolCmd),
lcli.WithCategory("developer", StateCmd),
lcli.WithCategory("developer", lcli.ChainCmd),
lcli.WithCategory("developer", lcli.LogCmd),
lcli.WithCategory("developer", lcli.WaitApiCmd),
lcli.WithCategory("developer", lcli.FetchParamCmd),
lcli.WithCategory("developer", lcli.EvmCmd),
lcli.WithCategory("network", lcli.NetCmd),
lcli.WithCategory("network", lcli.SyncCmd),
lcli.WithCategory("status", lcli.StatusCmd),
lcli.PprofCmd,
lcli.VersionCmd,
}
+70
View File
@@ -0,0 +1,70 @@
// Package clicommands contains only the cli.Command definitions that are
// common to sptool and miner. These are here because they can't be referenced
// in cli/spcli or cli/ because of the import cycle with all the other cli functions.
package clicommands
import (
"github.com/urfave/cli/v2"
"github.com/filecoin-project/go-address"
lcli "github.com/filecoin-project/lotus/cli"
"github.com/filecoin-project/lotus/cli/spcli"
)
var StateCmd = &cli.Command{
Name: "state",
Usage: "Interact with and query filecoin chain state",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "tipset",
Usage: "specify tipset to call method on (pass comma separated array of cids)",
},
},
Subcommands: []*cli.Command{
lcli.StatePowerCmd,
lcli.StateSectorsCmd,
lcli.StateActiveSectorsCmd,
lcli.StateListActorsCmd,
lcli.StateListMinersCmd,
lcli.StateCircSupplyCmd,
lcli.StateSectorCmd,
lcli.StateGetActorCmd,
lcli.StateLookupIDCmd,
lcli.StateReplayCmd,
lcli.StateSectorSizeCmd,
lcli.StateReadStateCmd,
lcli.StateListMessagesCmd,
lcli.StateComputeStateCmd,
lcli.StateCallCmd,
lcli.StateGetDealSetCmd,
lcli.StateWaitMsgCmd,
lcli.StateSearchMsgCmd,
StateMinerInfo,
lcli.StateMarketCmd,
lcli.StateExecTraceCmd,
lcli.StateNtwkVersionCmd,
lcli.StateMinerProvingDeadlineCmd,
lcli.StateSysActorCIDsCmd,
},
}
var StateMinerInfo = &cli.Command{
Name: "miner-info",
Usage: "Retrieve miner information",
ArgsUsage: "[minerAddress]",
Action: func(cctx *cli.Context) error {
addressGetter := func(_ *cli.Context) (address.Address, error) {
if cctx.NArg() != 1 {
return address.Address{}, lcli.IncorrectNumArgs(cctx)
}
return address.NewFromString(cctx.Args().First())
}
err := spcli.InfoCmd(addressGetter).Action(cctx)
if err != nil {
return err
}
return nil
},
}
+1 -1
View File
@@ -74,7 +74,7 @@ func GetCidEncoder(cctx *cli.Context) (cidenc.Encoder, error) {
return e, nil
}
var clientCmd = &cli.Command{
var ClientCmd = &cli.Command{
Name: "client",
Usage: "Make deals, store data, retrieve data",
Subcommands: []*cli.Command{
-23
View File
@@ -66,29 +66,6 @@ var CommonCommands = []*cli.Command{
VersionCmd,
}
var Commands = []*cli.Command{
WithCategory("basic", sendCmd),
WithCategory("basic", walletCmd),
WithCategory("basic", infoCmd),
WithCategory("basic", clientCmd),
WithCategory("basic", multisigCmd),
WithCategory("basic", filplusCmd),
WithCategory("basic", paychCmd),
WithCategory("developer", AuthCmd),
WithCategory("developer", MpoolCmd),
WithCategory("developer", StateCmd),
WithCategory("developer", ChainCmd),
WithCategory("developer", LogCmd),
WithCategory("developer", WaitApiCmd),
WithCategory("developer", FetchParamCmd),
WithCategory("developer", EvmCmd),
WithCategory("network", NetCmd),
WithCategory("network", SyncCmd),
WithCategory("status", StatusCmd),
PprofCmd,
VersionCmd,
}
func WithCategory(cat string, cmd *cli.Command) *cli.Command {
cmd.Category = strings.ToUpper(cat)
return cmd
+1 -1
View File
@@ -39,7 +39,7 @@ import (
"github.com/filecoin-project/lotus/lib/tablewriter"
)
var filplusCmd = &cli.Command{
var FilplusCmd = &cli.Command{
Name: "filplus",
Usage: "Interact with the verified registry actor used by Filplus",
Flags: []cli.Flag{},
+1 -1
View File
@@ -23,7 +23,7 @@ import (
"github.com/filecoin-project/lotus/journal/alerting"
)
var infoCmd = &cli.Command{
var InfoCmd = &cli.Command{
Name: "info",
Usage: "Print node info",
Action: infoCmdAct,
+1 -1
View File
@@ -32,7 +32,7 @@ import (
"github.com/filecoin-project/lotus/chain/types"
)
var multisigCmd = &cli.Command{
var MultisigCmd = &cli.Command{
Name: "msig",
Usage: "Interact with a multisig wallet",
Flags: []cli.Flag{
+1 -1
View File
@@ -20,7 +20,7 @@ import (
"github.com/filecoin-project/lotus/paychmgr"
)
var paychCmd = &cli.Command{
var PaychCmd = &cli.Command{
Name: "paych",
Usage: "Manage payment channels",
Subcommands: []*cli.Command{
+1 -1
View File
@@ -19,7 +19,7 @@ import (
"github.com/filecoin-project/lotus/chain/types/ethtypes"
)
var sendCmd = &cli.Command{
var SendCmd = &cli.Command{
Name: "send",
Usage: "Send funds between accounts",
ArgsUsage: "[targetAddress] [amount]",
+2 -2
View File
@@ -45,7 +45,7 @@ func TestSendCLI(t *testing.T) {
oneFil := abi.TokenAmount(types.MustParseFIL("1"))
t.Run("simple", func(t *testing.T) {
app, mockSrvcs, buf, done := newMockApp(t, sendCmd)
app, mockSrvcs, buf, done := newMockApp(t, SendCmd)
defer done()
arbtProto := &api.MessagePrototype{
@@ -76,7 +76,7 @@ func TestSendEthereum(t *testing.T) {
oneFil := abi.TokenAmount(types.MustParseFIL("1"))
t.Run("simple", func(t *testing.T) {
app, mockSrvcs, buf, done := newMockApp(t, sendCmd)
app, mockSrvcs, buf, done := newMockApp(t, SendCmd)
defer done()
testEthAddr, err := ethtypes.CastEthAddress(make([]byte, 20))
+1240
View File
File diff suppressed because it is too large Load Diff
+121
View File
@@ -0,0 +1,121 @@
package spcli
import (
"fmt"
"github.com/fatih/color"
"github.com/multiformats/go-multiaddr"
"github.com/urfave/cli/v2"
"golang.org/x/xerrors"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-state-types/big"
"github.com/filecoin-project/lotus/chain/types"
lcli "github.com/filecoin-project/lotus/cli"
cliutil "github.com/filecoin-project/lotus/cli/util"
)
func InfoCmd(getActorAddress ActorAddressGetter) *cli.Command {
return &cli.Command{
Name: "info",
Usage: "Print miner actor info",
Action: func(cctx *cli.Context) error {
api, closer, err := cliutil.GetFullNodeAPI(cctx)
if err != nil {
return err
}
defer closer()
ctx := cliutil.ReqContext(cctx)
ts, err := lcli.LoadTipSet(ctx, cctx, api)
if err != nil {
return err
}
addr, err := getActorAddress(cctx)
if err != nil {
return err
}
mi, err := api.StateMinerInfo(ctx, addr, ts.Key())
if err != nil {
return err
}
availableBalance, err := api.StateMinerAvailableBalance(ctx, addr, ts.Key())
if err != nil {
return xerrors.Errorf("getting miner available balance: %w", err)
}
fmt.Printf("Available Balance: %s\n", types.FIL(availableBalance))
fmt.Printf("Owner:\t%s\n", mi.Owner)
fmt.Printf("Worker:\t%s\n", mi.Worker)
for i, controlAddress := range mi.ControlAddresses {
fmt.Printf("Control %d: \t%s\n", i, controlAddress)
}
if mi.Beneficiary != address.Undef {
fmt.Printf("Beneficiary:\t%s\n", mi.Beneficiary)
if mi.Beneficiary != mi.Owner {
fmt.Printf("Beneficiary Quota:\t%s\n", mi.BeneficiaryTerm.Quota)
fmt.Printf("Beneficiary Used Quota:\t%s\n", mi.BeneficiaryTerm.UsedQuota)
fmt.Printf("Beneficiary Expiration:\t%s\n", mi.BeneficiaryTerm.Expiration)
}
}
if mi.PendingBeneficiaryTerm != nil {
fmt.Printf("Pending Beneficiary Term:\n")
fmt.Printf("New Beneficiary:\t%s\n", mi.PendingBeneficiaryTerm.NewBeneficiary)
fmt.Printf("New Quota:\t%s\n", mi.PendingBeneficiaryTerm.NewQuota)
fmt.Printf("New Expiration:\t%s\n", mi.PendingBeneficiaryTerm.NewExpiration)
fmt.Printf("Approved By Beneficiary:\t%t\n", mi.PendingBeneficiaryTerm.ApprovedByBeneficiary)
fmt.Printf("Approved By Nominee:\t%t\n", mi.PendingBeneficiaryTerm.ApprovedByNominee)
}
fmt.Printf("PeerID:\t%s\n", mi.PeerId)
fmt.Printf("Multiaddrs:\t")
for _, addr := range mi.Multiaddrs {
a, err := multiaddr.NewMultiaddrBytes(addr)
if err != nil {
return xerrors.Errorf("undecodable listen address: %w", err)
}
fmt.Printf("%s ", a)
}
fmt.Println()
fmt.Printf("Consensus Fault End:\t%d\n", mi.ConsensusFaultElapsed)
fmt.Printf("SectorSize:\t%s (%d)\n", types.SizeStr(types.NewInt(uint64(mi.SectorSize))), mi.SectorSize)
pow, err := api.StateMinerPower(ctx, addr, ts.Key())
if err != nil {
return err
}
fmt.Printf("Byte Power: %s / %s (%0.4f%%)\n",
color.BlueString(types.SizeStr(pow.MinerPower.RawBytePower)),
types.SizeStr(pow.TotalPower.RawBytePower),
types.BigDivFloat(
types.BigMul(pow.MinerPower.RawBytePower, big.NewInt(100)),
pow.TotalPower.RawBytePower,
),
)
fmt.Printf("Actual Power: %s / %s (%0.4f%%)\n",
color.GreenString(types.DeciStr(pow.MinerPower.QualityAdjPower)),
types.DeciStr(pow.TotalPower.QualityAdjPower),
types.BigDivFloat(
types.BigMul(pow.MinerPower.QualityAdjPower, big.NewInt(100)),
pow.TotalPower.QualityAdjPower,
),
)
fmt.Println()
cd, err := api.StateMinerProvingDeadline(ctx, addr, ts.Key())
if err != nil {
return xerrors.Errorf("getting miner info: %w", err)
}
fmt.Printf("Proving Period Start:\t%s\n", cliutil.EpochTime(cd.CurrentEpoch, cd.PeriodStart))
return nil
},
}
}
+451
View File
@@ -0,0 +1,451 @@
package spcli
import (
"bytes"
"fmt"
"os"
"strconv"
"strings"
"text/tabwriter"
"time"
"github.com/fatih/color"
"github.com/urfave/cli/v2"
"golang.org/x/xerrors"
"github.com/filecoin-project/go-bitfield"
"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/go-state-types/dline"
"github.com/filecoin-project/lotus/blockstore"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/actors/builtin/miner"
"github.com/filecoin-project/lotus/chain/store"
"github.com/filecoin-project/lotus/chain/types"
lcli "github.com/filecoin-project/lotus/cli"
cliutil "github.com/filecoin-project/lotus/cli/util"
)
func ProvingInfoCmd(getActorAddress ActorAddressGetter) *cli.Command {
return &cli.Command{
Name: "info",
Usage: "View current state information",
Action: func(cctx *cli.Context) error {
api, acloser, err := lcli.GetFullNodeAPI(cctx)
if err != nil {
return err
}
defer acloser()
ctx := lcli.ReqContext(cctx)
maddr, err := getActorAddress(cctx)
if err != nil {
return err
}
head, err := api.ChainHead(ctx)
if err != nil {
return xerrors.Errorf("getting chain head: %w", err)
}
mact, err := api.StateGetActor(ctx, maddr, head.Key())
if err != nil {
return err
}
stor := store.ActorStore(ctx, blockstore.NewAPIBlockstore(api))
mas, err := miner.Load(stor, mact)
if err != nil {
return err
}
cd, err := api.StateMinerProvingDeadline(ctx, maddr, head.Key())
if err != nil {
return xerrors.Errorf("getting miner info: %w", err)
}
fmt.Printf("Miner: %s\n", color.BlueString("%s", maddr))
proving := uint64(0)
faults := uint64(0)
recovering := uint64(0)
curDeadlineSectors := uint64(0)
if err := mas.ForEachDeadline(func(dlIdx uint64, dl miner.Deadline) error {
return dl.ForEachPartition(func(partIdx uint64, part miner.Partition) error {
if bf, err := part.LiveSectors(); err != nil {
return err
} else if count, err := bf.Count(); err != nil {
return err
} else {
proving += count
if dlIdx == cd.Index {
curDeadlineSectors += count
}
}
if bf, err := part.FaultySectors(); err != nil {
return err
} else if count, err := bf.Count(); err != nil {
return err
} else {
faults += count
}
if bf, err := part.RecoveringSectors(); err != nil {
return err
} else if count, err := bf.Count(); err != nil {
return err
} else {
recovering += count
}
return nil
})
}); err != nil {
return xerrors.Errorf("walking miner deadlines and partitions: %w", err)
}
var faultPerc float64
if proving > 0 {
faultPerc = float64(faults * 100 / proving)
}
fmt.Printf("Current Epoch: %d\n", cd.CurrentEpoch)
fmt.Printf("Proving Period Boundary: %d\n", cd.PeriodStart%cd.WPoStProvingPeriod)
fmt.Printf("Proving Period Start: %s\n", cliutil.EpochTimeTs(cd.CurrentEpoch, cd.PeriodStart, head))
fmt.Printf("Next Period Start: %s\n\n", cliutil.EpochTimeTs(cd.CurrentEpoch, cd.PeriodStart+cd.WPoStProvingPeriod, head))
fmt.Printf("Faults: %d (%.2f%%)\n", faults, faultPerc)
fmt.Printf("Recovering: %d\n", recovering)
fmt.Printf("Deadline Index: %d\n", cd.Index)
fmt.Printf("Deadline Sectors: %d\n", curDeadlineSectors)
fmt.Printf("Deadline Open: %s\n", cliutil.EpochTime(cd.CurrentEpoch, cd.Open))
fmt.Printf("Deadline Close: %s\n", cliutil.EpochTime(cd.CurrentEpoch, cd.Close))
fmt.Printf("Deadline Challenge: %s\n", cliutil.EpochTime(cd.CurrentEpoch, cd.Challenge))
fmt.Printf("Deadline FaultCutoff: %s\n", cliutil.EpochTime(cd.CurrentEpoch, cd.FaultCutoff))
return nil
},
}
}
func ProvingDeadlinesCmd(getActorAddress ActorAddressGetter) *cli.Command {
return &cli.Command{
Name: "deadlines",
Usage: "View the current proving period deadlines information",
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "all",
Usage: "Count all sectors (only live sectors are counted by default)",
Aliases: []string{"a"},
},
},
Action: func(cctx *cli.Context) error {
api, acloser, err := lcli.GetFullNodeAPI(cctx)
if err != nil {
return err
}
defer acloser()
ctx := lcli.ReqContext(cctx)
maddr, err := getActorAddress(cctx)
if err != nil {
return err
}
deadlines, err := api.StateMinerDeadlines(ctx, maddr, types.EmptyTSK)
if err != nil {
return xerrors.Errorf("getting deadlines: %w", err)
}
di, err := api.StateMinerProvingDeadline(ctx, maddr, types.EmptyTSK)
if err != nil {
return xerrors.Errorf("getting deadlines: %w", err)
}
head, err := api.ChainHead(ctx)
if err != nil {
return err
}
fmt.Printf("Miner: %s\n", color.BlueString("%s", maddr))
tw := tabwriter.NewWriter(os.Stdout, 2, 4, 2, ' ', 0)
_, _ = fmt.Fprintln(tw, "deadline\topen\tpartitions\tsectors (faults)\tproven partitions")
for dlIdx, deadline := range deadlines {
partitions, err := api.StateMinerPartitions(ctx, maddr, uint64(dlIdx), types.EmptyTSK)
if err != nil {
return xerrors.Errorf("getting partitions for deadline %d: %w", dlIdx, err)
}
provenPartitions, err := deadline.PostSubmissions.Count()
if err != nil {
return err
}
sectors := uint64(0)
faults := uint64(0)
var partitionCount int
for _, partition := range partitions {
if !cctx.Bool("all") {
sc, err := partition.LiveSectors.Count()
if err != nil {
return err
}
if sc > 0 {
partitionCount++
}
sectors += sc
} else {
sc, err := partition.AllSectors.Count()
if err != nil {
return err
}
partitionCount++
sectors += sc
}
fc, err := partition.FaultySectors.Count()
if err != nil {
return err
}
faults += fc
}
var cur string
if di.Index == uint64(dlIdx) {
cur += "\t(current)"
}
_, _ = fmt.Fprintf(tw, "%d\t%s\t%d\t%d (%d)\t%d%s\n", dlIdx, deadlineOpenTime(head, uint64(dlIdx), di),
partitionCount, sectors, faults, provenPartitions, cur)
}
return tw.Flush()
},
}
}
func deadlineOpenTime(ts *types.TipSet, dlIdx uint64, di *dline.Info) string {
gapIdx := dlIdx - di.Index
gapHeight := uint64(di.WPoStProvingPeriod) / di.WPoStPeriodDeadlines * gapIdx
openHeight := di.Open + abi.ChainEpoch(gapHeight)
genesisBlockTimestamp := ts.MinTimestamp() - uint64(ts.Height())*build.BlockDelaySecs
return time.Unix(int64(genesisBlockTimestamp+build.BlockDelaySecs*uint64(openHeight)), 0).Format(time.TimeOnly)
}
func ProvingDeadlineInfoCmd(getActorAddress ActorAddressGetter) *cli.Command {
return &cli.Command{
Name: "deadline",
Usage: "View the current proving period deadline information by its index",
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "sector-nums",
Aliases: []string{"n"},
Usage: "Print sector/fault numbers belonging to this deadline",
},
&cli.BoolFlag{
Name: "bitfield",
Aliases: []string{"b"},
Usage: "Print partition bitfield stats",
},
},
ArgsUsage: "<deadlineIdx>",
Action: func(cctx *cli.Context) error {
if cctx.NArg() != 1 {
return lcli.IncorrectNumArgs(cctx)
}
dlIdx, err := strconv.ParseUint(cctx.Args().Get(0), 10, 64)
if err != nil {
return xerrors.Errorf("could not parse deadline index: %w", err)
}
api, acloser, err := lcli.GetFullNodeAPI(cctx)
if err != nil {
return err
}
defer acloser()
ctx := lcli.ReqContext(cctx)
maddr, err := getActorAddress(cctx)
if err != nil {
return err
}
deadlines, err := api.StateMinerDeadlines(ctx, maddr, types.EmptyTSK)
if err != nil {
return xerrors.Errorf("getting deadlines: %w", err)
}
di, err := api.StateMinerProvingDeadline(ctx, maddr, types.EmptyTSK)
if err != nil {
return xerrors.Errorf("getting deadlines: %w", err)
}
partitions, err := api.StateMinerPartitions(ctx, maddr, dlIdx, types.EmptyTSK)
if err != nil {
return xerrors.Errorf("getting partitions for deadline %d: %w", dlIdx, err)
}
head, err := api.ChainHead(ctx)
if err != nil {
return err
}
provenPartitions, err := deadlines[dlIdx].PostSubmissions.Count()
if err != nil {
return err
}
fmt.Printf("Deadline Index: %d\n", dlIdx)
fmt.Printf("Deadline Open: %s\n", deadlineOpenTime(head, dlIdx, di))
fmt.Printf("Partitions: %d\n", len(partitions))
fmt.Printf("Proven Partitions: %d\n", provenPartitions)
fmt.Printf("Current: %t\n\n", di.Index == dlIdx)
for pIdx, partition := range partitions {
fmt.Printf("Partition Index: %d\n", pIdx)
printStats := func(bf bitfield.BitField, name string) error {
count, err := bf.Count()
if err != nil {
return err
}
rit, err := bf.RunIterator()
if err != nil {
return err
}
if cctx.Bool("bitfield") {
var ones, zeros, oneRuns, zeroRuns, invalid uint64
for rit.HasNext() {
r, err := rit.NextRun()
if err != nil {
return xerrors.Errorf("next run: %w", err)
}
if !r.Valid() {
invalid++
}
if r.Val {
ones += r.Len
oneRuns++
} else {
zeros += r.Len
zeroRuns++
}
}
var buf bytes.Buffer
if err := bf.MarshalCBOR(&buf); err != nil {
return err
}
sz := len(buf.Bytes())
szstr := types.SizeStr(types.NewInt(uint64(sz)))
fmt.Printf("\t%s Sectors:%s%d (bitfield - runs %d+%d=%d - %d 0s %d 1s - %d inv - %s %dB)\n", name, strings.Repeat(" ", 18-len(name)), count, zeroRuns, oneRuns, zeroRuns+oneRuns, zeros, ones, invalid, szstr, sz)
} else {
fmt.Printf("\t%s Sectors:%s%d\n", name, strings.Repeat(" ", 18-len(name)), count)
}
if cctx.Bool("sector-nums") {
nums, err := bf.All(count)
if err != nil {
return err
}
fmt.Printf("\t%s Sector Numbers:%s%v\n", name, strings.Repeat(" ", 12-len(name)), nums)
}
return nil
}
if err := printStats(partition.AllSectors, "All"); err != nil {
return err
}
if err := printStats(partition.LiveSectors, "Live"); err != nil {
return err
}
if err := printStats(partition.ActiveSectors, "Active"); err != nil {
return err
}
if err := printStats(partition.FaultySectors, "Faulty"); err != nil {
return err
}
if err := printStats(partition.RecoveringSectors, "Recovering"); err != nil {
return err
}
}
return nil
},
}
}
func ProvingFaultsCmd(getActorAddress ActorAddressGetter) *cli.Command {
return &cli.Command{
Name: "faults",
Usage: "View the currently known proving faulty sectors information",
Action: func(cctx *cli.Context) error {
api, acloser, err := lcli.GetFullNodeAPI(cctx)
if err != nil {
return err
}
defer acloser()
ctx := lcli.ReqContext(cctx)
stor := store.ActorStore(ctx, blockstore.NewAPIBlockstore(api))
maddr, err := getActorAddress(cctx)
if err != nil {
return err
}
mact, err := api.StateGetActor(ctx, maddr, types.EmptyTSK)
if err != nil {
return err
}
mas, err := miner.Load(stor, mact)
if err != nil {
return err
}
fmt.Printf("Miner: %s\n", color.BlueString("%s", maddr))
tw := tabwriter.NewWriter(os.Stdout, 2, 4, 2, ' ', 0)
_, _ = fmt.Fprintln(tw, "deadline\tpartition\tsectors")
err = mas.ForEachDeadline(func(dlIdx uint64, dl miner.Deadline) error {
return dl.ForEachPartition(func(partIdx uint64, part miner.Partition) error {
faults, err := part.FaultySectors()
if err != nil {
return err
}
return faults.ForEach(func(num uint64) error {
_, _ = fmt.Fprintf(tw, "%d\t%d\t%d\n", dlIdx, partIdx, num)
return nil
})
})
})
if err != nil {
return err
}
return tw.Flush()
},
}
}
+1398
View File
File diff suppressed because it is too large Load Diff
+95
View File
@@ -0,0 +1,95 @@
package spcli
import (
"github.com/fatih/color"
sealing "github.com/filecoin-project/lotus/storage/pipeline"
)
type StateMeta struct {
I int
Col color.Attribute
State sealing.SectorState
}
var StateOrder = map[sealing.SectorState]StateMeta{}
var StateList = []StateMeta{
{Col: 39, State: "Total"},
{Col: color.FgGreen, State: sealing.Proving},
{Col: color.FgGreen, State: sealing.Available},
{Col: color.FgGreen, State: sealing.UpdateActivating},
{Col: color.FgMagenta, State: sealing.ReceiveSector},
{Col: color.FgBlue, State: sealing.Empty},
{Col: color.FgBlue, State: sealing.WaitDeals},
{Col: color.FgBlue, State: sealing.AddPiece},
{Col: color.FgBlue, State: sealing.SnapDealsWaitDeals},
{Col: color.FgBlue, State: sealing.SnapDealsAddPiece},
{Col: color.FgRed, State: sealing.UndefinedSectorState},
{Col: color.FgYellow, State: sealing.Packing},
{Col: color.FgYellow, State: sealing.GetTicket},
{Col: color.FgYellow, State: sealing.PreCommit1},
{Col: color.FgYellow, State: sealing.PreCommit2},
{Col: color.FgYellow, State: sealing.PreCommitting},
{Col: color.FgYellow, State: sealing.PreCommitWait},
{Col: color.FgYellow, State: sealing.SubmitPreCommitBatch},
{Col: color.FgYellow, State: sealing.PreCommitBatchWait},
{Col: color.FgYellow, State: sealing.WaitSeed},
{Col: color.FgYellow, State: sealing.Committing},
{Col: color.FgYellow, State: sealing.CommitFinalize},
{Col: color.FgYellow, State: sealing.SubmitCommit},
{Col: color.FgYellow, State: sealing.CommitWait},
{Col: color.FgYellow, State: sealing.SubmitCommitAggregate},
{Col: color.FgYellow, State: sealing.CommitAggregateWait},
{Col: color.FgYellow, State: sealing.FinalizeSector},
{Col: color.FgYellow, State: sealing.SnapDealsPacking},
{Col: color.FgYellow, State: sealing.UpdateReplica},
{Col: color.FgYellow, State: sealing.ProveReplicaUpdate},
{Col: color.FgYellow, State: sealing.SubmitReplicaUpdate},
{Col: color.FgYellow, State: sealing.ReplicaUpdateWait},
{Col: color.FgYellow, State: sealing.WaitMutable},
{Col: color.FgYellow, State: sealing.FinalizeReplicaUpdate},
{Col: color.FgYellow, State: sealing.ReleaseSectorKey},
{Col: color.FgCyan, State: sealing.Terminating},
{Col: color.FgCyan, State: sealing.TerminateWait},
{Col: color.FgCyan, State: sealing.TerminateFinality},
{Col: color.FgCyan, State: sealing.TerminateFailed},
{Col: color.FgCyan, State: sealing.Removing},
{Col: color.FgCyan, State: sealing.Removed},
{Col: color.FgCyan, State: sealing.AbortUpgrade},
{Col: color.FgRed, State: sealing.FailedUnrecoverable},
{Col: color.FgRed, State: sealing.AddPieceFailed},
{Col: color.FgRed, State: sealing.SealPreCommit1Failed},
{Col: color.FgRed, State: sealing.SealPreCommit2Failed},
{Col: color.FgRed, State: sealing.PreCommitFailed},
{Col: color.FgRed, State: sealing.ComputeProofFailed},
{Col: color.FgRed, State: sealing.RemoteCommitFailed},
{Col: color.FgRed, State: sealing.CommitFailed},
{Col: color.FgRed, State: sealing.CommitFinalizeFailed},
{Col: color.FgRed, State: sealing.PackingFailed},
{Col: color.FgRed, State: sealing.FinalizeFailed},
{Col: color.FgRed, State: sealing.Faulty},
{Col: color.FgRed, State: sealing.FaultReported},
{Col: color.FgRed, State: sealing.FaultedFinal},
{Col: color.FgRed, State: sealing.RemoveFailed},
{Col: color.FgRed, State: sealing.DealsExpired},
{Col: color.FgRed, State: sealing.RecoverDealIDs},
{Col: color.FgRed, State: sealing.SnapDealsAddPieceFailed},
{Col: color.FgRed, State: sealing.SnapDealsDealsExpired},
{Col: color.FgRed, State: sealing.ReplicaUpdateFailed},
{Col: color.FgRed, State: sealing.ReleaseSectorKeyFailed},
{Col: color.FgRed, State: sealing.FinalizeReplicaUpdateFailed},
}
func init() {
for i, state := range StateList {
StateOrder[state.State] = StateMeta{
I: i,
Col: state.Col,
}
}
}
+9
View File
@@ -0,0 +1,9 @@
package spcli
import (
"github.com/urfave/cli/v2"
"github.com/filecoin-project/go-address"
)
type ActorAddressGetter func(cctx *cli.Context) (address address.Address, err error)
-147
View File
@@ -17,10 +17,8 @@ import (
"text/tabwriter"
"time"
"github.com/fatih/color"
"github.com/ipfs/go-cid"
cbor "github.com/ipfs/go-ipld-cbor"
"github.com/multiformats/go-multiaddr"
"github.com/urfave/cli/v2"
cbg "github.com/whyrusleeping/cbor-gen"
"golang.org/x/xerrors"
@@ -47,43 +45,6 @@ import (
cliutil "github.com/filecoin-project/lotus/cli/util"
)
var StateCmd = &cli.Command{
Name: "state",
Usage: "Interact with and query filecoin chain state",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "tipset",
Usage: "specify tipset to call method on (pass comma separated array of cids)",
},
},
Subcommands: []*cli.Command{
StatePowerCmd,
StateSectorsCmd,
StateActiveSectorsCmd,
StateListActorsCmd,
StateListMinersCmd,
StateCircSupplyCmd,
StateSectorCmd,
StateGetActorCmd,
StateLookupIDCmd,
StateReplayCmd,
StateSectorSizeCmd,
StateReadStateCmd,
StateListMessagesCmd,
StateComputeStateCmd,
StateCallCmd,
StateGetDealSetCmd,
StateWaitMsgCmd,
StateSearchMsgCmd,
StateMinerInfo,
StateMarketCmd,
StateExecTraceCmd,
StateNtwkVersionCmd,
StateMinerProvingDeadlineCmd,
StateSysActorCIDsCmd,
},
}
var StateMinerProvingDeadlineCmd = &cli.Command{
Name: "miner-proving-deadline",
Usage: "Retrieve information about a given miner's proving deadline",
@@ -127,114 +88,6 @@ var StateMinerProvingDeadlineCmd = &cli.Command{
},
}
var StateMinerInfo = &cli.Command{
Name: "miner-info",
Usage: "Retrieve miner information",
ArgsUsage: "[minerAddress]",
Action: func(cctx *cli.Context) error {
api, closer, err := GetFullNodeAPI(cctx)
if err != nil {
return err
}
defer closer()
ctx := ReqContext(cctx)
if cctx.NArg() != 1 {
return IncorrectNumArgs(cctx)
}
addr, err := address.NewFromString(cctx.Args().First())
if err != nil {
return err
}
ts, err := LoadTipSet(ctx, cctx, api)
if err != nil {
return err
}
mi, err := api.StateMinerInfo(ctx, addr, ts.Key())
if err != nil {
return err
}
availableBalance, err := api.StateMinerAvailableBalance(ctx, addr, ts.Key())
if err != nil {
return xerrors.Errorf("getting miner available balance: %w", err)
}
fmt.Printf("Available Balance: %s\n", types.FIL(availableBalance))
fmt.Printf("Owner:\t%s\n", mi.Owner)
fmt.Printf("Worker:\t%s\n", mi.Worker)
for i, controlAddress := range mi.ControlAddresses {
fmt.Printf("Control %d: \t%s\n", i, controlAddress)
}
if mi.Beneficiary != address.Undef {
fmt.Printf("Beneficiary:\t%s\n", mi.Beneficiary)
if mi.Beneficiary != mi.Owner {
fmt.Printf("Beneficiary Quota:\t%s\n", mi.BeneficiaryTerm.Quota)
fmt.Printf("Beneficiary Used Quota:\t%s\n", mi.BeneficiaryTerm.UsedQuota)
fmt.Printf("Beneficiary Expiration:\t%s\n", mi.BeneficiaryTerm.Expiration)
}
}
if mi.PendingBeneficiaryTerm != nil {
fmt.Printf("Pending Beneficiary Term:\n")
fmt.Printf("New Beneficiary:\t%s\n", mi.PendingBeneficiaryTerm.NewBeneficiary)
fmt.Printf("New Quota:\t%s\n", mi.PendingBeneficiaryTerm.NewQuota)
fmt.Printf("New Expiration:\t%s\n", mi.PendingBeneficiaryTerm.NewExpiration)
fmt.Printf("Approved By Beneficiary:\t%t\n", mi.PendingBeneficiaryTerm.ApprovedByBeneficiary)
fmt.Printf("Approved By Nominee:\t%t\n", mi.PendingBeneficiaryTerm.ApprovedByNominee)
}
fmt.Printf("PeerID:\t%s\n", mi.PeerId)
fmt.Printf("Multiaddrs:\t")
for _, addr := range mi.Multiaddrs {
a, err := multiaddr.NewMultiaddrBytes(addr)
if err != nil {
return xerrors.Errorf("undecodable listen address: %w", err)
}
fmt.Printf("%s ", a)
}
fmt.Println()
fmt.Printf("Consensus Fault End:\t%d\n", mi.ConsensusFaultElapsed)
fmt.Printf("SectorSize:\t%s (%d)\n", types.SizeStr(types.NewInt(uint64(mi.SectorSize))), mi.SectorSize)
pow, err := api.StateMinerPower(ctx, addr, ts.Key())
if err != nil {
return err
}
fmt.Printf("Byte Power: %s / %s (%0.4f%%)\n",
color.BlueString(types.SizeStr(pow.MinerPower.RawBytePower)),
types.SizeStr(pow.TotalPower.RawBytePower),
types.BigDivFloat(
types.BigMul(pow.MinerPower.RawBytePower, big.NewInt(100)),
pow.TotalPower.RawBytePower,
),
)
fmt.Printf("Actual Power: %s / %s (%0.4f%%)\n",
color.GreenString(types.DeciStr(pow.MinerPower.QualityAdjPower)),
types.DeciStr(pow.TotalPower.QualityAdjPower),
types.BigDivFloat(
types.BigMul(pow.MinerPower.QualityAdjPower, big.NewInt(100)),
pow.TotalPower.QualityAdjPower,
),
)
fmt.Println()
cd, err := api.StateMinerProvingDeadline(ctx, addr, ts.Key())
if err != nil {
return xerrors.Errorf("getting miner info: %w", err)
}
fmt.Printf("Proving Period Start:\t%s\n", cliutil.EpochTime(cd.CurrentEpoch, cd.PeriodStart))
return nil
},
}
func ParseTipSetString(ts string) ([]cid.Cid, error) {
strs := strings.Split(ts, ",")
+1 -1
View File
@@ -27,7 +27,7 @@ import (
"github.com/filecoin-project/lotus/lib/tablewriter"
)
var walletCmd = &cli.Command{
var WalletCmd = &cli.Command{
Name: "wallet",
Usage: "Manage wallet",
Subcommands: []*cli.Command{