lotus/cli/sync.go
Raúl Kripalani 0fddf3e114 make system constants configurable as vars.
This configurability is unlocked through the `testground`
build tag, which Project Oni will uses.

Changes in the usage places of these relaxed constants
were required due to the fact that Golang constants are
untyped, but vars aren't.

Read https://blog.golang.org/constants for more info.
2020-06-30 14:18:26 +01:00

202 lines
4.3 KiB
Go

package cli
import (
"context"
"fmt"
"time"
"github.com/filecoin-project/specs-actors/actors/abi"
cid "github.com/ipfs/go-cid"
"github.com/urfave/cli/v2"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain"
)
var syncCmd = &cli.Command{
Name: "sync",
Usage: "Inspect or interact with the chain syncer",
Subcommands: []*cli.Command{
syncStatusCmd,
syncWaitCmd,
syncMarkBadCmd,
syncCheckBadCmd,
},
}
var syncStatusCmd = &cli.Command{
Name: "status",
Usage: "check sync status",
Action: func(cctx *cli.Context) error {
apic, closer, err := GetFullNodeAPI(cctx)
if err != nil {
return err
}
defer closer()
ctx := ReqContext(cctx)
state, err := apic.SyncState(ctx)
if err != nil {
return err
}
fmt.Println("sync status:")
for i, ss := range state.ActiveSyncs {
fmt.Printf("worker %d:\n", i)
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
}
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", chain.SyncStageString(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))
}
if ss.Stage == api.StageSyncErrored {
fmt.Printf("\tError: %s\n", ss.Message)
}
}
return nil
},
}
var syncWaitCmd = &cli.Command{
Name: "wait",
Usage: "Wait for sync to be complete",
Action: func(cctx *cli.Context) error {
napi, closer, err := GetFullNodeAPI(cctx)
if err != nil {
return err
}
defer closer()
ctx := ReqContext(cctx)
return SyncWait(ctx, napi)
},
}
var syncMarkBadCmd = &cli.Command{
Name: "mark-bad",
Usage: "Mark the given block as bad, will prevent syncing to a chain that contains it",
ArgsUsage: "[blockCid]",
Action: func(cctx *cli.Context) error {
napi, closer, err := GetFullNodeAPI(cctx)
if err != nil {
return err
}
defer closer()
ctx := ReqContext(cctx)
if !cctx.Args().Present() {
return fmt.Errorf("must specify block cid to mark")
}
bcid, err := cid.Decode(cctx.Args().First())
if err != nil {
return fmt.Errorf("failed to decode input as a cid: %s", err)
}
return napi.SyncMarkBad(ctx, bcid)
},
}
var syncCheckBadCmd = &cli.Command{
Name: "check-bad",
Usage: "check if the given block was marked bad, and for what reason",
ArgsUsage: "[blockCid]",
Action: func(cctx *cli.Context) error {
napi, closer, err := GetFullNodeAPI(cctx)
if err != nil {
return err
}
defer closer()
ctx := ReqContext(cctx)
if !cctx.Args().Present() {
return fmt.Errorf("must specify block cid to check")
}
bcid, err := cid.Decode(cctx.Args().First())
if err != nil {
return fmt.Errorf("failed to decode input as a cid: %s", err)
}
reason, err := napi.SyncCheckBad(ctx, bcid)
if err != nil {
return err
}
if reason == "" {
fmt.Println("block was not marked as bad")
return nil
}
fmt.Println(reason)
return nil
},
}
func SyncWait(ctx context.Context, napi api.FullNode) error {
for {
state, err := napi.SyncState(ctx)
if err != nil {
return err
}
head, err := napi.ChainHead(ctx)
if err != nil {
return err
}
working := 0
for i, ss := range state.ActiveSyncs {
switch ss.Stage {
case api.StageSyncComplete:
default:
working = i
case api.StageIdle:
// not complete, not actively working
}
}
ss := state.ActiveSyncs[working]
var target []cid.Cid
if ss.Target != nil {
target = ss.Target.Cids()
}
fmt.Printf("\r\x1b[2KWorker %d: Target: %s\tState: %s\tHeight: %d", working, target, chain.SyncStageString(ss.Stage), ss.Height)
if time.Now().Unix()-int64(head.MinTimestamp()) < int64(build.BlockDelay) {
fmt.Println("\nDone!")
return nil
}
select {
case <-ctx.Done():
fmt.Println("\nExit by user")
return nil
case <-time.After(1 * time.Second):
}
}
}