diff --git a/chain/actors/builtin/verifreg/actor.go.template b/chain/actors/builtin/verifreg/actor.go.template index 9f9efef92..9b779a68d 100644 --- a/chain/actors/builtin/verifreg/actor.go.template +++ b/chain/actors/builtin/verifreg/actor.go.template @@ -83,6 +83,7 @@ type State interface { GetAllocations(clientIdAddr address.Address) (map[AllocationId]Allocation, error) GetClaim(providerIdAddr address.Address, claimId ClaimId) (*Claim, bool, error) GetClaims(providerIdAddr address.Address) (map[ClaimId]Claim, error) + GetClaimIdsBySector(providerIdAddr address.Address) (map[abi.SectorNumber][]ClaimId, error) GetState() interface{} } diff --git a/chain/actors/builtin/verifreg/state.go.template b/chain/actors/builtin/verifreg/state.go.template index 526dff54e..adcbc22c2 100644 --- a/chain/actors/builtin/verifreg/state.go.template +++ b/chain/actors/builtin/verifreg/state.go.template @@ -170,6 +170,27 @@ func (s *state{{.v}}) GetClaims(providerIdAddr address.Address) (map[ClaimId]Cla {{end}} } +func (s *state{{.v}}) GetClaimIdsBySector(providerIdAddr address.Address) (map[abi.SectorNumber][]ClaimId, error) { +{{if (le .v 8)}} + return nil, xerrors.Errorf("unsupported in actors v{{.v}}") +{{else}} + v{{.v}}Map, err := s.LoadClaimsToMap(s.store, providerIdAddr) + + retMap := make(map[abi.SectorNumber][]ClaimId) + for k, v := range v{{.v}}Map { + claims, ok := retMap[v.Sector] + if !ok { + retMap[v.Sector] = []ClaimId{ClaimId(k)} + } else { + retMap[v.Sector] = append(claims, ClaimId(k)) + } + } + + return retMap, err + +{{end}} +} + func (s *state{{.v}}) ActorKey() string { return manifest.VerifregKey } diff --git a/chain/actors/builtin/verifreg/v0.go b/chain/actors/builtin/verifreg/v0.go index 8d97ebbc2..9913c42c0 100644 --- a/chain/actors/builtin/verifreg/v0.go +++ b/chain/actors/builtin/verifreg/v0.go @@ -118,6 +118,12 @@ func (s *state0) GetClaims(providerIdAddr address.Address) (map[ClaimId]Claim, e } +func (s *state0) GetClaimIdsBySector(providerIdAddr address.Address) (map[abi.SectorNumber][]ClaimId, error) { + + return nil, xerrors.Errorf("unsupported in actors v0") + +} + func (s *state0) ActorKey() string { return manifest.VerifregKey } diff --git a/chain/actors/builtin/verifreg/v10.go b/chain/actors/builtin/verifreg/v10.go index 63b161da3..256f4d2f8 100644 --- a/chain/actors/builtin/verifreg/v10.go +++ b/chain/actors/builtin/verifreg/v10.go @@ -134,6 +134,24 @@ func (s *state10) GetClaims(providerIdAddr address.Address) (map[ClaimId]Claim, } +func (s *state10) GetClaimIdsBySector(providerIdAddr address.Address) (map[abi.SectorNumber][]ClaimId, error) { + + v10Map, err := s.LoadClaimsToMap(s.store, providerIdAddr) + + retMap := make(map[abi.SectorNumber][]ClaimId) + for k, v := range v10Map { + claims, ok := retMap[v.Sector] + if !ok { + retMap[v.Sector] = []ClaimId{ClaimId(k)} + } else { + retMap[v.Sector] = append(claims, ClaimId(k)) + } + } + + return retMap, err + +} + func (s *state10) ActorKey() string { return manifest.VerifregKey } diff --git a/chain/actors/builtin/verifreg/v2.go b/chain/actors/builtin/verifreg/v2.go index 61c175c7a..31f7f775d 100644 --- a/chain/actors/builtin/verifreg/v2.go +++ b/chain/actors/builtin/verifreg/v2.go @@ -118,6 +118,12 @@ func (s *state2) GetClaims(providerIdAddr address.Address) (map[ClaimId]Claim, e } +func (s *state2) GetClaimIdsBySector(providerIdAddr address.Address) (map[abi.SectorNumber][]ClaimId, error) { + + return nil, xerrors.Errorf("unsupported in actors v2") + +} + func (s *state2) ActorKey() string { return manifest.VerifregKey } diff --git a/chain/actors/builtin/verifreg/v3.go b/chain/actors/builtin/verifreg/v3.go index 5ba478500..3ea016fd5 100644 --- a/chain/actors/builtin/verifreg/v3.go +++ b/chain/actors/builtin/verifreg/v3.go @@ -119,6 +119,12 @@ func (s *state3) GetClaims(providerIdAddr address.Address) (map[ClaimId]Claim, e } +func (s *state3) GetClaimIdsBySector(providerIdAddr address.Address) (map[abi.SectorNumber][]ClaimId, error) { + + return nil, xerrors.Errorf("unsupported in actors v3") + +} + func (s *state3) ActorKey() string { return manifest.VerifregKey } diff --git a/chain/actors/builtin/verifreg/v4.go b/chain/actors/builtin/verifreg/v4.go index 3ad739f68..464cc9fdc 100644 --- a/chain/actors/builtin/verifreg/v4.go +++ b/chain/actors/builtin/verifreg/v4.go @@ -119,6 +119,12 @@ func (s *state4) GetClaims(providerIdAddr address.Address) (map[ClaimId]Claim, e } +func (s *state4) GetClaimIdsBySector(providerIdAddr address.Address) (map[abi.SectorNumber][]ClaimId, error) { + + return nil, xerrors.Errorf("unsupported in actors v4") + +} + func (s *state4) ActorKey() string { return manifest.VerifregKey } diff --git a/chain/actors/builtin/verifreg/v5.go b/chain/actors/builtin/verifreg/v5.go index 1ffe06f3f..17901dd23 100644 --- a/chain/actors/builtin/verifreg/v5.go +++ b/chain/actors/builtin/verifreg/v5.go @@ -119,6 +119,12 @@ func (s *state5) GetClaims(providerIdAddr address.Address) (map[ClaimId]Claim, e } +func (s *state5) GetClaimIdsBySector(providerIdAddr address.Address) (map[abi.SectorNumber][]ClaimId, error) { + + return nil, xerrors.Errorf("unsupported in actors v5") + +} + func (s *state5) ActorKey() string { return manifest.VerifregKey } diff --git a/chain/actors/builtin/verifreg/v6.go b/chain/actors/builtin/verifreg/v6.go index 9786838d1..68fac64cb 100644 --- a/chain/actors/builtin/verifreg/v6.go +++ b/chain/actors/builtin/verifreg/v6.go @@ -119,6 +119,12 @@ func (s *state6) GetClaims(providerIdAddr address.Address) (map[ClaimId]Claim, e } +func (s *state6) GetClaimIdsBySector(providerIdAddr address.Address) (map[abi.SectorNumber][]ClaimId, error) { + + return nil, xerrors.Errorf("unsupported in actors v6") + +} + func (s *state6) ActorKey() string { return manifest.VerifregKey } diff --git a/chain/actors/builtin/verifreg/v7.go b/chain/actors/builtin/verifreg/v7.go index e63e27742..e8f3ac739 100644 --- a/chain/actors/builtin/verifreg/v7.go +++ b/chain/actors/builtin/verifreg/v7.go @@ -118,6 +118,12 @@ func (s *state7) GetClaims(providerIdAddr address.Address) (map[ClaimId]Claim, e } +func (s *state7) GetClaimIdsBySector(providerIdAddr address.Address) (map[abi.SectorNumber][]ClaimId, error) { + + return nil, xerrors.Errorf("unsupported in actors v7") + +} + func (s *state7) ActorKey() string { return manifest.VerifregKey } diff --git a/chain/actors/builtin/verifreg/v8.go b/chain/actors/builtin/verifreg/v8.go index a1edeba34..89393c4d9 100644 --- a/chain/actors/builtin/verifreg/v8.go +++ b/chain/actors/builtin/verifreg/v8.go @@ -118,6 +118,12 @@ func (s *state8) GetClaims(providerIdAddr address.Address) (map[ClaimId]Claim, e } +func (s *state8) GetClaimIdsBySector(providerIdAddr address.Address) (map[abi.SectorNumber][]ClaimId, error) { + + return nil, xerrors.Errorf("unsupported in actors v8") + +} + func (s *state8) ActorKey() string { return manifest.VerifregKey } diff --git a/chain/actors/builtin/verifreg/v9.go b/chain/actors/builtin/verifreg/v9.go index bf6424ba7..ce63c7f94 100644 --- a/chain/actors/builtin/verifreg/v9.go +++ b/chain/actors/builtin/verifreg/v9.go @@ -133,6 +133,24 @@ func (s *state9) GetClaims(providerIdAddr address.Address) (map[ClaimId]Claim, e } +func (s *state9) GetClaimIdsBySector(providerIdAddr address.Address) (map[abi.SectorNumber][]ClaimId, error) { + + v9Map, err := s.LoadClaimsToMap(s.store, providerIdAddr) + + retMap := make(map[abi.SectorNumber][]ClaimId) + for k, v := range v9Map { + claims, ok := retMap[v.Sector] + if !ok { + retMap[v.Sector] = []ClaimId{ClaimId(k)} + } else { + retMap[v.Sector] = append(claims, ClaimId(k)) + } + } + + return retMap, err + +} + func (s *state9) ActorKey() string { return manifest.VerifregKey } diff --git a/chain/actors/builtin/verifreg/verifreg.go b/chain/actors/builtin/verifreg/verifreg.go index 1380a9207..8e025b242 100644 --- a/chain/actors/builtin/verifreg/verifreg.go +++ b/chain/actors/builtin/verifreg/verifreg.go @@ -131,6 +131,7 @@ type State interface { GetAllocations(clientIdAddr address.Address) (map[AllocationId]Allocation, error) GetClaim(providerIdAddr address.Address, claimId ClaimId) (*Claim, bool, error) GetClaims(providerIdAddr address.Address) (map[ClaimId]Claim, error) + GetClaimIdsBySector(providerIdAddr address.Address) (map[abi.SectorNumber][]ClaimId, error) GetState() interface{} } diff --git a/cmd/lotus-miner/sectors.go b/cmd/lotus-miner/sectors.go index 6ff84b3fa..93c950d7c 100644 --- a/cmd/lotus-miner/sectors.go +++ b/cmd/lotus-miner/sectors.go @@ -30,6 +30,7 @@ import ( "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" lminer "github.com/filecoin-project/lotus/chain/actors/builtin/miner" + "github.com/filecoin-project/lotus/chain/actors/builtin/verifreg" "github.com/filecoin-project/lotus/chain/actors/policy" "github.com/filecoin-project/lotus/chain/types" lcli "github.com/filecoin-project/lotus/cli" @@ -709,7 +710,7 @@ type PseudoExtendSectorExpirationParams struct { Extensions []PseudoExpirationExtension } -func NewPseudoExtendParams(p *miner.ExtendSectorExpirationParams) (*PseudoExtendSectorExpirationParams, error) { +func NewPseudoExtendParams(p *miner.ExtendSectorExpiration2Params) (*PseudoExtendSectorExpirationParams, error) { res := PseudoExtendSectorExpirationParams{} for _, ext := range p.Extensions { scount, err := ext.Sectors.Count() @@ -833,6 +834,10 @@ var sectorsExtendCmd = &cli.Command{ Name: "only-cc", Usage: "only extend CC sectors (useful for making sector ready for snap upgrade)", }, + &cli.BoolFlag{ + Name: "drop-claims", + Usage: "drop claims for sectors that can be extended, but only by dropping some of their verified power claims", + }, &cli.Int64Flag{ Name: "tolerance", Usage: "don't try to extend sectors by fewer than this number of epochs, defaults to 7 days", @@ -845,7 +850,7 @@ var sectorsExtendCmd = &cli.Command{ }, &cli.Int64Flag{ Name: "max-sectors", - Usage: "the maximum number of sectors contained in each message message", + Usage: "the maximum number of sectors contained in each message", }, &cli.BoolFlag{ Name: "really-do-it", @@ -900,7 +905,8 @@ var sectorsExtendCmd = &cli.Command{ } tbs := blockstore.NewTieredBstore(blockstore.NewAPIBlockstore(fullApi), blockstore.NewMemory()) - mas, err := lminer.Load(adt.WrapStore(ctx, cbor.NewCborStore(tbs)), mact) + adtStore := adt.WrapStore(ctx, cbor.NewCborStore(tbs)) + mas, err := lminer.Load(adtStore, mact) if err != nil { return err } @@ -1051,44 +1057,124 @@ var sectorsExtendCmd = &cli.Command{ } } - var params []miner.ExtendSectorExpirationParams + verifregAct, err := fullApi.StateGetActor(ctx, builtin.VerifiedRegistryActorAddr, types.EmptyTSK) + if err != nil { + return xerrors.Errorf("failed to lookup verifreg actor: %w", err) + } - p := miner.ExtendSectorExpirationParams{} + verifregSt, err := verifreg.Load(adtStore, verifregAct) + if err != nil { + return xerrors.Errorf("failed to load verifreg state: %w", err) + } + + claimsMap, err := verifregSt.GetClaims(maddr) + if err != nil { + return xerrors.Errorf("failed to lookup claims for miner: %w", err) + } + + claimIdsBySector, err := verifregSt.GetClaimIdsBySector(maddr) + if err != nil { + return xerrors.Errorf("failed to lookup claim IDs by sector: %w", err) + } + + sectorsMax, err := policy.GetAddressedSectorsMax(nv) + if err != nil { + return err + } + + declMax, err := policy.GetDeclarationsMax(nv) + if err != nil { + return err + } + + addrSectors := sectorsMax + if cctx.Int("max-sectors") != 0 { + addrSectors = cctx.Int("max-sectors") + if addrSectors > sectorsMax { + return xerrors.Errorf("the specified max-sectors exceeds the maximum limit") + } + } + + var params []miner.ExtendSectorExpiration2Params + + p := miner.ExtendSectorExpiration2Params{} scount := 0 for l, exts := range extensions { for newExp, numbers := range exts { - scount += len(numbers) - var addrSectors int - sectorsMax, err := policy.GetAddressedSectorsMax(nv) - if err != nil { - return err - } - if cctx.Int("max-sectors") == 0 { - addrSectors = sectorsMax - } else { - addrSectors = cctx.Int("max-sectors") - if addrSectors > sectorsMax { - return xerrors.Errorf("the specified max-sectors exceeds the maximum limit") + sectorsWithoutClaimsToExtend := bitfield.New() + var sectorsWithClaims []miner.SectorClaim + for _, sectorNumber := range numbers { + claimIdsToMaintain := make([]verifreg.ClaimId, 0) + claimIdsToDrop := make([]verifreg.ClaimId, 0) + cannotExtendSector := false + claimIds, ok := claimIdsBySector[sectorNumber] + // Nothing to check, add to ccSectors + if !ok { + sectorsWithoutClaimsToExtend.Set(uint64(sectorNumber)) + } else { + for _, claimId := range claimIds { + claim, ok := claimsMap[claimId] + if !ok { + return xerrors.Errorf("failed to find claim for claimId %d", claimId) + } + claimExpiration := claim.TermStart + claim.TermMax + // can be maintained in the extended sector + if claimExpiration > newExp { + claimIdsToMaintain = append(claimIdsToMaintain, claimId) + } else { + sectorInfo, ok := activeSectorsInfo[sectorNumber] + if !ok { + return xerrors.Errorf("failed to find sector in active sector set: %w", err) + } + if !cctx.Bool("drop-claims") || + // FIP-0045 requires the claim minimum duration to have passed + currEpoch <= (claim.TermStart+claim.TermMin) || + // FIP-0045 requires the sector to be in its last 30 days of life + (currEpoch <= sectorInfo.Expiration-builtin.EndOfLifeClaimDropPeriod) { + fmt.Printf("skipping sector %d because claim %d does not live long enough \n", sectorNumber, claimId) + cannotExtendSector = true + break + } + + claimIdsToDrop = append(claimIdsToDrop, claimId) + } + } + if cannotExtendSector { + continue + } + + if len(claimIdsToMaintain)+len(claimIdsToDrop) != 0 { + sectorsWithClaims = append(sectorsWithClaims, miner.SectorClaim{ + SectorNumber: sectorNumber, + MaintainClaims: claimIdsToMaintain, + DropClaims: claimIdsToDrop, + }) + } } } - declMax, err := policy.GetDeclarationsMax(nv) + sectorsWithoutClaimsCount, err := sectorsWithoutClaimsToExtend.Count() if err != nil { - return err - } - if scount > addrSectors || len(p.Extensions) == declMax { - params = append(params, p) - p = miner.ExtendSectorExpirationParams{} - scount = len(numbers) + return xerrors.Errorf("failed to count cc sectors: %w", err) } - p.Extensions = append(p.Extensions, miner.ExpirationExtension{ - Deadline: l.Deadline, - Partition: l.Partition, - Sectors: SectorNumsToBitfield(numbers), - NewExpiration: newExp, + sectorsInDecl := int(sectorsWithoutClaimsCount) + len(sectorsWithClaims) + + if scount+sectorsInDecl > addrSectors || len(p.Extensions) >= declMax { + params = append(params, p) + p = miner.ExtendSectorExpiration2Params{} + scount = sectorsInDecl + } + + p.Extensions = append(p.Extensions, miner.ExpirationExtension2{ + Deadline: l.Deadline, + Partition: l.Partition, + Sectors: SectorNumsToBitfield(numbers), + SectorsWithClaims: sectorsWithClaims, + NewExpiration: newExp, }) + } } diff --git a/documentation/en/cli-lotus-miner.md b/documentation/en/cli-lotus-miner.md index 94fec03fd..cedb422ec 100644 --- a/documentation/en/cli-lotus-miner.md +++ b/documentation/en/cli-lotus-miner.md @@ -1889,11 +1889,12 @@ USAGE: lotus-miner sectors extend [command options] OPTIONS: + --drop-claims drop claims for sectors that can be extended, but only by dropping some of their verified power claims (default: false) --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) --from value only consider sectors whose current expiration epoch is in the range of [from, to], defaults to: now + 120 (1 hour) (default: 0) --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 message (default: 0) + --max-sectors value the maximum number of sectors contained in each message (default: 0) --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) --really-do-it pass this flag to really extend sectors, otherwise will only print out json representation of parameters (default: false)