From ded4ff43f4c243b03109e685f15b024fe4c11f9d Mon Sep 17 00:00:00 2001 From: Aayush Rajasekaran Date: Sat, 27 Mar 2021 20:02:53 -0400 Subject: [PATCH 1/4] Allow miners to extend all v1 sectors --- cmd/lotus-storage-miner/sectors.go | 173 ++++++++++++++++++++++------- 1 file changed, 134 insertions(+), 39 deletions(-) diff --git a/cmd/lotus-storage-miner/sectors.go b/cmd/lotus-storage-miner/sectors.go index 8f6fd374f42..010e3cdeb0f 100644 --- a/cmd/lotus-storage-miner/sectors.go +++ b/cmd/lotus-storage-miner/sectors.go @@ -8,6 +8,8 @@ import ( "strings" "time" + "github.com/filecoin-project/lotus/chain/actors/builtin" + "github.com/docker/go-units" "github.com/fatih/color" "github.com/urfave/cli/v2" @@ -422,7 +424,12 @@ var sectorsExtendCmd = &cli.Command{ &cli.Int64Flag{ Name: "new-expiration", Usage: "new expiration epoch", - Required: true, + Required: false, + }, + &cli.BoolFlag{ + Name: "v1-sectors", + Usage: "renews all v1 sectors up to the maximum possible lifetime", + Required: false, }, &cli.StringFlag{}, }, @@ -440,49 +447,130 @@ var sectorsExtendCmd = &cli.Command{ defer nCloser() ctx := lcli.ReqContext(cctx) - if !cctx.Args().Present() { - return xerrors.Errorf("must pass at least one sector number") - } - maddr, err := nodeApi.ActorAddress(ctx) if err != nil { return xerrors.Errorf("getting miner actor address: %w", err) } - sectors := map[miner.SectorLocation][]uint64{} + var params []miner0.ExtendSectorExpirationParams - for i, s := range cctx.Args().Slice() { - id, err := strconv.ParseUint(s, 10, 64) - if err != nil { - return xerrors.Errorf("could not parse sector %d: %w", i, err) + if cctx.Bool("v1-sectors") { + sectors := map[miner.SectorLocation]map[abi.ChainEpoch][]uint64{} + // are given durations within a week? + closeEnough := func(a, b abi.ChainEpoch) bool { + diff := a - b + if diff < 0 { + diff = b - a + } + + return diff <= 7*builtin.EpochsInDay } - p, err := api.StateSectorPartition(ctx, maddr, abi.SectorNumber(id), types.EmptyTSK) + sis, err := api.StateMinerSectors(ctx, maddr, nil, types.EmptyTSK) if err != nil { - return xerrors.Errorf("getting sector location for sector %d: %w", id, err) + return xerrors.Errorf("getting miner sector infos: %w", err) } - if p == nil { - return xerrors.Errorf("sector %d not found in any partition", id) + for _, si := range sis { + if si.SealProof < abi.RegisteredSealProof_StackedDrg2KiBV1_1 { + // if the sector's missing less than a week of its maximum possible lifetimne, don't bother extending it + if closeEnough(si.Expiration-si.Activation, miner0.MaxSectorExpirationExtension) { + continue + } + + newExp := miner0.MaxSectorExpirationExtension - (miner0.WPoStProvingPeriod * 2) + si.Activation + p, err := api.StateSectorPartition(ctx, maddr, si.SectorNumber, types.EmptyTSK) + if err != nil { + return xerrors.Errorf("getting sector location for sector %d: %w", si.SectorNumber, err) + } + + if p == nil { + return xerrors.Errorf("sector %d not found in any partition", si.SectorNumber) + } + + es, found := sectors[*p] + if !found { + ne := make(map[abi.ChainEpoch][]uint64) + ne[newExp] = []uint64{uint64(si.SectorNumber)} + sectors[*p] = ne + } else { + added := false + for exp, secs := range es { + if closeEnough(exp, newExp) { + secs = append(secs, uint64(si.SectorNumber)) + //es[exp] = secs + //sectors[*p] = es + added = true + break + } + } + + if !added { + es[newExp] = []uint64{uint64(si.SectorNumber)} + //sectors[*p] = es + } + } + } + + // TODO: Count added sectors, if it exceeds 10k, split messages + p := &miner0.ExtendSectorExpirationParams{} + scount := 0 + for l, exts := range sectors { + for newExp, numbers := range exts { + scount += len(numbers) + if scount > miner.AddressedSectorsMax { + params = append(params, *p) + p = &miner0.ExtendSectorExpirationParams{} + scount = len(numbers) + } + + p.Extensions = append(p.Extensions, miner0.ExpirationExtension{ + Deadline: l.Deadline, + Partition: l.Partition, + Sectors: bitfield.NewFromSet(numbers), + NewExpiration: newExp, + }) + } + } + params = append(params, *p) } - sectors[*p] = append(sectors[*p], id) - } + } else { + if !cctx.Args().Present() || !cctx.IsSet("new-expiration") { + return xerrors.Errorf("must pass at least one sector number and new expiration") + } + sectors := map[miner.SectorLocation][]uint64{} + + for i, s := range cctx.Args().Slice() { + id, err := strconv.ParseUint(s, 10, 64) + if err != nil { + return xerrors.Errorf("could not parse sector %d: %w", i, err) + } - params := &miner0.ExtendSectorExpirationParams{} - for l, numbers := range sectors { + p, err := api.StateSectorPartition(ctx, maddr, abi.SectorNumber(id), types.EmptyTSK) + if err != nil { + return xerrors.Errorf("getting sector location for sector %d: %w", id, err) + } - params.Extensions = append(params.Extensions, miner0.ExpirationExtension{ - Deadline: l.Deadline, - Partition: l.Partition, - Sectors: bitfield.NewFromSet(numbers), - NewExpiration: abi.ChainEpoch(cctx.Int64("new-expiration")), - }) - } + if p == nil { + return xerrors.Errorf("sector %d not found in any partition", id) + } - sp, err := actors.SerializeParams(params) - if err != nil { - return xerrors.Errorf("serializing params: %w", err) + sectors[*p] = append(sectors[*p], id) + } + + p := &miner0.ExtendSectorExpirationParams{} + for l, numbers := range sectors { + + p.Extensions = append(p.Extensions, miner0.ExpirationExtension{ + Deadline: l.Deadline, + Partition: l.Partition, + Sectors: bitfield.NewFromSet(numbers), + NewExpiration: abi.ChainEpoch(cctx.Int64("new-expiration")), + }) + } + + params = append(params, *p) } mi, err := api.StateMinerInfo(ctx, maddr, types.EmptyTSK) @@ -490,19 +578,26 @@ var sectorsExtendCmd = &cli.Command{ return xerrors.Errorf("getting miner info: %w", err) } - smsg, err := api.MpoolPushMessage(ctx, &types.Message{ - From: mi.Worker, - To: maddr, - Method: miner.Methods.ExtendSectorExpiration, + for _, p := range params { + sp, aerr := actors.SerializeParams(&p) + if aerr != nil { + return xerrors.Errorf("serializing params: %w", err) + } + + smsg, err := api.MpoolPushMessage(ctx, &types.Message{ + From: mi.Worker, + To: maddr, + Method: miner.Methods.ExtendSectorExpiration, - Value: big.Zero(), - Params: sp, - }, nil) - if err != nil { - return xerrors.Errorf("mpool push message: %w", err) - } + Value: big.Zero(), + Params: sp, + }, nil) + if err != nil { + return xerrors.Errorf("mpool push message: %w", err) + } - fmt.Println(smsg.Cid()) + fmt.Println(smsg.Cid()) + } return nil }, From b734e5a2328ee1ba6a3bfc76a3dd5a907188ef08 Mon Sep 17 00:00:00 2001 From: Aayush Rajasekaran Date: Sun, 28 Mar 2021 01:21:09 -0400 Subject: [PATCH 2/4] Miner CLI: If performing read-only operations on a foreign miner, miner API isn't needed --- cmd/lotus-storage-miner/info.go | 2 +- cmd/lotus-storage-miner/main.go | 12 ++++++++--- cmd/lotus-storage-miner/proving.go | 32 ++++-------------------------- cmd/lotus-storage-miner/sectors.go | 23 ++++++--------------- 4 files changed, 20 insertions(+), 49 deletions(-) diff --git a/cmd/lotus-storage-miner/info.go b/cmd/lotus-storage-miner/info.go index cf39e5516da..7650de03582 100644 --- a/cmd/lotus-storage-miner/info.go +++ b/cmd/lotus-storage-miner/info.go @@ -90,7 +90,7 @@ func infoCmdAct(cctx *cli.Context) error { fmt.Println() - maddr, err := getActorAddress(ctx, nodeApi, cctx.String("actor")) + maddr, err := getActorAddress(ctx, cctx) if err != nil { return err } diff --git a/cmd/lotus-storage-miner/main.go b/cmd/lotus-storage-miner/main.go index 84654d7899b..f5ff2517772 100644 --- a/cmd/lotus-storage-miner/main.go +++ b/cmd/lotus-storage-miner/main.go @@ -106,15 +106,21 @@ func main() { lcli.RunApp(app) } -func getActorAddress(ctx context.Context, nodeAPI api.StorageMiner, overrideMaddr string) (maddr address.Address, err error) { - if overrideMaddr != "" { - maddr, err = address.NewFromString(overrideMaddr) +func getActorAddress(ctx context.Context, cctx *cli.Context) (maddr address.Address, err error) { + if cctx.IsSet("actor") { + maddr, err = address.NewFromString(cctx.String("actor")) if err != nil { return maddr, err } return } + nodeAPI, closer, err := lcli.GetStorageMinerAPI(cctx) + if err != nil { + return address.Undef, err + } + defer closer() + maddr, err = nodeAPI.ActorAddress(ctx) if err != nil { return maddr, xerrors.Errorf("getting actor address: %w", err) diff --git a/cmd/lotus-storage-miner/proving.go b/cmd/lotus-storage-miner/proving.go index f6bc74318e8..66007b63dc1 100644 --- a/cmd/lotus-storage-miner/proving.go +++ b/cmd/lotus-storage-miner/proving.go @@ -38,12 +38,6 @@ var provingFaultsCmd = &cli.Command{ Action: func(cctx *cli.Context) error { color.NoColor = !cctx.Bool("color") - nodeApi, closer, err := lcli.GetStorageMinerAPI(cctx) - if err != nil { - return err - } - defer closer() - api, acloser, err := lcli.GetFullNodeAPI(cctx) if err != nil { return err @@ -54,7 +48,7 @@ var provingFaultsCmd = &cli.Command{ stor := store.ActorStore(ctx, blockstore.NewAPIBlockstore(api)) - maddr, err := getActorAddress(ctx, nodeApi, cctx.String("actor")) + maddr, err := getActorAddress(ctx, cctx) if err != nil { return err } @@ -98,12 +92,6 @@ var provingInfoCmd = &cli.Command{ Action: func(cctx *cli.Context) error { color.NoColor = !cctx.Bool("color") - nodeApi, closer, err := lcli.GetStorageMinerAPI(cctx) - if err != nil { - return err - } - defer closer() - api, acloser, err := lcli.GetFullNodeAPI(cctx) if err != nil { return err @@ -112,7 +100,7 @@ var provingInfoCmd = &cli.Command{ ctx := lcli.ReqContext(cctx) - maddr, err := getActorAddress(ctx, nodeApi, cctx.String("actor")) + maddr, err := getActorAddress(ctx, cctx) if err != nil { return err } @@ -211,12 +199,6 @@ var provingDeadlinesCmd = &cli.Command{ Action: func(cctx *cli.Context) error { color.NoColor = !cctx.Bool("color") - nodeApi, closer, err := lcli.GetStorageMinerAPI(cctx) - if err != nil { - return err - } - defer closer() - api, acloser, err := lcli.GetFullNodeAPI(cctx) if err != nil { return err @@ -225,7 +207,7 @@ var provingDeadlinesCmd = &cli.Command{ ctx := lcli.ReqContext(cctx) - maddr, err := getActorAddress(ctx, nodeApi, cctx.String("actor")) + maddr, err := getActorAddress(ctx, cctx) if err != nil { return err } @@ -301,12 +283,6 @@ var provingDeadlineInfoCmd = &cli.Command{ return xerrors.Errorf("could not parse deadline index: %w", err) } - nodeApi, closer, err := lcli.GetStorageMinerAPI(cctx) - if err != nil { - return err - } - defer closer() - api, acloser, err := lcli.GetFullNodeAPI(cctx) if err != nil { return err @@ -315,7 +291,7 @@ var provingDeadlineInfoCmd = &cli.Command{ ctx := lcli.ReqContext(cctx) - maddr, err := getActorAddress(ctx, nodeApi, cctx.String("actor")) + maddr, err := getActorAddress(ctx, cctx) if err != nil { return err } diff --git a/cmd/lotus-storage-miner/sectors.go b/cmd/lotus-storage-miner/sectors.go index 010e3cdeb0f..8922a24fa8b 100644 --- a/cmd/lotus-storage-miner/sectors.go +++ b/cmd/lotus-storage-miner/sectors.go @@ -434,11 +434,6 @@ var sectorsExtendCmd = &cli.Command{ &cli.StringFlag{}, }, Action: func(cctx *cli.Context) error { - nodeApi, closer, err := lcli.GetStorageMinerAPI(cctx) - if err != nil { - return err - } - defer closer() api, nCloser, err := lcli.GetFullNodeAPI(cctx) if err != nil { @@ -447,9 +442,10 @@ var sectorsExtendCmd = &cli.Command{ defer nCloser() ctx := lcli.ReqContext(cctx) - maddr, err := nodeApi.ActorAddress(ctx) + + maddr, err := getActorAddress(ctx, cctx) if err != nil { - return xerrors.Errorf("getting miner actor address: %w", err) + return err } var params []miner0.ExtendSectorExpirationParams @@ -512,7 +508,6 @@ var sectorsExtendCmd = &cli.Command{ } } - // TODO: Count added sectors, if it exceeds 10k, split messages p := &miner0.ExtendSectorExpirationParams{} scount := 0 for l, exts := range sectors { @@ -578,8 +573,8 @@ var sectorsExtendCmd = &cli.Command{ return xerrors.Errorf("getting miner info: %w", err) } - for _, p := range params { - sp, aerr := actors.SerializeParams(&p) + for i := range params { + sp, aerr := actors.SerializeParams(¶ms[i]) if aerr != nil { return xerrors.Errorf("serializing params: %w", err) } @@ -836,12 +831,6 @@ var sectorsCapacityCollateralCmd = &cli.Command{ }, Action: func(cctx *cli.Context) error { - mApi, mCloser, err := lcli.GetStorageMinerAPI(cctx) - if err != nil { - return err - } - defer mCloser() - nApi, nCloser, err := lcli.GetFullNodeAPI(cctx) if err != nil { return err @@ -850,7 +839,7 @@ var sectorsCapacityCollateralCmd = &cli.Command{ ctx := lcli.ReqContext(cctx) - maddr, err := mApi.ActorAddress(ctx) + maddr, err := getActorAddress(ctx, cctx) if err != nil { return err } From 01bf3a89f4358ea704bc0f0d338890e25daef3e4 Mon Sep 17 00:00:00 2001 From: Aayush Rajasekaran Date: Tue, 30 Mar 2021 18:22:41 -0400 Subject: [PATCH 3/4] Add checks to v1 extension util --- cmd/lotus-storage-miner/sectors.go | 70 +++++++++++++++--------------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/cmd/lotus-storage-miner/sectors.go b/cmd/lotus-storage-miner/sectors.go index 8922a24fa8b..a3978b5082e 100644 --- a/cmd/lotus-storage-miner/sectors.go +++ b/cmd/lotus-storage-miner/sectors.go @@ -8,6 +8,8 @@ import ( "strings" "time" + builtin3 "github.com/filecoin-project/specs-actors/v3/actors/builtin" + "github.com/filecoin-project/lotus/chain/actors/builtin" "github.com/docker/go-units" @@ -18,7 +20,7 @@ import ( "github.com/filecoin-project/go-bitfield" "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/big" - miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner" + miner3 "github.com/filecoin-project/specs-actors/v3/actors/builtin/miner" "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/chain/actors" @@ -448,10 +450,10 @@ var sectorsExtendCmd = &cli.Command{ return err } - var params []miner0.ExtendSectorExpirationParams + var params []miner3.ExtendSectorExpirationParams if cctx.Bool("v1-sectors") { - sectors := map[miner.SectorLocation]map[abi.ChainEpoch][]uint64{} + extensions := map[miner.SectorLocation]map[abi.ChainEpoch][]uint64{} // are given durations within a week? closeEnough := func(a, b abi.ChainEpoch) bool { diff := a - b @@ -462,19 +464,21 @@ var sectorsExtendCmd = &cli.Command{ return diff <= 7*builtin.EpochsInDay } - sis, err := api.StateMinerSectors(ctx, maddr, nil, types.EmptyTSK) + sis, err := api.StateMinerActiveSectors(ctx, maddr, types.EmptyTSK) if err != nil { return xerrors.Errorf("getting miner sector infos: %w", err) } for _, si := range sis { if si.SealProof < abi.RegisteredSealProof_StackedDrg2KiBV1_1 { - // if the sector's missing less than a week of its maximum possible lifetimne, don't bother extending it - if closeEnough(si.Expiration-si.Activation, miner0.MaxSectorExpirationExtension) { + + ml := builtin3.SealProofPoliciesV11[si.SealProof].SectorMaxLifetime + // if the sector's missing less than a week of its maximum possible lifetime, don't bother extending it + if closeEnough(si.Expiration-si.Activation, ml) { continue } - newExp := miner0.MaxSectorExpirationExtension - (miner0.WPoStProvingPeriod * 2) + si.Activation + newExp := ml - (miner3.WPoStProvingPeriod * 2) + si.Activation p, err := api.StateSectorPartition(ctx, maddr, si.SectorNumber, types.EmptyTSK) if err != nil { return xerrors.Errorf("getting sector location for sector %d: %w", si.SectorNumber, err) @@ -484,18 +488,16 @@ var sectorsExtendCmd = &cli.Command{ return xerrors.Errorf("sector %d not found in any partition", si.SectorNumber) } - es, found := sectors[*p] + es, found := extensions[*p] if !found { ne := make(map[abi.ChainEpoch][]uint64) ne[newExp] = []uint64{uint64(si.SectorNumber)} - sectors[*p] = ne + extensions[*p] = ne } else { added := false - for exp, secs := range es { + for exp := range es { if closeEnough(exp, newExp) { - secs = append(secs, uint64(si.SectorNumber)) - //es[exp] = secs - //sectors[*p] = es + es[exp] = append(es[exp], uint64(si.SectorNumber)) added = true break } @@ -503,32 +505,30 @@ var sectorsExtendCmd = &cli.Command{ if !added { es[newExp] = []uint64{uint64(si.SectorNumber)} - //sectors[*p] = es } } } - - p := &miner0.ExtendSectorExpirationParams{} - scount := 0 - for l, exts := range sectors { - for newExp, numbers := range exts { - scount += len(numbers) - if scount > miner.AddressedSectorsMax { - params = append(params, *p) - p = &miner0.ExtendSectorExpirationParams{} - scount = len(numbers) - } - - p.Extensions = append(p.Extensions, miner0.ExpirationExtension{ - Deadline: l.Deadline, - Partition: l.Partition, - Sectors: bitfield.NewFromSet(numbers), - NewExpiration: newExp, - }) + } + p := &miner3.ExtendSectorExpirationParams{} + scount := 0 + for l, exts := range extensions { + for newExp, numbers := range exts { + scount += len(numbers) + if scount > miner.AddressedSectorsMax || len(p.Extensions) == miner3.DeclarationsMax { + params = append(params, *p) + p = &miner3.ExtendSectorExpirationParams{} + scount = len(numbers) } + + p.Extensions = append(p.Extensions, miner3.ExpirationExtension{ + Deadline: l.Deadline, + Partition: l.Partition, + Sectors: bitfield.NewFromSet(numbers), + NewExpiration: newExp, + }) } - params = append(params, *p) } + params = append(params, *p) } else { if !cctx.Args().Present() || !cctx.IsSet("new-expiration") { @@ -554,10 +554,10 @@ var sectorsExtendCmd = &cli.Command{ sectors[*p] = append(sectors[*p], id) } - p := &miner0.ExtendSectorExpirationParams{} + p := &miner3.ExtendSectorExpirationParams{} for l, numbers := range sectors { - p.Extensions = append(p.Extensions, miner0.ExpirationExtension{ + p.Extensions = append(p.Extensions, miner3.ExpirationExtension{ Deadline: l.Deadline, Partition: l.Partition, Sectors: bitfield.NewFromSet(numbers), From 72c410cd8f6d3835e103fa74f8206b4b3885fb09 Mon Sep 17 00:00:00 2001 From: Aayush Rajasekaran Date: Sat, 3 Apr 2021 22:02:06 -0400 Subject: [PATCH 4/4] Address review on v1 sector extension tool --- chain/actors/builtin/miner/miner.go | 1 + chain/actors/policy/policy.go | 37 ++++++++- cmd/lotus-storage-miner/sectors.go | 123 ++++++++++++++++++---------- 3 files changed, 118 insertions(+), 43 deletions(-) diff --git a/chain/actors/builtin/miner/miner.go b/chain/actors/builtin/miner/miner.go index 49a468efbf6..5bae8dea67c 100644 --- a/chain/actors/builtin/miner/miner.go +++ b/chain/actors/builtin/miner/miner.go @@ -50,6 +50,7 @@ var FaultDeclarationCutoff = miner0.FaultDeclarationCutoff const MinSectorExpiration = miner0.MinSectorExpiration // Not used / checked in v0 +// TODO: Abstract over network versions var DeclarationsMax = miner2.DeclarationsMax var AddressedSectorsMax = miner2.AddressedSectorsMax diff --git a/chain/actors/policy/policy.go b/chain/actors/policy/policy.go index e32b3674310..aff746df13e 100644 --- a/chain/actors/policy/policy.go +++ b/chain/actors/policy/policy.go @@ -132,7 +132,7 @@ func DealProviderCollateralBounds( case actors.Version3: return market3.DealProviderCollateralBounds(size, verified, rawBytePower, qaPower, baselinePower, circulatingFil) default: - panic("unsupported network version") + panic("unsupported actors version") } } @@ -191,3 +191,38 @@ func GetDefaultSectorSize() abi.SectorSize { return szs[0] } + +func GetSectorMaxLifetime(proof abi.RegisteredSealProof, nwVer network.Version) abi.ChainEpoch { + if nwVer <= network.Version10 { + return builtin3.SealProofPoliciesV0[proof].SectorMaxLifetime + } + + return builtin3.SealProofPoliciesV11[proof].SectorMaxLifetime +} + +func GetAddressedSectorsMax(nwVer network.Version) int { + switch actors.VersionForNetwork(nwVer) { + case actors.Version0: + return miner0.AddressedSectorsMax + case actors.Version2: + return miner2.AddressedSectorsMax + case actors.Version3: + return miner3.AddressedSectorsMax + default: + panic("unsupported network version") + } +} + +func GetDeclarationsMax(nwVer network.Version) int { + switch actors.VersionForNetwork(nwVer) { + case actors.Version0: + // TODO: Should we instead panic here since the concept doesn't exist yet? + return miner0.AddressedPartitionsMax + case actors.Version2: + return miner2.DeclarationsMax + case actors.Version3: + return miner3.DeclarationsMax + default: + panic("unsupported network version") + } +} diff --git a/cmd/lotus-storage-miner/sectors.go b/cmd/lotus-storage-miner/sectors.go index a3978b5082e..3791dbf0741 100644 --- a/cmd/lotus-storage-miner/sectors.go +++ b/cmd/lotus-storage-miner/sectors.go @@ -8,10 +8,6 @@ import ( "strings" "time" - builtin3 "github.com/filecoin-project/specs-actors/v3/actors/builtin" - - "github.com/filecoin-project/lotus/chain/actors/builtin" - "github.com/docker/go-units" "github.com/fatih/color" "github.com/urfave/cli/v2" @@ -433,6 +429,17 @@ var sectorsExtendCmd = &cli.Command{ Usage: "renews all v1 sectors up to the maximum possible lifetime", Required: false, }, + &cli.Int64Flag{ + Name: "tolerance", + Value: 20160, + Usage: "when extending v1 sectors, don't try to extend sectors by fewer than this number of epochs", + Required: false, + }, + &cli.Int64Flag{ + Name: "expiration-cutoff", + Usage: "when extending v1 sectors, skip sectors whose current expiration is more than epochs from now (infinity if unspecified)", + Required: false, + }, &cli.StringFlag{}, }, Action: func(cctx *cli.Context) error { @@ -453,15 +460,27 @@ var sectorsExtendCmd = &cli.Command{ var params []miner3.ExtendSectorExpirationParams if cctx.Bool("v1-sectors") { + + head, err := api.ChainHead(ctx) + if err != nil { + return err + } + + nv, err := api.StateNetworkVersion(ctx, types.EmptyTSK) + if err != nil { + return err + } + extensions := map[miner.SectorLocation]map[abi.ChainEpoch][]uint64{} - // are given durations within a week? - closeEnough := func(a, b abi.ChainEpoch) bool { + + // are given durations within tolerance epochs + withinTolerance := func(a, b abi.ChainEpoch) bool { diff := a - b if diff < 0 { diff = b - a } - return diff <= 7*builtin.EpochsInDay + return diff <= abi.ChainEpoch(cctx.Int64("tolerance")) } sis, err := api.StateMinerActiveSectors(ctx, maddr, types.EmptyTSK) @@ -470,53 +489,63 @@ var sectorsExtendCmd = &cli.Command{ } for _, si := range sis { - if si.SealProof < abi.RegisteredSealProof_StackedDrg2KiBV1_1 { + if si.SealProof >= abi.RegisteredSealProof_StackedDrg2KiBV1_1 { + continue + } - ml := builtin3.SealProofPoliciesV11[si.SealProof].SectorMaxLifetime - // if the sector's missing less than a week of its maximum possible lifetime, don't bother extending it - if closeEnough(si.Expiration-si.Activation, ml) { + if cctx.IsSet("expiration-cutoff") { + if si.Expiration > (head.Height() + abi.ChainEpoch(cctx.Int64("expiration-cutoff"))) { continue } + } - newExp := ml - (miner3.WPoStProvingPeriod * 2) + si.Activation - p, err := api.StateSectorPartition(ctx, maddr, si.SectorNumber, types.EmptyTSK) - if err != nil { - return xerrors.Errorf("getting sector location for sector %d: %w", si.SectorNumber, err) - } + ml := policy.GetSectorMaxLifetime(si.SealProof, nv) + // if the sector's missing less than "tolerance" of its maximum possible lifetime, don't bother extending it + if withinTolerance(si.Expiration-si.Activation, ml) { + continue + } - if p == nil { - return xerrors.Errorf("sector %d not found in any partition", si.SectorNumber) - } + // Set the new expiration to 48 hours less than the theoretical maximum lifetime + newExp := ml - (miner3.WPoStProvingPeriod * 2) + si.Activation + p, err := api.StateSectorPartition(ctx, maddr, si.SectorNumber, types.EmptyTSK) + if err != nil { + return xerrors.Errorf("getting sector location for sector %d: %w", si.SectorNumber, err) + } - es, found := extensions[*p] - if !found { - ne := make(map[abi.ChainEpoch][]uint64) - ne[newExp] = []uint64{uint64(si.SectorNumber)} - extensions[*p] = ne - } else { - added := false - for exp := range es { - if closeEnough(exp, newExp) { - es[exp] = append(es[exp], uint64(si.SectorNumber)) - added = true - break - } - } + if p == nil { + return xerrors.Errorf("sector %d not found in any partition", si.SectorNumber) + } - if !added { - es[newExp] = []uint64{uint64(si.SectorNumber)} + es, found := extensions[*p] + if !found { + ne := make(map[abi.ChainEpoch][]uint64) + ne[newExp] = []uint64{uint64(si.SectorNumber)} + extensions[*p] = ne + } else { + added := false + for exp := range es { + if withinTolerance(exp, newExp) { + es[exp] = append(es[exp], uint64(si.SectorNumber)) + added = true + break } } + + if !added { + es[newExp] = []uint64{uint64(si.SectorNumber)} + } } } - p := &miner3.ExtendSectorExpirationParams{} + + p := miner3.ExtendSectorExpirationParams{} scount := 0 + for l, exts := range extensions { for newExp, numbers := range exts { scount += len(numbers) - if scount > miner.AddressedSectorsMax || len(p.Extensions) == miner3.DeclarationsMax { - params = append(params, *p) - p = &miner3.ExtendSectorExpirationParams{} + if scount > policy.GetAddressedSectorsMax(nv) || len(p.Extensions) == policy.GetDeclarationsMax(nv) { + params = append(params, p) + p = miner3.ExtendSectorExpirationParams{} scount = len(numbers) } @@ -528,7 +557,11 @@ var sectorsExtendCmd = &cli.Command{ }) } } - params = append(params, *p) + + // if we have any sectors, then one last append is needed here + if scount != 0 { + params = append(params, p) + } } else { if !cctx.Args().Present() || !cctx.IsSet("new-expiration") { @@ -554,9 +587,10 @@ var sectorsExtendCmd = &cli.Command{ sectors[*p] = append(sectors[*p], id) } - p := &miner3.ExtendSectorExpirationParams{} + p := miner3.ExtendSectorExpirationParams{} for l, numbers := range sectors { + // TODO: Dedup with above loop p.Extensions = append(p.Extensions, miner3.ExpirationExtension{ Deadline: l.Deadline, Partition: l.Partition, @@ -565,7 +599,12 @@ var sectorsExtendCmd = &cli.Command{ }) } - params = append(params, *p) + params = append(params, p) + } + + if len(params) == 0 { + fmt.Println("nothing to extend") + return nil } mi, err := api.StateMinerInfo(ctx, maddr, types.EmptyTSK)