expose command to set chainstore head
This commit is contained in:
parent
0c6fcde9c4
commit
acec79cf3f
@ -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)
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -212,31 +212,45 @@ 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.
|
||||||
if cs.heaviest != nil {
|
return cs.takeHeaviestTipSet(ts)
|
||||||
revert, apply, err := cs.ReorgOps(cs.heaviest, ts)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "computing reorg ops failed")
|
|
||||||
}
|
|
||||||
for _, hcf := range cs.headChangeNotifs {
|
|
||||||
if err := hcf(revert, apply); err != nil {
|
|
||||||
return errors.Wrap(err, "head change func errored (BAD)")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
log.Warn("no heaviest tipset found, using %s", ts.Cids())
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Debugf("New heaviest tipset! %s", ts.Cids())
|
|
||||||
cs.heaviest = ts
|
|
||||||
|
|
||||||
if err := cs.writeHead(ts); err != nil {
|
|
||||||
log.Errorf("failed to write chain head: %s", err)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (cs *ChainStore) takeHeaviestTipSet(ts *types.TipSet) error {
|
||||||
|
if cs.heaviest != nil {
|
||||||
|
revert, apply, err := cs.ReorgOps(cs.heaviest, ts)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "computing reorg ops failed")
|
||||||
|
}
|
||||||
|
for _, hcf := range cs.headChangeNotifs {
|
||||||
|
if err := hcf(revert, apply); err != nil {
|
||||||
|
return errors.Wrap(err, "head change func errored (BAD)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.Warn("no heaviest tipset found, using %s", ts.Cids())
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debugf("New heaviest tipset! %s", ts.Cids())
|
||||||
|
cs.heaviest = ts
|
||||||
|
|
||||||
|
if err := cs.writeHead(ts); err != nil {
|
||||||
|
log.Errorf("failed to write chain head: %s", err)
|
||||||
|
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)
|
||||||
|
48
cli/chain.go
48
cli/chain.go
@ -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)
|
||||||
|
}
|
||||||
|
@ -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)
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user