Documentation ¶
Index ¶
- Variables
- func FlagSet(fs ...[]cli.Flag) []cli.Flag
- func GetAPI(ctx context.Context) (lily.LilyAPI, jsonrpc.ClientCloser, error)
- func LilyNodeAPIOption(out *lily.LilyAPI, fopts ...node.Option) node.Option
- func NewSentinelNodeRPC(ctx context.Context, addr string, requestHeader http.Header) (lily.LilyAPI, jsonrpc.ClientCloser, error)
- func PrintNewJob(w io.Writer, res *schedule.JobSubmitResult) error
- func SetupContextWithCancel(ctx context.Context) (context.Context, context.CancelFunc)
- func SetupStorage(configPath string, storageStr string) (strg model.Storage, err error)
- func SyncWait(ctx context.Context, lapi lily.LilyAPI, watch bool) error
- type FileToCAROpts
- type ImportFromCIDOpts
- type LilyDBOpts
- type LilyLogOpts
- type LilyMetricOpts
- type LilyTracingOpts
- type SyncStatus
- type SyncingState
Constants ¶
This section is empty.
Variables ¶
View Source
var ActorRegistry *vm.ActorRegistry
View Source
var ChainActorCodesCmd = &cli.Command{ Name: "actor-codes", Usage: "Print actor codes and names.", Flags: []cli.Flag{configFlag, storageFlag}, Action: func(_ *cli.Context) error { manifests := manifest.GetBuiltinActorsKeys(actorstypes.Version(actorVersions[len(actorVersions)-1])) t := table.NewWriter() t.AppendHeader(table.Row{"name", "family", "code"}) // values that may be accessed if user wants to persist to Storage var results common.ActorCodeList var strg model.Storage var ctx context.Context if chainActorFlags.storage != "" { results = common.ActorCodeList{} cfg, err := config.FromFile(chainActorFlags.config) if err != nil { return err } md := storage.Metadata{ JobName: chainActorFlags.storage, } ctx = context.Background() sc, err := storage.NewCatalog(cfg.Storage) if err != nil { return err } strg, err = sc.Connect(ctx, chainActorFlags.storage, md) if err != nil { return err } } for _, a := range manifests { av := make(map[actorstypes.Version]cid.Cid) for _, v := range actorVersions { code, ok := actors.GetActorCodeID(actorstypes.Version(v), a) if !ok { continue } av[actorstypes.Version(v)] = code name, family, err := util.ActorNameAndFamilyFromCode(av[actorstypes.Version(v)]) if err != nil { return err } t.AppendRow(table.Row{name, family, code}) results = append(results, &common.ActorCode{ CID: code.String(), Code: name, }) if chainActorFlags.storage != "" { err := strg.PersistBatch(ctx, results) if err != nil { return err } } } } fmt.Println(t.RenderCSV()) return nil }, }
View Source
var ChainActorMethodsCmd = &cli.Command{ Name: "actor-methods", Usage: "Print actor method numbers and their human readable names.", Flags: []cli.Flag{configFlag, storageFlag}, Action: func(_ *cli.Context) error { t := table.NewWriter() t.AppendHeader(table.Row{"actor_family", "method_name", "method_number"}) // values that may be accessed if user wants to persist to Storage var strg model.Storage var ctx context.Context if chainActorFlags.config != "" { cfg, err := config.FromFile(chainActorFlags.config) if err != nil { return err } md := storage.Metadata{ JobName: chainActorFlags.storage, } ctx = context.Background() sc, err := storage.NewCatalog(cfg.Storage) if err != nil { return err } strg, err = sc.Connect(ctx, chainActorFlags.storage, md) if err != nil { return err } } ActorRegistry = consensus.NewActorRegistry() actorCodeMap := getTheActorCodeMap() actorMethodList := common.ActorMethodList{} cache := map[string]bool{} for key, value := range ActorRegistry.Methods { actorFamily := actorCodeMap[key] if actorFamily == "" { fmt.Printf("can not get the family: %v\n", key) continue } for methodNum, value := range value { i, err := strconv.ParseInt(methodNum.String(), 10, 64) if err != nil { fmt.Printf("error at converting methodNum=%v to int64", methodNum) continue } _, exist := cache[actorFamily+methodNum.String()] if exist { continue } cache[actorFamily+methodNum.String()] = true t.AppendRow(table.Row{actorFamily, value.Name, methodNum.String()}) t.AppendSeparator() actorMethodList = append(actorMethodList, &common.ActorMethod{Family: actorFamily, Method: uint64(i), MethodName: value.Name}) } } if chainActorFlags.config != "" { err := strg.PersistBatch(ctx, actorMethodList) if err != nil { return err } } fmt.Println(t.RenderCSV()) return nil }, }
View Source
var ChainCmd = &cli.Command{ Name: "chain", Usage: "Interact with filecoin blockchain", Subcommands: []*cli.Command{ ChainHeadCmd, ChainGetBlock, ChainReadObjCmd, ChainStatObjCmd, ChainGetMsgCmd, ChainListCmd, ChainSetHeadCmd, ChainActorCodesCmd, ChainActorMethodsCmd, ChainStateInspect, ChainStateCompute, ChainStateComputeRange, ChainPruneCmd, }, }
View Source
var ChainGetBlock = &cli.Command{ Name: "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 { ctx := lotuscli.ReqContext(cctx) lapi, closer, err := GetAPI(ctx) if err != nil { return err } defer closer() if !cctx.Args().Present() { return fmt.Errorf("must pass cid of block to print") } bcid, err := cid.Decode(cctx.Args().First()) if err != nil { return err } blk, err := lapi.ChainGetBlock(ctx, bcid) if err != nil { return fmt.Errorf("get block failed: %w", err) } if cctx.Bool("raw") { out, err := json.MarshalIndent(blk, "", " ") if err != nil { return err } fmt.Println(string(out)) return nil } msgs, err := lapi.ChainGetBlockMessages(ctx, bcid) if err != nil { return fmt.Errorf("failed to get messages: %w", err) } pmsgs, err := lapi.ChainGetParentMessages(ctx, bcid) if err != nil { return fmt.Errorf("failed to get parent messages: %w", err) } recpts, err := lapi.ChainGetParentReceipts(ctx, bcid) if err != nil { log.Warn(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) out, err := json.MarshalIndent(cblock, "", " ") if err != nil { return err } fmt.Println(string(out)) return nil }, }
View Source
var ChainGetMsgCmd = &cli.Command{ Name: "getmessage", Usage: "Get and print a message by its cid", ArgsUsage: "[messageCid]", Action: func(cctx *cli.Context) error { if !cctx.Args().Present() { return fmt.Errorf("must pass a cid of a message to get") } ctx := lotuscli.ReqContext(cctx) lapi, closer, err := GetAPI(ctx) if err != nil { return err } defer closer() c, err := cid.Decode(cctx.Args().First()) if err != nil { return fmt.Errorf("failed to parse cid input: %w", err) } mb, err := lapi.ChainReadObj(ctx, c) if err != nil { return fmt.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 fmt.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 } fmt.Println(string(enc)) return nil }, }
View Source
var ChainHeadCmd = &cli.Command{ Name: "head", Usage: "Print chain head", Action: func(cctx *cli.Context) error { ctx := lotuscli.ReqContext(cctx) lapi, closer, err := GetAPI(ctx) if err != nil { return err } defer closer() head, err := lapi.ChainHead(ctx) if err != nil { return err } for _, c := range head.Cids() { fmt.Println(c) } return nil }, }
View Source
var ChainListCmd = &cli.Command{ Name: "list", Aliases: []string{"love"}, Usage: "View a segment of the chain", Flags: []cli.Flag{ &cli.Uint64Flag{Name: "height", DefaultText: "current head"}, &cli.IntFlag{Name: "count", Value: 30}, &cli.StringFlag{ Name: "format", Usage: "specify the format to print out tipsets", Value: "<height>: (<time>) <blocks>", }, &cli.BoolFlag{ Name: "gas-stats", Usage: "view gas statistics for the chain", }, }, Action: func(cctx *cli.Context) error { ctx := lotuscli.ReqContext(cctx) lapi, closer, err := GetAPI(ctx) if err != nil { return err } defer closer() var head *types.TipSet if cctx.IsSet("height") { head, err = lapi.ChainGetTipSetByHeight(ctx, abi.ChainEpoch(cctx.Uint64("height")), types.EmptyTSK) } else { head, err = lapi.ChainHead(ctx) } if err != nil { return err } count := cctx.Int("count") if count < 1 { return nil } tss := make([]*types.TipSet, 0, count) tss = append(tss, head) for i := 1; i < count; i++ { if head.Height() == 0 { break } head, err = lapi.ChainGetTipSet(ctx, head.Parents()) if err != nil { return err } tss = append(tss, head) } if cctx.Bool("gas-stats") { otss := make([]*types.TipSet, 0, len(tss)) for i := len(tss) - 1; i >= 0; i-- { otss = append(otss, tss[i]) } tss = otss for i, ts := range tss { pbf := ts.Blocks()[0].ParentBaseFee fmt.Printf("%d: %d blocks (baseFee: %s -> maxFee: %s)\n", ts.Height(), len(ts.Blocks()), ts.Blocks()[0].ParentBaseFee, types.FIL(types.BigMul(pbf, types.NewInt(uint64(lotusbuild.BlockGasLimit))))) for _, b := range ts.Blocks() { msgs, err := lapi.ChainGetBlockMessages(ctx, b.Cid()) if err != nil { return err } var limitSum int64 psum := big.NewInt(0) for _, m := range msgs.BlsMessages { limitSum += m.GasLimit psum = big.Add(psum, m.GasPremium) } for _, m := range msgs.SecpkMessages { limitSum += m.Message.GasLimit psum = big.Add(psum, m.Message.GasPremium) } lenmsgs := len(msgs.BlsMessages) + len(msgs.SecpkMessages) avgpremium := big.Zero() if lenmsgs > 0 { avgpremium = big.Div(psum, big.NewInt(int64(lenmsgs))) } fmt.Printf("\t%s: \t%d msgs, gasLimit: %d / %d (%0.2f%%), avgPremium: %s\n", b.Miner, len(msgs.BlsMessages)+len(msgs.SecpkMessages), limitSum, lotusbuild.BlockGasLimit, 100*float64(limitSum)/float64(lotusbuild.BlockGasLimit), avgpremium) } if i < len(tss)-1 { msgs, err := lapi.ChainGetParentMessages(ctx, tss[i+1].Blocks()[0].Cid()) if err != nil { return err } var limitSum int64 for _, m := range msgs { limitSum += m.Message.GasLimit } recpts, err := lapi.ChainGetParentReceipts(ctx, tss[i+1].Blocks()[0].Cid()) if err != nil { return err } var gasUsed int64 for _, r := range recpts { gasUsed += r.GasUsed } gasEfficiency := 100 * float64(gasUsed) / float64(limitSum) gasCapacity := 100 * float64(limitSum) / float64(lotusbuild.BlockGasLimit) fmt.Printf("\ttipset: \t%d msgs, %d (%0.2f%%) / %d (%0.2f%%)\n", len(msgs), gasUsed, gasEfficiency, limitSum, gasCapacity) } fmt.Println() } } else { for i := len(tss) - 1; i >= 0; i-- { printTipSet(cctx.String("format"), tss[i]) } } return nil }, }
View Source
var ChainPruneCmd = &cli.Command{
Name: "prune",
Usage: "splitstore gc",
Subcommands: []*cli.Command{
chainPruneColdCmd,
chainPruneHotGCCmd,
chainPruneHotMovingGCCmd,
},
}
View Source
var ChainReadObjCmd = &cli.Command{ Name: "read-obj", Usage: "Read the raw bytes of an object", ArgsUsage: "[objectCid]", Action: func(cctx *cli.Context) error { ctx := lotuscli.ReqContext(cctx) lapi, closer, err := GetAPI(ctx) if err != nil { return err } defer closer() c, err := cid.Decode(cctx.Args().First()) if err != nil { return fmt.Errorf("failed to parse cid input: %s", err) } obj, err := lapi.ChainReadObj(ctx, c) if err != nil { return err } fmt.Printf("%x\n", obj) return nil }, }
View Source
var ChainSetHeadCmd = &cli.Command{ Name: "sethead", 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 { ctx := lotuscli.ReqContext(cctx) lapi, closer, err := GetAPI(ctx) if err != nil { return err } defer closer() var ts *types.TipSet if cctx.Bool("genesis") { ts, err = lapi.ChainGetGenesis(ctx) } if ts == nil && cctx.IsSet("epoch") { ts, err = lapi.ChainGetTipSetByHeight(ctx, abi.ChainEpoch(cctx.Uint64("epoch")), types.EmptyTSK) } if ts == nil { ts, err = parseTipSet(ctx, lapi, cctx.Args().Slice()) } if err != nil { return err } if ts == nil { return fmt.Errorf("must pass cids for tipset to set as head") } err = lapi.ChainSetHead(ctx, ts.Key()) return err }, }
View Source
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 { ctx := lotuscli.ReqContext(cctx) lapi, closer, err := GetAPI(ctx) if err != nil { return err } defer closer() 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 := lapi.ChainStatObj(ctx, obj, base) if err != nil { return err } fmt.Printf("Links: %d\n", stats.Links) fmt.Printf("Size: %s (%d)\n", types.SizeStr(types.NewInt(stats.Size)), stats.Size) return nil }, }
View Source
var ChainStateCompute = &cli.Command{ Name: "state-compute", Usage: "Generates the state at epoch `N`", Flags: []cli.Flag{ &cli.Uint64Flag{ Name: "epoch", Aliases: []string{"e"}, Required: true, }, }, Action: func(cctx *cli.Context) error { ctx := lotuscli.ReqContext(cctx) lapi, closer, err := GetAPI(ctx) if err != nil { return err } defer closer() head, err := lapi.ChainHead(ctx) if err != nil { return err } ts, err := lapi.ChainGetTipSetByHeight(ctx, abi.ChainEpoch(cctx.Uint64("epoch")), head.Key()) if err != nil { return err } _, err = lapi.StateCompute(ctx, ts.Key()) return err }, }
View Source
var ChainStateComputeRange = &cli.Command{ Name: "state-compute-range", Usage: "Generates the state from epoch `FROM` to epoch `TO`", Flags: []cli.Flag{ &cli.Uint64Flag{ Name: "from", Required: true, }, &cli.Uint64Flag{ Name: "to", Required: true, }, }, Action: func(cctx *cli.Context) error { ctx := lotuscli.ReqContext(cctx) lapi, closer, err := GetAPI(ctx) if err != nil { return err } defer closer() head, err := lapi.ChainHead(ctx) if err != nil { return err } bar := pb.StartNew(int(cctx.Uint64("to") - cctx.Uint64("from"))) bar.ShowTimeLeft = true bar.ShowPercent = true bar.Units = pb.U_NO for i := cctx.Int64("from"); i <= cctx.Int64("to"); i++ { ts, err := lapi.ChainGetTipSetByHeight(ctx, abi.ChainEpoch(i), head.Key()) if err != nil { return err } _, err = lapi.StateCompute(ctx, ts.Key()) if err != nil { return err } bar.Add(1) } bar.Finish() return nil }, }
View Source
var ChainStateInspect = &cli.Command{ Name: "state-inspect", Usage: "Returns details about each epoch's state in the local datastore", Flags: []cli.Flag{ &cli.Uint64Flag{ Name: "limit", Aliases: []string{"l"}, Value: 100, Usage: "Limit traversal of statetree when searching for oldest state by `N` heights starting from most recent", }, &cli.BoolFlag{ Name: "verbose", Aliases: []string{"v"}, Usage: "Include detailed information about the completeness of state for all traversed height(s) starting from most recent", }, }, Action: func(cctx *cli.Context) error { ctx := lotuscli.ReqContext(cctx) lapi, closer, err := GetAPI(ctx) if err != nil { return err } defer closer() report, err := lapi.FindOldestState(ctx, cctx.Int64("limit")) if err != nil { return err } sort.Slice(report, func(i, j int) bool { return report[i].Height > report[j].Height }) out, err := marshalReport(report, cctx.Bool("verbose")) if err != nil { return err } fmt.Println(string(out)) return nil }, }
View Source
var ClientAPIFlag = &cli.StringFlag{ Name: "api", Usage: "Address of lily api in multiaddr format.", EnvVars: []string{"LILY_API"}, Value: "/ip4/127.0.0.1/tcp/1234", Destination: &ClientAPIFlags.APIAddr, }
View Source
var ClientAPIFlagSet = []cli.Flag{ ClientAPIFlag, ClientTokenFlag, }
ClientAPIFlagSet are used by commands that act as clients of a daemon's API
View Source
var ClientAPIFlags struct { APIAddr string APIToken string }
View Source
var ClientTokenFlag = &cli.StringFlag{ Name: "api-token", Usage: "Authentication token for lily api.", EnvVars: []string{"LILY_API_TOKEN"}, Value: "", Destination: &ClientAPIFlags.APIToken, }
View Source
var DaemonCmd = &cli.Command{ Name: "daemon", Usage: "Start a lily daemon process.", Description: `Starts lily in daemon mode with its own blockstore. In daemon mode lily synchronizes with the filecoin network and runs jobs such as walk and watch against its local blockstore. This gives better performance than operating against an external blockstore but requires more disk space and memory. Before starting the daemon for the first time the blockstore must be initialized and synchronized. Lily can use a copy of an already synchronized Lotus node repository or can initialize its own empty one and import a snapshot to catch up to the chain. To initialize an empty lily blockstore repository and import an initial snapshot of the chain: lily init --repo=<path> --import-snapshot=<url> This will initialize a blockstore repository at <path> and import chain state from the snapshot at <url>. The type of snapshot needed depends on the type of jobs expected to be run by the daemon. Watch jobs only require current actor state to be imported since incoming tipsets will be used to keep actor states up to date. The lightweight and full chain snapshots available at https://docs.filecoin.io/get-started/lotus/chain/ are suitable to initialize the daemon for watch jobs. Historic walks will require full actor states for the range of heights covered by the walk. These may be created from an existing Lotus node using the export command, provided receipts are also included in the export. See the Lotus documentation for full details. Once the repository is initialized, start the daemon: lily daemon --repo=<path> --config=<path>/config.toml Lily will connect to the filecoin network and begin synchronizing with the chain. To check the synchronization status use 'lily sync status' or 'lily sync wait'. Jobs may be started on the daemon at any time. A watch job will wait for the daemon to become synchronized before extracting data and will pause if the daemon falls out of sync. Start a watch using 'lily watch'. A walk job will start immediately. Start a walk using 'lily walk'. A walk may only be performed between heights that have been synchronized with the network. Note that jobs are not persisted between restarts of the daemon. See 'lily help job' for more information on managing jobs being run by the daemon. `, Flags: []cli.Flag{ ClientAPIFlag, &cli.StringFlag{ Name: "repo", Usage: "Specify path where lily should store chain state.", EnvVars: []string{"LILY_REPO"}, Value: "~/.lily", Destination: &daemonFlags.repo, }, &cli.BoolFlag{ Name: "bootstrap", Usage: "Specify whether to act as a bootstrapper, the initial point of contact for other lily daemons to find peers. If set to `false` lily will not sync to the network. This is useful for troubleshooting.", EnvVars: []string{"LILY_BOOTSTRAP"}, Value: true, Destination: &daemonFlags.bootstrap, }, &cli.StringFlag{ Name: "config", Usage: "Specify path of config file to use.", EnvVars: []string{"LILY_CONFIG"}, Destination: &daemonFlags.config, }, &cli.StringFlag{ Name: "genesis", Usage: "Genesis file to use for first node run.", EnvVars: []string{"LILY_GENESIS"}, Destination: &daemonFlags.genesis, }, &cli.UintFlag{ Name: "blockstore-cache-size", EnvVars: []string{"LILY_BLOCKSTORE_CACHE_SIZE"}, Value: 0, Destination: &cacheFlags.BlockstoreCacheSize, }, &cli.UintFlag{ Name: "statestore-cache-size", EnvVars: []string{"LILY_STATESTORE_CACHE_SIZE"}, Value: 0, Destination: &cacheFlags.StatestoreCacheSize, }, }, Action: func(c *cli.Context) error { lotuslog.SetupLogLevels() if err := setupLogging(LilyLogFlags); err != nil { return fmt.Errorf("setup logging: %w", err) } if err := setupMetrics(LilyMetricFlags); err != nil { return fmt.Errorf("setup metrics: %w", err) } if err := setupTracing(LilyTracingFlags); err != nil { return fmt.Errorf("setup tracing: %w", err) } ctx := context.Background() var err error daemonFlags.repo, err = homedir.Expand(daemonFlags.repo) if err != nil { log.Warnw("could not expand repo location", "error", err) } else { log.Infof("lily repo: %s", daemonFlags.repo) } r, err := repo.NewFS(daemonFlags.repo) if err != nil { return fmt.Errorf("opening fs repo: %w", err) } if daemonFlags.config == "" { daemonFlags.config = filepath.Join(daemonFlags.repo, "config.toml") } else { daemonFlags.config, err = homedir.Expand(daemonFlags.config) if err != nil { log.Warnw("could not expand repo location", "error", err) } else { log.Infof("lily config: %s", daemonFlags.config) } } ctx, _ = tag.New(ctx, tag.Insert(metrics.Version, version.String()), ) stats.Record(ctx, metrics.LilyInfo.M(1)) if err := config.EnsureExists(daemonFlags.config); err != nil { return fmt.Errorf("ensuring config is present at %q: %w", daemonFlags.config, err) } r.SetConfigPath(daemonFlags.config) err = r.Init(repo.FullNode) if err != nil && err != repo.ErrRepoExists { return fmt.Errorf("repo init error: %w", err) } if err := paramfetch.GetParams(lcli.ReqContext(c), lotusbuild.ParametersJSON(), lotusbuild.SrsJSON(), 0); err != nil { return fmt.Errorf("fetching proof parameters: %w", err) } var genBytes []byte if c.String("genesis") != "" { genBytes, err = os.ReadFile(daemonFlags.genesis) if err != nil { return fmt.Errorf("reading genesis: %w", err) } } else { genBytes = lotusbuild.MaybeGenesis() } genesis := node.Options() if len(genBytes) > 0 { genesis = node.Override(new(lotusmodules.Genesis), lotusmodules.LoadGenesis(genBytes)) } isBootstrapper := false shutdown := make(chan struct{}) liteModeDeps := node.Options() var api lily.LilyAPI stop, err := node.New(ctx, LilyNodeAPIOption(&api), node.Override(new(*config.Conf), modules.LoadConf(daemonFlags.config)), node.Override(new(*events.Events), modules.NewEvents), node.Override(new(*schedule.Scheduler), schedule.NewSchedulerDaemon), node.Override(new(*storage.Catalog), modules.NewStorageCatalog), node.Override(new(*distributed.Catalog), modules.NewQueueCatalog), node.Override(new(*lutil.CacheConfig), modules.CacheConfig(cacheFlags.BlockstoreCacheSize, cacheFlags.StatestoreCacheSize)), node.Override(new(dtypes.Bootstrapper), isBootstrapper), node.Override(new(dtypes.ShutdownChan), shutdown), node.Base(), node.Repo(r), node.Override(new(dtypes.UniversalBlockstore), modules.NewCachingUniversalBlockstore), node.Override(new(*stmgr.StateManager), modules.StateManager), node.Override(new(stmgr.ExecMonitor), modules.NewBufferedExecMonitor), genesis, liteModeDeps, node.ApplyIf(func(_ *node.Settings) bool { return c.IsSet("api") }, node.Override(node.SetApiEndpointKey, func(lr repo.LockedRepo) error { apima, err := multiaddr.NewMultiaddr(ClientAPIFlags.APIAddr) if err != nil { return err } return lr.SetAPIEndpoint(apima) })), node.ApplyIf(func(_ *node.Settings) bool { return !daemonFlags.bootstrap }, node.Unset(node.RunPeerMgrKey), node.Unset(new(*peermgr.PeerMgr)), ), ) if err != nil { return fmt.Errorf("initializing node: %w", err) } endpoint, err := r.APIEndpoint() if err != nil { return fmt.Errorf("getting api endpoint: %w", err) } maxAPIRequestSize := int64(0) return util.ServeRPC(api, stop, endpoint, shutdown, maxAPIRequestSize) }, }
View Source
var ExportChainCmd = &cli.Command{ Name: "export", Description: "Export chain from repo (requires node to be offline)", UsageText: ` Exported chains will include all block headers starting at height 'from' to the genesis block. This means block headers are not filtered by the 'from' and 'to' flags. Messages, Receipts, and StateRoots are filtered by the 'from' and 'to' flags. Some examples: lily export --from=100 --to=200 --include-messages=true --include-receipts=true --include-stateroots=false - export blocks from 200 to 0. - export messages from 200 to 100. - export receipts from 200 to 100. - no stateroots exported. lily export --repo=~/.lily --from=0 --to=200 --include-messages=true --include-receipts=true --include-stateroots=true: - export blocks from 200 to 0 - export messages from 200 to 0 - export receipts from 200 to 0 - export stateroots from 200 to 0 lily export --repo=~/.lily --from=0 --to=200 --include-messages=false --include-receipts=false --include-stateroots=false: - export all blocks from 200 to 0 - no messages exported - no receipts exported - no stateroots exported `, Flags: []cli.Flag{ &cli.StringFlag{ Name: "repo", Usage: "the repo to export chain from", Value: "~/.lily", Destination: &chainExportFlags.repo, }, &cli.Uint64Flag{ Name: "to", Usage: "inclusive highest epoch to export", Required: true, Destination: &chainExportFlags.to, }, &cli.Uint64Flag{ Name: "from", Usage: "inclusive lowest epoch to export", Required: true, Destination: &chainExportFlags.from, }, &cli.BoolFlag{ Name: "include-messages", Usage: "exports messages if true", Value: true, Destination: &chainExportFlags.includeMsgs, }, &cli.BoolFlag{ Name: "include-receipts", Usage: "exports receipts if true", Value: true, Destination: &chainExportFlags.includeRcpt, }, &cli.BoolFlag{ Name: "include-stateroots", Usage: "exports stateroots if true", Value: true, Destination: &chainExportFlags.includeStrt, }, &cli.StringFlag{ Name: "out-file", Usage: "file to export to", Value: "chain_export.car", Destination: &chainExportFlags.outFile, }, &cli.BoolFlag{ Name: "progress", Usage: "set to show progress bar of export", Value: true, Destination: &chainExportFlags.progress, }, }, Before: func(_ *cli.Context) error { from, to := chainExportFlags.from, chainExportFlags.to if to < from { return fmt.Errorf("value of --to (%d) should be >= --from (%d)", to, from) } return nil }, Action: func(cctx *cli.Context) error { ctx := cctx.Context path, err := homedir.Expand(chainExportFlags.outFile) if err != nil { return err } outFile, err := os.Create(path) if err != nil { return err } defer func() { if err := outFile.Close(); err != nil { log.Errorw("failed to close out file", "error", err.Error()) } }() cs, bs, closer, err := openChainAndBlockStores(ctx, chainExportFlags.repo) if err != nil { return err } defer closer() log.Info("loading export head...") exportHead, err := cs.GetTipsetByHeight(ctx, abi.ChainEpoch(chainExportFlags.to), cs.GetHeaviestTipSet(), true) if err != nil { return err } log.Infow("loaded export head", "tipset", exportHead.String()) return export.NewChainExporter(exportHead, bs, outFile, export.ExportConfig{ MinHeight: chainExportFlags.from, IncludeMessages: chainExportFlags.includeMsgs, IncludeReceipts: chainExportFlags.includeRcpt, IncludeStateRoots: chainExportFlags.includeStrt, ShowProcess: chainExportFlags.progress, }).Export(ctx) }, }
View Source
var FileToCARCmd = &cli.Command{ Name: "file-to-car", Usage: "Convert a file to a CAR file", Flags: csvToCARFlags, Action: func(_ *cli.Context) error { bs, err := util.ReadTargetFile(FileToCARFlags.TragetFile) if err != nil { return fmt.Errorf("failed to read file: %w", err) } filename := filepath.Base(FileToCARFlags.TragetFile) carData, err := util.MakeCar(filename, bs, mh.SHA2_256) if err != nil { return fmt.Errorf("failed to create CAR file: %w", err) } if err := os.WriteFile(FileToCARFlags.OutputCAR, carData, 0644); err != nil { return fmt.Errorf("failed to write CAR file: %w", err) } return nil }, }
CSVToCAR Command for converting CSV file to CAR file
View Source
var ImportFromCIDCmd = &cli.Command{ Name: "cid-to-car", Usage: "Download cid to a CAR file", Flags: flags, Action: func(ctx *cli.Context) error { err := util.DownloadCarFile(context.TODO(), ctx, ImportFromCIDFlags.CID, ImportFromCIDFlags.OutputCAR) if err != nil { return err } err = util.ExtractCar(ImportFromCIDFlags.OutputCAR, ImportFromCIDFlags.OutputFile) if err != nil { fmt.Printf("got error in extract car: %v", err) } return nil }, }
CSVToCAR Command for converting CSV file to CAR file
View Source
var InitCmd = &cli.Command{ Name: "init", Usage: "Initialise a lily repository.", Flags: []cli.Flag{ &cli.StringFlag{ Name: "repo", Usage: "Specify path where lily should store chain state.", EnvVars: []string{"LILY_REPO"}, Value: "~/.lily", Destination: &initFlags.repo, }, &cli.StringFlag{ Name: "config", Usage: "Specify path of config file to use.", EnvVars: []string{"LILY_CONFIG"}, Destination: &initFlags.config, }, &cli.StringFlag{ Name: "import-snapshot", Usage: "Import chain state from a given chain export file or url.", EnvVars: []string{"LILY_SNAPSHOT"}, Destination: &initFlags.importSnapshot, }, &cli.IntFlag{ Name: "backfill-tipsetkey-range", Usage: "Determine the extent of backfilling from the head.", EnvVars: []string{"LILY_BACKFILL_TIPSETKEY_RANGE"}, Value: 3600, Destination: &initFlags.backfillTipsetKeyRange, }, }, Action: func(c *cli.Context) error { lotuslog.SetupLogLevels() ctx := context.Background() { dir, err := homedir.Expand(initFlags.repo) if err != nil { log.Warnw("could not expand repo location", "error", err) } else { log.Infof("lotus repo: %s", dir) } } r, err := repo.NewFS(initFlags.repo) if err != nil { return fmt.Errorf("opening fs repo: %w", err) } if initFlags.config != "" { if err := config.EnsureExists(initFlags.config); err != nil { return fmt.Errorf("ensuring config is present at %q: %w", initFlags.config, err) } r.SetConfigPath(initFlags.config) } err = r.Init(repo.FullNode) if err != nil && err != repo.ErrRepoExists { return fmt.Errorf("repo init error: %w", err) } if err := paramfetch.GetParams(lcli.ReqContext(c), lotusbuild.ParametersJSON(), lotusbuild.SrsJSON(), 0); err != nil { return fmt.Errorf("fetching proof parameters: %w", err) } if initFlags.importSnapshot != "" { if err := util.ImportChain(ctx, r, initFlags.importSnapshot, true, initFlags.backfillTipsetKeyRange); err != nil { return err } } return nil }, }
View Source
var LogCmd = &cli.Command{ Name: "log", Usage: "Manage logging", Description: ` Manage lily logging systems. Environment Variables: GOLOG_LOG_LEVEL - Default log level for all log systems GOLOG_LOG_FMT - Change output log format (json, nocolor) GOLOG_FILE - Write logs to file GOLOG_OUTPUT - Specify whether to output to file, stderr, stdout or a combination, i.e. file+stderr `, Subcommands: []*cli.Command{ LogList, LogSetLevel, LogSetLevelRegex, }, }
View Source
var LogList = &cli.Command{ Name: "list", Usage: "List log systems", Action: func(cctx *cli.Context) error { ctx := lotuscli.ReqContext(cctx) api, closer, err := GetAPI(ctx) if err != nil { return err } defer closer() systems, err := api.LogList(ctx) if err != nil { return err } sort.Strings(systems) for _, system := range systems { fmt.Println(system) } return nil }, }
View Source
var LogSetLevel = &cli.Command{ Name: "set-level", Usage: "Set log level", ArgsUsage: "[level]", Description: `Set the log level for logging systems: The system flag can be specified multiple times. eg) log set-level --system chain --system chainxchg debug Available Levels: debug info warn error `, Flags: []cli.Flag{ &cli.StringSliceFlag{ Name: "system", Usage: "limit to log system", Value: &cli.StringSlice{}, }, }, Action: func(cctx *cli.Context) error { ctx := lotuscli.ReqContext(cctx) api, closer, err := GetAPI(ctx) if err != nil { return err } defer closer() if !cctx.Args().Present() { return fmt.Errorf("level is required") } systems := cctx.StringSlice("system") if len(systems) == 0 { var err error systems, err = api.LogList(ctx) if err != nil { return err } } for _, system := range systems { if err := api.LogSetLevel(ctx, system, cctx.Args().First()); err != nil { return fmt.Errorf("setting log level on %s: %v", system, err) } } return nil }, }
View Source
var LogSetLevelRegex = &cli.Command{ Name: "set-level-regex", Usage: "Set log level via regular expression", ArgsUsage: "[level] [regex]", Description: `Set the log level for logging systems via a regular expression matching all logging systems: eg) log set-level-regex info 'lily/*' eg) log set-level-regex debug 'lily/tasks/*' Available Levels: debug info warn error `, Action: func(cctx *cli.Context) error { ctx := lotuscli.ReqContext(cctx) api, closer, err := GetAPI(ctx) if err != nil { return err } defer closer() if !cctx.Args().Present() { return fmt.Errorf("level and regular expression are required") } if cctx.Args().Len() != 2 { return fmt.Errorf("extactyl two arguments required [level] [regex]") } if cctx.Args().First() == "" { return fmt.Errorf("level is required") } if cctx.Args().Get(1) == "" { return fmt.Errorf("regex is required") } if _, err := regexp.Compile(cctx.Args().Get(1)); err != nil { return fmt.Errorf("regex does not complie: %w", err) } if err := api.LogSetLevelRegex(ctx, cctx.Args().Get(1), cctx.Args().First()); err != nil { return fmt.Errorf("setting log level via regex: %w", err) } return nil }, }
View Source
var MigrateCmd = &cli.Command{ Name: "migrate", Usage: "Manage the schema version installed in a database.", Flags: FlagSet( dbConnectFlags, []cli.Flag{ &cli.StringFlag{ Name: "to", Usage: "Migrate the schema to specific `VERSION`.", Value: "", }, &cli.BoolFlag{ Name: "latest", Value: false, Usage: "Migrate the schema to the latest version.", }, }, ), Action: func(cctx *cli.Context) error { if err := setupLogging(LilyLogFlags); err != nil { return fmt.Errorf("setup logging: %w", err) } ctx := cctx.Context db, err := storage.NewDatabase(ctx, LilyDBFlags.DB, LilyDBFlags.DBPoolSize, LilyDBFlags.Name, LilyDBFlags.DBSchema, false) if err != nil { return fmt.Errorf("connect database: %w", err) } if cctx.IsSet("to") { targetVersion, err := model.ParseVersion(cctx.String("to")) if err != nil { return fmt.Errorf("invalid schema version: %w", err) } return db.MigrateSchemaTo(ctx, targetVersion) } if cctx.Bool("latest") { return db.MigrateSchema(ctx) } dbVersion, latestVersion, err := db.GetSchemaVersions(ctx) if err != nil { return fmt.Errorf("get schema versions: %w", err) } log.Infof("current database schema is version %s, latest is %s", dbVersion, latestVersion) if err := db.VerifyCurrentSchema(ctx); err != nil { return fmt.Errorf("verify schema: %w", err) } log.Infof("database schema is supported by this version of visor") return nil }, }
View Source
var NetCmd = &cli.Command{ Name: "net", Usage: "Manage P2P Network", Subcommands: []*cli.Command{ NetConnect, NetDisconnect, NetID, NetListen, NetPeers, NetReachability, NetScores, }, }
View Source
var NetConnect = &cli.Command{ Name: "connect", Usage: "Connect to a peer", ArgsUsage: "[peerMultiaddr]", Action: func(cctx *cli.Context) error { ctx := lotuscli.ReqContext(cctx) api, closer, err := GetAPI(ctx) if err != nil { return err } defer closer() pis, err := addrutil.ParseAddresses(ctx, cctx.Args().Slice()) if err != nil { return err } for _, pi := range pis { fmt.Printf("connect %s: ", pi.ID.String()) err := api.NetConnect(ctx, pi) if err != nil { fmt.Println("failure") return err } fmt.Println("success") } return nil }, }
View Source
var NetDisconnect = &cli.Command{ Name: "disconnect", Usage: "Disconnect from a peer", ArgsUsage: "[peerID]", Action: func(cctx *cli.Context) error { ctx := lotuscli.ReqContext(cctx) api, closer, err := GetAPI(ctx) if err != nil { return err } defer closer() ids := cctx.Args().Slice() for _, id := range ids { pid, err := peer.Decode(id) if err != nil { fmt.Println("failure") return err } fmt.Printf("disconnect %s: ", pid.String()) err = api.NetDisconnect(ctx, pid) if err != nil { fmt.Println("failure") return err } fmt.Println("success") } return nil }, }
View Source
var NetID = &cli.Command{ Name: "id", Usage: "Get peer ID of libp2p node used by daemon", Action: func(cctx *cli.Context) error { ctx := lotuscli.ReqContext(cctx) lapi, closer, err := GetAPI(ctx) if err != nil { return fmt.Errorf("get api: %w", err) } defer closer() pid, err := lapi.ID(ctx) if err != nil { return fmt.Errorf("get id: %w", err) } fmt.Println(pid) return nil }, }
View Source
var NetListen = &cli.Command{ Name: "listen", Usage: "List libp2p addresses daemon is listening on", Action: func(cctx *cli.Context) error { ctx := lotuscli.ReqContext(cctx) lapi, closer, err := GetAPI(ctx) if err != nil { return fmt.Errorf("get api: %w", err) } defer closer() addrs, err := lapi.NetAddrsListen(ctx) if err != nil { return err } for _, peer := range addrs.Addrs { fmt.Printf("%s/p2p/%s\n", peer, addrs.ID) } return nil }, }
View Source
var NetPeers = &cli.Command{ Name: "peers", Usage: "List peers daemon is connected to", Flags: []cli.Flag{ &cli.BoolFlag{ Name: "agent", Aliases: []string{"a"}, Usage: "Print agent name", }, &cli.BoolFlag{ Name: "extended", Aliases: []string{"x"}, Usage: "Print extended peer information in json", }, }, Action: func(cctx *cli.Context) error { ctx := lotuscli.ReqContext(cctx) lapi, closer, err := GetAPI(ctx) if err != nil { return fmt.Errorf("get api: %w", err) } defer closer() peers, err := lapi.NetPeers(ctx) if err != nil { return err } sort.Slice(peers, func(i, j int) bool { return strings.Compare(string(peers[i].ID), string(peers[j].ID)) > 0 }) if cctx.Bool("extended") { seen := make(map[peer.ID]struct{}) for _, peer := range peers { _, dup := seen[peer.ID] if dup { continue } seen[peer.ID] = struct{}{} info, err := lapi.NetPeerInfo(ctx, peer.ID) if err != nil { log.Warnf("error getting extended peer info: %s", err) } else { bytes, err := json.Marshal(&info) if err != nil { log.Warnf("error marshalling extended peer info: %s", err) } else { fmt.Println(string(bytes)) } } } } else { w := tabwriter.NewWriter(os.Stdout, 4, 0, 1, ' ', 0) for _, peer := range peers { var agent string if cctx.Bool("agent") { agent, err = lapi.NetAgentVersion(ctx, peer.ID) if err != nil { log.Warnf("getting agent version: %s", err) } } _, err = fmt.Fprintf(w, "%s\t%s\t%s\n", peer.ID, peer.Addrs, agent) if err != nil { fmt.Printf("got error in command [peers]: %v", err) } } if err := w.Flush(); err != nil { return err } } return nil }, }
View Source
var NetReachability = &cli.Command{ Name: "reachability", Usage: "Print information about reachability from the Internet", Action: func(cctx *cli.Context) error { ctx := lotuscli.ReqContext(cctx) lapi, closer, err := GetAPI(ctx) if err != nil { return fmt.Errorf("get api: %w", err) } defer closer() i, err := lapi.NetAutoNatStatus(ctx) if err != nil { return err } fmt.Println("AutoNAT status: ", i.Reachability.String()) if len(i.PublicAddrs) > 0 { fmt.Println("Public address: ", i.PublicAddrs) } return nil }, }
View Source
var NetScores = &cli.Command{ Name: "scores", Usage: "List scores assigned to peers", Flags: []cli.Flag{ &cli.BoolFlag{ Name: "extended", Aliases: []string{"x"}, Usage: "print extended peer scores in json", }, }, Action: func(cctx *cli.Context) error { ctx := lotuscli.ReqContext(cctx) lapi, closer, err := GetAPI(ctx) if err != nil { return fmt.Errorf("get api: %w", err) } defer closer() scores, err := lapi.NetPubsubScores(ctx) if err != nil { return err } if cctx.Bool("extended") { enc := json.NewEncoder(os.Stdout) for _, peer := range scores { err := enc.Encode(peer) if err != nil { return err } } } else { w := tabwriter.NewWriter(os.Stdout, 4, 0, 1, ' ', 0) for _, peer := range scores { _, err = fmt.Fprintf(w, "%s\t%f\n", peer.ID, peer.Score.Score) if err != nil { fmt.Printf("got error in command [socres]: %v", err) } } if err := w.Flush(); err != nil { return err } } return nil }, }
View Source
var ShedCmd = &cli.Command{ Name: "shed", Usage: "Various utilities to help with Lily development.", Subcommands: []*cli.Command{ ShedModelsListCmd, ShedModelsDescribeCmd, }, }
View Source
var ShedModelsDescribeCmd = &cli.Command{ Name: "models-describe", Action: func(cctx *cli.Context) error { if cctx.Args().First() == "" { return fmt.Errorf("model name required, run `lily help models-list`, to see all available models") } mname := cctx.Args().First() if _, found := tasktype.TableLookup[mname]; !found { return fmt.Errorf("model %s doesn't exist", mname) } modelFields := tasktype.TableFieldComments[mname] t := table.NewWriter() t.AppendHeader(table.Row{"Fields", "Description"}) t.SortBy([]table.SortBy{ {Name: "Fields", Mode: table.Asc}}) t.SetCaption(tasktype.TableComment[mname]) for field, comment := range modelFields { t.AppendRow(table.Row{field, comment}) t.AppendSeparator() } fmt.Println(t.Render()) return nil }, }
View Source
var ShedModelsListCmd = &cli.Command{ Name: "models-list", Flags: []cli.Flag{ &cli.BoolFlag{ Name: "short", Usage: "List only model names in a shell script-friendly output.", Aliases: []string{"s"}, }, }, Action: func(cctx *cli.Context) error { if cctx.Bool("short") { fmt.Printf("%s\n", strings.Join(tasktype.AllTableTasks, " ")) return nil } t := table.NewWriter() t.AppendHeader(table.Row{"Model", "Description"}) for _, m := range tasktype.AllTableTasks { comment := tasktype.TableComment[m] t.AppendRow(table.Row{m, text.WrapSoft(comment, 80)}) t.AppendSeparator() } fmt.Println(t.Render()) return nil }, }
View Source
var StopCmd = &cli.Command{ Name: "stop", Usage: "Stop a running lily daemon", Action: func(cctx *cli.Context) error { ctx := lotuscli.ReqContext(cctx) lapi, closer, err := GetAPI(ctx) if err != nil { return err } defer closer() err = lapi.Shutdown(ctx) if err != nil { return err } return nil }, }
View Source
var SyncCmd = &cli.Command{ Name: "sync", Usage: "Inspect or interact with the chain syncer", Subcommands: []*cli.Command{ SyncStatusCmd, SyncWaitCmd, SyncIncomingBlockCmd, }, }
View Source
var SyncIncomingBlockCmd = &cli.Command{ Name: "blocks", Usage: "Start to get incoming block", Flags: []cli.Flag{ &cli.StringFlag{ Name: "config", Usage: "Specify path of config file to use.", EnvVars: []string{"LILY_CONFIG"}, Destination: &syncFlags.config, }, &cli.StringFlag{ Name: "storage", Usage: "Specify the storage to use, if persisting the displayed output.", Destination: &syncFlags.storage, }, &cli.IntFlag{ Name: "confidence", Usage: "Sets the size of the cache used to hold tipsets for possible reversion before being committed to the database.", EnvVars: []string{"LILY_CONFIDENCE"}, Value: 2, Destination: &syncFlags.confidence, }, }, Action: func(cctx *cli.Context) error { ctx := lotuscli.ReqContext(cctx) lapi, closer, err := GetAPI(ctx) if err != nil { return err } defer closer() ctx, cancel := SetupContextWithCancel(ctx) defer cancel() strg, err := SetupStorage(syncFlags.config, syncFlags.storage) if err != nil { return err } state := &SyncingState{ UnsyncedBlockHeadersByEpoch: make(map[int64][]*blocks.UnsyncedBlockHeader), Confidence: int64(syncFlags.confidence), Storage: strg, MapMutex: sync.Mutex{}, StorageMutex: sync.Mutex{}, } go detectOrphanBlocks(ctx, lapi, state) go getIncomingBlocks(ctx, lapi, state) <-ctx.Done() return nil }, }
View Source
var SyncStatusCmd = &cli.Command{ Name: "status", Usage: "Report sync status of a running lily daemon", Flags: []cli.Flag{ &cli.StringFlag{ Name: "output", Usage: "Print only the current sync stage at the latest height. One of [text, json]", Aliases: []string{"o"}, Required: false, }, }, Action: func(cctx *cli.Context) error { ctx := lotuscli.ReqContext(cctx) lapi, closer, err := GetAPI(ctx) if err != nil { return err } defer closer() state, err := lapi.SyncState(ctx) if err != nil { return err } output := cctx.String("output") var max abi.ChainEpoch = -1 maxStateSync := api.StageIdle for _, ss := range state.ActiveSyncs { if max < ss.Height && maxStateSync <= ss.Stage { max = ss.Height maxStateSync = ss.Stage } var base, target []cid.Cid var heightDiff int64 var theight abi.ChainEpoch if ss.Base != nil { base = ss.Base.Cids() heightDiff = int64(ss.Base.Height()) } if ss.Target != nil { target = ss.Target.Cids() heightDiff = int64(ss.Target.Height()) - heightDiff theight = ss.Target.Height() } else { heightDiff = 0 } switch output { case "json": j, err := json.Marshal(SyncStatus{Stage: maxStateSync, Height: max}) if err != nil { return err } fmt.Printf("json format: %v\n", string(j)) case "": fmt.Printf("worker %d:\n", ss.WorkerID) fmt.Printf("\tBase:\t%s\n", base) fmt.Printf("\tTarget:\t%s (%d)\n", target, theight) fmt.Printf("\tHeight diff:\t%d\n", heightDiff) fmt.Printf("\tStage: %s\n", ss.Stage) fmt.Printf("\tHeight: %d\n", ss.Height) if ss.End.IsZero() { if !ss.Start.IsZero() { fmt.Printf("\tElapsed: %s\n", time.Since(ss.Start)) } } else { fmt.Printf("\tElapsed: %s\n", ss.End.Sub(ss.Start)) } case "text": fallthrough default: fmt.Printf("%s %d\n", maxStateSync, max) } if ss.Stage == api.StageSyncErrored && output != "json" { fmt.Printf("\tError: %s\n", ss.Message) } } return nil }, }
View Source
var SyncWaitCmd = &cli.Command{ Name: "wait", Usage: "Wait for sync to be complete", Flags: []cli.Flag{ &cli.BoolFlag{ Name: "watch", Usage: "don't exit after node is synced", }, }, Action: func(cctx *cli.Context) error { ctx := lotuscli.ReqContext(cctx) lapi, closer, err := GetAPI(ctx) if err != nil { return err } defer closer() return SyncWait(ctx, lapi, cctx.Bool("watch")) }, }
View Source
var WaitAPICmd = &cli.Command{ Name: "wait-api", Usage: "Wait for lily api to come online", Flags: []cli.Flag{ &cli.DurationFlag{ Name: "timeout", Usage: "Time to wait for API to become ready", Value: 30 * time.Second, }, }, Action: func(cctx *cli.Context) error { ctx := lotuscli.ReqContext(cctx) var timeout <-chan time.Time if cctx.Duration("timeout") > 0 { timeout = time.NewTimer(cctx.Duration("timeout")).C } for { err := checkAPI(ctx) if err == nil { return nil } log.Warnf("API not online yet... (%s)", err) select { case <-ctx.Done(): return nil case <-timeout: return fmt.Errorf("timed out waiting for api to come online") case <-time.After(time.Second): } } }, }
Functions ¶
func LilyNodeAPIOption ¶
Lily Node settings for injection into lotus node.
func NewSentinelNodeRPC ¶
func PrintNewJob ¶ added in v0.10.0
func PrintNewJob(w io.Writer, res *schedule.JobSubmitResult) error
func SetupContextWithCancel ¶ added in v0.17.2
func SetupStorage ¶ added in v0.17.2
Types ¶
type FileToCAROpts ¶ added in v0.22.0
var FileToCARFlags FileToCAROpts
type ImportFromCIDOpts ¶ added in v0.22.0
var ImportFromCIDFlags ImportFromCIDOpts
type LilyDBOpts ¶ added in v0.10.0
type LilyDBOpts struct { DB string Name string DBSchema string DBPoolSize int DBAllowUpsert bool DBAllowMigrations bool }
var LilyDBFlags LilyDBOpts
type LilyLogOpts ¶ added in v0.10.0
var LilyLogFlags LilyLogOpts
type LilyMetricOpts ¶ added in v0.10.0
type LilyMetricOpts struct { PrometheusPort string RedisAddr string RedisUsername string RedisPassword string RedisDB int }
var LilyMetricFlags LilyMetricOpts
type LilyTracingOpts ¶ added in v0.10.0
type LilyTracingOpts struct { Enabled bool ServiceName string ProviderURL string JaegerSamplerParam float64 }
var LilyTracingFlags LilyTracingOpts
type SyncStatus ¶ added in v0.11.0
type SyncStatus struct { Stage api.SyncStateStage Height abi.ChainEpoch }
type SyncingState ¶ added in v0.17.2
type SyncingState struct { UnsyncedBlockHeadersByEpoch map[int64][]*blocks.UnsyncedBlockHeader MapMutex sync.Mutex Confidence int64 Storage model.Storage StorageMutex sync.Mutex }
func (*SyncingState) PersistBlocks ¶ added in v0.17.2
func (ss *SyncingState) PersistBlocks(ctx context.Context, blocks blocks.UnsyncedBlockHeaders) error
func (*SyncingState) SetBlockHeaderToMap ¶ added in v0.17.2
func (ss *SyncingState) SetBlockHeaderToMap(block *blocks.UnsyncedBlockHeader)
Source Files ¶
Click to show internal directories.
Click to hide internal directories.