diff --git a/cmd/lotus-shed/main.go b/cmd/lotus-shed/main.go index 749ff2945..8b58dae38 100644 --- a/cmd/lotus-shed/main.go +++ b/cmd/lotus-shed/main.go @@ -21,6 +21,7 @@ func main() { peerkeyCmd, noncefix, bigIntParseCmd, + staterootStatsCmd, } app := &cli.App{ @@ -28,6 +29,14 @@ func main() { Usage: "A place for all the lotus tools", Version: build.BuildVersion, Commands: local, + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "repo", + EnvVars: []string{"LOTUS_PATH"}, + Hidden: true, + Value: "~/.lotus", // TODO: Consider XDG_DATA_HOME + }, + }, } if err := app.Run(os.Args); err != nil { diff --git a/cmd/lotus-shed/stateroot-stats.go b/cmd/lotus-shed/stateroot-stats.go new file mode 100644 index 000000000..89bd0bb47 --- /dev/null +++ b/cmd/lotus-shed/stateroot-stats.go @@ -0,0 +1,94 @@ +package main + +import ( + "fmt" + + "gopkg.in/urfave/cli.v2" + + "github.com/ipfs/go-cid" + + "github.com/filecoin-project/lotus/chain/types" + lcli "github.com/filecoin-project/lotus/cli" +) + +var staterootStatsCmd = &cli.Command{ + Name: "stateroot-stats", + Description: "Walk down the chain and collect stats-obj changes between tipsets", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "tipset", + Usage: "specify tipset to start from", + }, + &cli.IntFlag{ + Name: "count", + Usage: "number of tipsets to count back", + Value: 30, + }, + &cli.BoolFlag{ + Name: "diff", + Usage: "compare tipset with previous", + Value: false, + }, + }, + Action: func(cctx *cli.Context) error { + api, closer, err := lcli.GetFullNodeAPI(cctx) + if err != nil { + return err + } + + defer closer() + ctx := lcli.ReqContext(cctx) + + ts, err := lcli.LoadTipSet(ctx, cctx, api) + if err != nil { + return err + } + + if ts == nil { + ts, err = api.ChainHead(ctx) + if err != nil { + return err + } + } + + fn := func(ts *types.TipSet) (cid.Cid, []cid.Cid) { + blk := ts.Blocks()[0] + strt := blk.ParentStateRoot + cids := blk.Parents + + return strt, cids + } + + count := cctx.Int("count") + diff := cctx.Bool("diff") + + fmt.Printf("Height\tSize\tLinks\tObj\tBase\n") + for i := 0; i < count; i++ { + if ts.Height() == 0 { + return nil + } + strt, cids := fn(ts) + + k := types.NewTipSetKey(cids...) + ts, err = api.ChainGetTipSet(ctx, k) + if err != nil { + return err + } + + pstrt, _ := fn(ts) + + if !diff { + pstrt = cid.Undef + } + + stats, err := api.ChainStatObj(ctx, strt, pstrt) + if err != nil { + return err + } + + fmt.Printf("%d\t%d\t%d\t%s\t%s\n", ts.Height(), stats.Size, stats.Links, strt, pstrt) + } + + return nil + }, +}