expose command to set chainstore head

This commit is contained in:
whyrusleeping 2019-10-10 12:50:50 +09:00
parent 0c6fcde9c4
commit acec79cf3f
5 changed files with 93 additions and 21 deletions

View File

@ -57,6 +57,7 @@ type FullNode interface {
ChainGetParentMessages(context.Context, cid.Cid) ([]Message, error) ChainGetParentMessages(context.Context, cid.Cid) ([]Message, error)
ChainGetTipSetByHeight(context.Context, uint64, *types.TipSet) (*types.TipSet, error) ChainGetTipSetByHeight(context.Context, uint64, *types.TipSet) (*types.TipSet, error)
ChainReadObj(context.Context, cid.Cid) ([]byte, error) ChainReadObj(context.Context, cid.Cid) ([]byte, error)
ChainSetHead(context.Context, *types.TipSet) error
// syncer // syncer
SyncState(context.Context) (*SyncState, error) SyncState(context.Context) (*SyncState, error)

View File

@ -47,6 +47,7 @@ type FullNodeStruct struct {
ChainGetParentMessages func(context.Context, cid.Cid) ([]Message, error) `perm:"read"` ChainGetParentMessages func(context.Context, cid.Cid) ([]Message, error) `perm:"read"`
ChainGetTipSetByHeight func(context.Context, uint64, *types.TipSet) (*types.TipSet, error) `perm:"read"` ChainGetTipSetByHeight func(context.Context, uint64, *types.TipSet) (*types.TipSet, error) `perm:"read"`
ChainReadObj func(context.Context, cid.Cid) ([]byte, error) `perm:"read"` ChainReadObj func(context.Context, cid.Cid) ([]byte, error) `perm:"read"`
ChainSetHead func(context.Context, *types.TipSet) error `perm:"admin"`
SyncState func(context.Context) (*SyncState, error) `perm:"read"` SyncState func(context.Context) (*SyncState, error) `perm:"read"`
@ -303,6 +304,10 @@ func (c *FullNodeStruct) ChainReadObj(ctx context.Context, obj cid.Cid) ([]byte,
return c.Internal.ChainReadObj(ctx, obj) return c.Internal.ChainReadObj(ctx, obj)
} }
func (c *FullNodeStruct) ChainSetHead(ctx context.Context, ts *types.TipSet) error {
return c.Internal.ChainSetHead(ctx, ts)
}
func (c *FullNodeStruct) SyncState(ctx context.Context) (*SyncState, error) { func (c *FullNodeStruct) SyncState(ctx context.Context) (*SyncState, error) {
return c.Internal.SyncState(ctx) return c.Internal.SyncState(ctx)
} }

View File

@ -212,6 +212,12 @@ func (cs *ChainStore) MaybeTakeHeavierTipSet(ts *types.TipSet) error {
// TODO: don't do this for initial sync. Now that we don't have a // TODO: don't do this for initial sync. Now that we don't have a
// difference between 'bootstrap sync' and 'caught up' sync, we need // difference between 'bootstrap sync' and 'caught up' sync, we need
// some other heuristic. // some other heuristic.
return cs.takeHeaviestTipSet(ts)
}
return nil
}
func (cs *ChainStore) takeHeaviestTipSet(ts *types.TipSet) error {
if cs.heaviest != nil { if cs.heaviest != nil {
revert, apply, err := cs.ReorgOps(cs.heaviest, ts) revert, apply, err := cs.ReorgOps(cs.heaviest, ts)
if err != nil { if err != nil {
@ -233,10 +239,18 @@ func (cs *ChainStore) MaybeTakeHeavierTipSet(ts *types.TipSet) error {
log.Errorf("failed to write chain head: %s", err) log.Errorf("failed to write chain head: %s", err)
return nil return nil
} }
}
return nil return nil
} }
// SetHead sets the chainstores current 'best' head node.
// This should only be called if something is broken and needs fixing
func (cs *ChainStore) SetHead(ts *types.TipSet) error {
cs.heaviestLk.Lock()
defer cs.heaviestLk.Unlock()
return cs.takeHeaviestTipSet(ts)
}
func (cs *ChainStore) Contains(ts *types.TipSet) (bool, error) { func (cs *ChainStore) Contains(ts *types.TipSet) (bool, error) {
for _, c := range ts.Cids() { for _, c := range ts.Cids() {
has, err := cs.bs.Has(c) has, err := cs.bs.Has(c)

View File

@ -1,6 +1,7 @@
package cli package cli
import ( import (
"context"
"encoding/json" "encoding/json"
"fmt" "fmt"
@ -204,3 +205,50 @@ var chainGetMsgCmd = &cli.Command{
return nil return nil
}, },
} }
var chainSetHead = &cli.Command{
Name: "sethead",
Usage: "manually set the local nodes head tipset (Caution: normally only used for recovery)",
Action: func(cctx *cli.Context) error {
api, closer, err := GetFullNodeAPI(cctx)
if err != nil {
return err
}
defer closer()
ctx := ReqContext(cctx)
if !cctx.Args().Present() {
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
}
if err := api.ChainSetHead(ctx, ts); err != nil {
return err
}
return nil
},
}
func parseTipSet(api api.FullNode, ctx context.Context, vals []string) (*types.TipSet, error) {
var headers []*types.BlockHeader
for _, c := range vals {
blkc, err := cid.Decode(c)
if err != nil {
return nil, err
}
bh, err := api.ChainGetBlock(ctx, blkc)
if err != nil {
return nil, err
}
headers = append(headers, bh)
}
return types.NewTipSet(headers)
}

View File

@ -157,3 +157,7 @@ func (a *ChainAPI) ChainReadObj(ctx context.Context, obj cid.Cid) ([]byte, error
return blk.RawData(), nil return blk.RawData(), nil
} }
func (a *ChainAPI) ChainSetHead(ctx context.Context, ts *types.TipSet) error {
return a.Chain.SetHead(ts)
}