2019-07-27 21:08:10 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
2020-01-23 16:15:45 +00:00
|
|
|
"os"
|
2019-12-06 00:27:32 +00:00
|
|
|
"sort"
|
2019-07-27 21:08:10 +00:00
|
|
|
"strconv"
|
2020-01-23 16:15:45 +00:00
|
|
|
"text/tabwriter"
|
2020-01-23 14:18:05 +00:00
|
|
|
"time"
|
2019-07-27 21:08:10 +00:00
|
|
|
|
2020-06-02 18:12:53 +00:00
|
|
|
"github.com/urfave/cli/v2"
|
2020-06-05 22:59:01 +00:00
|
|
|
"golang.org/x/xerrors"
|
2019-07-27 21:08:10 +00:00
|
|
|
|
2020-04-06 20:27:14 +00:00
|
|
|
"github.com/filecoin-project/specs-actors/actors/abi"
|
|
|
|
|
2020-04-23 22:33:59 +00:00
|
|
|
"github.com/filecoin-project/lotus/api"
|
2020-04-06 20:27:14 +00:00
|
|
|
"github.com/filecoin-project/lotus/chain/types"
|
2019-10-18 04:47:41 +00:00
|
|
|
lcli "github.com/filecoin-project/lotus/cli"
|
2019-07-27 21:08:10 +00:00
|
|
|
)
|
|
|
|
|
2020-03-23 12:29:24 +00:00
|
|
|
var sectorsCmd = &cli.Command{
|
|
|
|
Name: "sectors",
|
|
|
|
Usage: "interact with sector store",
|
|
|
|
Subcommands: []*cli.Command{
|
|
|
|
sectorsStatusCmd,
|
|
|
|
sectorsListCmd,
|
|
|
|
sectorsRefsCmd,
|
|
|
|
sectorsUpdateCmd,
|
|
|
|
sectorsPledgeCmd,
|
2020-06-22 17:35:14 +00:00
|
|
|
sectorsRemoveCmd,
|
2020-07-01 14:49:17 +00:00
|
|
|
sectorsMarkForUpgradeCmd,
|
2020-07-03 21:05:59 +00:00
|
|
|
sectorsStartSealCmd,
|
2020-07-06 18:39:26 +00:00
|
|
|
sectorsSealDelayCmd,
|
2020-03-23 12:29:24 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
var sectorsPledgeCmd = &cli.Command{
|
|
|
|
Name: "pledge",
|
2019-07-27 21:08:10 +00:00
|
|
|
Usage: "store random data in a sector",
|
|
|
|
Action: func(cctx *cli.Context) error {
|
2019-10-03 18:12:30 +00:00
|
|
|
nodeApi, closer, err := lcli.GetStorageMinerAPI(cctx)
|
2019-07-27 21:08:10 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2019-10-03 18:12:30 +00:00
|
|
|
defer closer()
|
2019-07-27 21:08:10 +00:00
|
|
|
ctx := lcli.ReqContext(cctx)
|
|
|
|
|
2019-12-08 21:48:20 +00:00
|
|
|
return nodeApi.PledgeSector(ctx)
|
2019-07-27 21:08:10 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
var sectorsStatusCmd = &cli.Command{
|
2020-06-23 12:44:34 +00:00
|
|
|
Name: "status",
|
|
|
|
Usage: "Get the seal status of a sector by its number",
|
|
|
|
ArgsUsage: "<sectorNum>",
|
2020-01-23 14:18:05 +00:00
|
|
|
Flags: []cli.Flag{
|
|
|
|
&cli.BoolFlag{
|
|
|
|
Name: "log",
|
|
|
|
Usage: "display event log",
|
|
|
|
},
|
|
|
|
},
|
2019-07-27 21:08:10 +00:00
|
|
|
Action: func(cctx *cli.Context) error {
|
2019-10-03 18:12:30 +00:00
|
|
|
nodeApi, closer, err := lcli.GetStorageMinerAPI(cctx)
|
2019-07-27 21:08:10 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2019-10-03 18:12:30 +00:00
|
|
|
defer closer()
|
2019-07-27 21:08:10 +00:00
|
|
|
ctx := lcli.ReqContext(cctx)
|
|
|
|
|
|
|
|
if !cctx.Args().Present() {
|
2020-06-23 12:44:34 +00:00
|
|
|
return fmt.Errorf("must specify sector number to get status of")
|
2019-07-27 21:08:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
id, err := strconv.ParseUint(cctx.Args().First(), 10, 64)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2020-02-09 06:06:32 +00:00
|
|
|
status, err := nodeApi.SectorsStatus(ctx, abi.SectorNumber(id))
|
2019-07-27 21:08:10 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
fmt.Printf("SectorID:\t%d\n", status.SectorID)
|
2020-04-03 16:24:45 +00:00
|
|
|
fmt.Printf("Status:\t%s\n", status.State)
|
2019-07-27 21:08:10 +00:00
|
|
|
fmt.Printf("CommD:\t\t%x\n", status.CommD)
|
|
|
|
fmt.Printf("CommR:\t\t%x\n", status.CommR)
|
2020-02-27 21:45:31 +00:00
|
|
|
fmt.Printf("Ticket:\t\t%x\n", status.Ticket.Value)
|
|
|
|
fmt.Printf("TicketH:\t\t%d\n", status.Ticket.Epoch)
|
|
|
|
fmt.Printf("Seed:\t\t%x\n", status.Seed.Value)
|
|
|
|
fmt.Printf("SeedH:\t\t%d\n", status.Seed.Epoch)
|
2019-07-27 21:08:10 +00:00
|
|
|
fmt.Printf("Proof:\t\t%x\n", status.Proof)
|
2019-11-08 18:15:13 +00:00
|
|
|
fmt.Printf("Deals:\t\t%v\n", status.Deals)
|
2019-12-08 16:10:11 +00:00
|
|
|
fmt.Printf("Retries:\t\t%d\n", status.Retries)
|
2019-12-04 00:44:29 +00:00
|
|
|
if status.LastErr != "" {
|
|
|
|
fmt.Printf("Last Error:\t\t%s\n", status.LastErr)
|
|
|
|
}
|
2020-01-23 14:18:05 +00:00
|
|
|
|
|
|
|
if cctx.Bool("log") {
|
|
|
|
fmt.Printf("--------\nEvent Log:\n")
|
|
|
|
|
|
|
|
for i, l := range status.Log {
|
|
|
|
fmt.Printf("%d.\t%s:\t[%s]\t%s\n", i, time.Unix(int64(l.Timestamp), 0), l.Kind, l.Message)
|
|
|
|
if l.Trace != "" {
|
|
|
|
fmt.Printf("\t%s\n", l.Trace)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-07-27 21:08:10 +00:00
|
|
|
return nil
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2019-11-13 14:48:57 +00:00
|
|
|
var sectorsListCmd = &cli.Command{
|
|
|
|
Name: "list",
|
|
|
|
Usage: "List sectors",
|
2019-07-27 21:08:10 +00:00
|
|
|
Action: func(cctx *cli.Context) error {
|
2019-10-03 18:12:30 +00:00
|
|
|
nodeApi, closer, err := lcli.GetStorageMinerAPI(cctx)
|
2019-07-27 21:08:10 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2019-10-03 18:12:30 +00:00
|
|
|
defer closer()
|
2019-11-13 14:48:57 +00:00
|
|
|
|
|
|
|
fullApi, closer2, err := lcli.GetFullNodeAPI(cctx) // TODO: consider storing full node address in config
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer closer2()
|
|
|
|
|
2019-07-27 21:08:10 +00:00
|
|
|
ctx := lcli.ReqContext(cctx)
|
|
|
|
|
2019-11-13 14:48:57 +00:00
|
|
|
list, err := nodeApi.SectorsList(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
maddr, err := nodeApi.ActorAddress(ctx)
|
2019-07-27 21:08:10 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2020-07-17 14:26:48 +00:00
|
|
|
activeSet, err := fullApi.StateMinerActiveSectors(ctx, maddr, types.EmptyTSK)
|
2019-11-13 14:48:57 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-07-17 14:26:48 +00:00
|
|
|
activeIDs := make(map[abi.SectorNumber]struct{}, len(activeSet))
|
|
|
|
for _, info := range activeSet {
|
|
|
|
activeIDs[info.ID] = struct{}{}
|
2020-07-17 14:21:00 +00:00
|
|
|
}
|
2019-11-13 14:48:57 +00:00
|
|
|
|
2020-04-21 17:22:53 +00:00
|
|
|
sset, err := fullApi.StateMinerSectors(ctx, maddr, nil, true, types.EmptyTSK)
|
2019-11-13 14:48:57 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-07-17 14:26:48 +00:00
|
|
|
commitedIDs := make(map[abi.SectorNumber]struct{}, len(activeSet))
|
2019-11-13 14:48:57 +00:00
|
|
|
for _, info := range sset {
|
2020-02-21 18:20:22 +00:00
|
|
|
commitedIDs[info.ID] = struct{}{}
|
2019-11-13 14:48:57 +00:00
|
|
|
}
|
|
|
|
|
2019-12-06 00:27:32 +00:00
|
|
|
sort.Slice(list, func(i, j int) bool {
|
|
|
|
return list[i] < list[j]
|
|
|
|
})
|
|
|
|
|
2020-01-23 17:34:04 +00:00
|
|
|
w := tabwriter.NewWriter(os.Stdout, 8, 4, 1, ' ', 0)
|
2020-01-23 16:15:45 +00:00
|
|
|
|
2019-11-13 14:48:57 +00:00
|
|
|
for _, s := range list {
|
|
|
|
st, err := nodeApi.SectorsStatus(ctx, s)
|
|
|
|
if err != nil {
|
2020-01-23 16:15:45 +00:00
|
|
|
fmt.Fprintf(w, "%d:\tError: %s\n", s, err)
|
2019-11-13 14:48:57 +00:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
_, inSSet := commitedIDs[s]
|
2020-07-17 14:26:48 +00:00
|
|
|
_, inASet := activeIDs[s]
|
2019-11-13 14:48:57 +00:00
|
|
|
|
2020-07-17 14:26:48 +00:00
|
|
|
fmt.Fprintf(w, "%d: %s\tsSet: %s\tactive: %s\ttktH: %d\tseedH: %d\tdeals: %v\n",
|
2019-11-13 14:48:57 +00:00
|
|
|
s,
|
2020-04-03 16:24:45 +00:00
|
|
|
st.State,
|
2019-11-13 14:48:57 +00:00
|
|
|
yesno(inSSet),
|
2020-07-17 14:26:48 +00:00
|
|
|
yesno(inASet),
|
2020-02-27 21:45:31 +00:00
|
|
|
st.Ticket.Epoch,
|
|
|
|
st.Seed.Epoch,
|
2019-11-13 14:48:57 +00:00
|
|
|
st.Deals,
|
|
|
|
)
|
2019-07-27 21:08:10 +00:00
|
|
|
}
|
2020-01-23 16:15:45 +00:00
|
|
|
|
|
|
|
return w.Flush()
|
2019-07-27 21:08:10 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2019-08-26 10:04:57 +00:00
|
|
|
var sectorsRefsCmd = &cli.Command{
|
|
|
|
Name: "refs",
|
|
|
|
Usage: "List References to sectors",
|
|
|
|
Action: func(cctx *cli.Context) error {
|
2019-10-03 18:12:30 +00:00
|
|
|
nodeApi, closer, err := lcli.GetStorageMinerAPI(cctx)
|
2019-08-26 10:04:57 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2019-10-03 18:12:30 +00:00
|
|
|
defer closer()
|
2019-08-26 10:04:57 +00:00
|
|
|
ctx := lcli.ReqContext(cctx)
|
|
|
|
|
|
|
|
refs, err := nodeApi.SectorsRefs(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
for name, refs := range refs {
|
|
|
|
fmt.Printf("Block %s:\n", name)
|
|
|
|
for _, ref := range refs {
|
2019-12-01 17:58:31 +00:00
|
|
|
fmt.Printf("\t%d+%d %d bytes\n", ref.SectorID, ref.Offset, ref.Size)
|
2019-08-26 10:04:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
},
|
|
|
|
}
|
2019-11-13 14:48:57 +00:00
|
|
|
|
2020-06-22 17:35:14 +00:00
|
|
|
var sectorsRemoveCmd = &cli.Command{
|
2020-06-23 12:44:34 +00:00
|
|
|
Name: "remove",
|
|
|
|
Usage: "Forcefully remove a sector (WARNING: This means losing power and collateral for the removed sector)",
|
|
|
|
ArgsUsage: "<sectorNum>",
|
2020-06-22 17:35:14 +00:00
|
|
|
Flags: []cli.Flag{
|
|
|
|
&cli.BoolFlag{
|
|
|
|
Name: "really-do-it",
|
|
|
|
Usage: "pass this flag if you know what you are doing",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Action: func(cctx *cli.Context) error {
|
|
|
|
if !cctx.Bool("really-do-it") {
|
|
|
|
return xerrors.Errorf("this is a command for advanced users, only use it if you are sure of what you are doing")
|
|
|
|
}
|
|
|
|
nodeApi, closer, err := lcli.GetStorageMinerAPI(cctx)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer closer()
|
|
|
|
ctx := lcli.ReqContext(cctx)
|
|
|
|
if cctx.Args().Len() != 1 {
|
2020-06-23 12:44:34 +00:00
|
|
|
return xerrors.Errorf("must pass sector number")
|
2020-06-22 17:35:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
id, err := strconv.ParseUint(cctx.Args().Get(0), 10, 64)
|
|
|
|
if err != nil {
|
2020-06-23 12:44:34 +00:00
|
|
|
return xerrors.Errorf("could not parse sector number: %w", err)
|
2020-06-22 17:35:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return nodeApi.SectorRemove(ctx, abi.SectorNumber(id))
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2020-07-01 14:49:17 +00:00
|
|
|
var sectorsMarkForUpgradeCmd = &cli.Command{
|
|
|
|
Name: "mark-for-upgrade",
|
|
|
|
Usage: "Mark a committed capacity sector for replacement by a sector with deals",
|
|
|
|
ArgsUsage: "<sectorNum>",
|
|
|
|
Action: func(cctx *cli.Context) error {
|
|
|
|
nodeApi, closer, err := lcli.GetStorageMinerAPI(cctx)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer closer()
|
|
|
|
ctx := lcli.ReqContext(cctx)
|
|
|
|
if cctx.Args().Len() != 1 {
|
|
|
|
return xerrors.Errorf("must pass sector number")
|
|
|
|
}
|
|
|
|
|
|
|
|
id, err := strconv.ParseUint(cctx.Args().Get(0), 10, 64)
|
|
|
|
if err != nil {
|
|
|
|
return xerrors.Errorf("could not parse sector number: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nodeApi.SectorMarkForUpgrade(ctx, abi.SectorNumber(id))
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2020-07-03 21:05:59 +00:00
|
|
|
var sectorsStartSealCmd = &cli.Command{
|
|
|
|
Name: "seal",
|
|
|
|
Usage: "Manually start sealing a sector (filling any unused space with junk)",
|
|
|
|
ArgsUsage: "<sectorNum>",
|
|
|
|
Action: func(cctx *cli.Context) error {
|
|
|
|
nodeApi, closer, err := lcli.GetStorageMinerAPI(cctx)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer closer()
|
|
|
|
ctx := lcli.ReqContext(cctx)
|
|
|
|
if cctx.Args().Len() != 1 {
|
|
|
|
return xerrors.Errorf("must pass sector number")
|
|
|
|
}
|
|
|
|
|
|
|
|
id, err := strconv.ParseUint(cctx.Args().Get(0), 10, 64)
|
|
|
|
if err != nil {
|
|
|
|
return xerrors.Errorf("could not parse sector number: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nodeApi.SectorStartSealing(ctx, abi.SectorNumber(id))
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2020-07-06 18:39:26 +00:00
|
|
|
var sectorsSealDelayCmd = &cli.Command{
|
|
|
|
Name: "set-seal-delay",
|
|
|
|
Usage: "Set the time, in minutes, that a new sector waits for deals before sealing starts",
|
|
|
|
ArgsUsage: "<minutes>",
|
|
|
|
Action: func(cctx *cli.Context) error {
|
|
|
|
nodeApi, closer, err := lcli.GetStorageMinerAPI(cctx)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer closer()
|
|
|
|
ctx := lcli.ReqContext(cctx)
|
|
|
|
if cctx.Args().Len() != 1 {
|
|
|
|
return xerrors.Errorf("must pass duration in minutes")
|
|
|
|
}
|
|
|
|
|
|
|
|
hs, err := strconv.ParseUint(cctx.Args().Get(0), 10, 64)
|
|
|
|
if err != nil {
|
|
|
|
return xerrors.Errorf("could not parse sector number: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
delay := hs * uint64(time.Minute)
|
|
|
|
|
|
|
|
return nodeApi.SectorSetSealDelay(ctx, time.Duration(delay))
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2019-12-05 04:43:54 +00:00
|
|
|
var sectorsUpdateCmd = &cli.Command{
|
|
|
|
Name: "update-state",
|
|
|
|
Usage: "ADVANCED: manually update the state of a sector, this may aid in error recovery",
|
|
|
|
Flags: []cli.Flag{
|
|
|
|
&cli.BoolFlag{
|
|
|
|
Name: "really-do-it",
|
|
|
|
Usage: "pass this flag if you know what you are doing",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Action: func(cctx *cli.Context) error {
|
|
|
|
if !cctx.Bool("really-do-it") {
|
2019-12-05 11:15:39 +00:00
|
|
|
return xerrors.Errorf("this is a command for advanced users, only use it if you are sure of what you are doing")
|
2019-12-05 04:43:54 +00:00
|
|
|
}
|
|
|
|
nodeApi, closer, err := lcli.GetStorageMinerAPI(cctx)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer closer()
|
|
|
|
ctx := lcli.ReqContext(cctx)
|
|
|
|
if cctx.Args().Len() < 2 {
|
2020-06-23 12:44:34 +00:00
|
|
|
return xerrors.Errorf("must pass sector number and new state")
|
2019-12-05 04:43:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
id, err := strconv.ParseUint(cctx.Args().Get(0), 10, 64)
|
|
|
|
if err != nil {
|
2020-06-23 12:44:34 +00:00
|
|
|
return xerrors.Errorf("could not parse sector number: %w", err)
|
2019-12-05 04:43:54 +00:00
|
|
|
}
|
|
|
|
|
2020-04-23 22:33:59 +00:00
|
|
|
return nodeApi.SectorsUpdate(ctx, abi.SectorNumber(id), api.SectorState(cctx.Args().Get(1)))
|
2019-12-05 04:43:54 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2019-11-13 14:48:57 +00:00
|
|
|
func yesno(b bool) string {
|
|
|
|
if b {
|
|
|
|
return "YES"
|
|
|
|
}
|
|
|
|
return "NO"
|
|
|
|
}
|