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
parent 8062f200bd
commit b95e95f4d6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
44 changed files with 4765 additions and 3383 deletions

2
.gitignore vendored
View File

@ -7,6 +7,7 @@
/lotus-shed
/lotus-sim
/curio
/sptool
/lotus-townhall
/lotus-fountain
/lotus-stats
@ -36,7 +37,6 @@ build/paramfetch.sh
/darwin
/linux
*.snap
curio
devgen.car
localnet.json

View File

@ -66,7 +66,7 @@ CLEAN+=build/.update-modules
deps: $(BUILD_DEPS)
.PHONY: deps
build-devnets: build lotus-seed lotus-shed curio
build-devnets: build lotus-seed lotus-shed curio sptool
.PHONY: build-devnets
debug: GOFLAGS+=-tags=debug
@ -106,6 +106,12 @@ BINS+=curio
cu2k: GOFLAGS+=-tags=2k
cu2k: curio
sptool: $(BUILD_DEPS)
rm -f sptool
$(GOCC) build $(GOFLAGS) -o sptool ./cmd/sptool
.PHONY: sptool
BINS+=sptool
lotus-worker: $(BUILD_DEPS)
rm -f lotus-worker
$(GOCC) build $(GOFLAGS) -o lotus-worker ./cmd/lotus-worker
@ -124,13 +130,13 @@ lotus-gateway: $(BUILD_DEPS)
.PHONY: lotus-gateway
BINS+=lotus-gateway
build: lotus lotus-miner lotus-worker curio
build: lotus lotus-miner lotus-worker curio sptool
@[[ $$(type -P "lotus") ]] && echo "Caution: you have \
an existing lotus binary in your PATH. This may cause problems if you don't run 'sudo make install'" || true
.PHONY: build
install: install-daemon install-miner install-worker install-curio
install: install-daemon install-miner install-worker install-curio install-sptool
install-daemon:
install -C ./lotus /usr/local/bin/lotus
@ -141,6 +147,9 @@ install-miner:
install-curio:
install -C ./curio /usr/local/bin/curio
install-sptool:
install -C ./sptool /usr/local/bin/sptool
install-worker:
install -C ./lotus-worker /usr/local/bin/lotus-worker
@ -159,6 +168,9 @@ uninstall-miner:
uninstall-curio:
rm -f /usr/local/bin/curio
uninstall-sptool:
rm -f /usr/local/bin/sptool
uninstall-worker:
rm -f /usr/local/bin/lotus-worker
@ -260,7 +272,7 @@ install-miner-service: install-miner install-daemon-service
@echo "To start the service, run: 'sudo systemctl start lotus-miner'"
@echo "To enable the service on startup, run: 'sudo systemctl enable lotus-miner'"
install-curio-service: install-curio install-daemon-service
install-curio-service: install-curio install-sptool install-daemon-service
mkdir -p /etc/systemd/system
mkdir -p /var/log/lotus
install -C -m 0644 ./scripts/curio.service /etc/systemd/system/curio.service
@ -401,12 +413,12 @@ gen: actors-code-gen type-gen cfgdoc-gen docsgen api-gen circleci
jen: gen
snap: lotus lotus-miner lotus-worker curio
snap: lotus lotus-miner lotus-worker curio sptool
snapcraft
# snapcraft upload ./lotus_*.snap
# separate from gen because it needs binaries
docsgen-cli: lotus lotus-miner lotus-worker curio
docsgen-cli: lotus lotus-miner lotus-worker curio sptool
python3 ./scripts/generate-lotus-cli.py
./lotus config default > documentation/en/default-lotus-config.toml
./lotus-miner config default > documentation/en/default-lotus-miner-config.toml

30
cli/clicommands/cmd.go Normal file
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
cli/clicommands/state.go Normal file
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
},
}

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{

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

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{},

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,

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{

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{

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]",

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
cli/spcli/actor.go Normal file

File diff suppressed because it is too large Load Diff

121
cli/spcli/info.go Normal file
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
cli/spcli/proving.go Normal file
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
cli/spcli/sectors.go Normal file

File diff suppressed because it is too large Load Diff

95
cli/spcli/statemeta.go Normal file
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
cli/spcli/util.go Normal file
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)

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, ",")

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{

File diff suppressed because it is too large Load Diff

View File

@ -19,6 +19,7 @@ import (
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/chain/actors/policy"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/cli/spcli"
"github.com/filecoin-project/lotus/itests/kit"
"github.com/filecoin-project/lotus/node/repo"
)
@ -67,7 +68,7 @@ func TestWorkerKeyChange(t *testing.T) {
// Initialize wallet.
kit.SendFunds(ctx, t, client1, newKey, abi.NewTokenAmount(0))
require.NoError(t, run(actorProposeChangeWorker, "--really-do-it", newKey.String()))
require.NoError(t, run(spcli.ActorProposeChangeWorkerCmd(LMActorGetter), "--really-do-it", newKey.String()))
result := output.String()
output.Reset()
@ -82,12 +83,12 @@ func TestWorkerKeyChange(t *testing.T) {
require.NotZero(t, targetEpoch)
// Too early.
require.Error(t, run(actorConfirmChangeWorker, "--really-do-it", newKey.String()))
require.Error(t, run(spcli.ActorConfirmChangeWorkerCmd(LMActorGetter), "--really-do-it", newKey.String()))
output.Reset()
client1.WaitTillChain(ctx, kit.HeightAtLeast(abi.ChainEpoch(targetEpoch)))
require.NoError(t, run(actorConfirmChangeWorker, "--really-do-it", newKey.String()))
require.NoError(t, run(spcli.ActorConfirmChangeWorkerCmd(LMActorGetter), "--really-do-it", newKey.String()))
output.Reset()
head, err := client1.ChainHead(ctx)

View File

@ -29,6 +29,7 @@ import (
"github.com/filecoin-project/lotus/chain/actors/builtin/reward"
"github.com/filecoin-project/lotus/chain/types"
lcli "github.com/filecoin-project/lotus/cli"
"github.com/filecoin-project/lotus/cli/spcli"
cliutil "github.com/filecoin-project/lotus/cli/util"
"github.com/filecoin-project/lotus/journal/alerting"
sealing "github.com/filecoin-project/lotus/storage/pipeline"
@ -369,94 +370,6 @@ func handleMiningInfo(ctx context.Context, cctx *cli.Context, fullapi v1api.Full
return nil
}
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,
}
}
}
func sectorsInfo(ctx context.Context, mapi api.StorageMiner) error {
summary, err := mapi.SectorsSummary(ctx)
if err != nil {
@ -471,17 +384,17 @@ func sectorsInfo(ctx context.Context, mapi api.StorageMiner) error {
}
buckets["Total"] = total
var sorted []stateMeta
var sorted []spcli.StateMeta
for state, i := range buckets {
sorted = append(sorted, stateMeta{i: i, state: state})
sorted = append(sorted, spcli.StateMeta{I: i, State: state})
}
sort.Slice(sorted, func(i, j int) bool {
return stateOrder[sorted[i].state].i < stateOrder[sorted[j].state].i
return spcli.StateOrder[sorted[i].State].I < spcli.StateOrder[sorted[j].State].I
})
for _, s := range sorted {
_, _ = color.New(stateOrder[s.state].col).Printf("\t%s: %d\n", s.state, s.i)
_, _ = color.New(spcli.StateOrder[s.State].Col).Printf("\t%s: %d\n", s.State, s.I)
}
return nil

View File

@ -8,6 +8,7 @@ import (
"github.com/urfave/cli/v2"
lcli "github.com/filecoin-project/lotus/cli"
"github.com/filecoin-project/lotus/cli/spcli"
)
var _test = false
@ -82,17 +83,17 @@ var infoAllCmd = &cli.Command{
}
fmt.Println("\n#: Proving Info")
if err := provingInfoCmd.Action(cctx); err != nil {
if err := spcli.ProvingInfoCmd(LMActorOrEnvGetter).Action(cctx); err != nil {
fmt.Println("ERROR: ", err)
}
fmt.Println("\n#: Proving Deadlines")
if err := provingDeadlinesCmd.Action(cctx); err != nil {
if err := spcli.ProvingDeadlinesCmd(LMActorOrEnvGetter).Action(cctx); err != nil {
fmt.Println("ERROR: ", err)
}
fmt.Println("\n#: Proving Faults")
if err := provingFaultsCmd.Action(cctx); err != nil {
if err := spcli.ProvingFaultsCmd(LMActorOrEnvGetter).Action(cctx); err != nil {
fmt.Println("ERROR: ", err)
}
@ -237,7 +238,7 @@ var infoAllCmd = &cli.Command{
fmt.Printf("\n##: Sector %d Status\n", s)
fs := &flag.FlagSet{}
for _, f := range sectorsStatusCmd.Flags {
for _, f := range spcli.SectorsStatusCmd(LMActorOrEnvGetter, getOnDiskInfo).Flags {
if err := f.Apply(fs); err != nil {
fmt.Println("ERROR: ", err)
}
@ -246,7 +247,7 @@ var infoAllCmd = &cli.Command{
fmt.Println("ERROR: ", err)
}
if err := sectorsStatusCmd.Action(cli.NewContext(cctx.App, fs, cctx)); err != nil {
if err := spcli.SectorsStatusCmd(LMActorOrEnvGetter, getOnDiskInfo).Action(cli.NewContext(cctx.App, fs, cctx)); err != nil {
fmt.Println("ERROR: ", err)
}

View File

@ -197,3 +197,17 @@ func setHidden(cmd *cli.Command) *cli.Command {
cmd.Hidden = true
return cmd
}
func LMActorOrEnvGetter(cctx *cli.Context) (address.Address, error) {
return getActorAddress(cctx.Context, cctx)
}
func LMActorGetter(cctx *cli.Context) (address.Address, error) {
minerApi, closer, err := lcli.GetStorageMinerAPI(cctx)
if err != nil {
return address.Undef, err
}
defer closer()
return minerApi.ActorAddress(cctx.Context)
}

View File

@ -1,56 +0,0 @@
package main
import (
"fmt"
"sort"
cbor "github.com/ipfs/go-ipld-cbor"
"github.com/urfave/cli/v2"
"github.com/filecoin-project/specs-actors/v7/actors/util/adt"
"github.com/filecoin-project/lotus/blockstore"
"github.com/filecoin-project/lotus/chain/actors/builtin/miner"
"github.com/filecoin-project/lotus/chain/types"
lcli "github.com/filecoin-project/lotus/cli"
)
var sectorPreCommitsCmd = &cli.Command{
Name: "precommits",
Usage: "Print on-chain precommit info",
Action: func(cctx *cli.Context) error {
ctx := lcli.ReqContext(cctx)
mapi, closer, err := lcli.GetFullNodeAPI(cctx)
if err != nil {
return err
}
defer closer()
maddr, err := getActorAddress(ctx, cctx)
if err != nil {
return err
}
mact, err := mapi.StateGetActor(ctx, maddr, types.EmptyTSK)
if err != nil {
return err
}
store := adt.WrapStore(ctx, cbor.NewCborStore(blockstore.NewAPIBlockstore(mapi)))
mst, err := miner.Load(store, mact)
if err != nil {
return err
}
preCommitSector := make([]miner.SectorPreCommitOnChainInfo, 0)
err = mst.ForEachPrecommittedSector(func(info miner.SectorPreCommitOnChainInfo) error {
preCommitSector = append(preCommitSector, info)
return err
})
less := func(i, j int) bool {
return preCommitSector[i].Info.SectorNumber <= preCommitSector[j].Info.SectorNumber
}
sort.Slice(preCommitSector, less)
for _, info := range preCommitSector {
fmt.Printf("%s: %s\n", info.Info.SectorNumber, info.PreCommitEpoch)
}
return nil
},
}

View File

@ -1,12 +1,10 @@
package main
import (
"bytes"
"encoding/json"
"fmt"
"os"
"strconv"
"strings"
"sync"
"text/tabwriter"
"time"
@ -17,18 +15,13 @@ import (
"golang.org/x/xerrors"
"github.com/filecoin-project/go-address"
"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/go-state-types/proof"
"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"
"github.com/filecoin-project/lotus/cli/spcli"
"github.com/filecoin-project/lotus/storage/sealer/storiface"
)
@ -36,10 +29,10 @@ var provingCmd = &cli.Command{
Name: "proving",
Usage: "View proving information",
Subcommands: []*cli.Command{
provingInfoCmd,
provingDeadlinesCmd,
provingDeadlineInfoCmd,
provingFaultsCmd,
spcli.ProvingInfoCmd(LMActorOrEnvGetter),
spcli.ProvingDeadlinesCmd(LMActorOrEnvGetter),
spcli.ProvingDeadlineInfoCmd(LMActorOrEnvGetter),
spcli.ProvingFaultsCmd(LMActorOrEnvGetter),
provingCheckProvableCmd,
workersCmd(false),
provingComputeCmd,
@ -47,422 +40,6 @@ var provingCmd = &cli.Command{
},
}
var provingFaultsCmd = &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(ctx, 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()
},
}
var provingInfoCmd = &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(ctx, 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
},
}
var provingDeadlinesCmd = &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(ctx, 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)
}
var provingDeadlineInfoCmd = &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(ctx, 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
},
}
var provingCheckProvableCmd = &cli.Command{
Name: "check",
Usage: "Check sectors provable",

File diff suppressed because it is too large Load Diff

View File

@ -27,6 +27,7 @@ import (
"github.com/filecoin-project/lotus/api/v0api"
"github.com/filecoin-project/lotus/chain/types"
lcli "github.com/filecoin-project/lotus/cli"
"github.com/filecoin-project/lotus/cli/spcli"
"github.com/filecoin-project/lotus/lib/tablewriter"
sealing "github.com/filecoin-project/lotus/storage/pipeline"
"github.com/filecoin-project/lotus/storage/sealer/fsutil"
@ -803,7 +804,7 @@ var storageListSectorsCmd = &cli.Command{
"Storage": color.New(sc1).Sprint(e.storage),
"Sector": e.id,
"Type": e.ft.String(),
"State": color.New(stateOrder[sealing.SectorState(e.state)].col).Sprint(e.state),
"State": color.New(spcli.StateOrder[sealing.SectorState(e.state)].Col).Sprint(e.state),
"Primary": maybeStr(e.primary, color.FgGreen, "primary") + maybeStr(e.copy, color.FgBlue, "copy") + maybeStr(e.main, color.FgRed, "main"),
"Path use": maybeStr(e.seal, color.FgMagenta, "seal ") + maybeStr(e.store, color.FgCyan, "store"),
"URLs": e.urls,
@ -995,7 +996,7 @@ var storageLocks = &cli.Command{
return xerrors.Errorf("getting sector status(%d): %w", lock.Sector.Number, err)
}
lockstr := fmt.Sprintf("%d\t%s\t", lock.Sector.Number, color.New(stateOrder[sealing.SectorState(st.State)].col).Sprint(st.State))
lockstr := fmt.Sprintf("%d\t%s\t", lock.Sector.Number, color.New(spcli.StateOrder[sealing.SectorState(st.State)].Col).Sprint(st.State))
for i := 0; i < storiface.FileTypes; i++ {
if lock.Write[i] > 0 {

View File

@ -31,6 +31,7 @@ import (
"github.com/filecoin-project/lotus/chain/actors"
"github.com/filecoin-project/lotus/chain/types"
lcli "github.com/filecoin-project/lotus/cli"
"github.com/filecoin-project/lotus/cli/spcli"
"github.com/filecoin-project/lotus/lib/parmap"
"github.com/filecoin-project/lotus/node/repo"
"github.com/filecoin-project/lotus/storage/paths"
@ -44,7 +45,7 @@ var sectorsCmd = &cli.Command{
Usage: "Tools for interacting with sectors",
Flags: []cli.Flag{},
Subcommands: []*cli.Command{
terminateSectorCmd,
spcli.TerminateSectorCmd(shedGetActor),
terminateSectorPenaltyEstimationCmd,
visAllocatedSectorsCmd,
dumpRLESectorCmd,
@ -53,138 +54,14 @@ var sectorsCmd = &cli.Command{
},
}
var terminateSectorCmd = &cli.Command{
Name: "terminate",
Usage: "Forcefully terminate a sector (WARNING: This means losing power and pay a one-time termination penalty(including collateral) for the terminated sector)",
ArgsUsage: "[sectorNum1 sectorNum2 ...]",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "actor",
Usage: "specify the address of miner actor",
},
&cli.BoolFlag{
Name: "really-do-it",
Usage: "pass this flag if you know what you are doing",
},
&cli.StringFlag{
Name: "from",
Usage: "specify the address to send the terminate message from",
},
},
Action: func(cctx *cli.Context) error {
if cctx.NArg() < 1 {
return lcli.ShowHelp(cctx, fmt.Errorf("at least one sector must be specified"))
}
func shedGetActor(cctx *cli.Context) (address.Address, error) {
minerApi, acloser, err := lcli.GetStorageMinerAPI(cctx)
if err != nil {
return address.Address{}, err
}
defer acloser()
var maddr address.Address
if act := cctx.String("actor"); act != "" {
var err error
maddr, err = address.NewFromString(act)
if err != nil {
return fmt.Errorf("parsing address %s: %w", act, err)
}
}
if !cctx.Bool("really-do-it") {
return fmt.Errorf("this is a command for advanced users, only use it if you are sure of what you are doing")
}
nodeApi, closer, err := lcli.GetFullNodeAPI(cctx)
if err != nil {
return err
}
defer closer()
ctx := lcli.ReqContext(cctx)
if maddr.Empty() {
minerApi, acloser, err := lcli.GetStorageMinerAPI(cctx)
if err != nil {
return err
}
defer acloser()
maddr, err = minerApi.ActorAddress(ctx)
if err != nil {
return err
}
}
mi, err := nodeApi.StateMinerInfo(ctx, maddr, types.EmptyTSK)
if err != nil {
return err
}
terminationDeclarationParams := []miner2.TerminationDeclaration{}
for _, sn := range cctx.Args().Slice() {
sectorNum, err := strconv.ParseUint(sn, 10, 64)
if err != nil {
return fmt.Errorf("could not parse sector number: %w", err)
}
sectorbit := bitfield.New()
sectorbit.Set(sectorNum)
loca, err := nodeApi.StateSectorPartition(ctx, maddr, abi.SectorNumber(sectorNum), types.EmptyTSK)
if err != nil {
return fmt.Errorf("get state sector partition %s", err)
}
para := miner2.TerminationDeclaration{
Deadline: loca.Deadline,
Partition: loca.Partition,
Sectors: sectorbit,
}
terminationDeclarationParams = append(terminationDeclarationParams, para)
}
terminateSectorParams := &miner2.TerminateSectorsParams{
Terminations: terminationDeclarationParams,
}
sp, err := actors.SerializeParams(terminateSectorParams)
if err != nil {
return xerrors.Errorf("serializing params: %w", err)
}
var fromAddr address.Address
if from := cctx.String("from"); from != "" {
var err error
fromAddr, err = address.NewFromString(from)
if err != nil {
return fmt.Errorf("parsing address %s: %w", from, err)
}
} else {
fromAddr = mi.Worker
}
smsg, err := nodeApi.MpoolPushMessage(ctx, &types.Message{
From: fromAddr,
To: maddr,
Method: builtin.MethodsMiner.TerminateSectors,
Value: big.Zero(),
Params: sp,
}, nil)
if err != nil {
return xerrors.Errorf("mpool push message: %w", err)
}
fmt.Println("sent termination message:", smsg.Cid())
wait, err := nodeApi.StateWaitMsg(ctx, smsg.Cid(), uint64(cctx.Int("confidence")))
if err != nil {
return err
}
if wait.Receipt.ExitCode.IsError() {
return fmt.Errorf("terminate sectors message returned exit %d", wait.Receipt.ExitCode)
}
return nil
},
return minerApi.ActorAddress(cctx.Context)
}
func findPenaltyInInternalExecutions(prefix string, trace []types.ExecutionTrace) {

View File

@ -13,6 +13,7 @@ import (
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/build"
lcli "github.com/filecoin-project/lotus/cli"
"github.com/filecoin-project/lotus/cli/clicommands"
cliutil "github.com/filecoin-project/lotus/cli/util"
"github.com/filecoin-project/lotus/lib/lotuslog"
"github.com/filecoin-project/lotus/lib/tracing"
@ -112,7 +113,7 @@ func main() {
return nil
},
Commands: append(local, lcli.Commands...),
Commands: append(local, clicommands.Commands...),
}
app.Setup()

140
cmd/sptool/actor.go Normal file
View File

@ -0,0 +1,140 @@
package main
import (
"fmt"
"os"
"strings"
"github.com/fatih/color"
"github.com/urfave/cli/v2"
"github.com/filecoin-project/go-address"
builtin2 "github.com/filecoin-project/lotus/chain/actors/builtin"
"github.com/filecoin-project/lotus/chain/types"
lcli "github.com/filecoin-project/lotus/cli"
"github.com/filecoin-project/lotus/cli/spcli"
"github.com/filecoin-project/lotus/lib/tablewriter"
)
var actorCmd = &cli.Command{
Name: "actor",
Usage: "Manage Filecoin Miner Actor Metadata",
Subcommands: []*cli.Command{
spcli.ActorSetAddrsCmd(SPTActorGetter),
spcli.ActorWithdrawCmd(SPTActorGetter),
spcli.ActorRepayDebtCmd(SPTActorGetter),
spcli.ActorSetPeeridCmd(SPTActorGetter),
spcli.ActorSetOwnerCmd(SPTActorGetter),
spcli.ActorControlCmd(SPTActorGetter, actorControlListCmd(SPTActorGetter)),
spcli.ActorProposeChangeWorkerCmd(SPTActorGetter),
spcli.ActorConfirmChangeWorkerCmd(SPTActorGetter),
spcli.ActorCompactAllocatedCmd(SPTActorGetter),
spcli.ActorProposeChangeBeneficiaryCmd(SPTActorGetter),
spcli.ActorConfirmChangeBeneficiaryCmd(SPTActorGetter),
},
}
func actorControlListCmd(getActor spcli.ActorAddressGetter) *cli.Command {
return &cli.Command{
Name: "list",
Usage: "Get currently set control addresses. Note: This excludes most roles as they are not known to the immediate chain state.",
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "verbose",
},
},
Action: func(cctx *cli.Context) error {
api, acloser, err := lcli.GetFullNodeAPIV1(cctx)
if err != nil {
return err
}
defer acloser()
ctx := lcli.ReqContext(cctx)
maddr, err := getActor(cctx)
if err != nil {
return err
}
mi, err := api.StateMinerInfo(ctx, maddr, types.EmptyTSK)
if err != nil {
return err
}
tw := tablewriter.New(
tablewriter.Col("name"),
tablewriter.Col("ID"),
tablewriter.Col("key"),
tablewriter.Col("use"),
tablewriter.Col("balance"),
)
post := map[address.Address]struct{}{}
for _, ca := range mi.ControlAddresses {
post[ca] = struct{}{}
}
printKey := func(name string, a address.Address) {
var actor *types.Actor
if actor, err = api.StateGetActor(ctx, a, types.EmptyTSK); err != nil {
fmt.Printf("%s\t%s: error getting actor: %s\n", name, a, err)
return
}
b := actor.Balance
var k = a
// 'a' maybe a 'robust', in that case, 'StateAccountKey' returns an error.
if builtin2.IsAccountActor(actor.Code) {
if k, err = api.StateAccountKey(ctx, a, types.EmptyTSK); err != nil {
fmt.Printf("%s\t%s: error getting account key: %s\n", name, a, err)
return
}
}
kstr := k.String()
if !cctx.Bool("verbose") {
if len(kstr) > 9 {
kstr = kstr[:6] + "..."
}
}
bstr := types.FIL(b).String()
switch {
case b.LessThan(types.FromFil(10)):
bstr = color.RedString(bstr)
case b.LessThan(types.FromFil(50)):
bstr = color.YellowString(bstr)
default:
bstr = color.GreenString(bstr)
}
var uses []string
if a == mi.Worker {
uses = append(uses, color.YellowString("other"))
}
if _, ok := post[a]; ok {
uses = append(uses, color.GreenString("post"))
}
tw.Write(map[string]interface{}{
"name": name,
"ID": a,
"key": kstr,
"use": strings.Join(uses, " "),
"balance": bstr,
})
}
printKey("owner", mi.Owner)
printKey("worker", mi.Worker)
printKey("beneficiary", mi.Beneficiary)
for i, ca := range mi.ControlAddresses {
printKey(fmt.Sprintf("control-%d", i), ca)
}
return tw.Flush(os.Stdout)
},
}
}

84
cmd/sptool/main.go Normal file
View File

@ -0,0 +1,84 @@
package main
import (
"context"
"fmt"
"os"
"os/signal"
logging "github.com/ipfs/go-log/v2"
"github.com/urfave/cli/v2"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/cli/spcli"
)
var log = logging.Logger("sptool")
func main() {
local := []*cli.Command{
actorCmd,
spcli.InfoCmd(SPTActorGetter),
sectorsCmd,
provingCmd,
//multiSigCmd,
}
app := &cli.App{
Name: "sptool",
Usage: "Manage Filecoin Miner Actor",
Version: build.UserVersion(),
Commands: local,
Flags: []cli.Flag{
&cli.StringFlag{
Name: "repo",
EnvVars: []string{"LOTUS_PATH"},
Hidden: true,
Value: "~/.lotus", // TODO: Consider XDG_DATA_HOME
},
&cli.StringFlag{
Name: "log-level",
Value: "info",
},
&cli.StringFlag{
Name: "actor",
Required: os.Getenv("LOTUS_DOCS_GENERATION") != "1",
Usage: "miner actor to manage",
EnvVars: []string{"SP_ADDRESS"},
},
},
Before: func(cctx *cli.Context) error {
return logging.SetLogLevel("sptool", cctx.String("sptool"))
},
}
// terminate early on ctrl+c
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt)
ctx, cancel := context.WithCancel(context.Background())
go func() {
<-c
cancel()
fmt.Println("Received interrupt, shutting down... Press CTRL+C again to force shutdown")
<-c
fmt.Println("Forcing stop")
os.Exit(1)
}()
if err := app.RunContext(ctx, os.Args); err != nil {
log.Errorf("%+v", err)
os.Exit(1)
return
}
}
func SPTActorGetter(cctx *cli.Context) (address.Address, error) {
addr, err := address.NewFromString(cctx.String("actor"))
if err != nil {
return address.Undef, fmt.Errorf("parsing address: %w", err)
}
return addr, nil
}

18
cmd/sptool/proving.go Normal file
View File

@ -0,0 +1,18 @@
package main
import (
"github.com/urfave/cli/v2"
"github.com/filecoin-project/lotus/cli/spcli"
)
var provingCmd = &cli.Command{
Name: "proving",
Usage: "View proving information",
Subcommands: []*cli.Command{
spcli.ProvingInfoCmd(SPTActorGetter),
spcli.ProvingDeadlinesCmd(SPTActorGetter),
spcli.ProvingDeadlineInfoCmd(SPTActorGetter),
spcli.ProvingFaultsCmd(SPTActorGetter),
},
}

356
cmd/sptool/sector.go Normal file
View File

@ -0,0 +1,356 @@
package main
import (
"fmt"
"os"
"sort"
"github.com/docker/go-units"
"github.com/fatih/color"
cbor "github.com/ipfs/go-ipld-cbor"
"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/big"
"github.com/filecoin-project/lotus/blockstore"
"github.com/filecoin-project/lotus/chain/actors/adt"
"github.com/filecoin-project/lotus/chain/actors/builtin/miner"
"github.com/filecoin-project/lotus/chain/actors/policy"
"github.com/filecoin-project/lotus/chain/types"
lcli "github.com/filecoin-project/lotus/cli"
"github.com/filecoin-project/lotus/cli/spcli"
cliutil "github.com/filecoin-project/lotus/cli/util"
"github.com/filecoin-project/lotus/lib/tablewriter"
)
var sectorsCmd = &cli.Command{
Name: "sectors",
Usage: "interact with sector store",
Subcommands: []*cli.Command{
spcli.SectorsStatusCmd(SPTActorGetter, nil),
sectorsListCmd, // in-house b/c chain-only is so different. Needs Curio *web* implementation
spcli.SectorPreCommitsCmd(SPTActorGetter),
spcli.SectorsCheckExpireCmd(SPTActorGetter),
sectorsExpiredCmd, // in-house b/c chain-only is so different
spcli.SectorsExtendCmd(SPTActorGetter),
//spcli.SectorsTerminateCmd(SPTActorGetter), // Could not trace through the state-machine
spcli.SectorsCompactPartitionsCmd(SPTActorGetter),
}}
var sectorsExpiredCmd = &cli.Command{
Name: "expired",
Usage: "Get or cleanup expired sectors",
Flags: []cli.Flag{
&cli.Int64Flag{
Name: "expired-epoch",
Usage: "epoch at which to check sector expirations",
DefaultText: "WinningPoSt lookback epoch",
},
},
Action: func(cctx *cli.Context) error {
fullApi, nCloser, err := lcli.GetFullNodeAPI(cctx)
if err != nil {
return xerrors.Errorf("getting fullnode api: %w", err)
}
defer nCloser()
ctx := lcli.ReqContext(cctx)
head, err := fullApi.ChainHead(ctx)
if err != nil {
return xerrors.Errorf("getting chain head: %w", err)
}
lbEpoch := abi.ChainEpoch(cctx.Int64("expired-epoch"))
if !cctx.IsSet("expired-epoch") {
nv, err := fullApi.StateNetworkVersion(ctx, head.Key())
if err != nil {
return xerrors.Errorf("getting network version: %w", err)
}
lbEpoch = head.Height() - policy.GetWinningPoStSectorSetLookback(nv)
if lbEpoch < 0 {
return xerrors.Errorf("too early to terminate sectors")
}
}
if cctx.IsSet("confirm-remove-count") && !cctx.IsSet("expired-epoch") {
return xerrors.Errorf("--expired-epoch must be specified with --confirm-remove-count")
}
lbts, err := fullApi.ChainGetTipSetByHeight(ctx, lbEpoch, head.Key())
if err != nil {
return xerrors.Errorf("getting lookback tipset: %w", err)
}
maddr, err := SPTActorGetter(cctx)
if err != nil {
return xerrors.Errorf("getting actor address: %w", err)
}
// toCheck is a working bitfield which will only contain terminated sectors
toCheck := bitfield.New()
{
sectors, err := fullApi.StateMinerSectors(ctx, maddr, nil, lbts.Key())
if err != nil {
return xerrors.Errorf("getting sector on chain info: %w", err)
}
for _, sector := range sectors {
if sector.Expiration <= lbts.Height() {
toCheck.Set(uint64(sector.SectorNumber))
}
}
}
mact, err := fullApi.StateGetActor(ctx, maddr, lbts.Key())
if err != nil {
return err
}
tbs := blockstore.NewTieredBstore(blockstore.NewAPIBlockstore(fullApi), blockstore.NewMemory())
mas, err := miner.Load(adt.WrapStore(ctx, cbor.NewCborStore(tbs)), mact)
if err != nil {
return err
}
alloc, err := mas.GetAllocatedSectors()
if err != nil {
return xerrors.Errorf("getting allocated sectors: %w", err)
}
// only allocated sectors can be expired,
toCheck, err = bitfield.IntersectBitField(toCheck, *alloc)
if err != nil {
return xerrors.Errorf("intersecting bitfields: %w", err)
}
if err := mas.ForEachDeadline(func(dlIdx uint64, dl miner.Deadline) error {
return dl.ForEachPartition(func(partIdx uint64, part miner.Partition) error {
live, err := part.LiveSectors()
if err != nil {
return err
}
toCheck, err = bitfield.SubtractBitField(toCheck, live)
if err != nil {
return err
}
unproven, err := part.UnprovenSectors()
if err != nil {
return err
}
toCheck, err = bitfield.SubtractBitField(toCheck, unproven)
return err
})
}); err != nil {
return err
}
err = mas.ForEachPrecommittedSector(func(pci miner.SectorPreCommitOnChainInfo) error {
toCheck.Unset(uint64(pci.Info.SectorNumber))
return nil
})
if err != nil {
return err
}
// toCheck now only contains sectors which either failed to precommit or are expired/terminated
fmt.Printf("Sectors that either failed to precommit or are expired/terminated:\n")
err = toCheck.ForEach(func(u uint64) error {
fmt.Println(abi.SectorNumber(u))
return nil
})
if err != nil {
return err
}
return nil
},
}
var sectorsListCmd = &cli.Command{
Name: "list",
Usage: "List sectors",
Flags: []cli.Flag{
/*
&cli.BoolFlag{
Name: "show-removed",
Usage: "show removed sectors",
Aliases: []string{"r"},
},
&cli.BoolFlag{
Name: "fast",
Usage: "don't show on-chain info for better performance",
Aliases: []string{"f"},
},
&cli.BoolFlag{
Name: "events",
Usage: "display number of events the sector has received",
Aliases: []string{"e"},
},
&cli.BoolFlag{
Name: "initial-pledge",
Usage: "display initial pledge",
Aliases: []string{"p"},
},
&cli.BoolFlag{
Name: "seal-time",
Usage: "display how long it took for the sector to be sealed",
Aliases: []string{"t"},
},
&cli.StringFlag{
Name: "states",
Usage: "filter sectors by a comma-separated list of states",
},
&cli.BoolFlag{
Name: "unproven",
Usage: "only show sectors which aren't in the 'Proving' state",
Aliases: []string{"u"},
},
*/
},
Subcommands: []*cli.Command{
//sectorsListUpgradeBoundsCmd,
},
Action: func(cctx *cli.Context) error {
fullApi, closer2, err := lcli.GetFullNodeAPI(cctx) // TODO: consider storing full node address in config
if err != nil {
return err
}
defer closer2()
ctx := lcli.ReqContext(cctx)
maddr, err := SPTActorGetter(cctx)
if err != nil {
return err
}
head, err := fullApi.ChainHead(ctx)
if err != nil {
return err
}
activeSet, err := fullApi.StateMinerActiveSectors(ctx, maddr, head.Key())
if err != nil {
return err
}
activeIDs := make(map[abi.SectorNumber]struct{}, len(activeSet))
for _, info := range activeSet {
activeIDs[info.SectorNumber] = struct{}{}
}
sset, err := fullApi.StateMinerSectors(ctx, maddr, nil, head.Key())
if err != nil {
return err
}
commitedIDs := make(map[abi.SectorNumber]struct{}, len(sset))
for _, info := range sset {
commitedIDs[info.SectorNumber] = struct{}{}
}
sort.Slice(sset, func(i, j int) bool {
return sset[i].SectorNumber < sset[j].SectorNumber
})
tw := tablewriter.New(
tablewriter.Col("ID"),
tablewriter.Col("State"),
tablewriter.Col("OnChain"),
tablewriter.Col("Active"),
tablewriter.Col("Expiration"),
tablewriter.Col("SealTime"),
tablewriter.Col("Events"),
tablewriter.Col("Deals"),
tablewriter.Col("DealWeight"),
tablewriter.Col("VerifiedPower"),
tablewriter.Col("Pledge"),
tablewriter.NewLineCol("Error"),
tablewriter.NewLineCol("RecoveryTimeout"))
fast := cctx.Bool("fast")
for _, st := range sset {
s := st.SectorNumber
_, inSSet := commitedIDs[s]
_, inASet := activeIDs[s]
const verifiedPowerGainMul = 9
dw, vp := .0, .0
{
rdw := big.Add(st.DealWeight, st.VerifiedDealWeight)
dw = float64(big.Div(rdw, big.NewInt(int64(st.Expiration-st.Activation))).Uint64())
vp = float64(big.Div(big.Mul(st.VerifiedDealWeight, big.NewInt(verifiedPowerGainMul)), big.NewInt(int64(st.Expiration-st.Activation))).Uint64())
}
var deals int
for _, deal := range st.DealIDs {
if deal != 0 {
deals++
}
}
exp := st.Expiration
// if st.OnTime > 0 && st.OnTime < exp {
// exp = st.OnTime // Can be different when the sector was CC upgraded
// }
m := map[string]interface{}{
"ID": s,
//"State": color.New(spcli.StateOrder[sealing.SectorState(st.State)].Col).Sprint(st.State),
"OnChain": yesno(inSSet),
"Active": yesno(inASet),
}
if deals > 0 {
m["Deals"] = color.GreenString("%d", deals)
} else {
m["Deals"] = color.BlueString("CC")
// if st.ToUpgrade {
// m["Deals"] = color.CyanString("CC(upgrade)")
// }
}
if !fast {
if !inSSet {
m["Expiration"] = "n/a"
} else {
m["Expiration"] = cliutil.EpochTime(head.Height(), exp)
// if st.Early > 0 {
// m["RecoveryTimeout"] = color.YellowString(cliutil.EpochTime(head.Height(), st.Early))
// }
}
if inSSet && cctx.Bool("initial-pledge") {
m["Pledge"] = types.FIL(st.InitialPledge).Short()
}
}
if !fast && deals > 0 {
m["DealWeight"] = units.BytesSize(dw)
if vp > 0 {
m["VerifiedPower"] = color.GreenString(units.BytesSize(vp))
}
}
tw.Write(m)
}
return tw.Flush(os.Stdout)
},
}
func yesno(b bool) string {
if b {
return color.GreenString("YES")
}
return color.RedString("NO")
}

View File

@ -18,13 +18,12 @@ COMMANDS:
web Start Curio web interface
guided-setup Run the guided setup for migrating from lotus-miner to Curio
seal Manage the sealing pipeline
auth Manage RPC permissions
log Manage logging
wait-api Wait for lotus api to come online
fetch-params Fetch proving parameters
version Print version
help, h Shows a list of commands or help for one command
DEVELOPER:
auth Manage RPC permissions
log Manage logging
wait-api Wait for lotus api to come online
fetch-params Fetch proving parameters
GLOBAL OPTIONS:
--color use color in display output (default: depends on output being a TTY)
@ -348,18 +347,6 @@ OPTIONS:
--help, -h show help
```
## curio version
```
NAME:
curio version - Print version
USAGE:
curio version [command options] [arguments...]
OPTIONS:
--help, -h show help
```
## curio auth
```
NAME:
@ -487,9 +474,6 @@ NAME:
USAGE:
curio wait-api [command options] [arguments...]
CATEGORY:
DEVELOPER
OPTIONS:
--timeout value duration to wait till fail (default: 30s)
--help, -h show help
@ -503,8 +487,17 @@ NAME:
USAGE:
curio fetch-params [command options] [sectorSize]
CATEGORY:
DEVELOPER
OPTIONS:
--help, -h show help
```
## curio version
```
NAME:
curio version - Print version
USAGE:
curio version [command options] [arguments...]
OPTIONS:
--help, -h show help

View File

@ -10,21 +10,20 @@ VERSION:
1.27.0-dev
COMMANDS:
init Initialize a lotus miner repo
run Start a lotus miner process
stop Stop a running lotus miner
config Manage node config
backup Create node metadata backup
version Print version
help, h Shows a list of commands or help for one command
init Initialize a lotus miner repo
run Start a lotus miner process
stop Stop a running lotus miner
config Manage node config
backup Create node metadata backup
auth Manage RPC permissions
log Manage logging
wait-api Wait for lotus api to come online
fetch-params Fetch proving parameters
version Print version
help, h Shows a list of commands or help for one command
CHAIN:
actor manipulate the miner actor
info Print miner info
DEVELOPER:
auth Manage RPC permissions
log Manage logging
wait-api Wait for lotus api to come online
fetch-params Fetch proving parameters
STORAGE:
sectors interact with sector store
proving View proving information
@ -194,6 +193,150 @@ OPTIONS:
--help, -h show help
```
## lotus-miner auth
```
NAME:
lotus-miner auth - Manage RPC permissions
USAGE:
lotus-miner auth command [command options] [arguments...]
COMMANDS:
create-token Create token
api-info Get token with API info required to connect to this node
help, h Shows a list of commands or help for one command
OPTIONS:
--help, -h show help
```
### lotus-miner auth create-token
```
NAME:
lotus-miner auth create-token - Create token
USAGE:
lotus-miner auth create-token [command options] [arguments...]
OPTIONS:
--perm value permission to assign to the token, one of: read, write, sign, admin
--help, -h show help
```
### lotus-miner auth api-info
```
NAME:
lotus-miner auth api-info - Get token with API info required to connect to this node
USAGE:
lotus-miner auth api-info [command options] [arguments...]
OPTIONS:
--perm value permission to assign to the token, one of: read, write, sign, admin
--help, -h show help
```
## lotus-miner log
```
NAME:
lotus-miner log - Manage logging
USAGE:
lotus-miner log command [command options] [arguments...]
COMMANDS:
list List log systems
set-level Set log level
alerts Get alert states
help, h Shows a list of commands or help for one command
OPTIONS:
--help, -h show help
```
### lotus-miner log list
```
NAME:
lotus-miner log list - List log systems
USAGE:
lotus-miner log list [command options] [arguments...]
OPTIONS:
--help, -h show help
```
### lotus-miner log set-level
```
NAME:
lotus-miner log set-level - Set log level
USAGE:
lotus-miner log set-level [command options] [level]
DESCRIPTION:
Set the log level for logging systems:
The system flag can be specified multiple times.
eg) log set-level --system chain --system chainxchg debug
Available Levels:
debug
info
warn
error
Environment Variables:
GOLOG_LOG_LEVEL - Default log level for all log systems
GOLOG_LOG_FMT - Change output log format (json, nocolor)
GOLOG_FILE - Write logs to file
GOLOG_OUTPUT - Specify whether to output to file, stderr, stdout or a combination, i.e. file+stderr
OPTIONS:
--system value [ --system value ] limit to log system
--help, -h show help
```
### lotus-miner log alerts
```
NAME:
lotus-miner log alerts - Get alert states
USAGE:
lotus-miner log alerts [command options] [arguments...]
OPTIONS:
--all get all (active and inactive) alerts (default: false)
--help, -h show help
```
## lotus-miner wait-api
```
NAME:
lotus-miner wait-api - Wait for lotus api to come online
USAGE:
lotus-miner wait-api [command options] [arguments...]
OPTIONS:
--timeout value duration to wait till fail (default: 30s)
--help, -h show help
```
## lotus-miner fetch-params
```
NAME:
lotus-miner fetch-params - Fetch proving parameters
USAGE:
lotus-miner fetch-params [command options] [sectorSize]
OPTIONS:
--help, -h show help
```
## lotus-miner version
```
NAME:
@ -444,156 +587,6 @@ OPTIONS:
--help, -h show help
```
## lotus-miner auth
```
NAME:
lotus-miner auth - Manage RPC permissions
USAGE:
lotus-miner auth command [command options] [arguments...]
COMMANDS:
create-token Create token
api-info Get token with API info required to connect to this node
help, h Shows a list of commands or help for one command
OPTIONS:
--help, -h show help
```
### lotus-miner auth create-token
```
NAME:
lotus-miner auth create-token - Create token
USAGE:
lotus-miner auth create-token [command options] [arguments...]
OPTIONS:
--perm value permission to assign to the token, one of: read, write, sign, admin
--help, -h show help
```
### lotus-miner auth api-info
```
NAME:
lotus-miner auth api-info - Get token with API info required to connect to this node
USAGE:
lotus-miner auth api-info [command options] [arguments...]
OPTIONS:
--perm value permission to assign to the token, one of: read, write, sign, admin
--help, -h show help
```
## lotus-miner log
```
NAME:
lotus-miner log - Manage logging
USAGE:
lotus-miner log command [command options] [arguments...]
COMMANDS:
list List log systems
set-level Set log level
alerts Get alert states
help, h Shows a list of commands or help for one command
OPTIONS:
--help, -h show help
```
### lotus-miner log list
```
NAME:
lotus-miner log list - List log systems
USAGE:
lotus-miner log list [command options] [arguments...]
OPTIONS:
--help, -h show help
```
### lotus-miner log set-level
```
NAME:
lotus-miner log set-level - Set log level
USAGE:
lotus-miner log set-level [command options] [level]
DESCRIPTION:
Set the log level for logging systems:
The system flag can be specified multiple times.
eg) log set-level --system chain --system chainxchg debug
Available Levels:
debug
info
warn
error
Environment Variables:
GOLOG_LOG_LEVEL - Default log level for all log systems
GOLOG_LOG_FMT - Change output log format (json, nocolor)
GOLOG_FILE - Write logs to file
GOLOG_OUTPUT - Specify whether to output to file, stderr, stdout or a combination, i.e. file+stderr
OPTIONS:
--system value [ --system value ] limit to log system
--help, -h show help
```
### lotus-miner log alerts
```
NAME:
lotus-miner log alerts - Get alert states
USAGE:
lotus-miner log alerts [command options] [arguments...]
OPTIONS:
--all get all (active and inactive) alerts (default: false)
--help, -h show help
```
## lotus-miner wait-api
```
NAME:
lotus-miner wait-api - Wait for lotus api to come online
USAGE:
lotus-miner wait-api [command options] [arguments...]
CATEGORY:
DEVELOPER
OPTIONS:
--timeout value duration to wait till fail (default: 30s)
--help, -h show help
```
## lotus-miner fetch-params
```
NAME:
lotus-miner fetch-params - Fetch proving parameters
USAGE:
lotus-miner fetch-params [command options] [sectorSize]
CATEGORY:
DEVELOPER
OPTIONS:
--help, -h show help
```
## lotus-miner sectors
```
NAME:
@ -1039,7 +1032,6 @@ OPTIONS:
--deadline value the deadline to compact the partitions in (default: 0)
--partitions value [ --partitions value ] list of partitions to compact sectors in
--really-do-it Actually send transaction performing the action (default: false)
--actor value Specify the address of the miner to run this command
--help, -h show help
```

View File

@ -0,0 +1,441 @@
# sptool
```
NAME:
sptool - Manage Filecoin Miner Actor
USAGE:
sptool [global options] command [command options] [arguments...]
VERSION:
1.27.0-dev
COMMANDS:
actor Manage Filecoin Miner Actor Metadata
info Print miner actor info
sectors interact with sector store
proving View proving information
help, h Shows a list of commands or help for one command
GLOBAL OPTIONS:
--log-level value (default: "info")
--actor value miner actor to manage [$SP_ADDRESS]
--help, -h show help
--version, -v print the version
```
## sptool actor
```
NAME:
sptool actor - Manage Filecoin Miner Actor Metadata
USAGE:
sptool actor command [command options] [arguments...]
COMMANDS:
set-addresses, set-addrs set addresses that your miner can be publicly dialed on
withdraw withdraw available balance to beneficiary
repay-debt pay down a miner's debt
set-peer-id set the peer id of your miner
set-owner Set owner address (this command should be invoked twice, first with the old owner as the senderAddress, and then with the new owner)
control Manage control addresses
propose-change-worker Propose a worker address change
confirm-change-worker Confirm a worker address change
compact-allocated compact allocated sectors bitfield
propose-change-beneficiary Propose a beneficiary address change
confirm-change-beneficiary Confirm a beneficiary address change
help, h Shows a list of commands or help for one command
OPTIONS:
--help, -h show help
```
### sptool actor set-addresses
```
NAME:
sptool actor set-addresses - set addresses that your miner can be publicly dialed on
USAGE:
sptool actor set-addresses [command options] <multiaddrs>
OPTIONS:
--from value optionally specify the account to send the message from
--gas-limit value set gas limit (default: 0)
--unset unset address (default: false)
--help, -h show help
```
### sptool actor withdraw
```
NAME:
sptool actor withdraw - withdraw available balance to beneficiary
USAGE:
sptool actor withdraw [command options] [amount (FIL)]
OPTIONS:
--confidence value number of block confirmations to wait for (default: 5)
--beneficiary send withdraw message from the beneficiary address (default: false)
--help, -h show help
```
### sptool actor repay-debt
```
NAME:
sptool actor repay-debt - pay down a miner's debt
USAGE:
sptool actor repay-debt [command options] [amount (FIL)]
OPTIONS:
--from value optionally specify the account to send funds from
--help, -h show help
```
### sptool actor set-peer-id
```
NAME:
sptool actor set-peer-id - set the peer id of your miner
USAGE:
sptool actor set-peer-id [command options] <peer id>
OPTIONS:
--gas-limit value set gas limit (default: 0)
--help, -h show help
```
### sptool actor set-owner
```
NAME:
sptool actor set-owner - Set owner address (this command should be invoked twice, first with the old owner as the senderAddress, and then with the new owner)
USAGE:
sptool actor set-owner [command options] [newOwnerAddress senderAddress]
OPTIONS:
--really-do-it Actually send transaction performing the action (default: false)
--help, -h show help
```
### sptool actor control
```
NAME:
sptool actor control - Manage control addresses
USAGE:
sptool actor control command [command options] [arguments...]
COMMANDS:
list Get currently set control addresses. Note: This excludes most roles as they are not known to the immediate chain state.
set Set control address(-es)
help, h Shows a list of commands or help for one command
OPTIONS:
--help, -h show help
```
#### sptool actor control list
```
NAME:
sptool actor control list - Get currently set control addresses. Note: This excludes most roles as they are not known to the immediate chain state.
USAGE:
sptool actor control list [command options] [arguments...]
OPTIONS:
--verbose (default: false)
--help, -h show help
```
#### sptool actor control set
```
NAME:
sptool actor control set - Set control address(-es)
USAGE:
sptool actor control set [command options] [...address]
OPTIONS:
--really-do-it Actually send transaction performing the action (default: false)
--help, -h show help
```
### sptool actor propose-change-worker
```
NAME:
sptool actor propose-change-worker - Propose a worker address change
USAGE:
sptool actor propose-change-worker [command options] [address]
OPTIONS:
--really-do-it Actually send transaction performing the action (default: false)
--help, -h show help
```
### sptool actor confirm-change-worker
```
NAME:
sptool actor confirm-change-worker - Confirm a worker address change
USAGE:
sptool actor confirm-change-worker [command options] [address]
OPTIONS:
--really-do-it Actually send transaction performing the action (default: false)
--help, -h show help
```
### sptool actor compact-allocated
```
NAME:
sptool actor compact-allocated - compact allocated sectors bitfield
USAGE:
sptool actor compact-allocated [command options] [arguments...]
OPTIONS:
--mask-last-offset value Mask sector IDs from 0 to 'highest_allocated - offset' (default: 0)
--mask-upto-n value Mask sector IDs from 0 to 'n' (default: 0)
--really-do-it Actually send transaction performing the action (default: false)
--help, -h show help
```
### sptool actor propose-change-beneficiary
```
NAME:
sptool actor propose-change-beneficiary - Propose a beneficiary address change
USAGE:
sptool actor propose-change-beneficiary [command options] [beneficiaryAddress quota expiration]
OPTIONS:
--really-do-it Actually send transaction performing the action (default: false)
--overwrite-pending-change Overwrite the current beneficiary change proposal (default: false)
--actor value specify the address of miner actor
--help, -h show help
```
### sptool actor confirm-change-beneficiary
```
NAME:
sptool actor confirm-change-beneficiary - Confirm a beneficiary address change
USAGE:
sptool actor confirm-change-beneficiary [command options] [minerID]
OPTIONS:
--really-do-it Actually send transaction performing the action (default: false)
--existing-beneficiary send confirmation from the existing beneficiary address (default: false)
--new-beneficiary send confirmation from the new beneficiary address (default: false)
--help, -h show help
```
## sptool info
```
NAME:
sptool info - Print miner actor info
USAGE:
sptool info [command options] [arguments...]
OPTIONS:
--help, -h show help
```
## sptool sectors
```
NAME:
sptool sectors - interact with sector store
USAGE:
sptool sectors command [command options] [arguments...]
COMMANDS:
status Get the seal status of a sector by its number
list List sectors
precommits Print on-chain precommit info
check-expire Inspect expiring sectors
expired Get or cleanup expired sectors
extend Extend expiring sectors while not exceeding each sector's max life
compact-partitions removes dead sectors from partitions and reduces the number of partitions used if possible
help, h Shows a list of commands or help for one command
OPTIONS:
--help, -h show help
```
### sptool sectors status
```
NAME:
sptool sectors status - Get the seal status of a sector by its number
USAGE:
sptool sectors status [command options] <sectorNum>
OPTIONS:
--log, -l display event log (default: false)
--on-chain-info, -c show sector on chain info (default: false)
--partition-info, -p show partition related info (default: false)
--proof print snark proof bytes as hex (default: false)
--help, -h show help
```
### sptool sectors list
```
NAME:
sptool sectors list - List sectors
USAGE:
sptool sectors list [command options] [arguments...]
OPTIONS:
--help, -h show help
```
### sptool sectors precommits
```
NAME:
sptool sectors precommits - Print on-chain precommit info
USAGE:
sptool sectors precommits [command options] [arguments...]
OPTIONS:
--help, -h show help
```
### sptool sectors check-expire
```
NAME:
sptool sectors check-expire - Inspect expiring sectors
USAGE:
sptool sectors check-expire [command options] [arguments...]
OPTIONS:
--cutoff value skip sectors whose current expiration is more than <cutoff> epochs from now, defaults to 60 days (default: 172800)
--help, -h show help
```
### sptool sectors expired
```
NAME:
sptool sectors expired - Get or cleanup expired sectors
USAGE:
sptool sectors expired [command options] [arguments...]
OPTIONS:
--expired-epoch value epoch at which to check sector expirations (default: WinningPoSt lookback epoch)
--help, -h show help
```
### sptool sectors extend
```
NAME:
sptool sectors extend - Extend expiring sectors while not exceeding each sector's max life
USAGE:
sptool sectors extend [command options] <sectorNumbers...(optional)>
OPTIONS:
--from value only consider sectors whose current expiration epoch is in the range of [from, to], <from> defaults to: now + 120 (1 hour) (default: 0)
--to value only consider sectors whose current expiration epoch is in the range of [from, to], <to> defaults to: now + 92160 (32 days) (default: 0)
--sector-file value provide a file containing one sector number in each line, ignoring above selecting criteria
--exclude value optionally provide a file containing excluding sectors
--extension value try to extend selected sectors by this number of epochs, defaults to 540 days (default: 1555200)
--new-expiration value try to extend selected sectors to this epoch, ignoring extension (default: 0)
--only-cc only extend CC sectors (useful for making sector ready for snap upgrade) (default: false)
--drop-claims drop claims for sectors that can be extended, but only by dropping some of their verified power claims (default: false)
--tolerance value don't try to extend sectors by fewer than this number of epochs, defaults to 7 days (default: 20160)
--max-fee value use up to this amount of FIL for one message. pass this flag to avoid message congestion. (default: "0")
--max-sectors value the maximum number of sectors contained in each message (default: 0)
--really-do-it pass this flag to really extend sectors, otherwise will only print out json representation of parameters (default: false)
--help, -h show help
```
### sptool sectors compact-partitions
```
NAME:
sptool sectors compact-partitions - removes dead sectors from partitions and reduces the number of partitions used if possible
USAGE:
sptool sectors compact-partitions [command options] [arguments...]
OPTIONS:
--deadline value the deadline to compact the partitions in (default: 0)
--partitions value [ --partitions value ] list of partitions to compact sectors in
--really-do-it Actually send transaction performing the action (default: false)
--help, -h show help
```
## sptool proving
```
NAME:
sptool proving - View proving information
USAGE:
sptool proving command [command options] [arguments...]
COMMANDS:
info View current state information
deadlines View the current proving period deadlines information
deadline View the current proving period deadline information by its index
faults View the currently known proving faulty sectors information
help, h Shows a list of commands or help for one command
OPTIONS:
--help, -h show help
```
### sptool proving info
```
NAME:
sptool proving info - View current state information
USAGE:
sptool proving info [command options] [arguments...]
OPTIONS:
--help, -h show help
```
### sptool proving deadlines
```
NAME:
sptool proving deadlines - View the current proving period deadlines information
USAGE:
sptool proving deadlines [command options] [arguments...]
OPTIONS:
--all, -a Count all sectors (only live sectors are counted by default) (default: false)
--help, -h show help
```
### sptool proving deadline
```
NAME:
sptool proving deadline - View the current proving period deadline information by its index
USAGE:
sptool proving deadline [command options] <deadlineIdx>
OPTIONS:
--sector-nums, -n Print sector/fault numbers belonging to this deadline (default: false)
--bitfield, -b Print partition bitfield stats (default: false)
--help, -h show help
```
### sptool proving faults
```
NAME:
sptool proving faults - View the currently known proving faulty sectors information
USAGE:
sptool proving faults [command options] [arguments...]
OPTIONS:
--help, -h show help
```

View File

@ -6,7 +6,7 @@ import (
"testing"
"time"
"github.com/filecoin-project/lotus/cli"
"github.com/filecoin-project/lotus/cli/clicommands"
"github.com/filecoin-project/lotus/itests/kit"
)
@ -23,5 +23,5 @@ func TestClient(t *testing.T) {
blockTime := 5 * time.Millisecond
client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC())
ens.InterconnectAll().BeginMining(blockTime)
kit.RunClientTest(t, cli.Commands, client)
kit.RunClientTest(t, clicommands.Commands, client)
}

View File

@ -24,7 +24,7 @@ import (
"github.com/filecoin-project/lotus/api/client"
"github.com/filecoin-project/lotus/chain/stmgr"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/cli"
"github.com/filecoin-project/lotus/cli/clicommands"
"github.com/filecoin-project/lotus/gateway"
"github.com/filecoin-project/lotus/itests/kit"
"github.com/filecoin-project/lotus/itests/multisig"
@ -231,7 +231,7 @@ func TestGatewayCLIDealFlow(t *testing.T) {
ctx := context.Background()
nodes := startNodesWithFunds(ctx, t, blocktime, maxLookbackCap, maxStateWaitLookbackLimit)
kit.RunClientTest(t, cli.Commands, nodes.lite)
kit.RunClientTest(t, clicommands.Commands, nodes.lite)
}
type testNodes struct {

View File

@ -13,14 +13,14 @@ import (
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/cli"
"github.com/filecoin-project/lotus/cli/clicommands"
"github.com/filecoin-project/lotus/itests/kit"
)
func RunMultisigTests(t *testing.T, client *kit.TestFullNode) {
// Create mock CLI
ctx := context.Background()
mockCLI := kit.NewMockCLI(ctx, t, cli.Commands, api.NodeFull)
mockCLI := kit.NewMockCLI(ctx, t, clicommands.Commands, api.NodeFull)
clientCLI := mockCLI.Client(client.ListenAddr)
// Create some wallets on the node to use for testing multisig

View File

@ -25,7 +25,7 @@ import (
"github.com/filecoin-project/lotus/chain/actors/builtin/paych"
"github.com/filecoin-project/lotus/chain/events"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/cli"
"github.com/filecoin-project/lotus/cli/clicommands"
"github.com/filecoin-project/lotus/itests/kit"
)
@ -51,7 +51,7 @@ func TestPaymentChannelsBasic(t *testing.T) {
creatorAddr, receiverAddr := startPaychCreatorReceiverMiner(ctx, t, &paymentCreator, &paymentReceiver, blocktime)
// Create mock CLI
mockCLI := kit.NewMockCLI(ctx, t, cli.Commands, api.NodeFull)
mockCLI := kit.NewMockCLI(ctx, t, clicommands.Commands, api.NodeFull)
creatorCLI := mockCLI.Client(paymentCreator.ListenAddr)
receiverCLI := mockCLI.Client(paymentReceiver.ListenAddr)
@ -126,7 +126,7 @@ func TestPaymentChannelStatus(t *testing.T) {
creatorAddr, receiverAddr := startPaychCreatorReceiverMiner(ctx, t, &paymentCreator, &paymentReceiver, blocktime)
// Create mock CLI
mockCLI := kit.NewMockCLI(ctx, t, cli.Commands, api.NodeFull)
mockCLI := kit.NewMockCLI(ctx, t, clicommands.Commands, api.NodeFull)
creatorCLI := mockCLI.Client(paymentCreator.ListenAddr)
// creator: paych status-by-from-to <creator> <receiver>
@ -212,7 +212,7 @@ func TestPaymentChannelVouchers(t *testing.T) {
creatorAddr, receiverAddr := startPaychCreatorReceiverMiner(ctx, t, &paymentCreator, &paymentReceiver, blocktime)
// Create mock CLI
mockCLI := kit.NewMockCLI(ctx, t, cli.Commands, api.NodeFull)
mockCLI := kit.NewMockCLI(ctx, t, clicommands.Commands, api.NodeFull)
creatorCLI := mockCLI.Client(paymentCreator.ListenAddr)
receiverCLI := mockCLI.Client(paymentReceiver.ListenAddr)
@ -350,7 +350,7 @@ func TestPaymentChannelVoucherCreateShortfall(t *testing.T) {
creatorAddr, receiverAddr := startPaychCreatorReceiverMiner(ctx, t, &paymentCreator, &paymentReceiver, blocktime)
// Create mock CLI
mockCLI := kit.NewMockCLI(ctx, t, cli.Commands, api.NodeFull)
mockCLI := kit.NewMockCLI(ctx, t, clicommands.Commands, api.NodeFull)
creatorCLI := mockCLI.Client(paymentCreator.ListenAddr)
// creator: paych add-funds <creator> <receiver> <amount>

View File

@ -1377,15 +1377,15 @@ func (sm *StorageMinerAPI) RuntimeSubsystems(context.Context) (res api.MinerSubs
}
func (sm *StorageMinerAPI) ActorWithdrawBalance(ctx context.Context, amount abi.TokenAmount) (cid.Cid, error) {
return sm.withdrawBalance(ctx, amount, true)
return WithdrawBalance(ctx, sm.Full, sm.Miner.Address(), amount, true)
}
func (sm *StorageMinerAPI) BeneficiaryWithdrawBalance(ctx context.Context, amount abi.TokenAmount) (cid.Cid, error) {
return sm.withdrawBalance(ctx, amount, false)
return WithdrawBalance(ctx, sm.Full, sm.Miner.Address(), amount, false)
}
func (sm *StorageMinerAPI) withdrawBalance(ctx context.Context, amount abi.TokenAmount, fromOwner bool) (cid.Cid, error) {
available, err := sm.Full.StateMinerAvailableBalance(ctx, sm.Miner.Address(), types.EmptyTSK)
func WithdrawBalance(ctx context.Context, full api.FullNode, maddr address.Address, amount abi.TokenAmount, fromOwner bool) (cid.Cid, error) {
available, err := full.StateMinerAvailableBalance(ctx, maddr, types.EmptyTSK)
if err != nil {
return cid.Undef, xerrors.Errorf("Error getting miner balance: %w", err)
}
@ -1405,7 +1405,7 @@ func (sm *StorageMinerAPI) withdrawBalance(ctx context.Context, amount abi.Token
return cid.Undef, err
}
mi, err := sm.Full.StateMinerInfo(ctx, sm.Miner.Address(), types.EmptyTSK)
mi, err := full.StateMinerInfo(ctx, maddr, types.EmptyTSK)
if err != nil {
return cid.Undef, xerrors.Errorf("Error getting miner's owner address: %w", err)
}
@ -1417,8 +1417,8 @@ func (sm *StorageMinerAPI) withdrawBalance(ctx context.Context, amount abi.Token
sender = mi.Beneficiary
}
smsg, err := sm.Full.MpoolPushMessage(ctx, &types.Message{
To: sm.Miner.Address(),
smsg, err := full.MpoolPushMessage(ctx, &types.Message{
To: maddr,
From: sender,
Value: types.NewInt(0),
Method: builtintypes.MethodsMiner.WithdrawBalance,

View File

@ -51,8 +51,12 @@ if __name__ == "__main__":
for e in [ "LOTUS_PATH", "LOTUS_MARKETS_PATH", "LOTUS_MINER_PATH", "LOTUS_STORAGE_PATH", "LOTUS_WORKER_PATH", "WORKER_PATH", "LOTUS_PANIC_REPORT_PATH", "WALLET_PATH" ]:
os.environ.pop(e, None)
# Set env var telling the binaries that we're generating docs
os.putenv("LOTUS_DOCS_GENERATION", "1")
os.putenv("LOTUS_VERSION_IGNORE_COMMIT", "1")
generate_lotus_cli('lotus')
generate_lotus_cli('lotus-miner')
generate_lotus_cli('lotus-worker')
generate_lotus_cli('curio')
generate_lotus_cli('curio')
generate_lotus_cli('sptool')