diff --git a/api/api.go b/api/api.go index 1ea58cfdf..083c47b54 100644 --- a/api/api.go +++ b/api/api.go @@ -60,6 +60,7 @@ type FullNode interface { ChainGetTipSetByHeight(context.Context, uint64, *types.TipSet) (*types.TipSet, error) ChainReadObj(context.Context, cid.Cid) ([]byte, error) ChainSetHead(context.Context, *types.TipSet) error + ChainGetGenesis(context.Context) (*types.TipSet, error) // syncer SyncState(context.Context) (*SyncState, error) diff --git a/api/struct.go b/api/struct.go index ab61ef39e..bc83eea54 100644 --- a/api/struct.go +++ b/api/struct.go @@ -48,6 +48,7 @@ type FullNodeStruct struct { ChainGetTipSetByHeight func(context.Context, uint64, *types.TipSet) (*types.TipSet, error) `perm:"read"` ChainReadObj func(context.Context, cid.Cid) ([]byte, error) `perm:"read"` ChainSetHead func(context.Context, *types.TipSet) error `perm:"admin"` + ChainGetGenesis func(context.Context) (*types.TipSet, error) `perm:"read"` SyncState func(context.Context) (*SyncState, error) `perm:"read"` @@ -308,6 +309,10 @@ func (c *FullNodeStruct) ChainSetHead(ctx context.Context, ts *types.TipSet) err return c.Internal.ChainSetHead(ctx, ts) } +func (c *FullNodeStruct) ChainGetGenesis(ctx context.Context) (*types.TipSet, error) { + return c.Internal.ChainGetGenesis(ctx) +} + func (c *FullNodeStruct) SyncState(ctx context.Context) (*SyncState, error) { return c.Internal.SyncState(ctx) } diff --git a/cli/chain.go b/cli/chain.go index 13e99ff95..521350000 100644 --- a/cli/chain.go +++ b/cli/chain.go @@ -210,6 +210,12 @@ var chainGetMsgCmd = &cli.Command{ var chainSetHeadCmd = &cli.Command{ Name: "sethead", Usage: "manually set the local nodes head tipset (Caution: normally only used for recovery)", + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "genesis", + Usage: "reset head to genesis", + }, + }, Action: func(cctx *cli.Context) error { api, closer, err := GetFullNodeAPI(cctx) if err != nil { @@ -218,13 +224,25 @@ var chainSetHeadCmd = &cli.Command{ defer closer() ctx := ReqContext(cctx) - if !cctx.Args().Present() { + gen := cctx.Bool("genesis") + + if !cctx.Args().Present() && !gen { return fmt.Errorf("must pass cids for tipset to set as head") } - ts, err := parseTipSet(api, ctx, cctx.Args().Slice()) - if err != nil { - return err + var ts *types.TipSet + if gen { + gents, err := api.ChainGetGenesis(ctx) + if err != nil { + return err + } + ts = gents + } else { + parsedts, err := parseTipSet(api, ctx, cctx.Args().Slice()) + if err != nil { + return err + } + ts = parsedts } if err := api.ChainSetHead(ctx, ts); err != nil { diff --git a/node/impl/full/chain.go b/node/impl/full/chain.go index 0d68d22cb..91780af6a 100644 --- a/node/impl/full/chain.go +++ b/node/impl/full/chain.go @@ -161,3 +161,12 @@ func (a *ChainAPI) ChainReadObj(ctx context.Context, obj cid.Cid) ([]byte, error func (a *ChainAPI) ChainSetHead(ctx context.Context, ts *types.TipSet) error { return a.Chain.SetHead(ts) } + +func (a *ChainAPI) ChainGetGenesis(ctx context.Context) (*types.TipSet, error) { + genb, err := a.Chain.GetGenesis() + if err != nil { + return nil, err + } + + return types.NewTipSet([]*types.BlockHeader{genb}) +}