package main import ( "fmt" "github.com/urfave/cli/v2" lcli "github.com/filecoin-project/lotus/cli" ) var chainCmd = &cli.Command{ Name: "chain", Usage: "chain-related utilities", Subcommands: []*cli.Command{ chainNullTsCmd, computeStateRangeCmd, }, } var chainNullTsCmd = &cli.Command{ Name: "latest-null", Usage: "finds the most recent null tipset", 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 } for { pts, err := api.ChainGetTipSet(ctx, ts.Parents()) if err != nil { return err } if ts.Height() != pts.Height()+1 { fmt.Println("null tipset at height ", ts.Height()-1) return nil } ts = pts } }, } var computeStateRangeCmd = &cli.Command{ Name: "compute-state-range", Usage: "forces the computation of a range of tipsets", ArgsUsage: "[START_TIPSET_REF] [END_TIPSET_REF]", Action: func(cctx *cli.Context) error { if cctx.NArg() != 2 { return fmt.Errorf("expected two arguments: a start and an end tipset") } api, closer, err := lcli.GetFullNodeAPI(cctx) if err != nil { return err } defer closer() ctx := lcli.ReqContext(cctx) startTs, err := lcli.ParseTipSetRef(ctx, api, cctx.Args().First()) if err != nil { return err } endTs, err := lcli.ParseTipSetRef(ctx, api, cctx.Args().Get(1)) if err != nil { return err } fmt.Printf("computing tipset at height %d (start)\n", startTs.Height()) if _, err := api.StateCompute(ctx, startTs.Height(), nil, startTs.Key()); err != nil { return err } for height := startTs.Height() + 1; height < endTs.Height(); height++ { fmt.Printf("computing tipset at height %d\n", height) // The fact that the tipset lookup method takes a tipset is rather annoying. // This is because we walk back from the supplied tipset (which could be the HEAD) // to locate the desired one. ts, err := api.ChainGetTipSetByHeight(ctx, height, endTs.Key()) if err != nil { return err } if _, err := api.StateCompute(ctx, height, nil, ts.Key()); err != nil { return err } } fmt.Printf("computing tipset at height %d (end)\n", endTs.Height()) if _, err := api.StateCompute(ctx, endTs.Height(), nil, endTs.Key()); err != nil { return err } return nil }, }