diff --git a/api/api_storage.go b/api/api_storage.go index 9e65c1ced7d..a9e632998da 100644 --- a/api/api_storage.go +++ b/api/api_storage.go @@ -129,6 +129,8 @@ type StorageMiner interface { SectorMatchPendingPiecesToOpenSectors(ctx context.Context) error //perm:admin // SectorAbortUpgrade can be called on sectors that are in the process of being upgraded to abort it SectorAbortUpgrade(context.Context, abi.SectorNumber) error //perm:admin + // SectorUnseal unseals the provided sector + SectorUnseal(ctx context.Context, number abi.SectorNumber) error //perm:admin // SectorNumAssignerMeta returns sector number assigner metadata - reserved/allocated SectorNumAssignerMeta(ctx context.Context) (NumAssignerMeta, error) //perm:read diff --git a/api/proxy_gen.go b/api/proxy_gen.go index 538e5815833..303284febaf 100644 --- a/api/proxy_gen.go +++ b/api/proxy_gen.go @@ -1085,6 +1085,8 @@ type StorageMinerMethods struct { SectorTerminatePending func(p0 context.Context) ([]abi.SectorID, error) `perm:"admin"` + SectorUnseal func(p0 context.Context, p1 abi.SectorNumber) error `perm:"admin"` + SectorsList func(p0 context.Context) ([]abi.SectorNumber, error) `perm:"read"` SectorsListInStates func(p0 context.Context, p1 []SectorState) ([]abi.SectorNumber, error) `perm:"read"` @@ -6424,6 +6426,17 @@ func (s *StorageMinerStub) SectorTerminatePending(p0 context.Context) ([]abi.Sec return *new([]abi.SectorID), ErrNotSupported } +func (s *StorageMinerStruct) SectorUnseal(p0 context.Context, p1 abi.SectorNumber) error { + if s.Internal.SectorUnseal == nil { + return ErrNotSupported + } + return s.Internal.SectorUnseal(p0, p1) +} + +func (s *StorageMinerStub) SectorUnseal(p0 context.Context, p1 abi.SectorNumber) error { + return ErrNotSupported +} + func (s *StorageMinerStruct) SectorsList(p0 context.Context) ([]abi.SectorNumber, error) { if s.Internal.SectorsList == nil { return *new([]abi.SectorNumber), ErrNotSupported diff --git a/build/openrpc/full.json.gz b/build/openrpc/full.json.gz index c5d21c6da07..e56fd0fdae6 100644 Binary files a/build/openrpc/full.json.gz and b/build/openrpc/full.json.gz differ diff --git a/build/openrpc/gateway.json.gz b/build/openrpc/gateway.json.gz index ba8434f1ead..0b481419450 100644 Binary files a/build/openrpc/gateway.json.gz and b/build/openrpc/gateway.json.gz differ diff --git a/build/openrpc/miner.json.gz b/build/openrpc/miner.json.gz index c085149b99a..1dd7d16852f 100644 Binary files a/build/openrpc/miner.json.gz and b/build/openrpc/miner.json.gz differ diff --git a/build/openrpc/worker.json.gz b/build/openrpc/worker.json.gz index bdea2d97e12..ea2e3066f88 100644 Binary files a/build/openrpc/worker.json.gz and b/build/openrpc/worker.json.gz differ diff --git a/cmd/lotus-miner/sectors.go b/cmd/lotus-miner/sectors.go index a32f276a876..61e491a97b7 100644 --- a/cmd/lotus-miner/sectors.go +++ b/cmd/lotus-miner/sectors.go @@ -67,6 +67,7 @@ var sectorsCmd = &cli.Command{ sectorsBatching, sectorsRefreshPieceMatchingCmd, sectorsCompactPartitionsCmd, + sectorsUnsealCmd, }, } @@ -2254,3 +2255,27 @@ var sectorsNumbersFreeCmd = &cli.Command{ return minerAPI.SectorNumFree(ctx, cctx.Args().First()) }, } + +var sectorsUnsealCmd = &cli.Command{ + Name: "unseal", + Usage: "unseal a sector", + ArgsUsage: "[sector number]", + Action: func(cctx *cli.Context) error { + minerAPI, closer, err := lcli.GetStorageMinerAPI(cctx) + if err != nil { + return err + } + defer closer() + ctx := lcli.ReqContext(cctx) + if cctx.NArg() != 1 { + return lcli.IncorrectNumArgs(cctx) + } + + sectorNum, err := strconv.ParseUint(cctx.Args().Get(0), 10, 64) + if err != nil { + return xerrors.Errorf("could not parse sector number: %w", err) + } + + return minerAPI.SectorUnseal(ctx, abi.SectorNumber(sectorNum)) + }, +} diff --git a/documentation/en/api-v0-methods-miner.md b/documentation/en/api-v0-methods-miner.md index 1a149930502..d0b0e045d7c 100644 --- a/documentation/en/api-v0-methods-miner.md +++ b/documentation/en/api-v0-methods-miner.md @@ -159,6 +159,7 @@ * [SectorTerminate](#SectorTerminate) * [SectorTerminateFlush](#SectorTerminateFlush) * [SectorTerminatePending](#SectorTerminatePending) + * [SectorUnseal](#SectorUnseal) * [Sectors](#Sectors) * [SectorsList](#SectorsList) * [SectorsListInStates](#SectorsListInStates) @@ -3415,6 +3416,21 @@ Response: ] ``` +### SectorUnseal +SectorUnseal unseals the provided sector + + +Perms: admin + +Inputs: +```json +[ + 9 +] +``` + +Response: `{}` + ## Sectors diff --git a/documentation/en/cli-lotus-miner.md b/documentation/en/cli-lotus-miner.md index f3595dcc1dc..d304dc11da9 100644 --- a/documentation/en/cli-lotus-miner.md +++ b/documentation/en/cli-lotus-miner.md @@ -1671,6 +1671,7 @@ COMMANDS: batching manage batch sector operations match-pending-pieces force a refreshed match of pending pieces to open sectors without manually waiting for more deals compact-partitions removes dead sectors from partitions and reduces the number of partitions used if possible + unseal unseal a sector help, h Shows a list of commands or help for one command OPTIONS: @@ -2086,6 +2087,19 @@ OPTIONS: ``` +### lotus-miner sectors unseal +``` +NAME: + lotus-miner sectors unseal - unseal a sector + +USAGE: + lotus-miner sectors unseal [command options] [sector number] + +OPTIONS: + --help, -h show help (default: false) + +``` + ## lotus-miner proving ``` NAME: diff --git a/node/impl/storminer.go b/node/impl/storminer.go index 44ef7ee6a36..e4fa41c788a 100644 --- a/node/impl/storminer.go +++ b/node/impl/storminer.go @@ -254,6 +254,33 @@ func (sm *StorageMinerAPI) SectorsUnsealPiece(ctx context.Context, sector storif return sm.StorageMgr.SectorsUnsealPiece(ctx, sector, offset, size, randomness, commd) } +func (sm *StorageMinerAPI) SectorUnseal(ctx context.Context, sectorNum abi.SectorNumber) error { + + status, err := sm.Miner.SectorsStatus(ctx, sectorNum, false) + if err != nil { + return err + } + + minerAddr, err := sm.ActorAddress(ctx) + if err != nil { + return err + } + minerID, err := address.IDFromAddress(minerAddr) + if err != nil { + return err + } + + sector := storiface.SectorRef{ + ID: abi.SectorID{ + Miner: abi.ActorID(minerID), + Number: sectorNum, + }, + ProofType: status.SealProof, + } + + return sm.StorageMgr.SectorsUnsealPiece(ctx, sector, storiface.UnpaddedByteIndex(0), abi.UnpaddedPieceSize(0), status.Ticket.Value, status.CommD) +} + // List all staged sectors func (sm *StorageMinerAPI) SectorsList(context.Context) ([]abi.SectorNumber, error) { sectors, err := sm.Miner.ListSectors()