Merge pull request #8719 from filecoin-project/gstuart/cli-bad-post

feat: cli: New commands for testing.
This commit is contained in:
Geoff Stuart 2022-05-25 17:10:18 -04:00 committed by GitHub
commit 966f6816eb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 367 additions and 15 deletions

View File

@ -59,6 +59,7 @@ var sectorsCmd = &cli.Command{
sectorsCapacityCollateralCmd,
sectorsBatching,
sectorsRefreshPieceMatchingCmd,
sectorsCompactPartitionsCmd,
},
}
@ -2089,3 +2090,106 @@ 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",
Flags: []cli.Flag{
&cli.Uint64Flag{
Name: "deadline",
Usage: "the deadline to compact the partitions in",
Required: true,
},
&cli.Int64SliceFlag{
Name: "partitions",
Usage: "list of partitions to compact sectors in",
Required: true,
},
&cli.BoolFlag{
Name: "really-do-it",
Usage: "Actually send transaction performing the action",
Value: false,
},
&cli.StringFlag{
Name: "actor",
Usage: "Specify the address of the miner to run this 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)
if err != nil {
return err
}
defer acloser()
ctx := lcli.ReqContext(cctx)
maddr, err := getActorAddress(ctx, cctx)
if err != nil {
return err
}
minfo, err := api.StateMinerInfo(ctx, maddr, types.EmptyTSK)
if err != nil {
return err
}
deadline := cctx.Uint64("deadline")
if deadline > miner.WPoStPeriodDeadlines {
return fmt.Errorf("deadline %d out of range", deadline)
}
parts := cctx.Int64Slice("partitions")
if len(parts) <= 0 {
return fmt.Errorf("must include at least one partition to compact")
}
fmt.Printf("compacting %d paritions\n", len(parts))
partitions := bitfield.New()
for _, partition := range parts {
partitions.Set(uint64(partition))
}
params := miner.CompactPartitionsParams{
Deadline: deadline,
Partitions: partitions,
}
sp, err := actors.SerializeParams(&params)
if err != nil {
return xerrors.Errorf("serializing params: %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)
}
fmt.Printf("Requested compact partitions in message %s\n", smsg.Cid())
wait, err := api.StateWaitMsg(ctx, smsg.Cid(), 0)
if err != nil {
return err
}
// check it executed successfully
if wait.Receipt.ExitCode != 0 {
fmt.Println(cctx.App.Writer, "compact partitions failed!")
return err
}
return nil
},
}

View File

@ -9,15 +9,20 @@ import (
"path/filepath"
"strings"
miner2 "github.com/filecoin-project/specs-actors/actors/builtin/miner"
power6 "github.com/filecoin-project/specs-actors/v6/actors/builtin/power"
"github.com/docker/go-units"
"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/go-state-types/big"
"github.com/ipfs/go-cid"
"github.com/filecoin-project/go-address"
"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/go-state-types/builtin"
miner8 "github.com/filecoin-project/go-state-types/builtin/v8/miner"
"github.com/filecoin-project/go-state-types/crypto"
power7 "github.com/filecoin-project/specs-actors/v7/actors/builtin/power"
"github.com/filecoin-project/specs-actors/v7/actors/runtime/proof"
"github.com/docker/go-units"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/actors"
"github.com/filecoin-project/lotus/chain/actors/builtin/miner"
@ -37,6 +42,8 @@ var minerCmd = &cli.Command{
minerUnpackInfoCmd,
minerCreateCmd,
minerFaultsCmd,
sendInvalidWindowPoStCmd,
generateAndSendConsensusFaultCmd,
},
}
@ -75,7 +82,7 @@ var minerFaultsCmd = &cli.Command{
return err
}
faults, err := faultBf.All(miner2.SectorsMax)
faults, err := faultBf.All(abi.MaxSectorNumber)
if err != nil {
return err
}
@ -216,7 +223,7 @@ var minerCreateCmd = &cli.Command{
return xerrors.Errorf("getting post proof type: %w", err)
}
params, err := actors.SerializeParams(&power6.CreateMinerParams{
params, err := actors.SerializeParams(&power7.CreateMinerParams{
Owner: owner,
Worker: worker,
WindowPoStProofType: spt,
@ -252,7 +259,7 @@ var minerCreateCmd = &cli.Command{
return xerrors.Errorf("create miner failed: exit code %d", mw.Receipt.ExitCode)
}
var retval power6.CreateMinerReturn
var retval power7.CreateMinerReturn
if err := retval.UnmarshalCBOR(bytes.NewReader(mw.Receipt.Return)); err != nil {
return err
}
@ -354,3 +361,226 @@ var minerUnpackInfoCmd = &cli.Command{
}
},
}
var sendInvalidWindowPoStCmd = &cli.Command{
Name: "send-invalid-windowed-post",
Usage: "Sends an invalid windowed post for a specific deadline",
Description: `Note: This is meant for testing purposes and should NOT be used on mainnet or you will be slashed`,
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "really-do-it",
Usage: "Actually send transaction performing the action",
Value: false,
},
&cli.Int64SliceFlag{
Name: "partitions",
Usage: "list of partitions to submit invalid post for",
Required: true,
},
&cli.StringFlag{
Name: "actor",
Usage: "Specify the address of the miner to run this command",
},
},
Action: func(cctx *cli.Context) error {
if !cctx.Bool("really-do-it") {
return xerrors.Errorf("Pass --really-do-it to actually execute this action")
}
api, acloser, err := lcli.GetFullNodeAPI(cctx)
if err != nil {
return xerrors.Errorf("getting api: %w", err)
}
defer acloser()
ctx := lcli.ReqContext(cctx)
maddr, err := address.NewFromString(cctx.String("actor"))
if err != nil {
return xerrors.Errorf("getting actor address: %w", err)
}
minfo, err := api.StateMinerInfo(ctx, maddr, types.EmptyTSK)
if err != nil {
return xerrors.Errorf("getting mienr info: %w", err)
}
deadline, err := api.StateMinerProvingDeadline(ctx, maddr, types.EmptyTSK)
if err != nil {
return xerrors.Errorf("getting deadline: %w", err)
}
partitionIndices := cctx.Int64Slice("partitions")
if len(partitionIndices) <= 0 {
return fmt.Errorf("must include at least one partition to compact")
}
chainHead, err := api.ChainHead(ctx)
if err != nil {
return xerrors.Errorf("getting chain head: %w", err)
}
checkRand, err := api.StateGetRandomnessFromTickets(ctx, crypto.DomainSeparationTag_PoStChainCommit, deadline.Challenge, nil, chainHead.Key())
if err != nil {
return xerrors.Errorf("getting randomness: %w", err)
}
proofSize, err := minfo.WindowPoStProofType.ProofSize()
if err != nil {
return xerrors.Errorf("getting proof size: %w", err)
}
var partitions []miner8.PoStPartition
emptyProof := []proof.PoStProof{{
PoStProof: minfo.WindowPoStProofType,
ProofBytes: make([]byte, proofSize)}}
for _, partition := range partitionIndices {
newPartition := miner8.PoStPartition{
Index: uint64(partition),
Skipped: bitfield.New(),
}
partitions = append(partitions, newPartition)
}
params := miner8.SubmitWindowedPoStParams{
Deadline: deadline.Index,
Partitions: partitions,
Proofs: emptyProof,
ChainCommitEpoch: deadline.Challenge,
ChainCommitRand: checkRand,
}
sp, err := actors.SerializeParams(&params)
if err != nil {
return xerrors.Errorf("serializing params: %w", err)
}
fmt.Printf("submitting bad PoST for %d paritions\n", len(partitionIndices))
smsg, err := api.MpoolPushMessage(ctx, &types.Message{
From: minfo.Worker,
To: maddr,
Method: builtin.MethodsMiner.SubmitWindowedPoSt,
Value: big.Zero(),
Params: sp,
}, nil)
if err != nil {
return xerrors.Errorf("mpool push: %w", err)
}
fmt.Printf("Invalid PoST in message %s\n", smsg.Cid())
wait, err := api.StateWaitMsg(ctx, smsg.Cid(), 0)
if err != nil {
return err
}
// check it executed successfully
if wait.Receipt.ExitCode != 0 {
fmt.Println(cctx.App.Writer, "Invalid PoST message failed!")
return err
}
return nil
},
}
var generateAndSendConsensusFaultCmd = &cli.Command{
Name: "generate-and-send-consensus-fault",
Usage: "Provided a block CID mined by the miner, will create another block at the same height, and send both block headers to generate a consensus fault.",
Description: `Note: This is meant for testing purposes and should NOT be used on mainnet or you will be slashed`,
Action: func(cctx *cli.Context) error {
if cctx.NArg() != 1 {
return xerrors.Errorf("expected 1 arg (blockCID)")
}
blockCid, err := cid.Parse(cctx.Args().First())
if err != nil {
return xerrors.Errorf("getting first arg: %w", err)
}
api, acloser, err := lcli.GetFullNodeAPI(cctx)
if err != nil {
return xerrors.Errorf("getting chain head: %w", err)
}
defer acloser()
ctx := lcli.ReqContext(cctx)
blockHeader, err := api.ChainGetBlock(ctx, blockCid)
if err != nil {
return xerrors.Errorf("getting block header: %w", err)
}
maddr := blockHeader.Miner
minfo, err := api.StateMinerInfo(ctx, maddr, types.EmptyTSK)
if err != nil {
return xerrors.Errorf("getting miner info: %w", err)
}
// We are changing one field in the block header, then resigning the new block.
// This gives two different blocks signed by the same miner at the same height which will result in a consensus fault.
blockHeaderCopy := *blockHeader
blockHeaderCopy.ForkSignaling = blockHeader.ForkSignaling + 1
signingBytes, err := blockHeaderCopy.SigningBytes()
if err != nil {
return xerrors.Errorf("getting bytes to sign second block: %w", err)
}
sig, err := api.WalletSign(ctx, minfo.Worker, signingBytes)
if err != nil {
return xerrors.Errorf("signing second block: %w", err)
}
blockHeaderCopy.BlockSig = sig
buf1 := new(bytes.Buffer)
err = blockHeader.MarshalCBOR(buf1)
if err != nil {
return xerrors.Errorf("marshalling block header 1: %w", err)
}
buf2 := new(bytes.Buffer)
err = blockHeaderCopy.MarshalCBOR(buf2)
if err != nil {
return xerrors.Errorf("marshalling block header 2: %w", err)
}
params := miner8.ReportConsensusFaultParams{
BlockHeader1: buf1.Bytes(),
BlockHeader2: buf2.Bytes(),
}
sp, err := actors.SerializeParams(&params)
if err != nil {
return xerrors.Errorf("serializing params: %w", err)
}
smsg, err := api.MpoolPushMessage(ctx, &types.Message{
From: minfo.Worker,
To: maddr,
Method: builtin.MethodsMiner.ReportConsensusFault,
Value: big.Zero(),
Params: sp,
}, nil)
if err != nil {
return xerrors.Errorf("mpool push: %w", err)
}
fmt.Printf("Consensus fault reported in message %s\n", smsg.Cid())
wait, err := api.StateWaitMsg(ctx, smsg.Cid(), 0)
if err != nil {
return err
}
// check it executed successfully
if wait.Receipt.ExitCode != 0 {
fmt.Println(cctx.App.Writer, "Report consensus fault failed!")
return err
}
return nil
},
}

View File

@ -195,7 +195,7 @@ var verifRegVerifyClientCmd = &cli.Command{
},
},
Action: func(cctx *cli.Context) error {
fmt.Println("DEPRECATED: This behavior is being moved to `lotus verifreg`")
fmt.Println("DEPRECATED: This behavior is being moved to `lotus filplus`")
froms := cctx.String("from")
if froms == "" {
return fmt.Errorf("must specify from address with --from")
@ -264,7 +264,7 @@ var verifRegListVerifiersCmd = &cli.Command{
Usage: "list all verifiers",
Hidden: true,
Action: func(cctx *cli.Context) error {
fmt.Println("DEPRECATED: This behavior is being moved to `lotus verifreg`")
fmt.Println("DEPRECATED: This behavior is being moved to `lotus filplus`")
api, closer, err := lcli.GetFullNodeAPI(cctx)
if err != nil {
return err
@ -296,7 +296,7 @@ var verifRegListClientsCmd = &cli.Command{
Usage: "list all verified clients",
Hidden: true,
Action: func(cctx *cli.Context) error {
fmt.Println("DEPRECATED: This behavior is being moved to `lotus verifreg`")
fmt.Println("DEPRECATED: This behavior is being moved to `lotus filplus`")
api, closer, err := lcli.GetFullNodeAPI(cctx)
if err != nil {
return err
@ -328,7 +328,7 @@ var verifRegCheckClientCmd = &cli.Command{
Usage: "check verified client remaining bytes",
Hidden: true,
Action: func(cctx *cli.Context) error {
fmt.Println("DEPRECATED: This behavior is being moved to `lotus verifreg`")
fmt.Println("DEPRECATED: This behavior is being moved to `lotus filplus`")
if !cctx.Args().Present() {
return fmt.Errorf("must specify client address to check")
}
@ -364,7 +364,7 @@ var verifRegCheckVerifierCmd = &cli.Command{
Usage: "check verifiers remaining bytes",
Hidden: true,
Action: func(cctx *cli.Context) error {
fmt.Println("DEPRECATED: This behavior is being moved to `lotus verifreg`")
fmt.Println("DEPRECATED: This behavior is being moved to `lotus filplus`")
if !cctx.Args().Present() {
return fmt.Errorf("must specify verifier address to check")
}

View File

@ -1685,6 +1685,7 @@ COMMANDS:
get-cc-collateral Get the collateral required to pledge a committed capacity sector
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
help, h Shows a list of commands or help for one command
OPTIONS:
@ -2026,6 +2027,23 @@ OPTIONS:
```
### lotus-miner sectors compact-partitions
```
NAME:
lotus-miner sectors compact-partitions - removes dead sectors from partitions and reduces the number of partitions used if possible
USAGE:
lotus-miner sectors compact-partitions [command options] [arguments...]
OPTIONS:
--deadline value the deadline to compact the partitions in (default: 0)
--partitions value list of partitions to compact sectors in
--really-do-it Actually send transaction performing the action (default: false)
--actor value Specify the address of the miner to run this command
--help, -h show help (default: false)
```
## lotus-miner proving
```
NAME: