diff --git a/cmd/lotus-miner/sectors.go b/cmd/lotus-miner/sectors.go index 4d241b282..968e92174 100644 --- a/cmd/lotus-miner/sectors.go +++ b/cmd/lotus-miner/sectors.go @@ -5,6 +5,7 @@ import ( "encoding/json" "errors" "fmt" + "math" "os" "sort" "strconv" @@ -2056,7 +2057,6 @@ func yesno(b bool) string { return color.RedString("NO") } -// TODO simulate this call if --really-do-it is not used var sectorsCompactPartitionsCmd = &cli.Command{ Name: "compact-partitions", Usage: "removes dead sectors from partitions and reduces the number of partitions used if possible", @@ -2082,12 +2082,7 @@ var sectorsCompactPartitionsCmd = &cli.Command{ }, }, Action: func(cctx *cli.Context) error { - if !cctx.Bool("really-do-it") { - fmt.Println("Pass --really-do-it to actually execute this action") - return nil - } - - api, acloser, err := lcli.GetFullNodeAPI(cctx) + fullNodeAPI, acloser, err := lcli.GetFullNodeAPI(cctx) if err != nil { return err } @@ -2100,7 +2095,7 @@ var sectorsCompactPartitionsCmd = &cli.Command{ return err } - minfo, err := api.StateMinerInfo(ctx, maddr, types.EmptyTSK) + minfo, err := fullNodeAPI.StateMinerInfo(ctx, maddr, types.EmptyTSK) if err != nil { return err } @@ -2116,46 +2111,118 @@ var sectorsCompactPartitionsCmd = &cli.Command{ } fmt.Printf("compacting %d paritions\n", len(parts)) + var makeMsgForPartitions func(partitionsBf bitfield.BitField) ([]*types.Message, error) + makeMsgForPartitions = func(partitionsBf bitfield.BitField) ([]*types.Message, error) { + params := miner.CompactPartitionsParams{ + Deadline: deadline, + Partitions: partitionsBf, + } + + sp, aerr := actors.SerializeParams(¶ms) + if aerr != nil { + return nil, xerrors.Errorf("serializing params: %w", err) + } + + msg := &types.Message{ + From: minfo.Worker, + To: maddr, + Method: builtin.MethodsMiner.CompactPartitions, + Value: big.Zero(), + Params: sp, + } + + estimatedMsg, err := fullNodeAPI.GasEstimateMessageGas(ctx, msg, nil, types.EmptyTSK) + if err != nil && xerrors.Is(err, &api.ErrOutOfGas{}) { + // the message is too big -- split into 2 + partitionsSlice, err := partitionsBf.All(math.MaxUint64) + if err != nil { + return nil, err + } + + partitions1 := bitfield.New() + for i := 0; i < len(partitionsSlice)/2; i++ { + partitions1.Set(uint64(i)) + } + + msgs1, err := makeMsgForPartitions(partitions1) + if err != nil { + return nil, err + } + + // time for the second half + partitions2 := bitfield.New() + for i := len(partitionsSlice) / 2; i < len(partitionsSlice); i++ { + partitions2.Set(uint64(i)) + } + + msgs2, err := makeMsgForPartitions(partitions2) + if err != nil { + return nil, err + } + + return append(msgs1, msgs2...), nil + } else if err != nil { + return nil, err + } + + return []*types.Message{estimatedMsg}, nil + } + partitions := bitfield.New() for _, partition := range parts { partitions.Set(uint64(partition)) } - params := miner.CompactPartitionsParams{ - Deadline: deadline, - Partitions: partitions, - } - - sp, err := actors.SerializeParams(¶ms) + msgs, err := makeMsgForPartitions(partitions) if err != nil { - return xerrors.Errorf("serializing params: %w", err) + return xerrors.Errorf("failed to make messages: %w", err) } - smsg, err := api.MpoolPushMessage(ctx, &types.Message{ - From: minfo.Worker, - To: maddr, - Method: builtin.MethodsMiner.CompactPartitions, - Value: big.Zero(), - Params: sp, - }, nil) - if err != nil { - return xerrors.Errorf("mpool push: %w", err) + // Actually send the messages if really-do-it provided, simulate otherwise + if cctx.Bool("really-do-it") { + smsgs, err := fullNodeAPI.MpoolBatchPushMessage(ctx, msgs, nil) + if err != nil { + return xerrors.Errorf("mpool push: %w", err) + } + + if len(smsgs) == 1 { + fmt.Printf("Requested compact partitions in message %s\n", smsgs[0].Cid()) + } else { + fmt.Printf("Requested compact partitions in %d messages\n\n", len(smsgs)) + for _, v := range smsgs { + fmt.Println(v.Cid()) + } + } + + for _, v := range smsgs { + wait, err := fullNodeAPI.StateWaitMsg(ctx, v.Cid(), 2) + if err != nil { + return err + } + + // check it executed successfully + if wait.Receipt.ExitCode.IsError() { + fmt.Println(cctx.App.Writer, "compact partitions msg %s failed!", v.Cid()) + return err + } + } + + return nil } - fmt.Printf("Requested compact partitions in message %s\n", smsg.Cid()) + for i, v := range msgs { + fmt.Printf("total of %d CompactPartitions msgs would be sent\n", len(msgs)) - wait, err := api.StateWaitMsg(ctx, smsg.Cid(), 0) - if err != nil { - return err - } + estMsg, err := fullNodeAPI.GasEstimateMessageGas(ctx, v, nil, types.EmptyTSK) + if err != nil { + return err + } - // check it executed successfully - if wait.Receipt.ExitCode.IsError() { - fmt.Println(cctx.App.Writer, "compact partitions failed!") - return err + fmt.Printf("msg %d would cost up to %s\n", i+1, types.FIL(estMsg.RequiredFunds())) } return nil + }, }