From 70b4a699e5b69fc8bd22e962f8eb63948c0e6442 Mon Sep 17 00:00:00 2001 From: Shobit garg Date: Tue, 4 Feb 2025 12:26:11 +0530 Subject: [PATCH 1/2] changes --- cli/chain.go | 1724 ++-------------------------------------- cli/clicommands/cmd.go | 58 +- cli/index.go | 256 ++---- cli/miner/miner.go | 62 +- cli/util/output.go | 24 + 5 files changed, 215 insertions(+), 1909 deletions(-) create mode 100644 cli/util/output.go diff --git a/cli/chain.go b/cli/chain.go index 0c25a881c6b..20a068e4d13 100644 --- a/cli/chain.go +++ b/cli/chain.go @@ -14,1698 +14,116 @@ import ( "path" "sort" "strconv" - "strings" - "time" - "github.com/ipfs/go-cid" - "github.com/urfave/cli/v2" - cbg "github.com/whyrusleeping/cbor-gen" - "golang.org/x/xerrors" - - "github.com/filecoin-project/go-address" - cborutil "github.com/filecoin-project/go-cbor-util" - "github.com/filecoin-project/go-state-types/abi" - "github.com/filecoin-project/go-state-types/big" - "github.com/filecoin-project/specs-actors/actors/builtin" - "github.com/filecoin-project/specs-actors/actors/builtin/account" - "github.com/filecoin-project/specs-actors/actors/builtin/market" - "github.com/filecoin-project/specs-actors/actors/builtin/miner" - "github.com/filecoin-project/specs-actors/actors/builtin/power" - "github.com/filecoin-project/specs-actors/actors/util/adt" - - "github.com/filecoin-project/lotus/api" - lapi "github.com/filecoin-project/lotus/api" - "github.com/filecoin-project/lotus/api/v0api" - "github.com/filecoin-project/lotus/build/buildconstants" - "github.com/filecoin-project/lotus/chain/actors" - "github.com/filecoin-project/lotus/chain/actors/policy" - "github.com/filecoin-project/lotus/chain/consensus" - "github.com/filecoin-project/lotus/chain/types" + "github.com/spf13/cobra" + "github.com/spf13/viper" ) -var ChainCmd = &cli.Command{ - Name: "chain", - Usage: "Interact with filecoin blockchain", - Subcommands: []*cli.Command{ - ChainHeadCmd, - ChainGetBlock, - ChainReadObjCmd, - ChainDeleteObjCmd, - ChainStatObjCmd, - ChainGetMsgCmd, - ChainSetHeadCmd, - ChainListCmd, - ChainGetCmd, - ChainBisectCmd, - ChainExportCmd, - ChainExportRangeCmd, - SlashConsensusFault, - ChainGasPriceCmd, - ChainInspectUsage, - ChainDecodeCmd, - ChainEncodeCmd, - ChainDisputeSetCmd, - ChainPruneCmd, - }, -} - -var ChainHeadCmd = &cli.Command{ - Name: "head", - Usage: "Print chain head", - Flags: []cli.Flag{ - &cli.BoolFlag{ - Name: "height", - Usage: "print just the epoch number of the chain head", - }, - }, - Action: func(cctx *cli.Context) error { - afmt := NewAppFmt(cctx.App) - - api, closer, err := GetFullNodeAPI(cctx) - if err != nil { - return err - } - defer closer() - ctx := ReqContext(cctx) - - head, err := api.ChainHead(ctx) - if err != nil { - return err - } +var ( + outputFormat string +) - if cctx.Bool("height") { - afmt.Println(head.Height()) - } else { - for _, c := range head.Cids() { - afmt.Println(c) - } - } - return nil - }, +func init() { + rootCmd.PersistentFlags().StringVarP(&outputFormat, "output", "o", "text", "Output format (json|text)") } -var ChainGetBlock = &cli.Command{ - Name: "get-block", - Aliases: []string{"getblock"}, - Usage: "Get a block and print its details", - ArgsUsage: "[blockCid]", - Flags: []cli.Flag{ - &cli.BoolFlag{ - Name: "raw", - Usage: "print just the raw block header", - }, - }, - Action: func(cctx *cli.Context) error { - afmt := NewAppFmt(cctx.App) - - api, closer, err := GetFullNodeAPI(cctx) - if err != nil { - return err - } - defer closer() - ctx := ReqContext(cctx) - - if cctx.NArg() != 1 { - return IncorrectNumArgs(cctx) - } - - bcid, err := cid.Decode(cctx.Args().First()) - if err != nil { - return err - } - - blk, err := api.ChainGetBlock(ctx, bcid) - if err != nil { - return xerrors.Errorf("get block failed: %w", err) - } - - if cctx.Bool("raw") { - out, err := json.MarshalIndent(blk, "", " ") - if err != nil { - return err - } - - afmt.Println(string(out)) - return nil - } - - msgs, err := api.ChainGetBlockMessages(ctx, bcid) - if err != nil { - return xerrors.Errorf("failed to get messages: %w", err) - } - - pmsgs, err := api.ChainGetParentMessages(ctx, bcid) - if err != nil { - return xerrors.Errorf("failed to get parent messages: %w", err) - } - - recpts, err := api.ChainGetParentReceipts(ctx, bcid) - if err != nil { - log.Warn(err) - // return xerrors.Errorf("failed to get receipts: %w", err) - } - - cblock := struct { - types.BlockHeader - BlsMessages []*types.Message - SecpkMessages []*types.SignedMessage - ParentReceipts []*types.MessageReceipt - ParentMessages []cid.Cid - }{} - - cblock.BlockHeader = *blk - cblock.BlsMessages = msgs.BlsMessages - cblock.SecpkMessages = msgs.SecpkMessages - cblock.ParentReceipts = recpts - cblock.ParentMessages = apiMsgCids(pmsgs) +func rootCmd() *cobra.Command { + var rootCmd = &cobra.Command{ + Use: "lotus", + Short: "Lotus CLI", + } - out, err := json.MarshalIndent(cblock, "", " ") - if err != nil { - return err - } + // Add subcommands here - afmt.Println(string(out)) - return nil - }, + return rootCmd } -func apiMsgCids(in []lapi.Message) []cid.Cid { - out := make([]cid.Cid, len(in)) - for k, v := range in { - out[k] = v.Cid +func main() { + if err := rootCmd().Execute(); err != nil { + fmt.Println(err) + os.Exit(1) } - return out } -var ChainReadObjCmd = &cli.Command{ +var ChainReadObjCmd = &cobra.Command{ Name: "read-obj", Usage: "Read the raw bytes of an object", ArgsUsage: "[objectCid]", - Action: func(cctx *cli.Context) error { - afmt := NewAppFmt(cctx.App) - - api, closer, err := GetFullNodeAPI(cctx) - if err != nil { - return err - } - defer closer() - ctx := ReqContext(cctx) - - if cctx.NArg() != 1 { - return IncorrectNumArgs(cctx) - } - - c, err := cid.Decode(cctx.Args().First()) - if err != nil { - return fmt.Errorf("failed to parse cid input: %s", err) - } - - obj, err := api.ChainReadObj(ctx, c) - if err != nil { - return err - } - - afmt.Printf("%x\n", obj) - return nil - }, -} - -var ChainDeleteObjCmd = &cli.Command{ - Name: "delete-obj", - Usage: "Delete an object from the chain blockstore", - Description: "WARNING: Removing wrong objects from the chain blockstore may lead to sync issues", - ArgsUsage: "[objectCid]", - Flags: []cli.Flag{ - &cli.BoolFlag{ - Name: "really-do-it", - }, - }, - Action: func(cctx *cli.Context) error { - afmt := NewAppFmt(cctx.App) - - api, closer, err := GetFullNodeAPI(cctx) - if err != nil { - return err - } - defer closer() - ctx := ReqContext(cctx) - - if cctx.NArg() != 1 { - return IncorrectNumArgs(cctx) - } - - c, err := cid.Decode(cctx.Args().First()) - if err != nil { - return fmt.Errorf("failed to parse cid input: %s", err) - } - - if !cctx.Bool("really-do-it") { - return xerrors.Errorf("pass the --really-do-it flag to proceed") - } - - err = api.ChainDeleteObj(ctx, c) - if err != nil { - return err - } - - afmt.Printf("Obj %s deleted\n", c.String()) - return nil - }, -} - -var ChainStatObjCmd = &cli.Command{ - Name: "stat-obj", - Usage: "Collect size and ipld link counts for objs", - ArgsUsage: "[cid]", - Description: `Collect object size and ipld link count for an object. - - When a base is provided it will be walked first, and all links visisted - will be ignored when the passed in object is walked. -`, - Flags: []cli.Flag{ - &cli.StringFlag{ - Name: "base", - Usage: "ignore links found in this obj", - }, - }, - Action: func(cctx *cli.Context) error { - afmt := NewAppFmt(cctx.App) - api, closer, err := GetFullNodeAPI(cctx) - if err != nil { - return err - } - defer closer() - ctx := ReqContext(cctx) - - if cctx.NArg() != 1 { - return IncorrectNumArgs(cctx) - } - - obj, err := cid.Decode(cctx.Args().First()) - if err != nil { - return fmt.Errorf("failed to parse cid input: %s", err) - } - - base := cid.Undef - if cctx.IsSet("base") { - base, err = cid.Decode(cctx.String("base")) - if err != nil { - return err - } - } - - stats, err := api.ChainStatObj(ctx, obj, base) - if err != nil { - return err - } - - afmt.Printf("Links: %d\n", stats.Links) - afmt.Printf("Size: %s (%d)\n", types.SizeStr(types.NewInt(stats.Size)), stats.Size) - return nil - }, -} - -var ChainGetMsgCmd = &cli.Command{ - Name: "getmessage", - Aliases: []string{"get-message", "get-msg"}, - Usage: "Get and print a message by its cid", - ArgsUsage: "[messageCid]", - Action: func(cctx *cli.Context) error { - afmt := NewAppFmt(cctx.App) - - if cctx.NArg() != 1 { - return IncorrectNumArgs(cctx) - } - - api, closer, err := GetFullNodeAPI(cctx) - if err != nil { - return err - } - defer closer() - ctx := ReqContext(cctx) - - c, err := cid.Decode(cctx.Args().First()) - if err != nil { - return xerrors.Errorf("failed to parse cid input: %w", err) - } - - mb, err := api.ChainReadObj(ctx, c) - if err != nil { - return xerrors.Errorf("failed to read object: %w", err) - } - - var i interface{} - m, err := types.DecodeMessage(mb) - if err != nil { - sm, err := types.DecodeSignedMessage(mb) - if err != nil { - return xerrors.Errorf("failed to decode object as a message: %w", err) - } - i = sm - } else { - i = m - } - - enc, err := json.MarshalIndent(i, "", " ") - if err != nil { - return err + Run: func(cmd *cobra.Command, args []string) { + // ... + + switch outputFormat { + case "json": + // Output data in JSON format + jsonData, _ := json.Marshal(data) + fmt.Println(string(jsonData)) + case "text": + // Output data in plain text format + fmt.Println(data) + default: + return fmt.Errorf("unknown output format: %s", outputFormat) } - afmt.Println(string(enc)) return nil }, } -var ChainSetHeadCmd = &cli.Command{ +var ChainSetHeadCmd = &cobra.Command{ Name: "sethead", Aliases: []string{"set-head"}, Usage: "manually set the local nodes head tipset (Caution: normally only used for recovery)", ArgsUsage: "[tipsetkey]", - Flags: []cli.Flag{ - &cli.BoolFlag{ - Name: "genesis", - Usage: "reset head to genesis", - }, - &cli.Uint64Flag{ - Name: "epoch", - Usage: "reset head to given epoch", - }, - }, - Action: func(cctx *cli.Context) error { - api, closer, err := GetFullNodeAPI(cctx) - if err != nil { - return err - } - defer closer() - ctx := ReqContext(cctx) - - if !cctx.Bool("genesis") && !cctx.IsSet("epoch") && cctx.NArg() != 1 { - return IncorrectNumArgs(cctx) - } - - var ts *types.TipSet - - if cctx.Bool("genesis") { - ts, err = api.ChainGetGenesis(ctx) - } - if ts == nil && cctx.IsSet("epoch") { - ts, err = api.ChainGetTipSetByHeight(ctx, abi.ChainEpoch(cctx.Uint64("epoch")), types.EmptyTSK) - } - if ts == nil { - ts, err = parseTipSet(ctx, api, cctx.Args().Slice()) - } - if err != nil { - return err - } - - if ts == nil { - return fmt.Errorf("must pass cids for tipset to set as head") - } - - if err := api.ChainSetHead(ctx, ts.Key()); err != nil { - return err - } - - return nil - }, -} - -var ChainInspectUsage = &cli.Command{ - Name: "inspect-usage", - Usage: "Inspect block space usage of a given tipset", - Flags: []cli.Flag{ - &cli.StringFlag{ - Name: "tipset", - Usage: "specify tipset to view block space usage of", - Value: "@head", - }, - &cli.IntFlag{ - Name: "length", - Usage: "length of chain to inspect block space usage for", - Value: 1, - }, - &cli.IntFlag{ - Name: "num-results", - Usage: "number of results to print per category", - Value: 10, - }, - }, - Action: func(cctx *cli.Context) error { - afmt := NewAppFmt(cctx.App) - api, closer, err := GetFullNodeAPI(cctx) - if err != nil { - return err - } - defer closer() - ctx := ReqContext(cctx) - - ts, err := LoadTipSet(ctx, cctx, api) - if err != nil { - return err - } - - cur := ts - var msgs []lapi.Message - for i := 0; i < cctx.Int("length"); i++ { - pmsgs, err := api.ChainGetParentMessages(ctx, cur.Blocks()[0].Cid()) - if err != nil { - return err - } - - msgs = append(msgs, pmsgs...) - - next, err := api.ChainGetTipSet(ctx, cur.Parents()) - if err != nil { - return err - } - - cur = next - } - - codeCache := make(map[address.Address]cid.Cid) - - lookupActorCode := func(a address.Address) (cid.Cid, error) { - c, ok := codeCache[a] - if ok { - return c, nil - } - - act, err := api.StateGetActor(ctx, a, ts.Key()) - if err != nil { - return cid.Undef, err - } - - codeCache[a] = act.Code - return act.Code, nil - } - - bySender := make(map[string]int64) - byDest := make(map[string]int64) - byMethod := make(map[string]int64) - bySenderC := make(map[string]int64) - byDestC := make(map[string]int64) - byMethodC := make(map[string]int64) - - var sum int64 - for _, m := range msgs { - bySender[m.Message.From.String()] += m.Message.GasLimit - bySenderC[m.Message.From.String()]++ - byDest[m.Message.To.String()] += m.Message.GasLimit - byDestC[m.Message.To.String()]++ - sum += m.Message.GasLimit - - code, err := lookupActorCode(m.Message.To) - if err != nil { - if strings.Contains(err.Error(), types.ErrActorNotFound.Error()) { - continue - } - return err - } - - mm := consensus.NewActorRegistry().Methods[code][m.Message.Method] // TODO: use remote map - - byMethod[mm.Name] += m.Message.GasLimit - byMethodC[mm.Name]++ - } - - type keyGasPair struct { - Key string - Gas int64 - } - - mapToSortedKvs := func(m map[string]int64) []keyGasPair { - var vals []keyGasPair - for k, v := range m { - vals = append(vals, keyGasPair{ - Key: k, - Gas: v, - }) - } - sort.Slice(vals, func(i, j int) bool { - return vals[i].Gas > vals[j].Gas - }) - return vals - } - - senderVals := mapToSortedKvs(bySender) - destVals := mapToSortedKvs(byDest) - methodVals := mapToSortedKvs(byMethod) - - numRes := cctx.Int("num-results") - - afmt.Printf("Total Gas Limit: %d\n", sum) - afmt.Printf("By Sender:\n") - for i := 0; i < numRes && i < len(senderVals); i++ { - sv := senderVals[i] - afmt.Printf("%s\t%0.2f%%\t(total: %d, count: %d)\n", sv.Key, (100*float64(sv.Gas))/float64(sum), sv.Gas, bySenderC[sv.Key]) - } - afmt.Println() - afmt.Printf("By Receiver:\n") - for i := 0; i < numRes && i < len(destVals); i++ { - sv := destVals[i] - afmt.Printf("%s\t%0.2f%%\t(total: %d, count: %d)\n", sv.Key, (100*float64(sv.Gas))/float64(sum), sv.Gas, byDestC[sv.Key]) - } - afmt.Println() - afmt.Printf("By Method:\n") - for i := 0; i < numRes && i < len(methodVals); i++ { - sv := methodVals[i] - afmt.Printf("%s\t%0.2f%%\t(total: %d, count: %d)\n", sv.Key, (100*float64(sv.Gas))/float64(sum), sv.Gas, byMethodC[sv.Key]) - } - - return nil - }, -} - -var ChainListCmd = &cli.Command{ - Name: "list", - Aliases: []string{"love"}, - Usage: "View a segment of the chain", - Flags: []cli.Flag{ - &cli.Uint64Flag{Name: "epoch", Aliases: []string{"height"}, DefaultText: "current head"}, - &cli.IntFlag{Name: "count", Value: 30}, - &cli.StringFlag{ - Name: "format", - Usage: "specify the format to print out tipsets using placeholders: ,