2020-10-20 21:19:42 +00:00
package main
import (
"fmt"
2020-10-20 22:26:17 +00:00
"strconv"
2020-10-20 21:19:42 +00:00
"github.com/filecoin-project/go-bitfield"
"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/go-state-types/big"
"github.com/filecoin-project/lotus/chain/actors"
"golang.org/x/xerrors"
"github.com/filecoin-project/lotus/chain/types"
lcli "github.com/filecoin-project/lotus/cli"
"github.com/filecoin-project/specs-actors/actors/builtin"
miner0 "github.com/filecoin-project/specs-actors/v2/actors/builtin/miner"
"github.com/urfave/cli/v2"
)
var sectorsCmd = & cli . Command {
Name : "sectors" ,
Usage : "Tools for interacting with sectors" ,
Flags : [ ] cli . Flag { } ,
Subcommands : [ ] * cli . Command {
terminateSectorCmd ,
} ,
}
var terminateSectorCmd = & cli . Command {
Name : "terminate" ,
Usage : "Forcefully terminate a sector (WARNING: This means losing power and pay a one-time termination penalty(including collateral) for the terminated sector)" ,
ArgsUsage : "[sectorNum1 sectorNum2 ...]" ,
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 . Args ( ) . Len ( ) < 1 {
return fmt . Errorf ( "at least one sector must be specified" )
}
if ! cctx . Bool ( "really-do-it" ) {
return fmt . Errorf ( "this is a command for advanced users, only use it if you are sure of what you are doing" )
}
nodeApi , closer , err := lcli . GetFullNodeAPI ( cctx )
if err != nil {
return err
}
defer closer ( )
api , acloser , err := lcli . GetStorageMinerAPI ( cctx )
if err != nil {
return err
}
defer acloser ( )
ctx := lcli . ReqContext ( cctx )
maddr , err := api . ActorAddress ( ctx )
if err != nil {
return err
}
mi , err := nodeApi . StateMinerInfo ( ctx , maddr , types . EmptyTSK )
if err != nil {
return err
}
terminationDeclarationParams := [ ] miner0 . TerminationDeclaration { }
for _ , sn := range cctx . Args ( ) . Slice ( ) {
sectorNum , err := strconv . ParseUint ( sn , 10 , 64 )
if err != nil {
return fmt . Errorf ( "could not parse sector number: %w" , err )
}
sectorbit := bitfield . New ( )
sectorbit . Set ( sectorNum )
loca , err := nodeApi . StateSectorPartition ( ctx , maddr , abi . SectorNumber ( sectorNum ) , types . EmptyTSK )
if err != nil {
return fmt . Errorf ( "get state sector partition %s" , err )
}
para := miner0 . TerminationDeclaration {
Deadline : loca . Deadline ,
Partition : loca . Partition ,
Sectors : sectorbit ,
}
terminationDeclarationParams = append ( terminationDeclarationParams , para )
}
terminateSectorParams := & miner0 . TerminateSectorsParams {
Terminations : terminationDeclarationParams ,
}
sp , err := actors . SerializeParams ( terminateSectorParams )
if err != nil {
return xerrors . Errorf ( "serializing params: %w" , err )
}
smsg , err := nodeApi . MpoolPushMessage ( ctx , & types . Message {
From : mi . Owner ,
To : maddr ,
Method : builtin . MethodsMiner . TerminateSectors ,
Value : big . Zero ( ) ,
Params : sp ,
} , nil )
if err != nil {
return xerrors . Errorf ( "mpool push message: %w" , err )
}
2020-10-20 22:26:17 +00:00
fmt . Println ( "sent termination message:" , smsg . Cid ( ) )
wait , err := nodeApi . StateWaitMsg ( ctx , smsg . Cid ( ) , uint64 ( cctx . Int ( "confidence" ) ) )
if err != nil {
return err
}
if wait . Receipt . ExitCode != 0 {
return fmt . Errorf ( "terminate sectors message returned exit %d" , wait . Receipt . ExitCode )
}
2020-10-20 21:19:42 +00:00
return nil
} ,
}